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 9359ce7f4..94cae3f50 100644 --- a/jme3-core/src/main/java/com/jme3/material/RenderState.java +++ b/jme3-core/src/main/java/com/jme3/material/RenderState.java @@ -311,6 +311,8 @@ public class RenderState implements Cloneable, Savable { boolean applyPolyOffset = true; boolean stencilTest = false; boolean applyStencilTest = false; + float lineWidth = 1; + boolean applyLineWidth = false; TestFunction depthFunc = TestFunction.LessOrEqual; //by default depth func will be applied anyway if depth test is applied boolean applyDepthFunc = false; @@ -350,6 +352,9 @@ public class RenderState implements Cloneable, Savable { oc.write(backStencilDepthPassOperation, "backStencilDepthPassOperation", StencilOperation.Keep); oc.write(frontStencilFunction, "frontStencilFunction", TestFunction.Always); oc.write(backStencilFunction, "backStencilFunction", TestFunction.Always); + oc.write(depthFunc, "depthFunc", TestFunction.LessOrEqual); + oc.write(alphaFunc, "alphaFunc", TestFunction.Greater); + oc.write(lineWidth, "lineWidth", 1); // Only "additional render state" has them set to false by default oc.write(applyPointSprite, "applyPointSprite", true); @@ -364,8 +369,7 @@ public class RenderState implements Cloneable, Savable { oc.write(applyPolyOffset, "applyPolyOffset", true); oc.write(applyDepthFunc, "applyDepthFunc", true); oc.write(applyAlphaFunc, "applyAlphaFunc", false); - oc.write(depthFunc, "depthFunc", TestFunction.LessOrEqual); - oc.write(alphaFunc, "alphaFunc", TestFunction.Greater); + oc.write(applyLineWidth, "applyLineWidth", true); } @@ -394,6 +398,8 @@ public class RenderState implements Cloneable, Savable { backStencilFunction = ic.readEnum("backStencilFunction", TestFunction.class, TestFunction.Always); depthFunc = ic.readEnum("depthFunc", TestFunction.class, TestFunction.LessOrEqual); alphaFunc = ic.readEnum("alphaFunc", TestFunction.class, TestFunction.Greater); + lineWidth = ic.readFloat("lineWidth", 1); + applyPointSprite = ic.readBoolean("applyPointSprite", true); applyWireFrame = ic.readBoolean("applyWireFrame", true); @@ -407,6 +413,8 @@ public class RenderState implements Cloneable, Savable { applyPolyOffset = ic.readBoolean("applyPolyOffset", true); applyDepthFunc = ic.readBoolean("applyDepthFunc", true); applyAlphaFunc = ic.readBoolean("applyAlphaFunc", false); + applyLineWidth = ic.readBoolean("applyLineWidth", true); + } @@ -528,6 +536,10 @@ public class RenderState implements Cloneable, Savable { } } + if(lineWidth != rs.lineWidth){ + return false; + } + return true; } @@ -803,8 +815,17 @@ public class RenderState implements Cloneable, Savable { this.alphaFunc = alphaFunc; cachedHashCode = -1; } - - + + /** + * Sets the mesh line width. + * This is to use in conjunction with {@link #setWireframe(boolean)} or with a mesh in {@link Mesh.Mode#Lines} mode. + * @param lineWidth the line width. + */ + public void setLineWidth(float lineWidth) { + this.lineWidth = lineWidth; + this.applyLineWidth = true; + cachedHashCode = -1; + } /** * Check if stencil test is enabled. @@ -1118,8 +1139,16 @@ public class RenderState implements Cloneable, Savable { public TestFunction getAlphaFunc() { return alphaFunc; } - - + + /** + * returns the wireframe line width + * + * @return the line width + */ + public float getLineWidth() { + return lineWidth; + } + public boolean isApplyAlphaFallOff() { return applyAlphaFallOff; @@ -1168,8 +1197,10 @@ public class RenderState implements Cloneable, Savable { public boolean isApplyAlphaFunc() { return applyAlphaFunc; } - - + + public boolean isApplyLineWidth() { + return applyLineWidth; + } /** * @@ -1200,6 +1231,7 @@ public class RenderState implements Cloneable, Savable { hash = 79 * hash + (this.backStencilDepthPassOperation != null ? this.backStencilDepthPassOperation.hashCode() : 0); hash = 79 * hash + (this.frontStencilFunction != null ? this.frontStencilFunction.hashCode() : 0); hash = 79 * hash + (this.backStencilFunction != null ? this.backStencilFunction.hashCode() : 0); + hash = 79 * hash + Float.floatToIntBits(this.lineWidth); cachedHashCode = hash; } return cachedHashCode; @@ -1324,6 +1356,11 @@ public class RenderState implements Cloneable, Savable { state.frontStencilFunction = frontStencilFunction; state.backStencilFunction = backStencilFunction; } + if (additionalState.applyLineWidth) { + state.lineWidth = additionalState.lineWidth; + } else { + state.lineWidth = lineWidth; + } state.cachedHashCode = -1; return state; } @@ -1351,6 +1388,7 @@ public class RenderState implements Cloneable, Savable { backStencilFunction = state.backStencilFunction; depthFunc = state.depthFunc; alphaFunc = state.alphaFunc; + lineWidth = state.lineWidth; applyPointSprite = true; applyWireFrame = true; @@ -1364,6 +1402,7 @@ public class RenderState implements Cloneable, Savable { applyPolyOffset = true; applyDepthFunc = true; applyAlphaFunc = false; + applyLineWidth = true; } @Override @@ -1392,7 +1431,8 @@ public class RenderState implements Cloneable, Savable { + "\noffsetEnabled=" + offsetEnabled + "\napplyPolyOffset=" + applyPolyOffset + "\noffsetFactor=" + offsetFactor - + "\noffsetUnits=" + offsetUnits + + "\noffsetUnits=" + offsetUnits + + "\nlineWidth=" + lineWidth + "\n]"; } } 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 8287a270e..5be184c94 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java @@ -101,7 +101,7 @@ public class RenderContext { public float pointSize = 1; /** - * @see Mesh#setLineWidth(float) + * @see RenderState#setLineWidth(float) */ public float lineWidth = 1; 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 50e603d2f..1ad42eac9 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 @@ -779,6 +779,10 @@ public final class GLRenderer implements Renderer { gl.glDisable(GL.GL_STENCIL_TEST); } } + if (context.lineWidth != state.getLineWidth()) { + gl.glLineWidth(state.getLineWidth()); + context.lineWidth = state.getLineWidth(); + } } private int convertStencilOperation(StencilOperation stencilOp) { @@ -2681,8 +2685,8 @@ public final class GLRenderer implements Renderer { return; } - - if (context.lineWidth != mesh.getLineWidth()) { + //this is kept for backward compatibility. + if (mesh.getLineWidth() != -1 && context.lineWidth != mesh.getLineWidth()) { gl.glLineWidth(mesh.getLineWidth()); context.lineWidth = mesh.getLineWidth(); } diff --git a/jme3-core/src/main/java/com/jme3/scene/BatchNode.java b/jme3-core/src/main/java/com/jme3/scene/BatchNode.java index e352394bd..69a30897d 100644 --- a/jme3-core/src/main/java/com/jme3/scene/BatchNode.java +++ b/jme3-core/src/main/java/com/jme3/scene/BatchNode.java @@ -383,7 +383,7 @@ public class BatchNode extends GeometryGroupNode { maxVertCount = geom.getVertexCount(); } Mesh.Mode listMode; - float listLineWidth = 1f; + //float listLineWidth = 1f; int components; switch (geom.getMesh().getMode()) { case Points: @@ -394,7 +394,7 @@ public class BatchNode extends GeometryGroupNode { case LineStrip: case Lines: listMode = Mesh.Mode.Lines; - listLineWidth = geom.getMesh().getLineWidth(); + //listLineWidth = geom.getMesh().getLineWidth(); components = 2; break; case TriangleFan: @@ -426,19 +426,20 @@ public class BatchNode extends GeometryGroupNode { + " primitive types: " + mode + " != " + listMode); } mode = listMode; - if (mode == Mesh.Mode.Lines) { - if (lineWidth != 1f && listLineWidth != lineWidth) { - throw new UnsupportedOperationException("When using Mesh Line mode, cannot combine meshes with different line width " - + lineWidth + " != " + listLineWidth); - } - lineWidth = listLineWidth; - } + //Not needed anymore as lineWidth is now in RenderState and will be taken into account when merging according to the material +// if (mode == Mesh.Mode.Lines) { +// if (lineWidth != 1f && listLineWidth != lineWidth) { +// throw new UnsupportedOperationException("When using Mesh Line mode, cannot combine meshes with different line width " +// + lineWidth + " != " + listLineWidth); +// } +// lineWidth = listLineWidth; +// } compsForBuf[VertexBuffer.Type.Index.ordinal()] = components; } outMesh.setMaxNumWeights(maxWeights); outMesh.setMode(mode); - outMesh.setLineWidth(lineWidth); + //outMesh.setLineWidth(lineWidth); if (totalVerts >= 65536) { // make sure we create an UnsignedInt buffer so we can fit all of the meshes formatForBuf[VertexBuffer.Type.Index.ordinal()] = VertexBuffer.Format.UnsignedInt; diff --git a/jme3-core/src/main/java/com/jme3/scene/Mesh.java b/jme3-core/src/main/java/com/jme3/scene/Mesh.java index a0f8e1fe6..60f7eabe2 100644 --- a/jme3-core/src/main/java/com/jme3/scene/Mesh.java +++ b/jme3-core/src/main/java/com/jme3/scene/Mesh.java @@ -37,6 +37,7 @@ import com.jme3.collision.Collidable; import com.jme3.collision.CollisionResults; import com.jme3.collision.bih.BIHTree; import com.jme3.export.*; +import com.jme3.material.Material; import com.jme3.material.RenderState; import com.jme3.math.Matrix4f; import com.jme3.math.Triangle; @@ -65,7 +66,7 @@ import java.util.ArrayList; * Points can also be used for {@link RenderState#setPointSprite(boolean) point * sprite} mode. *
  • Lines - 2 vertices represent a line segment, with the width specified - * via {@link Mesh#setLineWidth(float) }.
  • + * via {@link Material#getAdditionalRenderState()} and {@link RenderState#setLineWidth(float)}. *
  • Triangles - 3 vertices represent a solid triangle primitive.
  • * * @@ -86,7 +87,7 @@ public class Mesh implements Savable, Cloneable { /** * A primitive is a line segment. Every two vertices specify - * a single line. {@link Mesh#setLineWidth(float) } can be used + * a single line. {@link Material#getAdditionalRenderState()} and {@link RenderState#setLineWidth(float)} can be used * to set the width of the lines. */ Lines(true), @@ -94,7 +95,7 @@ public class Mesh implements Savable, Cloneable { /** * A primitive is a line segment. The first two vertices specify * a single line, while subsequent vertices are combined with the - * previous vertex to make a line. {@link Mesh#setLineWidth(float) } can + * previous vertex to make a line. {@link Material#getAdditionalRenderState()} and {@link RenderState#setLineWidth(float)} can * be used to set the width of the lines. */ LineStrip(false), @@ -102,7 +103,7 @@ public class Mesh implements Savable, Cloneable { /** * Identical to {@link #LineStrip} except that at the end * the last vertex is connected with the first to form a line. - * {@link Mesh#setLineWidth(float) } can be used + * {@link Material#getAdditionalRenderState()} and {@link RenderState#setLineWidth(float)} can be used * to set the width of the lines. */ LineLoop(false), @@ -172,7 +173,7 @@ public class Mesh implements Savable, Cloneable { private IntMap buffers = new IntMap(); private VertexBuffer[] lodLevels; private float pointSize = 1; - private float lineWidth = 1; + private float lineWidth = -1; private transient int vertexArrayID = -1; @@ -583,7 +584,9 @@ public class Mesh implements Savable, Cloneable { * Returns the line width for line meshes. * * @return the line width + * @deprecated use {@link Material#getAdditionalRenderState()} and {@link RenderState#getLineWidth()} */ + @Deprecated public float getLineWidth() { return lineWidth; } @@ -594,7 +597,9 @@ public class Mesh implements Savable, Cloneable { * the default value is 1.0. * * @param lineWidth The line width + * @deprecated use {@link Material#getAdditionalRenderState()} and {@link RenderState#setLineWidth(float)} */ + @Deprecated public void setLineWidth(float lineWidth) { this.lineWidth = lineWidth; } 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 65350f29b..402ce6d47 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 @@ -458,6 +458,8 @@ public class J3MLoader implements AssetLoader { renderState.setDepthFunc(RenderState.TestFunction.valueOf(split[1])); }else if (split[0].equals("AlphaFunc")){ renderState.setAlphaFunc(RenderState.TestFunction.valueOf(split[1])); + }else if (split[0].equals("LineWidth")){ + renderState.setLineWidth(Float.parseFloat(split[1])); } else { throw new MatParseException(null, split[0], statement); } diff --git a/jme3-examples/src/main/java/jme3test/collision/TestMousePick.java b/jme3-examples/src/main/java/jme3test/collision/TestMousePick.java index 84d186e3a..f86f956b6 100644 --- a/jme3-examples/src/main/java/jme3test/collision/TestMousePick.java +++ b/jme3-examples/src/main/java/jme3test/collision/TestMousePick.java @@ -128,12 +128,12 @@ public class TestMousePick extends SimpleApplication { /** A red ball that marks the last spot that was "hit" by the "shot". */ protected void initMark() { Arrow arrow = new Arrow(Vector3f.UNIT_Z.mult(2f)); - arrow.setLineWidth(3); //Sphere sphere = new Sphere(30, 30, 0.2f); mark = new Geometry("BOOM!", arrow); //mark = new Geometry("BOOM!", sphere); Material mark_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mark_mat.getAdditionalRenderState().setLineWidth(3); mark_mat.setColor("Color", ColorRGBA.Red); mark.setMaterial(mark_mat); } diff --git a/jme3-examples/src/main/java/jme3test/light/TestTangentGenBadModels.java b/jme3-examples/src/main/java/jme3test/light/TestTangentGenBadModels.java index a786d767d..21817e7c8 100644 --- a/jme3-examples/src/main/java/jme3test/light/TestTangentGenBadModels.java +++ b/jme3-examples/src/main/java/jme3test/light/TestTangentGenBadModels.java @@ -72,7 +72,6 @@ public class TestTangentGenBadModels extends SimpleApplication { "debug tangents geom", TangentBinormalGenerator.genTbnLines(g.getMesh(), 0.2f) ); - debug.getMesh().setLineWidth(1); debug.setMaterial(debugMat); debug.setCullHint(Spatial.CullHint.Never); debug.setLocalTransform(g.getWorldTransform()); diff --git a/jme3-examples/src/main/java/jme3test/model/shape/TestDebugShapes.java b/jme3-examples/src/main/java/jme3test/model/shape/TestDebugShapes.java index 6c4c45e2f..fc4731615 100644 --- a/jme3-examples/src/main/java/jme3test/model/shape/TestDebugShapes.java +++ b/jme3-examples/src/main/java/jme3test/model/shape/TestDebugShapes.java @@ -50,10 +50,11 @@ public class TestDebugShapes extends SimpleApplication { app.start(); } - public Geometry putShape(Mesh shape, ColorRGBA color){ + public Geometry putShape(Mesh shape, ColorRGBA color, float lineWidth){ Geometry g = new Geometry("shape", shape); Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat.getAdditionalRenderState().setWireframe(true); + mat.getAdditionalRenderState().setLineWidth(lineWidth); mat.setColor("Color", color); g.setMaterial(mat); rootNode.attachChild(g); @@ -62,20 +63,19 @@ public class TestDebugShapes extends SimpleApplication { public void putArrow(Vector3f pos, Vector3f dir, ColorRGBA color){ Arrow arrow = new Arrow(dir); - arrow.setLineWidth(4); // make arrow thicker - putShape(arrow, color).setLocalTranslation(pos); + putShape(arrow, color, 4).setLocalTranslation(pos); } public void putBox(Vector3f pos, float size, ColorRGBA color){ - putShape(new WireBox(size, size, size), color).setLocalTranslation(pos); + putShape(new WireBox(size, size, size), color, 1).setLocalTranslation(pos); } public void putGrid(Vector3f pos, ColorRGBA color){ - putShape(new Grid(6, 6, 0.2f), color).center().move(pos); + putShape(new Grid(6, 6, 0.2f), color, 1).center().move(pos); } public void putSphere(Vector3f pos, ColorRGBA color){ - putShape(new WireSphere(1), color).setLocalTranslation(pos); + putShape(new WireSphere(1), color, 1).setLocalTranslation(pos); } @Override diff --git a/jme3-examples/src/main/java/jme3test/scene/TestLineWidthRenderState.java b/jme3-examples/src/main/java/jme3test/scene/TestLineWidthRenderState.java new file mode 100644 index 000000000..6bd629823 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/scene/TestLineWidthRenderState.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2009-2012 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.scene; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; + +public class TestLineWidthRenderState extends SimpleApplication { + + private Material mat; + + public static void main(String[] args){ + TestLineWidthRenderState app = new TestLineWidthRenderState(); + app.start(); + } + + + + @Override + public void simpleInitApp() { + setDisplayFps(false); + setDisplayStatView(false); + cam.setLocation(new Vector3f(5.5826545f, 3.6192513f, 8.016988f)); + cam.setRotation(new Quaternion(-0.04787097f, 0.9463123f, -0.16569641f, -0.27339742f)); + + Box b = new Box(1, 1, 1); + Geometry geom = new Geometry("Box", b); + mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", ColorRGBA.Blue); + mat.getAdditionalRenderState().setWireframe(true); + mat.getAdditionalRenderState().setLineWidth(2); + geom.setMaterial(mat); + rootNode.attachChild(geom); + + inputManager.addListener(new ActionListener() { + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if(name.equals("up") && isPressed){ + mat.getAdditionalRenderState().setLineWidth(mat.getAdditionalRenderState().getLineWidth() + 1); + } + if(name.equals("down") && isPressed){ + mat.getAdditionalRenderState().setLineWidth(Math.max(mat.getAdditionalRenderState().getLineWidth() - 1, 1)); + } + } + }, "up", "down"); + inputManager.addMapping("up", new KeyTrigger(KeyInput.KEY_U)); + inputManager.addMapping("down", new KeyTrigger(KeyInput.KEY_J)); + } +} \ No newline at end of file diff --git a/jme3-plugins/src/main/java/com/jme3/material/plugin/export/material/J3MRenderStateOutputCapsule.java b/jme3-plugins/src/main/java/com/jme3/material/plugin/export/material/J3MRenderStateOutputCapsule.java index 0e3d368d5..02c8df02c 100644 --- a/jme3-plugins/src/main/java/com/jme3/material/plugin/export/material/J3MRenderStateOutputCapsule.java +++ b/jme3-plugins/src/main/java/com/jme3/material/plugin/export/material/J3MRenderStateOutputCapsule.java @@ -32,6 +32,7 @@ public class J3MRenderStateOutputCapsule extends J3MOutputCapsule { NAME_MAP.put( "pointSprite", "PointSprite"); NAME_MAP.put( "depthFunc", "DepthFunc"); NAME_MAP.put( "alphaFunc", "AlphaFunc"); + NAME_MAP.put( "lineWidth", "LineWidth"); } public J3MRenderStateOutputCapsule(J3MExporter exporter) { super(exporter); diff --git a/jme3-plugins/src/test/java/com/jme3/material/plugin/TestMaterialWrite.java b/jme3-plugins/src/test/java/com/jme3/material/plugin/TestMaterialWrite.java index 584b16f84..be8fc3573 100644 --- a/jme3-plugins/src/test/java/com/jme3/material/plugin/TestMaterialWrite.java +++ b/jme3-plugins/src/test/java/com/jme3/material/plugin/TestMaterialWrite.java @@ -40,10 +40,7 @@ import com.jme3.material.plugin.export.material.J3MExporter; import com.jme3.material.plugins.J3MLoader; import com.jme3.math.ColorRGBA; import com.jme3.system.JmeSystem; -import static org.junit.Assert.*; - import com.jme3.texture.Texture; -import com.jme3.texture.Texture2D; import org.junit.Before; import org.junit.Test; @@ -51,7 +48,8 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; -import java.util.Scanner; + +import static org.junit.Assert.assertTrue; public class TestMaterialWrite { @@ -87,6 +85,7 @@ public class TestMaterialWrite { mat.setTexture("DiffuseMap", tex); mat.getAdditionalRenderState().setDepthWrite(false); mat.getAdditionalRenderState().setDepthTest(false); + mat.getAdditionalRenderState().setLineWidth(5); mat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha); final ByteArrayOutputStream stream = new ByteArrayOutputStream();