159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/*
259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Copyright (c) 2009-2010 jMonkeyEngine
359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * All rights reserved.
459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Redistribution and use in source and binary forms, with or without
659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * modification, are permitted provided that the following conditions are
759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * met:
859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Redistributions of source code must retain the above copyright
1059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   notice, this list of conditions and the following disclaimer.
1159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
1259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Redistributions in binary form must reproduce the above copyright
1359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   notice, this list of conditions and the following disclaimer in the
1459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   documentation and/or other materials provided with the distribution.
1559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
1659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
1759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   may be used to endorse or promote products derived from this software
1859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   without specific prior written permission.
1959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
2059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
2459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
2559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
2859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
2959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */
3259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapackage com.jme3.scene;
3359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.asset.AssetNotFoundException;
3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.bounding.BoundingVolume;
3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.collision.Collidable;
3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.collision.CollisionResults;
3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.export.InputCapsule;
3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.export.JmeExporter;
4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.export.JmeImporter;
4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.export.OutputCapsule;
4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.material.Material;
4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Matrix4f;
4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Transform;
4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.VertexBuffer.Type;
4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.util.TempVars;
4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.io.IOException;
4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.Queue;
4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.logging.Level;
5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.logging.Logger;
5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/**
5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <code>Geometry</code> defines a leaf node of the scene graph. The leaf node
5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * contains the geometric data for rendering objects. It manages all rendering
5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * information such as a {@link Material} object to define how the surface
5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * should be shaded and the {@link Mesh} data to contain the actual geometry.
5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @author Kirill Vainer
5959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */
6059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapublic class Geometry extends Spatial {
6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    // Version #1: removed shared meshes.
6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    // models loaded with shared mesh will be automatically fixed.
6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public static final int SAVABLE_VERSION = 1;
6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private static final Logger logger = Logger.getLogger(Geometry.class.getName());
6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected Mesh mesh;
6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected transient int lodLevel = 0;
6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected Material material;
7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * When true, the geometry's transform will not be applied.
7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected boolean ignoreTransform = false;
7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected transient Matrix4f cachedWorldMat = new Matrix4f();
7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * used when geometry is batched
7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected BatchNode batchNode = null;
7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * the start index of this geom's mesh in the batchNode mesh
8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected int startIndex;
8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * the previous transforms of the geometry used to compute world transforms
8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected Transform prevBatchTransforms = null;
8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * the cached offset matrix used when the geometry is batched
8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected Matrix4f cachedOffsetMat = null;
9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Serialization only. Do not use.
9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public Geometry() {
9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Create a geometry node without any mesh data.
10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Both the mesh and the material are null, the geometry
10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * cannot be rendered until those are set.
10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param name The name of this geometry
10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public Geometry(String name) {
10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        super(name);
10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Create a geometry node with mesh data.
11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * The material of the geometry is null, it cannot
11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * be rendered until it is set.
11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param name The name of this geometry
11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param mesh The mesh data for this geometry
11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public Geometry(String name, Mesh mesh) {
11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this(name);
11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (mesh == null) {
12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            throw new NullPointerException();
12159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
12259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
12359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.mesh = mesh;
12459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
12559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
12659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
12759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @return If ignoreTransform mode is set.
12859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
12959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @see Geometry#setIgnoreTransform(boolean)
13059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
13159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public boolean isIgnoreTransform() {
13259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return ignoreTransform;
13359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
13459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
13559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
13659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param ignoreTransform If true, the geometry's transform will not be applied.
13759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
13859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void setIgnoreTransform(boolean ignoreTransform) {
13959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.ignoreTransform = ignoreTransform;
14059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
14159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
14259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
14359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Sets the LOD level to use when rendering the mesh of this geometry.
14459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Level 0 indicates that the default index buffer should be used,
14559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * levels [1, LodLevels + 1] represent the levels set on the mesh
14659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * with {@link Mesh#setLodLevels(com.jme3.scene.VertexBuffer[]) }.
14759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
14859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param lod The lod level to set
14959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
15059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    @Override
15159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void setLodLevel(int lod) {
15259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (mesh.getNumLodLevels() == 0) {
15359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            throw new IllegalStateException("LOD levels are not set on this mesh");
15459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
15559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
15659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (lod < 0 || lod >= mesh.getNumLodLevels()) {
15759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            throw new IllegalArgumentException("LOD level is out of range: " + lod);
15859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
15959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
16059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        lodLevel = lod;
16159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
16259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
16359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
16459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Returns the LOD level set with {@link #setLodLevel(int) }.
16559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
16659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @return the LOD level set
16759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
16859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public int getLodLevel() {
16959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return lodLevel;
17059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
17159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
17259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
17359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Returns this geometry's mesh vertex count.
17459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
17559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @return this geometry's mesh vertex count.
17659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
17759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @see Mesh#getVertexCount()
17859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
17959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public int getVertexCount() {
18059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return mesh.getVertexCount();
18159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
18259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
18359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
18459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Returns this geometry's mesh triangle count.
18559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
18659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @return this geometry's mesh triangle count.
18759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
18859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @see Mesh#getTriangleCount()
18959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
19059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public int getTriangleCount() {
19159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return mesh.getTriangleCount();
19259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
19359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
19459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
19559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Sets the mesh to use for this geometry when rendering.
19659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
19759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param mesh the mesh to use for this geometry
19859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
19959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @throws IllegalArgumentException If mesh is null
20059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
20159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void setMesh(Mesh mesh) {
20259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (mesh == null) {
20359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            throw new IllegalArgumentException();
20459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
20559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (isBatched()) {
20659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            throw new UnsupportedOperationException("Cannot set the mesh of a batched geometry");
20759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
20859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
20959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.mesh = mesh;
21059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        setBoundRefresh();
21159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
21259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
21359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
21459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Returns the mseh to use for this geometry
21559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
21659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @return the mseh to use for this geometry
21759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
21859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @see #setMesh(com.jme3.scene.Mesh)
21959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
22059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public Mesh getMesh() {
22159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return mesh;
22259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
22359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
22459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
22559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Sets the material to use for this geometry.
22659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
22759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param material the material to use for this geometry
22859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
22959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    @Override
23059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void setMaterial(Material material) {
23159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (isBatched()) {
23259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            throw new UnsupportedOperationException("Cannot set the material of a batched geometry, change the material of the parent BatchNode.");
23359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
23459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.material = material;
23559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
23659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
23759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
23859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Returns the material that is used for this geometry.
23959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
24059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @return the material that is used for this geometry
24159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
24259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @see #setMaterial(com.jme3.material.Material)
24359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
24459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public Material getMaterial() {
24559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return material;
24659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
24759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
24859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
24959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @return The bounding volume of the mesh, in model space.
25059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
25159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public BoundingVolume getModelBound() {
25259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return mesh.getBound();
25359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
25459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
25559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
25659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Updates the bounding volume of the mesh. Should be called when the
25759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * mesh has been modified.
25859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
25959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void updateModelBound() {
26059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        mesh.updateBound();
26159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        setBoundRefresh();
26259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
26359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
26459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
26559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * <code>updateWorldBound</code> updates the bounding volume that contains
26659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * this geometry. The location of the geometry is based on the location of
26759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * all this node's parents.
26859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
26959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @see Spatial#updateWorldBound()
27059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
27159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    @Override
27259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected void updateWorldBound() {
27359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        super.updateWorldBound();
27459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (mesh == null) {
27559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            throw new NullPointerException("Geometry: " + getName() + " has null mesh");
27659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
27759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
27859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (mesh.getBound() != null) {
27959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (ignoreTransform) {
28059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                // we do not transform the model bound by the world transform,
28159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                // just use the model bound as-is
28259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                worldBound = mesh.getBound().clone(worldBound);
28359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            } else {
28459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                worldBound = mesh.getBound().transform(worldTransform, worldBound);
28559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
28659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
28759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
28859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
28959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    @Override
29059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected void updateWorldTransforms() {
29159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
29259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        super.updateWorldTransforms();
29359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        computeWorldMatrix();
29459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
29559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (isBatched()) {
29659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            computeOffsetTransform();
29759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            batchNode.updateSubBatch(this);
29859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            prevBatchTransforms.set(batchNode.getTransforms(this));
29959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
30059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
30159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // geometry requires lights to be sorted
30259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        worldLights.sort(true);
30359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
30459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
30559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
30659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Batch this geometry, should only be called by the BatchNode.
30759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param node the batchNode
30859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param startIndex the starting index of this geometry in the batched mesh
30959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
31059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected void batch(BatchNode node, int startIndex) {
31159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.batchNode = node;
31259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.startIndex = startIndex;
31359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        prevBatchTransforms = new Transform();
31459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        cachedOffsetMat = new Matrix4f();
31559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        setCullHint(CullHint.Always);
31659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
31759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
31859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
31959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * unBatch this geometry.
32059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
32159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected void unBatch() {
32259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.startIndex = 0;
32359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        prevBatchTransforms = null;
32459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        cachedOffsetMat = null;
32559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        //once the geometry is removed from the screnegraph the batchNode needs to be rebatched.
32659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.batchNode.setNeedsFullRebatch(true);
32759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.batchNode = null;
32859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        setCullHint(CullHint.Dynamic);
32959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
33059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
33159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    @Override
33259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public boolean removeFromParent() {
33359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        boolean removed = super.removeFromParent();
33459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        //if the geometry is batched we also have to unbatch it
33559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (isBatched()) {
33659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            unBatch();
33759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
33859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return removed;
33959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
34059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
34159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
34259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Recomputes the cached offset matrix used when the geometry is batched     *
34359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
34459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void computeOffsetTransform() {
34559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        TempVars vars = TempVars.get();
34659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Matrix4f tmpMat = vars.tempMat42;
34759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
34859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // Compute the cached world matrix
34959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        cachedOffsetMat.loadIdentity();
35059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        cachedOffsetMat.setRotationQuaternion(prevBatchTransforms.getRotation());
35159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        cachedOffsetMat.setTranslation(prevBatchTransforms.getTranslation());
35259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
35359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
35459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Matrix4f scaleMat = vars.tempMat4;
35559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        scaleMat.loadIdentity();
35659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        scaleMat.scale(prevBatchTransforms.getScale());
35759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        cachedOffsetMat.multLocal(scaleMat);
35859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        cachedOffsetMat.invertLocal();
35959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
36059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        tmpMat.loadIdentity();
36159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        tmpMat.setRotationQuaternion(batchNode.getTransforms(this).getRotation());
36259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        tmpMat.setTranslation(batchNode.getTransforms(this).getTranslation());
36359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        scaleMat.loadIdentity();
36459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        scaleMat.scale(batchNode.getTransforms(this).getScale());
36559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        tmpMat.multLocal(scaleMat);
36659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
36759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        tmpMat.mult(cachedOffsetMat, cachedOffsetMat);
36859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
36959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        vars.release();
37059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
37159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
37259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
37359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Indicate that the transform of this spatial has changed and that
37459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * a refresh is required.
37559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
37659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    @Override
37759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected void setTransformRefresh() {
37859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        refreshFlags |= RF_TRANSFORM;
37959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        setBoundRefresh();
38059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
38159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
38259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
38359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Recomputes the matrix returned by {@link Geometry#getWorldMatrix() }.
38459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * This will require a localized transform update for this geometry.
38559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
38659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void computeWorldMatrix() {
38759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // Force a local update of the geometry's transform
38859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        checkDoTransformUpdate();
38959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
39059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // Compute the cached world matrix
39159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        cachedWorldMat.loadIdentity();
39259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        cachedWorldMat.setRotationQuaternion(worldTransform.getRotation());
39359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        cachedWorldMat.setTranslation(worldTransform.getTranslation());
39459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
39559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        TempVars vars = TempVars.get();
39659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Matrix4f scaleMat = vars.tempMat4;
39759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        scaleMat.loadIdentity();
39859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        scaleMat.scale(worldTransform.getScale());
39959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        cachedWorldMat.multLocal(scaleMat);
40059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        vars.release();
40159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
40259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
40359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
40459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * A {@link Matrix4f matrix} that transforms the {@link Geometry#getMesh() mesh}
40559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * from model space to world space. This matrix is computed based on the
40659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * {@link Geometry#getWorldTransform() world transform} of this geometry.
40759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * In order to receive updated values, you must call {@link Geometry#computeWorldMatrix() }
40859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * before using this method.
40959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
41059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @return Matrix to transform from local space to world space
41159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
41259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public Matrix4f getWorldMatrix() {
41359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return cachedWorldMat;
41459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
41559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
41659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
41759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Sets the model bound to use for this geometry.
41859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * This alters the bound used on the mesh as well via
41959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * {@link Mesh#setBound(com.jme3.bounding.BoundingVolume) } and
42059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * forces the world bounding volume to be recomputed.
42159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
42259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param modelBound The model bound to set
42359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
42459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    @Override
42559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void setModelBound(BoundingVolume modelBound) {
42659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.worldBound = null;
42759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        mesh.setBound(modelBound);
42859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        setBoundRefresh();
42959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
43059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // NOTE: Calling updateModelBound() would cause the mesh
43159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // to recompute the bound based on the geometry thus making
43259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // this call useless!
43359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        //updateModelBound();
43459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
43559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
43659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public int collideWith(Collidable other, CollisionResults results) {
43759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // Force bound to update
43859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        checkDoBoundUpdate();
43959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // Update transform, and compute cached world matrix
44059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        computeWorldMatrix();
44159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
44259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        assert (refreshFlags & (RF_BOUND | RF_TRANSFORM)) == 0;
44359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
44459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (mesh != null) {
44559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // NOTE: BIHTree in mesh already checks collision with the
44659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // mesh's bound
44759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            int prevSize = results.size();
44859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            int added = mesh.collideWith(other, cachedWorldMat, worldBound, results);
44959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            int newSize = results.size();
45059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            for (int i = prevSize; i < newSize; i++) {
45159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                results.getCollisionDirect(i).setGeometry(this);
45259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
45359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return added;
45459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
45559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return 0;
45659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
45759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
45859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    @Override
45959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void depthFirstTraversal(SceneGraphVisitor visitor) {
46059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        visitor.visit(this);
46159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
46259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
46359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    @Override
46459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected void breadthFirstTraversal(SceneGraphVisitor visitor, Queue<Spatial> queue) {
46559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
46659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
46759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public boolean isBatched() {
46859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return batchNode != null;
46959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
47059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
47159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
47259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * This version of clone is a shallow clone, in other words, the
47359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * same mesh is referenced as the original geometry.
47459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Exception: if the mesh is marked as being a software
47559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * animated mesh, (bind pose is set) then the positions
47659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * and normals are deep copied.
47759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
47859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    @Override
47959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public Geometry clone(boolean cloneMaterial) {
48059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Geometry geomClone = (Geometry) super.clone(cloneMaterial);
48159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        geomClone.cachedWorldMat = cachedWorldMat.clone();
48259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (material != null) {
48359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (cloneMaterial) {
48459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                geomClone.material = material.clone();
48559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            } else {
48659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                geomClone.material = material;
48759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
48859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
48959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
49059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (mesh != null && mesh.getBuffer(Type.BindPosePosition) != null) {
49159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            geomClone.mesh = mesh.cloneForAnim();
49259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
49359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
49459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return geomClone;
49559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
49659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
49759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
49859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * This version of clone is a shallow clone, in other words, the
49959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * same mesh is referenced as the original geometry.
50059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Exception: if the mesh is marked as being a software
50159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * animated mesh, (bind pose is set) then the positions
50259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * and normals are deep copied.
50359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
50459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    @Override
50559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public Geometry clone() {
50659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return clone(true);
50759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
50859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
50959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
51059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Creates a deep clone of the geometry,
51159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * this creates an identical copy of the mesh
51259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * with the vertexbuffer data duplicated.
51359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
51459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    @Override
51559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public Spatial deepClone() {
51659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Geometry geomClone = clone(true);
51759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        geomClone.mesh = mesh.deepClone();
51859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return geomClone;
51959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
52059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
52159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    @Override
52259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void write(JmeExporter ex) throws IOException {
52359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        super.write(ex);
52459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        OutputCapsule oc = ex.getCapsule(this);
52559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        oc.write(mesh, "mesh", null);
52659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (material != null) {
52759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            oc.write(material.getAssetName(), "materialName", null);
52859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
52959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        oc.write(material, "material", null);
53059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        oc.write(ignoreTransform, "ignoreTransform", false);
53159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
53259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
53359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    @Override
53459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void read(JmeImporter im) throws IOException {
53559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        super.read(im);
53659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        InputCapsule ic = im.getCapsule(this);
53759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        mesh = (Mesh) ic.readSavable("mesh", null);
53859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
53959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        material = null;
54059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        String matName = ic.readString("materialName", null);
54159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (matName != null) {
54259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // Material name is set,
54359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // Attempt to load material via J3M
54459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            try {
54559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                material = im.getAssetManager().loadMaterial(matName);
54659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            } catch (AssetNotFoundException ex) {
54759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                // Cannot find J3M file.
54859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                logger.log(Level.FINE, "Cannot locate {0} for geometry {1}", new Object[]{matName, key});
54959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
55059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
55159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // If material is NULL, try to load it from the geometry
55259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (material == null) {
55359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            material = (Material) ic.readSavable("material", null);
55459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
55559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        ignoreTransform = ic.readBoolean("ignoreTransform", false);
55659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
55759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (ic.getSavableVersion(Geometry.class) == 0){
55859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // Fix shared mesh (if set)
55959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            Mesh sharedMesh = getUserData(UserData.JME_SHAREDMESH);
56059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (sharedMesh != null){
56159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                getMesh().extractVertexData(sharedMesh);
56259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
56359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
56459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
56559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta}
566