• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.bounding.BoundingBox;
36 import com.jme3.math.Transform;
37 import com.jme3.math.Vector2f;
38 import com.jme3.math.Vector3f;
39 import com.jme3.scene.Geometry;
40 import com.jme3.scene.Mesh;
41 import com.jme3.scene.VertexBuffer;
42 import com.jme3.scene.VertexBuffer.Format;
43 import com.jme3.scene.VertexBuffer.Type;
44 import com.jme3.scene.VertexBuffer.Usage;
45 import com.jme3.scene.mesh.IndexBuffer;
46 import com.jme3.util.BufferUtils;
47 import java.nio.*;
48 
49 public class FloatToFixed {
50 
51     private static final float shortSize = Short.MAX_VALUE - Short.MIN_VALUE;
52     private static final float shortOff  = (Short.MAX_VALUE + Short.MIN_VALUE) * 0.5f;
53 
54     private static final float byteSize = Byte.MAX_VALUE - Byte.MIN_VALUE;
55     private static final float byteOff  = (Byte.MAX_VALUE + Byte.MIN_VALUE) * 0.5f;
56 
convertToFixed(Geometry geom, Format posFmt, Format nmFmt, Format tcFmt)57     public static void convertToFixed(Geometry geom, Format posFmt, Format nmFmt, Format tcFmt){
58         geom.updateModelBound();
59         BoundingBox bbox = (BoundingBox) geom.getModelBound();
60         Mesh mesh = geom.getMesh();
61 
62         VertexBuffer positions = mesh.getBuffer(Type.Position);
63         VertexBuffer normals   = mesh.getBuffer(Type.Normal);
64         VertexBuffer texcoords = mesh.getBuffer(Type.TexCoord);
65         VertexBuffer indices   = mesh.getBuffer(Type.Index);
66 
67         // positions
68         FloatBuffer fb = (FloatBuffer) positions.getData();
69         if (posFmt != Format.Float){
70             Buffer newBuf = VertexBuffer.createBuffer(posFmt, positions.getNumComponents(),
71                                                       mesh.getVertexCount());
72             Transform t = convertPositions(fb, bbox, newBuf);
73             t.combineWithParent(geom.getLocalTransform());
74             geom.setLocalTransform(t);
75 
76             VertexBuffer newPosVb = new VertexBuffer(Type.Position);
77             newPosVb.setupData(positions.getUsage(),
78                                positions.getNumComponents(),
79                                posFmt,
80                                newBuf);
81             mesh.clearBuffer(Type.Position);
82             mesh.setBuffer(newPosVb);
83         }
84 
85         // normals, automatically convert to signed byte
86         fb = (FloatBuffer) normals.getData();
87 
88         ByteBuffer bb = BufferUtils.createByteBuffer(fb.capacity());
89         convertNormals(fb, bb);
90 
91         normals = new VertexBuffer(Type.Normal);
92         normals.setupData(Usage.Static, 3, Format.Byte, bb);
93         normals.setNormalized(true);
94         mesh.clearBuffer(Type.Normal);
95         mesh.setBuffer(normals);
96 
97         // texcoords
98         fb = (FloatBuffer) texcoords.getData();
99         if (tcFmt != Format.Float){
100             Buffer newBuf = VertexBuffer.createBuffer(tcFmt,
101                                                       texcoords.getNumComponents(),
102                                                       mesh.getVertexCount());
103             convertTexCoords2D(fb, newBuf);
104 
105             VertexBuffer newTcVb = new VertexBuffer(Type.TexCoord);
106             newTcVb.setupData(texcoords.getUsage(),
107                               texcoords.getNumComponents(),
108                               tcFmt,
109                               newBuf);
110             mesh.clearBuffer(Type.TexCoord);
111             mesh.setBuffer(newTcVb);
112         }
113     }
114 
compressIndexBuffer(Mesh mesh)115     public static void compressIndexBuffer(Mesh mesh){
116         int vertCount = mesh.getVertexCount();
117         VertexBuffer vb = mesh.getBuffer(Type.Index);
118         Format targetFmt;
119         if (vb.getFormat() == Format.UnsignedInt && vertCount <= 0xffff){
120             if (vertCount <= 256)
121                 targetFmt = Format.UnsignedByte;
122             else
123                 targetFmt = Format.UnsignedShort;
124         }else if (vb.getFormat() == Format.UnsignedShort && vertCount <= 0xff){
125             targetFmt = Format.UnsignedByte;
126         }else{
127             return;
128         }
129 
130         IndexBuffer src = mesh.getIndexBuffer();
131         Buffer newBuf = VertexBuffer.createBuffer(targetFmt, vb.getNumComponents(), src.size());
132 
133         VertexBuffer newVb = new VertexBuffer(Type.Index);
134         newVb.setupData(vb.getUsage(), vb.getNumComponents(), targetFmt, newBuf);
135         mesh.clearBuffer(Type.Index);
136         mesh.setBuffer(newVb);
137 
138         IndexBuffer dst = mesh.getIndexBuffer();
139         for (int i = 0; i < src.size(); i++){
140             dst.put(i, src.get(i));
141         }
142     }
143 
convertToFixed(FloatBuffer input, IntBuffer output)144     private static void convertToFixed(FloatBuffer input, IntBuffer output){
145         if (output.capacity() < input.capacity())
146             throw new RuntimeException("Output must be at least as large as input!");
147 
148         input.clear();
149         output.clear();
150         for (int i = 0; i < input.capacity(); i++){
151             output.put( (int) (input.get() * (float)(1<<16)) );
152         }
153         output.flip();
154     }
155 
convertToFloat(IntBuffer input, FloatBuffer output)156     private static void convertToFloat(IntBuffer input, FloatBuffer output){
157         if (output.capacity() < input.capacity())
158             throw new RuntimeException("Output must be at least as large as input!");
159 
160         input.clear();
161         output.clear();
162         for (int i = 0; i < input.capacity(); i++){
163             output.put( ((float)input.get() / (float)(1<<16)) );
164         }
165         output.flip();
166     }
167 
convertToUByte(FloatBuffer input, ByteBuffer output)168     private static void convertToUByte(FloatBuffer input, ByteBuffer output){
169         if (output.capacity() < input.capacity())
170             throw new RuntimeException("Output must be at least as large as input!");
171 
172         input.clear();
173         output.clear();
174         for (int i = 0; i < input.capacity(); i++){
175             output.put( (byte) (input.get() * 255f) );
176         }
177         output.flip();
178     }
179 
180 
convertToUByte(VertexBuffer vb)181     public static VertexBuffer convertToUByte(VertexBuffer vb){
182         FloatBuffer fb = (FloatBuffer) vb.getData();
183         ByteBuffer bb = BufferUtils.createByteBuffer(fb.capacity());
184         convertToUByte(fb, bb);
185 
186         VertexBuffer newVb = new VertexBuffer(vb.getBufferType());
187         newVb.setupData(vb.getUsage(),
188                         vb.getNumComponents(),
189                         Format.UnsignedByte,
190                         bb);
191         newVb.setNormalized(true);
192         return newVb;
193     }
194 
convertToFixed(VertexBuffer vb)195     public static VertexBuffer convertToFixed(VertexBuffer vb){
196         if (vb.getFormat() == Format.Int)
197             return vb;
198 
199         FloatBuffer fb = (FloatBuffer) vb.getData();
200         IntBuffer ib = BufferUtils.createIntBuffer(fb.capacity());
201         convertToFixed(fb, ib);
202 
203         VertexBuffer newVb = new VertexBuffer(vb.getBufferType());
204         newVb.setupData(vb.getUsage(),
205                         vb.getNumComponents(),
206                         Format.Int,
207                         ib);
208         return newVb;
209     }
210 
convertToFloat(VertexBuffer vb)211     public static VertexBuffer convertToFloat(VertexBuffer vb){
212         if (vb.getFormat() == Format.Float)
213             return vb;
214 
215         IntBuffer ib = (IntBuffer) vb.getData();
216         FloatBuffer fb = BufferUtils.createFloatBuffer(ib.capacity());
217         convertToFloat(ib, fb);
218 
219         VertexBuffer newVb = new VertexBuffer(vb.getBufferType());
220         newVb.setupData(vb.getUsage(),
221                         vb.getNumComponents(),
222                         Format.Float,
223                         fb);
224         return newVb;
225     }
226 
convertNormals(FloatBuffer input, ByteBuffer output)227     private static void convertNormals(FloatBuffer input, ByteBuffer output){
228         if (output.capacity() < input.capacity())
229             throw new RuntimeException("Output must be at least as large as input!");
230 
231         input.clear();
232         output.clear();
233         Vector3f temp = new Vector3f();
234         int vertexCount = input.capacity() / 3;
235         for (int i = 0; i < vertexCount; i++){
236             BufferUtils.populateFromBuffer(temp, input, i);
237 
238             // offset and scale vector into -128 ... 127
239             temp.multLocal(127).addLocal(0.5f, 0.5f, 0.5f);
240 
241             // quantize
242             byte v1 = (byte) temp.getX();
243             byte v2 = (byte) temp.getY();
244             byte v3 = (byte) temp.getZ();
245 
246             // store
247             output.put(v1).put(v2).put(v3);
248         }
249     }
250 
convertTexCoords2D(FloatBuffer input, Buffer output)251     private static void convertTexCoords2D(FloatBuffer input, Buffer output){
252         if (output.capacity() < input.capacity())
253             throw new RuntimeException("Output must be at least as large as input!");
254 
255         input.clear();
256         output.clear();
257         Vector2f temp = new Vector2f();
258         int vertexCount = input.capacity() / 2;
259 
260         ShortBuffer sb = null;
261         IntBuffer ib = null;
262 
263         if (output instanceof ShortBuffer)
264             sb = (ShortBuffer) output;
265         else if (output instanceof IntBuffer)
266             ib = (IntBuffer) output;
267         else
268             throw new UnsupportedOperationException();
269 
270         for (int i = 0; i < vertexCount; i++){
271             BufferUtils.populateFromBuffer(temp, input, i);
272 
273             if (sb != null){
274                 sb.put( (short) (temp.getX()*Short.MAX_VALUE) );
275                 sb.put( (short) (temp.getY()*Short.MAX_VALUE) );
276             }else{
277                 int v1 = (int) (temp.getX() * ((float)(1 << 16)));
278                 int v2 = (int) (temp.getY() * ((float)(1 << 16)));
279                 ib.put(v1).put(v2);
280             }
281         }
282     }
283 
convertPositions(FloatBuffer input, BoundingBox bbox, Buffer output)284     private static Transform convertPositions(FloatBuffer input, BoundingBox bbox, Buffer output){
285         if (output.capacity() < input.capacity())
286             throw new RuntimeException("Output must be at least as large as input!");
287 
288         Vector3f offset = bbox.getCenter().negate();
289         Vector3f size = new Vector3f(bbox.getXExtent(), bbox.getYExtent(), bbox.getZExtent());
290         size.multLocal(2);
291 
292         ShortBuffer sb = null;
293         ByteBuffer bb = null;
294         float dataTypeSize;
295         float dataTypeOffset;
296         if (output instanceof ShortBuffer){
297             sb = (ShortBuffer) output;
298             dataTypeOffset = shortOff;
299             dataTypeSize = shortSize;
300         }else{
301             bb = (ByteBuffer) output;
302             dataTypeOffset = byteOff;
303             dataTypeSize = byteSize;
304         }
305         Vector3f scale = new Vector3f();
306         scale.set(dataTypeSize, dataTypeSize, dataTypeSize).divideLocal(size);
307 
308         Vector3f invScale = new Vector3f();
309         invScale.set(size).divideLocal(dataTypeSize);
310 
311         offset.multLocal(scale);
312         offset.addLocal(dataTypeOffset, dataTypeOffset, dataTypeOffset);
313 
314         // offset = (-modelOffset * shortSize)/modelSize + shortOff
315         // scale = shortSize / modelSize
316 
317         input.clear();
318         output.clear();
319         Vector3f temp = new Vector3f();
320         int vertexCount = input.capacity() / 3;
321         for (int i = 0; i < vertexCount; i++){
322             BufferUtils.populateFromBuffer(temp, input, i);
323 
324             // offset and scale vector into -32768 ... 32767
325             // or into -128 ... 127 if using bytes
326             temp.multLocal(scale);
327             temp.addLocal(offset);
328 
329             // quantize and store
330             if (sb != null){
331                 short v1 = (short) temp.getX();
332                 short v2 = (short) temp.getY();
333                 short v3 = (short) temp.getZ();
334                 sb.put(v1).put(v2).put(v3);
335             }else{
336                 byte v1 = (byte) temp.getX();
337                 byte v2 = (byte) temp.getY();
338                 byte v3 = (byte) temp.getZ();
339                 bb.put(v1).put(v2).put(v3);
340             }
341         }
342 
343         Transform transform = new Transform();
344         transform.setTranslation(offset.negate().multLocal(invScale));
345         transform.setScale(invScale);
346         return transform;
347     }
348 
349 }
350