浏览代码

Merge branch 'BorealFeast-master'

Kirill Vainer 9 年之前
父节点
当前提交
0ab73359ca

+ 5 - 0
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);
+    }
 }

+ 188 - 3
jme3-core/src/main/java/com/jme3/material/RenderState.java

@@ -120,6 +120,92 @@ public class RenderState implements Cloneable, Savable {
         Always
     }
 
+    /**
+     * <code>BlendEquation</code> 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
+    }
+    
+    /**
+     * <code>BlendEquationAlpha</code> 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
+    }
+
     /**
      * <code>BlendMode</code> 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.
+     * <p>
+     * When blending is enabled, (<code>blendMode</code> 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:
+     * <br/>
+     * <code>Result = Source Color + Destination Color</code>
+     * <br/>
+     * 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:
+     * <br/>
+     * <code>Result = Source Color - Destination Color</code>
+     *
+     * @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.
+     * <p>
+     * When blending is enabled, (<code>blendMode</code> 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:
+     * <br/>
+     * <code>Result = Source Alpha + Destination Alpha</code>
+     * <br/>
+     * 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:
+     * <br/>
+     * <code>Result = Source Alpha - Destination Alpha</code>
+     *
+     * @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

+ 12 - 0
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;

+ 90 - 163
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);
 }

+ 5 - 0
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();
+    }
 }

+ 5 - 0
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();
+    }
 }

+ 48 - 0
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:

+ 5 - 0
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")){

+ 110 - 0
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);
+
+    }
+
+
+}

+ 5 - 0
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();

+ 1 - 0
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);

+ 5 - 0
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);

+ 4 - 0
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);
     }

+ 4 - 0
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);
     }