1 /* 2 * Copyright (c) 2009-2010 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.converters.model; 34 35 import com.jme3.scene.Mesh.Mode; 36 import com.jme3.scene.*; 37 import com.jme3.scene.VertexBuffer.Format; 38 import com.jme3.scene.VertexBuffer.Type; 39 import com.jme3.scene.mesh.IndexBuffer; 40 import com.jme3.util.IntMap; 41 import com.jme3.util.IntMap.Entry; 42 import java.nio.Buffer; 43 import java.util.Arrays; 44 import java.util.Comparator; 45 import jme3tools.converters.model.strip.PrimitiveGroup; 46 import jme3tools.converters.model.strip.TriStrip; 47 48 public class ModelConverter { 49 50 private static final class PrimComparator 51 implements Comparator<PrimitiveGroup> { 52 53 public int compare(PrimitiveGroup g1, PrimitiveGroup g2) { 54 if (g1.type < g2.type) 55 return -1; 56 else if (g1.type > g2.type) 57 return 1; 58 else 59 return 0; 60 } 61 } 62 63 private static final PrimComparator primComp = new PrimComparator(); 64 65 public static void generateStrips(Mesh mesh, boolean stitch, boolean listOnly, int cacheSize, int minStripSize){ 66 TriStrip ts = new TriStrip(); 67 ts.setStitchStrips(stitch); 68 ts.setCacheSize(cacheSize); 69 ts.setListsOnly(listOnly); 70 ts.setMinStripSize(minStripSize); 71 72 IndexBuffer ib = mesh.getIndicesAsList(); 73 int[] indices = new int[ib.size()]; 74 for (int i = 0; i < indices.length; i++) 75 indices[i] = ib.get(i); 76 77 PrimitiveGroup[] groups = ts.generateStrips(indices); 78 Arrays.sort(groups, primComp); 79 80 int numElements = 0; 81 for (PrimitiveGroup group : groups) 82 numElements += group.numIndices; 83 84 VertexBuffer original = mesh.getBuffer(Type.Index); 85 Buffer buf = VertexBuffer.createBuffer(original.getFormat(), 86 original.getNumComponents(), 87 numElements); 88 original.updateData(buf); 89 ib = mesh.getIndexBuffer(); 90 91 int curIndex = 0; 92 int[] modeStart = new int[]{ -1, -1, -1 }; 93 int[] elementLengths = new int[groups.length]; 94 for (int i = 0; i < groups.length; i++){ 95 PrimitiveGroup group = groups[i]; 96 elementLengths[i] = group.numIndices; 97 98 if (modeStart[group.type] == -1){ 99 modeStart[group.type] = i; 100 } 101 102 int[] trimmedIndices = group.getTrimmedIndices(); 103 for (int j = 0; j < trimmedIndices.length; j++){ 104 ib.put(curIndex + j, trimmedIndices[j]); 105 } 106 107 curIndex += group.numIndices; 108 } 109 110 if (modeStart[0] == -1 && modeStart[1] == 0 && modeStart[2] == -1 && 111 elementLengths.length == 1){ 112 original.compact(elementLengths[0]); 113 mesh.setMode(Mode.TriangleStrip); 114 }else{ 115 mesh.setElementLengths(elementLengths); 116 mesh.setModeStart(modeStart); 117 mesh.setMode(Mode.Hybrid); 118 } 119 120 mesh.updateCounts(); 121 } 122 123 public static void optimize(Mesh mesh, boolean toFixed){ 124 // update any data that need updating 125 mesh.updateBound(); 126 mesh.updateCounts(); 127 128 // set all buffers into STATIC_DRAW mode 129 mesh.setStatic(); 130 131 if (mesh.getBuffer(Type.Index) != null){ 132 // compress index buffer from UShort to UByte (if possible) 133 FloatToFixed.compressIndexBuffer(mesh); 134 135 // generate triangle strips stitched with degenerate tris 136 generateStrips(mesh, false, false, 16, 0); 137 } 138 139 IntMap<VertexBuffer> bufs = mesh.getBuffers(); 140 for (Entry<VertexBuffer> entry : bufs){ 141 VertexBuffer vb = entry.getValue(); 142 if (vb == null || vb.getBufferType() == Type.Index) 143 continue; 144 145 if (vb.getFormat() == Format.Float){ 146 if (vb.getBufferType() == Type.Color){ 147 // convert the color buffer to UByte 148 vb = FloatToFixed.convertToUByte(vb); 149 vb.setNormalized(true); 150 }else if (toFixed){ 151 // convert normals, positions, and texcoords 152 // to fixed-point (16.16) 153 vb = FloatToFixed.convertToFixed(vb); 154 // vb = FloatToFixed.convertToFloat(vb); 155 } 156 mesh.clearBuffer(vb.getBufferType()); 157 mesh.setBuffer(vb); 158 } 159 } 160 //mesh.setInterleaved(); 161 } 162 163 private static void optimizeScene(Spatial source, boolean toFixed){ 164 if (source instanceof Geometry){ 165 Geometry geom = (Geometry) source; 166 Mesh mesh = geom.getMesh(); 167 optimize(mesh, toFixed); 168 }else if (source instanceof Node){ 169 Node node = (Node) source; 170 for (int i = node.getQuantity() - 1; i >= 0; i--){ 171 Spatial child = node.getChild(i); 172 optimizeScene(child, toFixed); 173 } 174 } 175 } 176 177 public static void optimize(Spatial source, boolean toFixed){ 178 optimizeScene(source, toFixed); 179 source.updateLogicalState(0); 180 source.updateGeometricState(); 181 } 182 183 } 184