diff options
Diffstat (limited to 'engine/src/tools/jme3tools/converters/model/FloatToFixed.java')
-rw-r--r-- | engine/src/tools/jme3tools/converters/model/FloatToFixed.java | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/engine/src/tools/jme3tools/converters/model/FloatToFixed.java b/engine/src/tools/jme3tools/converters/model/FloatToFixed.java new file mode 100644 index 0000000..0d0647a --- /dev/null +++ b/engine/src/tools/jme3tools/converters/model/FloatToFixed.java @@ -0,0 +1,349 @@ +/* + * 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.bounding.BoundingBox; +import com.jme3.math.Transform; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.VertexBuffer; +import com.jme3.scene.VertexBuffer.Format; +import com.jme3.scene.VertexBuffer.Type; +import com.jme3.scene.VertexBuffer.Usage; +import com.jme3.scene.mesh.IndexBuffer; +import com.jme3.util.BufferUtils; +import java.nio.*; + +public class FloatToFixed { + + private static final float shortSize = Short.MAX_VALUE - Short.MIN_VALUE; + private static final float shortOff = (Short.MAX_VALUE + Short.MIN_VALUE) * 0.5f; + + private static final float byteSize = Byte.MAX_VALUE - Byte.MIN_VALUE; + private static final float byteOff = (Byte.MAX_VALUE + Byte.MIN_VALUE) * 0.5f; + + public static void convertToFixed(Geometry geom, Format posFmt, Format nmFmt, Format tcFmt){ + geom.updateModelBound(); + BoundingBox bbox = (BoundingBox) geom.getModelBound(); + Mesh mesh = geom.getMesh(); + + VertexBuffer positions = mesh.getBuffer(Type.Position); + VertexBuffer normals = mesh.getBuffer(Type.Normal); + VertexBuffer texcoords = mesh.getBuffer(Type.TexCoord); + VertexBuffer indices = mesh.getBuffer(Type.Index); + + // positions + FloatBuffer fb = (FloatBuffer) positions.getData(); + if (posFmt != Format.Float){ + Buffer newBuf = VertexBuffer.createBuffer(posFmt, positions.getNumComponents(), + mesh.getVertexCount()); + Transform t = convertPositions(fb, bbox, newBuf); + t.combineWithParent(geom.getLocalTransform()); + geom.setLocalTransform(t); + + VertexBuffer newPosVb = new VertexBuffer(Type.Position); + newPosVb.setupData(positions.getUsage(), + positions.getNumComponents(), + posFmt, + newBuf); + mesh.clearBuffer(Type.Position); + mesh.setBuffer(newPosVb); + } + + // normals, automatically convert to signed byte + fb = (FloatBuffer) normals.getData(); + + ByteBuffer bb = BufferUtils.createByteBuffer(fb.capacity()); + convertNormals(fb, bb); + + normals = new VertexBuffer(Type.Normal); + normals.setupData(Usage.Static, 3, Format.Byte, bb); + normals.setNormalized(true); + mesh.clearBuffer(Type.Normal); + mesh.setBuffer(normals); + + // texcoords + fb = (FloatBuffer) texcoords.getData(); + if (tcFmt != Format.Float){ + Buffer newBuf = VertexBuffer.createBuffer(tcFmt, + texcoords.getNumComponents(), + mesh.getVertexCount()); + convertTexCoords2D(fb, newBuf); + + VertexBuffer newTcVb = new VertexBuffer(Type.TexCoord); + newTcVb.setupData(texcoords.getUsage(), + texcoords.getNumComponents(), + tcFmt, + newBuf); + mesh.clearBuffer(Type.TexCoord); + mesh.setBuffer(newTcVb); + } + } + + public static void compressIndexBuffer(Mesh mesh){ + int vertCount = mesh.getVertexCount(); + VertexBuffer vb = mesh.getBuffer(Type.Index); + Format targetFmt; + if (vb.getFormat() == Format.UnsignedInt && vertCount <= 0xffff){ + if (vertCount <= 256) + targetFmt = Format.UnsignedByte; + else + targetFmt = Format.UnsignedShort; + }else if (vb.getFormat() == Format.UnsignedShort && vertCount <= 0xff){ + targetFmt = Format.UnsignedByte; + }else{ + return; + } + + IndexBuffer src = mesh.getIndexBuffer(); + Buffer newBuf = VertexBuffer.createBuffer(targetFmt, vb.getNumComponents(), src.size()); + + VertexBuffer newVb = new VertexBuffer(Type.Index); + newVb.setupData(vb.getUsage(), vb.getNumComponents(), targetFmt, newBuf); + mesh.clearBuffer(Type.Index); + mesh.setBuffer(newVb); + + IndexBuffer dst = mesh.getIndexBuffer(); + for (int i = 0; i < src.size(); i++){ + dst.put(i, src.get(i)); + } + } + + private static void convertToFixed(FloatBuffer input, IntBuffer output){ + if (output.capacity() < input.capacity()) + throw new RuntimeException("Output must be at least as large as input!"); + + input.clear(); + output.clear(); + for (int i = 0; i < input.capacity(); i++){ + output.put( (int) (input.get() * (float)(1<<16)) ); + } + output.flip(); + } + + private static void convertToFloat(IntBuffer input, FloatBuffer output){ + if (output.capacity() < input.capacity()) + throw new RuntimeException("Output must be at least as large as input!"); + + input.clear(); + output.clear(); + for (int i = 0; i < input.capacity(); i++){ + output.put( ((float)input.get() / (float)(1<<16)) ); + } + output.flip(); + } + + private static void convertToUByte(FloatBuffer input, ByteBuffer output){ + if (output.capacity() < input.capacity()) + throw new RuntimeException("Output must be at least as large as input!"); + + input.clear(); + output.clear(); + for (int i = 0; i < input.capacity(); i++){ + output.put( (byte) (input.get() * 255f) ); + } + output.flip(); + } + + + public static VertexBuffer convertToUByte(VertexBuffer vb){ + FloatBuffer fb = (FloatBuffer) vb.getData(); + ByteBuffer bb = BufferUtils.createByteBuffer(fb.capacity()); + convertToUByte(fb, bb); + + VertexBuffer newVb = new VertexBuffer(vb.getBufferType()); + newVb.setupData(vb.getUsage(), + vb.getNumComponents(), + Format.UnsignedByte, + bb); + newVb.setNormalized(true); + return newVb; + } + + public static VertexBuffer convertToFixed(VertexBuffer vb){ + if (vb.getFormat() == Format.Int) + return vb; + + FloatBuffer fb = (FloatBuffer) vb.getData(); + IntBuffer ib = BufferUtils.createIntBuffer(fb.capacity()); + convertToFixed(fb, ib); + + VertexBuffer newVb = new VertexBuffer(vb.getBufferType()); + newVb.setupData(vb.getUsage(), + vb.getNumComponents(), + Format.Int, + ib); + return newVb; + } + + public static VertexBuffer convertToFloat(VertexBuffer vb){ + if (vb.getFormat() == Format.Float) + return vb; + + IntBuffer ib = (IntBuffer) vb.getData(); + FloatBuffer fb = BufferUtils.createFloatBuffer(ib.capacity()); + convertToFloat(ib, fb); + + VertexBuffer newVb = new VertexBuffer(vb.getBufferType()); + newVb.setupData(vb.getUsage(), + vb.getNumComponents(), + Format.Float, + fb); + return newVb; + } + + private static void convertNormals(FloatBuffer input, ByteBuffer output){ + if (output.capacity() < input.capacity()) + throw new RuntimeException("Output must be at least as large as input!"); + + input.clear(); + output.clear(); + Vector3f temp = new Vector3f(); + int vertexCount = input.capacity() / 3; + for (int i = 0; i < vertexCount; i++){ + BufferUtils.populateFromBuffer(temp, input, i); + + // offset and scale vector into -128 ... 127 + temp.multLocal(127).addLocal(0.5f, 0.5f, 0.5f); + + // quantize + byte v1 = (byte) temp.getX(); + byte v2 = (byte) temp.getY(); + byte v3 = (byte) temp.getZ(); + + // store + output.put(v1).put(v2).put(v3); + } + } + + private static void convertTexCoords2D(FloatBuffer input, Buffer output){ + if (output.capacity() < input.capacity()) + throw new RuntimeException("Output must be at least as large as input!"); + + input.clear(); + output.clear(); + Vector2f temp = new Vector2f(); + int vertexCount = input.capacity() / 2; + + ShortBuffer sb = null; + IntBuffer ib = null; + + if (output instanceof ShortBuffer) + sb = (ShortBuffer) output; + else if (output instanceof IntBuffer) + ib = (IntBuffer) output; + else + throw new UnsupportedOperationException(); + + for (int i = 0; i < vertexCount; i++){ + BufferUtils.populateFromBuffer(temp, input, i); + + if (sb != null){ + sb.put( (short) (temp.getX()*Short.MAX_VALUE) ); + sb.put( (short) (temp.getY()*Short.MAX_VALUE) ); + }else{ + int v1 = (int) (temp.getX() * ((float)(1 << 16))); + int v2 = (int) (temp.getY() * ((float)(1 << 16))); + ib.put(v1).put(v2); + } + } + } + + private static Transform convertPositions(FloatBuffer input, BoundingBox bbox, Buffer output){ + if (output.capacity() < input.capacity()) + throw new RuntimeException("Output must be at least as large as input!"); + + Vector3f offset = bbox.getCenter().negate(); + Vector3f size = new Vector3f(bbox.getXExtent(), bbox.getYExtent(), bbox.getZExtent()); + size.multLocal(2); + + ShortBuffer sb = null; + ByteBuffer bb = null; + float dataTypeSize; + float dataTypeOffset; + if (output instanceof ShortBuffer){ + sb = (ShortBuffer) output; + dataTypeOffset = shortOff; + dataTypeSize = shortSize; + }else{ + bb = (ByteBuffer) output; + dataTypeOffset = byteOff; + dataTypeSize = byteSize; + } + Vector3f scale = new Vector3f(); + scale.set(dataTypeSize, dataTypeSize, dataTypeSize).divideLocal(size); + + Vector3f invScale = new Vector3f(); + invScale.set(size).divideLocal(dataTypeSize); + + offset.multLocal(scale); + offset.addLocal(dataTypeOffset, dataTypeOffset, dataTypeOffset); + + // offset = (-modelOffset * shortSize)/modelSize + shortOff + // scale = shortSize / modelSize + + input.clear(); + output.clear(); + Vector3f temp = new Vector3f(); + int vertexCount = input.capacity() / 3; + for (int i = 0; i < vertexCount; i++){ + BufferUtils.populateFromBuffer(temp, input, i); + + // offset and scale vector into -32768 ... 32767 + // or into -128 ... 127 if using bytes + temp.multLocal(scale); + temp.addLocal(offset); + + // quantize and store + if (sb != null){ + short v1 = (short) temp.getX(); + short v2 = (short) temp.getY(); + short v3 = (short) temp.getZ(); + sb.put(v1).put(v2).put(v3); + }else{ + byte v1 = (byte) temp.getX(); + byte v2 = (byte) temp.getY(); + byte v3 = (byte) temp.getZ(); + bb.put(v1).put(v2).put(v3); + } + } + + Transform transform = new Transform(); + transform.setTranslation(offset.negate().multLocal(invScale)); + transform.setScale(invScale); + return transform; + } + +} |