Browse Source

BatchNode enhancements :
- batching after adding a new geometry only does an incremental batch instead of rebatching all geometries
- there is now a getOffsetIndex(geometry) method that returns the index of the first vertex of the geometry in the batch.

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

rem..om 13 years ago
parent
commit
03da8d5316

+ 44 - 20
engine/src/core/com/jme3/scene/BatchNode.java

@@ -80,6 +80,7 @@ public class BatchNode extends Node implements Savable {
     private float[] tmpFloatT;
     private float[] tmpFloatT;
     int maxVertCount = 0;
     int maxVertCount = 0;
     boolean useTangents = false;
     boolean useTangents = false;
+    boolean needsFullRebatch = true;
 
 
     /**
     /**
      * Construct a batchNode
      * Construct a batchNode
@@ -178,16 +179,25 @@ public class BatchNode extends Node implements Savable {
     }
     }
 
 
     protected void doBatch() {
     protected void doBatch() {
-        ///List<Geometry> tmpList = new ArrayList<Geometry>();
         Map<Material, List<Geometry>> matMap = new HashMap<Material, List<Geometry>>();
         Map<Material, List<Geometry>> matMap = new HashMap<Material, List<Geometry>>();
         maxVertCount = 0;
         maxVertCount = 0;
-        gatherGeomerties(matMap, this);
-        batches.clear();
         int nbGeoms = 0;
         int nbGeoms = 0;
+
+        gatherGeomerties(matMap, this, needsFullRebatch);
+        if (needsFullRebatch) {
+            for (Batch batch : batches.values()) {
+                batch.geometry.removeFromParent();
+            }
+            batches.clear();
+        }
+        
         for (Material material : matMap.keySet()) {
         for (Material material : matMap.keySet()) {
             Mesh m = new Mesh();
             Mesh m = new Mesh();
             List<Geometry> list = matMap.get(material);
             List<Geometry> list = matMap.get(material);
             nbGeoms += list.size();
             nbGeoms += list.size();
+            if (!needsFullRebatch) {
+                list.add(batches.get(material).geometry);
+            }
             mergeGeometries(m, list);
             mergeGeometries(m, list);
             m.setDynamic();
             m.setDynamic();
             Batch batch = new Batch();
             Batch batch = new Batch();
@@ -202,30 +212,36 @@ public class BatchNode extends Node implements Savable {
             batch.geometry.getMesh().updateBound();
             batch.geometry.getMesh().updateBound();
             batches.put(material, batch);
             batches.put(material, batch);
         }
         }
+
+        logger.log(Level.INFO, "Batched {0} geometries in {1} batches.", new Object[]{nbGeoms, batches.size()});
+
+
         //init temp float arrays
         //init temp float arrays
         tmpFloat = new float[maxVertCount * 3];
         tmpFloat = new float[maxVertCount * 3];
         tmpFloatN = new float[maxVertCount * 3];
         tmpFloatN = new float[maxVertCount * 3];
         if (useTangents) {
         if (useTangents) {
             tmpFloatT = new float[maxVertCount * 4];
             tmpFloatT = new float[maxVertCount * 4];
         }
         }
-        logger.log(Level.INFO, "Batched {0} geometries in {1} batches.", new Object[]{nbGeoms, batches.size()});
     }
     }
 
 
-    private void gatherGeomerties(Map<Material, List<Geometry>> map, Spatial n) {
+    private void gatherGeomerties(Map<Material, List<Geometry>> map, Spatial n, boolean rebatch) {
 
 
         if (n.getClass() == Geometry.class) {
         if (n.getClass() == Geometry.class) {
 
 
             if (!isBatch(n) && n.getBatchHint() != BatchHint.Never) {
             if (!isBatch(n) && n.getBatchHint() != BatchHint.Never) {
                 Geometry g = (Geometry) n;
                 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");
-                }
-                List<Geometry> list = map.get(g.getMaterial());
-                if (list == null) {
-                    list = new ArrayList<Geometry>();
-                    map.put(g.getMaterial(), list);
+                if (!g.isBatched() || rebatch) {
+                    if (g.getMaterial() == null) {
+                        throw new IllegalStateException("No material is set for Geometry: " + g.getName() + " please set a material before batching");
+                    }
+                    List<Geometry> list = map.get(g.getMaterial());
+                    if (list == null) {
+                        list = new ArrayList<Geometry>();
+                        map.put(g.getMaterial(), list);
+                    }
+                    g.setTransformRefresh();
+                    list.add(g);
                 }
                 }
-                list.add(g);
             }
             }
 
 
         } else if (n instanceof Node) {
         } else if (n instanceof Node) {
@@ -233,7 +249,7 @@ public class BatchNode extends Node implements Savable {
                 if (child instanceof BatchNode) {
                 if (child instanceof BatchNode) {
                     continue;
                     continue;
                 }
                 }
-                gatherGeomerties(map, child);
+                gatherGeomerties(map, child, rebatch);
             }
             }
         }
         }
 
 
@@ -465,12 +481,12 @@ public class BatchNode extends Node implements Savable {
                     }
                     }
                 } else if (VertexBuffer.Type.Position.ordinal() == bufType) {
                 } else if (VertexBuffer.Type.Position.ordinal() == bufType) {
                     FloatBuffer inPos = (FloatBuffer) inBuf.getData();
                     FloatBuffer inPos = (FloatBuffer) inBuf.getData();
-                    FloatBuffer outPos = (FloatBuffer) outBuf.getData();
-                    doCopyBuffer(inPos, globalVertIndex, outPos,3);
+                    FloatBuffer outPos = (FloatBuffer) outBuf.getData();                    
+                    doCopyBuffer(inPos, globalVertIndex, outPos, 3);
                 } else if (VertexBuffer.Type.Normal.ordinal() == bufType || VertexBuffer.Type.Tangent.ordinal() == bufType) {
                 } else if (VertexBuffer.Type.Normal.ordinal() == bufType || VertexBuffer.Type.Tangent.ordinal() == bufType) {
                     FloatBuffer inPos = (FloatBuffer) inBuf.getData();
                     FloatBuffer inPos = (FloatBuffer) inBuf.getData();
-                    FloatBuffer outPos = (FloatBuffer) outBuf.getData();                  
-                    doCopyBuffer(inPos, globalVertIndex, outPos,compsForBuf[bufType]);
+                    FloatBuffer outPos = (FloatBuffer) outBuf.getData();
+                    doCopyBuffer(inPos, globalVertIndex, outPos, compsForBuf[bufType]);
                     if (VertexBuffer.Type.Tangent.ordinal() == bufType) {
                     if (VertexBuffer.Type.Tangent.ordinal() == bufType) {
                         useTangents = true;
                         useTangents = true;
                     }
                     }
@@ -584,9 +600,9 @@ public class BatchNode extends Node implements Savable {
             tmpFloatT[tanIndex++] = tan.x;
             tmpFloatT[tanIndex++] = tan.x;
             tmpFloatT[tanIndex++] = tan.y;
             tmpFloatT[tanIndex++] = tan.y;
             tmpFloatT[tanIndex++] = tan.z;
             tmpFloatT[tanIndex++] = tan.z;
-            
+
             //Skipping 4th element of tangent buffer (handedness)
             //Skipping 4th element of tangent buffer (handedness)
-            tanIndex++;  
+            tanIndex++;
 
 
         }
         }
         vars.release();
         vars.release();
@@ -626,4 +642,12 @@ public class BatchNode extends Node implements Savable {
         Geometry geometry;
         Geometry geometry;
         boolean needMeshUpdate = false;
         boolean needMeshUpdate = false;
     }
     }
+
+    protected void setNeedsFullRebatch(boolean needsFullRebatch) {
+        this.needsFullRebatch = needsFullRebatch;
+    }
+    
+    public int getOffsetIndex(Geometry batchedGeometry){
+        return batchedGeometry.startIndex;
+    }
 }
 }

+ 2 - 2
engine/src/core/com/jme3/scene/Geometry.java

@@ -322,8 +322,8 @@ public class Geometry extends Spatial {
         this.startIndex = 0;
         this.startIndex = 0;
         prevBatchTransforms = null;
         prevBatchTransforms = null;
         cachedOffsetMat = null;
         cachedOffsetMat = null;
-        //once the geometry is removed from the screnegraph we call batch on the batchNode before unreferencing it.
-        this.batchNode.batch();
+        //once the geometry is removed from the screnegraph the batchNode needs to be rebatched.
+        this.batchNode.setNeedsFullRebatch(true);
         this.batchNode = null;
         this.batchNode = null;
         setCullHint(CullHint.Dynamic);
         setCullHint(CullHint.Dynamic);
     }
     }