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);
}