//===============================================================================
// @ IvIndexedGeometry.cpp
// ------------------------------------------------------------------------------
// Abstract scene graph object that supports rendering a geometry
//
// Copyright (C) 2004 by Elsevier, Inc. All rights reserved.
//
//
//
//===============================================================================

//-------------------------------------------------------------------------------
//-- Dependencies ---------------------------------------------------------------
//-------------------------------------------------------------------------------
#include "IvIndexedGeometry.h"
#include <IvGLHelp.h>
#include <IvVector3.h>
#include <IvMatrix44.h>

//-------------------------------------------------------------------------------
//-- Static Members -------------------------------------------------------------
//-------------------------------------------------------------------------------

//-------------------------------------------------------------------------------
//-- Methods --------------------------------------------------------------------
//-------------------------------------------------------------------------------

//-------------------------------------------------------------------------------
// @ IvIndexedGeometry::IvIndexedGeometry()
//-------------------------------------------------------------------------------
//
//-------------------------------------------------------------------------------
IvIndexedGeometry::IvIndexedGeometry()
{
    mVerts = 0;
    mNorms = 0;
    mColors = 0;
    mNumVerts = 0;

    mIndices = 0;
    mNumIndices = 0;
}  // End of IvIndexedGeometry::IvIndexedGeometry


//-------------------------------------------------------------------------------
// @ IvIndexedGeometry::~IvIndexedGeometry()
//-------------------------------------------------------------------------------
//
//-------------------------------------------------------------------------------
IvIndexedGeometry::~IvIndexedGeometry()
{
    delete[] mVerts;
    delete[] mNorms;
    delete[] mColors;

    delete[] mIndices;

}  // End of IvIndexedGeometry::~IvIndexedGeometry


//-------------------------------------------------------------------------------
// @ operator<<()
//-------------------------------------------------------------------------------
// Text output for debugging
//-------------------------------------------------------------------------------
IvWriter& 
operator<<(IvWriter& out, const IvIndexedGeometry& source)
{
    // call base class
    out << ((IvGeometry&)source);

    out << source.mNumVerts << eol;

    unsigned int i;
    if (source.mVerts)
    {
        for ( i = 0; i < source.mNumVerts; ++i )
            out << source.mVerts[i] << eol;
    }
    else
    {
        out << "No vertices" << eol;
    }
    out << eol;

    if (source.mNorms)
    {
        for ( i = 0; i < source.mNumVerts; ++i )
            out << source.mNorms[i] << eol;
    }
    else
    {
        out << "No normals" << eol;
    }
    out << eol;

    if (source.mColors)
    {
        for ( i = 0; i < source.mNumVerts; ++i )
            out << source.mColors[i] << eol;
    }
    else
    {
        out << "No colors" << eol;
    }
    out << eol;

    const unsigned int numTris = source.mNumIndices / 3;
    out << numTris;

    if (source.mIndices)
    {
        for ( i = 0; i < numTris; ++i )
        {
            out << source.mIndices[3*i] << ' ' 
               << source.mIndices[3*i + 1] << ' ' 
               << source.mIndices[3*i + 2] << eol;
        }
    }
    else
    {
        out << "No indices" << eol;
    }
    out << eol;

    return out;
    
}   // End of operator<<()
    

//-------------------------------------------------------------------------------
// @ IvIndexedGeometry::CreateFromStream()
//-------------------------------------------------------------------------------
//
// Creates an IvIndexedGeometry object from a file of the following format
//
// VertexCount
//
// Vertex positions X Y Z for each vertex
// ...
//
// Vertex normals X Y Z for each vertex
// ...
// 
// Vertex colors R G B for each vertex
// ...
//
// Triangle index count (count of indices, not triangles, so this should be 3x
// the triangle count
//
// Triangle indices 
// ...
//
//-------------------------------------------------------------------------------
IvIndexedGeometry* IvIndexedGeometry::CreateFromStream(IvReader& in)
{
    IvIndexedGeometry* geom = new IvIndexedGeometry;
    
    // get number of vertices
    in >> geom->mNumVerts;
    if ( !in.good() )
        goto error_exit;

    // read verts
    geom->mVerts = new IvVector3[geom->mNumVerts];
    unsigned int i;
    for ( i = 0; i < geom->mNumVerts; ++i )
    {
        in >> geom->mVerts[i].x >> geom->mVerts[i].y 
            >> geom->mVerts[i].z;
        if (!in.good() )
            goto error_exit;
    }

    // read normals
    geom->mNorms = new IvVector3[geom->mNumVerts];
    for ( i = 0; i < geom->mNumVerts; ++i )
    {
        in >> geom->mNorms[i].x >> geom->mNorms[i].y 
            >> geom->mNorms[i].z;
        if (!in.good() )
            goto error_exit;
    }

    // read colors
    geom->mColors = new IvVector3[geom->mNumVerts];
    for ( i = 0; i < geom->mNumVerts; ++i )
    {
        in >> geom->mColors[i].x >> geom->mColors[i].y >> geom->mColors[i].z;
        if (!in.good() )
            goto error_exit;
    }

    // get number of indices
    in >> geom->mNumIndices;
    if ( !in.good() )
        goto error_exit;

    // read indices
    geom->mIndices = new unsigned short[geom->mNumIndices];
    for ( i = 0; i < geom->mNumIndices; ++i )
    {
        in >> geom->mIndices[i];
        if (!in.good() )
            goto error_exit;
    }

    // initialize the model-space capsule to the vertex data
    geom->mModelCapsule.Set( geom->mVerts, geom->mNumVerts );

    return geom;

error_exit:
    // error cleanup case

    // delete the partially-created object
    delete geom;

    return 0;
}  // End of IvIndexedGeometry::CreateFromStream


//-------------------------------------------------------------------------------
// @ IvIndexedGeometry::Render()
//-------------------------------------------------------------------------------
//
// Draws the indexed geometry object using vertex arrays
//
//-------------------------------------------------------------------------------
void IvIndexedGeometry::Render()
{
    IvGeometry::Render();

    // Render the given arrays as a set of indexed triangles
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);

    glVertexPointer(3, GL_FLOAT, 0, mVerts); 
    glNormalPointer(GL_FLOAT, 0, mNorms); 
    glColorPointer(3, GL_FLOAT, 0, mColors); 
    
    glDrawElements(GL_TRIANGLES, mNumIndices, GL_UNSIGNED_SHORT, 
        mIndices);

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);

    if (gDisplayLeafBounds)
    {
        glPolygonMode(GL_FRONT, GL_LINE);

        IvSetWorldIdentity();
        IvSetColor( 1.0f, 0.5f, 0.0f );
        IvDrawCapsule(mWorldCapsule.GetSegment(), mWorldCapsule.GetRadius());
        glPolygonMode(GL_FRONT, GL_FILL);
    }
       
    if (gDisplayHierarchyBounds)
    {
        glPolygonMode(GL_FRONT, GL_LINE);
        IvMatrix44 ident;
        ident.Identity();
        ident(0,3) = mWorldSphere.GetCenter().x;
        ident(1,3) = mWorldSphere.GetCenter().y;
        ident(2,3) = mWorldSphere.GetCenter().z;

        IvSetWorldMatrix(ident);
        IvSetColor( 1.0f, 1.0f, 0.0f );
        IvDrawSphere(mWorldSphere.GetRadius());

        glPolygonMode(GL_FRONT, GL_FILL);
    }

}  // End of IvIndexedGeometry::Render

