1 /* 2 * Copyright (c) 2009-2012 jMonkeyEngine 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 package jme3tools.optimize; 34 35 import com.jme3.light.Light; 36 import com.jme3.scene.Geometry; 37 import com.jme3.scene.Mesh; 38 import com.jme3.scene.VertexBuffer; 39 import com.jme3.scene.VertexBuffer.Type; 40 import com.jme3.util.BufferUtils; 41 import com.jme3.util.IntMap; 42 import com.jme3.util.IntMap.Entry; 43 import java.nio.Buffer; 44 import java.nio.ShortBuffer; 45 import java.util.*; 46 47 public class TriangleCollector { 48 49 private static final GeomTriComparator comparator = new GeomTriComparator(); 50 51 private static class GeomTriComparator implements Comparator<OCTTriangle> { compare(OCTTriangle a, OCTTriangle b)52 public int compare(OCTTriangle a, OCTTriangle b) { 53 if (a.getGeometryIndex() < b.getGeometryIndex()){ 54 return -1; 55 }else if (a.getGeometryIndex() > b.getGeometryIndex()){ 56 return 1; 57 }else{ 58 return 0; 59 } 60 } 61 } 62 63 private static class Range { 64 65 private int start, length; 66 Range(int start, int length)67 public Range(int start, int length) { 68 this.start = start; 69 this.length = length; 70 } 71 getLength()72 public int getLength() { 73 return length; 74 } 75 setLength(int length)76 public void setLength(int length) { 77 this.length = length; 78 } 79 getStart()80 public int getStart() { 81 return start; 82 } 83 setStart(int start)84 public void setStart(int start) { 85 this.start = start; 86 } 87 88 } 89 90 /** 91 * Grabs all the triangles specified in <code>tris</code> from the input array 92 * (using the indices OCTTriangle.getGeometryIndex() & OCTTriangle.getTriangleIndex()) 93 * then organizes them into output geometry. 94 * 95 * @param inGeoms 96 * @param tris 97 * @return 98 */ gatherTris(Geometry[] inGeoms, List<OCTTriangle> tris)99 public static final List<Geometry> gatherTris(Geometry[] inGeoms, List<OCTTriangle> tris){ 100 Collections.sort(tris, comparator); 101 HashMap<Integer, Range> ranges = new HashMap<Integer, Range>(); 102 103 for (int i = 0; i < tris.size(); i++){ 104 Range r = ranges.get(tris.get(i).getGeometryIndex()); 105 if (r != null){ 106 // incremenet length 107 r.setLength(r.getLength()+1); 108 }else{ 109 // set offset, length is 1 110 ranges.put(tris.get(i).getGeometryIndex(), new Range(i, 1)); 111 } 112 } 113 114 List<Geometry> newGeoms = new ArrayList<Geometry>(); 115 int[] vertIndicies = new int[3]; 116 int[] newIndices = new int[3]; 117 boolean[] vertexCreated = new boolean[3]; 118 HashMap<Integer, Integer> indexCache = new HashMap<Integer, Integer>(); 119 for (Map.Entry<Integer, Range> entry : ranges.entrySet()){ 120 int inGeomIndex = entry.getKey().intValue(); 121 int outOffset = entry.getValue().start; 122 int outLength = entry.getValue().length; 123 124 Geometry inGeom = inGeoms[inGeomIndex]; 125 Mesh in = inGeom.getMesh(); 126 Mesh out = new Mesh(); 127 128 int outElementCount = outLength * 3; 129 ShortBuffer ib = BufferUtils.createShortBuffer(outElementCount); 130 out.setBuffer(Type.Index, 3, ib); 131 132 // generate output buffers based on input buffers 133 IntMap<VertexBuffer> bufs = in.getBuffers(); 134 for (Entry<VertexBuffer> ent : bufs){ 135 VertexBuffer vb = ent.getValue(); 136 if (vb.getBufferType() == Type.Index) 137 continue; 138 139 // NOTE: we are not actually sure 140 // how many elements will be in this buffer. 141 // It will be compacted later. 142 Buffer b = VertexBuffer.createBuffer(vb.getFormat(), 143 vb.getNumComponents(), 144 outElementCount); 145 146 VertexBuffer outVb = new VertexBuffer(vb.getBufferType()); 147 outVb.setNormalized(vb.isNormalized()); 148 outVb.setupData(vb.getUsage(), vb.getNumComponents(), vb.getFormat(), b); 149 out.setBuffer(outVb); 150 } 151 152 int currentVertex = 0; 153 for (int i = outOffset; i < outOffset + outLength; i++){ 154 OCTTriangle t = tris.get(i); 155 156 // find vertex indices for triangle t 157 in.getTriangle(t.getTriangleIndex(), vertIndicies); 158 159 // find indices in new buf 160 Integer i0 = indexCache.get(vertIndicies[0]); 161 Integer i1 = indexCache.get(vertIndicies[1]); 162 Integer i2 = indexCache.get(vertIndicies[2]); 163 164 // check which ones were not created 165 // if not created in new IB, create them 166 if (i0 == null){ 167 vertexCreated[0] = true; 168 newIndices[0] = currentVertex++; 169 indexCache.put(vertIndicies[0], newIndices[0]); 170 }else{ 171 newIndices[0] = i0.intValue(); 172 vertexCreated[0] = false; 173 } 174 if (i1 == null){ 175 vertexCreated[1] = true; 176 newIndices[1] = currentVertex++; 177 indexCache.put(vertIndicies[1], newIndices[1]); 178 }else{ 179 newIndices[1] = i1.intValue(); 180 vertexCreated[1] = false; 181 } 182 if (i2 == null){ 183 vertexCreated[2] = true; 184 newIndices[2] = currentVertex++; 185 indexCache.put(vertIndicies[2], newIndices[2]); 186 }else{ 187 newIndices[2] = i2.intValue(); 188 vertexCreated[2] = false; 189 } 190 191 // if any verticies were created for this triangle 192 // copy them to the output mesh 193 IntMap<VertexBuffer> inbufs = in.getBuffers(); 194 for (Entry<VertexBuffer> ent : inbufs){ 195 VertexBuffer vb = ent.getValue(); 196 if (vb.getBufferType() == Type.Index) 197 continue; 198 199 VertexBuffer outVb = out.getBuffer(vb.getBufferType()); 200 // copy verticies that were created for this triangle 201 for (int v = 0; v < 3; v++){ 202 if (!vertexCreated[v]) 203 continue; 204 205 // copy triangle's attribute from one 206 // buffer to another 207 vb.copyElement(vertIndicies[v], outVb, newIndices[v]); 208 } 209 } 210 211 // write the indices onto the output index buffer 212 ib.put((short)newIndices[0]) 213 .put((short)newIndices[1]) 214 .put((short)newIndices[2]); 215 } 216 ib.clear(); 217 indexCache.clear(); 218 219 // since some verticies were cached, it means there's 220 // extra data in some buffers 221 IntMap<VertexBuffer> outbufs = out.getBuffers(); 222 for (Entry<VertexBuffer> ent : outbufs){ 223 VertexBuffer vb = ent.getValue(); 224 if (vb.getBufferType() == Type.Index) 225 continue; 226 227 vb.compact(currentVertex); 228 } 229 230 out.updateBound(); 231 out.updateCounts(); 232 out.setStatic(); 233 //out.setInterleaved(); 234 Geometry outGeom = new Geometry("Geom"+entry.getKey(), out); 235 outGeom.setLocalTransform(inGeom.getWorldTransform()); 236 outGeom.setMaterial(inGeom.getMaterial()); 237 for (Light light : inGeom.getWorldLightList()){ 238 outGeom.addLight(light); 239 } 240 241 outGeom.updateGeometricState(); 242 newGeoms.add(outGeom); 243 } 244 245 return newGeoms; 246 } 247 248 } 249