diff --git a/jme3-core/src/main/java/com/jme3/material/RenderState.java b/jme3-core/src/main/java/com/jme3/material/RenderState.java index f6236efd0..d2a557c65 100644 --- a/jme3-core/src/main/java/com/jme3/material/RenderState.java +++ b/jme3-core/src/main/java/com/jme3/material/RenderState.java @@ -331,9 +331,17 @@ public class RenderState implements Cloneable, Savable { */ Exclusion, /** - * Allows for custom blending by using glBlendFuncSeparate. + * Uses the blend equations and blend factors defined by the render state. *

- * + * These attributes can be set by using the following methods: + *

+ *

+ * Result.RGB = BlendEquation( sfactorRGB * Source.RGB , dfactorRGB * Destination.RGB )
+ * Result.A = BlendEquationAlpha( sfactorAlpha * Source.A , dfactorAlpha * Destination.A ) */ Custom } @@ -425,8 +433,6 @@ public class RenderState implements Cloneable, Savable { ADDITIONAL.applyDepthWrite = false; ADDITIONAL.applyDepthTest = false; ADDITIONAL.applyColorWrite = false; - ADDITIONAL.applyBlendEquation = false; - ADDITIONAL.applyBlendEquationAlpha = false; ADDITIONAL.applyBlendMode = false; ADDITIONAL.applyPolyOffset = false; } @@ -441,9 +447,7 @@ public class RenderState implements Cloneable, Savable { boolean colorWrite = true; boolean applyColorWrite = true; BlendEquation blendEquation = BlendEquation.Add; - boolean applyBlendEquation = true; BlendEquationAlpha blendEquationAlpha = BlendEquationAlpha.InheritColor; - boolean applyBlendEquationAlpha = true; BlendMode blendMode = BlendMode.Off; boolean applyBlendMode = true; float offsetFactor = 0; @@ -466,10 +470,10 @@ public class RenderState implements Cloneable, Savable { TestFunction frontStencilFunction = TestFunction.Always; TestFunction backStencilFunction = TestFunction.Always; int cachedHashCode = -1; - BlendFunc sfactorRGB=BlendFunc.One; - BlendFunc dfactorRGB=BlendFunc.Zero; - BlendFunc sfactorAlpha=BlendFunc.One; - BlendFunc dfactorAlpha=BlendFunc.Zero; + BlendFunc sfactorRGB = BlendFunc.One; + BlendFunc dfactorRGB = BlendFunc.One; + BlendFunc sfactorAlpha = BlendFunc.One; + BlendFunc dfactorAlpha = BlendFunc.One; public void write(JmeExporter ex) throws IOException { OutputCapsule oc = ex.getCapsule(this); @@ -507,8 +511,6 @@ public class RenderState implements Cloneable, Savable { oc.write(applyDepthWrite, "applyDepthWrite", true); oc.write(applyDepthTest, "applyDepthTest", true); oc.write(applyColorWrite, "applyColorWrite", true); - oc.write(applyBlendEquation, "applyBlendEquation", true); - oc.write(applyBlendEquationAlpha, "applyBlendEquationAlpha", true); oc.write(applyBlendMode, "applyBlendMode", true); oc.write(applyPolyOffset, "applyPolyOffset", true); oc.write(applyDepthFunc, "applyDepthFunc", true); @@ -541,9 +543,9 @@ public class RenderState implements Cloneable, Savable { depthFunc = ic.readEnum("depthFunc", TestFunction.class, TestFunction.LessOrEqual); lineWidth = ic.readFloat("lineWidth", 1); sfactorRGB = ic.readEnum("sfactorRGB", BlendFunc.class, BlendFunc.One); - dfactorAlpha = ic.readEnum("dfactorRGB", BlendFunc.class, BlendFunc.Zero); + dfactorAlpha = ic.readEnum("dfactorRGB", BlendFunc.class, BlendFunc.One); sfactorRGB = ic.readEnum("sfactorAlpha", BlendFunc.class, BlendFunc.One); - dfactorAlpha = ic.readEnum("dfactorAlpha", BlendFunc.class, BlendFunc.Zero); + dfactorAlpha = ic.readEnum("dfactorAlpha", BlendFunc.class, BlendFunc.One); applyWireFrame = ic.readBoolean("applyWireFrame", true); @@ -551,14 +553,11 @@ public class RenderState implements Cloneable, Savable { applyDepthWrite = ic.readBoolean("applyDepthWrite", true); applyDepthTest = ic.readBoolean("applyDepthTest", true); applyColorWrite = ic.readBoolean("applyColorWrite", true); - applyBlendEquation = ic.readBoolean("applyBlendEquation", true); - applyBlendEquationAlpha = ic.readBoolean("applyBlendEquationAlpha", true); applyBlendMode = ic.readBoolean("applyBlendMode", true); applyPolyOffset = ic.readBoolean("applyPolyOffset", true); applyDepthFunc = ic.readBoolean("applyDepthFunc", true); applyLineWidth = ic.readBoolean("applyLineWidth", true); - } /** @@ -615,19 +614,32 @@ public class RenderState implements Cloneable, Savable { return false; } - if (blendEquation != rs.blendEquation) { + if (blendMode != rs.blendMode) { return false; } - if (blendEquationAlpha != rs.blendEquationAlpha) { - return false; - } + if (blendMode == BlendMode.Custom) { + if (blendEquation != rs.blendEquation) { + return false; + } + if (blendEquationAlpha != rs.blendEquationAlpha) { + return false; + } - if (blendMode != rs.blendMode) { - return false; + if (sfactorRGB != rs.sfactorRGB) { + return false; + } + if (dfactorRGB != rs.dfactorRGB) { + return false; + } + if (sfactorAlpha != rs.sfactorAlpha) { + return false; + } + if (dfactorAlpha != rs.dfactorAlpha) { + return false; + } } - if (offsetEnabled != rs.offsetEnabled) { return false; } @@ -675,14 +687,6 @@ public class RenderState implements Cloneable, Savable { if(lineWidth != rs.lineWidth){ return false; } - - if (blendMode.equals(BlendMode.Custom)) { - return sfactorRGB==rs.getCustomSfactorRGB() - && dfactorRGB==rs.getCustomDfactorRGB() - && sfactorAlpha==rs.getCustomSfactorAlpha() - && dfactorAlpha==rs.getCustomDfactorAlpha(); - - } return true; } @@ -768,80 +772,68 @@ public class RenderState implements Cloneable, Savable { } /** - * Set the blending equation. + * Set the blending equation for the color component (RGB). *

- * When blending is enabled, (blendMode is not - * {@link BlendMode#Off}) the input pixel will be blended with the pixel - * already in the color buffer. The blending equation is determined by the - * {@link BlendEquation}. For example, the mode {@link BlendMode#Additive} - * and {@link BlendEquation#Add} will add the input pixel's color to the - * color already in the color buffer: + * The blending equation determines, how the RGB values of the input pixel + * will be blended with the RGB values of the pixel already in the color buffer.
+ * For example, {@link BlendEquation#Add} will add the input pixel's color + * to the color already in the color buffer: *
* Result = Source Color + Destination Color - *
- * However, the mode {@link BlendMode#Additive} - * and {@link BlendEquation#Subtract} will subtract the input pixel's color to the - * color already in the color buffer: - *
- * Result = Source Color - Destination Color + *

+ * Note: This gets only used in {@link BlendMode#Custom} mode. + * All other blend modes will ignore this setting. * - * @param blendEquation The blend equation to use. + * @param blendEquation The {@link BlendEquation} to use. */ public void setBlendEquation(BlendEquation blendEquation) { - applyBlendEquation = true; this.blendEquation = blendEquation; cachedHashCode = -1; } - + /** * Set the blending equation for the alpha component. *

- * When blending is enabled, (blendMode is not - * {@link BlendMode#Off}) the input pixel will be blended with the pixel - * already in the color buffer. The blending equation is determined by the - * {@link BlendEquation} and can be overrode for the alpha component using - * the {@link BlendEquationAlpha} . For example, the mode - * {@link BlendMode#Additive} and {@link BlendEquationAlpha#Add} will add - * the input pixel's alpha to the alpha component already in the color - * buffer: + * The alpha blending equation determines, how the alpha values of the input pixel + * will be blended with the alpha values of the pixel already in the color buffer.
+ * For example, {@link BlendEquationAlpha#Add} will add the input pixel's color + * to the color already in the color buffer: *
- * Result = Source Alpha + Destination Alpha - *
- * However, the mode {@link BlendMode#Additive} and - * {@link BlendEquationAlpha#Subtract} will subtract the input pixel's alpha - * to the alpha component already in the color buffer: - *
- * Result = Source Alpha - Destination Alpha + * Result = Source Color + Destination Color + *

+ * Note: This gets only used in {@link BlendMode#Custom} mode. + * All other blend modes will ignore this setting. * - * @param blendEquationAlpha The blend equation to use for the alpha - * component. + * @param blendEquationAlpha The {@link BlendEquationAlpha} to use. */ public void setBlendEquationAlpha(BlendEquationAlpha blendEquationAlpha) { - applyBlendEquationAlpha = true; this.blendEquationAlpha = blendEquationAlpha; cachedHashCode = -1; } - /** - * Sets the custom blend factors for BlendMode.Custom as - * defined by the appropriate BlendFunc. - * + * Sets the blend factors used for the source and destination color. + *

+ * These factors will be multiplied with the color values of the input pixel + * and the pixel already in the color buffer, before both colors gets combined by the {@link BlendEquation}. + *

+ * Note: This gets only used in {@link BlendMode#Custom} mode. + * All other blend modes will ignore this setting. + * * @param sfactorRGB The source blend factor for RGB components. * @param dfactorRGB The destination blend factor for RGB components. * @param sfactorAlpha The source blend factor for the alpha component. * @param dfactorAlpha The destination blend factor for the alpha component. */ - public void setCustomBlendFactors(BlendFunc sfactorRGB, BlendFunc dfactorRGB, BlendFunc sfactorAlpha, BlendFunc dfactorAlpha) - { + public void setCustomBlendFactors(BlendFunc sfactorRGB, BlendFunc dfactorRGB, BlendFunc sfactorAlpha, BlendFunc dfactorAlpha) { this.sfactorRGB = sfactorRGB; this.dfactorRGB = dfactorRGB; this.sfactorAlpha = sfactorAlpha; this.dfactorAlpha = dfactorAlpha; cachedHashCode = -1; } - - + + /** * Enable depth testing. * @@ -1374,14 +1366,6 @@ public class RenderState implements Cloneable, Savable { return applyBlendMode; } - public boolean isApplyBlendEquation() { - return applyBlendEquation; - } - - public boolean isApplyBlendEquationAlpha() { - return applyBlendEquationAlpha; - } - public boolean isApplyColorWrite() { return applyColorWrite; } @@ -1511,27 +1495,26 @@ public class RenderState implements Cloneable, Savable { } else { state.colorWrite = colorWrite; } - if (additionalState.applyBlendEquation) { - state.blendEquation = additionalState.blendEquation; - } else { - state.blendEquation = blendEquation; - } - if (additionalState.applyBlendEquationAlpha) { - state.blendEquationAlpha = additionalState.blendEquationAlpha; - } else { - state.blendEquationAlpha = blendEquationAlpha; - } if (additionalState.applyBlendMode) { state.blendMode = additionalState.blendMode; - if (additionalState.getBlendMode().equals(BlendMode.Custom)) { - state.setCustomBlendFactors( - additionalState.getCustomSfactorRGB(), - additionalState.getCustomDfactorRGB(), - additionalState.getCustomSfactorAlpha(), - additionalState.getCustomDfactorAlpha()); + if (additionalState.blendMode == BlendMode.Custom) { + state.blendEquation = additionalState.blendEquation; + state.blendEquationAlpha = additionalState.blendEquationAlpha; + state.sfactorRGB = additionalState.sfactorRGB; + state.dfactorRGB = additionalState.dfactorRGB; + state.sfactorAlpha = additionalState.sfactorAlpha; + state.dfactorAlpha = additionalState.dfactorAlpha; } } else { state.blendMode = blendMode; + if (blendMode == BlendMode.Custom) { + state.blendEquation = blendEquation; + state.blendEquationAlpha = blendEquationAlpha; + state.sfactorRGB = sfactorRGB; + state.dfactorRGB = dfactorRGB; + state.sfactorAlpha = sfactorAlpha; + state.dfactorAlpha = dfactorAlpha; + } } if (additionalState.applyPolyOffset) { @@ -1608,8 +1591,6 @@ public class RenderState implements Cloneable, Savable { applyDepthWrite = true; applyDepthTest = true; applyColorWrite = true; - applyBlendEquation = true; - applyBlendEquationAlpha = true; applyBlendMode = true; applyPolyOffset = true; applyDepthFunc = true; @@ -1636,8 +1617,6 @@ public class RenderState implements Cloneable, Savable { + "\ncolorWrite=" + colorWrite + "\napplyColorWrite=" + applyColorWrite + "\nblendEquation=" + blendEquation - + "\napplyBlendEquation=" + applyBlendEquation - + "\napplyBlendEquationAlpha=" + applyBlendEquationAlpha + "\nblendMode=" + blendMode + "\napplyBlendMode=" + applyBlendMode + "\noffsetEnabled=" + offsetEnabled diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java b/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java index 49f25240a..4599fdbb3 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java @@ -32,6 +32,7 @@ package com.jme3.renderer; import com.jme3.material.RenderState; +import com.jme3.material.RenderState.BlendFunc; import com.jme3.math.ColorRGBA; import com.jme3.scene.Mesh; import com.jme3.scene.VertexBuffer; @@ -110,6 +111,30 @@ public class RenderContext { */ public RenderState.BlendEquationAlpha blendEquationAlpha = RenderState.BlendEquationAlpha.InheritColor; + /** + * @see RenderState#setCustomBlendFactors(com.jme3.material.RenderState.BlendFunc, com.jme3.material.RenderState.BlendFunc, + * com.jme3.material.RenderState.BlendFunc, com.jme3.material.RenderState.BlendFunc) + */ + public RenderState.BlendFunc sfactorRGB = RenderState.BlendFunc.One; + + /** + * @see RenderState#setCustomBlendFactors(com.jme3.material.RenderState.BlendFunc, com.jme3.material.RenderState.BlendFunc, + * com.jme3.material.RenderState.BlendFunc, com.jme3.material.RenderState.BlendFunc) + */ + public RenderState.BlendFunc dfactorRGB = RenderState.BlendFunc.One; + + /** + * @see RenderState#setCustomBlendFactors(com.jme3.material.RenderState.BlendFunc, com.jme3.material.RenderState.BlendFunc, + * com.jme3.material.RenderState.BlendFunc, com.jme3.material.RenderState.BlendFunc) + */ + public RenderState.BlendFunc sfactorAlpha = RenderState.BlendFunc.One; + + /** + * @see RenderState#setCustomBlendFactors(com.jme3.material.RenderState.BlendFunc, com.jme3.material.RenderState.BlendFunc, + * com.jme3.material.RenderState.BlendFunc, com.jme3.material.RenderState.BlendFunc) + */ + public RenderState.BlendFunc dfactorAlpha = RenderState.BlendFunc.One; + /** * @see RenderState#setWireframe(boolean) */ @@ -266,6 +291,10 @@ public class RenderContext { blendMode = RenderState.BlendMode.Off; blendEquation = RenderState.BlendEquation.Add; blendEquationAlpha = RenderState.BlendEquationAlpha.InheritColor; + sfactorRGB = BlendFunc.One; + dfactorRGB = BlendFunc.One; + sfactorAlpha = BlendFunc.One; + dfactorAlpha = BlendFunc.One; wireframe = false; boundShaderProgram = 0; boundShader = null; diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java index 9851f3418..746db4084 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java @@ -33,6 +33,7 @@ package com.jme3.renderer.opengl; import com.jme3.material.RenderState; import com.jme3.material.RenderState.BlendFunc; +import com.jme3.material.RenderState.BlendMode; import com.jme3.material.RenderState.StencilOperation; import com.jme3.material.RenderState.TestFunction; import com.jme3.math.*; @@ -743,68 +744,57 @@ public final class GLRenderer implements Renderer { context.cullMode = state.getFaceCullMode(); } - if (state.getBlendMode() != context.blendMode) { - if (state.getBlendMode() == RenderState.BlendMode.Off) { - gl.glDisable(GL.GL_BLEND); - } else { - if (context.blendMode == RenderState.BlendMode.Off) { - gl.glEnable(GL.GL_BLEND); - } - switch (state.getBlendMode()) { - case Off: - break; - case Additive: - gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE); - break; - case AlphaAdditive: - gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE); - break; - case Alpha: - gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); - break; - case PremultAlpha: - gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE_MINUS_SRC_ALPHA); - break; - case Modulate: - gl.glBlendFunc(GL.GL_DST_COLOR, GL.GL_ZERO); - break; - case ModulateX2: - gl.glBlendFunc(GL.GL_DST_COLOR, GL.GL_SRC_COLOR); - break; - case Color: - case Screen: - gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE_MINUS_SRC_COLOR); - break; - case Exclusion: - gl.glBlendFunc(GL.GL_ONE_MINUS_DST_COLOR, GL.GL_ONE_MINUS_SRC_COLOR); - break; - case Custom: - gl.glBlendFuncSeparate( - convertBlendFunc(state.getCustomSfactorRGB()), - convertBlendFunc(state.getCustomDfactorRGB()), - convertBlendFunc(state.getCustomSfactorAlpha()), - convertBlendFunc(state.getCustomDfactorAlpha())); - break; - default: - throw new UnsupportedOperationException("Unrecognized blend mode: " - + state.getBlendMode()); - } - - if (state.getBlendEquation() != context.blendEquation || state.getBlendEquationAlpha() != context.blendEquationAlpha) { - int colorMode = convertBlendEquation(state.getBlendEquation()); - int alphaMode; - if (state.getBlendEquationAlpha() == RenderState.BlendEquationAlpha.InheritColor) { - alphaMode = colorMode; - } else { - alphaMode = convertBlendEquationAlpha(state.getBlendEquationAlpha()); - } - gl.glBlendEquationSeparate(colorMode, alphaMode); - context.blendEquation = state.getBlendEquation(); - context.blendEquationAlpha = state.getBlendEquationAlpha(); - } + // Always update the blend equations and factors when using custom blend mode. + if (state.getBlendMode() == BlendMode.Custom) { + changeBlendMode(BlendMode.Custom); + + blendFuncSeparate( + state.getCustomSfactorRGB(), + state.getCustomDfactorRGB(), + state.getCustomSfactorAlpha(), + state.getCustomDfactorAlpha()); + blendEquationSeparate(state.getBlendEquation(), state.getBlendEquationAlpha()); + + // Update the blend equations and factors only on a mode change for all the other (common) blend modes. + } else if (state.getBlendMode() != context.blendMode) { + changeBlendMode(state.getBlendMode()); + + switch (state.getBlendMode()) { + case Off: + break; + case Additive: + blendFunc(RenderState.BlendFunc.One, RenderState.BlendFunc.One); + break; + case AlphaAdditive: + blendFunc(RenderState.BlendFunc.Src_Alpha, RenderState.BlendFunc.One); + break; + case Alpha: + blendFunc(RenderState.BlendFunc.Src_Alpha, RenderState.BlendFunc.One_Minus_Src_Alpha); + break; + case PremultAlpha: + blendFunc(RenderState.BlendFunc.One, RenderState.BlendFunc.One_Minus_Src_Alpha); + break; + case Modulate: + blendFunc(RenderState.BlendFunc.Dst_Color, RenderState.BlendFunc.Zero); + break; + case ModulateX2: + blendFunc(RenderState.BlendFunc.Dst_Color, RenderState.BlendFunc.Src_Color); + break; + case Color: + case Screen: + blendFunc(RenderState.BlendFunc.One, RenderState.BlendFunc.One_Minus_Src_Color); + break; + case Exclusion: + blendFunc(RenderState.BlendFunc.One_Minus_Dst_Color, RenderState.BlendFunc.One_Minus_Src_Color); + break; + default: + throw new UnsupportedOperationException("Unrecognized blend mode: " + + state.getBlendMode()); } - context.blendMode = state.getBlendMode(); + // All of the common modes requires the ADD equation. + // (This might change in the future?) + blendEquationSeparate(RenderState.BlendEquation.Add, RenderState.BlendEquationAlpha.InheritColor); } if (context.stencilTest != state.isStencilTest() @@ -852,6 +842,65 @@ public final class GLRenderer implements Renderer { } } + private void changeBlendMode(RenderState.BlendMode blendMode) { + if (blendMode != context.blendMode) { + if (blendMode == RenderState.BlendMode.Off) { + gl.glDisable(GL.GL_BLEND); + } else if (context.blendMode == RenderState.BlendMode.Off) { + gl.glEnable(GL.GL_BLEND); + } + + context.blendMode = blendMode; + } + } + + private void blendEquationSeparate(RenderState.BlendEquation blendEquation, RenderState.BlendEquationAlpha blendEquationAlpha) { + if (blendEquation != context.blendEquation || blendEquationAlpha != context.blendEquationAlpha) { + int glBlendEquation = convertBlendEquation(blendEquation); + int glBlendEquationAlpha = blendEquationAlpha == RenderState.BlendEquationAlpha.InheritColor + ? glBlendEquation + : convertBlendEquationAlpha(blendEquationAlpha); + gl.glBlendEquationSeparate(glBlendEquation, glBlendEquationAlpha); + context.blendEquation = blendEquation; + context.blendEquationAlpha = blendEquationAlpha; + } + } + + private void blendFunc(RenderState.BlendFunc sfactor, RenderState.BlendFunc dfactor) { + if (sfactor != context.sfactorRGB + || dfactor != context.dfactorRGB + || sfactor != context.sfactorAlpha + || dfactor != context.dfactorAlpha) { + + gl.glBlendFunc( + convertBlendFunc(sfactor), + convertBlendFunc(dfactor)); + context.sfactorRGB = sfactor; + context.dfactorRGB = dfactor; + context.sfactorAlpha = sfactor; + context.dfactorAlpha = dfactor; + } + } + + private void blendFuncSeparate(RenderState.BlendFunc sfactorRGB, RenderState.BlendFunc dfactorRGB, + RenderState.BlendFunc sfactorAlpha, RenderState.BlendFunc dfactorAlpha) { + if (sfactorRGB != context.sfactorRGB + || dfactorRGB != context.dfactorRGB + || sfactorAlpha != context.sfactorAlpha + || dfactorAlpha != context.dfactorAlpha) { + + gl.glBlendFuncSeparate( + convertBlendFunc(sfactorRGB), + convertBlendFunc(dfactorRGB), + convertBlendFunc(sfactorAlpha), + convertBlendFunc(dfactorAlpha)); + context.sfactorRGB = sfactorRGB; + context.dfactorRGB = dfactorRGB; + context.sfactorAlpha = sfactorAlpha; + context.dfactorAlpha = dfactorAlpha; + } + } + private int convertBlendEquation(RenderState.BlendEquation blendEquation) { switch (blendEquation) { case Add: