diff --git a/jme3-android/src/main/java/com/jme3/renderer/android/AndroidGL.java b/jme3-android/src/main/java/com/jme3/renderer/android/AndroidGL.java index b77c4a36d..8aeb883e0 100644 --- a/jme3-android/src/main/java/com/jme3/renderer/android/AndroidGL.java +++ b/jme3-android/src/main/java/com/jme3/renderer/android/AndroidGL.java @@ -523,4 +523,9 @@ public class AndroidGL implements GL, GLExt, GLFbo { public Object glFenceSync(int condition, int flags) { throw new UnsupportedOperationException("OpenGL ES 2 does not support sync fences"); } + + @Override + public void glBlendEquationSeparate(int colorMode, int alphaMode) { + GLES20.glBlendEquationSeparate(colorMode, alphaMode); + } } 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 e5f3d4825..e8b613bef 100644 --- a/jme3-core/src/main/java/com/jme3/material/RenderState.java +++ b/jme3-core/src/main/java/com/jme3/material/RenderState.java @@ -120,6 +120,92 @@ public class RenderState implements Cloneable, Savable { Always } + /** + * BlendEquation specifies the blending equation to combine + * pixels. + */ + public enum BlendEquation { + /** + * Sets the blend equation so that the source and destination data are + * added. (Default) Clamps to [0,1] Useful for things like antialiasing + * and transparency. + */ + Add, + /** + * Sets the blend equation so that the source and destination data are + * subtracted (Src - Dest). Clamps to [0,1] Falls back to Add if + * supportsSubtract is false. + */ + Subtract, + /** + * Same as Subtract, but the order is reversed (Dst - Src). Clamps to + * [0,1] Falls back to Add if supportsSubtract is false. + */ + ReverseSubtract, + /** + * Sets the blend equation so that each component of the result color is + * the minimum of the corresponding components of the source and + * destination colors. This and Max are useful for applications that + * analyze image data (image thresholding against a constant color, for + * example). Falls back to Add if supportsMinMax is false. + */ + Min, + /** + * Sets the blend equation so that each component of the result color is + * the maximum of the corresponding components of the source and + * destination colors. This and Min are useful for applications that + * analyze image data (image thresholding against a constant color, for + * example). Falls back to Add if supportsMinMax is false. + */ + Max + } + + /** + * BlendEquationAlpha specifies the blending equation to + * combine pixels for the alpha component. + */ + public enum BlendEquationAlpha { + /** + * Sets the blend equation to be the same as the one defined by + * {@link #blendEquation}. + * + */ + InheritColor, + /** + * Sets the blend equation so that the source and destination data are + * added. (Default) Clamps to [0,1] Useful for things like antialiasing + * and transparency. + */ + Add, + /** + * Sets the blend equation so that the source and destination data are + * subtracted (Src - Dest). Clamps to [0,1] Falls back to Add if + * supportsSubtract is false. + */ + Subtract, + /** + * Same as Subtract, but the order is reversed (Dst - Src). Clamps to + * [0,1] Falls back to Add if supportsSubtract is false. + */ + ReverseSubtract, + /** + * Sets the blend equation so that the result alpha is the minimum of + * the source alpha and destination alpha. This and Max are useful for + * applications that analyze image data (image thresholding against a + * constant color, for example). Falls back to Add if supportsMinMax is + * false. + */ + Min, + /** + * sSets the blend equation so that the result alpha is the maximum of + * the source alpha and destination alpha. This and Min are useful for + * applications that analyze image data (image thresholding against a + * constant color, for example). Falls back to Add if supportsMinMax is + * false. + */ + Max + } + /** * BlendMode specifies the blending operation to use. * @@ -377,6 +463,7 @@ public class RenderState implements Cloneable, Savable { depthFunc = ic.readEnum("depthFunc", TestFunction.class, TestFunction.LessOrEqual); lineWidth = ic.readFloat("lineWidth", 1); + applyWireFrame = ic.readBoolean("applyWireFrame", true); applyCullMode = ic.readBoolean("applyCullMode", true); applyDepthWrite = ic.readBoolean("applyDepthWrite", true); @@ -405,8 +492,8 @@ public class RenderState implements Cloneable, Savable { } /** - * returns true if the given renderState is equall to this one - * @param o the renderState to compate to + * returns true if the given renderState is equal to this one + * @param o the renderState to compare to * @return true if the renderStates are equal */ @Override @@ -448,6 +535,7 @@ public class RenderState implements Cloneable, Savable { return false; } + if (offsetEnabled != rs.offsetEnabled) { return false; } @@ -579,6 +667,61 @@ public class RenderState implements Cloneable, Savable { cachedHashCode = -1; } + /** + * Set the blending equation. + *

+ * 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: + *
+ * 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 + * + * @param blendEquation The blend equation 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: + *
+ * 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 + * + * @param blendEquationAlpha The blend equation to use for the alpha + * component. + */ + public void setBlendEquationAlpha(BlendEquationAlpha blendEquationAlpha) { + applyBlendEquationAlpha = true; + this.blendEquationAlpha = blendEquationAlpha; + cachedHashCode = -1; + } + /** * Enable depth testing. * @@ -893,6 +1036,24 @@ public class RenderState implements Cloneable, Savable { return backStencilFunction; } + /** + * Retrieve the blend equation. + * + * @return the blend equation. + */ + public BlendEquation getBlendEquation() { + return blendEquation; + } + + /** + * Retrieve the blend equation used for the alpha component. + * + * @return the blend equation for the alpha component. + */ + public BlendEquationAlpha getBlendEquationAlpha() { + return blendEquationAlpha; + } + /** * Retrieve the blend mode. * @@ -1047,6 +1208,8 @@ public class RenderState implements Cloneable, Savable { return lineWidth; } + + public boolean isApplyBlendMode() { return applyBlendMode; } @@ -1067,6 +1230,7 @@ public class RenderState implements Cloneable, Savable { return applyDepthWrite; } + public boolean isApplyPolyOffset() { return applyPolyOffset; } @@ -1079,6 +1243,7 @@ public class RenderState implements Cloneable, Savable { return applyDepthFunc; } + public boolean isApplyLineWidth() { return applyLineWidth; } @@ -1096,6 +1261,8 @@ public class RenderState implements Cloneable, Savable { hash = 79 * hash + (this.depthFunc != null ? this.depthFunc.hashCode() : 0); hash = 79 * hash + (this.colorWrite ? 1 : 0); hash = 79 * hash + (this.blendMode != null ? this.blendMode.hashCode() : 0); + hash = 79 * hash + (this.blendEquation != null ? this.blendEquation.hashCode() : 0); + hash = 79 * hash + (this.blendEquationAlpha != null ? this.blendEquationAlpha.hashCode() : 0); hash = 79 * hash + Float.floatToIntBits(this.offsetFactor); hash = 79 * hash + Float.floatToIntBits(this.offsetUnits); hash = 79 * hash + (this.offsetEnabled ? 1 : 0); @@ -1171,6 +1338,16 @@ 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; } else { @@ -1221,6 +1398,7 @@ public class RenderState implements Cloneable, Savable { state.cachedHashCode = -1; return state; } + public void set(RenderState state) { wireframe = state.wireframe; cullMode = state.cullMode; @@ -1240,6 +1418,8 @@ public class RenderState implements Cloneable, Savable { backStencilDepthPassOperation = state.backStencilDepthPassOperation; frontStencilFunction = state.frontStencilFunction; backStencilFunction = state.backStencilFunction; + blendEquationAlpha = state.blendEquationAlpha; + blendEquation = state.blendEquation; depthFunc = state.depthFunc; lineWidth = state.lineWidth; @@ -1248,7 +1428,9 @@ public class RenderState implements Cloneable, Savable { applyDepthWrite = true; applyDepthTest = true; applyColorWrite = true; - applyBlendMode = true; + applyBlendEquation = true; + applyBlendEquationAlpha = true; + applyBlendMode = true; applyPolyOffset = true; applyDepthFunc = true; applyLineWidth = true; @@ -1268,6 +1450,9 @@ public class RenderState implements Cloneable, Savable { + "\napplyDepthTest=" + applyDepthTest + "\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 2e0f6e79e..49f25240a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java @@ -100,6 +100,16 @@ public class RenderContext { */ public RenderState.BlendMode blendMode = RenderState.BlendMode.Off; + /** + * @see RenderState#setBlendEquation(com.jme3.material.RenderState.BlendEquation) + */ + public RenderState.BlendEquation blendEquation = RenderState.BlendEquation.Add; + + /** + * @see RenderState#setBlendEquationAlpha(com.jme3.material.RenderState.BlendEquationAlpha) + */ + public RenderState.BlendEquationAlpha blendEquationAlpha = RenderState.BlendEquationAlpha.InheritColor; + /** * @see RenderState#setWireframe(boolean) */ @@ -254,6 +264,8 @@ public class RenderContext { polyOffsetUnits = 0; pointSize = 1; blendMode = RenderState.BlendMode.Off; + blendEquation = RenderState.BlendEquation.Add; + blendEquationAlpha = RenderState.BlendEquationAlpha.InheritColor; wireframe = false; boundShaderProgram = 0; boundShader = null; diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java index 51d1213b3..a4a738152 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java @@ -71,6 +71,9 @@ public interface GL { public static final int GL_FLOAT = 0x1406; public static final int GL_FRAGMENT_SHADER = 0x8B30; public static final int GL_FRONT = 0x404; + public static final int GL_FUNC_ADD = 0x8006; + public static final int GL_FUNC_SUBTRACT = 0x800A; + public static final int GL_FUNC_REVERSE_SUBTRACT = 0x800B; public static final int GL_FRONT_AND_BACK = 0x408; public static final int GL_GEQUAL = 0x206; public static final int GL_GREATER = 0x204; @@ -95,6 +98,7 @@ public interface GL { public static final int GL_LINK_STATUS = 0x8B82; public static final int GL_LUMINANCE = 0x1909; public static final int GL_LUMINANCE_ALPHA = 0x190A; + public static final int GL_MAX = 0x8008; public static final int GL_MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C; public static final int GL_MAX_FRAGMENT_UNIFORM_COMPONENTS = 0x8B49; public static final int GL_MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD; @@ -105,6 +109,7 @@ public interface GL { public static final int GL_MAX_VERTEX_UNIFORM_COMPONENTS = 0x8B4A; public static final int GL_MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB; public static final int GL_MIRRORED_REPEAT = 0x8370; + public static final int GL_MIN = 0x8007; public static final int GL_NEAREST = 0x2600; public static final int GL_NEAREST_MIPMAP_LINEAR = 0x2702; public static final int GL_NEAREST_MIPMAP_NEAREST = 0x2700; @@ -184,167 +189,89 @@ public interface GL { public static final int GL_VERTEX_SHADER = 0x8B31; public static final int GL_ZERO = 0x0; - public void resetStats(); - - public void glActiveTexture(int texture); - - public void glAttachShader(int program, int shader); - - public void glBindBuffer(int target, int buffer); - - public void glBindTexture(int target, int texture); - - public void glBlendFunc(int sfactor, int dfactor); - - public void glBufferData(int target, long data_size, int usage); - - public void glBufferData(int target, FloatBuffer data, int usage); - - public void glBufferData(int target, ShortBuffer data, int usage); - - public void glBufferData(int target, ByteBuffer data, int usage); - - public void glBufferSubData(int target, long offset, FloatBuffer data); - - public void glBufferSubData(int target, long offset, ShortBuffer data); - - public void glBufferSubData(int target, long offset, ByteBuffer data); - - public void glClear(int mask); - - public void glClearColor(float red, float green, float blue, float alpha); - - public void glColorMask(boolean red, boolean green, boolean blue, boolean alpha); - - public void glCompileShader(int shader); - - public void glCompressedTexImage2D(int target, int level, int internalformat, int width, int height, int border, ByteBuffer data); - - public void glCompressedTexSubImage2D(int target, int level, int xoffset, int yoffset, int width, int height, int format, ByteBuffer data); - - public int glCreateProgram(); - - public int glCreateShader(int shaderType); - - public void glCullFace(int mode); - - public void glDeleteBuffers(IntBuffer buffers); - - public void glDeleteProgram(int program); - - public void glDeleteShader(int shader); - - public void glDeleteTextures(IntBuffer textures); - - public void glDepthFunc(int func); - - public void glDepthMask(boolean flag); - - public void glDepthRange(double nearVal, double farVal); - - public void glDetachShader(int program, int shader); - - public void glDisable(int cap); - - public void glDisableVertexAttribArray(int index); - - public void glDrawArrays(int mode, int first, int count); - - public void glDrawRangeElements(int mode, int start, int end, int count, int type, long indices); /// GL2+ - - public void glEnable(int cap); - - public void glEnableVertexAttribArray(int index); - - public void glGenBuffers(IntBuffer buffers); - - public void glGenTextures(IntBuffer textures); - - public int glGetAttribLocation(int program, String name); - - public void glGetBoolean(int pname, ByteBuffer params); - - public void glGetBufferSubData(int target, long offset, ByteBuffer data); - - public int glGetError(); - - public void glGetInteger(int pname, IntBuffer params); - - public void glGetProgram(int program, int pname, IntBuffer params); - - public String glGetProgramInfoLog(int program, int maxSize); - - public void glGetShader(int shader, int pname, IntBuffer params); - - public String glGetShaderInfoLog(int shader, int maxSize); - - public String glGetString(int name); - - public int glGetUniformLocation(int program, String name); - - public boolean glIsEnabled(int cap); - - public void glLineWidth(float width); - - public void glLinkProgram(int program); - - public void glPixelStorei(int pname, int param); - - public void glPolygonOffset(float factor, float units); - - public void glReadPixels(int x, int y, int width, int height, int format, int type, ByteBuffer data); - - public void glReadPixels(int x, int y, int width, int height, int format, int type, long offset); - - public void glScissor(int x, int y, int width, int height); - - public void glShaderSource(int shader, String[] string, IntBuffer length); - - public void glStencilFuncSeparate(int face, int func, int ref, int mask); - - public void glStencilOpSeparate(int face, int sfail, int dpfail, int dppass); - - public void glTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, ByteBuffer data); - - public void glTexParameterf(int target, int pname, float param); - - public void glTexParameteri(int target, int pname, int param); - - public void glTexSubImage2D(int target, int level, int xoffset, int yoffset, int width, int height, int format, int type, ByteBuffer data); - - public void glUniform1(int location, FloatBuffer value); - - public void glUniform1(int location, IntBuffer value); - - public void glUniform1f(int location, float v0); - - public void glUniform1i(int location, int v0); - - public void glUniform2(int location, IntBuffer value); - - public void glUniform2(int location, FloatBuffer value); - - public void glUniform2f(int location, float v0, float v1); - - public void glUniform3(int location, IntBuffer value); - - public void glUniform3(int location, FloatBuffer value); - - public void glUniform3f(int location, float v0, float v1, float v2); - - public void glUniform4(int location, FloatBuffer value); - - public void glUniform4(int location, IntBuffer value); - - public void glUniform4f(int location, float v0, float v1, float v2, float v3); - - public void glUniformMatrix3(int location, boolean transpose, FloatBuffer value); - - public void glUniformMatrix4(int location, boolean transpose, FloatBuffer value); - - public void glUseProgram(int program); - - public void glVertexAttribPointer(int index, int size, int type, boolean normalized, int stride, long pointer); - - public void glViewport(int x, int y, int width, int height); + public void resetStats(); + + public void glActiveTexture(int texture); + public void glAttachShader(int program, int shader); + public void glBindBuffer(int target, int buffer); + public void glBindTexture(int target, int texture); + public void glBlendEquationSeparate(int colorMode, int alphaMode); + public void glBlendFunc(int sfactor, int dfactor); + public void glBufferData(int target, long data_size, int usage); + public void glBufferData(int target, FloatBuffer data, int usage); + public void glBufferData(int target, ShortBuffer data, int usage); + public void glBufferData(int target, ByteBuffer data, int usage); + public void glBufferSubData(int target, long offset, FloatBuffer data); + public void glBufferSubData(int target, long offset, ShortBuffer data); + public void glBufferSubData(int target, long offset, ByteBuffer data); + public void glClear(int mask); + public void glClearColor(float red, float green, float blue, float alpha); + public void glColorMask(boolean red, boolean green, boolean blue, boolean alpha); + public void glCompileShader(int shader); + public void glCompressedTexImage2D(int target, int level, int internalformat, int width, int height, int border, ByteBuffer data); + public void glCompressedTexSubImage2D(int target, int level, int xoffset, int yoffset, int width, int height, int format, ByteBuffer data); + public int glCreateProgram(); + public int glCreateShader(int shaderType); + public void glCullFace(int mode); + public void glDeleteBuffers(IntBuffer buffers); + public void glDeleteProgram(int program); + public void glDeleteShader(int shader); + public void glDeleteTextures(IntBuffer textures); + public void glDepthFunc(int func); + public void glDepthMask(boolean flag); + public void glDepthRange(double nearVal, double farVal); + public void glDetachShader(int program, int shader); + public void glDisable(int cap); + public void glDisableVertexAttribArray(int index); + public void glDrawArrays(int mode, int first, int count); + + public void glDrawRangeElements(int mode, int start, int end, int count, int type, long indices); /// GL2+ + public void glEnable(int cap); + public void glEnableVertexAttribArray(int index); + public void glGenBuffers(IntBuffer buffers); + public void glGenTextures(IntBuffer textures); + public int glGetAttribLocation(int program, String name); + public void glGetBoolean(int pname, ByteBuffer params); + public void glGetBufferSubData(int target, long offset, ByteBuffer data); + public int glGetError(); + public void glGetInteger(int pname, IntBuffer params); + public void glGetProgram(int program, int pname, IntBuffer params); + public String glGetProgramInfoLog(int program, int maxSize); + public void glGetShader(int shader, int pname, IntBuffer params); + public String glGetShaderInfoLog(int shader, int maxSize); + public String glGetString(int name); + public int glGetUniformLocation(int program, String name); + public boolean glIsEnabled(int cap); + public void glLineWidth(float width); + public void glLinkProgram(int program); + public void glPixelStorei(int pname, int param); + public void glPolygonOffset(float factor, float units); + public void glReadPixels(int x, int y, int width, int height, int format, int type, ByteBuffer data); + public void glReadPixels(int x, int y, int width, int height, int format, int type, long offset); + public void glScissor(int x, int y, int width, int height); + public void glShaderSource(int shader, String[] string, IntBuffer length); + public void glStencilFuncSeparate(int face, int func, int ref, int mask); + public void glStencilOpSeparate(int face, int sfail, int dpfail, int dppass); + public void glTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, ByteBuffer data); + public void glTexParameterf(int target, int pname, float param); + public void glTexParameteri(int target, int pname, int param); + public void glTexSubImage2D(int target, int level, int xoffset, int yoffset, int width, int height, int format, int type, ByteBuffer data); + public void glUniform1(int location, FloatBuffer value); + public void glUniform1(int location, IntBuffer value); + public void glUniform1f(int location, float v0); + public void glUniform1i(int location, int v0); + public void glUniform2(int location, IntBuffer value); + public void glUniform2(int location, FloatBuffer value); + public void glUniform2f(int location, float v0, float v1); + public void glUniform3(int location, IntBuffer value); + public void glUniform3(int location, FloatBuffer value); + public void glUniform3f(int location, float v0, float v1, float v2); + public void glUniform4(int location, FloatBuffer value); + public void glUniform4(int location, IntBuffer value); + public void glUniform4f(int location, float v0, float v1, float v2, float v3); + public void glUniformMatrix3(int location, boolean transpose, FloatBuffer value); + public void glUniformMatrix4(int location, boolean transpose, FloatBuffer value); + public void glUseProgram(int program); + public void glVertexAttribPointer(int index, int size, int type, boolean normalized, int stride, long pointer); + public void glViewport(int x, int y, int width, int height); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugDesktop.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugDesktop.java index fd18cc7ff..44dc3687a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugDesktop.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugDesktop.java @@ -100,4 +100,9 @@ public class GLDebugDesktop extends GLDebugES implements GL2, GL3, GL4 { gl3.glFramebufferTextureLayer(param1, param2, param3, param4, param5); checkError(); } + + public void glBlendEquationSeparate(int colorMode, int alphaMode) { + gl.glBlendEquationSeparate(colorMode, alphaMode); + checkError(); + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugES.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugES.java index 2348bd3cd..ed6b336f8 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugES.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugES.java @@ -560,4 +560,9 @@ public class GLDebugES extends GLDebug implements GL, GLFbo, GLExt { checkError(); return sync; } + + public void glBlendEquationSeparate(int colorMode, int alphaMode) { + gl.glBlendEquationSeparate(colorMode, alphaMode); + checkError(); + } } 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 1c5caff89..70d25ccd4 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 @@ -750,6 +750,19 @@ public final class GLRenderer implements Renderer { 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(); + } } context.blendMode = state.getBlendMode(); @@ -800,6 +813,41 @@ public final class GLRenderer implements Renderer { } } + private int convertBlendEquation(RenderState.BlendEquation blendEquation) { + switch (blendEquation) { + case Add: + return GL2.GL_FUNC_ADD; + case Subtract: + return GL2.GL_FUNC_SUBTRACT; + case ReverseSubtract: + return GL2.GL_FUNC_REVERSE_SUBTRACT; + case Min: + return GL2.GL_MIN; + case Max: + return GL2.GL_MAX; + default: + throw new UnsupportedOperationException("Unrecognized blend operation: " + blendEquation); + } + } + + private int convertBlendEquationAlpha(RenderState.BlendEquationAlpha blendEquationAlpha) { + //Note: InheritColor mode should already be handled, that is why it does not belong the the switch case. + switch (blendEquationAlpha) { + case Add: + return GL2.GL_FUNC_ADD; + case Subtract: + return GL2.GL_FUNC_SUBTRACT; + case ReverseSubtract: + return GL2.GL_FUNC_REVERSE_SUBTRACT; + case Min: + return GL2.GL_MIN; + case Max: + return GL2.GL_MAX; + default: + throw new UnsupportedOperationException("Unrecognized alpha blend operation: " + blendEquationAlpha); + } + } + private int convertStencilOperation(StencilOperation stencilOp) { switch (stencilOp) { case Keep: diff --git a/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java b/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java index 31039502f..18b79a3b9 100644 --- a/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java +++ b/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java @@ -36,6 +36,7 @@ import com.jme3.material.logic.SinglePassLightingLogic; import com.jme3.material.logic.DefaultTechniqueDefLogic; import com.jme3.asset.*; import com.jme3.material.*; +import com.jme3.material.RenderState.BlendEquation; import com.jme3.material.RenderState.BlendMode; import com.jme3.material.RenderState.FaceCullMode; import com.jme3.material.TechniqueDef.LightMode; @@ -448,6 +449,10 @@ public class J3MLoader implements AssetLoader { renderState.setDepthTest(parseBoolean(split[1])); }else if (split[0].equals("Blend")){ renderState.setBlendMode(BlendMode.valueOf(split[1])); + }else if (split[0].equals("BlendEquation")){ + renderState.setBlendEquation(BlendEquation.valueOf(split[1])); + }else if (split[0].equals("BlendEquationAlpha")){ + renderState.setBlendEquationAlpha(RenderState.BlendEquationAlpha.valueOf(split[1])); }else if (split[0].equals("AlphaTestFalloff")){ // Ignore for backwards compatbility }else if (split[0].equals("PolyOffset")){ diff --git a/jme3-examples/src/main/java/jme3test/renderer/TestBlendEquations.java b/jme3-examples/src/main/java/jme3test/renderer/TestBlendEquations.java new file mode 100644 index 000000000..9335912b6 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/renderer/TestBlendEquations.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2009-2016 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.renderer; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.material.RenderState; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Quad; + +public class TestBlendEquations extends SimpleApplication { + + public static void main(String[] args) { + TestBlendEquations app = new TestBlendEquations(); + app.start(); + } + + public void simpleInitApp() { + Geometry teaGeom = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj"); + teaGeom.scale(6); + teaGeom.getMaterial().getAdditionalRenderState().setBlendEquation(RenderState.BlendEquation.Add); + teaGeom.move(0, -2f, 0); + + DirectionalLight dl = new DirectionalLight(); + dl.setColor(ColorRGBA.Red); + dl.setDirection(Vector3f.UNIT_XYZ.negate()); + + rootNode.addLight(dl); + rootNode.attachChild(teaGeom); + + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", new ColorRGBA(0.5f, 0f, 1f, 0.3f)); + mat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Color); + mat.getAdditionalRenderState().setBlendEquation(RenderState.BlendEquation.Subtract); + + Geometry geo = new Geometry("BottomLeft", new Quad(guiViewPort.getCamera().getWidth() / 2, guiViewPort.getCamera().getHeight() / 2)); + geo.setMaterial(mat); + geo.setQueueBucket(RenderQueue.Bucket.Gui); + geo.setLocalTranslation(0, 0, 1); + + guiNode.attachChild(geo); + + Material m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + m.getAdditionalRenderState().setBlendEquation(RenderState.BlendEquation.ReverseSubtract); + m.setColor("Color", new ColorRGBA(0.0f, 1f, 1.f, 1f)); + m.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.AlphaAdditive); + + geo = new Geometry("BottomRight", new Quad(guiViewPort.getCamera().getWidth() / 2, guiViewPort.getCamera().getHeight() / 2)); + geo.setMaterial(m); + geo.setQueueBucket(RenderQueue.Bucket.Gui); + geo.setLocalTranslation(guiViewPort.getCamera().getWidth() / 2, 0, 1); + + guiNode.attachChild(geo); + + m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + m.getAdditionalRenderState().setBlendEquation(RenderState.BlendEquation.Min); + m.setColor("Color", new ColorRGBA(0.3f, 0f, 0.1f, 0.3f)); + m.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Additive); + + geo = new Geometry("TopRight", new Quad(guiViewPort.getCamera().getWidth() / 2, guiViewPort.getCamera().getHeight() / 2)); + geo.setMaterial(m); + geo.setQueueBucket(RenderQueue.Bucket.Gui); + geo.setLocalTranslation(guiViewPort.getCamera().getWidth() / 2, guiViewPort.getCamera().getHeight() / 2, 1); + + guiNode.attachChild(geo); + + geo = new Geometry("OverTeaPot", new Quad(guiViewPort.getCamera().getWidth() / 2, guiViewPort.getCamera().getHeight() / 2)); + geo.setMaterial(mat); + geo.setQueueBucket(RenderQueue.Bucket.Transparent); + geo.setLocalTranslation(0, -100, 5); + + rootNode.attachChild(geo); + + } + + +} diff --git a/jme3-ios/src/main/java/com/jme3/renderer/ios/IosGL.java b/jme3-ios/src/main/java/com/jme3/renderer/ios/IosGL.java index a9398f159..958163596 100644 --- a/jme3-ios/src/main/java/com/jme3/renderer/ios/IosGL.java +++ b/jme3-ios/src/main/java/com/jme3/renderer/ios/IosGL.java @@ -78,6 +78,11 @@ public class IosGL implements GL, GLExt, GLFbo { checkLimit(buffer); return buffer.limit() / elementSize; } + + @Override + public void glBlendEquationSeparate(int colorMode, int alphaMode) { + JmeIosGLES.glBlendEquationSeparate(colorMode, alphaMode); + } private int toArray(IntBuffer buffer) { int remain = buffer.remaining(); diff --git a/jme3-ios/src/main/java/com/jme3/renderer/ios/JmeIosGLES.java b/jme3-ios/src/main/java/com/jme3/renderer/ios/JmeIosGLES.java index 0811dc422..b8ec75a77 100644 --- a/jme3-ios/src/main/java/com/jme3/renderer/ios/JmeIosGLES.java +++ b/jme3-ios/src/main/java/com/jme3/renderer/ios/JmeIosGLES.java @@ -142,6 +142,7 @@ public class JmeIosGLES { public static native void glBindRenderbuffer(int target, int renderbuffer); public static native void glBindTexture(int target, int texture); // public static native void glBindVertexArray // TODO: Investigate this + public static native void glBlendEquationSeparate(int colorMode, int alphaMode); public static native void glBlendFunc(int sfactor, int dfactor); public static native void glBufferData(int target, int size, Buffer data, int usage); public static native void glBufferData2(int target, int size, byte[] data, int offset, int usage); diff --git a/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglGL.java b/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglGL.java index 2ca2fb266..8b222d751 100644 --- a/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglGL.java +++ b/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglGL.java @@ -78,6 +78,11 @@ public class JoglGL implements GL, GL2, GL3, GL4 { GLContext.getCurrentGL().glBindTexture(param1, param2); } + @Override + public void glBlendEquationSeparate(int colorMode, int alphaMode){ + GLContext.getCurrentGL().glBlendEquationSeparate(colorMode, alphaMode); + } + @Override public void glBlendFunc(int param1, int param2) { GLContext.getCurrentGL().glBlendFunc(param1, param2); diff --git a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java index 6f640042f..abc419c41 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java +++ b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java @@ -50,6 +50,10 @@ public final class LwjglGL implements GL, GL2, GL3, GL4 { GL11.glBindTexture(param1, param2); } + public void glBlendEquationSeparate(int colorMode, int alphaMode){ + GL20.glBlendEquationSeparate(colorMode,alphaMode); + } + public void glBlendFunc(int param1, int param2) { GL11.glBlendFunc(param1, param2); } diff --git a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java index 25de6b148..10358c009 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java @@ -79,6 +79,10 @@ public class LwjglGL implements GL, GL2, GL3, GL4 { GL11.glBindTexture(param1, param2); } + public void glBlendEquationSeparate(int colorMode, int alphaMode){ + GL20.glBlendEquationSeparate(colorMode,alphaMode); + } + public void glBlendFunc(int param1, int param2) { GL11.glBlendFunc(param1, param2); }