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

gov.nasa.worldwind.ogc.collada.ColladaNode Maven / Gradle / Ivy

The newest version!
/*
 * 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;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy