src.gov.nasa.worldwind.ogc.collada.ColladaNode Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of worldwindx Show documentation
Show all versions of worldwindx Show documentation
World Wind is a collection of components that interactively display 3D geographic information within Java applications or applets.
/*
* Copyright (C) 2012 United States Government as represented by the Administrator of the
* National Aeronautics and Space Administration.
* All Rights Reserved.
*/
package gov.nasa.worldwind.ogc.collada;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.ogc.collada.impl.*;
import gov.nasa.worldwind.render.DrawContext;
import gov.nasa.worldwind.util.*;
import java.util.*;
/**
* Represents the COLLADA node element and provides access to its contents.
*
* @author pabercrombie
* @version $Id: ColladaNode.java 1696 2013-10-31 18:46:55Z tgaskins $
*/
public class ColladaNode extends ColladaAbstractObject implements ColladaRenderable
{
/**
* Children of this node. Children may be ColladaNode (direct child of this node) or ColladaInstanceNode (reference
* to a node elsewhere in the current document, or another document).
*/
protected List children;
/** Geometries defined in this node. */
protected List geometries;
/** Shape used to render geometry in this node. */
protected List shapes;
/** Transform matrix for this node. */
protected Matrix matrix;
/**
* Construct an instance.
*
* @param ns the qualifying namespace URI. May be null to indicate no namespace qualification.
*/
public ColladaNode(String ns)
{
super(ns);
}
public Box getLocalExtent(ColladaTraversalContext tc)
{
if (tc == null)
{
String msg = Logging.getMessage("nullValue.TraversalContextIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
// Create shapes for this node, if necessary
if (this.shapes == null)
this.shapes = this.createShapes();
if (this.getMatrix() != null)
{
tc.pushMatrix();
tc.multiplyMatrix(this.getMatrix());
}
ArrayList extents = new ArrayList();
for (ColladaMeshShape shape : this.shapes)
{
Box extent = shape.getLocalExtent(tc);
if (extent != null)
extents.add(extent);
}
if (this.children != null)
{
for (ColladaRenderable node : children)
{
Box extent = node.getLocalExtent(tc);
if (extent != null)
extents.add(extent);
}
}
if (this.getMatrix() != null)
tc.popMatrix();
if (extents.isEmpty())
return null;
return Box.union(extents);
}
/** {@inheritDoc} */
public void preRender(ColladaTraversalContext tc, DrawContext dc)
{
List children = this.getChildren();
if (WWUtil.isEmpty(children))
return;
Matrix matrix = this.getMatrix();
try
{
if (matrix != null && matrix != Matrix.IDENTITY)
{
tc.pushMatrix();
tc.multiplyMatrix(matrix);
}
for (ColladaRenderable node : children)
{
node.preRender(tc, dc);
}
}
finally
{
if (matrix != null && matrix != Matrix.IDENTITY)
tc.popMatrix();
}
}
/** {@inheritDoc} */
public void render(ColladaTraversalContext tc, DrawContext dc)
{
// Create shapes for this node, if necessary
if (this.shapes == null)
this.shapes = this.createShapes();
Matrix matrix = this.getMatrix();
try
{
if (matrix != null && matrix != Matrix.IDENTITY)
{
tc.pushMatrix();
tc.multiplyMatrix(matrix);
}
ColladaRoot root = this.getRoot();
// Apply the current root position and highlight state to shapes in this node. Do this every frame so that
// the node will pickup changes in the root's state.
boolean highlighted = root.isHighlighted();
int altitudeMode = root.getAltitudeMode();
Position position = root.getPosition();
Matrix traversalMatrix = tc.peekMatrix();
for (ColladaMeshShape shape : this.shapes)
{
shape.setModelPosition(position);
shape.setAltitudeMode(altitudeMode);
shape.setHighlighted(highlighted);
shape.render(dc, traversalMatrix);
}
for (ColladaRenderable node : this.getChildren())
{
node.render(tc, dc);
}
}
finally
{
if (matrix != null && matrix != Matrix.IDENTITY)
tc.popMatrix();
}
}
/**
* Create shapes to render this node.
*
* @return List shapes. The list may be empty, but will never be null.
*/
protected List createShapes()
{
if (WWUtil.isEmpty(this.geometries))
return Collections.emptyList();
List shapes = new ArrayList();
for (ColladaInstanceGeometry geometry : this.geometries)
{
this.createShapesForGeometry(geometry, shapes);
}
return shapes;
}
/**
* Create shapes for a geometry.
*
* @param geomInstance Geometry for which to create shapes.
* @param shapes List to collect the new shapes.
*/
protected void createShapesForGeometry(ColladaInstanceGeometry geomInstance, List shapes)
{
ColladaGeometry geometry = geomInstance.get();
if (geometry == null)
return;
ColladaMesh mesh = geometry.getMesh();
if (mesh == null)
return;
ColladaBindMaterial bindMaterial = geomInstance.getBindMaterial();
ColladaRoot root = this.getRoot();
List triangles = mesh.getTriangles();
if (!WWUtil.isEmpty(triangles))
{
ColladaMeshShape newShape = ColladaMeshShape.createTriangleMesh(triangles, bindMaterial);
newShape.setDelegateOwner(root);
shapes.add(newShape);
}
List lines = mesh.getLines();
if (!WWUtil.isEmpty(lines))
{
ColladaMeshShape newShape = ColladaMeshShape.createLineMesh(lines, bindMaterial);
newShape.setDelegateOwner(root);
shapes.add(newShape);
}
}
@Override
public void setField(String keyName, Object value)
{
if ("node".equals(keyName) || "instance_node".equals(keyName))
{
if (this.children == null)
this.children = new ArrayList();
this.children.add((ColladaRenderable) value);
}
else if ("instance_geometry".equals(keyName))
{
if (this.geometries == null)
this.geometries = new ArrayList();
this.geometries.add((ColladaInstanceGeometry) value);
}
else
{
super.setField(keyName, value);
}
}
/**
* Indicates the children of this node. Children may be other node elements contained directly within this node, or
* other nodes referenced indirectly by a instance_node element.
*
* @return List of children. The list may be empty, but will never be null.
*/
protected List getChildren()
{
return this.children != null ? this.children : Collections.emptyList();
}
/**
* Indicates the transform matrix specified in this node.
*
* @return The matrix specified in this node. Returns the identity matrix if the node does not specify a matrix.
*/
protected Matrix getMatrix()
{
if (this.matrix != null)
return this.matrix;
// TODO a node can have more than one matrix
ColladaMatrix matrix = (ColladaMatrix) this.getField("matrix");
if (matrix == null)
{
// Set matrix to identity so that we won't look for it again.
this.matrix = Matrix.IDENTITY;
return this.matrix;
}
String matrixAsString = matrix.getCharacters();
String linesCleaned = matrixAsString.replaceAll("\n", " ");
double[] doubles = this.parseDoubleArray(linesCleaned);
this.matrix = Matrix.fromArray(doubles, 0, true);
return this.matrix;
}
/**
* Parse a string of doubles into a double[].
*
* @param doubleArrayString String of doubles, separated by whitespace.
*
* @return Parsed double[]
*/
protected double[] parseDoubleArray(String doubleArrayString)
{
String[] arrayOfNumbers = doubleArrayString.trim().split("\\s+");
double[] doubles = new double[arrayOfNumbers.length];
int i = 0;
for (String s : arrayOfNumbers)
{
doubles[i++] = Double.parseDouble(s);
}
return doubles;
}
}