OSDN Git Service

Set optimal mime types and executable settings.
[mikumikustudio/MikuMikuStudio.git] / src / com / jme / scene / TriMesh.java
1 /*
2  * Copyright (c) 2003-2009 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.jme.scene;
34
35 import java.io.IOException;
36 import java.io.Serializable;
37 import java.nio.FloatBuffer;
38 import java.nio.IntBuffer;
39 import java.util.ArrayList;
40 import java.util.logging.Logger;
41
42 import com.jme.bounding.CollisionTree;
43 import com.jme.bounding.CollisionTreeManager;
44 import com.jme.intersection.CollisionResults;
45 import com.jme.math.FastMath;
46 import com.jme.math.Ray;
47 import com.jme.math.Triangle;
48 import com.jme.math.Vector3f;
49 import com.jme.renderer.Renderer;
50 import com.jme.system.JmeException;
51 import com.jme.util.export.InputCapsule;
52 import com.jme.util.export.JMEExporter;
53 import com.jme.util.export.JMEImporter;
54 import com.jme.util.export.OutputCapsule;
55 import com.jme.util.geom.BufferUtils;
56
57 /**
58  * <code>TriMesh</code> defines a geometry mesh. This mesh defines a three
59  * dimensional object via a collection of points, colors, normals and textures.
60  * The points are referenced via a indices array. This array instructs the
61  * renderer the order in which to draw the points, creating triangles based on the mode set.
62  * 
63  * @author Mark Powell
64  * @author Joshua Slack
65  * @version $Id: TriMesh.java,v 1.69 2007/08/02 21:54:36 nca Exp $
66  */
67 public class TriMesh extends Geometry implements Serializable {
68     private static final Logger logger = Logger.getLogger(TriMesh.class
69             .getName());
70
71     private static final long serialVersionUID = 2L;
72
73     public enum Mode {
74         /**
75          * Every three vertices referenced by the indexbuffer will be considered
76          * a stand-alone triangle.
77          */
78         Triangles,
79         /**
80          * The first three vertices referenced by the indexbuffer create a
81          * triangle, from there, every additional vertex is paired with the two
82          * preceding vertices to make a new triangle.
83          */
84         Strip, 
85         /**
86          * The first three vertices (V0, V1, V2) referenced by the indexbuffer
87          * create a triangle, from there, every additional vertex is paired with
88          * the preceding vertex and the initial vertex (V0) to make a new
89          * triangle.
90          */
91         Fan;
92     }
93
94     protected transient IntBuffer indexBuffer;
95     protected Mode mode = Mode.Triangles;
96     protected int triangleQuantity;
97
98     /**
99      * Empty Constructor to be used internally only.
100      */
101     public TriMesh() {
102         super();
103     }
104
105     /**
106      * Constructor instantiates a new <code>TriMesh</code> object.
107      * 
108      * @param name
109      *            the name of the scene element. This is required for
110      *            identification and comparision purposes.
111      */
112     public TriMesh(String name) {
113         super(name);
114     }
115
116     /**
117      * Constructor instantiates a new <code>TriMesh</code> object. Provided
118      * are the attributes that make up the mesh all attributes may be null,
119      * except for vertices and indices.
120      * 
121      * @param name
122      *            the name of the scene element. This is required for
123      *            identification and comparision purposes.
124      * @param vertices
125      *            the vertices of the geometry.
126      * @param normal
127      *            the normals of the geometry.
128      * @param color
129      *            the colors of the geometry.
130      * @param coords
131      *            the texture coordinates of the mesh.
132      * @param indices
133      *            the indices of the vertex array.
134      */
135     public TriMesh(String name, FloatBuffer vertices, FloatBuffer normal,
136             FloatBuffer color, TexCoords coords, IntBuffer indices) {
137
138         super(name);
139
140         reconstruct(vertices, normal, color, coords);
141
142         if (null == indices) {
143             logger.severe("Indices may not be null.");
144             throw new JmeException("Indices may not be null.");
145         }
146         setIndexBuffer(indices);
147         logger.info("TriMesh created.");
148     }
149
150     /**
151      * Recreates the geometric information of this TriMesh from scratch. The
152      * index and vertex array must not be null, but the others may be. Every 3
153      * indices define an index in the <code>vertices</code> array that
154      * refrences a vertex of a triangle.
155      * 
156      * @param vertices
157      *            The vertex information for this TriMesh.
158      * @param normal
159      *            The normal information for this TriMesh.
160      * @param color
161      *            The color information for this TriMesh.
162      * @param coords
163      *            The texture information for this TriMesh.
164      * @param indices
165      *            The index information for this TriMesh.
166      */
167     public void reconstruct(FloatBuffer vertices, FloatBuffer normal,
168             FloatBuffer color, TexCoords coords, IntBuffer indices) {
169         super.reconstruct(vertices, normal, color, coords);
170
171         if (null == indices) {
172             logger.severe("Indices may not be null.");
173             throw new JmeException("Indices may not be null.");
174         }
175         setIndexBuffer(indices);
176     }
177
178     public void setMode(Mode mode) {
179         this.mode = mode;
180     }
181
182     public Mode getMode() {
183         return mode;
184     }
185
186     public IntBuffer getIndexBuffer() {
187         return indexBuffer;
188     }
189
190     public void setIndexBuffer(IntBuffer indices) {
191         this.indexBuffer = indices;
192         recalcTriangleQuantity();
193     }
194
195     protected void recalcTriangleQuantity() {
196         if (indexBuffer == null) {
197             triangleQuantity = 0;
198             return;
199         }
200
201         switch (mode) {
202             case Triangles:
203                 triangleQuantity = indexBuffer.limit() / 3;
204                 break;
205             case Strip:
206             case Fan:
207                 triangleQuantity = indexBuffer.limit() - 2;
208                 break;
209         }
210     }
211
212     /**
213      * Returns the number of triangles contained in this mesh.
214      */
215     @Override
216     public int getTriangleCount() {
217         return triangleQuantity;
218     }
219
220     public void setTriangleQuantity(int triangleQuantity) {
221         this.triangleQuantity = triangleQuantity;
222     }
223
224     /**
225      * <code>draw</code> calls super to set the render state then passes
226      * itself to the renderer. LOGIC: 1. If we're not RenderQueue calling draw
227      * goto 2, if we are, goto 3 2. If we are supposed to use queue, add to
228      * queue and RETURN, else 3 3. call super draw 4. tell renderer to draw me.
229      * 
230      * @param r
231      *            the renderer to display
232      */
233     public void draw(Renderer r) {
234         if (!r.isProcessingQueue()) {
235             if (r.checkAndAdd(this))
236                 return;
237         }
238
239         super.draw(r);
240         r.draw(this);
241     }
242
243     /**
244      * Clears the buffers of this TriMesh. The buffers include its indexBuffer
245      * only.
246      */
247     public void clearBuffers() {
248         super.clearBuffers();
249         setIndexBuffer(null);
250     }
251
252     /**
253      * determines if a collision between this trimesh and a given spatial occurs
254      * if it has true is returned, otherwise false is returned.
255      */
256     public boolean hasCollision(Spatial scene, boolean checkTriangles) {
257         if (this == scene || !isCollidable || !scene.isCollidable()) {
258             return false;
259         }
260         if (getWorldBound().intersects(scene.getWorldBound())) {
261             if (scene instanceof Node) {
262                 Node parent = (Node) scene;
263                 for (int i = 0; i < parent.getQuantity(); i++) {
264                     if (hasCollision(parent.getChild(i), checkTriangles)) {
265                         return true;
266                     }
267                 }
268
269                 return false;
270             }
271
272             if (!checkTriangles) {
273                 return true;
274             }
275
276             return hasTriangleCollision((TriMesh) scene);
277         }
278
279         return false;
280     }
281
282     /**
283      * determines if this TriMesh has made contact with the give scene. The
284      * scene is recursively transversed until a trimesh is found, at which time
285      * the two trimesh OBBTrees are then compared to find the triangles that
286      * hit.
287      */
288     public void findCollisions(Spatial scene, CollisionResults results) {
289         if (this == scene || !isCollidable || !scene.isCollidable()) {
290             return;
291         }
292
293         if (getWorldBound().intersects(scene.getWorldBound())) {
294             if (scene instanceof Node) {
295                 Node parent = (Node) scene;
296                 for (int i = 0; i < parent.getQuantity(); i++) {
297                     findCollisions(parent.getChild(i), results);
298                 }
299             } else {
300                 results.addCollision(this, (Geometry) scene);
301             }
302         }
303     }
304
305     /**
306      * This function checks for intersection between this trimesh and the given
307      * one. On the first intersection, true is returned.
308      * 
309      * @param toCheck
310      *            The intersection testing mesh.
311      * @return True if they intersect.
312      */
313     public boolean hasTriangleCollision(TriMesh toCheck) {
314         CollisionTree thisCT = CollisionTreeManager.getInstance()
315                 .getCollisionTree(this);
316         CollisionTree checkCT = CollisionTreeManager.getInstance()
317                 .getCollisionTree(toCheck);
318
319         if (thisCT == null || checkCT == null || !isCollidable
320                 || !toCheck.isCollidable()) {
321             return false;
322         }
323         thisCT.getBounds().transform(worldRotation, worldTranslation,
324                 worldScale, thisCT.getWorldBounds());
325         return thisCT.intersect(checkCT);
326     }
327
328     /**
329      * This function finds all intersections between this trimesh and the
330      * checking one. The intersections are stored as Integer objects of Triangle
331      * indexes in each of the parameters.
332      * 
333      * @param toCheck
334      *            The TriMesh to check.
335      * @param thisIndex
336      *            The array of triangle indexes intersecting in this mesh.
337      * @param otherIndex
338      *            The array of triangle indexes intersecting in the given mesh.
339      */
340     public void findTriangleCollision(TriMesh toCheck,
341             ArrayList<Integer> thisIndex, ArrayList<Integer> otherIndex) {
342
343         CollisionTree myTree = CollisionTreeManager.getInstance()
344                 .getCollisionTree(this);
345         CollisionTree otherTree = CollisionTreeManager.getInstance()
346                 .getCollisionTree(toCheck);
347
348         if (myTree == null || otherTree == null) {
349             return;
350         }
351
352         myTree.getBounds().transform(worldRotation, worldTranslation,
353                 worldScale, myTree.getWorldBounds());
354         myTree.intersect(otherTree, thisIndex, otherIndex);
355     }
356
357     /**
358      * Stores in the <code>storage</code> array the indices of triangle
359      * <code>i</code>. If <code>i</code> is an invalid index, or if
360      * <code>storage.length<3</code>, then nothing happens
361      * 
362      * @param i
363      *            The index of the triangle to get.
364      * @param storage
365      *            The array that will hold the i's indexes.
366      */
367     public void getTriangle(int i, int[] storage) {
368         if (i < getTriangleCount() && storage.length >= 3) {
369             IntBuffer indices = getIndexBuffer();
370             storage[0] = indices.get(getVertIndex(i, 0));
371             storage[1] = indices.get(getVertIndex(i, 1));
372             storage[2] = indices.get(getVertIndex(i, 2));
373         }
374     }
375
376     /**
377      * Stores in the <code>vertices</code> array the vertex values of triangle
378      * <code>i</code>. If <code>i</code> is an invalid triangle index,
379      * nothing happens.
380      * 
381      * @param i
382      * @param vertices
383      */
384     public void getTriangle(int i, Vector3f[] vertices) {
385         if (vertices == null) {
386             vertices = new Vector3f[3];
387         }
388         if (i < getTriangleCount() && i >= 0) {
389             for (int x = 0; x < 3; x++) {
390                 if (vertices[x] == null) {
391                     vertices[x] = new Vector3f();
392                 }
393
394                 BufferUtils.populateFromBuffer(vertices[x], getVertexBuffer(),
395                         getIndexBuffer().get(getVertIndex(i, x)));
396             }
397         }
398     }
399
400     /**
401      * <code>findTrianglePick</code> determines the triangles of this trimesh
402      * that are being touched by the ray. The indices of the triangles are
403      * stored in the provided ArrayList.
404      * 
405      * @param toTest
406      *            the ray to test. The direction of the ray must be normalized
407      *            (length 1).
408      * @param results
409      *            the indices to the triangles.
410      */
411     public void findTrianglePick(Ray toTest, ArrayList<Integer> results) {
412         if (worldBound == null || !isCollidable) {
413             return;
414         }
415
416         if (worldBound.intersects(toTest)) {
417             CollisionTree ct = CollisionTreeManager.getInstance()
418                     .getCollisionTree(this);
419             if (ct != null) {
420                 ct.getBounds().transform(getWorldRotation(),
421                         getWorldTranslation(), getWorldScale(),
422                         ct.getWorldBounds());
423                 ct.intersect(toTest, results);
424             }
425         }
426     }
427
428     /**
429      * Return this mesh object as triangles. Every 3 vertices returned compose a
430      * single triangle.
431      * 
432      * @param verts
433      *            a storage array to place the results in
434      * @return view of current mesh as group of triangle vertices
435      */
436     public Vector3f[] getMeshAsTrianglesVertices(Vector3f[] verts) {
437         int maxCount = getTriangleCount() * 3;
438         if (verts == null || verts.length != maxCount)
439             verts = new Vector3f[maxCount];
440         getIndexBuffer().rewind();
441         for (int i = 0; i < maxCount; i++) {
442             if (verts[i] == null)
443                 verts[i] = new Vector3f();
444             int index = getVertIndex(i / 3, i % 3);
445             BufferUtils.populateFromBuffer(verts[i], getVertexBuffer(),
446                     getIndexBuffer().get(index));
447         }
448         return verts;
449     }
450
451     protected int getVertIndex(int triangle, int point) {
452         int index = 0, i = (triangle * 3) + point;
453         switch (mode) {
454             case Triangles:
455                 index = i;
456                 break;
457             case Strip:
458                 index = (i / 3) + (i % 3);
459                 break;
460             case Fan:
461                 if (i % 3 == 0)
462                     index = 0;
463                 else {
464                     index = (i % 3);
465                     index = ((i - index) / 3) + index;
466                 }
467                 break;
468         }
469         return index;
470     }
471
472     public int[] getTriangleIndices(int[] indices) {
473         int maxCount = getTriangleCount();
474         if (indices == null || indices.length != maxCount)
475             indices = new int[maxCount];
476
477         for (int i = 0, tLength = maxCount; i < tLength; i++) {
478             indices[i] = i;
479         }
480         return indices;
481     }
482
483     public Triangle[] getMeshAsTriangles(Triangle[] tris) {
484         int maxCount = getTriangleCount();
485         if (tris == null || tris.length != maxCount)
486             tris = new Triangle[maxCount];
487
488         for (int i = 0, tLength = maxCount; i < tLength; i++) {
489             Vector3f vec1 = new Vector3f();
490             Vector3f vec2 = new Vector3f();
491             Vector3f vec3 = new Vector3f();
492
493             Triangle t = tris[i];
494             if (t == null) {
495                 t = new Triangle(getVector(i * 3 + 0, vec1), getVector(
496                         i * 3 + 1, vec2), getVector(i * 3 + 2, vec3));
497                 tris[i] = t;
498             } else {
499                 t.set(0, getVector(i * 3 + 0, vec1));
500                 t.set(1, getVector(i * 3 + 1, vec2));
501                 t.set(2, getVector(i * 3 + 2, vec3));
502             }
503             // t.calculateCenter();
504             t.setIndex(i);
505         }
506         return tris;
507     }
508
509     private Vector3f getVector(int index, Vector3f store) {
510         int vertIndex = getVertIndex(index / 3, index % 3);
511         BufferUtils.populateFromBuffer(store, getVertexBuffer(),
512                 getIndexBuffer().get(vertIndex));
513         return store;
514     }
515
516     public int getMaxIndex() {
517         if (indexBuffer == null)
518             return -1;
519
520         switch (mode) {
521             case Triangles:
522                 return triangleQuantity * 3;
523             case Strip:
524             case Fan:
525                 triangleQuantity = indexBuffer.limit() - 2;
526                 return triangleQuantity + 2;
527         }
528         return -1;
529     }
530
531     /**
532      * Returns a random point on the surface of a randomly selected triangle on
533      * the mesh
534      * 
535      * @param fill
536      *            The resulting selected point
537      * @param work
538      *            Used in calculations to minimize memory creation overhead
539      * @return The resulting selected point
540      */
541     public Vector3f randomPointOnTriangles(Vector3f fill, Vector3f work) {
542         if (getVertexBuffer() == null || getIndexBuffer() == null)
543             return null;
544         int tri = (int) (FastMath.nextRandomFloat() * getTriangleCount());
545         int pntA = getIndexBuffer().get(getVertIndex(tri, 0));
546         int pntB = getIndexBuffer().get(getVertIndex(tri, 1));
547         int pntC = getIndexBuffer().get(getVertIndex(tri, 2));
548
549         float b = FastMath.nextRandomFloat();
550         float c = FastMath.nextRandomFloat();
551
552         if (b + c > 1) {
553             b = 1 - b;
554             c = 1 - c;
555         }
556
557         float a = 1 - b - c;
558
559         if (fill == null)
560             fill = new Vector3f();
561
562         BufferUtils.populateFromBuffer(work, getVertexBuffer(), pntA);
563         work.multLocal(a);
564         fill.set(work);
565
566         BufferUtils.populateFromBuffer(work, getVertexBuffer(), pntB);
567         work.multLocal(b);
568         fill.addLocal(work);
569
570         BufferUtils.populateFromBuffer(work, getVertexBuffer(), pntC);
571         work.multLocal(c);
572         fill.addLocal(work);
573
574         localToWorld(fill, fill);
575
576         return fill;
577     }
578
579     /**
580      * Used with Serialization. Do not call this directly.
581      * 
582      * @param s
583      * @throws IOException
584      * @see java.io.Serializable
585      */
586     private void writeObject(java.io.ObjectOutputStream s) throws IOException {
587         s.defaultWriteObject();
588         if (getIndexBuffer() == null)
589             s.writeInt(0);
590         else {
591             s.writeInt(getIndexBuffer().limit());
592             getIndexBuffer().rewind();
593             for (int x = 0, len = getIndexBuffer().limit(); x < len; x++)
594                 s.writeInt(getIndexBuffer().get());
595         }
596     }
597
598     /**
599      * Used with Serialization. Do not call this directly.
600      * 
601      * @param s
602      * @throws IOException
603      * @throws ClassNotFoundException
604      * @see java.io.Serializable
605      */
606     private void readObject(java.io.ObjectInputStream s) throws IOException,
607             ClassNotFoundException {
608         s.defaultReadObject();
609         int len = s.readInt();
610         if (len == 0) {
611             setIndexBuffer(null);
612         } else {
613             IntBuffer buf = BufferUtils.createIntBuffer(len);
614             for (int x = 0; x < len; x++)
615                 buf.put(s.readInt());
616             setIndexBuffer(buf);
617         }
618     }
619
620     public void write(JMEExporter e) throws IOException {
621         super.write(e);
622         OutputCapsule capsule = e.getCapsule(this);
623         capsule.write(indexBuffer, "indexBuffer", null);
624         capsule.write(mode, "mode", Mode.Triangles);
625     }
626
627     public void read(JMEImporter e) throws IOException {
628         super.read(e);
629         InputCapsule capsule = e.getCapsule(this);
630         indexBuffer = capsule.readIntBuffer("indexBuffer", null);
631         recalcTriangleQuantity();
632         mode = (Mode) capsule.readEnum("mode", Mode.class, Mode.Triangles);
633     }
634 }