/* * Copyright (c) 2009-2010 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of 'jMonkeyEngine' nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package jme3tools.converters.model; import com.jme3.scene.Mesh.Mode; import com.jme3.scene.*; import com.jme3.scene.VertexBuffer.Format; import com.jme3.scene.VertexBuffer.Type; import com.jme3.scene.mesh.IndexBuffer; import com.jme3.util.IntMap; import com.jme3.util.IntMap.Entry; import java.nio.Buffer; import java.util.Arrays; import java.util.Comparator; import jme3tools.converters.model.strip.PrimitiveGroup; import jme3tools.converters.model.strip.TriStrip; public class ModelConverter { private static final class PrimComparator implements Comparator { public int compare(PrimitiveGroup g1, PrimitiveGroup g2) { if (g1.type < g2.type) return -1; else if (g1.type > g2.type) return 1; else return 0; } } private static final PrimComparator primComp = new PrimComparator(); public static void generateStrips(Mesh mesh, boolean stitch, boolean listOnly, int cacheSize, int minStripSize){ TriStrip ts = new TriStrip(); ts.setStitchStrips(stitch); ts.setCacheSize(cacheSize); ts.setListsOnly(listOnly); ts.setMinStripSize(minStripSize); IndexBuffer ib = mesh.getIndicesAsList(); int[] indices = new int[ib.size()]; for (int i = 0; i < indices.length; i++) indices[i] = ib.get(i); PrimitiveGroup[] groups = ts.generateStrips(indices); Arrays.sort(groups, primComp); int numElements = 0; for (PrimitiveGroup group : groups) numElements += group.numIndices; VertexBuffer original = mesh.getBuffer(Type.Index); Buffer buf = VertexBuffer.createBuffer(original.getFormat(), original.getNumComponents(), numElements); original.updateData(buf); ib = mesh.getIndexBuffer(); int curIndex = 0; int[] modeStart = new int[]{ -1, -1, -1 }; int[] elementLengths = new int[groups.length]; for (int i = 0; i < groups.length; i++){ PrimitiveGroup group = groups[i]; elementLengths[i] = group.numIndices; if (modeStart[group.type] == -1){ modeStart[group.type] = i; } int[] trimmedIndices = group.getTrimmedIndices(); for (int j = 0; j < trimmedIndices.length; j++){ ib.put(curIndex + j, trimmedIndices[j]); } curIndex += group.numIndices; } if (modeStart[0] == -1 && modeStart[1] == 0 && modeStart[2] == -1 && elementLengths.length == 1){ original.compact(elementLengths[0]); mesh.setMode(Mode.TriangleStrip); }else{ mesh.setElementLengths(elementLengths); mesh.setModeStart(modeStart); mesh.setMode(Mode.Hybrid); } mesh.updateCounts(); } public static void optimize(Mesh mesh, boolean toFixed){ // update any data that need updating mesh.updateBound(); mesh.updateCounts(); // set all buffers into STATIC_DRAW mode mesh.setStatic(); if (mesh.getBuffer(Type.Index) != null){ // compress index buffer from UShort to UByte (if possible) FloatToFixed.compressIndexBuffer(mesh); // generate triangle strips stitched with degenerate tris generateStrips(mesh, false, false, 16, 0); } IntMap bufs = mesh.getBuffers(); for (Entry entry : bufs){ VertexBuffer vb = entry.getValue(); if (vb == null || vb.getBufferType() == Type.Index) continue; if (vb.getFormat() == Format.Float){ if (vb.getBufferType() == Type.Color){ // convert the color buffer to UByte vb = FloatToFixed.convertToUByte(vb); vb.setNormalized(true); }else if (toFixed){ // convert normals, positions, and texcoords // to fixed-point (16.16) vb = FloatToFixed.convertToFixed(vb); // vb = FloatToFixed.convertToFloat(vb); } mesh.clearBuffer(vb.getBufferType()); mesh.setBuffer(vb); } } //mesh.setInterleaved(); } private static void optimizeScene(Spatial source, boolean toFixed){ if (source instanceof Geometry){ Geometry geom = (Geometry) source; Mesh mesh = geom.getMesh(); optimize(mesh, toFixed); }else if (source instanceof Node){ Node node = (Node) source; for (int i = node.getQuantity() - 1; i >= 0; i--){ Spatial child = node.getChild(i); optimizeScene(child, toFixed); } } } public static void optimize(Spatial source, boolean toFixed){ optimizeScene(source, toFixed); source.updateLogicalState(0); source.updateGeometricState(); } }