Parcourir la source

- BatchNode now use a temp float array and bulk put data into the floatbuffer instad of iterative puts. (it's faster)
- Spatials have now a BatchHint (Inherit, Never,Always) to know if they should be batched or not (use is the same as cullHint)

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8550 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

rem..om il y a 14 ans
Parent
commit
83f3b2b1a3

+ 46 - 24
engine/src/core/com/jme3/scene/BatchNode.java

@@ -76,7 +76,10 @@ public class BatchNode extends Node implements Savable {
      * the map of geometry holding the batched meshes
      */
     protected Map<Material, Batch> batches = new HashMap<Material, Batch>();
-
+    /**
+     * used to store transformed vectors before proceeding to a bulk put into the FloatBuffer 
+     */
+    private float[] tmpFloat;
     /**
      * Construct a batchNode
      */
@@ -129,8 +132,8 @@ public class BatchNode extends Node implements Savable {
 
         assert refreshFlags == 0;
     }
-    
-    protected Transform getTransforms(Geometry geom){
+
+    protected Transform getTransforms(Geometry geom) {
         return geom.getWorldTransform();
     }
 
@@ -140,18 +143,18 @@ public class BatchNode extends Node implements Savable {
             Mesh mesh = batch.geometry.getMesh();
 
             FloatBuffer buf = (FloatBuffer) mesh.getBuffer(VertexBuffer.Type.Position).getData();
-            doTransformVerts(buf, 0, bg.startIndex, bg.startIndex + bg.getVertexCount(), buf, bg.cachedOffsetMat);
+            doTransformVerts(buf, bg.startIndex, bg.startIndex + bg.getVertexCount(), buf, bg.cachedOffsetMat);
             mesh.getBuffer(VertexBuffer.Type.Position).updateData(buf);
 
-            buf = (FloatBuffer) mesh.getBuffer(VertexBuffer.Type.Normal).getData();
-            doTransformNorm(buf, 0, bg.startIndex, bg.startIndex + bg.getVertexCount(), buf, bg.cachedOffsetMat);
-            mesh.getBuffer(VertexBuffer.Type.Normal).updateData(buf);
+//            buf = (FloatBuffer) mesh.getBuffer(VertexBuffer.Type.Normal).getData();
+//            doTransformNorm(buf, 0, bg.startIndex, bg.startIndex + bg.getVertexCount(), buf, bg.cachedOffsetMat);
+//            mesh.getBuffer(VertexBuffer.Type.Normal).updateData(buf);
 
 
             if (mesh.getBuffer(VertexBuffer.Type.Tangent) != null) {
 
                 buf = (FloatBuffer) mesh.getBuffer(VertexBuffer.Type.Tangent).getData();
-                doTransformNorm(buf, 0, bg.startIndex, bg.startIndex + bg.getVertexCount(), buf, bg.cachedOffsetMat);
+                doTransformNorm(buf, bg.startIndex, bg.startIndex + bg.getVertexCount(), buf, bg.cachedOffsetMat);
                 mesh.getBuffer(VertexBuffer.Type.Tangent).updateData(buf);
             }
 
@@ -183,6 +186,7 @@ public class BatchNode extends Node implements Savable {
             List<Geometry> list = matMap.get(material);
             nbGeoms += list.size();
             mergeGeometries(m, list);
+            m.setDynamic();
             Batch batch = new Batch();
 
             batch.geometry = new Geometry(name + "-batch" + batches.size());
@@ -201,7 +205,8 @@ public class BatchNode extends Node implements Savable {
     private void gatherGeomerties(Map<Material, List<Geometry>> map, Spatial n) {
 
         if (n.getClass() == Geometry.class) {
-            if (!isBatch(n)) {
+
+            if (!isBatch(n) && n.getBatchHint() != BatchHint.Never) {
                 Geometry g = (Geometry) n;
                 if (g.getMaterial() == null) {
                     throw new IllegalStateException("No material is set for Geometry: " + g.getName() + " please set a material before batching");
@@ -264,7 +269,7 @@ public class BatchNode extends Node implements Savable {
         }
         return null;//material;
     }
-    
+
 //    /**
 //     * Sets the material to the a specific batch of this BatchNode
 //     * 
@@ -294,7 +299,6 @@ public class BatchNode extends Node implements Savable {
 //        }
 //        return null;//material;
 //    }
-
     @Override
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
@@ -413,18 +417,22 @@ public class BatchNode extends Node implements Savable {
             }
 
             VertexBuffer vb = new VertexBuffer(VertexBuffer.Type.values()[i]);
-            vb.setupData(VertexBuffer.Usage.Static, compsForBuf[i], formatForBuf[i], data);
+            vb.setupData(VertexBuffer.Usage.Dynamic, compsForBuf[i], formatForBuf[i], data);
             outMesh.setBuffer(vb);
         }
 
         int globalVertIndex = 0;
         int globalTriIndex = 0;
+        int maxVertCount = 0;
 
         for (Geometry geom : geometries) {
             Mesh inMesh = geom.getMesh();
             geom.batch(this, globalVertIndex);
 
             int geomVertCount = inMesh.getVertexCount();
+            if (maxVertCount < geomVertCount) {
+                maxVertCount = geomVertCount;
+            }
             int geomTriCount = inMesh.getTriangleCount();
 
             for (int bufType = 0; bufType < compsForBuf.length; bufType++) {
@@ -466,15 +474,19 @@ public class BatchNode extends Node implements Savable {
             globalVertIndex += geomVertCount;
             globalTriIndex += geomTriCount;
         }
+        tmpFloat = new float[maxVertCount*3];
     }
+  
 
-    private void doTransformVerts(FloatBuffer inBuf, int offset, int start, int end, FloatBuffer outBuf, Matrix4f transform) {
+    private void doTransformVerts(FloatBuffer inBuf, int start, int end, FloatBuffer outBuf, Matrix4f transform) {
         TempVars vars = TempVars.get();
         Vector3f pos = vars.vect1;
 
+        int length = (end - start) * 3;
+
         // offset is given in element units
         // convert to be in component units
-        offset *= 3;
+        int offset = start * 3;
 
         for (int i = start; i < end; i++) {
             int index = i * 3;
@@ -483,21 +495,27 @@ public class BatchNode extends Node implements Savable {
             pos.z = inBuf.get(index + 2);
 
             transform.mult(pos, pos);
-            index += offset;
-            outBuf.put(index, pos.x);
-            outBuf.put(index + 1, pos.y);
-            outBuf.put(index + 2, pos.z);
+            index -= offset;
+            tmpFloat[index] = pos.x;
+            tmpFloat[index + 1] = pos.y;
+            tmpFloat[index + 2] = pos.z;
+
         }
         vars.release();
+        outBuf.position(offset);
+        //using bulk put as it's faster
+        outBuf.put(tmpFloat, 0, length);
     }
 
-    private void doTransformNorm(FloatBuffer inBuf, int offset, int start, int end, FloatBuffer outBuf, Matrix4f transform) {
+    private void doTransformNorm(FloatBuffer inBuf, int start, int end, FloatBuffer outBuf, Matrix4f transform) {
         TempVars vars = TempVars.get();
         Vector3f pos = vars.vect1;
+        int length = (end - start) * 3;
+
 
         // offset is given in element units
         // convert to be in component units
-        offset *= 3;
+        int offset = start * 3;
 
         for (int i = start; i < end; i++) {
             int index = i * 3;
@@ -506,12 +524,16 @@ public class BatchNode extends Node implements Savable {
             pos.z = inBuf.get(index + 2);
 
             transform.multNormal(pos, pos);
-            index += offset;
-            outBuf.put(index, pos.x);
-            outBuf.put(index + 1, pos.y);
-            outBuf.put(index + 2, pos.z);
+            index -= offset;
+            tmpFloat[index] = pos.x;
+            tmpFloat[index + 1] = pos.y;
+            tmpFloat[index + 2] = pos.z;
+
         }
         vars.release();
+        outBuf.position(offset);
+        //using bulk put as it's faster
+        outBuf.put(tmpFloat, 0, length);
     }
 
     private void doCopyBuffer(FloatBuffer inBuf, int offset, FloatBuffer outBuf) {

+ 60 - 16
engine/src/core/com/jme3/scene/Spatial.java

@@ -107,31 +107,46 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Asset {
          */
         Never;
     }
+
+    /**
+     * Specifies is this spatial should be batched
+     */
+    public enum BatchHint {
+
+        /** 
+         * Do whatever our parent does. If no parent, default to {@link #Always}.
+         */
+        Inherit,
+        /** 
+         * this spatial will always be batched when attached to a BatchNode
+         */
+        Always,
+        /** 
+         * this spatial will naver be batched when attached to a BatchNode
+         */
+        Never;
+    }
     /**
      * Refresh flag types
      */
     protected static final int RF_TRANSFORM = 0x01, // need light resort + combine transforms
             RF_BOUND = 0x02,
             RF_LIGHTLIST = 0x04; // changes in light lists          
-    
     protected CullHint cullHint = CullHint.Inherit;
-    
+    protected BatchHint batchHint = BatchHint.Inherit;
     /** 
      * Spatial's bounding volume relative to the world.
      */
     protected BoundingVolume worldBound;
-    
     /**
      * LightList
      */
     protected LightList localLights;
     protected transient LightList worldLights;
-    
     /** 
      * This spatial's name.
      */
     protected String name;
-    
     // scale values
     protected transient Camera.FrustumIntersect frustrumIntersects = Camera.FrustumIntersect.Intersects;
     protected RenderQueue.Bucket queueBucket = RenderQueue.Bucket.Inherit;
@@ -141,14 +156,12 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Asset {
     protected Transform worldTransform;
     protected SafeArrayList<Control> controls = new SafeArrayList<Control>(Control.class);
     protected HashMap<String, Savable> userData = null;
-    
     /**
      * Used for smart asset caching
      * 
      * @see AssetKey#useSmartCache() 
      */
-    protected AssetKey key; 
-    
+    protected AssetKey key;
     /** 
      * Spatial's parent, or null if it has none.
      */
@@ -185,14 +198,14 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Asset {
         this.name = name;
     }
 
-    public void setKey(AssetKey key){
+    public void setKey(AssetKey key) {
         this.key = key;
     }
-    
-    public AssetKey getKey(){
+
+    public AssetKey getKey() {
         return key;
     }
-    
+
     /**
      * Indicate that the transform of this spatial has changed and that
      * a refresh is required.
@@ -556,7 +569,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Asset {
             return;
         }
 
-        for (Control c : controls.getArray() ) {
+        for (Control c : controls.getArray()) {
             c.render(rm, vp);
         }
     }
@@ -616,7 +629,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Asset {
     public <T extends Control> T getControl(Class<T> controlType) {
         for (Control c : controls.getArray()) {
             if (controlType.isAssignableFrom(c.getClass())) {
-                return (T)c;
+                return (T) c;
             }
         }
         return null;
@@ -1027,6 +1040,16 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Asset {
         }
     }
 
+    public BatchHint getBatchHint() {
+        if (batchHint != BatchHint.Inherit) {
+            return batchHint;
+        } else if (parent != null) {
+            return parent.getBatchHint();
+        } else {
+            return BatchHint.Always;
+        }
+    }
+
     /**
      * Returns this spatial's renderqueue bucket. If the mode is set to inherit,
      * then the spatial gets its renderqueue bucket from its parent.
@@ -1249,13 +1272,14 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Asset {
         capsule.write(name, "name", null);
         capsule.write(worldBound, "world_bound", null);
         capsule.write(cullHint, "cull_mode", CullHint.Inherit);
+        capsule.write(batchHint, "batch_hint", BatchHint.Inherit);
         capsule.write(queueBucket, "queue", RenderQueue.Bucket.Inherit);
         capsule.write(shadowMode, "shadow_mode", ShadowMode.Inherit);
         capsule.write(localTransform, "transform", Transform.IDENTITY);
         capsule.write(localLights, "lights", null);
-        
+
         // Shallow clone the controls array to convert its type.
-        capsule.writeSavableArrayList( new ArrayList(controls), "controlsList", null);
+        capsule.writeSavableArrayList(new ArrayList(controls), "controlsList", null);
         capsule.writeStringSavableMap(userData, "user_data", null);
     }
 
@@ -1265,6 +1289,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Asset {
         name = ic.readString("name", null);
         worldBound = (BoundingVolume) ic.readSavable("world_bound", null);
         cullHint = ic.readEnum("cull_mode", CullHint.class, CullHint.Inherit);
+        batchHint = ic.readEnum("batch_hint", BatchHint.class, BatchHint.Inherit);
         queueBucket = ic.readEnum("queue", RenderQueue.Bucket.class,
                 RenderQueue.Bucket.Inherit);
         shadowMode = ic.readEnum("shadow_mode", ShadowMode.class,
@@ -1309,6 +1334,18 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Asset {
         cullHint = hint;
     }
 
+    /**
+     * <code>setBatchHint</code> sets how batching should work on this
+     * spatial. NOTE: You must set this AFTER attaching to a 
+     * parent or it will be reset with the parent's cullMode value.
+     *
+     * @param hint
+     *            one of BatchHint.Never, BatchHint.Always, BatchHint.Inherit 
+     */
+    public void setBatchHint(BatchHint hint) {
+        batchHint = hint;
+    }
+
     /**
      * @return the cullmode set on this Spatial
      */
@@ -1316,6 +1353,13 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Asset {
         return cullHint;
     }
 
+    /**
+     * @return the batchHint set on this Spatial
+     */
+    public BatchHint getLocalBatchHint() {
+        return batchHint;
+    }
+
     /**
      * <code>setQueueBucket</code> determines at what phase of the
      * rendering process this Spatial will rendered. See the