OSDN Git Service

Add AndroidTGALoader
[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         VertexBuffer pb = getBuffer(Type.Position);
678         VertexBuffer ib = getBuffer(Type.Index);
679         if (pb != null && pb.getData() != null){
680             vertCount = pb.getData().capacity() / pb.getNumComponents();
681         }
682         if (ib != null){
683             elementCount = computeNumElements(ib.getData().capacity());
684         }else{
685             elementCount = computeNumElements(vertCount);
686         }
687     }
688
689     /**
690      * Returns the triangle count for the given LOD level.
691      * 
692      * @param lod The lod level to look up
693      * @return The triangle count for that LOD level
694      */
695     public int getTriangleCount(int lod){
696         if (lodLevels != null){
697             if (lod < 0)
698                 throw new IllegalArgumentException("LOD level cannot be < 0");
699
700             if (lod >= lodLevels.length)
701                 throw new IllegalArgumentException("LOD level "+lod+" does not exist!");
702
703             return computeNumElements(lodLevels[lod].getData().capacity());
704         }else if (lod == 0){
705             return elementCount;
706         }else{
707             throw new IllegalArgumentException("There are no LOD levels on the mesh!");
708         }
709     }
710
711     /**
712      * Returns how many triangles or elements are on this Mesh.
713      * This value is only updated when {@link #updateCounts() } is called.
714      * If the mesh mode is not a triangle mode, then this returns the 
715      * number of elements/primitives, e.g. how many lines or how many points,
716      * instead of how many triangles.
717      * 
718      * @return how many triangles/elements are on this Mesh.
719      */
720     public int getTriangleCount(){
721         return elementCount;
722     }
723
724     /**
725      * Returns the number of vertices on this mesh.
726      * The value is computed based on the position buffer, which 
727      * must be set on all meshes.
728      * 
729      * @return Number of vertices on the mesh
730      */
731     public int getVertexCount(){
732         return vertCount;
733     }
734     public void setVertCount(int vertCount) {
735         this.vertCount = vertCount;
736     }
737     /**
738      * Gets the triangle vertex positions at the given triangle index 
739      * and stores them into the v1, v2, v3 arguments.
740      * 
741      * @param index The index of the triangle. 
742      * Should be between 0 and {@link #getTriangleCount()}.
743      * 
744      * @param v1 Vector to contain first vertex position
745      * @param v2 Vector to contain second vertex position
746      * @param v3 Vector to contain third vertex position
747      */
748     public void getTriangle(int index, Vector3f v1, Vector3f v2, Vector3f v3){
749         VertexBuffer pb = getBuffer(Type.Position);
750         IndexBuffer ib = getIndicesAsList();
751         if (pb != null && pb.getFormat() == Format.Float && pb.getNumComponents() == 3){
752             FloatBuffer fpb = (FloatBuffer) pb.getData();
753
754             // aquire triangle's vertex indices
755             int vertIndex = index * 3;
756             int vert1 = ib.get(vertIndex);
757             int vert2 = ib.get(vertIndex+1);
758             int vert3 = ib.get(vertIndex+2);
759
760             BufferUtils.populateFromBuffer(v1, fpb, vert1);
761             BufferUtils.populateFromBuffer(v2, fpb, vert2);
762             BufferUtils.populateFromBuffer(v3, fpb, vert3);
763         }else{
764             throw new UnsupportedOperationException("Position buffer not set or "
765                                                   + " has incompatible format");
766         }
767     }
768     
769     /**
770      * Gets the triangle vertex positions at the given triangle index 
771      * and stores them into the {@link Triangle} argument.
772      * Also sets the triangle index to the <code>index</code> argument.
773      * 
774      * @param index The index of the triangle. 
775      * Should be between 0 and {@link #getTriangleCount()}.
776      * 
777      * @param tri The triangle to store the positions in
778      */
779     public void getTriangle(int index, Triangle tri){
780         getTriangle(index, tri.get1(), tri.get2(), tri.get3());
781         tri.setIndex(index);
782         tri.setNormal(null);
783     }
784
785     /**
786      * Gets the triangle vertex indices at the given triangle index 
787      * and stores them into the given int array.
788      * 
789      * @param index The index of the triangle. 
790      * Should be between 0 and {@link #getTriangleCount()}.
791      * 
792      * @param indices Indices of the triangle's vertices
793      */
794     public void getTriangle(int index, int[] indices){
795         IndexBuffer ib = getIndicesAsList();
796
797         // acquire triangle's vertex indices
798         int vertIndex = index * 3;
799         indices[0] = ib.get(vertIndex);
800         indices[1] = ib.get(vertIndex+1);
801         indices[2] = ib.get(vertIndex+2);
802     }
803
804     /**
805      * Returns the mesh's VAO ID. Internal use only.
806      */
807     public int getId(){
808         return vertexArrayID;
809     }
810
811     /**
812      * Sets the mesh's VAO ID. Internal use only.
813      */
814     public void setId(int id){
815         if (vertexArrayID != -1)
816             throw new IllegalStateException("ID has already been set.");
817         
818         vertexArrayID = id;
819     }
820
821     /**
822      * Generates a collision tree for the mesh.
823      * Called automatically by {@link #collideWith(com.jme3.collision.Collidable, 
824      * com.jme3.math.Matrix4f, 
825      * com.jme3.bounding.BoundingVolume, 
826      * com.jme3.collision.CollisionResults) }.
827      */
828     public void createCollisionData(){
829         BIHTree tree = new BIHTree(this);
830         tree.construct();
831         collisionTree = tree;
832     }
833
834     /**
835      * Handles collision detection, internal use only.
836      * User code should only use collideWith() on scene
837      * graph elements such as {@link Spatial}s.
838      */
839     public int collideWith(Collidable other, 
840                            Matrix4f worldMatrix,
841                            BoundingVolume worldBound,
842                            CollisionResults results){
843
844         if (collisionTree == null){
845             createCollisionData();
846         }
847         
848         return collisionTree.collideWith(other, worldMatrix, worldBound, results);
849     }
850
851     /**
852      * Set a floating point {@link VertexBuffer} on the mesh. 
853      * 
854      * @param type The type of {@link VertexBuffer}, 
855      * e.g. {@link Type#Position}, {@link Type#Normal}, etc.
856      * 
857      * @param components Number of components on the vertex buffer, should
858      * be between 1 and 4.
859      * 
860      * @param buf The floating point data to contain
861      */
862     public void setBuffer(Type type, int components, FloatBuffer buf) {
863 //        VertexBuffer vb = buffers.get(type);
864         VertexBuffer vb = buffers.get(type.ordinal());
865         if (vb == null){
866             if (buf == null)
867                 return;
868
869             vb = new VertexBuffer(type);
870             vb.setupData(Usage.Dynamic, components, Format.Float, buf);
871 //            buffers.put(type, vb);
872             buffers.put(type.ordinal(), vb);
873             buffersList.add(vb);
874         }else{
875             vb.setupData(Usage.Dynamic, components, Format.Float, buf);
876         }
877         updateCounts();
878     }
879
880     public void setBuffer(Type type, int components, float[] buf){
881         setBuffer(type, components, BufferUtils.createFloatBuffer(buf));
882     }
883
884     public void setBuffer(Type type, int components, IntBuffer buf) {
885         VertexBuffer vb = buffers.get(type.ordinal());
886         if (vb == null){
887             vb = new VertexBuffer(type);
888             vb.setupData(Usage.Dynamic, components, Format.UnsignedInt, buf);
889             buffers.put(type.ordinal(), vb);
890             buffersList.add(vb);
891             updateCounts();
892         }
893     }
894
895     public void setBuffer(Type type, int components, int[] buf){
896         setBuffer(type, components, BufferUtils.createIntBuffer(buf));
897     }
898
899     public void setBuffer(Type type, int components, ShortBuffer buf) {
900         VertexBuffer vb = buffers.get(type.ordinal());
901         if (vb == null){
902             vb = new VertexBuffer(type);
903             vb.setupData(Usage.Dynamic, components, Format.UnsignedShort, buf);
904             buffers.put(type.ordinal(), vb);
905             buffersList.add(vb);
906             updateCounts();
907         }
908     }
909
910     public void setBuffer(Type type, int components, byte[] buf){
911         setBuffer(type, components, BufferUtils.createByteBuffer(buf));
912     }
913
914     public void setBuffer(Type type, int components, ByteBuffer buf) {
915         VertexBuffer vb = buffers.get(type.ordinal());
916         if (vb == null){
917             vb = new VertexBuffer(type);
918             vb.setupData(Usage.Dynamic, components, Format.UnsignedByte, buf);
919             buffers.put(type.ordinal(), vb);
920             buffersList.add(vb);
921             updateCounts();
922         }
923     }
924
925     public void setBuffer(VertexBuffer vb){
926 //        if (buffers.containsKey(vb.getBufferType().ordinal()))
927 //            throw new IllegalArgumentException("Buffer type already set: "+vb.getBufferType());
928
929         VertexBuffer vb2 = buffers.put(vb.getBufferType().ordinal(), vb);
930         if (vb2 != null) {
931             buffersList.remove(vb2);
932         }
933         buffersList.add(vb);
934         updateCounts();
935     }
936
937     /**
938      * Clears or unsets the {@link VertexBuffer} set on this mesh
939      * with the given type.
940      * Does nothing if the vertex buffer type is not set initially
941      * 
942      * @param type The type to remove
943      */
944     public void clearBuffer(VertexBuffer.Type type){
945         VertexBuffer vb = buffers.remove(type.ordinal());
946         if (vb != null){
947             buffersList.remove(vb);
948             updateCounts();
949         }
950     }
951
952     public void setBuffer(Type type, int components, short[] buf){
953         setBuffer(type, components, BufferUtils.createShortBuffer(buf));
954     }
955
956     /**
957      * Get the {@link VertexBuffer} stored on this mesh with the given
958      * type.
959      * 
960      * @param type The type of VertexBuffer
961      * @return the VertexBuffer data, or null if not set 
962      */
963     public VertexBuffer getBuffer(Type type){
964         return buffers.get(type.ordinal());
965     }
966
967     /**
968      * Get the {@link VertexBuffer} data stored on this mesh in float
969      * format.
970      * 
971      * @param type The type of VertexBuffer
972      * @return the VertexBuffer data, or null if not set
973      */
974     public FloatBuffer getFloatBuffer(Type type) {
975         VertexBuffer vb = getBuffer(type);
976         if (vb == null)
977             return null;
978
979         return (FloatBuffer) vb.getData();
980     }
981     
982     /**
983      * Get the {@link VertexBuffer} data stored on this mesh in short
984      * format.
985      * 
986      * @param type The type of VertexBuffer
987      * @return the VertexBuffer data, or null if not set
988      */
989     public ShortBuffer getShortBuffer(Type type) {
990         VertexBuffer vb = getBuffer(type);
991         if (vb == null)
992             return null;
993
994         return (ShortBuffer) vb.getData();
995     }
996
997     /**
998      * Acquires an index buffer that will read the vertices on the mesh
999      * as a list.
1000      * 
1001      * @param mesh The mesh to read from
1002      * @return A virtual or wrapped index buffer to read the data as a list
1003      */
1004     public IndexBuffer getIndicesAsList(){
1005         if (mode == Mode.Hybrid)
1006             throw new UnsupportedOperationException("Hybrid mode not supported");
1007         
1008         IndexBuffer ib = getIndexBuffer();
1009         if (ib != null){
1010             if (mode.isListMode()){
1011                 // already in list mode
1012                 return ib; 
1013             }else{
1014                 // not in list mode but it does have an index buffer
1015                 // wrap it so the data is converted to list format
1016                 return new WrappedIndexBuffer(this);
1017             }
1018         }else{
1019             // return a virtual index buffer that will supply
1020             // "fake" indices in list format
1021             return new VirtualIndexBuffer(vertCount, mode);
1022         }
1023     }
1024     
1025     /**
1026      * Get the index buffer for this mesh. 
1027      * Will return <code>null</code> if no index buffer is set.
1028      * 
1029      * @return The index buffer of this mesh.
1030      * 
1031      * @see Type#Index
1032      */
1033     public IndexBuffer getIndexBuffer() {
1034         VertexBuffer vb = getBuffer(Type.Index);
1035         if (vb == null)
1036             return null;
1037         
1038         Buffer buf = vb.getData();
1039         if (buf instanceof ByteBuffer) {
1040             return new IndexByteBuffer((ByteBuffer) buf);
1041         } else if (buf instanceof ShortBuffer) {
1042             return new IndexShortBuffer((ShortBuffer) buf);
1043         } else if (buf instanceof IntBuffer) {
1044             return new IndexIntBuffer((IntBuffer) buf);
1045         } else {
1046             throw new UnsupportedOperationException("Index buffer type unsupported: "+ buf.getClass());
1047         }
1048     }
1049
1050     /**
1051      * Scales the texture coordinate buffer on this mesh by the given
1052      * scale factor. 
1053      * <p>
1054      * Note that values above 1 will cause the 
1055      * texture to tile, while values below 1 will cause the texture 
1056      * to stretch.
1057      * </p>
1058      * 
1059      * @param scaleFactor The scale factor to scale by. Every texture
1060      * coordinate is multiplied by this vector to get the result.
1061      * 
1062      * @throws IllegalStateException If there's no texture coordinate
1063      * buffer on the mesh
1064      * @throws UnsupportedOperationException If the texture coordinate
1065      * buffer is not in 2D float format.
1066      */
1067     public void scaleTextureCoordinates(Vector2f scaleFactor){
1068         VertexBuffer tc = getBuffer(Type.TexCoord);
1069         if (tc == null)
1070             throw new IllegalStateException("The mesh has no texture coordinates");
1071
1072         if (tc.getFormat() != VertexBuffer.Format.Float)
1073             throw new UnsupportedOperationException("Only float texture coord format is supported");
1074
1075         if (tc.getNumComponents() != 2)
1076             throw new UnsupportedOperationException("Only 2D texture coords are supported");
1077
1078         FloatBuffer fb = (FloatBuffer) tc.getData();
1079         fb.clear();
1080         for (int i = 0; i < fb.capacity() / 2; i++){
1081             float x = fb.get();
1082             float y = fb.get();
1083             fb.position(fb.position()-2);
1084             x *= scaleFactor.getX();
1085             y *= scaleFactor.getY();
1086             fb.put(x).put(y);
1087         }
1088         fb.clear();
1089         tc.updateData(fb);
1090     }
1091
1092     /**
1093      * Updates the bounding volume of this mesh. 
1094      * The method does nothing if the mesh has no {@link Type#Position} buffer.
1095      * It is expected that the position buffer is a float buffer with 3 components.
1096      */
1097     public void updateBound(){
1098         VertexBuffer posBuf = getBuffer(VertexBuffer.Type.Position);
1099         if (meshBound != null && posBuf != null){
1100             meshBound.computeFromPoints((FloatBuffer)posBuf.getData());
1101         }
1102     }
1103
1104     /**
1105      * Returns the {@link BoundingVolume} of this Mesh.
1106      * By default the bounding volume is a {@link BoundingBox}.
1107      * 
1108      * @return the bounding volume of this mesh
1109      */
1110     public BoundingVolume getBound() {
1111         return meshBound;
1112     }
1113
1114     /**
1115      * Sets the {@link BoundingVolume} for this Mesh.
1116      * The bounding volume is recomputed by calling {@link #updateBound() }.
1117      * 
1118      * @param modelBound The model bound to set
1119      */
1120     public void setBound(BoundingVolume modelBound) {
1121         meshBound = modelBound;
1122     }
1123
1124     /**
1125      * Returns a map of all {@link VertexBuffer vertex buffers} on this Mesh.
1126      * The integer key for the map is the {@link Enum#ordinal() ordinal}
1127      * of the vertex buffer's {@link Type}.
1128      * Note that the returned map is a reference to the map used internally, 
1129      * modifying it will cause undefined results.
1130      * 
1131      * @return map of vertex buffers on this mesh.
1132      */
1133     public IntMap<VertexBuffer> getBuffers(){
1134         return buffers;
1135     }
1136     
1137     public ArrayList<VertexBuffer> getBufferList(){
1138         return buffersList;
1139     }
1140
1141     public void write(JmeExporter ex) throws IOException {
1142         OutputCapsule out = ex.getCapsule(this);
1143
1144 //        HashMap<String, VertexBuffer> map = new HashMap<String, VertexBuffer>();
1145 //        for (Entry<VertexBuffer> buf : buffers){
1146 //            if (buf.getValue() != null)
1147 //                map.put(buf.getKey()+"a", buf.getValue());
1148 //        }
1149 //        out.writeStringSavableMap(map, "buffers", null);
1150
1151         out.write(meshBound, "modelBound", null);
1152         out.write(vertCount, "vertCount", -1);
1153         out.write(elementCount, "elementCount", -1);
1154         out.write(maxNumWeights, "max_num_weights", -1);
1155         out.write(mode, "mode", Mode.Triangles);
1156         out.write(collisionTree, "collisionTree", null);
1157         out.write(elementLengths, "elementLengths", null);
1158         out.write(modeStart, "modeStart", null);
1159         out.write(pointSize, "pointSize", 1f);
1160
1161         out.writeIntSavableMap(buffers, "buffers", null);
1162         out.write(lodLevels, "lodLevels", null);
1163     }
1164
1165     public void read(JmeImporter im) throws IOException {
1166         InputCapsule in = im.getCapsule(this);
1167         meshBound = (BoundingVolume) in.readSavable("modelBound", null);
1168         vertCount = in.readInt("vertCount", -1);
1169         elementCount = in.readInt("elementCount", -1);
1170         maxNumWeights = in.readInt("max_num_weights", -1);
1171         mode = in.readEnum("mode", Mode.class, Mode.Triangles);
1172         elementLengths = in.readIntArray("elementLengths", null);
1173         modeStart = in.readIntArray("modeStart", null);
1174         collisionTree = (BIHTree) in.readSavable("collisionTree", null);
1175         elementLengths = in.readIntArray("elementLengths", null);
1176         modeStart = in.readIntArray("modeStart", null);
1177         pointSize = in.readFloat("pointSize", 1f);
1178
1179 //        in.readStringSavableMap("buffers", null);
1180         buffers = (IntMap<VertexBuffer>) in.readIntSavableMap("buffers", null);
1181         for (Entry<VertexBuffer> entry : buffers){
1182             buffersList.add(entry.getValue());
1183         }
1184         
1185         Savable[] lodLevelsSavable = in.readSavableArray("lodLevels", null);
1186         if (lodLevelsSavable != null) {
1187             lodLevels = new VertexBuffer[lodLevelsSavable.length];
1188             System.arraycopy( lodLevelsSavable, 0, lodLevels, 0, lodLevels.length);
1189         }
1190     }
1191
1192 }