2 * Copyright (c) 2003-2009 jMonkeyEngine
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
33 package com.jme.scene;
35 import java.io.IOException;
36 import java.nio.FloatBuffer;
37 import java.nio.IntBuffer;
38 import java.util.ArrayList;
39 import java.util.logging.Logger;
41 import com.jme.bounding.BoundingVolume;
42 import com.jme.math.Ray;
43 import com.jme.math.Vector3f;
44 import com.jme.renderer.ColorRGBA;
45 import com.jme.renderer.Renderer;
46 import com.jme.scene.state.RenderState;
47 import com.jme.util.export.InputCapsule;
48 import com.jme.util.export.JMEExporter;
49 import com.jme.util.export.JMEImporter;
50 import com.jme.util.export.OutputCapsule;
53 * <code>SharedMesh</code> allows the sharing of data between multiple nodes.
54 * A provided TriMesh is used as the model for this node. This allows the user
55 * to place multiple copies of the same object throughout the scene without
56 * having to duplicate data. It should be known that any change to the provided
57 * target mesh will affect the appearance of this mesh, including animations.
58 * Secondly, the SharedMesh is read only. Any attempt to write to the mesh data
59 * via set* methods, will result in a warning being logged and nothing else. Any
60 * changes to the mesh should happened to the target mesh being shared. <br>
61 * If you plan to use collisions with a <code>SharedMesh</code> it is
62 * recommended that you disable the passing of <code>updateCollisionTree</code>
63 * calls to the target mesh. This is to prevent multiple calls to the target's
64 * <code>updateCollisionTree</code> method, from different shared meshes.
65 * Instead of this method being called from the scenegraph, you can now invoke
66 * it directly on the target mesh, thus ensuring it will only be invoked once.
68 * <b>Important:</b> It is highly recommended that the Target mesh is NOT
69 * placed into the scenegraph, as its translation, rotation and scale are
70 * replaced by the shared meshes using it before they are rendered. <br>
71 * <b>Note:</b> Special thanks to Kevin Glass.
76 public class SharedMesh extends TriMesh {
77 private static final Logger logger = Logger.getLogger(SharedMesh.class
80 private static final long serialVersionUID = 1L;
82 private TriMesh target;
90 * Constructor creates a new <code>SharedMesh</code> object. Uses the name
94 * the TriMesh to share the data.
96 public SharedMesh(TriMesh target) {
97 this(target.getName(), target);
101 * Constructor creates a new <code>SharedMesh</code> object.
104 * the name of this shared mesh.
106 * the TriMesh to share the data.
108 public SharedMesh(String name, TriMesh target) {
113 if (target instanceof SharedMesh) {
114 setTarget(((SharedMesh) target).getTarget());
115 this.setName(target.getName());
116 this.setCullHint(target.cullHint);
117 this.setLightCombineMode(target.lightCombineMode);
118 this.getLocalRotation().set(target.getLocalRotation());
119 this.getLocalScale().set(target.getLocalScale());
120 this.getLocalTranslation().set(target.getLocalTranslation());
121 this.setRenderQueueMode(target.renderQueueMode);
122 this.setTextureCombineMode(target.textureCombineMode);
123 this.setZOrder(target.getZOrder());
124 for (RenderState.StateType type : RenderState.StateType.values()) {
125 RenderState state = target.getRenderState( type );
127 this.setRenderState(state );
134 this.localRotation.set(target.getLocalRotation());
135 this.localScale.set(target.getLocalScale());
136 this.localTranslation.set(target.getLocalTranslation());
140 * <code>setTarget</code> sets the shared data mesh.
143 * the TriMesh to share the data.
145 public void setTarget(TriMesh target) {
146 this.target = target;
147 UserDataManager.getInstance().bind(this, target);
148 for (RenderState.StateType type : RenderState.StateType.values()) {
149 RenderState state = this.target.getRenderState( type );
151 setRenderState(state);
155 setCullHint(target.getLocalCullHint());
156 setLightCombineMode(target.getLocalLightCombineMode());
157 setRenderQueueMode(target.getLocalRenderQueueMode());
158 setTextureCombineMode(target.getLocalTextureCombineMode());
159 setZOrder(target.getZOrder());
163 * <code>getTarget</code> returns the mesh that is being shared by this
166 * @return the mesh being shared.
168 public TriMesh getTarget() {
173 * <code>reconstruct</code> is not supported in SharedMesh.
176 * the new vertices to use.
178 * the new normals to use.
180 * the new colors to use.
181 * @param textureCoords
182 * the new texture coordinates to use (position 0).
185 public void reconstruct(FloatBuffer vertices, FloatBuffer normals,
186 FloatBuffer colors, TexCoords textureCoords) {
187 logger.info("SharedMesh will ignore reconstruct.");
191 * <code>setVBOInfo</code> is not supported in SharedMesh.
194 public void setVBOInfo(VBOInfo info) {
195 logger.warning("SharedMesh does not allow the manipulation"
196 + "of the the mesh data.");
200 * <code>getVBOInfo</code> returns the target mesh's vbo info.
203 public VBOInfo getVBOInfo() {
204 return target.getVBOInfo();
208 * <code>setSolidColor</code> is not supported by SharedMesh.
214 public void setSolidColor(ColorRGBA color) {
215 logger.warning("SharedMesh does not allow the manipulation"
216 + "of the the mesh data.");
220 * <code>setRandomColors</code> is not supported by SharedMesh.
223 public void setRandomColors() {
224 logger.warning("SharedMesh does not allow the manipulation"
225 + "of the the mesh data.");
229 * <code>getVertexBuffer</code> returns the float buffer that contains the
230 * target geometry's vertex information.
232 * @return the float buffer that contains the target geometry's vertex
236 public FloatBuffer getVertexBuffer() {
237 return target.getVertexBuffer();
241 * <code>setVertexBuffer</code> is not supported by SharedMesh.
244 * the new vertex buffer.
247 public void setVertexBuffer(FloatBuffer buff) {
248 logger.warning("SharedMesh does not allow the manipulation"
249 + "of the the mesh data.");
253 * Returns the number of vertexes defined in the target's Geometry object.
255 * @return The number of vertexes in the target Geometry object.
258 public int getVertexCount() {
259 return target.getVertexCount();
263 * <code>getNormalBuffer</code> retrieves the target geometry's normal
264 * information as a float buffer.
266 * @return the float buffer containing the target geometry information.
269 public FloatBuffer getNormalBuffer() {
270 return target.getNormalBuffer();
274 * <code>setNormalBuffer</code> is not supported by SharedMesh.
277 * the new normal buffer.
280 public void setNormalBuffer(FloatBuffer buff) {
281 logger.warning("SharedMesh does not allow the manipulation"
282 + "of the the mesh data.");
286 * <code>getColorBuffer</code> retrieves the float buffer that contains
287 * the target geometry's color information.
289 * @return the buffer that contains the target geometry's color information.
292 public FloatBuffer getColorBuffer() {
293 return target.getColorBuffer();
297 * <code>setColorBuffer</code> is not supported by SharedMesh.
300 * the new color buffer.
303 public void setColorBuffer(FloatBuffer buff) {
304 logger.warning("SharedMesh does not allow the manipulation"
305 + "of the the mesh data.");
309 * <code>getIndexAsBuffer</code> retrieves the target's indices array as
310 * an <code>IntBuffer</code>.
312 * @return the indices array as an <code>IntBuffer</code>.
315 public IntBuffer getIndexBuffer() {
316 return target.getIndexBuffer();
320 * <code>setIndexBuffer</code> is not supported by SharedMesh.
323 * the index array as an IntBuffer.
326 public void setIndexBuffer(IntBuffer indices) {
327 logger.warning("SharedMesh does not allow the manipulation"
328 + "of the the mesh data.");
332 * Stores in the <code>storage</code> array the indices of triangle
333 * <code>i</code>. If <code>i</code> is an invalid index, or if
334 * <code>storage.length<3</code>, then nothing happens
337 * The index of the triangle to get.
339 * The array that will hold the i's indexes.
342 public void getTriangle(int i, int[] storage) {
343 target.getTriangle(i, storage);
347 * Stores in the <code>vertices</code> array the vertex values of triangle
348 * <code>i</code>. If <code>i</code> is an invalid triangle index,
355 public void getTriangle(int i, Vector3f[] vertices) {
356 target.getTriangle(i, vertices);
360 * Returns the number of triangles the target TriMesh contains.
362 * @return The current number of triangles.
365 public int getTriangleCount() {
366 return target.getTriangleCount();
370 * <code>copyTextureCoords</code> is not supported by SharedMesh.
373 * the coordinates to copy.
375 * the texture unit to set them to.
378 public void copyTextureCoordinates(int fromIndex, int toIndex, float factor) {
379 logger.warning("SharedMesh does not allow the manipulation"
380 + "of the the mesh data.");
384 * <code>getTextureBuffers</code> retrieves the target geometry's texture
385 * information contained within a float buffer array.
387 * @return the float buffers that contain the target geometry's texture
391 public ArrayList<TexCoords> getTextureCoords() {
392 return target.getTextureCoords();
396 * <code>getTextureAsFloatBuffer</code> retrieves the texture buffer of a
397 * given texture unit.
400 * the texture unit to check.
401 * @return the texture coordinates at the given texture unit.
404 public TexCoords getTextureCoords(int textureUnit) {
405 return target.getTextureCoords(textureUnit);
409 * retrieves the mesh as triangle vertices of the target mesh.
412 public Vector3f[] getMeshAsTrianglesVertices(Vector3f[] verts) {
413 return target.getMeshAsTrianglesVertices(verts);
417 * clearBuffers is not supported by SharedMesh
420 public void clearBuffers() {
421 logger.warning("SharedMesh does not allow the manipulation"
422 + "of the the mesh data.");
426 * This function checks for intersection between the target trimesh and the
427 * given one. On the first intersection, true is returned.
430 * The intersection testing mesh.
431 * @return True if they intersect.
434 public boolean hasTriangleCollision(TriMesh toCheck) {
435 target.setLocalTranslation(worldTranslation);
436 target.setLocalRotation(worldRotation);
437 target.setLocalScale(worldScale);
438 target.updateWorldBound();
439 return target.hasTriangleCollision(toCheck);
443 * This function finds all intersections between this trimesh and the
444 * checking one. The intersections are stored as Integer objects of Triangle
445 * indexes in each of the parameters.
448 * The TriMesh to check.
450 * The array of triangle indexes intersecting in this mesh.
452 * The array of triangle indexes intersecting in the given mesh.
455 public void findTriangleCollision(TriMesh toCheck,
456 ArrayList<Integer> thisIndex, ArrayList<Integer> otherIndex) {
457 target.setLocalTranslation(worldTranslation);
458 target.setLocalRotation(worldRotation);
459 target.setLocalScale(worldScale);
460 target.updateWorldBound();
461 target.findTriangleCollision(toCheck, thisIndex, otherIndex);
465 * <code>findTrianglePick</code> determines the triangles of the target
466 * trimesh that are being touched by the ray. The indices of the triangles
467 * are stored in the provided ArrayList.
472 * the indices to the triangles.
475 public void findTrianglePick(Ray toTest, ArrayList<Integer> results) {
476 target.setLocalTranslation(worldTranslation);
477 target.setLocalRotation(worldRotation);
478 target.setLocalScale(worldScale);
479 target.updateWorldBound();
480 target.findTrianglePick(toTest, results);
484 public void write(JMEExporter e) throws IOException {
485 OutputCapsule capsule = e.getCapsule(this);
486 capsule.write(target, "target", null);
491 public void read(JMEImporter e) throws IOException {
492 InputCapsule capsule = e.getCapsule(this);
493 target = (TriMesh) capsule.readSavable("target", null);
498 * @see Geometry#randomVertex(Vector3f)
501 public Vector3f randomVertex(Vector3f fill) {
502 return target.randomVertex(fill);
506 * <code>setTextureBuffer</code> is not supported by SharedMesh.
509 * the new vertex buffer.
512 public void setTextureCoords(TexCoords buff) {
513 logger.warning("SharedMesh does not allow the manipulation"
514 + "of the the mesh data.");
518 * <code>setTextureBuffer</code> not supported by SharedMesh
521 * the new vertex buffer.
524 public void setTextureCoords(TexCoords buff, int position) {
525 logger.warning("SharedMesh does not allow the manipulation"
526 + "of the the mesh data.");
530 public void setTangentBuffer(FloatBuffer tangentBuf) {
531 logger.warning("SharedMesh does not allow the manipulation"
532 + "of the the mesh data.");
536 public FloatBuffer getTangentBuffer() {
537 return target.getTangentBuffer();
541 public void setBinormalBuffer(FloatBuffer binormalBuf) {
542 logger.warning("SharedMesh does not allow the manipulation"
543 + "of the the mesh data.");
547 public FloatBuffer getBinormalBuffer() {
548 return target.getBinormalBuffer();
552 * <code>updateWorldBound</code> updates the bounding volume that contains
553 * this geometry. The location of the geometry is based on the location of
554 * all this node's parents.
556 * @see com.jme.scene.Spatial#updateWorldBound()
559 public void updateWorldBound() {
560 if (target.getModelBound() != null) {
561 worldBound = target.getModelBound().transform(getWorldRotation(),
562 getWorldTranslation(), getWorldScale(), worldBound);
567 * <code>setModelBound</code> sets the bounding object for this geometry.
570 * the bounding object for this geometry.
573 public void setModelBound(BoundingVolume modelBound) {
574 target.setModelBound(modelBound);
578 * <code>updateBound</code> recalculates the bounding object assigned to
579 * the geometry. This resets it parameters to adjust for any changes to the
580 * vertex information.
583 public void updateModelBound() {
584 if (target.getModelBound() != null) {
585 target.updateModelBound();
591 * returns the model bound of the target object.
594 public BoundingVolume getModelBound() {
595 return target.getModelBound();
599 * draw renders the target mesh, at the translation, rotation and scale of
602 * @see com.jme.scene.Spatial#draw(com.jme.renderer.Renderer)
605 public void draw(Renderer r) {
606 if (!r.isProcessingQueue()) {
607 if (r.checkAndAdd(this))
611 target.getWorldTranslation().set(getWorldTranslation());
612 target.getWorldRotation().set(getWorldRotation());
613 target.getWorldScale().set(getWorldScale());
614 target.setDefaultColor(getDefaultColor());
615 System.arraycopy(this.states, 0, target.states, 0, states.length);
621 public void lockMeshes(Renderer r) {
622 target.lockMeshes(r);
626 public boolean hasDirtyVertices() {
627 return target.hasDirtyVertices;
631 public ColorRGBA getDefaultColor() {
632 if (defaultColor == null) {
633 return target.getDefaultColor();