/**	
	Company:		Shout Interactive
	Project:		Custom Nodes
	Class:			Pyramid
	Date:			August 31, 1999
	Description:	Pyramid geometry, subclass of IndexedFaceSet 
	(C) Copyright Shout Interactive, Inc. - 1997/1998/1999 - All rights reserved
 */

package custom_nodes;

import  shout3d.core.*;

/**
 * Pyramid.
 * 
 * Subclass of IndexedFaceSet
 * Adds three fields -- height width and depth.
 * When any of these changes, the Pyramid recalculates the 
 * vertices of its geometry.
 * 
 * @author Paul Isaacs
 * @author Jim Stewartson
 * @author Dave Westwood
 */

public class Pyramid extends IndexedFaceSet implements FieldObserver {
	
	final public    FloatField	width  = new FloatField(this, "width",  Field.NON_NEGATIVE_FLOAT, 1);
	final public    FloatField	height = new FloatField(this, "height", Field.NON_NEGATIVE_FLOAT, 1);
	final public    FloatField	depth  = new FloatField(this, "depth",  Field.NON_NEGATIVE_FLOAT, 1);
	
	private float[] normalizedCoords = { -1, -1,  1,     1, -1,  1, 
										  1, -1, -1,    -1, -1, -1, 
										  0,  1,  0 };
	private int[]   myCoordIndex  = {	0, 3, 2,  1, -1,  // base is a quad
			   			 				0, 1, 4, -1, 
										1, 2, 4, -1, 
										2, 3, 4, -1, 
										3, 0, 4, -1 };
							 
	
	/**
	 * Constructs a default Pyramid
	 */
	public Pyramid(){
		// Watch the 3 new fields to update vertices when they change
		width.addFieldObserver(this, null);
		height.addFieldObserver(this, null);
		depth.addFieldObserver(this, null);
		
		// Set the IFS fields to create the initial geometry.
		calculateVertices();
		coordIndex.setValue(myCoordIndex);
	}
	
	/**
	 *  Clean up. Subclasses must call this from within their own finalize() method
	 */
	protected void finalize() throws Throwable { 
		width.removeFieldObserver(this);
		height.removeFieldObserver(this);
		depth.removeFieldObserver(this);
		super.finalize();
	}
	
	/**
	 * 
	 * Subclasses must call this from within their own onFieldChange() method.
	 * 
	 */
	public void onFieldChange(Field theField, Object userData) {
		if ( theField == width || theField == height || theField == depth) {
			calculateVertices();
		}
		else {
			// Call the super class, it's not a field this node cares about.
			super.onFieldChange(theField, userData);
		}
	}
	
	float[] cVals = null;
	/**
	 * Calculates the values of the vertices based on the width/height/depth 
	 * fields.
	 */
	public void calculateVertices() {
		// Start with the coords in the field, reallocate if there are 
		// the wrong amount.
		Node testNode = coord.getValue();
		Coordinate cNode = null;
		if (testNode != null && testNode instanceof Coordinate)
			cNode = (Coordinate) testNode;
		else {
			cNode = new Coordinate();
			coord.setValue(cNode);
		}
		cVals = cNode.point.getValue();
		if (cVals == null || cVals.length != normalizedCoords.length)
			cVals = new float[normalizedCoords.length];

		// Scale the normalized coords by the fields to create the
		// node's new coordinate values.
		for (int i = 0; i < normalizedCoords.length-2; i += 3){
			cVals[i]   = width.getValue()  * normalizedCoords[i];
			cVals[i+1] = height.getValue() * normalizedCoords[i+1];
			cVals[i+2] = depth.getValue()  * normalizedCoords[i+2];
		}
		
		// Set the coord field with the new values
		cNode.point.setValue(cVals);
	}
}
