OSDN Git Service

628358c6bee7619f382cef0dd3991f49336da7d6
[mikumikustudio/MikuMikuStudio.git] / engine / src / core / com / jme3 / scene / Mesh.java
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 com.jme3.scene;
34
35 import com.jme3.scene.mesh.IndexShortBuffer;
36 import com.jme3.scene.mesh.IndexIntBuffer;
37 import com.jme3.scene.mesh.IndexBuffer;
38 import com.jme3.scene.mesh.IndexByteBuffer;
39 import com.jme3.bounding.BoundingBox;
40 import com.jme3.bounding.BoundingVolume;
41 import com.jme3.collision.Collidable;
42 import com.jme3.collision.CollisionResults;
43 import com.jme3.collision.bih.BIHTree;
44 import com.jme3.export.JmeExporter;
45 import com.jme3.export.JmeImporter;
46 import com.jme3.export.InputCapsule;
47 import com.jme3.export.OutputCapsule;
48 import com.jme3.export.Savable;
49 import com.jme3.material.RenderState;
50 import com.jme3.math.Matrix4f;
51 import com.jme3.math.Triangle;
52 import com.jme3.math.Vector2f;
53 import com.jme3.math.Vector3f;
54 import com.jme3.scene.VertexBuffer.*;
55 import com.jme3.scene.mesh.VirtualIndexBuffer;
56 import com.jme3.scene.mesh.WrappedIndexBuffer;
57 import com.jme3.util.BufferUtils;
58 import com.jme3.util.IntMap;
59 import com.jme3.util.IntMap.Entry;
60 import java.io.IOException;
61 import java.nio.Buffer;
62 import java.nio.ByteBuffer;
63 import java.nio.DoubleBuffer;
64 import java.nio.FloatBuffer;
65 import java.nio.IntBuffer;
66 import java.nio.ShortBuffer;
67 import java.util.ArrayList;
68
69 /**
70  * <code>Mesh</code> is used to store rendering data.
71  * <p>
72  * All visible elements in a scene are represented by meshes.
73  * Meshes may contain three types of geometric primitives:
74  * <ul>
75  * <li>Points - Every vertex represents a single point in space, 
76  * the size of each point is specified via {@link Mesh#setPointSize(float) }.
77  * Points can also be used for {@link RenderState#setPointSprite(boolean) point
78  * sprite} mode.</li>
79  * <li>Lines - 2 vertices represent a line segment, with the width specified
80  * via {@link Mesh#setLineWidth(float) }.</li>
81  * <li>Triangles - 3 vertices represent a solid triangle primitive. </li>
82  * </ul>
83  * 
84  * @author Kirill Vainer
85  */
86 public class Mesh implements Savable, Cloneable {
87
88     /**
89      * The mode of the Mesh specifies both the type of primitive represented
90      * by the mesh and how the data should be interpreted.
91      */
92     public enum Mode {
93         /**
94          * A primitive is a single point in space. The size of the points 
95          * can be specified with {@link Mesh#setPointSize(float) }.
96          */
97         Points(true),
98         
99         /**
100          * A primitive is a line segment. Every two vertices specify
101          * a single line. {@link Mesh#setLineWidth(float) } can be used 
102          * to set the width of the lines.
103          */
104         Lines(true),
105         
106         /**
107          * A primitive is a line segment. The first two vertices specify
108          * a single line, while subsequent vertices are combined with the 
109          * previous vertex to make a line. {@link Mesh#setLineWidth(float) } can 
110          * be used to set the width of the lines.
111          */
112         LineStrip(false),
113         
114         /**
115          * Identical to {@link #LineStrip} except that at the end
116          * the last vertex is connected with the first to form a line.
117          * {@link Mesh#setLineWidth(float) } can be used 
118          * to set the width of the lines.
119          */
120         LineLoop(false),
121         
122         /**
123          * A primitive is a triangle. Each 3 vertices specify a single
124          * triangle.
125          */
126         Triangles(true),
127         
128         /**
129          * Similar to {@link #Triangles}, the first 3 vertices 
130          * specify a triangle, while subsequent vertices are combined with
131          * the previous two to form a triangle. 
132          */
133         TriangleStrip(false),
134         
135         /**
136          * Similar to {@link #Triangles}, the first 3 vertices 
137          * specify a triangle, each 2 subsequent vertices are combined
138          * with the very first vertex to make a triangle.
139          */
140         TriangleFan(false),
141         
142         /**
143          * A combination of various triangle modes. It is best to avoid
144          * using this mode as it may not be supported by all renderers.
145          * The {@link Mesh#setModeStart(int[]) mode start points} and
146          * {@link Mesh#setElementLengths(int[]) element lengths} must 
147          * be specified for this mode.
148          */
149         Hybrid(false);
150         
151         private boolean listMode = false;
152         
153         private Mode(boolean listMode){
154             this.listMode = listMode;
155         }
156         
157         /**
158          * Returns true if the specified mode is a list mode (meaning
159          * ,it specifies the indices as a linear list and not some special 
160          * format).
161          * Will return true for the types {@link #Points}, {@link #Lines} and
162          * {@link #Triangles}.
163          * 
164          * @return true if the mode is a list type mode
165          */
166         public boolean isListMode(){
167             return listMode;
168         }
169     }
170
171     /**
172      * The bounding volume that contains the mesh entirely.
173      * By default a BoundingBox (AABB).
174      */
175     private BoundingVolume meshBound =  new BoundingBox();
176
177     private CollisionData collisionTree = null;
178
179     private ArrayList<VertexBuffer> buffersList = new ArrayList<VertexBuffer>(5);
180     private IntMap<VertexBuffer> buffers = new IntMap<VertexBuffer>();
181     private VertexBuffer[] lodLevels;
182     private float pointSize = 1;
183     private float lineWidth = 1;
184
185     private transient int vertexArrayID = -1;
186
187     private int vertCount = -1;
188     private int elementCount = -1;
189     private int maxNumWeights = -1; // only if using skeletal animation
190
191     private int[] elementLengths;
192     private int[] modeStart;
193
194     private Mode mode = Mode.Triangles;
195
196     /**
197      * Creates a new mesh with no {@link VertexBuffer vertex buffers}.
198      */
199     public Mesh(){
200     }
201
202     /**
203      * Create a shallow clone of this Mesh. The {@link VertexBuffer vertex
204      * buffers} are shared between this and the clone mesh, the rest
205      * of the data is cloned.
206      * 
207      * @return A shallow clone of the mesh
208      */
209     @Override
210     public Mesh clone() {
211         try {
212             Mesh clone = (Mesh) super.clone();
213             clone.meshBound = meshBound.clone();
214             clone.collisionTree = collisionTree != null ? collisionTree : null;
215             clone.buffers = buffers.clone();
216             clone.buffersList = new ArrayList<VertexBuffer>(buffersList);
217             clone.vertexArrayID = -1;
218             if (elementLengths != null) {
219                 clone.elementLengths = elementLengths.clone();
220             }
221             if (modeStart != null) {
222                 clone.modeStart = modeStart.clone();
223             }
224             return clone;
225         } catch (CloneNotSupportedException ex) {
226             throw new AssertionError();
227         }
228     }
229
230     /**
231      * Creates a deep clone of this mesh. 
232      * The {@link VertexBuffer vertex buffers} and the data inside them
233      * is cloned.
234      * 
235      * @return a deep clone of this mesh.
236      */
237     public Mesh deepClone(){
238         try{
239             Mesh clone = (Mesh) super.clone();
240             clone.meshBound = meshBound != null ? meshBound.clone() : null;
241
242             // TODO: Collision tree cloning
243             //clone.collisionTree = collisionTree != null ? collisionTree : null;
244             clone.collisionTree = null; // it will get re-generated in any case
245
246             clone.buffers = new IntMap<VertexBuffer>();
247             clone.buffersList = new ArrayList<VertexBuffer>();
248             for (Entry<VertexBuffer> ent : buffers){
249                 VertexBuffer bufClone = ent.getValue().clone();
250                 clone.buffers.put(ent.getKey(), bufClone);
251                 clone.buffersList.add(bufClone);
252             }
253             
254             clone.vertexArrayID = -1;
255             clone.vertCount = -1;
256             clone.elementCount = -1;
257             
258             // although this could change
259             // if the bone weight/index buffers are modified
260             clone.maxNumWeights = maxNumWeights; 
261             
262             clone.elementLengths = elementLengths != null ? elementLengths.clone() : null;
263             clone.modeStart = modeStart != null ? modeStart.clone() : null;
264             return clone;
265         }catch (CloneNotSupportedException ex){
266             throw new AssertionError();
267         }
268     }
269
270     /**
271      * Clone the mesh for animation use.
272      * This creates a shallow clone of the mesh, sharing most
273      * of the {@link VertexBuffer vertex buffer} data, however the
274      * {@link Type#BindPosePosition} and {@link Type#BindPoseNormal} buffers
275      * are deeply cloned.
276      * 
277      * @return A clone of the mesh for animation use.
278      */
279     public Mesh cloneForAnim(){
280         Mesh clone = clone();
281         if (getBuffer(Type.BindPosePosition) != null){
282             VertexBuffer oldPos = getBuffer(Type.Position);
283             // NOTE: creates deep clone
284             VertexBuffer newPos = oldPos.clone();
285             clone.clearBuffer(Type.Position);
286             clone.setBuffer(newPos);
287
288             if (getBuffer(Type.BindPoseNormal) != null){
289                 VertexBuffer oldNorm = getBuffer(Type.Normal);
290                 VertexBuffer newNorm = oldNorm.clone();
291                 clone.clearBuffer(Type.Normal);
292                 clone.setBuffer(newNorm);
293             }
294         }
295         return clone;
296     }
297
298     /**
299      * Generates the {@link Type#BindPosePosition} and {@link Type#BindPoseNormal}
300      * buffers for this mesh by duplicating them based on the position and normal
301      * buffers already set on the mesh.
302      * This method does nothing if the mesh has no bone weight or index
303      * buffers.
304      * 
305      * @param forSoftwareAnim Should be true if the bind pose is to be generated.
306      */
307     public void generateBindPose(boolean forSoftwareAnim){
308         if (forSoftwareAnim){
309             VertexBuffer pos = getBuffer(Type.Position);
310             if (pos == null || getBuffer(Type.BoneIndex) == null) {
311                 // ignore, this mesh doesn't have positional data
312                 // or it doesn't have bone-vertex assignments, so its not animated
313                 return;
314             }
315
316             VertexBuffer bindPos = new VertexBuffer(Type.BindPosePosition);
317             bindPos.setupData(Usage.CpuOnly,
318                     3,
319                     Format.Float,
320                     BufferUtils.clone(pos.getData()));
321             setBuffer(bindPos);
322
323             // XXX: note that this method also sets stream mode
324             // so that animation is faster. this is not needed for hardware skinning
325             pos.setUsage(Usage.Stream);
326
327             VertexBuffer norm = getBuffer(Type.Normal);
328             if (norm != null) {
329                 VertexBuffer bindNorm = new VertexBuffer(Type.BindPoseNormal);
330                 bindNorm.setupData(Usage.CpuOnly,
331                         3,
332                         Format.Float,
333                         BufferUtils.clone(norm.getData()));
334                 setBuffer(bindNorm);
335                 norm.setUsage(Usage.Stream);
336             }
337         }
338     }
339
340     /**
341      * Prepares the mesh for software skinning by converting the bone index
342      * and weight buffers to heap buffers. 
343      * 
344      * @param forSoftwareAnim Should be true to enable the conversion.
345      */
346     public void prepareForAnim(boolean forSoftwareAnim){
347         if (forSoftwareAnim){
348             // convert indices
349             VertexBuffer indices = getBuffer(Type.BoneIndex);
350             ByteBuffer originalIndex = (ByteBuffer) indices.getData();
351             ByteBuffer arrayIndex = ByteBuffer.allocate(originalIndex.capacity());
352             originalIndex.clear();
353             arrayIndex.put(originalIndex);
354             indices.updateData(arrayIndex);
355
356             // convert weights
357             VertexBuffer weights = getBuffer(Type.BoneWeight);
358             FloatBuffer originalWeight = (FloatBuffer) weights.getData();
359             FloatBuffer arrayWeight = FloatBuffer.allocate(originalWeight.capacity());
360             originalWeight.clear();
361             arrayWeight.put(originalWeight);
362             weights.updateData(arrayWeight);
363         }
364     }
365
366     /**
367      * Set the LOD (level of detail) index buffers on this mesh.
368      * 
369      * @param lodLevels The LOD levels to set
370      */
371     public void setLodLevels(VertexBuffer[] lodLevels){
372         this.lodLevels = lodLevels;
373     }
374
375     /**
376      * @return The number of LOD levels set on this mesh, including the main
377      * index buffer, returns zero if there are no lod levels.
378      */
379     public int getNumLodLevels(){
380         return lodLevels != null ? lodLevels.length : 0;
381     }
382
383     /**
384      * Returns the lod level at the given index.
385      * 
386      * @param lod The lod level index, this does not include
387      * the main index buffer.
388      * @return The LOD index buffer at the index
389      * 
390      * @throws IndexOutOfBoundsException If the index is outside of the 
391      * range [0, {@link #getNumLodLevels()}].
392      * 
393      * @see #setLodLevels(com.jme3.scene.VertexBuffer[]) 
394      */
395     public VertexBuffer getLodLevel(int lod){
396         return lodLevels[lod];
397     }
398     
399     /**
400      * Get the element lengths for {@link Mode#Hybrid} mesh mode.
401      * 
402      * @return element lengths
403      */
404     public int[] getElementLengths() {
405         return elementLengths;
406     }
407
408     /**
409      * Set the element lengths for {@link Mode#Hybrid} mesh mode.
410      * 
411      * @param elementLengths The element lengths to set
412      */
413     public void setElementLengths(int[] elementLengths) {
414         this.elementLengths = elementLengths;
415     }
416
417     /**
418      * Set the mode start indices for {@link Mode#Hybrid} mesh mode.
419      * 
420      * @return mode start indices
421      */
422     public int[] getModeStart() {
423         return modeStart;
424     }
425
426     /**
427      * Get the mode start indices for {@link Mode#Hybrid} mesh mode.
428      * 
429      * @return mode start indices
430      */
431     public void setModeStart(int[] modeStart) {
432         this.modeStart = modeStart;
433     }
434
435     /**
436      * Returns the mesh mode
437      * 
438      * @return the mesh mode
439      * 
440      * @see #setMode(com.jme3.scene.Mesh.Mode) 
441      */
442     public Mode getMode() {
443         return mode;
444     }
445
446     /**
447      * Change the Mesh's mode. By default the mode is {@link Mode#Triangles}.
448      * 
449      * @param mode The new mode to set
450      * 
451      * @see Mode
452      */
453     public void setMode(Mode mode) {
454         this.mode = mode;
455         updateCounts();
456     }
457
458     /**
459      * Returns the maximum number of weights per vertex on this mesh.
460      * 
461      * @return maximum number of weights per vertex
462      * 
463      * @see #setMaxNumWeights(int) 
464      */
465     public int getMaxNumWeights() {
466         return maxNumWeights;
467     }
468
469     /**
470      * Set the maximum number of weights per vertex on this mesh.
471      * Only relevant if this mesh has bone index/weight buffers.
472      * This value should be between 0 and 4.
473      * 
474      * @param maxNumWeights 
475      */
476     public void setMaxNumWeights(int maxNumWeights) {
477         this.maxNumWeights = maxNumWeights;
478     }
479
480     /**
481      * Returns the size of points for point meshes
482      * 
483      * @return the size of points
484      * 
485      * @see #setPointSize(float) 
486      */
487     public float getPointSize() {
488         return pointSize;
489     }
490
491     /**
492      * Set the size of points for meshes of mode {@link Mode#Points}. 
493      * The point size is specified as on-screen pixels, the default
494      * value is 1.0. The point size
495      * does nothing if {@link RenderState#setPointSprite(boolean) point sprite}
496      * render state is enabled, in that case, the vertex shader must specify the 
497      * point size by writing to <code>gl_PointSize</code>.
498      * 
499      * @param pointSize The size of points
500      */
501     public void setPointSize(float pointSize) {
502         this.pointSize = pointSize;
503     }
504
505     /**
506      * Returns the line width for line meshes.
507      * 
508      * @return the line width
509      */
510     public float getLineWidth() {
511         return lineWidth;
512     }
513
514     /**
515      * Specify the line width for meshes of the line modes, such
516      * as {@link Mode#Lines}. The line width is specified as on-screen pixels, 
517      * the default value is 1.0.
518      * 
519      * @param lineWidth The line width
520      */
521     public void setLineWidth(float lineWidth) {
522         this.lineWidth = lineWidth;
523     }
524
525     /**
526      * Indicates to the GPU that this mesh will not be modified (a hint). 
527      * Sets the usage mode to {@link Usage#Static}
528      * for all {@link VertexBuffer vertex buffers} on this Mesh.
529      */
530     public void setStatic() {
531         for (Entry<VertexBuffer> entry : buffers){
532             entry.getValue().setUsage(Usage.Static);
533         }
534     }
535
536     /**
537      * Indicates to the GPU that this mesh will be modified occasionally (a hint).
538      * Sets the usage mode to {@link Usage#Dynamic}
539      * for all {@link VertexBuffer vertex buffers} on this Mesh.
540      */
541     public void setDynamic() {
542         for (Entry<VertexBuffer> entry : buffers){
543             entry.getValue().setUsage(Usage.Dynamic);
544         }
545     }
546
547     /**
548      * Indicates to the GPU that this mesh will be modified every frame (a hint).
549      * Sets the usage mode to {@link Usage#Stream}
550      * for all {@link VertexBuffer vertex buffers} on this Mesh.
551      */
552     public void setStreamed(){
553         for (Entry<VertexBuffer> entry : buffers){
554             entry.getValue().setUsage(Usage.Stream);
555         }
556     }
557
558     /**
559      * Interleaves the data in this mesh. This operation cannot be reversed.
560      * Some GPUs may prefer the data in this format, however it is a good idea
561      * to <em>avoid</em> using this method as it disables some engine features.
562      */
563     public void setInterleaved(){
564         ArrayList<VertexBuffer> vbs = new ArrayList<VertexBuffer>();
565         for (Entry<VertexBuffer> entry : buffers){
566             vbs.add(entry.getValue());
567         }
568 //        ArrayList<VertexBuffer> vbs = new ArrayList<VertexBuffer>(buffers.values());
569         // index buffer not included when interleaving
570         vbs.remove(getBuffer(Type.Index));
571
572         int stride = 0; // aka bytes per vertex
573         for (int i = 0; i < vbs.size(); i++){
574             VertexBuffer vb = vbs.get(i);
575 //            if (vb.getFormat() != Format.Float){
576 //                throw new UnsupportedOperationException("Cannot interleave vertex buffer.\n" +
577 //                                                        "Contains not-float data.");
578 //            }
579             stride += vb.componentsLength;
580             vb.getData().clear(); // reset position & limit (used later)
581         }
582
583         VertexBuffer allData = new VertexBuffer(Type.InterleavedData);
584         ByteBuffer dataBuf = BufferUtils.createByteBuffer(stride * getVertexCount());
585         allData.setupData(Usage.Static, 1, Format.UnsignedByte, dataBuf);
586         
587         // adding buffer directly so that no update counts is forced
588         buffers.put(Type.InterleavedData.ordinal(), allData);
589         buffersList.add(allData);
590
591         for (int vert = 0; vert < getVertexCount(); vert++){
592             for (int i = 0; i < vbs.size(); i++){
593                 VertexBuffer vb = vbs.get(i);
594                 switch (vb.getFormat()){
595                     case Float:
596                         FloatBuffer fb = (FloatBuffer) vb.getData();
597                         for (int comp = 0; comp < vb.components; comp++){
598                             dataBuf.putFloat(fb.get());
599                         }
600                         break;
601                     case Byte:
602                     case UnsignedByte:
603                         ByteBuffer bb = (ByteBuffer) vb.getData();
604                         for (int comp = 0; comp < vb.components; comp++){
605                             dataBuf.put(bb.get());
606                         }
607                         break;
608                     case Half:
609                     case Short:
610                     case UnsignedShort:
611                         ShortBuffer sb = (ShortBuffer) vb.getData();
612                         for (int comp = 0; comp < vb.components; comp++){
613                             dataBuf.putShort(sb.get());
614                         }
615                         break;
616                     case Int:
617                     case UnsignedInt:
618                         IntBuffer ib = (IntBuffer) vb.getData();
619                         for (int comp = 0; comp < vb.components; comp++){
620                             dataBuf.putInt(ib.get());
621                         }
622                         break;
623                     case Double:
624                         DoubleBuffer db = (DoubleBuffer) vb.getData();
625                         for (int comp = 0; comp < vb.components; comp++){
626                             dataBuf.putDouble(db.get());
627                         }
628                         break;
629                 }
630             }
631         }
632
633         int offset = 0;
634         for (VertexBuffer vb : vbs){
635             vb.setOffset(offset);
636             vb.setStride(stride);
637             
638             vb.updateData(null);
639             //vb.setupData(vb.usage, vb.components, vb.format, null);
640             offset += vb.componentsLength;
641         }
642     }
643
644     private int computeNumElements(int bufSize){
645         switch (mode){
646             case Triangles:
647                 return bufSize / 3;
648             case TriangleFan:
649             case TriangleStrip:
650                 return bufSize - 2;
651             case Points:
652                 return bufSize;
653             case Lines:
654                 return bufSize / 2;
655             case LineLoop:
656                 return bufSize;
657             case LineStrip:
658                 return bufSize - 1;
659             default:
660                 throw new UnsupportedOperationException();
661         }
662     }
663
664     /**
665      * Update the {@link #getVertexCount() vertex} and 
666      * {@link #getTriangleCount() triangle} counts for this mesh
667      * based on the current data. This method should be called
668      * after the {@link Buffer#capacity() capacities} of the mesh's
669      * {@link VertexBuffer vertex buffers} has been altered.
670      * 
671      * @throws IllegalStateException If this mesh is in 
672      * {@link #setInterleaved() interleaved} format.
673      */
674     public void updateCounts(){
675         if (getBuffer(Type.InterleavedData) != null)
676             throw new IllegalStateException("Should update counts before interleave");
677
678         VertexBuffer pb = getBuffer(Type.Position);
679         VertexBuffer ib = getBuffer(Type.Index);
680         if (pb != null){
681             vertCount = pb.getData().capacity() / pb.getNumComponents();
682         }
683         if (ib != null){
684             elementCount = computeNumElements(ib.getData().capacity());
685         }else{
686             elementCount = computeNumElements(vertCount);
687         }
688     }
689
690     /**
691      * Returns the triangle count for the given LOD level.
692      * 
693      * @param lod The lod level to look up
694      * @return The triangle count for that LOD level
695      */
696     public int getTriangleCount(int lod){
697         if (lodLevels != null){
698             if (lod < 0)
699                 throw new IllegalArgumentException("LOD level cannot be < 0");
700
701             if (lod >= lodLevels.length)
702                 throw new IllegalArgumentException("LOD level "+lod+" does not exist!");
703
704             return computeNumElements(lodLevels[lod].getData().capacity());
705         }else if (lod == 0){
706             return elementCount;
707         }else{
708             throw new IllegalArgumentException("There are no LOD levels on the mesh!");
709         }
710     }
711
712     /**
713      * Returns how many triangles or elements are on this Mesh.
714      * This value is only updated when {@link #updateCounts() } is called.
715      * If the mesh mode is not a triangle mode, then this returns the 
716      * number of elements/primitives, e.g. how many lines or how many points,
717      * instead of how many triangles.
718      * 
719      * @return how many triangles/elements are on this Mesh.
720      */
721     public int getTriangleCount(){
722         return elementCount;
723     }
724
725     /**
726      * Returns the number of vertices on this mesh.
727      * The value is computed based on the position buffer, which 
728      * must be set on all meshes.
729      * 
730      * @return Number of vertices on the mesh
731      */
732     public int getVertexCount(){
733         return vertCount;
734     }
735
736     /**
737      * Gets the triangle vertex positions at the given triangle index 
738      * and stores them into the v1, v2, v3 arguments.
739      * 
740      * @param index The index of the triangle. 
741      * Should be between 0 and {@link #getTriangleCount()}.
742      * 
743      * @param v1 Vector to contain first vertex position
744      * @param v2 Vector to contain second vertex position
745      * @param v3 Vector to contain third vertex position
746      */
747     public void getTriangle(int index, Vector3f v1, Vector3f v2, Vector3f v3){
748         VertexBuffer pb = getBuffer(Type.Position);
749         IndexBuffer ib = getIndicesAsList();
750         if (pb != null && pb.getFormat() == Format.Float && pb.getNumComponents() == 3){
751             FloatBuffer fpb = (FloatBuffer) pb.getData();
752
753             // aquire triangle's vertex indices
754             int vertIndex = index * 3;
755             int vert1 = ib.get(vertIndex);
756             int vert2 = ib.get(vertIndex+1);
757             int vert3 = ib.get(vertIndex+2);
758
759             BufferUtils.populateFromBuffer(v1, fpb, vert1);
760             BufferUtils.populateFromBuffer(v2, fpb, vert2);
761             BufferUtils.populateFromBuffer(v3, fpb, vert3);
762         }else{
763             throw new UnsupportedOperationException("Position buffer not set or "
764                                                   + " has incompatible format");
765         }
766     }
767     
768     /**
769      * Gets the triangle vertex positions at the given triangle index 
770      * and stores them into the {@link Triangle} argument.
771      * Also sets the triangle index to the <code>index</code> argument.
772      * 
773      * @param index The index of the triangle. 
774      * Should be between 0 and {@link #getTriangleCount()}.
775      * 
776      * @param tri The triangle to store the positions in
777      */
778     public void getTriangle(int index, Triangle tri){
779         getTriangle(index, tri.get1(), tri.get2(), tri.get3());
780         tri.setIndex(index);
781         tri.setNormal(null);
782     }
783
784     /**
785      * Gets the triangle vertex indices at the given triangle index 
786      * and stores them into the given int array.
787      * 
788      * @param index The index of the triangle. 
789      * Should be between 0 and {@link #getTriangleCount()}.
790      * 
791      * @param indices Indices of the triangle's vertices
792      */
793     public void getTriangle(int index, int[] indices){
794         IndexBuffer ib = getIndicesAsList();
795
796         // acquire triangle's vertex indices
797         int vertIndex = index * 3;
798         indices[0] = ib.get(vertIndex);
799         indices[1] = ib.get(vertIndex+1);
800         indices[2] = ib.get(vertIndex+2);
801     }
802
803     /**
804      * Returns the mesh's VAO ID. Internal use only.
805      */
806     public int getId(){
807         return vertexArrayID;
808     }
809
810     /**
811      * Sets the mesh's VAO ID. Internal use only.
812      */
813     public void setId(int id){
814         if (vertexArrayID != -1)
815             throw new IllegalStateException("ID has already been set.");
816         
817         vertexArrayID = id;
818     }
819
820     /**
821      * Generates a collision tree for the mesh.
822      * Called automatically by {@link #collideWith(com.jme3.collision.Collidable, 
823      * com.jme3.math.Matrix4f, 
824      * com.jme3.bounding.BoundingVolume, 
825      * com.jme3.collision.CollisionResults) }.
826      */
827     public void createCollisionData(){
828         BIHTree tree = new BIHTree(this);
829         tree.construct();
830         collisionTree = tree;
831     }
832
833     /**
834      * Handles collision detection, internal use only.
835      * User code should only use collideWith() on scene
836      * graph elements such as {@link Spatial}s.
837      */
838     public int collideWith(Collidable other, 
839                            Matrix4f worldMatrix,
840                            BoundingVolume worldBound,
841                            CollisionResults results){
842
843         if (collisionTree == null){
844             createCollisionData();
845         }
846         
847         return collisionTree.collideWith(other, worldMatrix, worldBound, results);
848     }
849
850     /**
851      * Set a floating point {@link VertexBuffer} on the mesh. 
852      * 
853      * @param type The type of {@link VertexBuffer}, 
854      * e.g. {@link Type#Position}, {@link Type#Normal}, etc.
855      * 
856      * @param components Number of components on the vertex buffer, should
857      * be between 1 and 4.
858      * 
859      * @param buf The floating point data to contain
860      */
861     public void setBuffer(Type type, int components, FloatBuffer buf) {
862 //        VertexBuffer vb = buffers.get(type);
863         VertexBuffer vb = buffers.get(type.ordinal());
864         if (vb == null){
865             if (buf == null)
866                 return;
867
868             vb = new VertexBuffer(type);
869             vb.setupData(Usage.Dynamic, components, Format.Float, buf);
870 //            buffers.put(type, vb);
871             buffers.put(type.ordinal(), vb);
872             buffersList.add(vb);
873         }else{
874             vb.setupData(Usage.Dynamic, components, Format.Float, buf);
875         }
876         updateCounts();
877     }
878
879     public void setBuffer(Type type, int components, float[] buf){
880         setBuffer(type, components, BufferUtils.createFloatBuffer(buf));
881     }
882
883     public void setBuffer(Type type, int components, IntBuffer buf) {
884         VertexBuffer vb = buffers.get(type.ordinal());
885         if (vb == null){
886             vb = new VertexBuffer(type);
887             vb.setupData(Usage.Dynamic, components, Format.UnsignedInt, buf);
888             buffers.put(type.ordinal(), vb);
889             buffersList.add(vb);
890             updateCounts();
891         }
892     }
893
894     public void setBuffer(Type type, int components, int[] buf){
895         setBuffer(type, components, BufferUtils.createIntBuffer(buf));
896     }
897
898     public void setBuffer(Type type, int components, ShortBuffer buf) {
899         VertexBuffer vb = buffers.get(type.ordinal());
900         if (vb == null){
901             vb = new VertexBuffer(type);
902             vb.setupData(Usage.Dynamic, components, Format.UnsignedShort, buf);
903             buffers.put(type.ordinal(), vb);
904             buffersList.add(vb);
905             updateCounts();
906         }
907     }
908
909     public void setBuffer(Type type, int components, byte[] buf){
910         setBuffer(type, components, BufferUtils.createByteBuffer(buf));
911     }
912
913     public void setBuffer(Type type, int components, ByteBuffer buf) {
914         VertexBuffer vb = buffers.get(type.ordinal());
915         if (vb == null){
916             vb = new VertexBuffer(type);
917             vb.setupData(Usage.Dynamic, components, Format.UnsignedByte, buf);
918             buffers.put(type.ordinal(), vb);
919             buffersList.add(vb);
920             updateCounts();
921         }
922     }
923
924     public void setBuffer(VertexBuffer vb){
925 //        if (buffers.containsKey(vb.getBufferType().ordinal()))
926 //            throw new IllegalArgumentException("Buffer type already set: "+vb.getBufferType());
927
928         VertexBuffer vb2 = buffers.put(vb.getBufferType().ordinal(), vb);
929         if (vb2 != null) {
930             buffersList.remove(vb2);
931         }
932         buffersList.add(vb);
933         updateCounts();
934     }
935
936     /**
937      * Clears or unsets the {@link VertexBuffer} set on this mesh
938      * with the given type.
939      * Does nothing if the vertex buffer type is not set initially
940      * 
941      * @param type The type to remove
942      */
943     public void clearBuffer(VertexBuffer.Type type){
944         VertexBuffer vb = buffers.remove(type.ordinal());
945         if (vb != null){
946             buffersList.remove(vb);
947             updateCounts();
948         }
949     }
950
951     public void setBuffer(Type type, int components, short[] buf){
952         setBuffer(type, components, BufferUtils.createShortBuffer(buf));
953     }
954
955     /**
956      * Get the {@link VertexBuffer} stored on this mesh with the given
957      * type.
958      * 
959      * @param type The type of VertexBuffer
960      * @return the VertexBuffer data, or null if not set 
961      */
962     public VertexBuffer getBuffer(Type type){
963         return buffers.get(type.ordinal());
964     }
965
966     /**
967      * Get the {@link VertexBuffer} data stored on this mesh in float
968      * format.
969      * 
970      * @param type The type of VertexBuffer
971      * @return the VertexBuffer data, or null if not set
972      */
973     public FloatBuffer getFloatBuffer(Type type) {
974         VertexBuffer vb = getBuffer(type);
975         if (vb == null)
976             return null;
977
978         return (FloatBuffer) vb.getData();
979     }
980     
981     /**
982      * Get the {@link VertexBuffer} data stored on this mesh in short
983      * format.
984      * 
985      * @param type The type of VertexBuffer
986      * @return the VertexBuffer data, or null if not set
987      */
988     public ShortBuffer getShortBuffer(Type type) {
989         VertexBuffer vb = getBuffer(type);
990         if (vb == null)
991             return null;
992
993         return (ShortBuffer) vb.getData();
994     }
995
996     /**
997      * Acquires an index buffer that will read the vertices on the mesh
998      * as a list.
999      * 
1000      * @param mesh The mesh to read from
1001      * @return A virtual or wrapped index buffer to read the data as a list
1002      */
1003     public IndexBuffer getIndicesAsList(){
1004         if (mode == Mode.Hybrid)
1005             throw new UnsupportedOperationException("Hybrid mode not supported");
1006         
1007         IndexBuffer ib = getIndexBuffer();
1008         if (ib != null){
1009             if (mode.isListMode()){
1010                 // already in list mode
1011                 return ib; 
1012             }else{
1013                 // not in list mode but it does have an index buffer
1014                 // wrap it so the data is converted to list format
1015                 return new WrappedIndexBuffer(this);
1016             }
1017         }else{
1018             // return a virtual index buffer that will supply
1019             // "fake" indices in list format
1020             return new VirtualIndexBuffer(vertCount, mode);
1021         }
1022     }
1023     
1024     /**
1025      * Get the index buffer for this mesh. 
1026      * Will return <code>null</code> if no index buffer is set.
1027      * 
1028      * @return The index buffer of this mesh.
1029      * 
1030      * @see Type#Index
1031      */
1032     public IndexBuffer getIndexBuffer() {
1033         VertexBuffer vb = getBuffer(Type.Index);
1034         if (vb == null)
1035             return null;
1036         
1037         Buffer buf = vb.getData();
1038         if (buf instanceof ByteBuffer) {
1039             return new IndexByteBuffer((ByteBuffer) buf);
1040         } else if (buf instanceof ShortBuffer) {
1041             return new IndexShortBuffer((ShortBuffer) buf);
1042         } else if (buf instanceof IntBuffer) {
1043             return new IndexIntBuffer((IntBuffer) buf);
1044         } else {
1045             throw new UnsupportedOperationException("Index buffer type unsupported: "+ buf.getClass());
1046         }
1047     }
1048
1049     /**
1050      * Scales the texture coordinate buffer on this mesh by the given
1051      * scale factor. 
1052      * <p>
1053      * Note that values above 1 will cause the 
1054      * texture to tile, while values below 1 will cause the texture 
1055      * to stretch.
1056      * </p>
1057      * 
1058      * @param scaleFactor The scale factor to scale by. Every texture
1059      * coordinate is multiplied by this vector to get the result.
1060      * 
1061      * @throws IllegalStateException If there's no texture coordinate
1062      * buffer on the mesh
1063      * @throws UnsupportedOperationException If the texture coordinate
1064      * buffer is not in 2D float format.
1065      */
1066     public void scaleTextureCoordinates(Vector2f scaleFactor){
1067         VertexBuffer tc = getBuffer(Type.TexCoord);
1068         if (tc == null)
1069             throw new IllegalStateException("The mesh has no texture coordinates");
1070
1071         if (tc.getFormat() != VertexBuffer.Format.Float)
1072             throw new UnsupportedOperationException("Only float texture coord format is supported");
1073
1074         if (tc.getNumComponents() != 2)
1075             throw new UnsupportedOperationException("Only 2D texture coords are supported");
1076
1077         FloatBuffer fb = (FloatBuffer) tc.getData();
1078         fb.clear();
1079         for (int i = 0; i < fb.capacity() / 2; i++){
1080             float x = fb.get();
1081             float y = fb.get();
1082             fb.position(fb.position()-2);
1083             x *= scaleFactor.getX();
1084             y *= scaleFactor.getY();
1085             fb.put(x).put(y);
1086         }
1087         fb.clear();
1088         tc.updateData(fb);
1089     }
1090
1091     /**
1092      * Updates the bounding volume of this mesh. 
1093      * The method does nothing if the mesh has no {@link Type#Position} buffer.
1094      * It is expected that the position buffer is a float buffer with 3 components.
1095      */
1096     public void updateBound(){
1097         VertexBuffer posBuf = getBuffer(VertexBuffer.Type.Position);
1098         if (meshBound != null && posBuf != null){
1099             meshBound.computeFromPoints((FloatBuffer)posBuf.getData());
1100         }
1101     }
1102
1103     /**
1104      * Returns the {@link BoundingVolume} of this Mesh.
1105      * By default the bounding volume is a {@link BoundingBox}.
1106      * 
1107      * @return the bounding volume of this mesh
1108      */
1109     public BoundingVolume getBound() {
1110         return meshBound;
1111     }
1112
1113     /**
1114      * Sets the {@link BoundingVolume} for this Mesh.
1115      * The bounding volume is recomputed by calling {@link #updateBound() }.
1116      * 
1117      * @param modelBound The model bound to set
1118      */
1119     public void setBound(BoundingVolume modelBound) {
1120         meshBound = modelBound;
1121     }
1122
1123     /**
1124      * Returns a map of all {@link VertexBuffer vertex buffers} on this Mesh.
1125      * The integer key for the map is the {@link Enum#ordinal() ordinal}
1126      * of the vertex buffer's {@link Type}.
1127      * Note that the returned map is a reference to the map used internally, 
1128      * modifying it will cause undefined results.
1129      * 
1130      * @return map of vertex buffers on this mesh.
1131      */
1132     public IntMap<VertexBuffer> getBuffers(){
1133         return buffers;
1134     }
1135     
1136     public ArrayList<VertexBuffer> getBufferList(){
1137         return buffersList;
1138     }
1139
1140     public void write(JmeExporter ex) throws IOException {
1141         OutputCapsule out = ex.getCapsule(this);
1142
1143 //        HashMap<String, VertexBuffer> map = new HashMap<String, VertexBuffer>();
1144 //        for (Entry<VertexBuffer> buf : buffers){
1145 //            if (buf.getValue() != null)
1146 //                map.put(buf.getKey()+"a", buf.getValue());
1147 //        }
1148 //        out.writeStringSavableMap(map, "buffers", null);
1149
1150         out.write(meshBound, "modelBound", null);
1151         out.write(vertCount, "vertCount", -1);
1152         out.write(elementCount, "elementCount", -1);
1153         out.write(maxNumWeights, "max_num_weights", -1);
1154         out.write(mode, "mode", Mode.Triangles);
1155         out.write(collisionTree, "collisionTree", null);
1156         out.write(elementLengths, "elementLengths", null);
1157         out.write(modeStart, "modeStart", null);
1158         out.write(pointSize, "pointSize", 1f);
1159
1160         out.writeIntSavableMap(buffers, "buffers", null);
1161         out.write(lodLevels, "lodLevels", null);
1162     }
1163
1164     public void read(JmeImporter im) throws IOException {
1165         InputCapsule in = im.getCapsule(this);
1166         meshBound = (BoundingVolume) in.readSavable("modelBound", null);
1167         vertCount = in.readInt("vertCount", -1);
1168         elementCount = in.readInt("elementCount", -1);
1169         maxNumWeights = in.readInt("max_num_weights", -1);
1170         mode = in.readEnum("mode", Mode.class, Mode.Triangles);
1171         elementLengths = in.readIntArray("elementLengths", null);
1172         modeStart = in.readIntArray("modeStart", null);
1173         collisionTree = (BIHTree) in.readSavable("collisionTree", null);
1174         elementLengths = in.readIntArray("elementLengths", null);
1175         modeStart = in.readIntArray("modeStart", null);
1176         pointSize = in.readFloat("pointSize", 1f);
1177
1178 //        in.readStringSavableMap("buffers", null);
1179         buffers = (IntMap<VertexBuffer>) in.readIntSavableMap("buffers", null);
1180         for (Entry<VertexBuffer> entry : buffers){
1181             buffersList.add(entry.getValue());
1182         }
1183         
1184         Savable[] lodLevelsSavable = in.readSavableArray("lodLevels", null);
1185         if (lodLevelsSavable != null) {
1186             lodLevels = new VertexBuffer[lodLevelsSavable.length];
1187             System.arraycopy( lodLevelsSavable, 0, lodLevels, 0, lodLevels.length);
1188         }
1189     }
1190
1191 }