From 67fe2c404747c6f7a06ae1048cf2a82af757647b Mon Sep 17 00:00:00 2001 From: Bebul Date: Tue, 21 Oct 2014 10:33:48 +0200 Subject: [PATCH 01/28] optimize CollideWith using preliminary BoundingVolume collide check --- jme3-core/src/main/java/com/jme3/scene/Node.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/jme3-core/src/main/java/com/jme3/scene/Node.java b/jme3-core/src/main/java/com/jme3/scene/Node.java index f22c5b4b0..9ed225662 100644 --- a/jme3-core/src/main/java/com/jme3/scene/Node.java +++ b/jme3-core/src/main/java/com/jme3/scene/Node.java @@ -489,6 +489,18 @@ public class Node extends Spatial implements Savable { public int collideWith(Collidable other, CollisionResults results){ int total = 0; + + // optimization: try collideWith BoundingVolume to avoid possibly redundant tests on children + if (children.size() > 4) + { + BoundingVolume bv = this.getWorldBound(); + CollisionResults bvColRes = new CollisionResults(); + if (bv.collideWith(other, bvColRes) == 0) + { + System.out.println("Skipping collideWith "+getName()); + return 0; + } + } for (Spatial child : children.getArray()){ total += child.collideWith(other, results); } From 2dd23c38c0bb18512d6b0752ef452a542f6c0758 Mon Sep 17 00:00:00 2001 From: Bebul Date: Wed, 5 Nov 2014 09:54:46 +0100 Subject: [PATCH 02/28] FIX: possible null getWorldBound in collideWith --- .../src/main/java/com/jme3/scene/Node.java | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/jme3-core/src/main/java/com/jme3/scene/Node.java b/jme3-core/src/main/java/com/jme3/scene/Node.java index 9ed225662..5a11dd2f2 100644 --- a/jme3-core/src/main/java/com/jme3/scene/Node.java +++ b/jme3-core/src/main/java/com/jme3/scene/Node.java @@ -494,6 +494,9 @@ public class Node extends Spatial implements Savable { if (children.size() > 4) { BoundingVolume bv = this.getWorldBound(); + if (bv==null) + return 0; + CollisionResults bvColRes = new CollisionResults(); if (bv.collideWith(other, bvColRes) == 0) { @@ -650,5 +653,24 @@ public class Node extends Spatial implements Savable { protected void breadthFirstTraversal(SceneGraphVisitor visitor, Queue queue) { queue.addAll(children); } - +/* + @Override + void checkDoBoundUpdate() { + if ((refreshFlags & RF_BOUND) == 0) { + return; + } + + checkDoTransformUpdate(); + + // Go to children recursively and update their bound + int len = getQuantity(); + for (int i = 0; i < len; i++) { + Spatial child = getChild(i); + child.checkDoBoundUpdate(); + } + + // All children's bounds have been updated. Update my own now. + updateWorldBound(); + } +*/ } From 6636fba06aae852a4288b24a637e55fe1b056dc5 Mon Sep 17 00:00:00 2001 From: Bebul Date: Thu, 4 Dec 2014 11:44:48 +0100 Subject: [PATCH 03/28] commented code relict removed --- .../src/main/java/com/jme3/scene/Node.java | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/scene/Node.java b/jme3-core/src/main/java/com/jme3/scene/Node.java index 5a11dd2f2..3e69e1f9a 100644 --- a/jme3-core/src/main/java/com/jme3/scene/Node.java +++ b/jme3-core/src/main/java/com/jme3/scene/Node.java @@ -653,24 +653,4 @@ public class Node extends Spatial implements Savable { protected void breadthFirstTraversal(SceneGraphVisitor visitor, Queue queue) { queue.addAll(children); } -/* - @Override - void checkDoBoundUpdate() { - if ((refreshFlags & RF_BOUND) == 0) { - return; - } - - checkDoTransformUpdate(); - - // Go to children recursively and update their bound - int len = getQuantity(); - for (int i = 0; i < len; i++) { - Spatial child = getChild(i); - child.checkDoBoundUpdate(); - } - - // All children's bounds have been updated. Update my own now. - updateWorldBound(); - } -*/ } From 7f66641b7494ab2dc7077eda5320550ac3ec6816 Mon Sep 17 00:00:00 2001 From: Bebul Date: Thu, 4 Dec 2014 12:52:50 +0100 Subject: [PATCH 04/28] Debug lines removed --- jme3-core/src/main/java/com/jme3/scene/Node.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/scene/Node.java b/jme3-core/src/main/java/com/jme3/scene/Node.java index 3e69e1f9a..b8d379315 100644 --- a/jme3-core/src/main/java/com/jme3/scene/Node.java +++ b/jme3-core/src/main/java/com/jme3/scene/Node.java @@ -494,15 +494,10 @@ public class Node extends Spatial implements Savable { if (children.size() > 4) { BoundingVolume bv = this.getWorldBound(); - if (bv==null) - return 0; + if (bv==null) return 0; CollisionResults bvColRes = new CollisionResults(); - if (bv.collideWith(other, bvColRes) == 0) - { - System.out.println("Skipping collideWith "+getName()); - return 0; - } + if (bv.collideWith(other, bvColRes) == 0) return 0; } for (Spatial child : children.getArray()){ total += child.collideWith(other, results); From b46973f33f17cabe8067285b8a3740825ea3f803 Mon Sep 17 00:00:00 2001 From: Bebul Date: Tue, 9 Dec 2014 15:04:42 +0100 Subject: [PATCH 05/28] Optimize Node.collideWith with no additional CollisionResults allocation --- .../jme3/collision/DummyCollisionResults.java | 77 +++++++++++++++++++ .../src/main/java/com/jme3/scene/Node.java | 9 ++- 2 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/collision/DummyCollisionResults.java diff --git a/jme3-core/src/main/java/com/jme3/collision/DummyCollisionResults.java b/jme3-core/src/main/java/com/jme3/collision/DummyCollisionResults.java new file mode 100644 index 000000000..f0f1777bd --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/collision/DummyCollisionResults.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2009-2014 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 com.jme3.collision; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +/** + * DummyCollisionResults is an empty "dummy" collection returned as a result of a + * collision detection operation done by {@link Collidable}. + * Its purpose is to avoid allocation of CollisionResults and its content, + * when collisionResults are out of our interest. + * Using the same API Collidable.collideWith() instead of possibly some new countCollideWith() implementation + * is chosen to keep the collision detection code "DRY", @see Don't repeat yourself + * + * @author Bebul + */ +public class DummyCollisionResults extends CollisionResults { + // the singleton for DummyCollisionResults is sufficient + private static DummyCollisionResults instance = null; + + // exists only to defeat instantiation + protected DummyCollisionResults() {} + + // classic singleton instance + public static DummyCollisionResults getInstance() { + if ( instance == null ) { + instance = new DummyCollisionResults(); + } + return instance; + } + + // Dummy implementation of CollisionResults + // All methods can be dummy except for iterator + @Override public void clear(){} + // even dummy iterator should return valid iterator + @Override public Iterator iterator() { + List dumbCompiler = Collections.emptyList(); + return dumbCompiler.iterator(); + } + @Override public void addCollision(CollisionResult result){} + @Override public int size(){ return 0; } + @Override public CollisionResult getClosestCollision(){ return null; } + @Override public CollisionResult getFarthestCollision(){ return null; } + @Override public CollisionResult getCollision(int index){ return null; } + @Override public CollisionResult getCollisionDirect(int index){ return null; } +} diff --git a/jme3-core/src/main/java/com/jme3/scene/Node.java b/jme3-core/src/main/java/com/jme3/scene/Node.java index b8d379315..330ebaf4c 100644 --- a/jme3-core/src/main/java/com/jme3/scene/Node.java +++ b/jme3-core/src/main/java/com/jme3/scene/Node.java @@ -34,6 +34,7 @@ package com.jme3.scene; import com.jme3.bounding.BoundingVolume; import com.jme3.collision.Collidable; import com.jme3.collision.CollisionResults; +import com.jme3.collision.DummyCollisionResults; import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.Savable; @@ -491,13 +492,17 @@ public class Node extends Spatial implements Savable { int total = 0; // optimization: try collideWith BoundingVolume to avoid possibly redundant tests on children + // number 4 in condition is somewhat arbitrary. When there is only one child, the boundingVolume test is redundant at all. + // The idea is when there are few children, it can be too expensive to test boundingVolume first. if (children.size() > 4) { BoundingVolume bv = this.getWorldBound(); if (bv==null) return 0; - CollisionResults bvColRes = new CollisionResults(); - if (bv.collideWith(other, bvColRes) == 0) return 0; + // use DummyCollisionResults to avoid allocation while making the call to any BoundingVolume.collideWith possible + // moreover, the DummyCollisionResults operations are empty, so faster + DummyCollisionResults dummyColRes = DummyCollisionResults.getInstance(); + if (bv.collideWith(other, dummyColRes) == 0) return 0; } for (Spatial child : children.getArray()){ total += child.collideWith(other, results); From b1f040d8e05a5eabee12fa4693ec1970b9d1476a Mon Sep 17 00:00:00 2001 From: Bebul Date: Fri, 30 Jan 2015 11:57:09 +0100 Subject: [PATCH 06/28] Optimize RenderShadow to use scene hierarchy for culling --- .../java/com/jme3/renderer/RenderManager.java | 13 +- .../com/jme3/renderer/queue/RenderQueue.java | 23 +- .../jme3/shadow/AbstractShadowRenderer.java | 14 +- .../com/jme3/shadow/BasicShadowRenderer.java | 30 +- .../DirectionalLightShadowRenderer.java | 13 +- .../jme3/shadow/PointLightShadowRenderer.java | 10 +- .../com/jme3/shadow/PssmShadowRenderer.java | 24 +- .../main/java/com/jme3/shadow/ShadowUtil.java | 301 +++++++++++++++--- .../jme3/shadow/SpotLightShadowRenderer.java | 8 +- 9 files changed, 330 insertions(+), 106 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java index 5e87ed350..598a428e6 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -591,6 +591,7 @@ public class RenderManager { * is still rendered in the shadow frustum (shadow casting queue) * through this recursive method. */ + @Deprecated private void renderShadow(Spatial s, RenderQueue rq) { if (s instanceof Node) { Node n = (Node) s; @@ -681,6 +682,8 @@ public class RenderManager { public void renderScene(Spatial scene, ViewPort vp) { //reset of the camera plane state for proper culling (must be 0 for the first note of the scene to be rendered) vp.getCamera().setPlaneState(0); + //remember the scene for possible later use + vp.getQueue().setRootScene(scene); //rendering the scene renderSubScene(scene, vp); } @@ -690,10 +693,6 @@ public class RenderManager { // check culling first. if (!scene.checkCulling(vp.getCamera())) { - // move on to shadow-only render - if ((scene.getShadowMode() != RenderQueue.ShadowMode.Off || scene instanceof Node) && scene.getCullHint() != Spatial.CullHint.Always) { - renderShadow(scene, vp.getQueue()); - } return; } @@ -717,12 +716,6 @@ public class RenderManager { } vp.getQueue().addToQueue(gm, scene.getQueueBucket()); - - // add to shadow queue if needed - RenderQueue.ShadowMode shadowMode = scene.getShadowMode(); - if (shadowMode != RenderQueue.ShadowMode.Off) { - vp.getQueue().addToShadowQueue(gm, shadowMode); - } } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java b/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java index 98323c7a3..1a6728540 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java +++ b/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java @@ -50,8 +50,9 @@ public class RenderQueue { private GeometryList transparentList; private GeometryList translucentList; private GeometryList skyList; - private GeometryList shadowRecv; - private GeometryList shadowCast; + @Deprecated private GeometryList shadowRecv; + @Deprecated private GeometryList shadowCast; + private Spatial rootScene = null; /** * Creates a new RenderQueue, the default {@link GeometryComparator comparators} @@ -242,21 +243,14 @@ public class RenderQueue { * {@link ShadowMode#CastAndReceive}, it is added to both the cast * and the receive buckets. */ + @Deprecated public void addToShadowQueue(Geometry g, ShadowMode shadBucket) { switch (shadBucket) { case Inherit: - break; case Off: - break; case Cast: - shadowCast.add(g); - break; case Receive: - shadowRecv.add(g); - break; case CastAndReceive: - shadowCast.add(g); - shadowRecv.add(g); break; default: throw new UnsupportedOperationException("Unrecognized shadow bucket type: " + shadBucket); @@ -331,6 +325,7 @@ public class RenderQueue { renderGeometryList(list, rm, cam, clear); } + @Deprecated public void renderShadowQueue(ShadowMode shadBucket, RenderManager rm, Camera cam, boolean clear) { switch (shadBucket) { case Cast: @@ -388,6 +383,14 @@ public class RenderQueue { } } + public void setRootScene(Spatial rs) { + rootScene = rs; + } + + public Spatial getRootScene() { + return rootScene; + } + public void clear() { opaqueList.clear(); guiList.clear(); diff --git a/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java index ae495b2b6..055b289fb 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java @@ -387,8 +387,9 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable public void postQueue(RenderQueue rq) { GeometryList occluders = rq.getShadowQueueContent(ShadowMode.Cast); sceneReceivers = rq.getShadowQueueContent(ShadowMode.Receive); + lightReceivers.clear(); skipPostPass = false; - if (sceneReceivers.size() == 0 || occluders.size() == 0 || !checkCulling(viewPort.getCamera())) { + if ( !checkCulling(viewPort.getCamera()) ) { skipPostPass = true; return; } @@ -473,12 +474,12 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable if (debug) { displayShadowMap(renderManager.getRenderer()); } - + lightReceivers = getReceivers(sceneReceivers, lightReceivers); if (lightReceivers.size() != 0) { //setting params to recieving geometry list - setMatParams(); + setMatParams(lightReceivers); Camera cam = viewPort.getCamera(); //some materials in the scene does not have a post shadow technique so we're using the fall back material @@ -541,10 +542,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable */ protected abstract void setMaterialParameters(Material material); - private void setMatParams() { - - GeometryList l = viewPort.getQueue().getShadowQueueContent(ShadowMode.Receive); - + private void setMatParams(GeometryList l) { //iteration throught all the geometries of the list to gather the materials matCache.clear(); @@ -785,4 +783,4 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable oc.write(flushQueues, "flushQueues", false); oc.write(edgesThickness, "edgesThickness", 1.0f); } -} \ No newline at end of file +} diff --git a/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java index 50be4c91d..f18222ee9 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java @@ -40,6 +40,7 @@ import com.jme3.renderer.RenderManager; import com.jme3.renderer.Renderer; import com.jme3.renderer.ViewPort; import com.jme3.renderer.queue.GeometryList; +import com.jme3.renderer.queue.OpaqueComparator; import com.jme3.renderer.queue.RenderQueue; import com.jme3.renderer.queue.RenderQueue.ShadowMode; import com.jme3.texture.FrameBuffer; @@ -71,6 +72,9 @@ public class BasicShadowRenderer implements SceneProcessor { protected Texture2D dummyTex; private float shadowMapSize; + protected GeometryList lightReceivers = new GeometryList(new OpaqueComparator()); + protected GeometryList shadowOccluders = new GeometryList(new OpaqueComparator()); + /** * Creates a BasicShadowRenderer * @param manager the asset manager @@ -142,15 +146,7 @@ public class BasicShadowRenderer implements SceneProcessor { } public void postQueue(RenderQueue rq) { - GeometryList occluders = rq.getShadowQueueContent(ShadowMode.Cast); - if (occluders.size() == 0) { - noOccluders = true; - return; - } else { - noOccluders = false; - } - - GeometryList receivers = rq.getShadowQueueContent(ShadowMode.Receive); + ShadowUtil.getGeometriesInCamFrustum(rq.getRootScene(), viewPort.getCamera(), ShadowMode.Receive, lightReceivers); // update frustum points based on current camera Camera viewCam = viewPort.getCamera(); @@ -178,15 +174,23 @@ public class BasicShadowRenderer implements SceneProcessor { shadowCam.updateViewProjection(); // render shadow casters to shadow map - ShadowUtil.updateShadowCamera(occluders, receivers, shadowCam, points, shadowMapSize); - + ShadowUtil.rootScene = rq.getRootScene(); + ShadowUtil.updateShadowCamera(null, lightReceivers, shadowCam, points, shadowOccluders, shadowMapSize); + ShadowUtil.rootScene = null; + if (shadowOccluders.size() == 0) { + noOccluders = true; + return; + } else { + noOccluders = false; + } + Renderer r = renderManager.getRenderer(); renderManager.setCamera(shadowCam, false); renderManager.setForcedMaterial(preshadowMat); r.setFrameBuffer(shadowFB); r.clearBuffers(false, true, false); - viewPort.getQueue().renderShadowQueue(ShadowMode.Cast, renderManager, shadowCam, true); + viewPort.getQueue().renderShadowQueue(shadowOccluders, renderManager, shadowCam, true); r.setFrameBuffer(viewPort.getOutputFrameBuffer()); renderManager.setForcedMaterial(null); @@ -205,7 +209,7 @@ public class BasicShadowRenderer implements SceneProcessor { if (!noOccluders) { postshadowMat.setMatrix4("LightViewProjectionMatrix", shadowCam.getViewProjectionMatrix()); renderManager.setForcedMaterial(postshadowMat); - viewPort.getQueue().renderShadowQueue(ShadowMode.Receive, renderManager, viewPort.getCamera(), true); + viewPort.getQueue().renderShadowQueue(lightReceivers, renderManager, shadowCam, true); renderManager.setForcedMaterial(null); } } diff --git a/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java index 9b47848aa..187b2e51e 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java @@ -42,7 +42,9 @@ import com.jme3.math.ColorRGBA; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; +import com.jme3.renderer.RenderManager; import com.jme3.renderer.queue.GeometryList; +import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Node; import java.io.IOException; @@ -178,14 +180,21 @@ public class DirectionalLightShadowRenderer extends AbstractShadowRenderer { // update frustum points based on current camera and split ShadowUtil.updateFrustumPoints(viewPort.getCamera(), splitsArray[shadowMapIndex], splitsArray[shadowMapIndex + 1], 1.0f, points); - //Updating shadow cam with curent split frustra - ShadowUtil.updateShadowCamera(sceneOccluders, sceneReceivers, shadowCam, points, shadowMapOccluders, stabilize?shadowMapSize:0); + //Updating shadow cam with curent split frustra + if (sceneReceivers.size()==0) { + ShadowUtil.getGeometriesInCamFrustum(viewPort.getQueue().getRootScene(), viewPort.getCamera(), RenderQueue.ShadowMode.Receive, sceneReceivers); + } + ShadowUtil.updateShadowCameraFromRoot(viewPort.getQueue().getRootScene(), sceneReceivers, shadowCam, points, shadowMapOccluders, stabilize?shadowMapSize:0); return shadowMapOccluders; } @Override GeometryList getReceivers(GeometryList sceneReceivers, GeometryList lightReceivers) { + if (sceneReceivers.size()==0) { + ShadowUtil.getGeometriesInCamFrustum(viewPort.getQueue().getRootScene(), viewPort.getCamera(), RenderQueue.ShadowMode.Receive, sceneReceivers); + } + lightReceivers = sceneReceivers; return sceneReceivers; } diff --git a/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java index 9d80adec8..b0926a64c 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java @@ -40,7 +40,10 @@ import com.jme3.light.PointLight; import com.jme3.material.Material; import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; +import com.jme3.renderer.RenderManager; import com.jme3.renderer.queue.GeometryList; +import com.jme3.renderer.queue.OpaqueComparator; +import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.Node; import com.jme3.util.TempVars; @@ -130,14 +133,14 @@ public class PointLightShadowRenderer extends AbstractShadowRenderer { @Override protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList sceneOccluders, GeometryList sceneReceivers, GeometryList shadowMapOccluders) { - ShadowUtil.getGeometriesInCamFrustum(sceneOccluders, shadowCams[shadowMapIndex], shadowMapOccluders); + ShadowUtil.getGeometriesInCamFrustum(viewPort.getQueue().getRootScene(), shadowCams[shadowMapIndex], RenderQueue.ShadowMode.Cast, shadowMapOccluders); return shadowMapOccluders; } @Override GeometryList getReceivers(GeometryList sceneReceivers, GeometryList lightReceivers) { lightReceivers.clear(); - ShadowUtil.getGeometriesInLightRadius(sceneReceivers, shadowCams, lightReceivers); + ShadowUtil.getLitGeometriesInViewPort(viewPort.getQueue().getRootScene(), viewPort.getCamera(), shadowCams, RenderQueue.ShadowMode.Receive, lightReceivers); return lightReceivers; } @@ -207,7 +210,7 @@ public class PointLightShadowRenderer extends AbstractShadowRenderer { oc.write(light, "light", null); } - /** + /** * * @param viewCam * @return @@ -224,6 +227,5 @@ public class PointLightShadowRenderer extends AbstractShadowRenderer { boolean intersects = light.intersectsFrustum(cam,vars); vars.release(); return intersects; - } } diff --git a/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java index 080c91fea..02f2d4e1f 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java @@ -175,6 +175,8 @@ public class PssmShadowRenderer implements SceneProcessor { protected float fadeLength; protected boolean applyFadeInfo = false; + protected GeometryList lightReceivers = new GeometryList(new OpaqueComparator()); + /** * Create a PSSM Shadow Renderer More info on the technique at http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html @@ -385,15 +387,7 @@ public class PssmShadowRenderer implements SceneProcessor { @SuppressWarnings("fallthrough") public void postQueue(RenderQueue rq) { - GeometryList occluders = rq.getShadowQueueContent(ShadowMode.Cast); - if (occluders.size() == 0) { - return; - } - - GeometryList receivers = rq.getShadowQueueContent(ShadowMode.Receive); - if (receivers.size() == 0) { - return; - } + ShadowUtil.getGeometriesInCamFrustum(rq.getRootScene(), viewPort.getCamera(), ShadowMode.Receive, lightReceivers); Camera viewCam = viewPort.getCamera(); @@ -437,7 +431,9 @@ public class PssmShadowRenderer implements SceneProcessor { ShadowUtil.updateFrustumPoints(viewCam, splitsArray[i], splitsArray[i + 1], 1.0f, points); //Updating shadow cam with curent split frustra - ShadowUtil.updateShadowCamera(occluders, receivers, shadowCam, points, splitOccluders, shadowMapSize); + ShadowUtil.rootScene = rq.getRootScene(); + ShadowUtil.updateShadowCamera(null, lightReceivers, shadowCam, points, splitOccluders, shadowMapSize); + ShadowUtil.rootScene = null; //saving light view projection matrix for this split lightViewProjectionsMatrices[i].set(shadowCam.getViewProjectionMatrix()); @@ -460,9 +456,7 @@ public class PssmShadowRenderer implements SceneProcessor { viewPort.getQueue().renderShadowQueue(splitOccluders, renderManager, shadowCam, true); } debugfrustums = false; - if (flushQueues) { - occluders.clear(); - } + //restore setting for future rendering r.setFrameBuffer(viewPort.getOutputFrameBuffer()); renderManager.setForcedMaterial(null); @@ -518,7 +512,7 @@ public class PssmShadowRenderer implements SceneProcessor { renderManager.setForcedTechnique(postTechniqueName); //rendering the post shadow pass - viewPort.getQueue().renderShadowQueue(ShadowMode.Receive, renderManager, cam, flushQueues); + viewPort.getQueue().renderShadowQueue(lightReceivers, renderManager, cam, true); //resetting renderManager settings renderManager.setForcedTechnique(null); @@ -531,7 +525,7 @@ public class PssmShadowRenderer implements SceneProcessor { private void setMatParams() { - GeometryList l = viewPort.getQueue().getShadowQueueContent(ShadowMode.Receive); + GeometryList l = lightReceivers; //iteration throught all the geometries of the list to gather the materials diff --git a/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java b/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java index 0795b990b..91858689b 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java +++ b/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java @@ -39,8 +39,12 @@ import com.jme3.math.Transform; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; +import com.jme3.renderer.RenderManager; import com.jme3.renderer.queue.GeometryList; +import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; import com.jme3.util.TempVars; import static java.lang.Math.max; import static java.lang.Math.min; @@ -343,7 +347,126 @@ public class ShadowUtil { float shadowMapSize) { updateShadowCamera(occluders, receivers, shadowCam, points, null, shadowMapSize); } + + /** + * OccludersExtractor is a helper class to collect splitOccluders from scene recursively. + * It utilizes the scene hierarchy, instead of making the huge flat geometries list first. + * Instead of adding all geometries from scene to the RenderQueue.shadowCast and checking + * all of them one by one against camera frustum the whole Node is checked first + * to hopefully avoid the check on its children. + */ + static public Spatial rootScene = null; // static global used for OccludersExtractor in order not to change public ShadoUtil.updateShadowCamera interface + public static class OccludersExtractor + { + // global variables set in order not to have recursive addOccluders method with too many parameters + Matrix4f viewProjMatrix; + public Integer casterCount; + BoundingBox splitBB, casterBB; + GeometryList splitOccluders; + TempVars vars; + + public OccludersExtractor() {} + + // initialize the global OccludersExtractor variables + public OccludersExtractor(Matrix4f vpm, int cc, BoundingBox sBB, BoundingBox cBB, GeometryList sOCC, TempVars v) { + viewProjMatrix = vpm; + casterCount = cc; + splitBB = sBB; + casterBB = cBB; + splitOccluders = sOCC; + vars = v; + } + /** + * Check the rootScene against camera frustum and if intersects process it recursively. + * The global OccludersExtractor variables need to be initialized first. + * The {@link OccludersExtractor#rootScene} need to be set before the call to {@link ShadowUtil#updateShadowCamera} + * Variables are updated and used in {@link ShadowUtil#updateShadowCamera} at last. + */ + public int addOccluders() { + if ( rootScene != null ) addOccluders(rootScene); + return casterCount; + } + + private void addOccluders(Spatial scene) { + if (scene.getCullHint() == Spatial.CullHint.Always) return; + + RenderQueue.ShadowMode shadowMode = scene.getShadowMode(); + if ( scene instanceof Geometry ) + { + // convert bounding box to light's viewproj space + Geometry occluder = (Geometry)scene; + if (shadowMode != RenderQueue.ShadowMode.Off && shadowMode != RenderQueue.ShadowMode.Receive + && !occluder.isGrouped() && occluder.getWorldBound()!=null) { + BoundingVolume bv = occluder.getWorldBound(); + BoundingVolume occBox = bv.transform(viewProjMatrix, vars.bbox); + + boolean intersects = splitBB.intersects(occBox); + if (!intersects && occBox instanceof BoundingBox) { + BoundingBox occBB = (BoundingBox) occBox; + //Kirill 01/10/2011 + // Extend the occluder further into the frustum + // This fixes shadow dissapearing issues when + // the caster itself is not in the view camera + // but its shadow is in the camera + // The number is in world units + occBB.setZExtent(occBB.getZExtent() + 50); + occBB.setCenter(occBB.getCenter().addLocal(0, 0, 25)); + if (splitBB.intersects(occBB)) { + //Nehon : prevent NaN and infinity values to screw the final bounding box + if (!Float.isNaN(occBox.getCenter().x) && !Float.isInfinite(occBox.getCenter().x)) { + // To prevent extending the depth range too much + // We return the bound to its former shape + // Before adding it + occBB.setZExtent(occBB.getZExtent() - 50); + occBB.setCenter(occBB.getCenter().subtractLocal(0, 0, 25)); + casterBB.mergeLocal(occBox); + casterCount++; + } + if (splitOccluders != null) { + splitOccluders.add(occluder); + } + } + } else if (intersects) { + casterBB.mergeLocal(occBox); + casterCount++; + if (splitOccluders != null) { + splitOccluders.add(occluder); + } + } + } + } + else if ( scene instanceof Node && ((Node)scene).getWorldBound()!=null ) + { + Node nodeOcc = (Node)scene; + boolean intersects = false; + // some + BoundingVolume bv = nodeOcc.getWorldBound(); + BoundingVolume occBox = bv.transform(viewProjMatrix, vars.bbox); + + intersects = splitBB.intersects(occBox); + if (!intersects && occBox instanceof BoundingBox) { + BoundingBox occBB = (BoundingBox) occBox; + //Kirill 01/10/2011 + // Extend the occluder further into the frustum + // This fixes shadow dissapearing issues when + // the caster itself is not in the view camera + // but its shadow is in the camera + // The number is in world units + occBB.setZExtent(occBB.getZExtent() + 50); + occBB.setCenter(occBB.getCenter().addLocal(0, 0, 25)); + intersects = splitBB.intersects(occBB); + } + + if ( intersects ) { + for (Spatial child : ((Node)scene).getChildren()) { + addOccluders(child); + } + } + } + } + } + /** * Updates the shadow camera to properly contain the given points (which * contain the eye camera frustum corners) and the shadow occluder objects. @@ -394,47 +517,9 @@ public class ShadowUtil { } } - for (int i = 0; i < occluders.size(); i++) { - // convert bounding box to light's viewproj space - Geometry occluder = occluders.get(i); - BoundingVolume bv = occluder.getWorldBound(); - BoundingVolume occBox = bv.transform(viewProjMatrix, vars.bbox); - - boolean intersects = splitBB.intersects(occBox); - if (!intersects && occBox instanceof BoundingBox) { - BoundingBox occBB = (BoundingBox) occBox; - //Kirill 01/10/2011 - // Extend the occluder further into the frustum - // This fixes shadow dissapearing issues when - // the caster itself is not in the view camera - // but its shadow is in the camera - // The number is in world units - occBB.setZExtent(occBB.getZExtent() + 50); - occBB.setCenter(occBB.getCenter().addLocal(0, 0, 25)); - if (splitBB.intersects(occBB)) { - //Nehon : prevent NaN and infinity values to screw the final bounding box - if (!Float.isNaN(occBox.getCenter().x) && !Float.isInfinite(occBox.getCenter().x)) { - // To prevent extending the depth range too much - // We return the bound to its former shape - // Before adding it - occBB.setZExtent(occBB.getZExtent() - 50); - occBB.setCenter(occBB.getCenter().subtractLocal(0, 0, 25)); - casterBB.mergeLocal(occBox); - casterCount++; - } - if (splitOccluders != null) { - splitOccluders.add(occluder); - } - - } - } else if (intersects) { - casterBB.mergeLocal(occBox); - casterCount++; - if (splitOccluders != null) { - splitOccluders.add(occluder); - } - } - } + // collect splitOccluders through scene recursive traverse + OccludersExtractor occExt = new OccludersExtractor(viewProjMatrix, casterCount, splitBB, casterBB, splitOccluders, vars); + casterCount = occExt.addOccluders(); // the rootScene inside //Nehon 08/18/2010 this is to avoid shadow bleeding when the ground is set to only receive shadows if (casterCount != receiverCount) { @@ -526,6 +611,23 @@ public class ShadowUtil { } + /** + * Updates the shadow camera to properly contain the given points (which + * contain the eye camera frustum corners) and the shadow occluder objects. + * + * Render Shadow optimization to traverse the scene hierarchy instead of using the whole, but flattened, scene + */ + public static void updateShadowCameraFromRoot(Spatial rootScene, + GeometryList receivers, + Camera shadowCam, + Vector3f[] points, + GeometryList splitOccluders, + float shadowMapSize) { + ShadowUtil.rootScene = rootScene; + ShadowUtil.updateShadowCamera(null, receivers, shadowCam, points, splitOccluders, shadowMapSize); + ShadowUtil.rootScene = null; + } + /** * Populates the outputGeometryList with the geometry of the * inputGeomtryList that are in the frustum of the given camera @@ -551,10 +653,75 @@ public class ShadowUtil { } + /** + * Populates the outputGeometryList with the geometries of the children + * of OccludersExtractor.rootScene node that are in the frustum of the given camera + * + * @param camera the camera to check geometries against + * @param outputGeometryList the list of all geometries that are in the + * camera frustum + */ + public static void getGeometriesInCamFrustum(Spatial rootScene, Camera camera, RenderQueue.ShadowMode mode, GeometryList outputGeometryList) { + if (rootScene != null && rootScene instanceof Node) { + int planeState = camera.getPlaneState(); + addGeometriesInCamFrustumFromNode(camera, (Node)rootScene, mode, outputGeometryList); + camera.setPlaneState(planeState); + } + } + + /** + * Helper function to distinguish between Occluders and Receivers + * + * @param shadowMode the ShadowMode tested + * @param desired the desired ShadowMode + * @return true if tested ShadowMode matches the desired one + */ + static private boolean checkShadowMode(RenderQueue.ShadowMode shadowMode, RenderQueue.ShadowMode desired) + { + if (shadowMode != RenderQueue.ShadowMode.Off) + { + switch (desired) { + case Cast : + return shadowMode==RenderQueue.ShadowMode.Cast || shadowMode==RenderQueue.ShadowMode.CastAndReceive; + case Receive: + return shadowMode==RenderQueue.ShadowMode.Receive || shadowMode==RenderQueue.ShadowMode.CastAndReceive; + case CastAndReceive: + return true; + } + } + return false; + } + + /** + * Helper function used to recursively populate the outputGeometryList + * with geometry children of scene node + * + * @param camera + * @param scene + * @param outputGeometryList + */ + private static void addGeometriesInCamFrustumFromNode(Camera camera, Node scene, RenderQueue.ShadowMode mode, GeometryList outputGeometryList) { + if (scene.getCullHint() == Spatial.CullHint.Always) return; + camera.setPlaneState(0); + if (camera.contains(scene.getWorldBound()) != Camera.FrustumIntersect.Outside) { + for (Spatial child: scene.getChildren()) { + if (child instanceof Node) addGeometriesInCamFrustumFromNode(camera, (Node)child, mode, outputGeometryList); + else if (child instanceof Geometry && child.getCullHint() != Spatial.CullHint.Always) { + camera.setPlaneState(0); + if (checkShadowMode(child.getShadowMode(), mode) && + !((Geometry)child).isGrouped() && + camera.contains(child.getWorldBound()) != Camera.FrustumIntersect.Outside) { + outputGeometryList.add((Geometry)child); + } + } + } + } + } + /** * Populates the outputGeometryList with the geometry of the * inputGeomtryList that are in the radius of a light. - * The array of camera must be an array of 6 cameara initialized so they represent the light viewspace of a pointlight + * The array of camera must be an array of 6 cameras initialized so they represent the light viewspace of a pointlight * * @param inputGeometryList The list containing all geometry to check * against the camera frustum @@ -581,4 +748,54 @@ public class ShadowUtil { } } + + /** + * Populates the outputGeometryList with the geometries of the children + * of OccludersExtractor.rootScene node that are both in the frustum of the given vpCamera and some camera inside cameras array. + * The array of cameras must be initialized to represent the light viewspace of some light like pointLight or spotLight + * + * @param camera the viewPort camera + * @param cameras the camera array to check geometries against, representing the light viewspace + * @param outputGeometryList the output list of all geometries that are in the camera frustum + */ + public static void getLitGeometriesInViewPort(Spatial rootScene, Camera vpCamera, Camera[] cameras, RenderQueue.ShadowMode mode, GeometryList outputGeometryList) { + if (rootScene != null && rootScene instanceof Node) { + addGeometriesInCamFrustumAndViewPortFromNode(vpCamera, cameras, (Node)rootScene, mode, outputGeometryList); + } + } + /** + * Helper function to recursively collect the geometries for getLitGeometriesInViewPort function. + * + * @param vpCamera the viewPort camera + * @param cameras the camera array to check geometries against, representing the light viewspace + * @param scene the Node to traverse or geometry to possibly add + * @param outputGeometryList the output list of all geometries that are in the camera frustum + */ + private static void addGeometriesInCamFrustumAndViewPortFromNode(Camera vpCamera, Camera[] cameras, Spatial scene, RenderQueue.ShadowMode mode, GeometryList outputGeometryList) { + if (scene.getCullHint() == Spatial.CullHint.Always) return; + + boolean inFrustum = false; + for (int j = 0; j < cameras.length && inFrustum == false; j++) { + Camera camera = cameras[j]; + int planeState = camera.getPlaneState(); + camera.setPlaneState(0); + inFrustum = camera.contains(scene.getWorldBound()) != Camera.FrustumIntersect.Outside && scene.checkCulling(vpCamera); + camera.setPlaneState(planeState); + } + if (inFrustum) { + if (scene instanceof Node) + { + Node node = (Node)scene; + for (Spatial child: node.getChildren()) { + addGeometriesInCamFrustumAndViewPortFromNode(vpCamera, cameras, child, mode, outputGeometryList); + } + } + else if (scene instanceof Geometry) { + if (checkShadowMode(scene.getShadowMode(), mode) && !((Geometry)scene).isGrouped() ) { + outputGeometryList.add((Geometry)scene); + } + } + } + } + } diff --git a/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java index 1fbcba2e3..6b2386e04 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java @@ -42,7 +42,9 @@ import com.jme3.math.FastMath; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; +import com.jme3.renderer.RenderManager; import com.jme3.renderer.queue.GeometryList; +import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Node; import com.jme3.util.TempVars; import java.io.IOException; @@ -142,14 +144,16 @@ public class SpotLightShadowRenderer extends AbstractShadowRenderer { @Override protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList sceneOccluders, GeometryList sceneReceivers, GeometryList shadowMapOccluders) { - ShadowUtil.getGeometriesInCamFrustum(sceneOccluders, shadowCam, shadowMapOccluders); + ShadowUtil.getGeometriesInCamFrustum(viewPort.getQueue().getRootScene(), shadowCam, RenderQueue.ShadowMode.Cast, shadowMapOccluders); return shadowMapOccluders; } @Override GeometryList getReceivers(GeometryList sceneReceivers, GeometryList lightReceivers) { lightReceivers.clear(); - ShadowUtil.getGeometriesInCamFrustum(sceneReceivers, shadowCam, lightReceivers); + Camera[] cameras = new Camera[1]; + cameras[0] = shadowCam; + ShadowUtil.getLitGeometriesInViewPort(viewPort.getQueue().getRootScene(), viewPort.getCamera(), cameras, RenderQueue.ShadowMode.Receive, lightReceivers); return lightReceivers; } From 4569154d9f06d71e8b76dc0667aef31a05c31138 Mon Sep 17 00:00:00 2001 From: Bebul Date: Mon, 2 Feb 2015 14:02:26 +0100 Subject: [PATCH 07/28] RenderShadow relict code clean up, no more static ShadowUtils.rootScene --- .../java/com/jme3/renderer/RenderManager.java | 24 ------- .../com/jme3/renderer/queue/RenderQueue.java | 51 +------------- .../jme3/shadow/AbstractShadowRenderer.java | 13 ++-- .../com/jme3/shadow/BasicShadowRenderer.java | 6 +- .../DirectionalLightShadowRenderer.java | 5 +- .../jme3/shadow/PointLightShadowRenderer.java | 4 +- .../com/jme3/shadow/PssmShadowRenderer.java | 4 +- .../main/java/com/jme3/shadow/ShadowUtil.java | 66 ++++--------------- .../jme3/shadow/SpotLightShadowRenderer.java | 3 +- 9 files changed, 27 insertions(+), 149 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java index 598a428e6..89d41761c 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -586,30 +586,6 @@ public class RenderManager { } } - /** - * If a spatial is not inside the eye frustum, it - * is still rendered in the shadow frustum (shadow casting queue) - * through this recursive method. - */ - @Deprecated - private void renderShadow(Spatial s, RenderQueue rq) { - if (s instanceof Node) { - Node n = (Node) s; - List children = n.getChildren(); - for (int i = 0; i < children.size(); i++) { - renderShadow(children.get(i), rq); - } - } else if (s instanceof Geometry) { - Geometry gm = (Geometry) s; - - RenderQueue.ShadowMode shadowMode = s.getShadowMode(); - if (shadowMode != RenderQueue.ShadowMode.Off && shadowMode != RenderQueue.ShadowMode.Receive && !gm.isGrouped()) { - //forcing adding to shadow cast mode, culled objects doesn't have to be in the receiver queue - rq.addToShadowQueue(gm, RenderQueue.ShadowMode.Cast); - } - } - } - /** * Preloads a scene for rendering. *

diff --git a/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java b/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java index 1a6728540..9bd46f30f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java +++ b/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java @@ -50,8 +50,7 @@ public class RenderQueue { private GeometryList transparentList; private GeometryList translucentList; private GeometryList skyList; - @Deprecated private GeometryList shadowRecv; - @Deprecated private GeometryList shadowCast; + private GeometryList shadowRecv; private Spatial rootScene = null; /** @@ -65,7 +64,6 @@ public class RenderQueue { this.translucentList = new GeometryList(new TransparentComparator()); this.skyList = new GeometryList(new NullComparator()); this.shadowRecv = new GeometryList(new OpaqueComparator()); - this.shadowCast = new GeometryList(new OpaqueComparator()); } /** @@ -230,33 +228,6 @@ public class RenderQueue { } } - /** - * Adds a geometry to a shadow bucket. - * Note that this operation is done automatically by the - * {@link RenderManager}. {@link SceneProcessor}s that handle - * shadow rendering should fetch the queue by using - * {@link #getShadowQueueContent(com.jme3.renderer.queue.RenderQueue.ShadowMode) }, - * by default no action is taken on the shadow queues. - * - * @param g The geometry to add - * @param shadBucket The shadow bucket type, if it is - * {@link ShadowMode#CastAndReceive}, it is added to both the cast - * and the receive buckets. - */ - @Deprecated - public void addToShadowQueue(Geometry g, ShadowMode shadBucket) { - switch (shadBucket) { - case Inherit: - case Off: - case Cast: - case Receive: - case CastAndReceive: - break; - default: - throw new UnsupportedOperationException("Unrecognized shadow bucket type: " + shadBucket); - } - } - /** * Adds a geometry to the given bucket. * The {@link RenderManager} automatically handles this task @@ -292,14 +263,11 @@ public class RenderQueue { /** * * @param shadBucket The shadow mode to retrieve the {@link GeometryList - * queue content} for. Only {@link ShadowMode#Cast Cast} and - * {@link ShadowMode#Receive Receive} are valid. + * queue content} for. Only {@link ShadowMode#Receive Receive} is valid. * @return The cast or receive {@link GeometryList} */ public GeometryList getShadowQueueContent(ShadowMode shadBucket) { switch (shadBucket) { - case Cast: - return shadowCast; case Receive: return shadowRecv; default: @@ -325,20 +293,6 @@ public class RenderQueue { renderGeometryList(list, rm, cam, clear); } - @Deprecated - public void renderShadowQueue(ShadowMode shadBucket, RenderManager rm, Camera cam, boolean clear) { - switch (shadBucket) { - case Cast: - renderGeometryList(shadowCast, rm, cam, clear); - break; - case Receive: - renderGeometryList(shadowRecv, rm, cam, clear); - break; - default: - throw new IllegalArgumentException("Unexpected shadow bucket: " + shadBucket); - } - } - public boolean isQueueEmpty(Bucket bucket) { switch (bucket) { case Gui: @@ -397,7 +351,6 @@ public class RenderQueue { transparentList.clear(); translucentList.clear(); skyList.clear(); - shadowCast.clear(); shadowRecv.clear(); } } diff --git a/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java index 055b289fb..545dff9e4 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java @@ -363,7 +363,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable * @param shadowMapOcculders * @return */ - protected abstract GeometryList getOccludersToRender(int shadowMapIndex, GeometryList sceneOccluders, GeometryList sceneReceivers, GeometryList shadowMapOccluders); + protected abstract GeometryList getOccludersToRender(int shadowMapIndex, GeometryList shadowMapOccluders); /** * return the shadow camera to use for rendering the shadow map according @@ -385,7 +385,6 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable @SuppressWarnings("fallthrough") public void postQueue(RenderQueue rq) { - GeometryList occluders = rq.getShadowQueueContent(ShadowMode.Cast); sceneReceivers = rq.getShadowQueueContent(ShadowMode.Receive); lightReceivers.clear(); skipPostPass = false; @@ -405,14 +404,12 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable if (debugfrustums) { doDisplayFrustumDebug(shadowMapIndex); } - renderShadowMap(shadowMapIndex, occluders, sceneReceivers); + renderShadowMap(shadowMapIndex); } debugfrustums = false; - if (flushQueues) { - occluders.clear(); - } + //restore setting for future rendering r.setFrameBuffer(viewPort.getOutputFrameBuffer()); renderManager.setForcedMaterial(null); @@ -421,8 +418,8 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable } - protected void renderShadowMap(int shadowMapIndex, GeometryList occluders, GeometryList receivers) { - shadowMapOccluders = getOccludersToRender(shadowMapIndex, occluders, receivers, shadowMapOccluders); + protected void renderShadowMap(int shadowMapIndex) { + shadowMapOccluders = getOccludersToRender(shadowMapIndex, shadowMapOccluders); Camera shadowCam = getShadowCam(shadowMapIndex); //saving light view projection matrix for this split diff --git a/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java index f18222ee9..bc86bd210 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java @@ -174,9 +174,7 @@ public class BasicShadowRenderer implements SceneProcessor { shadowCam.updateViewProjection(); // render shadow casters to shadow map - ShadowUtil.rootScene = rq.getRootScene(); - ShadowUtil.updateShadowCamera(null, lightReceivers, shadowCam, points, shadowOccluders, shadowMapSize); - ShadowUtil.rootScene = null; + ShadowUtil.updateShadowCamera(rq.getRootScene(), lightReceivers, shadowCam, points, shadowOccluders, shadowMapSize); if (shadowOccluders.size() == 0) { noOccluders = true; return; @@ -209,7 +207,7 @@ public class BasicShadowRenderer implements SceneProcessor { if (!noOccluders) { postshadowMat.setMatrix4("LightViewProjectionMatrix", shadowCam.getViewProjectionMatrix()); renderManager.setForcedMaterial(postshadowMat); - viewPort.getQueue().renderShadowQueue(lightReceivers, renderManager, shadowCam, true); + viewPort.getQueue().renderShadowQueue(lightReceivers, renderManager, viewPort.getCamera(), true); renderManager.setForcedMaterial(null); } } diff --git a/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java index 187b2e51e..f5f0f1b92 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java @@ -42,7 +42,6 @@ import com.jme3.math.ColorRGBA; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; -import com.jme3.renderer.RenderManager; import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Node; @@ -175,7 +174,7 @@ public class DirectionalLightShadowRenderer extends AbstractShadowRenderer { } @Override - protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList sceneOccluders, GeometryList sceneReceivers, GeometryList shadowMapOccluders) { + protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList shadowMapOccluders) { // update frustum points based on current camera and split ShadowUtil.updateFrustumPoints(viewPort.getCamera(), splitsArray[shadowMapIndex], splitsArray[shadowMapIndex + 1], 1.0f, points); @@ -184,7 +183,7 @@ public class DirectionalLightShadowRenderer extends AbstractShadowRenderer { if (sceneReceivers.size()==0) { ShadowUtil.getGeometriesInCamFrustum(viewPort.getQueue().getRootScene(), viewPort.getCamera(), RenderQueue.ShadowMode.Receive, sceneReceivers); } - ShadowUtil.updateShadowCameraFromRoot(viewPort.getQueue().getRootScene(), sceneReceivers, shadowCam, points, shadowMapOccluders, stabilize?shadowMapSize:0); + ShadowUtil.updateShadowCamera(viewPort.getQueue().getRootScene(), sceneReceivers, shadowCam, points, shadowMapOccluders, stabilize?shadowMapSize:0); return shadowMapOccluders; } diff --git a/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java index b0926a64c..df09adbe9 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java @@ -40,9 +40,7 @@ import com.jme3.light.PointLight; import com.jme3.material.Material; import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; -import com.jme3.renderer.RenderManager; import com.jme3.renderer.queue.GeometryList; -import com.jme3.renderer.queue.OpaqueComparator; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.Node; @@ -132,7 +130,7 @@ public class PointLightShadowRenderer extends AbstractShadowRenderer { } @Override - protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList sceneOccluders, GeometryList sceneReceivers, GeometryList shadowMapOccluders) { + protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList shadowMapOccluders) { ShadowUtil.getGeometriesInCamFrustum(viewPort.getQueue().getRootScene(), shadowCams[shadowMapIndex], RenderQueue.ShadowMode.Cast, shadowMapOccluders); return shadowMapOccluders; } diff --git a/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java index 02f2d4e1f..f1985df9d 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java @@ -431,9 +431,7 @@ public class PssmShadowRenderer implements SceneProcessor { ShadowUtil.updateFrustumPoints(viewCam, splitsArray[i], splitsArray[i + 1], 1.0f, points); //Updating shadow cam with curent split frustra - ShadowUtil.rootScene = rq.getRootScene(); - ShadowUtil.updateShadowCamera(null, lightReceivers, shadowCam, points, splitOccluders, shadowMapSize); - ShadowUtil.rootScene = null; + ShadowUtil.updateShadowCamera(rq.getRootScene(), lightReceivers, shadowCam, points, splitOccluders, shadowMapSize); //saving light view projection matrix for this split lightViewProjectionsMatrices[i].set(shadowCam.getViewProjectionMatrix()); diff --git a/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java b/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java index 91858689b..b4f41e0a4 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java +++ b/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java @@ -39,7 +39,6 @@ import com.jme3.math.Transform; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; -import com.jme3.renderer.RenderManager; import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; @@ -331,23 +330,6 @@ public class ShadowUtil { shadowCam.setProjectionMatrix(result); } - /** - * Updates the shadow camera to properly contain the given points (which - * contain the eye camera frustum corners) and the shadow occluder objects. - * - * @param occluders - * @param receivers - * @param shadowCam - * @param points - */ - public static void updateShadowCamera(GeometryList occluders, - GeometryList receivers, - Camera shadowCam, - Vector3f[] points, - float shadowMapSize) { - updateShadowCamera(occluders, receivers, shadowCam, points, null, shadowMapSize); - } - /** * OccludersExtractor is a helper class to collect splitOccluders from scene recursively. * It utilizes the scene hierarchy, instead of making the huge flat geometries list first. @@ -355,10 +337,9 @@ public class ShadowUtil { * all of them one by one against camera frustum the whole Node is checked first * to hopefully avoid the check on its children. */ - static public Spatial rootScene = null; // static global used for OccludersExtractor in order not to change public ShadoUtil.updateShadowCamera interface public static class OccludersExtractor { - // global variables set in order not to have recursive addOccluders method with too many parameters + // global variables set in order not to have recursive process method with too many parameters Matrix4f viewProjMatrix; public Integer casterCount; BoundingBox splitBB, casterBB; @@ -380,15 +361,14 @@ public class ShadowUtil { /** * Check the rootScene against camera frustum and if intersects process it recursively. * The global OccludersExtractor variables need to be initialized first. - * The {@link OccludersExtractor#rootScene} need to be set before the call to {@link ShadowUtil#updateShadowCamera} * Variables are updated and used in {@link ShadowUtil#updateShadowCamera} at last. */ - public int addOccluders() { - if ( rootScene != null ) addOccluders(rootScene); + public int addOccluders(Spatial scene) { + if ( scene != null ) process(scene); return casterCount; } - private void addOccluders(Spatial scene) { + private void process(Spatial scene) { if (scene.getCullHint() == Spatial.CullHint.Always) return; RenderQueue.ShadowMode shadowMode = scene.getShadowMode(); @@ -460,7 +440,7 @@ public class ShadowUtil { if ( intersects ) { for (Spatial child : ((Node)scene).getChildren()) { - addOccluders(child); + process(child); } } } @@ -469,13 +449,10 @@ public class ShadowUtil { /** * Updates the shadow camera to properly contain the given points (which - * contain the eye camera frustum corners) and the shadow occluder objects. - * - * @param occluders - * @param shadowCam - * @param points + * contain the eye camera frustum corners) and the shadow occluder objects + * collected through the traverse of the scene hierarchy */ - public static void updateShadowCamera(GeometryList occluders, + public static void updateShadowCamera(Spatial rootScene, GeometryList receivers, Camera shadowCam, Vector3f[] points, @@ -519,8 +496,8 @@ public class ShadowUtil { // collect splitOccluders through scene recursive traverse OccludersExtractor occExt = new OccludersExtractor(viewProjMatrix, casterCount, splitBB, casterBB, splitOccluders, vars); - casterCount = occExt.addOccluders(); // the rootScene inside - + casterCount = occExt.addOccluders(rootScene); + //Nehon 08/18/2010 this is to avoid shadow bleeding when the ground is set to only receive shadows if (casterCount != receiverCount) { casterBB.setXExtent(casterBB.getXExtent() + 2.0f); @@ -608,24 +585,6 @@ public class ShadowUtil { vars.release(); shadowCam.setProjectionMatrix(result); - - } - - /** - * Updates the shadow camera to properly contain the given points (which - * contain the eye camera frustum corners) and the shadow occluder objects. - * - * Render Shadow optimization to traverse the scene hierarchy instead of using the whole, but flattened, scene - */ - public static void updateShadowCameraFromRoot(Spatial rootScene, - GeometryList receivers, - Camera shadowCam, - Vector3f[] points, - GeometryList splitOccluders, - float shadowMapSize) { - ShadowUtil.rootScene = rootScene; - ShadowUtil.updateShadowCamera(null, receivers, shadowCam, points, splitOccluders, shadowMapSize); - ShadowUtil.rootScene = null; } /** @@ -654,9 +613,10 @@ public class ShadowUtil { } /** - * Populates the outputGeometryList with the geometries of the children - * of OccludersExtractor.rootScene node that are in the frustum of the given camera + * Populates the outputGeometryList with the rootScene children geometries + * that are in the frustum of the given camera * + * @param rootScene the rootNode of the scene to traverse * @param camera the camera to check geometries against * @param outputGeometryList the list of all geometries that are in the * camera frustum diff --git a/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java index 6b2386e04..c8207f615 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java @@ -42,7 +42,6 @@ import com.jme3.math.FastMath; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; -import com.jme3.renderer.RenderManager; import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Node; @@ -143,7 +142,7 @@ public class SpotLightShadowRenderer extends AbstractShadowRenderer { } @Override - protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList sceneOccluders, GeometryList sceneReceivers, GeometryList shadowMapOccluders) { + protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList shadowMapOccluders) { ShadowUtil.getGeometriesInCamFrustum(viewPort.getQueue().getRootScene(), shadowCam, RenderQueue.ShadowMode.Cast, shadowMapOccluders); return shadowMapOccluders; } From ed369135fa471495b9d6190e31a9d1094cc628d7 Mon Sep 17 00:00:00 2001 From: Bebul Date: Fri, 20 Feb 2015 11:58:49 +0100 Subject: [PATCH 08/28] fix renderShadow optimization to work on multiple scenes attached to viewPort properly --- .../main/java/com/jme3/renderer/RenderManager.java | 2 -- .../java/com/jme3/renderer/queue/RenderQueue.java | 9 --------- .../java/com/jme3/shadow/AbstractShadowRenderer.java | 6 +++--- .../java/com/jme3/shadow/BasicShadowRenderer.java | 7 +++++-- .../jme3/shadow/DirectionalLightShadowRenderer.java | 11 ++++++++--- .../com/jme3/shadow/PointLightShadowRenderer.java | 9 +++++++-- .../main/java/com/jme3/shadow/PssmShadowRenderer.java | 6 ++++-- .../src/main/java/com/jme3/shadow/ShadowUtil.java | 8 ++++++-- .../java/com/jme3/shadow/SpotLightShadowRenderer.java | 9 +++++++-- 9 files changed, 40 insertions(+), 27 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java index 89d41761c..2c0c8a4b8 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -658,8 +658,6 @@ public class RenderManager { public void renderScene(Spatial scene, ViewPort vp) { //reset of the camera plane state for proper culling (must be 0 for the first note of the scene to be rendered) vp.getCamera().setPlaneState(0); - //remember the scene for possible later use - vp.getQueue().setRootScene(scene); //rendering the scene renderSubScene(scene, vp); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java b/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java index 9bd46f30f..ea4215d6c 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java +++ b/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java @@ -51,7 +51,6 @@ public class RenderQueue { private GeometryList translucentList; private GeometryList skyList; private GeometryList shadowRecv; - private Spatial rootScene = null; /** * Creates a new RenderQueue, the default {@link GeometryComparator comparators} @@ -337,14 +336,6 @@ public class RenderQueue { } } - public void setRootScene(Spatial rs) { - rootScene = rs; - } - - public Spatial getRootScene() { - return rootScene; - } - public void clear() { opaqueList.clear(); guiList.clear(); diff --git a/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java index 545dff9e4..b78d1e3bd 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java @@ -489,9 +489,6 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable //rendering the post shadow pass viewPort.getQueue().renderShadowQueue(lightReceivers, renderManager, cam, false); - if (flushQueues) { - sceneReceivers.clear(); - } //resetting renderManager settings renderManager.setForcedTechnique(null); @@ -502,6 +499,9 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable clearMatParams(); } + if (flushQueues) { + sceneReceivers.clear(); + } } /** diff --git a/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java index bc86bd210..bc4273db7 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java @@ -43,6 +43,7 @@ import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.OpaqueComparator; import com.jme3.renderer.queue.RenderQueue; import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Spatial; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image.Format; import com.jme3.texture.Texture2D; @@ -146,7 +147,9 @@ public class BasicShadowRenderer implements SceneProcessor { } public void postQueue(RenderQueue rq) { - ShadowUtil.getGeometriesInCamFrustum(rq.getRootScene(), viewPort.getCamera(), ShadowMode.Receive, lightReceivers); + for (Spatial scene : viewPort.getScenes()) { + ShadowUtil.getGeometriesInCamFrustum(scene, viewPort.getCamera(), ShadowMode.Receive, lightReceivers); + } // update frustum points based on current camera Camera viewCam = viewPort.getCamera(); @@ -174,7 +177,7 @@ public class BasicShadowRenderer implements SceneProcessor { shadowCam.updateViewProjection(); // render shadow casters to shadow map - ShadowUtil.updateShadowCamera(rq.getRootScene(), lightReceivers, shadowCam, points, shadowOccluders, shadowMapSize); + ShadowUtil.updateShadowCamera(viewPort, lightReceivers, shadowCam, points, shadowOccluders, shadowMapSize); if (shadowOccluders.size() == 0) { noOccluders = true; return; diff --git a/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java index f5f0f1b92..1c5b2617c 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java @@ -45,6 +45,7 @@ import com.jme3.renderer.Camera; import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Node; +import com.jme3.scene.Spatial; import java.io.IOException; /** @@ -181,9 +182,11 @@ public class DirectionalLightShadowRenderer extends AbstractShadowRenderer { //Updating shadow cam with curent split frustra if (sceneReceivers.size()==0) { - ShadowUtil.getGeometriesInCamFrustum(viewPort.getQueue().getRootScene(), viewPort.getCamera(), RenderQueue.ShadowMode.Receive, sceneReceivers); + for (Spatial scene : viewPort.getScenes()) { + ShadowUtil.getGeometriesInCamFrustum(scene, viewPort.getCamera(), RenderQueue.ShadowMode.Receive, sceneReceivers); + } } - ShadowUtil.updateShadowCamera(viewPort.getQueue().getRootScene(), sceneReceivers, shadowCam, points, shadowMapOccluders, stabilize?shadowMapSize:0); + ShadowUtil.updateShadowCamera(viewPort, sceneReceivers, shadowCam, points, shadowMapOccluders, stabilize?shadowMapSize:0); return shadowMapOccluders; } @@ -191,7 +194,9 @@ public class DirectionalLightShadowRenderer extends AbstractShadowRenderer { @Override GeometryList getReceivers(GeometryList sceneReceivers, GeometryList lightReceivers) { if (sceneReceivers.size()==0) { - ShadowUtil.getGeometriesInCamFrustum(viewPort.getQueue().getRootScene(), viewPort.getCamera(), RenderQueue.ShadowMode.Receive, sceneReceivers); + for (Spatial scene : viewPort.getScenes()) { + ShadowUtil.getGeometriesInCamFrustum(scene, viewPort.getCamera(), RenderQueue.ShadowMode.Receive, sceneReceivers); + } } lightReceivers = sceneReceivers; return sceneReceivers; diff --git a/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java index df09adbe9..4ded98b23 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java @@ -44,6 +44,7 @@ import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.Node; +import com.jme3.scene.Spatial; import com.jme3.util.TempVars; import java.io.IOException; @@ -131,14 +132,18 @@ public class PointLightShadowRenderer extends AbstractShadowRenderer { @Override protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList shadowMapOccluders) { - ShadowUtil.getGeometriesInCamFrustum(viewPort.getQueue().getRootScene(), shadowCams[shadowMapIndex], RenderQueue.ShadowMode.Cast, shadowMapOccluders); + for (Spatial scene : viewPort.getScenes()) { + ShadowUtil.getGeometriesInCamFrustum(scene, shadowCams[shadowMapIndex], RenderQueue.ShadowMode.Cast, shadowMapOccluders); + } return shadowMapOccluders; } @Override GeometryList getReceivers(GeometryList sceneReceivers, GeometryList lightReceivers) { lightReceivers.clear(); - ShadowUtil.getLitGeometriesInViewPort(viewPort.getQueue().getRootScene(), viewPort.getCamera(), shadowCams, RenderQueue.ShadowMode.Receive, lightReceivers); + for (Spatial scene : viewPort.getScenes()) { + ShadowUtil.getLitGeometriesInViewPort(scene, viewPort.getCamera(), shadowCams, RenderQueue.ShadowMode.Receive, lightReceivers); + } return lightReceivers; } diff --git a/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java index f1985df9d..182052e13 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java @@ -387,7 +387,9 @@ public class PssmShadowRenderer implements SceneProcessor { @SuppressWarnings("fallthrough") public void postQueue(RenderQueue rq) { - ShadowUtil.getGeometriesInCamFrustum(rq.getRootScene(), viewPort.getCamera(), ShadowMode.Receive, lightReceivers); + for (Spatial scene : viewPort.getScenes()) { + ShadowUtil.getGeometriesInCamFrustum(scene, viewPort.getCamera(), ShadowMode.Receive, lightReceivers); + } Camera viewCam = viewPort.getCamera(); @@ -431,7 +433,7 @@ public class PssmShadowRenderer implements SceneProcessor { ShadowUtil.updateFrustumPoints(viewCam, splitsArray[i], splitsArray[i + 1], 1.0f, points); //Updating shadow cam with curent split frustra - ShadowUtil.updateShadowCamera(rq.getRootScene(), lightReceivers, shadowCam, points, splitOccluders, shadowMapSize); + ShadowUtil.updateShadowCamera(viewPort, lightReceivers, shadowCam, points, splitOccluders, shadowMapSize); //saving light view projection matrix for this split lightViewProjectionsMatrices[i].set(shadowCam.getViewProjectionMatrix()); diff --git a/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java b/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java index b4f41e0a4..d97a354f9 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java +++ b/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java @@ -39,6 +39,7 @@ import com.jme3.math.Transform; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; +import com.jme3.renderer.ViewPort; import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; @@ -452,7 +453,7 @@ public class ShadowUtil { * contain the eye camera frustum corners) and the shadow occluder objects * collected through the traverse of the scene hierarchy */ - public static void updateShadowCamera(Spatial rootScene, + public static void updateShadowCamera(ViewPort viewPort, GeometryList receivers, Camera shadowCam, Vector3f[] points, @@ -496,7 +497,10 @@ public class ShadowUtil { // collect splitOccluders through scene recursive traverse OccludersExtractor occExt = new OccludersExtractor(viewProjMatrix, casterCount, splitBB, casterBB, splitOccluders, vars); - casterCount = occExt.addOccluders(rootScene); + for (Spatial scene : viewPort.getScenes()) { + occExt.addOccluders(scene); + } + casterCount = occExt.casterCount; //Nehon 08/18/2010 this is to avoid shadow bleeding when the ground is set to only receive shadows if (casterCount != receiverCount) { diff --git a/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java index c8207f615..e7a3a5407 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java @@ -45,6 +45,7 @@ import com.jme3.renderer.Camera; import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Node; +import com.jme3.scene.Spatial; import com.jme3.util.TempVars; import java.io.IOException; @@ -143,7 +144,9 @@ public class SpotLightShadowRenderer extends AbstractShadowRenderer { @Override protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList shadowMapOccluders) { - ShadowUtil.getGeometriesInCamFrustum(viewPort.getQueue().getRootScene(), shadowCam, RenderQueue.ShadowMode.Cast, shadowMapOccluders); + for (Spatial scene : viewPort.getScenes()) { + ShadowUtil.getGeometriesInCamFrustum(scene, shadowCam, RenderQueue.ShadowMode.Cast, shadowMapOccluders); + } return shadowMapOccluders; } @@ -152,7 +155,9 @@ public class SpotLightShadowRenderer extends AbstractShadowRenderer { lightReceivers.clear(); Camera[] cameras = new Camera[1]; cameras[0] = shadowCam; - ShadowUtil.getLitGeometriesInViewPort(viewPort.getQueue().getRootScene(), viewPort.getCamera(), cameras, RenderQueue.ShadowMode.Receive, lightReceivers); + for (Spatial scene : viewPort.getScenes()) { + ShadowUtil.getLitGeometriesInViewPort(scene, viewPort.getCamera(), cameras, RenderQueue.ShadowMode.Receive, lightReceivers); + } return lightReceivers; } From 3aa8aed142df268a39f4f867e160662eb0b170db Mon Sep 17 00:00:00 2001 From: Normen Hansen Date: Tue, 24 Feb 2015 11:10:00 +0100 Subject: [PATCH 09/28] - add/remove multiple physics controls via PhysicsSpace.add / .remove --- .../main/java/com/jme3/bullet/PhysicsSpace.java | 14 +++++++++++--- .../main/java/com/jme3/bullet/PhysicsSpace.java | 14 ++++++++++++-- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/jme3-bullet/src/main/java/com/jme3/bullet/PhysicsSpace.java b/jme3-bullet/src/main/java/com/jme3/bullet/PhysicsSpace.java index ff81b83aa..0f011f8d7 100644 --- a/jme3-bullet/src/main/java/com/jme3/bullet/PhysicsSpace.java +++ b/jme3-bullet/src/main/java/com/jme3/bullet/PhysicsSpace.java @@ -405,8 +405,11 @@ public class PhysicsSpace { ((PhysicsControl) obj).setPhysicsSpace(this); } else if (obj instanceof Spatial) { Spatial node = (Spatial) obj; - PhysicsControl control = node.getControl(PhysicsControl.class); - control.setPhysicsSpace(this); + for (int i = 0; i < node.getNumControls(); i++) { + if (node.getControl(i) instanceof PhysicsControl) { + add(((PhysicsControl) node.getControl(i))); + } + } } else if (obj instanceof PhysicsCollisionObject) { addCollisionObject((PhysicsCollisionObject) obj); } else if (obj instanceof PhysicsJoint) { @@ -438,7 +441,12 @@ public class PhysicsSpace { if (obj instanceof PhysicsControl) { ((PhysicsControl) obj).setPhysicsSpace(null); } else if (obj instanceof Spatial) { - remove(((Spatial) obj).getControl(PhysicsControl.class)); + Spatial node = (Spatial) obj; + for (int i = 0; i < node.getNumControls(); i++) { + if (node.getControl(i) instanceof PhysicsControl) { + remove(((PhysicsControl) node.getControl(i))); + } + } } else if (obj instanceof PhysicsCollisionObject) { removeCollisionObject((PhysicsCollisionObject) obj); } else if (obj instanceof PhysicsJoint) { diff --git a/jme3-jbullet/src/main/java/com/jme3/bullet/PhysicsSpace.java b/jme3-jbullet/src/main/java/com/jme3/bullet/PhysicsSpace.java index 49fda33c5..dc61e6c6c 100644 --- a/jme3-jbullet/src/main/java/com/jme3/bullet/PhysicsSpace.java +++ b/jme3-jbullet/src/main/java/com/jme3/bullet/PhysicsSpace.java @@ -391,7 +391,12 @@ public class PhysicsSpace { if (obj instanceof PhysicsControl) { ((PhysicsControl) obj).setPhysicsSpace(this); } else if (obj instanceof Spatial) { - add(((Spatial) obj).getControl(PhysicsControl.class)); + Spatial node = (Spatial) obj; + for (int i = 0; i < node.getNumControls(); i++) { + if (node.getControl(i) instanceof PhysicsControl) { + add(((PhysicsControl) node.getControl(i))); + } + } } else if (obj instanceof PhysicsCollisionObject) { addCollisionObject((PhysicsCollisionObject) obj); } else if (obj instanceof PhysicsJoint) { @@ -423,7 +428,12 @@ public class PhysicsSpace { if (obj instanceof PhysicsControl) { ((PhysicsControl) obj).setPhysicsSpace(null); } else if (obj instanceof Spatial) { - remove(((Spatial) obj).getControl(PhysicsControl.class)); + Spatial node = (Spatial) obj; + for (int i = 0; i < node.getNumControls(); i++) { + if (node.getControl(i) instanceof PhysicsControl) { + remove(((PhysicsControl) node.getControl(i))); + } + } } else if (obj instanceof PhysicsCollisionObject) { removeCollisionObject((PhysicsCollisionObject) obj); } else if (obj instanceof PhysicsJoint) { From 75a801f0f7dbab6a2ebbef68358629a491125008 Mon Sep 17 00:00:00 2001 From: Bebul Date: Tue, 24 Feb 2015 17:53:12 +0100 Subject: [PATCH 10/28] CollideWith optimization with CollisionResult allocation avoided --- .../java/com/jme3/bounding/BoundingBox.java | 45 +++++++++++ .../com/jme3/bounding/BoundingSphere.java | 42 +++++++++- .../com/jme3/bounding/BoundingVolume.java | 11 +++ .../jme3/collision/DummyCollisionResults.java | 77 ------------------- .../src/main/java/com/jme3/scene/Node.java | 8 +- 5 files changed, 100 insertions(+), 83 deletions(-) delete mode 100644 jme3-core/src/main/java/com/jme3/collision/DummyCollisionResults.java diff --git a/jme3-core/src/main/java/com/jme3/bounding/BoundingBox.java b/jme3-core/src/main/java/com/jme3/bounding/BoundingBox.java index 71f4d9422..bdba19fe3 100644 --- a/jme3-core/src/main/java/com/jme3/bounding/BoundingBox.java +++ b/jme3-core/src/main/java/com/jme3/bounding/BoundingBox.java @@ -761,6 +761,35 @@ public class BoundingBox extends BoundingVolume { } } + private int collideWithRay(Ray ray) { + TempVars vars = TempVars.get(); + try { + Vector3f diff = vars.vect1.set(ray.origin).subtractLocal(center); + Vector3f direction = vars.vect2.set(ray.direction); + + //float[] t = {0f, Float.POSITIVE_INFINITY}; + float[] t = vars.fWdU; // use one of the tempvars arrays + t[0] = 0; + t[1] = Float.POSITIVE_INFINITY; + + float saveT0 = t[0], saveT1 = t[1]; + boolean notEntirelyClipped = clip(+direction.x, -diff.x - xExtent, t) + && clip(-direction.x, +diff.x - xExtent, t) + && clip(+direction.y, -diff.y - yExtent, t) + && clip(-direction.y, +diff.y - yExtent, t) + && clip(+direction.z, -diff.z - zExtent, t) + && clip(-direction.z, +diff.z - zExtent, t); + + if (notEntirelyClipped && (t[0] != saveT0 || t[1] != saveT1)) { + if (t[1] > t[0]) return 2; + else return 1; + } + return 0; + } finally { + vars.release(); + } + } + public int collideWith(Collidable other, CollisionResults results) { if (other instanceof Ray) { Ray ray = (Ray) other; @@ -777,6 +806,22 @@ public class BoundingBox extends BoundingVolume { throw new UnsupportedCollisionException("With: " + other.getClass().getSimpleName()); } } + + @Override + public int collideWith(Collidable other) { + if (other instanceof Ray) { + Ray ray = (Ray) other; + return collideWithRay(ray); + } else if (other instanceof Triangle) { + Triangle t = (Triangle) other; + if (intersects(t.get1(), t.get2(), t.get3())) { + return 1; + } + return 0; + } else { + throw new UnsupportedCollisionException("With: " + other.getClass().getSimpleName()); + } + } /** * C code ported from diff --git a/jme3-core/src/main/java/com/jme3/bounding/BoundingSphere.java b/jme3-core/src/main/java/com/jme3/bounding/BoundingSphere.java index 18be750f1..30751e078 100644 --- a/jme3-core/src/main/java/com/jme3/bounding/BoundingSphere.java +++ b/jme3-core/src/main/java/com/jme3/bounding/BoundingSphere.java @@ -792,7 +792,35 @@ public class BoundingSphere extends BoundingVolume { return 1; } } - + + private int collideWithRay(Ray ray) { + TempVars vars = TempVars.get(); + + Vector3f diff = vars.vect1.set(ray.getOrigin()).subtractLocal( + center); + float a = diff.dot(diff) - (getRadius() * getRadius()); + float a1, discr; + if (a <= 0.0) { + // inside sphere + vars.release(); + return 1; + } + + a1 = ray.direction.dot(diff); + vars.release(); + if (a1 >= 0.0) { + return 0; + } + + discr = a1 * a1 - a; + if (discr < 0.0) { + return 0; + } else if (discr >= FastMath.ZERO_TOLERANCE) { + return 2; + } + return 1; + } + private int collideWithTri(Triangle tri, CollisionResults results) { TempVars tvars = TempVars.get(); try { @@ -991,6 +1019,18 @@ public class BoundingSphere extends BoundingVolume { } } + @Override public int collideWith(Collidable other) { + if (other instanceof Ray) { + Ray ray = (Ray) other; + return collideWithRay(ray); + } else if (other instanceof Triangle){ + return super.collideWith(other); + } else { + throw new UnsupportedCollisionException(); + } + } + + @Override public boolean contains(Vector3f point) { return center.distanceSquared(point) < (getRadius() * getRadius()); diff --git a/jme3-core/src/main/java/com/jme3/bounding/BoundingVolume.java b/jme3-core/src/main/java/com/jme3/bounding/BoundingVolume.java index 994a74e73..f9be2e573 100644 --- a/jme3-core/src/main/java/com/jme3/bounding/BoundingVolume.java +++ b/jme3-core/src/main/java/com/jme3/bounding/BoundingVolume.java @@ -32,10 +32,12 @@ package com.jme3.bounding; import com.jme3.collision.Collidable; +import com.jme3.collision.CollisionResults; import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.Savable; import com.jme3.math.*; +import com.jme3.util.TempVars; import java.io.IOException; import java.nio.FloatBuffer; @@ -322,6 +324,15 @@ public abstract class BoundingVolume implements Savable, Cloneable, Collidable { public void read(JmeImporter e) throws IOException { center = (Vector3f) e.getCapsule(this).readSavable("center", Vector3f.ZERO.clone()); } + + public int collideWith(Collidable other) { + TempVars tempVars = TempVars.get(); + CollisionResults tempResults = tempVars.collisionResults; + tempResults.clear(); + int retval = collideWith(other, tempResults); + tempVars.release(); + return retval; + } } diff --git a/jme3-core/src/main/java/com/jme3/collision/DummyCollisionResults.java b/jme3-core/src/main/java/com/jme3/collision/DummyCollisionResults.java deleted file mode 100644 index f0f1777bd..000000000 --- a/jme3-core/src/main/java/com/jme3/collision/DummyCollisionResults.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2009-2014 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 com.jme3.collision; - -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -/** - * DummyCollisionResults is an empty "dummy" collection returned as a result of a - * collision detection operation done by {@link Collidable}. - * Its purpose is to avoid allocation of CollisionResults and its content, - * when collisionResults are out of our interest. - * Using the same API Collidable.collideWith() instead of possibly some new countCollideWith() implementation - * is chosen to keep the collision detection code "DRY", @see Don't repeat yourself - * - * @author Bebul - */ -public class DummyCollisionResults extends CollisionResults { - // the singleton for DummyCollisionResults is sufficient - private static DummyCollisionResults instance = null; - - // exists only to defeat instantiation - protected DummyCollisionResults() {} - - // classic singleton instance - public static DummyCollisionResults getInstance() { - if ( instance == null ) { - instance = new DummyCollisionResults(); - } - return instance; - } - - // Dummy implementation of CollisionResults - // All methods can be dummy except for iterator - @Override public void clear(){} - // even dummy iterator should return valid iterator - @Override public Iterator iterator() { - List dumbCompiler = Collections.emptyList(); - return dumbCompiler.iterator(); - } - @Override public void addCollision(CollisionResult result){} - @Override public int size(){ return 0; } - @Override public CollisionResult getClosestCollision(){ return null; } - @Override public CollisionResult getFarthestCollision(){ return null; } - @Override public CollisionResult getCollision(int index){ return null; } - @Override public CollisionResult getCollisionDirect(int index){ return null; } -} diff --git a/jme3-core/src/main/java/com/jme3/scene/Node.java b/jme3-core/src/main/java/com/jme3/scene/Node.java index 330ebaf4c..602922b1e 100644 --- a/jme3-core/src/main/java/com/jme3/scene/Node.java +++ b/jme3-core/src/main/java/com/jme3/scene/Node.java @@ -34,12 +34,12 @@ package com.jme3.scene; import com.jme3.bounding.BoundingVolume; import com.jme3.collision.Collidable; import com.jme3.collision.CollisionResults; -import com.jme3.collision.DummyCollisionResults; import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.Savable; import com.jme3.material.Material; import com.jme3.util.SafeArrayList; +import com.jme3.util.TempVars; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -499,10 +499,8 @@ public class Node extends Spatial implements Savable { BoundingVolume bv = this.getWorldBound(); if (bv==null) return 0; - // use DummyCollisionResults to avoid allocation while making the call to any BoundingVolume.collideWith possible - // moreover, the DummyCollisionResults operations are empty, so faster - DummyCollisionResults dummyColRes = DummyCollisionResults.getInstance(); - if (bv.collideWith(other, dummyColRes) == 0) return 0; + // collideWith without CollisionResults parameter used to avoid allocation when possible + if (bv.collideWith(other) == 0) return 0; } for (Spatial child : children.getArray()){ total += child.collideWith(other, results); From 02322d04ccab5c1279e8634b76f520f4bb835aca Mon Sep 17 00:00:00 2001 From: shadowislord Date: Tue, 24 Feb 2015 20:35:02 -0500 Subject: [PATCH 11/28] J3MLoader: fix negative signs ("-") inside mat params - Also move the "-LINEAR" directive to be associated with the parameter declaration instead of parameter default value --- .../com/jme3/material/plugins/J3MLoader.java | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) 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 23310f12f..48159df39 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 @@ -217,21 +217,13 @@ public class J3MLoader implements AssetLoader { } } - // [ "(" ")" ] [ ":" ] [-LINEAR] + // [ "(" ")" ] [-LINEAR] [ ":" ] private void readParam(String statement) throws IOException{ String name; String defaultVal = null; ColorSpace colorSpace = null; - String[] split = statement.split("-"); - if(split.length>1){ - if(split[1].equalsIgnoreCase("LINEAR")){ - colorSpace = ColorSpace.Linear; - } - statement = split[0].trim(); - } - - split = statement.split(":"); + String[] split = statement.split(":"); // Parse default val if (split.length == 1){ @@ -244,6 +236,11 @@ public class J3MLoader implements AssetLoader { defaultVal = split[1].trim(); } + if (statement.endsWith("-LINEAR")) { + colorSpace = ColorSpace.Linear; + statement = statement.substring(0, statement.length() - "-LINEAR".length()); + } + // Parse ffbinding int startParen = statement.indexOf("("); if (startParen != -1){ From 550255b1d5ed937d852b21706b3d471c66b0ed2d Mon Sep 17 00:00:00 2001 From: shadowislord Date: Tue, 24 Feb 2015 21:49:06 -0500 Subject: [PATCH 12/28] HttpZipLocator: fix unsupported exception on HTTPS URLs --- .../plugins/java/com/jme3/asset/plugins/HttpZipLocator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jme3-core/src/plugins/java/com/jme3/asset/plugins/HttpZipLocator.java b/jme3-core/src/plugins/java/com/jme3/asset/plugins/HttpZipLocator.java index ab964ab2c..af7026206 100644 --- a/jme3-core/src/plugins/java/com/jme3/asset/plugins/HttpZipLocator.java +++ b/jme3-core/src/plugins/java/com/jme3/asset/plugins/HttpZipLocator.java @@ -298,8 +298,8 @@ public class HttpZipLocator implements AssetLocator { } public void load(URL url) throws IOException { - if (!url.getProtocol().equals("http")) - throw new UnsupportedOperationException(); + if (!url.getProtocol().equals("http") && !url.getProtocol().equals("https")) + throw new UnsupportedOperationException("HttpZipLocator only supports HTTP(S) URLs"); zipUrl = url; readEndHeader(); From 957801ea1292d288fdd3cf88ca6e47001e7eca15 Mon Sep 17 00:00:00 2001 From: shadowislord Date: Tue, 24 Feb 2015 21:50:03 -0500 Subject: [PATCH 13/28] SinglePass Lighting: Comment out color ramp - doesn't seem to work --- .../resources/Common/MatDefs/Light/SPLighting.frag | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag index 749602ccd..69fcfa848 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag @@ -178,6 +178,11 @@ void main(){ vec4 refColor = Optics_GetEnvColor(m_EnvMap, refVec.xyz); #endif +// #ifdef COLORRAMP +// diffuseColor.rgb *= texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb; +// specularColor.rgb *= texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb; +// #endif + for( int i = 0;i < NB_LIGHTS; i+=3){ vec4 lightColor = g_LightData[i]; vec4 lightData1 = g_LightData[i+1]; @@ -205,11 +210,6 @@ void main(){ vec2 light = computeLighting(normal, viewDir, lightDir.xyz, lightDir.w * spotFallOff , m_Shininess); - #ifdef COLORRAMP - diffuseColor.rgb *= texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb; - specularColor.rgb *= texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb; - #endif - // Workaround, since it is not possible to modify varying variables vec4 SpecularSum2 = vec4(SpecularSum, 1.0); #ifdef USE_REFLECTION From fd0832af98010b06d90c79bc3444bf192d55fd2c Mon Sep 17 00:00:00 2001 From: shadowislord Date: Tue, 24 Feb 2015 21:50:45 -0500 Subject: [PATCH 14/28] SinglePass Lighting: fix light color not being used for specular highlight --- .../src/main/resources/Common/MatDefs/Light/SPLighting.frag | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag index 69fcfa848..9e3881028 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag @@ -221,8 +221,8 @@ void main(){ light.y = 1.0; #endif - gl_FragColor.rgb += DiffuseSum.rgb * lightColor.rgb * diffuseColor.rgb * vec3(light.x) + - SpecularSum2.rgb * specularColor.rgb * vec3(light.y); + gl_FragColor.rgb += DiffuseSum.rgb * lightColor.rgb * diffuseColor.rgb * vec3(light.x) + + SpecularSum2.rgb * lightColor.rgb * specularColor.rgb * vec3(light.y); } #endif From 3a19a2bb12498bd42725b0cc6fab6b781af111ab Mon Sep 17 00:00:00 2001 From: shadowislord Date: Tue, 24 Feb 2015 21:52:00 -0500 Subject: [PATCH 15/28] Shader: make sure uniform name starts with either m_ or g_ --- jme3-core/src/main/java/com/jme3/shader/Shader.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jme3-core/src/main/java/com/jme3/shader/Shader.java b/jme3-core/src/main/java/com/jme3/shader/Shader.java index d0efe81b7..2925fe0f2 100644 --- a/jme3-core/src/main/java/com/jme3/shader/Shader.java +++ b/jme3-core/src/main/java/com/jme3/shader/Shader.java @@ -241,6 +241,7 @@ public final class Shader extends NativeObject { } public Uniform getUniform(String name){ + assert name.startsWith("m_") || name.startsWith("g_"); Uniform uniform = uniforms.get(name); if (uniform == null){ uniform = new Uniform(); From 32e56351df99596738a96c601482fec6ffd3ddc8 Mon Sep 17 00:00:00 2001 From: shadowislord Date: Tue, 24 Feb 2015 21:52:42 -0500 Subject: [PATCH 16/28] Material.preload(): fix incorrect param names being uploaded (w/o prefix) - This would cause garbage uniforms to be allocated when testing for HW skinning --- jme3-core/src/main/java/com/jme3/material/Material.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/material/Material.java b/jme3-core/src/main/java/com/jme3/material/Material.java index f852fa6f9..520362f40 100644 --- a/jme3-core/src/main/java/com/jme3/material/Material.java +++ b/jme3-core/src/main/java/com/jme3/material/Material.java @@ -1056,12 +1056,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { Collection params = paramValues.values(); for (MatParam param : params) { - if (param instanceof MatParamTexture) { - MatParamTexture texParam = (MatParamTexture) param; - r.setTexture(0, texParam.getTextureValue()); - } else { - technique.updateUniformParam(param.getName(), param.getVarType(), param.getValue()); - } + param.apply(r, technique); } r.setShader(technique.getShader()); From 4c69cc00a6066b140ec0cd632b80f92ace0c8167 Mon Sep 17 00:00:00 2001 From: shadowislord Date: Tue, 24 Feb 2015 21:53:55 -0500 Subject: [PATCH 17/28] SP / MP Lighting: render ambient color if no lights or only ambient lights - Prevents "invisible model" bug if there are no lights --- .../main/java/com/jme3/material/Material.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/material/Material.java b/jme3-core/src/main/java/com/jme3/material/Material.java index 520362f40..74fdbb006 100644 --- a/jme3-core/src/main/java/com/jme3/material/Material.java +++ b/jme3-core/src/main/java/com/jme3/material/Material.java @@ -935,9 +935,9 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { renderMeshFromGeometry(r, g); } - if (isFirstLight && lightList.size() > 0) { - // There are only ambient lights in the scene. Render - // a dummy "normal light" so we can see the ambient + if (isFirstLight) { + // Either there are no lights at all, or only ambient lights. + // Render a dummy "normal light" so we can see the ambient color. ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList, false)); lightColor.setValue(VarType.Vector4, ColorRGBA.BlackNoAlpha); lightPos.setValue(VarType.Vector4, nullDirLight); @@ -1152,11 +1152,6 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { TechniqueDef techDef = technique.getDef(); - if (techDef.getLightMode() == LightMode.MultiPass - && lights.size() == 0) { - return; - } - if (rm.getForcedRenderState() != null) { r.applyRenderState(rm.getForcedRenderState()); } else { @@ -1191,10 +1186,16 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { case SinglePass: int nbRenderedLights = 0; resetUniformsNotSetByCurrent(shader); - while (nbRenderedLights < lights.size()) { - nbRenderedLights = updateLightListUniforms(shader, geom, lights, rm.getSinglePassLightBatchSize(), rm, nbRenderedLights); + if (lights.size() == 0) { + nbRenderedLights = updateLightListUniforms(shader, geom, lights, rm.getSinglePassLightBatchSize(), rm, 0); r.setShader(shader); renderMeshFromGeometry(r, geom); + } else { + while (nbRenderedLights < lights.size()) { + nbRenderedLights = updateLightListUniforms(shader, geom, lights, rm.getSinglePassLightBatchSize(), rm, nbRenderedLights); + r.setShader(shader); + renderMeshFromGeometry(r, geom); + } } return; case FixedPipeline: From d3b71cd946cef8b6c6ca8dec4117db95070cdc0b Mon Sep 17 00:00:00 2001 From: shadowislord Date: Tue, 24 Feb 2015 22:09:57 -0500 Subject: [PATCH 18/28] OgreXML material loading: some material state was not reset, causing it to leak to other models --- .../com/jme3/scene/plugins/ogre/MaterialLoader.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/MaterialLoader.java b/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/MaterialLoader.java index fe9de477a..cd2ecb8fa 100644 --- a/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/MaterialLoader.java +++ b/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/MaterialLoader.java @@ -336,8 +336,7 @@ public class MaterialLoader implements AssetLoader { mat.setName(matName); if (blend){ RenderState rs = mat.getAdditionalRenderState(); - rs.setAlphaTest(true); - rs.setAlphaFallOff(0.01f); + mat.setFloat("AlphaDiscardThreshold", 0.01f); rs.setBlendMode(RenderState.BlendMode.Alpha); if (twoSide){ @@ -422,13 +421,18 @@ public class MaterialLoader implements AssetLoader { noLight = false; Arrays.fill(textures, null); + ambient = null; diffuse = null; specular = null; + emissive = null; shinines = 0f; vcolor = false; blend = false; texUnit = 0; separateTexCoord = false; + twoSide = false; + matName = null; + texName = null; return mat; } @@ -464,7 +468,7 @@ public class MaterialLoader implements AssetLoader { } readMaterial(statement); Material mat = compileMaterial(); - list.put(matName, mat); + list.put(mat.getName(), mat); } } From 331e71f2616f115d57e43d234f174d4474bd724c Mon Sep 17 00:00:00 2001 From: shadowislord Date: Tue, 24 Feb 2015 23:09:38 -0500 Subject: [PATCH 19/28] SinglePass Lighting: fix colorramp feature --- .../resources/Common/MatDefs/Light/SPLighting.frag | 13 +++++++------ .../resources/Common/MatDefs/Light/SPLighting.vert | 10 ++++++++-- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag index 9e3881028..11834ffc0 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag @@ -178,11 +178,6 @@ void main(){ vec4 refColor = Optics_GetEnvColor(m_EnvMap, refVec.xyz); #endif -// #ifdef COLORRAMP -// diffuseColor.rgb *= texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb; -// specularColor.rgb *= texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb; -// #endif - for( int i = 0;i < NB_LIGHTS; i+=3){ vec4 lightColor = g_LightData[i]; vec4 lightData1 = g_LightData[i+1]; @@ -221,7 +216,13 @@ void main(){ light.y = 1.0; #endif - gl_FragColor.rgb += DiffuseSum.rgb * lightColor.rgb * diffuseColor.rgb * vec3(light.x) + + #ifdef COLORRAMP + DiffuseSum2.rgb *= texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb; + SpecularSum2.rgb *= texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb; + light.xy = vec2(1.0); + #endif + + gl_FragColor.rgb += DiffuseSum2.rgb * lightColor.rgb * diffuseColor.rgb * vec3(light.x) + SpecularSum2.rgb * lightColor.rgb * specularColor.rgb * vec3(light.y); } diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert index 1303aa2b6..b0d8828a5 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert @@ -160,8 +160,14 @@ void main(){ } #endif vec2 v = computeLighting(wvNormal, viewDir, lightDir.xyz, lightDir.w * spotFallOff, m_Shininess); - diffuseAccum +=v.x * diffuseColor; - specularAccum += v.y * specularColor; + + #ifdef COLORRAMP + diffuseAccum += texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb * diffuseColor; + specularAccum += texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb * specularColor; + #else + diffuseAccum += v.x * diffuseColor; + specularAccum += v.y * specularColor; + #endif } #endif From f0998d14d0e58974459831feaf0b6728f4cfce0c Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Wed, 25 Feb 2015 10:45:39 -0500 Subject: [PATCH 20/28] GLRenderer: support limited NPOT on iOS See this: https://www.khronos.org/registry/gles/extensions/APPLE/APPLE_texture_2D_limited_npot.txt Note that NPOT is still not available on cubemaps or 3D textures, however this is fairly uncommon. --- jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java | 1 + 1 file changed, 1 insertion(+) 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 da5392b5c..cc7acb390 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 @@ -343,6 +343,7 @@ public class GLRenderer implements Renderer { if (hasExtension("GL_ARB_texture_non_power_of_two") || hasExtension("GL_OES_texture_npot") || + hasExtension("GL_APPLE_texture_2D_limited_npot") || caps.contains(Caps.OpenGL30)) { caps.add(Caps.NonPowerOfTwoTextures); } else { From ee151af5d23ea1ea6dacd94f84c29929efa6b81c Mon Sep 17 00:00:00 2001 From: shadowislord Date: Wed, 25 Feb 2015 23:19:48 -0500 Subject: [PATCH 21/28] iOS: use generic GLRenderer (untested) - many methods are stubs .. may need some cleanup later on the native code side. --- .../java/com/jme3/renderer/ios/IosGL.java | 573 ++++++++++++++++++ .../com/jme3/system/ios/IGLESContext.java | 22 +- 2 files changed, 591 insertions(+), 4 deletions(-) create mode 100644 jme3-ios/src/main/java/com/jme3/renderer/ios/IosGL.java diff --git a/jme3-ios/src/main/java/com/jme3/renderer/ios/IosGL.java b/jme3-ios/src/main/java/com/jme3/renderer/ios/IosGL.java new file mode 100644 index 000000000..d3276972d --- /dev/null +++ b/jme3-ios/src/main/java/com/jme3/renderer/ios/IosGL.java @@ -0,0 +1,573 @@ +/* + * Copyright (c) 2009-2015 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 com.jme3.renderer.ios; + +import com.jme3.renderer.RendererException; +import com.jme3.renderer.opengl.GL; +import com.jme3.renderer.opengl.GLExt; +import java.nio.Buffer; +import java.nio.BufferOverflowException; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; + +/** + * Implements OpenGL ES 2.0 for iOS. + * + * @author Kirill Vainer + */ +public class IosGL implements GL, GLExt { + + private final int[] temp_array = new int[16]; + + private static int getLimitBytes(ByteBuffer buffer) { + checkLimit(buffer); + return buffer.limit(); + } + + private static int getLimitBytes(ShortBuffer buffer) { + checkLimit(buffer); + return buffer.limit() * 2; + } + + private static int getLimitBytes(IntBuffer buffer) { + checkLimit(buffer); + return buffer.limit() * 4; + } + + private static int getLimitBytes(FloatBuffer buffer) { + checkLimit(buffer); + return buffer.limit() * 4; + } + + private static int getLimitCount(Buffer buffer, int elementSize) { + checkLimit(buffer); + return buffer.limit() / elementSize; + } + + private int toArray(IntBuffer buffer) { + int remain = buffer.remaining(); + if (buffer.remaining() > 16) { + throw new ArrayIndexOutOfBoundsException(); + } + int pos = buffer.position(); + buffer.get(temp_array, 0, remain); + buffer.position(pos); + return remain; + } + + private void fromArray(int n, int[] array, IntBuffer buffer) { + if (buffer.remaining() < n) { + throw new BufferOverflowException(); + } + buffer.put(array, 0, n); + } + + private static void checkLimit(Buffer buffer) { + if (buffer == null) { + return; + } + if (buffer.limit() == 0) { + throw new RendererException("Attempting to upload empty buffer (limit = 0), that's an error"); + } + if (buffer.remaining() == 0) { + throw new RendererException("Attempting to upload empty buffer (remaining = 0), that's an error"); + } + } + + public void glActiveTexture(int texture) { + JmeIosGLES.glActiveTexture(texture); + } + + public void glAttachShader(int program, int shader) { + JmeIosGLES.glAttachShader(program, shader); + } + + public void glBindBuffer(int target, int buffer) { + JmeIosGLES.glBindBuffer(target, buffer); + } + + public void glBindTexture(int target, int texture) { + JmeIosGLES.glBindTexture(target, texture); + } + + public void glBlendFunc(int sfactor, int dfactor) { + JmeIosGLES.glBlendFunc(sfactor, dfactor); + } + + public void glBufferData(int target, FloatBuffer data, int usage) { + JmeIosGLES.glBufferData(target, getLimitBytes(data), data, usage); + } + + public void glBufferData(int target, ShortBuffer data, int usage) { + JmeIosGLES.glBufferData(target, getLimitBytes(data), data, usage); + } + + public void glBufferData(int target, ByteBuffer data, int usage) { + JmeIosGLES.glBufferData(target, getLimitBytes(data), data, usage); + } + + public void glBufferData(int target, long data_size, int usage) { + JmeIosGLES.glBufferData(target, (int) data_size, null, usage); + } + + public void glBufferSubData(int target, long offset, FloatBuffer data) { + JmeIosGLES.glBufferSubData(target, (int) offset, getLimitBytes(data), data); + } + + public void glBufferSubData(int target, long offset, ShortBuffer data) { + JmeIosGLES.glBufferSubData(target, (int) offset, getLimitBytes(data), data); + } + + public void glBufferSubData(int target, long offset, ByteBuffer data) { + JmeIosGLES.glBufferSubData(target, (int) offset, getLimitBytes(data), data); + } + + public void glGetBufferSubData(int target, long offset, ByteBuffer data) { + throw new UnsupportedOperationException("OpenGL ES 2 does not support glGetBufferSubData"); + } + + public void glClear(int mask) { + JmeIosGLES.glClear(mask); + } + + public void glClearColor(float red, float green, float blue, float alpha) { + JmeIosGLES.glClearColor(red, green, blue, alpha); + } + + public void glColorMask(boolean red, boolean green, boolean blue, boolean alpha) { + JmeIosGLES.glColorMask(red, green, blue, alpha); + } + + public void glCompileShader(int shader) { + JmeIosGLES.glCompileShader(shader); + } + + public void glCompressedTexImage2D(int target, int level, int internalformat, int width, int height, int border, ByteBuffer data) { + JmeIosGLES.glCompressedTexImage2D(target, level, internalformat, width, height, 0, getLimitBytes(data), data); + } + + public void glCompressedTexSubImage2D(int target, int level, int xoffset, int yoffset, int width, int height, int format, ByteBuffer data) { + JmeIosGLES.glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, getLimitBytes(data), data); + } + + public int glCreateProgram() { + return JmeIosGLES.glCreateProgram(); + } + + public int glCreateShader(int shaderType) { + return JmeIosGLES.glCreateShader(shaderType); + } + + public void glCullFace(int mode) { + JmeIosGLES.glCullFace(mode); + } + + public void glDeleteBuffers(IntBuffer buffers) { + checkLimit(buffers); + int n = toArray(buffers); + JmeIosGLES.glDeleteBuffers(n, temp_array, 0); + } + + public void glDeleteProgram(int program) { + JmeIosGLES.glDeleteProgram(program); + } + + public void glDeleteShader(int shader) { + JmeIosGLES.glDeleteShader(shader); + } + + public void glDeleteTextures(IntBuffer textures) { + checkLimit(textures); + int n = toArray(textures); + JmeIosGLES.glDeleteTextures(n, temp_array, 0); + } + + public void glDepthFunc(int func) { + JmeIosGLES.glDepthFunc(func); + } + + public void glDepthMask(boolean flag) { + JmeIosGLES.glDepthMask(flag); + } + + public void glDepthRange(double nearVal, double farVal) { + JmeIosGLES.glDepthRangef((float)nearVal, (float)farVal); + } + + public void glDetachShader(int program, int shader) { + JmeIosGLES.glDetachShader(program, shader); + } + + public void glDisable(int cap) { + JmeIosGLES.glDisable(cap); + } + + public void glDisableVertexAttribArray(int index) { + JmeIosGLES.glDisableVertexAttribArray(index); + } + + public void glDrawArrays(int mode, int first, int count) { + JmeIosGLES.glDrawArrays(mode, first, count); + } + + public void glDrawRangeElements(int mode, int start, int end, int count, int type, long indices) { + JmeIosGLES.glDrawElementsIndex(mode, count, type, (int)indices); + } + + public void glEnable(int cap) { + JmeIosGLES.glEnable(cap); + } + + public void glEnableVertexAttribArray(int index) { + JmeIosGLES.glEnableVertexAttribArray(index); + } + + public void glGenBuffers(IntBuffer buffers) { + checkLimit(buffers); + JmeIosGLES.glGenBuffers(buffers.remaining(), temp_array, 0); + fromArray(buffers.remaining(), temp_array, buffers); + } + + public void glGenTextures(IntBuffer textures) { + checkLimit(textures); + JmeIosGLES.glGenTextures(textures.remaining(), temp_array, 0); + fromArray(textures.remaining(), temp_array, textures); + } + + public int glGetAttribLocation(int program, String name) { + return JmeIosGLES.glGetAttribLocation(program, name); + } + + public void glGetBoolean(int pname, ByteBuffer params) { + // TODO: fix me!!! + // JmeIosGLES.glGetBoolean(pname, params); + throw new UnsupportedOperationException("Today is not a good day for this"); + } + + public int glGetError() { + return JmeIosGLES.glGetError(); + } + + public void glGetInteger(int pname, IntBuffer params) { + checkLimit(params); + JmeIosGLES.glGetIntegerv(pname, temp_array, 0); + fromArray(params.remaining(), temp_array, params); + } + + public void glGetProgram(int program, int pname, IntBuffer params) { + checkLimit(params); + JmeIosGLES.glGetProgramiv(program, pname, temp_array, 0); + fromArray(params.remaining(), temp_array, params); + } + + public String glGetProgramInfoLog(int program, int maxLength) { + return JmeIosGLES.glGetProgramInfoLog(program); + } + + public void glGetShader(int shader, int pname, IntBuffer params) { + checkLimit(params); + JmeIosGLES.glGetShaderiv(shader, pname, temp_array, 0); + fromArray(params.remaining(), temp_array, params); + } + + public String glGetShaderInfoLog(int shader, int maxLength) { + return JmeIosGLES.glGetShaderInfoLog(shader); + } + + public String glGetString(int name) { + return JmeIosGLES.glGetString(name); + } + + public int glGetUniformLocation(int program, String name) { + return JmeIosGLES.glGetUniformLocation(program, name); + } + + public boolean glIsEnabled(int cap) { + // TODO: fix me!!! + if (cap == GLExt.GL_MULTISAMPLE_ARB) { + return true; + } else { + throw new UnsupportedOperationException(); + } + } + + public void glLineWidth(float width) { + JmeIosGLES.glLineWidth(width); + } + + public void glLinkProgram(int program) { + JmeIosGLES.glLinkProgram(program); + } + + public void glPixelStorei(int pname, int param) { + JmeIosGLES.glPixelStorei(pname, param); + } + + public void glPolygonOffset(float factor, float units) { + JmeIosGLES.glPolygonOffset(factor, units); + } + + public void glReadPixels(int x, int y, int width, int height, int format, int type, ByteBuffer data) { + JmeIosGLES.glReadPixels(x, y, width, height, format, type, data); + } + + public void glScissor(int x, int y, int width, int height) { + JmeIosGLES.glScissor(x, y, width, height); + } + + public void glShaderSource(int shader, String[] string, IntBuffer length) { + if (string.length != 1) { + throw new UnsupportedOperationException("Today is not a good day"); + } + JmeIosGLES.glShaderSource(shader, string[0]); + } + + public void glStencilFuncSeparate(int face, int func, int ref, int mask) { + // TODO: fix me!!! + // JmeIosGLES.glStencilFuncSeparate(face, func, ref, mask); + } + + public void glStencilOpSeparate(int face, int sfail, int dpfail, int dppass) { + // TODO: fix me!!! + // JmeIosGLES.glStencilOpSeparate(face, sfail, dpfail, dppass); + } + + public void glTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, ByteBuffer data) { + JmeIosGLES.glTexImage2D(target, level, format, width, height, 0, format, type, data); + } + + public void glTexParameterf(int target, int pname, float param) { + // TODO: fix me!!! + // JmeIosGLES.glTexParameterf(target, pname, param); + } + + public void glTexParameteri(int target, int pname, int param) { + JmeIosGLES.glTexParameteri(target, pname, param); + } + + public void glTexSubImage2D(int target, int level, int xoffset, int yoffset, int width, int height, int format, int type, ByteBuffer data) { + JmeIosGLES.glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, data); + } + + public void glUniform1(int location, FloatBuffer value) { + JmeIosGLES.glUniform1fv(location, getLimitCount(value, 1), value); + } + + public void glUniform1(int location, IntBuffer value) { + JmeIosGLES.glUniform1iv(location, getLimitCount(value, 1), value); + } + + public void glUniform1f(int location, float v0) { + JmeIosGLES.glUniform1f(location, v0); + } + + public void glUniform1i(int location, int v0) { + JmeIosGLES.glUniform1i(location, v0); + } + + public void glUniform2(int location, IntBuffer value) { + // TODO: fix me!!! + // JmeIosGLES.glUniform2iv(location, getLimitCount(value, 2), value); + throw new UnsupportedOperationException(); + } + + public void glUniform2(int location, FloatBuffer value) { + JmeIosGLES.glUniform2fv(location, getLimitCount(value, 2), value); + } + + public void glUniform2f(int location, float v0, float v1) { + JmeIosGLES.glUniform2f(location, v0, v1); + } + + public void glUniform3(int location, IntBuffer value) { + // TODO: fix me!!! + // JmeIosGLES.glUniform3iv(location, getLimitCount(value, 3), value); + throw new UnsupportedOperationException(); + } + + public void glUniform3(int location, FloatBuffer value) { + JmeIosGLES.glUniform3fv(location, getLimitCount(value, 3), value); + } + + public void glUniform3f(int location, float v0, float v1, float v2) { + JmeIosGLES.glUniform3f(location, v0, v1, v2); + } + + public void glUniform4(int location, FloatBuffer value) { + JmeIosGLES.glUniform4fv(location, getLimitCount(value, 4), value); + } + + public void glUniform4(int location, IntBuffer value) { + // TODO: fix me!!! + // JmeIosGLES.glUniform4iv(location, getLimitCount(value, 4), value); + throw new UnsupportedOperationException(); + } + + public void glUniform4f(int location, float v0, float v1, float v2, float v3) { + JmeIosGLES.glUniform4f(location, v0, v1, v2, v3); + } + + public void glUniformMatrix3(int location, boolean transpose, FloatBuffer value) { + JmeIosGLES.glUniformMatrix3fv(location, getLimitCount(value, 3 * 3), transpose, value); + } + + public void glUniformMatrix4(int location, boolean transpose, FloatBuffer value) { + JmeIosGLES.glUniformMatrix4fv(location, getLimitCount(value, 4 * 4), transpose, value); + } + + public void glUseProgram(int program) { + JmeIosGLES.glUseProgram(program); + } + + public void glVertexAttribPointer(int index, int size, int type, boolean normalized, int stride, long pointer) { + JmeIosGLES.glVertexAttribPointer2(index, size, type, normalized, stride, (int)pointer); + } + + public void glViewport(int x, int y, int width, int height) { + JmeIosGLES.glViewport(x, y, width, height); + } + + public void glBlitFramebufferEXT(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter) { + throw new UnsupportedOperationException("FBO blit not available on iOS"); + } + + public void glBufferData(int target, IntBuffer data, int usage) { + JmeIosGLES.glBufferData(target, getLimitBytes(data), data, usage); + } + + public void glBufferSubData(int target, long offset, IntBuffer data) { + JmeIosGLES.glBufferSubData(target, (int)offset, getLimitBytes(data), data); + } + + public void glDrawArraysInstancedARB(int mode, int first, int count, int primcount) { + throw new UnsupportedOperationException("Instancing not available on iOS"); + } + + public void glDrawBuffers(IntBuffer bufs) { + throw new UnsupportedOperationException("MRT not available on iOS"); + } + + public void glDrawElementsInstancedARB(int mode, int indices_count, int type, long indices_buffer_offset, int primcount) { + throw new UnsupportedOperationException("Instancing not available on iOS"); + } + + public void glGetMultisample(int pname, int index, FloatBuffer val) { + throw new UnsupportedOperationException("Multisample renderbuffers not available on iOS"); + } + + public void glRenderbufferStorageMultisampleEXT(int target, int samples, int internalformat, int width, int height) { + throw new UnsupportedOperationException("Multisample renderbuffers not available on iOS"); + } + + public void glTexImage2DMultisample(int target, int samples, int internalformat, int width, int height, boolean fixedsamplelocations) { + throw new UnsupportedOperationException("Multisample textures not available on iOS"); + } + + public void glVertexAttribDivisorARB(int index, int divisor) { + throw new UnsupportedOperationException("Instancing not available on iOS"); + } + + public void glBindFramebufferEXT(int param1, int param2) { + JmeIosGLES.glBindFramebuffer(param1, param2); + } + + public void glBindRenderbufferEXT(int param1, int param2) { + JmeIosGLES.glBindRenderbuffer(param1, param2); + } + + public int glCheckFramebufferStatusEXT(int param1) { + return JmeIosGLES.glCheckFramebufferStatus(param1); + } + + public void glDeleteFramebuffersEXT(IntBuffer param1) { + checkLimit(param1); + int n = toArray(param1); + JmeIosGLES.glDeleteFramebuffers(n, temp_array, 0); + } + + public void glDeleteRenderbuffersEXT(IntBuffer param1) { + checkLimit(param1); + int n = toArray(param1); + JmeIosGLES.glDeleteRenderbuffers(n, temp_array, 0); + } + + public void glFramebufferRenderbufferEXT(int param1, int param2, int param3, int param4) { + JmeIosGLES.glFramebufferRenderbuffer(param1, param2, param3, param4); + } + + public void glFramebufferTexture2DEXT(int param1, int param2, int param3, int param4, int param5) { + JmeIosGLES.glFramebufferTexture2D(param1, param2, param3, param4, param5); + } + + public void glGenFramebuffersEXT(IntBuffer param1) { + checkLimit(param1); + JmeIosGLES.glGenFramebuffers(param1.remaining(), temp_array, 0); + fromArray(param1.remaining(), temp_array, param1); + } + + public void glGenRenderbuffersEXT(IntBuffer param1) { + checkLimit(param1); + JmeIosGLES.glGenRenderbuffers(param1.remaining(), temp_array, 0); + fromArray(param1.remaining(), temp_array, param1); + } + + public void glGenerateMipmapEXT(int param1) { + JmeIosGLES.glGenerateMipmap(param1); + } + + public void glRenderbufferStorageEXT(int param1, int param2, int param3, int param4) { + JmeIosGLES.glRenderbufferStorage(param1, param2, param3, param4); + } + + @Override + public void glReadPixels(int x, int y, int width, int height, int format, int type, long offset) { + // TODO: no offset??? + JmeIosGLES.glReadPixels(x, y, width, height, format, type, null); + } + + @Override + public int glClientWaitSync(Object sync, int flags, long timeout) { + throw new UnsupportedOperationException("OpenGL ES 2 does not support sync fences"); + } + + @Override + public void glDeleteSync(Object sync) { + throw new UnsupportedOperationException("OpenGL ES 2 does not support sync fences"); + } + + @Override + public Object glFenceSync(int condition, int flags) { + throw new UnsupportedOperationException("OpenGL ES 2 does not support sync fences"); + } +} diff --git a/jme3-ios/src/main/java/com/jme3/system/ios/IGLESContext.java b/jme3-ios/src/main/java/com/jme3/system/ios/IGLESContext.java index 90d786244..7feaeae5b 100644 --- a/jme3-ios/src/main/java/com/jme3/system/ios/IGLESContext.java +++ b/jme3-ios/src/main/java/com/jme3/system/ios/IGLESContext.java @@ -32,12 +32,15 @@ package com.jme3.system.ios; import com.jme3.input.*; -import com.jme3.input.controls.SoftTextDialogInputListener; import com.jme3.input.dummy.DummyKeyInput; import com.jme3.input.dummy.DummyMouseInput; -import com.jme3.renderer.ios.IGLESShaderRenderer; import com.jme3.system.*; import com.jme3.input.ios.IosInputHandler; +import com.jme3.renderer.ios.IosGL; +import com.jme3.renderer.opengl.GL; +import com.jme3.renderer.opengl.GLDebugES; +import com.jme3.renderer.opengl.GLExt; +import com.jme3.renderer.opengl.GLRenderer; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; @@ -54,7 +57,7 @@ public class IGLESContext implements JmeContext { /* * >= OpenGL ES 2.0 (iOS) */ - protected IGLESShaderRenderer renderer; + protected GLRenderer renderer; protected Timer timer; protected SystemListener listener; protected IosInputHandler input; @@ -150,7 +153,18 @@ public class IGLESContext implements JmeContext { @Override public void create(boolean waitFor) { logger.log(Level.FINE, "IGLESContext create"); - renderer = new IGLESShaderRenderer(); + + GL gl = new IosGL(); + GLExt glext = (GLExt) gl; + +// if (settings.getBoolean("GraphicsDebug")) { + gl = new GLDebugES(gl, glext); + glext = (GLExt) gl; +// } + + renderer = new GLRenderer(gl, glext); + renderer.initialize(); + input = new IosInputHandler(); timer = new NanoTimer(); From 2aa6f9f5212451ebb6f9e5460736e95f90e7da36 Mon Sep 17 00:00:00 2001 From: NemesisMate Date: Thu, 26 Feb 2015 14:41:29 +0100 Subject: [PATCH 22/28] Fixed BufferUnderflowException Fixed the exception occurring when using this serializer. More commented here: http://hub.jmonkeyengine.org/t/savableserializer-and-client-bufferunderflowexception/31774 --- .../jme3/network/serializing/serializers/SavableSerializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jme3-networking/src/main/java/com/jme3/network/serializing/serializers/SavableSerializer.java b/jme3-networking/src/main/java/com/jme3/network/serializing/serializers/SavableSerializer.java index 47be44129..c91c8e4c5 100644 --- a/jme3-networking/src/main/java/com/jme3/network/serializing/serializers/SavableSerializer.java +++ b/jme3-networking/src/main/java/com/jme3/network/serializing/serializers/SavableSerializer.java @@ -93,7 +93,7 @@ public class SavableSerializer extends Serializer { @Override public int read(byte[] b, int off, int len){ int toRead = len > input.remaining() ? input.remaining() : len; - input.get(b, off, len); + input.get(b, off, toRead); return toRead; } From 6bb5fcfb04f544cd8a2895d341ad403b0c32c65c Mon Sep 17 00:00:00 2001 From: Nicholas Hansen Date: Fri, 27 Feb 2015 12:25:04 +1000 Subject: [PATCH 23/28] Fix for incorrect viewport sizes Fixed an issue where viewport sizes could be a pixel smaller in either dimension in certain situations. This caused gaps to appear between adjacent viewports at certain resolutions. Forum Reference: http://hub.jmonkeyengine.org/t/fix-for-rounding-errors-in-viewport-dimensions/31751 --- jme3-core/src/main/java/com/jme3/renderer/RenderManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java index 2c0c8a4b8..311a3bcfc 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -865,8 +865,8 @@ public class RenderManager { if (cam != prevCam || cam.isViewportChanged()) { viewX = (int) (cam.getViewPortLeft() * cam.getWidth()); viewY = (int) (cam.getViewPortBottom() * cam.getHeight()); - viewWidth = (int) ((cam.getViewPortRight() - cam.getViewPortLeft()) * cam.getWidth()); - viewHeight = (int) ((cam.getViewPortTop() - cam.getViewPortBottom()) * cam.getHeight()); + viewWidth = ((int)(cam.getViewPortRight() * cam.getWidth())) - ((int)(cam.getViewPortLeft() * cam.getWidth())); + viewHeight = ((int)(cam.getViewPortTop() * cam.getHeight())) - ((int)(cam.getViewPortBottom() * cam.getHeight())); uniformBindingManager.setViewPort(viewX, viewY, viewWidth, viewHeight); renderer.setViewPort(viewX, viewY, viewWidth, viewHeight); renderer.setClipRect(viewX, viewY, viewWidth, viewHeight); From 74e4b9823a4c4ffb01e6864d4b3405533e22d5a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Bouquet?= Date: Fri, 27 Feb 2015 08:29:35 +0100 Subject: [PATCH 24/28] Changed enable() and disable() methods in BaseAppState in onEnable() and onDisable() --- .../java/com/jme3/app/BasicProfilerState.java | 4 +- .../java/com/jme3/app/state/BaseAppState.java | 40 +++++++++---------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/app/BasicProfilerState.java b/jme3-core/src/main/java/com/jme3/app/BasicProfilerState.java index bfabbee9b..52e1d49a1 100644 --- a/jme3-core/src/main/java/com/jme3/app/BasicProfilerState.java +++ b/jme3-core/src/main/java/com/jme3/app/BasicProfilerState.java @@ -209,7 +209,7 @@ public class BasicProfilerState extends BaseAppState { } @Override - protected void enable() { + protected void onEnable() { // Set the number of visible frames to the current width of the screen setFrameCount(getApplication().getCamera().getWidth()); @@ -221,7 +221,7 @@ public class BasicProfilerState extends BaseAppState { } @Override - protected void disable() { + protected void onDisable() { getApplication().setAppProfiler(null); graph.removeFromParent(); background.removeFromParent(); diff --git a/jme3-core/src/main/java/com/jme3/app/state/BaseAppState.java b/jme3-core/src/main/java/com/jme3/app/state/BaseAppState.java index 7d0110b96..d28f3d921 100644 --- a/jme3-core/src/main/java/com/jme3/app/state/BaseAppState.java +++ b/jme3-core/src/main/java/com/jme3/app/state/BaseAppState.java @@ -43,7 +43,7 @@ import java.util.logging.Logger; * A base app state implementation the provides more built-in * management convenience than AbstractAppState, including methods * for enable/disable/initialize state management. - * The abstract enable() and disable() methods are called + * The abstract onEnable() and onDisable() methods are called * appropriately during initialize(), terminate(), or setEnabled() * depending on the mutual state of "initialized" and "enabled". * @@ -52,20 +52,20 @@ import java.util.logging.Logger; * app state is attached. This is useful for resources that might * be expensive to create or load.

* - *

enable()/disable() can be used for managing things that + *

onEnable()/onDisable() can be used for managing things that * should only exist while the state is enabled. Prime examples * would be scene graph attachment or input listener attachment.

* - *

The base class logic is such that disable() will always be called + *

The base class logic is such that onDisable() will always be called * before cleanup() if the state is enabled. Likewise, enable() * will always be called after initialize() if the state is enable(). - * enable()/disable() are also called appropriate when setEnabled() + * onEnable()/onDisable() are also called appropriate when setEnabled() * is called that changes the enabled state AND if the state is attached. - * In other words, enable()/disable() are only ever called on an already + * In other words, onEnable()/onDisable() are only ever called on an already * attached state.

* *

It is technically safe to do all initialization and cleanup in - * the enable()/disable() methods. Choosing to use initialize() + * the onEnable()/onDisable() methods. Choosing to use initialize() * and cleanup() for this is a matter of performance specifics for the * implementor.

* @@ -81,14 +81,14 @@ public abstract class BaseAppState implements AppState { /** * Called during initialization once the app state is - * attached and before enable() is called. + * attached and before onEnable() is called. */ protected abstract void initialize( Application app ); /** * Called after the app state is detached or during * application shutdown if the state is still attached. - * disable() is called before this cleanup() method if + * onDisable() is called before this cleanup() method if * the state is enabled at the time of cleanup. */ protected abstract void cleanup( Application app ); @@ -98,19 +98,19 @@ public abstract class BaseAppState implements AppState { * and isEnabled() is true or when the setEnabled() status * changes after the state is attached. */ - protected abstract void enable(); + protected abstract void onEnable(); /** * Called when the state was previously enabled but is * now disabled either because setEnabled(false) was called * or the state is being cleaned up. */ - protected abstract void disable(); + protected abstract void onDisable(); /** * Do not call directly: Called by the state manager to initialize this * state post-attachment. - * This implementation calls initialize(app) and then enable() if the + * This implementation calls initialize(app) and then onEnable() if the * state is enabled. */ public final void initialize( AppStateManager stateManager, Application app ) { @@ -120,8 +120,8 @@ public abstract class BaseAppState implements AppState { initialized = true; initialize(app); if( isEnabled() ) { - log.log(Level.FINEST, "enable():{0}", this); - enable(); + log.log(Level.FINEST, "onEnable():{0}", this); + onEnable(); } } @@ -149,11 +149,11 @@ public abstract class BaseAppState implements AppState { if( !isInitialized() ) return; if( enabled ) { - log.log(Level.FINEST, "enable():{0}", this); - enable(); + log.log(Level.FINEST, "onEnable():{0}", this); + onEnable(); } else { - log.log(Level.FINEST, "disable():{0}", this); - disable(); + log.log(Level.FINEST, "onDisable():{0}", this); + onDisable(); } } @@ -179,15 +179,15 @@ public abstract class BaseAppState implements AppState { /** * Do not call directly: Called by the state manager to terminate this * state post-detachment or during state manager termination. - * This implementation calls disable() if the state is enabled and + * This implementation calls onDisable() if the state is enabled and * then cleanup(app). */ public final void cleanup() { log.log(Level.FINEST, "cleanup():{0}", this); if( isEnabled() ) { - log.log(Level.FINEST, "disable():{0}", this); - disable(); + log.log(Level.FINEST, "onDisable():{0}", this); + onDisable(); } cleanup(app); initialized = false; From 45c3776395188571060b93998d540c64f1c5247e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Bouquet?= Date: Fri, 27 Feb 2015 08:32:40 +0100 Subject: [PATCH 25/28] Fixed warnings due to missing @Override or missing @params in javadoc. In BasicProfilerState and BaseAppState --- .../main/java/com/jme3/app/BasicProfilerState.java | 5 ++++- .../main/java/com/jme3/app/state/BaseAppState.java | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/jme3-core/src/main/java/com/jme3/app/BasicProfilerState.java b/jme3-core/src/main/java/com/jme3/app/BasicProfilerState.java index 52e1d49a1..50ace1dab 100644 --- a/jme3-core/src/main/java/com/jme3/app/BasicProfilerState.java +++ b/jme3-core/src/main/java/com/jme3/app/BasicProfilerState.java @@ -61,7 +61,7 @@ public class BasicProfilerState extends BaseAppState { private Geometry background; private float scale = 2; - private ProfilerKeyListener keyListener = new ProfilerKeyListener(); + private final ProfilerKeyListener keyListener = new ProfilerKeyListener(); public BasicProfilerState() { this(false); @@ -84,6 +84,7 @@ public class BasicProfilerState extends BaseAppState { * Sets the vertical scale of the visualization where * each unit is a millisecond. Defaults to 2, ie: a * single millisecond stretches two pixels high. + * @param scale the scale */ public void setGraphScale( float scale ) { if( this.scale == scale ) { @@ -101,6 +102,7 @@ public class BasicProfilerState extends BaseAppState { /** * Sets the number frames displayed and tracked. + * @param count the number of frames */ public void setFrameCount( int count ) { if( profiler.getFrameCount() == count ) { @@ -229,6 +231,7 @@ public class BasicProfilerState extends BaseAppState { private class ProfilerKeyListener implements ActionListener { + @Override public void onAction(String name, boolean value, float tpf) { if (!value) { return; diff --git a/jme3-core/src/main/java/com/jme3/app/state/BaseAppState.java b/jme3-core/src/main/java/com/jme3/app/state/BaseAppState.java index d28f3d921..a8a80f19e 100644 --- a/jme3-core/src/main/java/com/jme3/app/state/BaseAppState.java +++ b/jme3-core/src/main/java/com/jme3/app/state/BaseAppState.java @@ -82,6 +82,7 @@ public abstract class BaseAppState implements AppState { /** * Called during initialization once the app state is * attached and before onEnable() is called. + * @param app the application */ protected abstract void initialize( Application app ); @@ -90,6 +91,7 @@ public abstract class BaseAppState implements AppState { * application shutdown if the state is still attached. * onDisable() is called before this cleanup() method if * the state is enabled at the time of cleanup. + * @param app the application */ protected abstract void cleanup( Application app ); @@ -113,6 +115,7 @@ public abstract class BaseAppState implements AppState { * This implementation calls initialize(app) and then onEnable() if the * state is enabled. */ + @Override public final void initialize( AppStateManager stateManager, Application app ) { log.log(Level.FINEST, "initialize():{0}", this); @@ -125,6 +128,7 @@ public abstract class BaseAppState implements AppState { } } + @Override public final boolean isInitialized() { return initialized; } @@ -141,6 +145,7 @@ public abstract class BaseAppState implements AppState { return getStateManager().getState(type); } + @Override public final void setEnabled( boolean enabled ) { if( this.enabled == enabled ) @@ -157,22 +162,28 @@ public abstract class BaseAppState implements AppState { } } + @Override public final boolean isEnabled() { return enabled; } + @Override public void stateAttached( AppStateManager stateManager ) { } + @Override public void stateDetached( AppStateManager stateManager ) { } + @Override public void update( float tpf ) { } + @Override public void render( RenderManager rm ) { } + @Override public void postRender() { } @@ -182,6 +193,7 @@ public abstract class BaseAppState implements AppState { * This implementation calls onDisable() if the state is enabled and * then cleanup(app). */ + @Override public final void cleanup() { log.log(Level.FINEST, "cleanup():{0}", this); From bebabb32c83aea8bbb7a7a2795bae22fb42beb14 Mon Sep 17 00:00:00 2001 From: Erlend Sogge Heggen Date: Fri, 27 Feb 2015 18:12:11 +0100 Subject: [PATCH 26/28] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5fa4b1f72..73664144f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,7 +23,7 @@ To import the local repository as a project follow these steps: 2. Navigate to the project directory in command line and execute command 'gradle eclipse'. This will load all the dependancies for eclipse. 3. In Eclipse, add the repository as an existing Java Project. - +p.s. We will try hold ourselves to a [certain standard](http://www.defmacro.org/2013/04/03/issue-etiquette.html) when it comes to GitHub etiquette. If at any point we fail to uphold this standard, let us know. #### Core Contributors From b0b62cb467e07989df639c1a66cc3848aaf37ab7 Mon Sep 17 00:00:00 2001 From: Erlend Sogge Heggen Date: Fri, 27 Feb 2015 18:15:24 +0100 Subject: [PATCH 27/28] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 73664144f..ebecab28b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,7 +5,7 @@ First and foremost, you have to familiarize yourself with Git & GitHub. Dig thro ## Communication -Communication always comes first. **All** code changes and other contributions should start with the [forum](http://hub.jmonkeyengine.org/forum/). Make a thread to explain your change and show us the important bits of your code. If the code is too long to be posted within the forum’s code tags, please paste your code in a Gist or pastebin and link to the submission in your thread. You are required to register on our website in order to create threads. +Communication always comes first. **All** code changes and other contributions should start with the [forum](http://hub.jmonkeyengine.org/). Make a thread to explain your change and show us the important bits of your code. If the code is too long to be posted within the forum’s code tags, please paste your code in a Gist or pastebin and link to the submission in your thread. You are required to register on our website in order to create threads. (We do support login via GitHub though). ### New Contributors From 56aabe3facfe9bd27be870f3fc21d0068cf99578 Mon Sep 17 00:00:00 2001 From: Nehon Date: Fri, 27 Feb 2015 18:37:27 +0100 Subject: [PATCH 28/28] Fixed a NPE in MaterialDebugAppState when a Pass was declared in a filter but not instantiated. --- .../src/main/java/com/jme3/util/MaterialDebugAppState.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jme3-core/src/main/java/com/jme3/util/MaterialDebugAppState.java b/jme3-core/src/main/java/com/jme3/util/MaterialDebugAppState.java index 9fb6c9e54..1c512e41b 100644 --- a/jme3-core/src/main/java/com/jme3/util/MaterialDebugAppState.java +++ b/jme3-core/src/main/java/com/jme3/util/MaterialDebugAppState.java @@ -317,7 +317,7 @@ public class MaterialDebugAppState extends AbstractAppState { if (field.getType().isInstance(p)) { field.setAccessible(true); p = (Filter.Pass) field.get(filter); - if (p.getPassMaterial() != null) { + if (p!= null && p.getPassMaterial() != null) { Material mat = reloadMaterial(p.getPassMaterial()); if (mat == null) { return;