/*
 * GeometryCounter.java
 *
 * Created on May 9, 2003, 12:57 AM
 */


import javax.media.j3d.*;
import com.sun.j3d.utils.geometry.Primitive;

/**
 *
 * @author  Ian Nieves
 */
public class GeometryCounter {
    
    // This method can output the triangle count of any given Node.  It will recurse into the initial
    // Node, eventually counting triangles of all reachable children.  Nodes that can be counted include
    // Switch, Primitive, BranchGroup, OrderedGroup, TransformGroup, SharedGroup/Link, Group, Shape3D (ALL geometry
    // subclasses counted), Background, Morph.  Thus, any place that Geometry can be hidden in subgraph,
    // this method will find it and count it.  In a switch group, only the active switch is counted, NOT
    // all switched.  In a morph node, all geometry arrays are counted.  In a Shape3D all geometries are
    // counted.
    
    // The input parentNode can be part of a live scene graph, or it can be part of a non-live scenegraph.
    // It is generally easier to use this method on a non-live sub-graph because then you do not need to
    // worry about setting capability bits to allow accessing geometry information, etc, and the method
    // should work without a hitch.  However, if you use this method on a live sub-graph, then you must be
    // sure to:
    // set capability bits of Groups to ALLOW_CHILDREN_READ
    // set capability bits of Backgrounds to ALLOW_GEOMETRY_READ
    // set capability bits of Links to ALLOW_SHARED_GROUP_READ
    // set capability bits of Morphs to ALLOW_GEOMETRY_ARRAY_READ
    // set capability bits of Shape3Ds to ALLOW_GEOMETRY_READ
    // set capability bits of GeometryArrays to ALLOW_COUNT_READ
    // As you can see, it may be easier to simply take your sub-graph out of the live scenegraph in order
    // to count its triangles.
    public static long countTrianglesInSubgraph(Node parentNode) {
        
        long triangleCount = 0;
        
        if(parentNode instanceof Switch){
            triangleCount += countTrianglesInSubgraph(((Switch)parentNode).currentChild());
        }
        else if(parentNode instanceof Primitive){
            triangleCount += ((Primitive)parentNode).getNumTriangles();
        }
        else if(parentNode instanceof BranchGroup || parentNode instanceof OrderedGroup || parentNode instanceof TransformGroup || parentNode instanceof SharedGroup || parentNode instanceof Group){
            for(int i = 0; i < ((Group)parentNode).numChildren(); i++)
                triangleCount += countTrianglesInSubgraph(((Group)parentNode).getChild(i));
        }
        else if(parentNode instanceof Shape3D){
            for(int i=0; i < ((Shape3D)parentNode).numGeometries(); i++)
                triangleCount += countTrianglesInGeometry(((Shape3D)parentNode).getGeometry(i));
        }
        else if(parentNode instanceof Background){
            triangleCount += countTrianglesInSubgraph(((Background)parentNode).getGeometry());
        }
        else if(parentNode instanceof Morph){
            for(int i=0; true; i++){
                GeometryArray tempGeometryArray = ((Morph)parentNode).getGeometryArray(i);
                if(!(tempGeometryArray instanceof GeometryArray))
                    break;
                else
                    triangleCount += countTrianglesInGeometry(tempGeometryArray);
            }
        }
        else if(parentNode instanceof Link){
            triangleCount += countTrianglesInSubgraph(((Link)parentNode).getSharedGroup());
        }
        else if(parentNode instanceof BranchGroup || parentNode instanceof OrderedGroup || parentNode instanceof TransformGroup || parentNode instanceof SharedGroup || parentNode instanceof Group){     
            for(int i = 0; i < ((Group)parentNode).numChildren(); i++)
                triangleCount += countTrianglesInSubgraph(((Group)parentNode).getChild(i));
        }
        else{
            System.out.println("ERROR: Encountered unknown Node type: " + parentNode.toString());
        }
            
        
        return triangleCount;
    }
    
    // This method can output the vertex count of any given Node.  It will recurse into the initial
    // Node, eventually counting vertices of all reachable children.  Nodes that can be counted include
    // Switch, Primitive, BranchGroup, OrderedGroup, TransformGroup, SharedGroup/Link, Group, Shape3D (ALL geometry
    // subclasses counted), Background, Morph.  Thus, any place that Geometry can be hidden in subgraph,
    // this method will find it and count it.  In a switch group, only the active switch is counted, NOT
    // all switched.  In a morph node, all geometry arrays are counted.  In a Shape3D all geometries are
    // counted.
    
    // The input parentNode can be part of a live scene graph, or it can be part of a non-live scenegraph.
    // It is generally easier to use this method on a non-live sub-graph because then you do not need to
    // worry about setting capability bits to allow accessing geometry information, etc, and the method
    // should work without a hitch.  However, if you use this method on a live sub-graph, then you must be
    // sure to:
    // set capability bits of Groups to ALLOW_CHILDREN_READ
    // set capability bits of Backgrounds to ALLOW_GEOMETRY_READ
    // set capability bits of Links to ALLOW_SHARED_GROUP_READ
    // set capability bits of Morphs to ALLOW_GEOMETRY_ARRAY_READ
    // set capability bits of Shape3Ds to ALLOW_GEOMETRY_READ
    // set capability bits of GeometryArrays to ALLOW_COUNT_READ
    // As you can see, it may be easier to simply take your sub-graph out of the live scenegraph in order
    // to count its vertices.
    public static long countVerticesInSubgraph(Node parentNode) {
        
        long vertexCount = 0;
        
        if(parentNode instanceof Switch){
            vertexCount += countVerticesInSubgraph(((Switch)parentNode).currentChild());
        }
        else if(parentNode instanceof Primitive){
            vertexCount += ((Primitive)parentNode).getNumTriangles();
        }
        else if(parentNode instanceof BranchGroup || parentNode instanceof OrderedGroup || parentNode instanceof TransformGroup || parentNode instanceof SharedGroup || parentNode instanceof Group){
            for(int i = 0; i < ((Group)parentNode).numChildren(); i++)
                vertexCount += countVerticesInSubgraph(((Group)parentNode).getChild(i));
        }
        else if(parentNode instanceof Shape3D){
            for(int i=0; i < ((Shape3D)parentNode).numGeometries(); i++)
                vertexCount += countVerticesInGeometry(((Shape3D)parentNode).getGeometry(i));
        }
        else if(parentNode instanceof Background){
            vertexCount += countVerticesInSubgraph(((Background)parentNode).getGeometry());
        }
        else if(parentNode instanceof Morph){
            for(int i=0; true; i++){
                GeometryArray tempGeometryArray = ((Morph)parentNode).getGeometryArray(i);
                if(!(tempGeometryArray instanceof GeometryArray))
                    break;
                else
                    vertexCount += countVerticesInGeometry(tempGeometryArray);
            }
        }
        else if(parentNode instanceof Link){
            vertexCount += countVerticesInSubgraph(((Link)parentNode).getSharedGroup());
        }
        else{
            System.out.println("ERROR: Encountered unknown Node type: " + parentNode.toString());          
        }
        
        return vertexCount;
    }
    
    // This method can output the triangle count of any given type of Geometry
    public static long countTrianglesInGeometry(Geometry inGeom){
       
        long polygonCount = 0;
        
        if(inGeom instanceof TriangleFanArray){
            int vertexCounts[] = new int[((TriangleFanArray)inGeom).getNumStrips()];
            ((TriangleFanArray)inGeom).getStripVertexCounts(vertexCounts);
            for(int i = 0; i < vertexCounts.length; i++)
                polygonCount += vertexCounts[i] - 2;
        }
        else if(inGeom instanceof TriangleStripArray){
            TriangleStripArray tsArray = (TriangleStripArray) inGeom;
            int vertexCounts[] = new int[((TriangleStripArray)inGeom).getNumStrips()];
            ((TriangleStripArray)inGeom).getStripVertexCounts(vertexCounts);
            for(int i = 0; i < vertexCounts.length; i++)
                polygonCount += vertexCounts[i] - 2;
        }
        else if(inGeom instanceof IndexedTriangleFanArray){
            int indexCounts[] = new int[((IndexedTriangleFanArray)inGeom).getNumStrips()];
            ((IndexedTriangleFanArray)inGeom).getStripIndexCounts(indexCounts);
            for(int i = 0; i < indexCounts.length; i++)
                polygonCount += indexCounts[i] - 2;
        }
        else if(inGeom instanceof IndexedTriangleStripArray){
            int indexCounts[] = new int[((IndexedTriangleStripArray)inGeom).getNumStrips()];
            ((IndexedTriangleStripArray)inGeom).getStripIndexCounts(indexCounts);
            for(int i = 0; i < indexCounts.length; i++)
                polygonCount += indexCounts[i] - 2;
        }
        else if(inGeom instanceof IndexedQuadArray){
            polygonCount += (((IndexedQuadArray)inGeom).getIndexCount()/4)*2;
        }
        else if(inGeom instanceof IndexedTriangleArray){
            polygonCount += ((IndexedTriangleArray)inGeom).getIndexCount()/3;
        }
        else if(inGeom instanceof QuadArray){
            polygonCount += (((QuadArray)inGeom).getVertexCount()/4)*2;
        }
        else if(inGeom instanceof TriangleArray){
            polygonCount += ((TriangleArray)inGeom).getVertexCount()/3;
        } 
        return polygonCount;
    }
    
    // This method can output the vertex count of any given type of Geometry
    public static long countVerticesInGeometry(Geometry inGeom){
        
        long vertexCount = 0;
        
        if(inGeom instanceof TriangleFanArray){
            int vertexCounts[] = new int[((TriangleFanArray)inGeom).getNumStrips()];
            ((TriangleFanArray)inGeom).getStripVertexCounts(vertexCounts);
            for(int i = 0; i < vertexCounts.length; i++)
                vertexCount += vertexCounts[i];
        }
        else if(inGeom instanceof TriangleStripArray){
            int vertexCounts[] = new int[((TriangleStripArray)inGeom).getNumStrips()];
            ((TriangleStripArray)inGeom).getStripVertexCounts(vertexCounts);
            for(int i = 0; i < vertexCounts.length; i++)
                vertexCount += vertexCounts[i];
        }
        else if(inGeom instanceof IndexedTriangleFanArray){
            int indexCounts[] = new int[((IndexedTriangleFanArray)inGeom).getNumStrips()];
            ((IndexedTriangleFanArray)inGeom).getStripIndexCounts(indexCounts);
            for(int i = 0; i < indexCounts.length; i++)
                vertexCount += indexCounts[i];
        }
        else if(inGeom instanceof IndexedTriangleStripArray){
            int indexCounts[] = new int[((IndexedTriangleStripArray)inGeom).getNumStrips()];
            ((IndexedTriangleStripArray)inGeom).getStripIndexCounts(indexCounts);
            for(int i = 0; i < indexCounts.length; i++)
                vertexCount += indexCounts[i];
        }
        else if(inGeom instanceof LineStripArray){
            int vertexCounts[] = new int[((LineStripArray)inGeom).getNumStrips()];
            ((LineStripArray)inGeom).getStripVertexCounts(vertexCounts);
            for(int i = 0; i < vertexCounts.length; i++)
                vertexCount += vertexCounts[i];
        }
        else if(inGeom instanceof IndexedQuadArray){
            vertexCount += ((IndexedQuadArray)inGeom).getIndexCount();
        }
        else if(inGeom instanceof IndexedTriangleArray){
            vertexCount += ((IndexedTriangleArray)inGeom).getIndexCount();
        }
        else if(inGeom instanceof QuadArray){
            vertexCount += ((QuadArray)inGeom).getVertexCount();
        }
        else if(inGeom instanceof TriangleArray){
            vertexCount += ((TriangleArray)inGeom).getVertexCount();
        }
        else if(inGeom instanceof IndexedLineArray){
            vertexCount += ((IndexedLineArray)inGeom).getIndexCount();
        }
        else if(inGeom instanceof IndexedPointArray){
            vertexCount += ((IndexedPointArray)inGeom).getIndexCount();
        }
        else if(inGeom instanceof LineArray){
            vertexCount += ((LineArray)inGeom).getVertexCount();
        }
        else if(inGeom instanceof PointArray){
            vertexCount += ((PointArray)inGeom).getVertexCount();
        }
        return vertexCount;
    }
}