All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javax.media.j3d.MorphRetained Maven / Gradle / Ivy

/*
 * Copyright 1997-2008 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 *
 */

package javax.media.j3d;

import java.util.ArrayList;

import javax.vecmath.Color3b;
import javax.vecmath.Color3f;
import javax.vecmath.Color4b;
import javax.vecmath.Color4f;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.TexCoord2f;
import javax.vecmath.TexCoord3f;
import javax.vecmath.Vector3f;

/**
 * A morph leaf node consisting of geometery and appearance properties.
 */

class MorphRetained extends LeafRetained implements GeometryUpdater {

    // These bits should match the Shape3D bits ...(Since the mirrors for
    // both are Shape3DRetained
    static final int GEOMETRY_CHANGED		= 0x00001;
    static final int APPEARANCE_CHANGED		= 0x00002;
    static final int COLLISION_CHANGED		= 0x00004;
    static final int BOUNDS_CHANGED		= 0x00008;
    static final int APPEARANCEOVERRIDE_CHANGED	= 0x00010;
    static final int UPDATE_MORPH		= 0x00020;

    private static final double TOLERANCE = 1.0e-4;


    /**
     * The mirror Shape3DRetained nodes for this object.  There is one
     * mirror for each instance of this Shape3D node.  If it is not in
     * a SharedGroup, only index 0 is valid.
     */
    ArrayList mirrorShape3D = new ArrayList();


    // Target threads to be notified when morph changes
    final static int targetThreads = (J3dThread.UPDATE_RENDER |
				      J3dThread.UPDATE_GEOMETRY);

    /**
     * The appearance component of the morph node.
     */
    AppearanceRetained appearance = null;

    /**
     * The Geosets associated with the morph node.
     */
    GeometryArrayRetained geometryArrays[];

    private int numGeometryArrays = 0;

    /**
     * The weight vector the morph node.
     */
    double weights[];

    /**
     * Reference to the  BranchGroup path of this mirror shape
     * This is used for picking only.
     */
    BranchGroupRetained branchGroupPath[];


    // cache value for picking in mirror shape.
    // True if all the node of the path from this to root are all pickable
    boolean isPickable = true;


    // cache value for collidable in mirror shape.
    // True if all the node of the path from this to root are all collidable
    boolean isCollidable = true;


    // closest switch parent
    SwitchRetained  closestSwitchParent = null;

    // the child index from the closest switch parent
    int closestSwitchIndex = -1;

    // Is this Morph visible ? The default is true.
    boolean visible = true;

    // geometry Bounds in local coordinate
    Bounds bounds = null;

    // geometry Bounds in virtual world coordinate
    BoundingBox vwcBounds = new BoundingBox();

    // collision Bound in local coordinate
    Bounds collisionBound = null;

    // collision Bounds in virtual world coordinate
    Bounds collisionVwcBound = null;


    GeometryArray morphedGeometryArray = null;

    // Morph data
    float[] Mcoord = null;
    float[] Mcolor = null;
    float[] Mnormal = null;
    // First dimension is the coordSet, second dimenension is the vertex index
    // each vertex has 2 or 3floats
    float[][]MtexCoord = null;

    // Whether the normal appearance is overrided by the alternate app
    boolean appearanceOverrideEnable = false;

    int changedFrequent = 0;


    MorphRetained() {
        this.nodeType = NodeRetained.MORPH;
	localBounds = new BoundingBox((Bounds)null);
    }

    /**
     * Sets the collision bounds of a node.
     * @param bounds the bounding object for the node
     */
    void setCollisionBounds(Bounds bounds) {
        if (bounds != null) {
	    collisionBound = (Bounds)bounds.clone();
	} else {
            collisionBound = null;
	}
	if (source.isLive()) {
	    // Notify Geometry Structure to set mirror shape collision
	    // bound and check for collision
	    J3dMessage message = new J3dMessage();
	    message.type = J3dMessage.COLLISION_BOUND_CHANGED;
            message.threads = J3dThread.UPDATE_TRANSFORM;
	    message.universe = universe;
            message.args[1] = collisionBound;
	    VirtualUniverse.mc.processMessage(message);
	}
    }

    /**
     * Sets the geometric bounds of a node.
     * @param bounds the bounding object for the node
     */
    @Override
    void setBounds(Bounds bounds) {
	super.setBounds(bounds);
	if (source.isLive() && !boundsAutoCompute) {
	    J3dMessage message = new J3dMessage();
	    message.type = J3dMessage.REGION_BOUND_CHANGED;
	    message.threads = J3dThread.UPDATE_TRANSFORM |
		              targetThreads;
	    message.universe = universe;
	    message.args[0] = Shape3DRetained.getGeomAtomsArray(mirrorShape3D);
	    message.args[1] = localBounds;
	    VirtualUniverse.mc.processMessage(message);
	}
    }

    /**
     * Gets the collision bounds of a node.
     * @return the node's bounding object
     */
    Bounds getCollisionBounds() {
        return (collisionBound == null? null : (Bounds)collisionBound.clone());
    }

    /**
     * Sets the geometryArrays component of the Morph node.
     * @param geometryArrays the new vector of geometryArrays for the morph node
     */
    void setGeometryArrays(GeometryArray geometryArrays[]) {
        int i;

	if ((geometryArrays == null || geometryArrays.length == 0) && numGeometryArrays == 0)
	    return;

        GeometryArrayRetained geo, prevGeo;

        if (numGeometryArrays != 0 && (geometryArrays == null || numGeometryArrays != geometryArrays.length))
	    throw new IllegalArgumentException(J3dI18N.getString("MorphRetained0"));


        for (i=1;i < geometryArrays.length;i++) {
	    if (geometryArrays[i] == null || geometryArrays[i-1] == null)
		throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));
	    geo = (GeometryArrayRetained)geometryArrays[i].retained;
	    prevGeo = (GeometryArrayRetained)geometryArrays[i-1].retained;
	    if (prevGeo == null || geo == null) {
		throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));

	    }
	    doErrorCheck(prevGeo, geo);
	}

	// Check the first one for vertex attributes
	geo = (GeometryArrayRetained)geometryArrays[0].retained;
	if ((geo.vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) {
	    throw new UnsupportedOperationException(J3dI18N.getString("MorphRetained9"));
	}

	// Check if the first one is in Immediate context
	if (geometryArrays[0] != null) {
	    geo = (GeometryArrayRetained)geometryArrays[0].retained;
	}

	if (numGeometryArrays == 0) {
            this.geometryArrays = new GeometryArrayRetained[geometryArrays.length];
	    numGeometryArrays = geometryArrays.length;
	}

        for (i=0;i < numGeometryArrays;i++) {
	    geo = (GeometryArrayRetained)geometryArrays[i].retained;
	    if (((Morph)this.source).isLive()) {
		if (this.geometryArrays[i] != null) {
		    this.geometryArrays[i].clearLive(refCount);
		    this.geometryArrays[i].removeMorphUser(this);
		}
		if (geo != null) {
		    geo.setLive(inBackgroundGroup, refCount);
		    geo.addMorphUser(this);
		}
	    }

	    this.geometryArrays[i] = geo;
	}
	if (this.geometryArrays[0] == null)
	    return;


        if (weights == null) {
	    weights = new double[numGeometryArrays];
	    weights[0] = 1.0;
	    int vFormat = this.geometryArrays[0].vertexFormat;
	    // default is zero when new array
	    //for (i=1; i < numGeometryArrays;i++)  weights[i] = 0.0;

	    int texCoordSetCount = this.geometryArrays[0].getTexCoordSetCount();
	    if (this.geometryArrays[0] instanceof IndexedGeometryArrayRetained) {
		Mcoord = new float[this.geometryArrays[0].getNumCoordCount()* 3];

		if ((vFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3)
		    Mcolor = new float[this.geometryArrays[0].getNumColorCount()* 3];
		else if ((vFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4)
		    Mcolor = new float[this.geometryArrays[0].getNumColorCount()* 4];

		MtexCoord = new float[texCoordSetCount][];
		if ((vFormat & GeometryArray.NORMALS) != 0)
		    Mnormal = new float[this.geometryArrays[0].getNumNormalCount() *3];
		for (int k = 0; k < texCoordSetCount; k++) {
		    if ((vFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0)
			MtexCoord[k] = new float[this.geometryArrays[0].getNumTexCoordCount(k) * 2];
		    else if (((vFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0))
			MtexCoord[k] = new float[this.geometryArrays[0].getNumTexCoordCount(k) * 3];
		    else if (((vFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0))
			MtexCoord[k] = new float[this.geometryArrays[0].getNumTexCoordCount(k) * 4];
		}
	    }
	    else {
		Mcoord = new float[this.geometryArrays[0].validVertexCount* 3];

		if ((vFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) {
		    Mcolor = new float[this.geometryArrays[0].validVertexCount* 3];
		} else if ((vFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) {
		    Mcolor = new float[this.geometryArrays[0].validVertexCount* 4];
		}
		MtexCoord = new float[texCoordSetCount][];
		if ((vFormat & GeometryArray.NORMALS) != 0) {
		    Mnormal = new float[this.geometryArrays[0].validVertexCount *3];
		}
		for (int k = 0; k < texCoordSetCount; k++) {
		    if ((vFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0)
			MtexCoord[k] = new float[this.geometryArrays[0].validVertexCount * 2];
		    else if (((vFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0))
			MtexCoord[k] = new float[this.geometryArrays[0].validVertexCount * 3];
		    else if (((vFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0))
			MtexCoord[k] = new float[this.geometryArrays[0].validVertexCount * 4];
		}
	    }
	}

	//  create a new morphedGeometryArray
	initMorphedGeometry();

	if (source.isLive()) {

	    Shape3DRetained shape = (Shape3DRetained)mirrorShape3D.get(0);

	    shape.setMorphGeometry(morphedGeometryArray, mirrorShape3D);

	    J3dMessage mChangeMessage = null;
	    mChangeMessage = new J3dMessage();
	    mChangeMessage.type = J3dMessage.MORPH_CHANGED;
	    mChangeMessage.threads = (J3dThread.UPDATE_GEOMETRY |
				      J3dThread.UPDATE_TRANSFORM);
	    // If its a indexed geometry array, unindexify in renderBin
	    if (this.geometryArrays[0] instanceof IndexedGeometryArrayRetained)
		mChangeMessage.threads |= J3dThread.UPDATE_RENDERING_ATTRIBUTES;
	    mChangeMessage.args[0] = this;
	    mChangeMessage.args[1]= new Integer(GEOMETRY_CHANGED);
	  // a shadow copy of this ArrayList instance. (The elements themselves are not copied.)
	    mChangeMessage.args[3] = Shape3DRetained.getGeomAtomsArray(mirrorShape3D);
	    mChangeMessage.universe = universe;
	    VirtualUniverse.mc.processMessage(mChangeMessage);

	    if (boundsAutoCompute) {
		GeometryArrayRetained mga = (GeometryArrayRetained)morphedGeometryArray.retained;
		// Compute the bounds once
		mga.incrComputeGeoBounds();// This compute the bbox if dirty
		mga.decrComputeGeoBounds();
	    }
	}



    }

    /**
     * Retrieves the geometryArrays component of this Morph node.
     * @param index the index of GeometryArray to be returned
     * @return the geometryArray component of this morph node
     */
    GeometryArray getGeometryArray(int index) {
        return (GeometryArray)this.geometryArrays[index].source;
    }

    /**
     * Sets the appearance component of this Morph node.
     * @param appearance the new apearance component for this morph node
     */
    void setAppearance(Appearance newAppearance) {
	boolean visibleIsDirty = false;

        if (((Morph)this.source).isLive()) {

	    if (appearance != null) {
		this.appearance.clearLive(refCount);
		for (int i=mirrorShape3D.size()-1; i>=0; i--) {
		    this.appearance.removeAMirrorUser(
					(Shape3DRetained)mirrorShape3D.get(i));
		}
	    }

	    if (newAppearance != null) {
		((AppearanceRetained)newAppearance.retained).setLive(inBackgroundGroup, refCount);
		appearance = ((AppearanceRetained)newAppearance.retained);
		int size= mirrorShape3D.size();
		for (int i=0; i=0; i--)  {
	    sum += weights[i];
	}

	if (Math.abs(sum - 1.0) > TOLERANCE)
	    throw new IllegalArgumentException(J3dI18N.getString("MorphRetained8"));

	// Weights array is ALWAYS malloced in setGeometryArrays method
	for (i=numGeometryArrays-1; i>=0; i--)
	    this.weights[i] = weights[i];


	if (source.isLive()) {
	    ((GeometryArrayRetained)morphedGeometryArray.retained).updateData(this);
	    J3dMessage mChangeMessage = null;
	    mChangeMessage = new J3dMessage();
	    mChangeMessage.type = J3dMessage.MORPH_CHANGED;
	    mChangeMessage.threads = (J3dThread.UPDATE_GEOMETRY |
				      J3dThread.UPDATE_TRANSFORM);
	    // If its a indexed geometry array, unindexify in renderBin
	    if (this.geometryArrays[0] instanceof IndexedGeometryArrayRetained)
		mChangeMessage.threads |= J3dThread.UPDATE_RENDERING_ATTRIBUTES;
	    mChangeMessage.args[0] = this;
	    mChangeMessage.args[1]= new Integer(GEOMETRY_CHANGED);
	    mChangeMessage.args[3] = Shape3DRetained.getGeomAtomsArray(mirrorShape3D);
	    mChangeMessage.universe = universe;
	    VirtualUniverse.mc.processMessage(mChangeMessage);
	}

    }

    /**
     * Retrieves the Morph node's weight vector
     * @return the morph node's weight vector.
     */
    double[] getWeights() {
	return (double[]) weights.clone();
    }

    /**
     * Gets the bounding object of a node.
     * @return the node's bounding object
     */
    @Override
    Bounds getBounds() {
        if(boundsAutoCompute) {
            GeometryArrayRetained mga =
		(GeometryArrayRetained)morphedGeometryArray.retained;
            if (mga != null) {
                synchronized(mga.geoBounds) {
                    return (Bounds) mga.geoBounds.clone();
                }
            } else {
                return null;
            }
        } else {
            return super.getBounds();
        }
    }

    @Override
    Bounds getEffectiveBounds() {
        if(boundsAutoCompute) {
	    return getBounds();
	}
	else {
	    return super.getEffectiveBounds();
	}
    }

    /**
     * ONLY needed for SHAPE, MORPH, and LINK node type.
     * Compute the combine bounds of bounds and its localBounds.
     */
    @Override
    void computeCombineBounds(Bounds bounds) {

	if(boundsAutoCompute) {
	    GeometryArrayRetained mga =
		(GeometryArrayRetained)morphedGeometryArray.retained;
	    if (mga != null) {
		synchronized(mga.geoBounds) {
		    bounds.combine(mga.geoBounds);
		}
	    }
	} else {
	    // Should this be lock too ? ( MT safe  ? )
	    synchronized(localBounds) {
		bounds.combine(localBounds);
	    }
	}
    }

    // Return the number of geometry arrays in this MorphRetained object.
    int getNumGeometryArrays() {
	return numGeometryArrays;
    }

    // If the geometry of a morph changes, make sure that the
    // validVertexCount has not changed
    void updateMorphedGeometryArray(GeometryArrayRetained geo, boolean coordinatesChanged) {
	if (numGeometryArrays > 0) {
	    // check if not the first geo, then compare with the first geometry
	    if (geometryArrays[0] != geo) {
		doErrorCheck(geo, geometryArrays[0]);
	    }
	    else {
		// if first geo, compare with the second geo
		if (numGeometryArrays > 1) {
		    doErrorCheck(geo, geometryArrays[1]);
		}

	    }
	}


	((GeometryArrayRetained)morphedGeometryArray.retained).updateData(this);
	// Compute the bounds once
	if (boundsAutoCompute && coordinatesChanged) {
	    GeometryArrayRetained mga = (GeometryArrayRetained)morphedGeometryArray.retained;
	    mga.incrComputeGeoBounds();  // This compute the bbox if dirty
	    mga.decrComputeGeoBounds();
	}
    }

    /**
     * Update GeometryArray computed by morphing input GeometryArrays
     * with weights
     */
    @Override
    public void updateData(Geometry mga) {

	int i,j,k, vFormat, geoType, stripVCount[];
	int iCount = 0;
	int numStrips = 0;
	int texCoordSetCount = 0;
	float coord[] = new float[3], color[] = new float[4],
	    normal[] = new float[3], texCoord[] = new float[3];

	vFormat = geometryArrays[0].vertexFormat;
	geoType = geometryArrays[0].geoType;
	texCoordSetCount = geometryArrays[0].getTexCoordSetCount();



	int vc = 0, nc = 0, cc = 0, n = 0;
	int count = 0;
	if (geometryArrays[0] instanceof IndexedGeometryArrayRetained){
	     count = geometryArrays[0].getNumCoordCount();
	} else {
	     count = geometryArrays[0].validVertexCount;
	}

	for (i=0; i < count; i++) {
	    Mcoord[vc++] = Mcoord[vc++] = Mcoord[vc++] = 0.0f;
	}


	if ((vFormat & GeometryArray.COLOR) != 0) {
	    if (geometryArrays[0] instanceof IndexedGeometryArrayRetained){
		count = geometryArrays[0].getNumColorCount();
	    } else {
		count = geometryArrays[0].validVertexCount;
	    }
	    for (i=0; i < count; i++) {
		if ((vFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3)
		    Mcolor[cc++] = Mcolor[cc++] = Mcolor[cc++] = 0.0f;

		else if ((vFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4)
		    Mcolor[cc++] = Mcolor[cc++] = Mcolor[cc++] = Mcolor[cc++] = 0.0f;
	    }
	}


	if ((vFormat & GeometryArray.NORMALS) != 0) {
	    if (geometryArrays[0] instanceof IndexedGeometryArrayRetained){
		count = geometryArrays[0].getNumNormalCount();
	    } else {
		count = geometryArrays[0].validVertexCount;
	    }
	    for (i=0; i < count; i++) {
		Mnormal[nc++] = Mnormal[nc++] = Mnormal[nc++] = 0.0f;
	    }
	}

	if ((vFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
	    for (k = 0; k < texCoordSetCount; k++) {
		if (geometryArrays[0] instanceof IndexedGeometryArrayRetained){
		    count = geometryArrays[0].getNumTexCoordCount(k);
		} else {
		    count = geometryArrays[0].validVertexCount;
		}
		int tcount = 0;
		for (i=0; i < count; i++) {
		    MtexCoord[k][tcount++] = MtexCoord[k][tcount++] = 0.0f;
		    if ((vFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
			MtexCoord[k][tcount++] = 0.0f;
		    } else if ((vFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
			MtexCoord[k][tcount++] = 0.0f;
			MtexCoord[k][tcount++] = 0.0f;
		    }
		}
	    }
	}
	// If by copy, then ...
	if ((vFormat & GeometryArray.BY_REFERENCE) == 0) {
	    count = 0;
	    for (j=0;j < numGeometryArrays;j++) {
		double w = weights[j];
		if (w != 0) {
		    vc = 0; nc = 0; cc = 0;
		    int initialVertex = 0;
		    if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
			initialVertex = 0;
			count =  geometryArrays[j].getNumCoordCount();
		    }
		    else {
			initialVertex = geometryArrays[j].getInitialVertexIndex();
			count = geometryArrays[j].validVertexCount;
		    }
		    int endVertex = initialVertex + count;
		    for (i=initialVertex; i< endVertex; i++) {
			geometryArrays[j].getCoordinate(i, coord);
			Mcoord[vc++] += coord[0]*w;
			Mcoord[vc++] += coord[1]*w;
			Mcoord[vc++] += coord[2]*w;
		    }

		    if ((vFormat & GeometryArray.COLOR) != 0) {
			if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
			    count =  geometryArrays[j].getNumColorCount();
			}
			endVertex = initialVertex + count;
			for (i=initialVertex; i<  endVertex; i++) {
			    geometryArrays[j].getColor(i, color);
			    Mcolor[cc++] += color[0]*w;
			    Mcolor[cc++] += color[1]*w;
			    Mcolor[cc++] += color[2]*w;
			    if ((vFormat & GeometryArray.WITH_ALPHA) != 0)
				Mcolor[cc++] += color[3]*w;
			}
		    }
		    if ((vFormat & GeometryArray.NORMALS) != 0) {
			if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
			    count =  geometryArrays[j].getNumNormalCount();
			}
			endVertex = initialVertex + count;
			for (i=initialVertex; i<  endVertex; i++) {
			    geometryArrays[j].getNormal(i, normal);
			    Mnormal[nc++] += normal[0]*w;
			    Mnormal[nc++] += normal[1]*w;
			    Mnormal[nc++] += normal[2]*w;
			}
		    }

		    if ((vFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
			for (k = 0; k < texCoordSetCount; k++) {
			    int tcount = 0;
			    if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
				count =  geometryArrays[j].getNumTexCoordCount(i);
			    }
			    endVertex = initialVertex + count;
			    for (i=initialVertex; i<  endVertex; i++) {
				geometryArrays[j].getTextureCoordinate(k, i, texCoord);
				MtexCoord[k][tcount++] += texCoord[0]*w;
				MtexCoord[k][tcount++] += texCoord[1]*w;
				if ((vFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
				    MtexCoord[k][tcount++] += texCoord[2]*w;
				} else if ((vFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
				    MtexCoord[k][tcount++] += texCoord[2]*w;
				    MtexCoord[k][tcount++] += texCoord[3]*w;
				}
			    }
			}
		    }
		}
	    }
	}
	else {
	    int vIndex, tIndex, cIndex, nIndex, tstride = 0, cstride = 0;
	    if ((vFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
		if ((vFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) {
		    tstride = 2;
		} else if ((vFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
		    tstride = 3;
		} else {
		    tstride = 4;
		}
	    }

	    if ((vFormat & GeometryArray.COLOR) != 0) {
		cstride = 3;
		if ((vFormat & GeometryArray.WITH_ALPHA) != 0)
		    cstride = 4;
	    }

	    if ((vFormat & GeometryArray.INTERLEAVED) != 0) {
		float[] vdata;
		int stride;

		stride = geometryArrays[0].stride();
		int coffset = geometryArrays[0].colorOffset();
		int noffset = geometryArrays[0].normalOffset();
		int voffset = geometryArrays[0].coordinateOffset();
		int offset = 0;

		int initialVertex = 0;
		for (j=0;j < numGeometryArrays;j++) {
		    double w = weights[j];
		    if (w != 0) {
			vc = 0; nc = 0; cc = 0; n = 0;
			vdata = geometryArrays[j].getInterleavedVertices();
			if ((vFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
			    for (k = 0; k < texCoordSetCount; k++) {
				if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
				    tIndex = 0;
				    count =  geometryArrays[j].getNumCoordCount();
				}
				else {
				    tIndex = geometryArrays[j].getInitialVertexIndex();
				    count = geometryArrays[j].validVertexCount;
				}
				offset = (tIndex * stride)+k*tstride;
				int tcount = 0;
				for (i = 0; i < count; i++, offset += stride) {
				    MtexCoord[k][tcount++] += vdata[offset] * w;
				    MtexCoord[k][tcount++] += vdata[offset+1] * w;
				    if ((vFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
					MtexCoord[k][tcount++] += vdata[offset+2]*w;
				    } else if ((vFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
					MtexCoord[k][tcount++] += vdata[offset+2]*w;
					MtexCoord[k][tcount++] += vdata[offset+3]*w;
				    }
				}
			    }

			}
			if ((vFormat & GeometryArray.COLOR) != 0) {
			    if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
				cIndex = 0;
				count =  geometryArrays[j].getNumCoordCount();
			    }
			    else {
				cIndex = geometryArrays[j].getInitialVertexIndex();
				count = geometryArrays[j].validVertexCount;
			    }
			    offset = (cIndex * stride)+coffset;
			    for (i = 0; i < count; i++, offset += stride) {
				Mcolor[cc++] += vdata[offset]*w;
				Mcolor[cc++] += vdata[offset+1]*w;
				Mcolor[cc++] += vdata[offset+2]*w;
				if ((vFormat & GeometryArray.WITH_ALPHA)!= 0)
				    Mcolor[cc++] += vdata[offset+3]*w;

			    }
			}

			if ((vFormat & GeometryArray.NORMALS) != 0) {
			    if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
				nIndex = 0;
				count =  geometryArrays[j].getNumCoordCount();
			    }
			    else {
				nIndex = geometryArrays[j].getInitialVertexIndex();
				count = geometryArrays[j].validVertexCount;
			    }
			    offset = (nIndex * stride)+noffset;
			    for (i = 0; i < count; i++, offset += stride) {
				Mnormal[nc++] += vdata[offset]*w;
				Mnormal[nc++] += vdata[offset+1]*w;
				Mnormal[nc++] += vdata[offset+2]*w;
			    }
			}
			if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
			    vIndex = 0;
			    count =  geometryArrays[j].getNumCoordCount();
			}
			else {
			    vIndex = geometryArrays[j].getInitialVertexIndex();
			    count = geometryArrays[j].validVertexCount;
			}
			offset = (vIndex * stride)+voffset;
			for (i = 0; i < count; i++, offset += stride) {
			    Mcoord[vc++] += vdata[offset]*w;
			    Mcoord[vc++] += vdata[offset+1]*w;
			    Mcoord[vc++] += vdata[offset+2]*w;

			}
		    }
		}
	    }
	    else {
		float byteToFloatScale = 1.0f/255.0f;
		for (j=0;j < numGeometryArrays;j++) {
		    double w = weights[j];
		    if (w != 0) {
			if ((vFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
			    switch ((geometryArrays[j].vertexType & GeometryArrayRetained.TEXCOORD_DEFINED)) {
			    case GeometryArrayRetained.TF:
				for (k = 0; k < texCoordSetCount; k++) {
				    float[] tf = geometryArrays[j].getTexCoordRefFloat(k);
				    if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
					tIndex = 0;
					count =  geometryArrays[j].getNumTexCoordCount(k);
				    }
				    else {
					tIndex = geometryArrays[j].getInitialTexCoordIndex(k);
					count =  geometryArrays[j].validVertexCount;
				    }
				    tIndex *= tstride;
				    int tcount = 0;
				    for (i=0; i< count; i++) {
					MtexCoord[k][tcount++] += tf[tIndex++]*w;
					MtexCoord[k][tcount++] += tf[tIndex++]*w;
					if ((vFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0)
					    MtexCoord[k][tcount++] += tf[tIndex++]*w;
				    }
				}
				break;
			    case GeometryArrayRetained.T2F:
				for (k = 0; k < texCoordSetCount; k++) {
				    int tcount = 0;
				    float[] tf = geometryArrays[j].getTexCoordRefFloat(k);
				    if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
					tIndex = 0;
					count =  geometryArrays[j].getNumTexCoordCount(k);
				    }
				    else {
					tIndex = geometryArrays[j].getInitialTexCoordIndex(k);
					count =  geometryArrays[j].validVertexCount;
				    }
				    TexCoord2f[] t2f = geometryArrays[j].getTexCoordRef2f(k);
				    for (i=0; i< count; i++, tIndex++) {
					MtexCoord[k][tcount++] += t2f[tIndex].x*w;
					MtexCoord[k][tcount++] += t2f[tIndex].y*w;
				    }
				}
				break;
			    case GeometryArrayRetained.T3F:
				for (k = 0; k < texCoordSetCount; k++) {
				    int tcount = 0;
				    TexCoord3f[] t3f = geometryArrays[j].getTexCoordRef3f(k);
				    if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
					tIndex = 0;
					count =  geometryArrays[j].getNumTexCoordCount(k);
				    }
				    else {
					tIndex = geometryArrays[j].getInitialTexCoordIndex(k);
					count =  geometryArrays[j].validVertexCount;
				    }
				    for (i=0; i< count; i++, tIndex++) {
					MtexCoord[k][tcount++] += t3f[tIndex].x*w;
					MtexCoord[k][tcount++] += t3f[tIndex].y*w;
					MtexCoord[k][tcount++] += t3f[tIndex].z*w;
				    }
				}
				break;

			    }
			}
			if ((vFormat & GeometryArray.COLOR) != 0) {
			    double val = byteToFloatScale * w;
			    if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
				cIndex = 0;
				count =  geometryArrays[j].getNumColorCount();
			    }
			    else {
				cIndex = geometryArrays[j].getInitialColorIndex();
				count =  geometryArrays[j].validVertexCount;
			    }

			    switch ((geometryArrays[j].vertexType & GeometryArrayRetained.COLOR_DEFINED)) {
			    case GeometryArrayRetained.CF:
				float[] cf = geometryArrays[j].getColorRefFloat();
				cc = 0;
				cIndex *= cstride;
				for (i=0; i< count; i++) {
				    Mcolor[cc++] += cf[cIndex++]*w;
				    Mcolor[cc++] += cf[cIndex++]*w;
				    Mcolor[cc++] += cf[cIndex++]*w;
				    if ((vFormat & GeometryArray.WITH_ALPHA)!= 0)
					Mcolor[cc++] += cf[cIndex++]*w;
				}
				break;
			    case GeometryArrayRetained.CUB:
				byte[] cub = geometryArrays[j].getColorRefByte();
				cc = 0;
				cIndex *= cstride;
				for (i=0; i< count; i++) {
				    Mcolor[cc++] += (cub[cIndex++] & 0xff) * val;
				    Mcolor[cc++] += (cub[cIndex++] & 0xff) *val;
				    Mcolor[cc++] += (cub[cIndex++] & 0xff) *val;
				    if ((vFormat & GeometryArray.WITH_ALPHA)!= 0)
					Mcolor[cc++] += (cub[cIndex++] & 0xff) *val;
				}

				break;
			    case GeometryArrayRetained.C3F:
				Color3f[] c3f = geometryArrays[j].getColorRef3f();
				cc = 0;
				for (i=0; i< count; i++, cIndex++) {
				    Mcolor[cc++] += c3f[cIndex].x * w;
				    Mcolor[cc++] += c3f[cIndex].y * w;
				    Mcolor[cc++] += c3f[cIndex].z * w;
				}
				break;
			    case GeometryArrayRetained.C4F:
				Color4f[] c4f = geometryArrays[j].getColorRef4f();
				cc = 0;
				for (i=0; i< count; i++, cIndex++) {
				    Mcolor[cc++] += c4f[cIndex].x * w;
				    Mcolor[cc++] += c4f[cIndex].y * w;
				    Mcolor[cc++] += c4f[cIndex].z * w;
				    Mcolor[cc++] += c4f[cIndex].w * w;
				}
				break;
			    case GeometryArrayRetained.C3UB:
				Color3b[] c3b = geometryArrays[j].getColorRef3b();
				cc = 0;
				for (i=0; i< count; i++, cIndex++) {
				    Mcolor[cc++] += (c3b[cIndex].x  & 0xff)* val;
				    Mcolor[cc++] += (c3b[cIndex].y  & 0xff) * val;
				    Mcolor[cc++] += (c3b[cIndex].z & 0xff) * val;
				}
				break;
			    case GeometryArrayRetained.C4UB:
				Color4b[] c4b = geometryArrays[j].getColorRef4b();
				cc = 0;
				for (i=0; i< count; i++, cIndex++) {
				    Mcolor[cc++] += (c4b[cIndex].x  & 0xff)* val;
				    Mcolor[cc++] += (c4b[cIndex].y  & 0xff) * val;
				    Mcolor[cc++] += (c4b[cIndex].z & 0xff) * val;
				    Mcolor[cc++] += (c4b[cIndex].w & 0xff) * val;
				}
				break;

			    }
			}
			if ((vFormat & GeometryArray.NORMALS) != 0) {
			    nc = 0;
			    if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
				nIndex = 0;
				count =  geometryArrays[j].getNumNormalCount();
			    }
			    else {
				nIndex = geometryArrays[j].getInitialNormalIndex();
				count =  geometryArrays[j].validVertexCount;
			    }
			    switch ((geometryArrays[j].vertexType & GeometryArrayRetained.NORMAL_DEFINED)) {
			    case GeometryArrayRetained.NF:
				float[] nf = geometryArrays[j].getNormalRefFloat();
				nIndex *= 3;
				for (i=0; i< count; i++) {
				    Mnormal[nc++] += nf[nIndex++]*w;
				    Mnormal[nc++] += nf[nIndex++]*w;
				    Mnormal[nc++] += nf[nIndex++]*w;
				}
				break;
			    case GeometryArrayRetained.N3F:
				Vector3f[] n3f = geometryArrays[j].getNormalRef3f();
				for (i=0; i< count; i++, nIndex++) {
				    Mnormal[nc++] += n3f[nIndex].x*w;
				    Mnormal[nc++] += n3f[nIndex].y*w;
				    Mnormal[nc++] += n3f[nIndex].z*w;
				}
				break;
			    }
			}
			// Handle vertices ..
			vc = 0;
			if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
			    vIndex = 0;
			    count =  geometryArrays[j].getNumCoordCount();
			}
			else {
			    vIndex = geometryArrays[j].getInitialCoordIndex();
			    count =  geometryArrays[j].validVertexCount;
			}
			switch ((geometryArrays[j].vertexType & GeometryArrayRetained.VERTEX_DEFINED)) {
			case GeometryArrayRetained.PF:
			    float[] pf = geometryArrays[j].getCoordRefFloat();
			    vIndex *= 3;
			    for (i=0; i< count; i++) {
				Mcoord[vc++] += pf[vIndex++]*w;
				Mcoord[vc++] += pf[vIndex++]*w;
				Mcoord[vc++] += pf[vIndex++]*w;
			    }
			    break;
			case GeometryArrayRetained.PD:
			    double[] pd = geometryArrays[j].getCoordRefDouble();
			    vIndex *= 3;
			    for (i=0; i< count; i++) {
				Mcoord[vc++] += (float)pd[vIndex++]*w;
				Mcoord[vc++] += (float)pd[vIndex++]*w;
				Mcoord[vc++] += (float)pd[vIndex++]*w;
			    }
			    break;
			case GeometryArrayRetained.P3F:
			    Point3f[] p3f = geometryArrays[j].getCoordRef3f();
			    for (i=0; i< count; i++, vIndex++) {
				Mcoord[vc++] += p3f[vIndex].x*w;
				Mcoord[vc++] += p3f[vIndex].y*w;
				Mcoord[vc++] += p3f[vIndex].z*w;
			    }
			    break;
			case GeometryArrayRetained.P3D:
			    Point3d[] p3d = geometryArrays[j].getCoordRef3d();
			    for (i=0; i< count; i++, vIndex++) {
				Mcoord[vc++] += (float)p3d[vIndex].x*w;
				Mcoord[vc++] += (float)p3d[vIndex].y*w;
				Mcoord[vc++] += (float)p3d[vIndex].z*w;
			    }
			    break;

			}

		    }
		}
	    }
	}

	GeometryArrayRetained mgaR =
	    (GeometryArrayRetained)mga.retained;

	mgaR.setCoordRefFloat(Mcoord);

	if ((vFormat & GeometryArray.COLOR) != 0)
	    mgaR.setColorRefFloat(Mcolor);

	// *******Need to normalize normals
	if ((vFormat & GeometryArray.NORMALS) != 0)
	    mgaR.setNormalRefFloat(Mnormal);

	if ((vFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
    	    for (k = 0; k < texCoordSetCount; k++) {
		mgaR.setTexCoordRefFloat(k, MtexCoord[k]);
	    }
	}
    }

    void updateImmediateMirrorObject(Object[] objs) {
	int i;

	int component = ((Integer)objs[1]).intValue();
	Shape3DRetained[] msArr = (Shape3DRetained[]) objs[2];
	if ((component & APPEARANCE_CHANGED) != 0) {
	    Object[] arg = (Object[])objs[3];
	    int val = ((Integer)arg[1]).intValue();
	    for ( i = msArr.length-1; i >=0; i--) {
		msArr[i].appearance = (AppearanceRetained)arg[0];
		msArr[i].changedFrequent = val;
	    }
	}
	if ((component & APPEARANCEOVERRIDE_CHANGED) != 0) {
	    Object[] arg = (Object[])objs[3];
	    int val = ((Integer)arg[1]).intValue();
	    System.err.println("ChangedFrequent = "+changedFrequent);
	    for ( i = msArr.length-1; i >=0; i--) {
		msArr[i].appearanceOverrideEnable = ((Boolean)arg[0]).booleanValue();
		msArr[i].changedFrequent = val;
	    }
	}
    }

    /**
     * assign a name to this node when it is made live.
     */
    @Override
    void setLive(SetLiveState s) {
	int i, j;
	Shape3DRetained shape;
	ArrayList msList = new ArrayList();
        GeometryAtom ga;
	int oldrefCount = refCount;

	super.doSetLive(s);
	nodeId = universe.getNodeId();


	for (i = 0; i < numGeometryArrays; i++) {
	    synchronized(geometryArrays[i].liveStateLock) {
		geometryArrays[i].setLive(inBackgroundGroup, s.refCount);
		// Add this morph object as user the first time
		if (oldrefCount <= 0) {
		    geometryArrays[i].addMorphUser(this);
		}
	    }
	}

	if (this.morphedGeometryArray == null){
	    initMorphedGeometry();

	}
	((GeometryArrayRetained)(morphedGeometryArray.retained)).setLive(inBackgroundGroup, s.refCount);

	if (boundsAutoCompute) {
	    GeometryArrayRetained mga = (GeometryArrayRetained)morphedGeometryArray.retained;
	    // Compute the bounds once
	    mga.incrComputeGeoBounds(); // This compute the bbox if dirty
	    mga.decrComputeGeoBounds();
	    localBounds.setWithLock(mga.geoBounds);
	}


	if (inSharedGroup) {
	    for (i=0; i l = s.lights.get(j);
				if (l != null) {
					for (int m = 0; m < l.size(); m++) {
						shape.addLight(l.get(m));
					}
				}
			}

			// Add any scoped fog
			if (s.fogs != null) {
				ArrayList l = s.fogs.get(j);
				if (l != null) {
					for (int m = 0; m < l.size(); m++) {
						shape.addFog(l.get(m));
					}
				}
			}

			// Add any scoped modelClip
			if (s.modelClips != null) {
				ArrayList l = s.modelClips.get(j);
				if (l != null) {
					for (int m = 0; m < l.size(); m++) {
						shape.addModelClip(l.get(m));
					}
				}
			}

			// Add any scoped alt app
			if (s.altAppearances != null) {
				ArrayList l = s.altAppearances.get(j);
				if (l != null) {
					for (int m = 0; m < l.size(); m++) {
						shape.addAltApp(l.get(m));
					}
				}
			}

		if (s.viewLists != null)
		    shape.viewList = s.viewLists.get(i);
		else
		    shape.viewList = null;

		//		((GeometryArrayRetained)(morphedGeometryArray.retained)).addUser(shape);


                ga = Shape3DRetained.getGeomAtom(shape);

		// Add the geometry atom for this shape to the Targets
		s.nodeList.add(ga);

                if (s.transformTargets != null &&
                                s.transformTargets[i] != null) {
		    s.transformTargets[i].addNode(ga, Targets.GEO_TARGETS);
		}
                if (s.switchTargets != null &&
                        s.switchTargets[i] != null) {
		    s.switchTargets[i].addNode(shape, Targets.GEO_TARGETS);
                    shape.closestSwitchParent = s.closestSwitchParents[i];
                    shape.closestSwitchIndex = s.closestSwitchIndices[i];
                }
			shape.switchState = s.switchStates.get(j);

	    }
	} else {
	    shape = new Shape3DRetained();
	    shape.localToVworld = new Transform3D[1][];
	    shape.localToVworldIndex = new int[1][];
	    shape.localToVworld[0] = this.localToVworld[0];
	    shape.localToVworldIndex[0] = this.localToVworldIndex[0];
			shape.branchGroupPath = branchGroupPaths.get(0);
	    shape.isPickable = s.pickable[0];
	    shape.isCollidable = s.collidable[0];
	    shape.initMirrorShape3D(s, this, 0);
	    mirrorShape3D.add(shape);

	    msList.add(shape);
		// Add any scoped lights to the mirror shape
		if (s.lights != null) {
			ArrayList l = s.lights.get(0);
			if (l != null) {
				for (int m = 0; m < l.size(); m++) {
					shape.addLight(l.get(m));
				}
			}
		}

		// Add any scoped fog
		if (s.fogs != null) {
			ArrayList l = s.fogs.get(0);
			if (l != null) {
				for (int m = 0; m < l.size(); m++) {
					shape.addFog(l.get(m));
				}
			}
		}

		// Add any scoped modelClip
		if (s.modelClips != null) {
			ArrayList l = s.modelClips.get(0);
			if (l != null) {
				for (int m = 0; m < l.size(); m++) {
					shape.addModelClip(l.get(m));
				}
			}
		}

		// Add any scoped alt app
		if (s.altAppearances != null) {
			ArrayList l = s.altAppearances.get(0);
			if (l != null) {
				for (int m = 0; m < l.size(); m++) {
					shape.addAltApp(l.get(m));
				}
			}
		}

	    if (s.viewLists != null)
		shape.viewList = s.viewLists.get(0);
	    else
		shape.viewList = null;

	    //	    ((GeometryArrayRetained)(morphedGeometryArray.retained)).addUser(shape);

            ga = Shape3DRetained.getGeomAtom(shape);

    	    // Add the geometry atom for this shape to the Targets
	    s.nodeList.add(ga);

            if (s.transformTargets != null &&
                                s.transformTargets[0] != null) {
		s.transformTargets[0].addNode(ga, Targets.GEO_TARGETS);
	    }
            if (s.switchTargets != null &&
                        s.switchTargets[0] != null) {
		s.switchTargets[0].addNode(shape, Targets.GEO_TARGETS);
                shape.closestSwitchParent = s.closestSwitchParents[0];
                shape.closestSwitchIndex = s.closestSwitchIndices[0];
            }
		shape.switchState = s.switchStates.get(0);
	}
	if (appearance != null) {
	    synchronized(appearance.liveStateLock) {
		appearance.setLive(inBackgroundGroup, s.refCount);
		appearance.initMirrorObject();
		if (appearance.renderingAttributes != null)
		    visible = appearance.renderingAttributes.visible;
		for (int k = 0; k < msList.size(); k++) {
		    Shape3DRetained sh = (Shape3DRetained)msList.get(k);
		    sh.appearance = (AppearanceRetained)appearance.mirror;
		    appearance.addAMirrorUser(sh);
		}
	    }

	}
	else {
	    for (int k = 0; k < msList.size(); k++) {
		Shape3DRetained sh = (Shape3DRetained)msList.get(k);
		sh.appearance = null;
	    }
	}

	s.notifyThreads |= (J3dThread.UPDATE_GEOMETRY |
			    J3dThread.UPDATE_TRANSFORM |
			    J3dThread.UPDATE_RENDER |
			    J3dThread.UPDATE_RENDERING_ATTRIBUTES);

	// Need to clone the geometry , if its indexed ...
	if (refCount == 1 && this.geometryArrays[0] instanceof IndexedGeometryArrayRetained) {
	    J3dMessage mChangeMessage = new J3dMessage();
	    mChangeMessage.type = J3dMessage.MORPH_CHANGED;
	    mChangeMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES;
	    mChangeMessage.args[0] = this;
	    mChangeMessage.args[1]= new Integer(GEOMETRY_CHANGED);
	    mChangeMessage.universe = universe;
	    VirtualUniverse.mc.processMessage(mChangeMessage);
	}
	super.markAsLive();

    }


    /**
     * assign a name to this node when it is made live.
     */
    @Override
    void clearLive(SetLiveState s) {
	int i, j;
	Shape3DRetained shape;
	Object[] shapes;
	ArrayList appList = new ArrayList();
	GeometryAtom ga;

	super.clearLive(s);

	for (i = 0; i < numGeometryArrays; i++) {
	    synchronized(geometryArrays[i].liveStateLock) {
		geometryArrays[i].clearLive(s.refCount);
		// Remove this morph object as user, when the last branch
		// is clearlived
		if (refCount <= 0) {
		    geometryArrays[i].removeMorphUser(this);
		}
	    }
	}
	GeometryArrayRetained mga = (GeometryArrayRetained)morphedGeometryArray.retained;

	mga.clearLive( s.refCount);

	if (inSharedGroup) {
	    shapes = mirrorShape3D.toArray();
	    for (i=0; i=0) {
	    return (Shape3DRetained) mirrorShape3D.get(i);
	}

	// Not possible
	throw new RuntimeException("Shape3DRetained: MirrorShape Not found!");
    }

    @Override
    void getMirrorObjects(ArrayList leafList, HashKey key) {
	Shape3DRetained ms;
	if (inSharedGroup) {
	    ms = getMirrorShape(key);
	}
	else {
	    ms = (Shape3DRetained)mirrorShape3D.get(0);
	}
	GeometryAtom ga = Shape3DRetained.getGeomAtom(ms);
	leafList.add(ga);

    }

    @Override
    void setBoundsAutoCompute(boolean autoCompute) {
        if (autoCompute != boundsAutoCompute) {
            if (autoCompute) {
                // localBounds may not have been set to bbox
                localBounds = new BoundingBox();
		if (source.isLive() && morphedGeometryArray != null) {
		    GeometryArrayRetained mga = (GeometryArrayRetained)morphedGeometryArray.retained;
		    mga.incrComputeGeoBounds(); // This compute the bbox if dirty
		    mga.decrComputeGeoBounds();
		}
            }


	    localBounds = getBounds();
            super.setBoundsAutoCompute(autoCompute);
            if (source.isLive()) {
                J3dMessage message = new J3dMessage();
                message.type = J3dMessage.BOUNDS_AUTO_COMPUTE_CHANGED;
                message.threads = J3dThread.UPDATE_TRANSFORM |
		                  J3dThread.UPDATE_GEOMETRY |
		                  J3dThread.UPDATE_RENDER;
                message.universe = universe;
                message.args[0] = Shape3DRetained.getGeomAtomsArray(mirrorShape3D);
		message.args[1] = localBounds;
                VirtualUniverse.mc.processMessage(message);
            }
        }
    }

    @Override
    void updateBounds() {
	localBounds = getEffectiveBounds();
	if (source.isLive()) {
	    J3dMessage message = new J3dMessage();
	    message.type = J3dMessage.BOUNDS_AUTO_COMPUTE_CHANGED;
	    message.threads = J3dThread.UPDATE_TRANSFORM |
		J3dThread.UPDATE_GEOMETRY |
		J3dThread.UPDATE_RENDER;
                message.universe = universe;
                message.args[0] = Shape3DRetained.getGeomAtomsArray(mirrorShape3D);
		message.args[1] = localBounds;
                VirtualUniverse.mc.processMessage(message);
	}
    }

    /**
     * Initialization of morphed geometry
     */
    void initMorphedGeometry() {
      int  vFormat, geoType, stripVCount[];
      int iCount = 0;
      int numStrips = 0;
      int texCoordSetCount = 0;
      int texCoordSetMapLen = 0;
      int [] texCoordSetMap = null;
      int k;
      GeometryArrayRetained geo = geometryArrays[0];
      vFormat = ((geo.getVertexFormat() | (GeometryArray.BY_REFERENCE)) & ~(GeometryArray.INTERLEAVED)) ;
      texCoordSetCount = geo.getTexCoordSetCount();
      texCoordSetMapLen = geo.getTexCoordSetMapLength();
      if (texCoordSetMapLen > 0) {
          texCoordSetMap = new int[texCoordSetMapLen];
	   geo.getTexCoordSetMap(texCoordSetMap);
      }
      geoType = geo.geoType;

      switch (geoType){
	case GeometryRetained.GEO_TYPE_QUAD_SET:
	    this.morphedGeometryArray =
	     	new QuadArray(geometryArrays[0].validVertexCount, vFormat, texCoordSetCount,
				texCoordSetMap);
	    break;
	case GeometryRetained.GEO_TYPE_TRI_SET:
	    this.morphedGeometryArray =
		new TriangleArray(geometryArrays[0].validVertexCount, vFormat, texCoordSetCount,
				texCoordSetMap);
	    break;
	case GeometryRetained.GEO_TYPE_POINT_SET:
	    this.morphedGeometryArray =
		new PointArray(geometryArrays[0].validVertexCount, vFormat, texCoordSetCount,
				texCoordSetMap);
	    break;
	case GeometryRetained.GEO_TYPE_LINE_SET:
	    this.morphedGeometryArray =
		new LineArray(geometryArrays[0].validVertexCount, vFormat, texCoordSetCount,
				texCoordSetMap);
	    break;
	case GeometryRetained.GEO_TYPE_TRI_STRIP_SET:
	    numStrips = ((TriangleStripArrayRetained)geo).getNumStrips();
	    stripVCount = new int[numStrips];
	    ((TriangleStripArrayRetained)geo).getStripVertexCounts(stripVCount);
	    this.morphedGeometryArray =
		new TriangleStripArray(geometryArrays[0].validVertexCount, vFormat, texCoordSetCount,
			texCoordSetMap, stripVCount);
	    break;
	case GeometryRetained.GEO_TYPE_TRI_FAN_SET:
	    numStrips = ((TriangleFanArrayRetained)geo).getNumStrips();
	    stripVCount = new int[numStrips];
	    ((TriangleFanArrayRetained)geo).getStripVertexCounts(stripVCount);
	    this.morphedGeometryArray =
		new TriangleFanArray(geometryArrays[0].validVertexCount, vFormat, texCoordSetCount,
			texCoordSetMap, stripVCount);
		break;
	case GeometryRetained.GEO_TYPE_LINE_STRIP_SET:
	    numStrips = ((LineStripArrayRetained)geo).getNumStrips();
	    stripVCount = new int[numStrips];
	    ((LineStripArrayRetained)geo).getStripVertexCounts(stripVCount);
	    this.morphedGeometryArray =
		new LineStripArray(geometryArrays[0].validVertexCount, vFormat, texCoordSetCount,
			texCoordSetMap, stripVCount);
		break;

	case GeometryRetained.GEO_TYPE_INDEXED_QUAD_SET:
	    iCount = ((IndexedGeometryArrayRetained)geo).getIndexCount();
	    this.morphedGeometryArray =
		new IndexedQuadArray(geometryArrays[0].getNumCoordCount(), vFormat, texCoordSetCount,
			texCoordSetMap, iCount);
		break;
	case GeometryRetained.GEO_TYPE_INDEXED_TRI_SET:
	    iCount = ((IndexedGeometryArrayRetained)geo).getIndexCount();
	    this.morphedGeometryArray =
		new IndexedTriangleArray(geometryArrays[0].getNumCoordCount(), vFormat, texCoordSetCount,
			texCoordSetMap, iCount);
		break;
	case GeometryRetained.GEO_TYPE_INDEXED_POINT_SET:
	    iCount = ((IndexedGeometryArrayRetained)geo).getIndexCount();
	    this.morphedGeometryArray =
		new IndexedPointArray(geometryArrays[0].getNumCoordCount(), vFormat, texCoordSetCount,
			texCoordSetMap, iCount);
		break;
	case GeometryRetained.GEO_TYPE_INDEXED_LINE_SET:
	    iCount = ((IndexedGeometryArrayRetained)geo).getIndexCount();
	    this.morphedGeometryArray =
		new IndexedLineArray(geometryArrays[0].getNumCoordCount(), vFormat, texCoordSetCount,
			texCoordSetMap, iCount);
	    break;
	case GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET:
	    iCount = ((IndexedGeometryArrayRetained)geo).getIndexCount();
	    numStrips = ((IndexedTriangleStripArrayRetained)geo).getNumStrips();
	    stripVCount = new int[numStrips];
	    ((IndexedTriangleStripArrayRetained)geo).getStripIndexCounts(stripVCount);
	    this.morphedGeometryArray =
		new IndexedTriangleStripArray(geometryArrays[0].getNumCoordCount(), vFormat, texCoordSetCount,
			texCoordSetMap, iCount, stripVCount);break;
	case GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET:
	    iCount = ((IndexedGeometryArrayRetained)geo).getIndexCount();
	    numStrips = ((IndexedTriangleFanArrayRetained)geo).getNumStrips();
	    stripVCount = new int[numStrips];
	    ((IndexedTriangleFanArrayRetained)geo).getStripIndexCounts(stripVCount);
	    this.morphedGeometryArray =
		new IndexedTriangleFanArray(geometryArrays[0].getNumCoordCount(), vFormat, texCoordSetCount,
			texCoordSetMap, iCount, stripVCount);break;
	case GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET:
	    iCount = ((IndexedGeometryArrayRetained)geo).getIndexCount();
	    numStrips = ((IndexedLineStripArrayRetained)geo).getNumStrips();
	    stripVCount = new int[numStrips];
	    ((IndexedLineStripArrayRetained)geo).getStripIndexCounts(stripVCount);
	    this.morphedGeometryArray =
		new IndexedLineStripArray(geometryArrays[0].getNumCoordCount(), vFormat, texCoordSetCount,
			texCoordSetMap, iCount, stripVCount);break;
	}
	if (geometryArrays[0] instanceof IndexedGeometryArrayRetained) {
	    IndexedGeometryArrayRetained igeo = (IndexedGeometryArrayRetained)
		geometryArrays[0];
	    IndexedGeometryArray morphedGeo = (IndexedGeometryArray)
		morphedGeometryArray;
	    if ((vFormat & GeometryArray.COORDINATES) != 0) {
		morphedGeo.setCoordinateIndices(0, igeo.indexCoord);
	    }
	    if ((vFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0) {
	        if ((vFormat & GeometryArray.NORMALS) != 0) {
	            morphedGeo.setNormalIndices(0, igeo.indexNormal);
	        }
	        if ((vFormat & GeometryArray.COLOR) != 0) {
	            morphedGeo.setColorIndices(0, igeo.indexColor);
	        }
	        if ((vFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
	            for (k = 0; k < texCoordSetCount; k++) {
	                 morphedGeo.setTextureCoordinateIndices(k, 0,
                                 igeo.indexTexCoord[k]);
	            }
	        }
            }
	}
	this.morphedGeometryArray.setCapability(GeometryArray.ALLOW_REF_DATA_WRITE);

	GeometryArrayRetained mga = (GeometryArrayRetained)morphedGeometryArray.retained;
	mga.updateData(this);


    }

    void getMirrorShape3D(ArrayList list, HashKey k) {
	Shape3DRetained ms;
	if (inSharedGroup) {
	    ms = getMirrorShape(k);
	}
	else {
	    ms = (Shape3DRetained)mirrorShape3D.get(0);
	}
	list.add(ms);

    }

    @Override
    void compile(CompileState compState) {

        super.compile(compState);

        // XXXX: for now keep the static transform in the parent tg
        compState.keepTG = true;

        if (J3dDebug.devPhase && J3dDebug.debug) {
            compState.numMorphs++;
        }
    }

    void doErrorCheck(GeometryArrayRetained prevGeo, GeometryArrayRetained geo) {

	// If indexed Geometry array check the entire list instead of just the vcount
	if ((prevGeo.vertexFormat != geo.vertexFormat) ||
	    (prevGeo.validVertexCount != geo.validVertexCount) ||
	    (prevGeo.geoType != geo.geoType) ||
	    (prevGeo.texCoordSetCount != geo.texCoordSetCount)) {
	    throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));
	}
	if (geo.getTexCoordSetMapLength() != prevGeo.getTexCoordSetMapLength()){
	    throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));
	}
	int texCoordSetMapLen = geo.getTexCoordSetMapLength();
	int[] prevSvc= prevGeo.texCoordSetMap;
	int[] svc= geo.texCoordSetMap;
	for (int k = 0; k < texCoordSetMapLen; k++) {
	    if (prevSvc[k] != svc[k])
		throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));
	}

	if (geo instanceof GeometryStripArrayRetained) {
	    prevSvc= ((GeometryStripArrayRetained)prevGeo).stripVertexCounts;
	    svc= ((GeometryStripArrayRetained)geo).stripVertexCounts;
	    if (prevSvc.length != svc.length)
		throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));
	    for (int k = 0; k < prevSvc.length; k++) {
		if (prevSvc[k] != svc[k])
		    throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));
	    }
	} else if (geo instanceof IndexedGeometryArrayRetained) {
	    if (((IndexedGeometryArrayRetained)prevGeo).validIndexCount != ((IndexedGeometryArrayRetained)geo).validIndexCount)
		throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));

	    // If by reference, then all array lengths should be same
	    if (geo.getNumCoordCount() != prevGeo.getNumCoordCount() ||
		geo.getNumColorCount() != prevGeo.getNumColorCount() ||
		geo.getNumNormalCount() != prevGeo.getNumNormalCount()) {
		throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));
	    }
	    int texCoordSetCount = geo.getTexCoordSetCount();
	    for (int k = 0; k < texCoordSetCount; k++) {
		if (geo.getNumTexCoordCount(k) != prevGeo.getNumTexCoordCount(k)) {
		    throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));
		}
	    }

	    if (geo instanceof IndexedGeometryStripArrayRetained) {
		prevSvc= ((IndexedGeometryStripArrayRetained)prevGeo).stripIndexCounts;
		svc= ((IndexedGeometryStripArrayRetained)geo).stripIndexCounts;
		if (prevSvc.length != svc.length)
		    throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));
		for (int k = 0; k < prevSvc.length; k++) {
		    if (prevSvc[k] != svc[k])
			throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));
		}
	    }
	}
    }

    @Override
    void handleFrequencyChange(int bit) {
	int mask = 0;
	if (bit == Morph.ALLOW_GEOMETRY_ARRAY_WRITE) {
	    mask = GEOMETRY_CHANGED;
	}
	else if (bit == Morph.ALLOW_APPEARANCE_WRITE) {
	    mask = APPEARANCE_CHANGED;
	}
	else if (bit == Morph.ALLOW_APPEARANCE_OVERRIDE_WRITE) {
	    mask = APPEARANCEOVERRIDE_CHANGED;
	}
	if (mask != 0) {
	    if (source.getCapabilityIsFrequent(bit))
		changedFrequent |= mask;
	    else if (!source.isLive()) {
		changedFrequent &= ~mask;
	    }
	}
    }

    @Override
    void searchGeometryAtoms(UnorderList list) {
	list.add(Shape3DRetained.getGeomAtom(
	     (Shape3DRetained) mirrorShape3D.get(0)));
    }
}









© 2015 - 2024 Weber Informatics LLC | Privacy Policy