diff --git a/engine/src/core/com/jme3/material/RenderState.java b/engine/src/core/com/jme3/material/RenderState.java index 27be6eda6..f549f39be 100644 --- a/engine/src/core/com/jme3/material/RenderState.java +++ b/engine/src/core/com/jme3/material/RenderState.java @@ -36,26 +36,100 @@ import com.jme3.export.JmeImporter; import com.jme3.export.InputCapsule; import com.jme3.export.OutputCapsule; import com.jme3.export.Savable; +import com.jme3.scene.Mesh; import java.io.IOException; +/** + * RenderState specifies material rendering properties that cannot + * be controlled by a shader on a {@link Material}. The properties + * allow manipulation of rendering features such as depth testing, alpha blending, + * face culling, stencil operations, and much more. + * + * @author Kirill Vainer + */ public class RenderState implements Cloneable, Savable { + /** + * The DEFAULT render state is the one used by default + * on all materials unless changed otherwise by the user. + * + *

+ * It has the following properties: + *

+ */ public static final RenderState DEFAULT = new RenderState(); + + /** + * The NULL render state is identical to the {@link RenderState#DEFAULT} + * render state except that depth testing and face culling are disabled. + */ public static final RenderState NULL = new RenderState(); + + /** + * The ADDITIONAL render state is identical to the + * {@link RenderState#DEFAULT} render state except that all apply + * values are set to false. This allows the ADDITIONAL render + * state to be combined with other state but only influencing values + * that were changed from the original. + */ public static final RenderState ADDITIONAL = new RenderState(); - public enum TestFunc { + /** + * TestFunction specifies the testing function for stencil test + * function and alpha test function. + * + *

The functions work similarly as described except that for stencil + * test function, the reference value given in the stencil command is + * the input value while the reference is the value already in the stencil + * buffer. + */ + public enum TestFunction { + /** + * The test always fails + */ Never, + /** + * The test succeeds if the input value is equal to the reference value. + */ Equal, + /** + * The test succeeds if the input value is less than the reference value. + */ Less, + /** + * The test succeeds if the input value is less than or equal to + * the reference value. + */ LessOrEqual, + /** + * The test succeeds if the input value is greater than the reference value. + */ Greater, + /** + * The test succeeds if the input value is greater than or equal to + * the reference value. + */ GreaterOrEqual, + /** + * The test succeeds if the input value does not equal the + * reference value. + */ NotEqual, - Always, - } + /** + * The test always passes + */ + Always,} + /** + * BlendMode specifies the blending operation to use. + * + * @see RenderState#setBlendMode(com.jme3.material.RenderState.BlendMode) + */ public enum BlendMode { /** @@ -64,52 +138,57 @@ public class RenderState implements Cloneable, Savable { Off, /** * Additive blending. For use with glows and particle emitters. - * + *

* Result = Source Color + Destination Color */ Additive, /** * Premultiplied alpha blending, for use with premult alpha textures. - * - * Result = Source Color + (Dest Color * 1 - Source Alpha) + *

+ * Result = Source Color + (Dest Color * (1 - Source Alpha) ) */ PremultAlpha, /** * Additive blending that is multiplied with source alpha. * For use with glows and particle emitters. - * + *

* Result = (Source Alpha * Source Color) + Dest Color */ AlphaAdditive, /** * Color blending, blends in color from dest color * using source color. - * + *

* Result = Source Color + (1 - Source Color) * Dest Color */ Color, /** * Alpha blending, interpolates to source color from dest color * using source alpha. - * + *

* Result = Source Alpha * Source Color + * (1 - Source Alpha) * Dest Color */ Alpha, /** * Multiplies the source and dest colors. - * + *

* Result = Source Color * Dest Color */ Modulate, /** * Multiplies the source and dest colors then doubles the result. - * + *

* Result = 2 * Source Color * Dest Color */ ModulateX2 } + /** + * FaceCullMode specifies the criteria for faces to be culled. + * + * @see RenderState#setFaceCullMode(com.jme3.material.RenderState.FaceCullMode) + */ public enum FaceCullMode { /** @@ -130,29 +209,60 @@ public class RenderState implements Cloneable, Savable { FrontAndBack } - + /** + * StencilOperation specifies the stencil operation to use + * in a certain scenario as specified in {@link RenderState#setStencil(boolean, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilFunction, + * com.jme3.material.RenderState.StencilFunction)} + */ public enum StencilOperation { - Keep, //keep the current value - Zero, //set the value to 0 - Replace, //sets the buffer to + + /** + * Keep the current value. + */ + Keep, + /** + * Set the value to 0 + */ + Zero, + /** + * Replace the value in the stencil buffer with the reference value. + */ + Replace, + + /** + * Increment the value in the stencil buffer, clamp once reaching + * the maximum value. + */ Increment, + + /** + * Increment the value in the stencil buffer and wrap to 0 when + * reaching the maximum value. + */ IncrementWrap, + /** + * Decrement the value in the stencil buffer and clamp once reaching 0. + */ Decrement, + /** + * Decrement the value in the stencil buffer and wrap to the maximum + * value when reaching 0. + */ DecrementWrap, + + /** + * Does a bitwise invert of the value in the stencil buffer. + */ Invert } - public enum StencilFunction { - Never, - Less, - LessEqual, - Greater, - GreaterEqual, - Equal, - NotEqual, - Always - } - static { NULL.cullMode = FaceCullMode.Off; NULL.depthTest = false; @@ -170,38 +280,49 @@ public class RenderState implements Cloneable, Savable { ADDITIONAL.applyAlphaFallOff = false; ADDITIONAL.applyPolyOffset = false; } - + boolean pointSprite = false; boolean applyPointSprite = true; + boolean wireframe = false; boolean applyWireFrame = true; + FaceCullMode cullMode = FaceCullMode.Back; boolean applyCullMode = true; + boolean depthWrite = true; boolean applyDepthWrite = true; + boolean depthTest = true; boolean applyDepthTest = true; + boolean colorWrite = true; boolean applyColorWrite = true; + BlendMode blendMode = BlendMode.Off; boolean applyBlendMode = true; + boolean alphaTest = false; boolean applyAlphaTest = true; + float alphaFallOff = 0; boolean applyAlphaFallOff = true; - boolean offsetEnabled = false; - boolean applyPolyOffset = true; + float offsetFactor = 0; float offsetUnits = 0; + boolean offsetEnabled = false; + boolean applyPolyOffset = true; + boolean stencilTest = false; + boolean applyStencilTest = false; StencilOperation frontStencilStencilFailOperation = StencilOperation.Keep; StencilOperation frontStencilDepthFailOperation = StencilOperation.Keep; StencilOperation frontStencilDepthPassOperation = StencilOperation.Keep; StencilOperation backStencilStencilFailOperation = StencilOperation.Keep; StencilOperation backStencilDepthFailOperation = StencilOperation.Keep; StencilOperation backStencilDepthPassOperation = StencilOperation.Keep; - StencilFunction frontStencilFunction = StencilFunction.Always; - StencilFunction backStencilFunction = StencilFunction.Always; + TestFunction frontStencilFunction = TestFunction.Always; + TestFunction backStencilFunction = TestFunction.Always; public void write(JmeExporter ex) throws IOException { OutputCapsule oc = ex.getCapsule(this); @@ -224,8 +345,8 @@ public class RenderState implements Cloneable, Savable { oc.write(backStencilStencilFailOperation, "frontStencilStencilFailOperation", StencilOperation.Keep); oc.write(backStencilDepthFailOperation, "backStencilDepthFailOperation", StencilOperation.Keep); oc.write(backStencilDepthPassOperation, "backStencilDepthPassOperation", StencilOperation.Keep); - oc.write(frontStencilFunction, "frontStencilFunction", StencilFunction.Always); - oc.write(backStencilFunction, "backStencilFunction", StencilFunction.Always); + oc.write(frontStencilFunction, "frontStencilFunction", TestFunction.Always); + oc.write(backStencilFunction, "backStencilFunction", TestFunction.Always); } public void read(JmeImporter im) throws IOException { @@ -249,10 +370,15 @@ public class RenderState implements Cloneable, Savable { backStencilStencilFailOperation = ic.readEnum("backStencilStencilFailOperation", StencilOperation.class, StencilOperation.Keep); backStencilDepthFailOperation = ic.readEnum("backStencilDepthFailOperation", StencilOperation.class, StencilOperation.Keep); backStencilDepthPassOperation = ic.readEnum("backStencilDepthPassOperation", StencilOperation.class, StencilOperation.Keep); - frontStencilFunction = ic.readEnum("frontStencilFunction", StencilFunction.class, StencilFunction.Always); - backStencilFunction = ic.readEnum("backStencilFunction", StencilFunction.class, StencilFunction.Always); + frontStencilFunction = ic.readEnum("frontStencilFunction", TestFunction.class, TestFunction.Always); + backStencilFunction = ic.readEnum("backStencilFunction", TestFunction.class, TestFunction.Always); } + /** + * Create a clone of this RenderState + * + * @return Clone of this render state. + */ @Override public RenderState clone() { try { @@ -262,69 +388,161 @@ public class RenderState implements Cloneable, Savable { } } - public boolean isPointSprite() { - return pointSprite; - } - + /** + * Enables point sprite mode. + * + *

When point sprite is enabled, any meshes + * with the type of {@link Mesh#Mode#Points} will be rendered as 2D quads + * with texturing enabled. Fragment shaders can write to the + * gl_PointCoord variable to manipulate the texture coordinate + * for each pixel. The size of the 2D quad can be controlled by writing + * to the gl_PointSize variable in the vertex shader. + * + * @param pointSprite Enables Point Sprite mode. + */ public void setPointSprite(boolean pointSprite) { applyPointSprite = true; this.pointSprite = pointSprite; } - public boolean isColorWrite() { - return colorWrite; - } - - public float getPolyOffsetFactor() { - return offsetFactor; - } - - public float getPolyOffsetUnits() { - return offsetUnits; - } - - public boolean isPolyOffset() { - return offsetEnabled; - } - - public float getAlphaFallOff() { - return alphaFallOff; - } - + /** + * Sets the alpha fall off value for alpha testing. + * + *

If the pixel's alpha value is greater than the + * alphaFallOff then the pixel will be rendered, otherwise + * the pixel will be discarded. + * + * @param alphaFallOff The alpha of all rendered pixels must be higher + * than this value to be rendered. + * + * @see RenderState#setAlphaTest(boolean) + */ public void setAlphaFallOff(float alphaFallOff) { applyAlphaFallOff = true; this.alphaFallOff = alphaFallOff; } - public boolean isAlphaTest() { - return alphaTest; - } - + /** + * Enable alpha testing. + * + *

When alpha testing is enabled, all input pixels' alpha are compared + * to the constant alpha falloff. If the input alpha is greater than + * the falloff, the pixel will be rendered, otherwise it will be discarded. + * + * @param alphaTest Set to true to enable alpha testing. + * + * @see RenderState#setAlphaFallOff(float) + */ public void setAlphaTest(boolean alphaTest) { applyAlphaTest = true; this.alphaTest = alphaTest; } - public FaceCullMode getFaceCullMode() { - return cullMode; - } - + /** + * Enable writing color. + * + *

When color write is enabled, the result of a fragment shader, the + * gl_FragColor, will be rendered into the color buffer + * (including alpha). + * + * @param colorWrite Set to true to enable color writing. + */ public void setColorWrite(boolean colorWrite) { applyColorWrite = true; this.colorWrite = colorWrite; } /** - * Offsets the on-screen z-order of the material's polygons, to combat visual artefacts like - * stitching, bleeding and z-fighting for overlapping polygons. - * Factor and units are summed to produce the depth offset. This offset is applied in screen space, - * typically with positive Z pointing into the screen. - * Typical values are (1.0f, 1.0f) or (-1.0f, -1.0f) - * - * @see http://www.opengl.org/resources/faq/technical/polygonoffset.htm - * @param factor scales the maximum Z slope, with respect to X or Y of the polygon - * @param units scales the minimum resolvable depth buffer value - **/ + * Set the face culling mode. + * + *

See the {@link FaceCullMode} enum on what each value does. + * Face culling will project the triangle's points onto the screen + * and determine if the triangle is in counter-clockwise order or + * clockwise order. If a triangle is in counter-clockwise order, then + * it is considered a front-facing triangle, otherwise, it is considered + * a back-facing triangle. + * + * @param cullMode the face culling mode. + */ + public void setFaceCullMode(FaceCullMode cullMode) { + applyCullMode = true; + this.cullMode = cullMode; + } + + /** + * Set the blending mode. + * + *

When blending is enabled, (blendMode is not BlendMode.Off) + * the input pixel will be blended with the pixel + * already in the color buffer. The blending operation is determined + * by the {@link BlendMode}. For example, the {@link BlendMode#Additive} + * will add the input pixel's color to the color already in the color buffer: + *
+ * Result = Source Color + Destination Color + * + * @param blendMode The blend mode to use. Set to {@link BlendMode#Off} + * to disable blending. + */ + public void setBlendMode(BlendMode blendMode) { + applyBlendMode = true; + this.blendMode = blendMode; + } + + /** + * Enable depth testing. + * + *

When depth testing is enabled, a pixel must pass the depth test + * before it is written to the color buffer. + * The input pixel's depth value must be less than or equal than + * the value already in the depth buffer to pass the depth test. + * + * @param depthTest Enable or disable depth testing. + */ + public void setDepthTest(boolean depthTest) { + applyDepthTest = true; + this.depthTest = depthTest; + } + + /** + * Enable depth writing. + * + *

After passing the {@link RenderState#setDepthTest(boolean) depth test}, + * a pixel's depth value will be written into the depth buffer if + * depth writing is enabled. + * + * @param depthWrite True to enable writing to the depth buffer. + */ + public void setDepthWrite(boolean depthWrite) { + applyDepthWrite = true; + this.depthWrite = depthWrite; + } + + /** + * Enables wireframe rendering mode. + * + *

When in wireframe mode, {@link Mesh meshes} rendered in triangle mode + * will not be solid, but instead, only the edges of the triangles + * will be rendered. + * + * @param wireframe True to enable wireframe mode. + */ + public void setWireframe(boolean wireframe) { + applyWireFrame = true; + this.wireframe = wireframe; + } + + /** + * Offsets the on-screen z-order of the material's polygons, to combat visual artefacts like + * stitching, bleeding and z-fighting for overlapping polygons. + * Factor and units are summed to produce the depth offset. + * This offset is applied in screen space, + * typically with positive Z pointing into the screen. + * Typical values are (1.0f, 1.0f) or (-1.0f, -1.0f) + * + * @see http://www.opengl.org/resources/faq/technical/polygonoffset.htm + * @param factor scales the maximum Z slope, with respect to X or Y of the polygon + * @param units scales the minimum resolvable depth buffer value + **/ public void setPolyOffset(float factor, float units) { applyPolyOffset = true; offsetEnabled = true; @@ -332,6 +550,32 @@ public class RenderState implements Cloneable, Savable { offsetUnits = units; } + /** + * Enable stencil testing. + * + *

Stencil testing can be used to filter pixels according to the stencil + * buffer. Objects can be rendered with some stencil operation to manipulate + * the values in the stencil buffer, then, other objects can be rendered + * to test against the values written previously. + * + * @param enabled Set to true to enable stencil functionality. If false + * all other parameters are ignored. + * + * @param _frontStencilStencilFailOperation Sets the operation to occur when + * a front-facing triangle fails the front stencil function. + * @param _frontStencilDepthFailOperation Sets the operation to occur when + * a front-facing triangle fails the depth test. + * @param _frontStencilDepthPassOperation Set the operation to occur when + * a front-facing triangle passes the depth test. + * @param _backStencilStencilFailOperation Set the operation to occur when + * a back-facing triangle fails the back stencil function. + * @param _backStencilDepthFailOperation Set the operation to occur when + * a back-facing triangle fails the depth test. + * @param _backStencilDepthPassOperation Set the operation to occur when + * a back-facing triangle passes the depth test. + * @param _frontStencilFunction Set the test function for front-facing triangles. + * @param _backStencilFunction Set the test function for back-facing triangles. + */ public void setStencil(boolean enabled, StencilOperation _frontStencilStencilFailOperation, StencilOperation _frontStencilDepthFailOperation, @@ -339,10 +583,11 @@ public class RenderState implements Cloneable, Savable { StencilOperation _backStencilStencilFailOperation, StencilOperation _backStencilDepthFailOperation, StencilOperation _backStencilDepthPassOperation, - StencilFunction _frontStencilFunction, - StencilFunction _backStencilFunction){ + TestFunction _frontStencilFunction, + TestFunction _backStencilFunction) { stencilTest = enabled; + applyStencilTest = true; this.frontStencilStencilFailOperation = _frontStencilStencilFailOperation; this.frontStencilDepthFailOperation = _frontStencilDepthFailOperation; this.frontStencilDepthPassOperation = _frontStencilDepthPassOperation; @@ -353,61 +598,298 @@ public class RenderState implements Cloneable, Savable { this.backStencilFunction = _backStencilFunction; } + /** + * Check if stencil test is enabled. + * + * @return True if stencil test is enabled. + */ public boolean isStencilTest() { return stencilTest; } - public StencilOperation getFrontStencilStencilFailOperation(){ return frontStencilStencilFailOperation; } - public StencilOperation getFrontStencilDepthFailOperation(){ return frontStencilDepthFailOperation; } - public StencilOperation getFrontStencilDepthPassOperation(){ return frontStencilDepthPassOperation; } - public StencilOperation getBackStencilStencilFailOperation(){ return backStencilStencilFailOperation; } - public StencilOperation getBackStencilDepthFailOperation(){ return backStencilDepthFailOperation; } - public StencilOperation getBackStencilDepthPassOperation(){ return backStencilDepthPassOperation; } + /** + * Retrieve the front stencil fail operation. + * + * @return the front stencil fail operation. + * + * @see RenderState#setStencil(boolean, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.TestFunction, + * com.jme3.material.RenderState.TestFunction) + */ + public StencilOperation getFrontStencilStencilFailOperation() { + return frontStencilStencilFailOperation; + } - public StencilFunction getFrontStencilFunction(){ return frontStencilFunction; } - public StencilFunction getBackStencilFunction(){ return backStencilFunction; } + /** + * Retrieve the front depth test fail operation. + * + * @return the front depth test fail operation. + * + * @see RenderState#setStencil(boolean, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.TestFunction, + * com.jme3.material.RenderState.TestFunction) + */ + public StencilOperation getFrontStencilDepthFailOperation() { + return frontStencilDepthFailOperation; + } - public void setFaceCullMode(FaceCullMode cullMode) { - applyCullMode = true; - this.cullMode = cullMode; + /** + * Retrieve the front depth test pass operation. + * + * @return the front depth test pass operation. + * + * @see RenderState#setStencil(boolean, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.TestFunction, + * com.jme3.material.RenderState.TestFunction) + */ + public StencilOperation getFrontStencilDepthPassOperation() { + return frontStencilDepthPassOperation; + } + + /** + * Retrieve the back stencil fail operation. + * + * @return the back stencil fail operation. + * + * @see RenderState#setStencil(boolean, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.TestFunction, + * com.jme3.material.RenderState.TestFunction) + */ + public StencilOperation getBackStencilStencilFailOperation() { + return backStencilStencilFailOperation; } + /** + * Retrieve the back depth test fail operation. + * + * @return the back depth test fail operation. + * + * @see RenderState#setStencil(boolean, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.TestFunction, + * com.jme3.material.RenderState.TestFunction) + */ + public StencilOperation getBackStencilDepthFailOperation() { + return backStencilDepthFailOperation; + } + + /** + * Retrieve the back depth test pass operation. + * + * @return the back depth test pass operation. + * + * @see RenderState#setStencil(boolean, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.TestFunction, + * com.jme3.material.RenderState.TestFunction) + */ + public StencilOperation getBackStencilDepthPassOperation() { + return backStencilDepthPassOperation; + } + + /** + * Retrieve the front stencil function. + * + * @return the front stencil function. + * + * @see RenderState#setStencil(boolean, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.TestFunction, + * com.jme3.material.RenderState.TestFunction) + */ + public TestFunction getFrontStencilFunction() { + return frontStencilFunction; + } + + /** + * Retrieve the back stencil function. + * + * @return the back stencil function. + * + * @see RenderState#setStencil(boolean, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.StencilOperation, + * com.jme3.material.RenderState.TestFunction, + * com.jme3.material.RenderState.TestFunction) + */ + public TestFunction getBackStencilFunction() { + return backStencilFunction; + } + + /** + * Retrieve the blend mode. + * + * @return the blend mode. + */ public BlendMode getBlendMode() { return blendMode; } - public void setBlendMode(BlendMode blendMode) { - applyBlendMode = true; - this.blendMode = blendMode; + /** + * Check if point sprite mode is enabled + * + * @return True if point sprite mode is enabled. + * + * @see RenderState#setPointSprite(boolean) + */ + public boolean isPointSprite() { + return pointSprite; + } + + /** + * Check if alpha test is enabled. + * + * @return True if alpha test is enabled. + * + * @see RenderState#setAlphaTest(boolean) + */ + public boolean isAlphaTest() { + return alphaTest; } + /** + * Retrieve the face cull mode. + * + * @return the face cull mode. + * + * @see RenderState#setFaceCullMode(com.jme3.material.RenderState.FaceCullMode) + */ + public FaceCullMode getFaceCullMode() { + return cullMode; + } + + /** + * Check if depth test is enabled. + * + * @return True if depth test is enabled. + * + * @see RenderState#setDepthTest(boolean) + */ public boolean isDepthTest() { return depthTest; } - public void setDepthTest(boolean depthTest) { - applyDepthTest = true; - this.depthTest = depthTest; - } - + /** + * Check if depth write is enabled. + * + * @return True if depth write is enabled. + * + * @see RenderState#setDepthWrite(boolean) + */ public boolean isDepthWrite() { return depthWrite; } - public void setDepthWrite(boolean depthWrite) { - applyDepthWrite = true; - this.depthWrite = depthWrite; - } - + /** + * Check if wireframe mode is enabled. + * + * @return True if wireframe mode is enabled. + * + * @see RenderState#setWireframe(boolean) + */ public boolean isWireframe() { return wireframe; } + + /** + * Check if color writing is enabled. + * + * @return True if color writing is enabled. + * + * @see RenderState#setColorWrite(boolean) + */ + public boolean isColorWrite() { + return colorWrite; + } - public void setWireframe(boolean wireframe) { - applyWireFrame = true; - this.wireframe = wireframe; + /** + * Retrieve the poly offset factor value. + * + * @return the poly offset factor value. + * + * @see RenderState#setPolyOffset(float, float) + */ + public float getPolyOffsetFactor() { + return offsetFactor; + } + + /** + * Retrieve the poly offset units value. + * + * @return the poly offset units value. + * + * @see RenderState#setPolyOffset(float, float) + */ + public float getPolyOffsetUnits() { + return offsetUnits; } + /** + * Check if polygon offset is enabled. + * + * @return True if polygon offset is enabled. + * + * @see RenderState#setPolyOffset(float, float) + */ + public boolean isPolyOffset() { + return offsetEnabled; + } + + /** + * Retrieve the alpha falloff value. + * + * @return the alpha falloff value. + * + * @see RenderState#setAlphaFallOff(float) + */ + public float getAlphaFallOff() { + return alphaFallOff; + } + +/* public boolean isApplyAlphaFallOff() { return applyAlphaFallOff; } @@ -447,73 +929,100 @@ public class RenderState implements Cloneable, Savable { public boolean isApplyWireFrame() { return applyWireFrame; } - - public RenderState copyMergedTo(RenderState additionalState,RenderState state) { +*/ + + /** + * Merges this state and additionalState into + * the parameter state based on a specific criteria. + * + *

The criteria for this merge is the following:
+ * For every given property, such as alpha test or depth write, check + * if it was modified from the original in the additionalState + * if it was modified, then copy the property from the additionalState + * into the parameter state, otherwise, copy the property from this + * into the parameter state. If additionalState + * is null, then no modifications are made and this is returned, + * otherwise, the parameter state is returned with the result + * of the merge. + * + * @param additionalState The additionalState, from which data is taken only + * if it was modified by the user. + * @param state Contains output of the method if additionalState + * is not null. + * @return state if additionalState is non-null, + * otherwise returns this + */ + public RenderState copyMergedTo(RenderState additionalState, RenderState state) { if (additionalState == null) { return this; } - if (additionalState.isApplyPointSprite()) { + if (additionalState.applyPointSprite) { state.pointSprite = additionalState.pointSprite; - }else{ + } else { state.pointSprite = pointSprite; } - if (additionalState.isApplyWireFrame()) { + if (additionalState.applyWireFrame) { state.wireframe = additionalState.wireframe; - }else{ + } else { state.wireframe = wireframe; } - if (additionalState.isApplyCullMode()) { + if (additionalState.applyCullMode) { state.cullMode = additionalState.cullMode; - }else{ + } else { state.cullMode = cullMode; } - if (additionalState.isApplyDepthWrite()) { + if (additionalState.applyDepthWrite) { state.depthWrite = additionalState.depthWrite; - }else{ + } else { state.depthWrite = depthWrite; } - if (additionalState.isApplyDepthTest()) { + if (additionalState.applyDepthTest) { state.depthTest = additionalState.depthTest; - }else{ + } else { state.depthTest = depthTest; } - if (additionalState.isApplyColorWrite()) { + if (additionalState.applyColorWrite) { state.colorWrite = additionalState.colorWrite; - }else{ + } else { state.colorWrite = colorWrite; } - if (additionalState.isApplyBlendMode()) { + if (additionalState.applyBlendMode) { state.blendMode = additionalState.blendMode; - }else{ + } else { state.blendMode = blendMode; } - if (additionalState.isApplyAlphaTest()) { + if (additionalState.applyAlphaTest) { state.alphaTest = additionalState.alphaTest; - }else{ + } else { state.alphaTest = alphaTest; } - if (additionalState.isApplyAlphaFallOff()) { + if (additionalState.applyAlphaFallOff) { state.alphaFallOff = additionalState.alphaFallOff; - }else{ + } else { state.alphaFallOff = alphaFallOff; } - if (additionalState.isApplyPolyOffset()) { + if (additionalState.applyPolyOffset) { state.offsetEnabled = additionalState.offsetEnabled; state.offsetFactor = additionalState.offsetFactor; state.offsetUnits = additionalState.offsetUnits; - }else{ + } else { state.offsetEnabled = offsetEnabled; state.offsetFactor = offsetFactor; state.offsetUnits = offsetUnits; } + if (additionalState.applyStencilTest){ + state.stencilTest = additionalState.stencilTest; + }else{ + state.stencilTest = stencilTest; + } return state; } @Override public String toString() { - return "RenderState{" + "pointSprite=" + pointSprite + "applyPointSprite=" + applyPointSprite + "wireframe=" + wireframe + "applyWireFrame=" + applyWireFrame + "cullMode=" + cullMode + "applyCullMode=" + applyCullMode + "depthWrite=" + depthWrite + "applyDepthWrite=" + applyDepthWrite + "depthTest=" + depthTest + "applyDepthTest=" + applyDepthTest + "colorWrite=" + colorWrite + "applyColorWrite=" + applyColorWrite + "blendMode=" + blendMode + "applyBlendMode=" + applyBlendMode + "alphaTest=" + alphaTest + "applyAlphaTest=" + applyAlphaTest + "alphaFallOff=" + alphaFallOff + "applyAlphaFallOff=" + applyAlphaFallOff + "offsetEnabled=" + offsetEnabled + "applyPolyOffset=" + applyPolyOffset + "offsetFactor=" + offsetFactor + "offsetUnits=" + offsetUnits + '}'; + return "RenderState[" + "pointSprite=" + pointSprite + "applyPointSprite=" + applyPointSprite + "wireframe=" + wireframe + "applyWireFrame=" + applyWireFrame + "cullMode=" + cullMode + "applyCullMode=" + applyCullMode + "depthWrite=" + depthWrite + "applyDepthWrite=" + applyDepthWrite + "depthTest=" + depthTest + "applyDepthTest=" + applyDepthTest + "colorWrite=" + colorWrite + "applyColorWrite=" + applyColorWrite + "blendMode=" + blendMode + "applyBlendMode=" + applyBlendMode + "alphaTest=" + alphaTest + "applyAlphaTest=" + applyAlphaTest + "alphaFallOff=" + alphaFallOff + "applyAlphaFallOff=" + applyAlphaFallOff + "offsetEnabled=" + offsetEnabled + "applyPolyOffset=" + applyPolyOffset + "offsetFactor=" + offsetFactor + "offsetUnits=" + offsetUnits + ']'; } } diff --git a/engine/src/core/com/jme3/renderer/RenderContext.java b/engine/src/core/com/jme3/renderer/RenderContext.java index fd70be103..34834a1a1 100644 --- a/engine/src/core/com/jme3/renderer/RenderContext.java +++ b/engine/src/core/com/jme3/renderer/RenderContext.java @@ -35,7 +35,6 @@ package com.jme3.renderer; import com.jme3.material.RenderState; import com.jme3.scene.VertexBuffer; import com.jme3.texture.Image; -import com.jme3.texture.Texture; /** * Represents the current state of the graphics library. This class is used @@ -149,8 +148,8 @@ public class RenderContext { public RenderState.StencilOperation backStencilStencilFailOperation = RenderState.StencilOperation.Keep; public RenderState.StencilOperation backStencilDepthFailOperation = RenderState.StencilOperation.Keep; public RenderState.StencilOperation backStencilDepthPassOperation = RenderState.StencilOperation.Keep; - public RenderState.StencilFunction frontStencilFunction = RenderState.StencilFunction.Always; - public RenderState.StencilFunction backStencilFunction = RenderState.StencilFunction.Always; + public RenderState.TestFunction frontStencilFunction = RenderState.TestFunction.Always; + public RenderState.TestFunction backStencilFunction = RenderState.TestFunction.Always; /** * Vertex attribs currently bound and enabled. If a slot is null, then @@ -193,5 +192,15 @@ public class RenderContext { boundAttribs[i] = null; attribIndexList.reset(); + + stencilTest = false; + frontStencilStencilFailOperation = RenderState.StencilOperation.Keep; + frontStencilDepthFailOperation = RenderState.StencilOperation.Keep; + frontStencilDepthPassOperation = RenderState.StencilOperation.Keep; + backStencilStencilFailOperation = RenderState.StencilOperation.Keep; + backStencilDepthFailOperation = RenderState.StencilOperation.Keep; + backStencilDepthPassOperation = RenderState.StencilOperation.Keep; + frontStencilFunction = RenderState.TestFunction.Always; + backStencilFunction = RenderState.TestFunction.Always; } } diff --git a/engine/src/lwjgl-ogl/com/jme3/renderer/lwjgl/LwjglRenderer.java b/engine/src/lwjgl-ogl/com/jme3/renderer/lwjgl/LwjglRenderer.java index 0cbc408b8..54444a19e 100644 --- a/engine/src/lwjgl-ogl/com/jme3/renderer/lwjgl/LwjglRenderer.java +++ b/engine/src/lwjgl-ogl/com/jme3/renderer/lwjgl/LwjglRenderer.java @@ -33,6 +33,8 @@ package com.jme3.renderer.lwjgl; import com.jme3.light.LightList; import com.jme3.material.RenderState; +import com.jme3.material.RenderState.StencilOperation; +import com.jme3.material.RenderState.TestFunction; import com.jme3.math.ColorRGBA; import com.jme3.math.FastMath; import com.jme3.math.Matrix4f; @@ -67,6 +69,7 @@ import com.jme3.util.BufferUtils; import com.jme3.util.IntMap; import com.jme3.util.IntMap.Entry; import com.jme3.util.ListMap; +import java.io.File; import java.nio.ByteBuffer; import java.nio.DoubleBuffer; import java.nio.FloatBuffer; @@ -632,28 +635,27 @@ public class LwjglRenderer implements Renderer { if (state.isStencilTest()) { glEnable(GL_STENCIL_TEST); glStencilOpSeparate(GL_FRONT, - glStencilOpFromStencilOp(state.getFrontStencilStencilFailOperation()), - glStencilOpFromStencilOp(state.getFrontStencilDepthFailOperation()), - glStencilOpFromStencilOp(state.getFrontStencilDepthPassOperation())); + convertStencilOperation(state.getFrontStencilStencilFailOperation()), + convertStencilOperation(state.getFrontStencilDepthFailOperation()), + convertStencilOperation(state.getFrontStencilDepthPassOperation())); glStencilOpSeparate(GL_BACK, - glStencilOpFromStencilOp(state.getBackStencilStencilFailOperation()), - glStencilOpFromStencilOp(state.getBackStencilDepthFailOperation()), - glStencilOpFromStencilOp(state.getBackStencilDepthPassOperation())); + convertStencilOperation(state.getBackStencilStencilFailOperation()), + convertStencilOperation(state.getBackStencilDepthFailOperation()), + convertStencilOperation(state.getBackStencilDepthPassOperation())); glStencilFuncSeparate(GL_FRONT, - glStencilFuncFromStencilFunc(state.getFrontStencilFunction()), + convertTestFunction(state.getFrontStencilFunction()), 0, Integer.MAX_VALUE); glStencilFuncSeparate(GL_BACK, - glStencilFuncFromStencilFunc(state.getBackStencilFunction()), + convertTestFunction(state.getBackStencilFunction()), 0, Integer.MAX_VALUE); } else { glDisable(GL_STENCIL_TEST); } } - } - private int glStencilOpFromStencilOp(RenderState.StencilOperation s) { - switch (s) { + private int convertStencilOperation(StencilOperation stencilOp) { + switch (stencilOp) { case Keep: return GL_KEEP; case Zero: @@ -671,21 +673,21 @@ public class LwjglRenderer implements Renderer { case Invert: return GL_INVERT; default: - throw new UnsupportedOperationException("Unrecognized front stencil operation: " + s); - } //end switch + throw new UnsupportedOperationException("Unrecognized stencil operation: " + stencilOp); + } } - private int glStencilFuncFromStencilFunc(RenderState.StencilFunction s) { - switch (s) { + private int convertTestFunction(TestFunction testFunc) { + switch (testFunc) { case Never: return GL_NEVER; case Less: return GL_LESS; - case LessEqual: + case LessOrEqual: return GL_LEQUAL; case Greater: return GL_GREATER; - case GreaterEqual: + case GreaterOrEqual: return GL_GEQUAL; case Equal: return GL_EQUAL; @@ -694,10 +696,10 @@ public class LwjglRenderer implements Renderer { case Always: return GL_ALWAYS; default: - throw new UnsupportedOperationException("Unrecognized front stencil functin: " + s); - } //end switch + throw new UnsupportedOperationException("Unrecognized test function: " + testFunc); + } } - + /*********************************************************************\ |* Camera and World transforms *| \*********************************************************************/