FloatToFixed.java 13 KB

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