aboutsummaryrefslogtreecommitdiff
path: root/engine/src/tools/jme3tools/converters/model/FloatToFixed.java
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/tools/jme3tools/converters/model/FloatToFixed.java')
-rw-r--r--engine/src/tools/jme3tools/converters/model/FloatToFixed.java349
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;
+ }
+
+}