Home | History | Annotate | Download | only in optimize
      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> {
     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 
     67         public Range(int start, int length) {
     68             this.start = start;
     69             this.length = length;
     70         }
     71 
     72         public int getLength() {
     73             return length;
     74         }
     75 
     76         public void setLength(int length) {
     77             this.length = length;
     78         }
     79 
     80         public int getStart() {
     81             return start;
     82         }
     83 
     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      */
     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