

#include <assert.h>
#include "ScenegraphItemI.h"
#include "PajaTypes.h"
#include "ShapeC.h"
#include <algorithm>
#include "ImportableImageI.h"
#include "MaterialC.h"

using namespace Composition;
using namespace PajaTypes;
using namespace FileIO;
using namespace Import;


static
void
TRACE( const char* szFormat, ...  )
{
	char	szMsg[256];
	va_list	rList;
	va_start( rList, szFormat );
	_vsnprintf( szMsg, 255, szFormat, rList );
	va_end( rList );
	OutputDebugString( szMsg );
}


KnotC::KnotC()
{
	// empty
}

KnotC::~KnotC()
{
	// empty
}

void
KnotC::set_knot( const Vector3C& rKnot )
{
	m_rKnot = rKnot;
}

void
KnotC::set_in_vector( const Vector3C& rVec )
{
	m_rInVector = rVec;
}

void
KnotC::set_out_vector( const Vector3C& rVec )
{
	m_rOutVector = rVec;
}

const Vector3C&
KnotC::get_knot() const
{
	return m_rKnot;
}

const Vector3C&
KnotC::get_in_vector() const
{
	return m_rInVector;
}

const Vector3C&
KnotC::get_out_vector() const
{
	return m_rOutVector;
}



PathC::PathC() :
	m_bClosed( false )
{
}

PathC::~PathC()
{
}

void
PathC::add_knot( const KnotC& rKnot )
{
	m_rKnots.push_back( rKnot );
}

uint32
PathC::get_knot_count() const
{
	return m_rKnots.size();
}

const KnotC&
PathC::get_knot( uint32 ui32Index ) const
{
	assert( ui32Index < m_rKnots.size() );
	return m_rKnots[ui32Index];
}

void
PathC::calc_outline()
{
	m_rVertices.clear();

	if( m_rKnots.size() > 1 ) {

		Vector3C	rInKnot, rInVec, rOutVec, rOutKnot;

		int32	i32Next;
		int32	i32KnotCount = m_rKnots.size() - 1;
		if( m_bClosed )
			i32KnotCount = m_rKnots.size();


		m_rVertices.push_back( rInKnot[0] );
		m_rVertices.push_back( rInKnot[1] );
		m_rVertices.push_back( rInKnot[2] );

		for( uint32 i = 0; i < i32KnotCount; i++ ) {

			i32Next = (i + 1) % m_rKnots.size();

			rInKnot = m_rKnots[i].get_knot();
			rInVec = m_rKnots[i].get_out_vector();
			rOutVec = m_rKnots[i32Next].get_in_vector();
			rOutKnot = m_rKnots[i32Next].get_knot();

/*			m_rVertices.push_back( rInKnot[0] );
			m_rVertices.push_back( rInKnot[1] );
			m_rVertices.push_back( rInKnot[2] );

			m_rVertices.push_back( rInVec[0] );
			m_rVertices.push_back( rInVec[1] );
			m_rVertices.push_back( rInVec[2] );

			m_rVertices.push_back( rOutVec[0] );
			m_rVertices.push_back( rOutVec[1] );
			m_rVertices.push_back( rOutVec[2] );
*/

			float32	f32T, f32T2, f32TP1, f32TP2;

			for( uint32 j = 1; j < 16; j++ ) {
				f32T = (float32)j / 15.0f;
				f32T2 = f32T * f32T;
				f32TP1 = 1.0f - f32T;
				f32TP2 = f32TP1 * f32TP1;

				m_rVertices.push_back( rInKnot[0] * f32TP2 * f32TP1 + rInVec[0] * 3 * f32TP2 * f32T + rOutVec[0] * 3 * f32TP1 * f32T2 + rOutKnot[0] * f32T * f32T2 );
				m_rVertices.push_back( rInKnot[1] * f32TP2 * f32TP1 + rInVec[1] * 3 * f32TP2 * f32T + rOutVec[1] * 3 * f32TP1 * f32T2 + rOutKnot[1] * f32T * f32T2 );
				m_rVertices.push_back( rInKnot[2] * f32TP2 * f32TP1 + rInVec[2] * 3 * f32TP2 * f32T + rOutVec[2] * 3 * f32TP1 * f32T2 + rOutKnot[2] * f32T * f32T2 );
			}

		}

/*		m_rVertices.push_back( rOutKnot[0] );
		m_rVertices.push_back( rOutKnot[1] );
		m_rVertices.push_back( rOutKnot[2] );*/
	}
}

uint32
PathC::get_vertex_count() const
{
	return m_rVertices.size() / 3;
}

float32*
PathC::get_vertex_pointer()
{
	return &(m_rVertices[0]);
}

void
PathC::calc_bbox()
{
	if( m_rVertices.size() ) {
		m_rMin = m_rMax = Vector3C( m_rVertices[0], m_rVertices[1], m_rVertices[2] );
		for( uint32 i = 0; i < m_rVertices.size(); i += 3 ) {
			m_rMin[0] = __min( m_rVertices[i + 0], m_rMin[0] );
			m_rMin[1] = __min( m_rVertices[i + 1], m_rMin[1] );
			m_rMin[2] = __min( m_rVertices[i + 2], m_rMin[2] );
			m_rMax[0] = __max( m_rVertices[i + 0], m_rMax[0] );
			m_rMax[1] = __max( m_rVertices[i + 1], m_rMax[1] );
			m_rMax[2] = __max( m_rVertices[i + 2], m_rMax[2] );
		}
		return;
	}
	else if( m_rKnots.size() ) {
		Vector3C	rKnot;
		m_rMin = m_rMax = m_rKnots[0].get_knot();
		for( uint32 i = 1; i < m_rKnots.size(); i++ ) {
			rKnot = m_rKnots[i].get_knot();
			m_rMin[0] = __min( rKnot[0], m_rMin[0] );
			m_rMin[1] = __min( rKnot[1], m_rMin[1] );
			m_rMin[2] = __min( rKnot[2], m_rMin[2] );
			m_rMax[0] = __max( rKnot[0], m_rMax[0] );
			m_rMax[1] = __max( rKnot[1], m_rMax[1] );
			m_rMax[2] = __max( rKnot[2], m_rMax[2] );
		}
		return;
	}

	m_rMin = m_rMax = Vector3C( 0, 0, 0 );
}

Vector3C
PathC::get_bbox_min() const
{
	return m_rMin;
}

Vector3C
PathC::get_bbox_max() const
{
	return m_rMax;
}

void
PathC::set_closed( bool bState )
{
	m_bClosed = bState;
}

bool
PathC::get_closed() const
{
	return m_bClosed;
}


enum PathChunksE {
	CHUNK_PATH_GEOM			= 0x1000,
	CHUNK_PATH_CLOSED		= 0x2000,
};

const uint32	PATH_VERSION = 1;

uint32
PathC::save( SaveC* pSave )
{
	uint32		ui32Error = IO_OK;
	float32		f32Temp3[3];
	uint32		ui32Temp;
	Vector3C	rVec;

	pSave->begin_chunk( CHUNK_PATH_GEOM, PATH_VERSION );
	
		ui32Temp = m_rKnots.size();

		ui32Error = pSave->write( &ui32Temp, sizeof( ui32Temp ) );

		for( uint32 i = 0; i < m_rKnots.size(); i++ ) {
			// knot
			rVec = m_rKnots[i].get_knot();
			f32Temp3[0] = rVec[0];
			f32Temp3[1] = rVec[1];
			f32Temp3[2] = rVec[2];
			ui32Error = pSave->write( f32Temp3, sizeof( f32Temp3 ) );

			// in vec
			rVec = m_rKnots[i].get_in_vector();
			f32Temp3[0] = rVec[0];
			f32Temp3[1] = rVec[1];
			f32Temp3[2] = rVec[2];
			ui32Error = pSave->write( f32Temp3, sizeof( f32Temp3 ) );

			// out vec
			rVec = m_rKnots[i].get_out_vector();
			f32Temp3[0] = rVec[0];
			f32Temp3[1] = rVec[1];
			f32Temp3[2] = rVec[2];
			ui32Error = pSave->write( f32Temp3, sizeof( f32Temp3 ) );
		}

	pSave->end_chunk();

	if( m_bClosed ) {
		pSave->begin_chunk( CHUNK_PATH_CLOSED, PATH_VERSION );
		pSave->end_chunk();
	}

	return ui32Error;
}

uint32
PathC::load( LoadC* pLoad )
{
	uint32	ui32Error = IO_OK;
	float32	f32Temp3[3];
	uint32	i;

	while( (ui32Error = pLoad->open_chunk()) == IO_OK ) {

		switch( pLoad->get_chunk_id() ) {

		case CHUNK_PATH_GEOM:
			if( pLoad->get_chunk_version() == PATH_VERSION ) {

				uint32	ui32KnotCount = 0;
				ui32Error = pLoad->read( &ui32KnotCount, sizeof( ui32KnotCount ) );

				for( i = 0; i < ui32KnotCount; i++ ) {
					KnotC	rKnot;
					// knot
					ui32Error = pLoad->read( f32Temp3, sizeof( f32Temp3 ) );
					rKnot.set_knot( Vector3C( f32Temp3 ) );

					// knot
					ui32Error = pLoad->read( f32Temp3, sizeof( f32Temp3 ) );
					rKnot.set_in_vector( Vector3C( f32Temp3 ) );

					// knot
					ui32Error = pLoad->read( f32Temp3, sizeof( f32Temp3 ) );
					rKnot.set_out_vector( Vector3C( f32Temp3 ) );

					m_rKnots.push_back( rKnot );
				}
			}
			break;

		case CHUNK_PATH_CLOSED:
			if( pLoad->get_chunk_version() == PATH_VERSION ) {
				m_bClosed = true;
			}
			break;
		}

		pLoad->close_chunk();

		if( ui32Error != IO_OK && ui32Error != IO_END ) {
			return ui32Error;
		}
	}

	if( ui32Error != IO_OK && ui32Error != IO_END ) {
		return ui32Error;
	}

	calc_outline();

	return IO_OK;
}



ShapeC::ShapeC() :
	m_pPosCont( 0 ),
	m_pRotCont( 0 ),
	m_pScaleCont( 0 ),
	m_pScaleRotCont( 0 ),
	m_pVisCont( 0 ),
	m_bVis( true ),
	m_rDiffuse( 1, 1, 1 ),
	m_bTransparent( false ),
	m_f32Shininess( 0 ),
	m_f32Transparency( 0 ),
	m_f32SelfIllum( 0 ),
	m_bAdditive( false )
{
	// empty
}

ShapeC::~ShapeC()
{
	delete m_pPosCont;
	delete m_pRotCont;
	delete m_pScaleCont;
	delete m_pScaleRotCont;
	delete m_pVisCont;

	uint32	i;

	for( i = 0; i < m_rPaths.size(); i++ )
		delete m_rPaths[i];
	m_rPaths.clear();
}

int32
ShapeC::get_type()
{
	return CGITEM_SHAPE;
}

void
ShapeC::set_position( const Vector3C& rPos )
{
	m_rPosition = rPos;
}


const
Vector3C&
ShapeC::get_position()
{
	return m_rPosition;
}

void
ShapeC::set_scale( const Vector3C& rScale )
{
	m_rScale = rScale;
}

const
Vector3C&
ShapeC::get_scale()
{
	return m_rScale;
}

void
ShapeC::set_rotation( const QuatC& rRot )
{
	m_rRotation = rRot;
}

const
QuatC&
ShapeC::get_rotation()
{
	return m_rRotation;
}

void
ShapeC::set_scale_rotation( const QuatC& rRot )
{
	m_rScaleRot = rRot;
}

const
QuatC&
ShapeC::get_scale_rotation()
{
	return m_rScaleRot;
}


void
ShapeC::eval_state( int32 i32Time )
{
	if( m_pVisCont )
		m_bVis = m_pVisCont->get_value( i32Time );

	if( m_pPosCont )
		m_rPosition = m_pPosCont->get_value( i32Time );
	if( m_pScaleCont )
		m_rScale = m_pScaleCont->get_value( i32Time );
	if( m_pScaleRotCont ) {
		m_rScaleRot = m_pScaleRotCont->get_value( i32Time );
	}
	if( m_pRotCont )
		m_rRotation = m_pRotCont->get_value( i32Time );


	Matrix3C	rScaleMat;
	Matrix3C	rScaleRotMat;
	Matrix3C	rRotMat;
	Matrix3C	rInvScaleRotMat;
	QuatC		rScaleRot( m_rScaleRot );
	QuatC		rRot( m_rRotation );
	QuatC		rInvScaleRot = rScaleRot.unit_inverse();

	rScaleMat.set_scale( m_rScale );
	rScaleRotMat.set_rot( rScaleRot );
	rRotMat.set_rot( rRot );
	rInvScaleRotMat.set_rot( rInvScaleRot );

	// Compose matrix
	m_rTM = rInvScaleRotMat * rScaleMat * rScaleRotMat * rRotMat;
	m_rTM[3] = m_rPosition;

	if( m_pParent )
		m_rTM *= m_pParent->get_tm();
}

void
ShapeC::eval_geom( int32 i32Time )
{
	// empty
}


void
ShapeC::set_position_controller( ContVector3C* pCont )
{
	m_pPosCont = pCont;
}

ContVector3C*
ShapeC::get_position_controller()
{
	return m_pPosCont;
}

void
ShapeC::set_rotation_controller( ContQuatC* pCont )
{
	m_pRotCont = pCont;
}

ContQuatC*
ShapeC::get_rotation_controller()
{
	return m_pRotCont;
}

void
ShapeC::set_scale_controller( ContVector3C* pCont )
{
	m_pScaleCont = pCont;
}

ContVector3C*
ShapeC::get_scale_controller()
{
	return m_pScaleCont;
}

void
ShapeC::set_scale_rotation_controller( ContQuatC* pCont )
{
	m_pScaleRotCont = pCont;
}

ContQuatC*
ShapeC::get_scale_rotation_controller()
{
	return m_pScaleRotCont;
}

void
ShapeC::set_vis_controller( ContBoolC* pCont )
{
	m_pVisCont = pCont;
}

ContBoolC*
ShapeC::get_vis_controller()
{
	return m_pVisCont;
}

bool
ShapeC::get_visible() const
{
	return m_bVis;
}


void
ShapeC::add_path( PathC* pPath )
{
	m_rPaths.push_back( pPath );
}

uint32
ShapeC::get_path_count() const
{
	return m_rPaths.size();
}

PathC*
ShapeC::get_path( uint32 ui32Index )
{
	assert( ui32Index < m_rPaths.size() );
	return m_rPaths[ui32Index];
}


void
ShapeC::calc_outline()
{
	for( uint32 i = 0; i < m_rPaths.size(); i++ )
		m_rPaths[i]->calc_outline();
}


void
ShapeC::calc_bbox()
{
	if( m_rPaths.size() ) {

		Vector3C	rMin, rMax;

		m_rPaths[0]->calc_bbox();
		m_rMin = m_rPaths[0]->get_bbox_min();
		m_rMax = m_rPaths[0]->get_bbox_max();

		for( uint32 i = 1; i < m_rPaths.size(); i++ ) {

			m_rPaths[i]->calc_bbox();
			m_rMin = m_rPaths[i]->get_bbox_min();
			m_rMax = m_rPaths[i]->get_bbox_max();

			m_rMin[0] = __min( rMin[0], m_rMin[0] );
			m_rMin[1] = __min( rMin[1], m_rMin[1] );
			m_rMin[2] = __min( rMin[2], m_rMin[2] );
			m_rMax[0] = __max( rMax[0], m_rMax[0] );
			m_rMax[1] = __max( rMax[1], m_rMax[1] );
			m_rMax[2] = __max( rMax[2], m_rMax[2] );
		}
		return;
	}

	m_rMin = m_rMax = Vector3C( 0, 0, 0 );
}

Vector3C
ShapeC::get_bbox_min() const
{
	return m_rMin;
}

Vector3C
ShapeC::get_bbox_max() const
{
	return m_rMax;
}


// material
void
ShapeC::set_ambient( const ColorC &rAmbient )
{
	m_rAmbient = rAmbient;
}

void
ShapeC::set_diffuse( const ColorC &rDiffuse )
{
	m_rDiffuse = rDiffuse;
}

void
ShapeC::set_specular( const ColorC &rSpecular )
{
	m_rSpecular = rSpecular;
}

void
ShapeC::set_shininess( const float32 f32Shininess )
{
	m_f32Shininess = f32Shininess;
}

void
ShapeC::set_transparency( const float32 f32Trans )
{
	m_f32Transparency = f32Trans;

	if( m_f32Transparency > 0.001f )
		m_bTransparent = true;
}

void
ShapeC::set_selfillum( const float32 f32SelfIllum )
{
	m_f32SelfIllum = f32SelfIllum;
}

const ColorC&
ShapeC::get_ambient() const
{
	return m_rAmbient;
}

const ColorC&
ShapeC::get_diffuse() const
{
	return m_rDiffuse;
}

const ColorC&
ShapeC::get_specular() const
{
	return m_rSpecular;
}

float32
ShapeC::get_shininess() const
{
	return m_f32Shininess;
}

float32
ShapeC::get_transparency() const
{
	return m_f32Transparency;
}

float32
ShapeC::get_selfillum() const
{
	return m_f32SelfIllum;
}

bool
ShapeC::is_transparent() const
{
	return m_bTransparent;
}

void
ShapeC::set_additive( bool bState )
{
	m_bAdditive = bState;
}

bool
ShapeC::get_additive() const
{
	return m_bAdditive;
}


void
ShapeC::update_dependencies( std::vector<ScenegraphItemI*> rScenegraph )
{
	uint32	i;
	// find parent
	m_pParent = 0;
	if( !m_sParentName.empty() ) {
		for( i = 0; i < rScenegraph.size(); i++ ) {
			if( m_sParentName.compare( rScenegraph[i]->get_name() ) == 0 ) {
				m_pParent = rScenegraph[i];
				break;
			}
		}
	}
}


enum ShapeChunksE {
	CHUNK_SHAPE_BASE			= 0x1000,
	CHUNK_SHAPE_STATIC			= 0x1001,
	CHUNK_SHAPE_PATH			= 0x1002,
	CHUNK_SHAPE_MATERIAL		= 0x1003,
	CHUNK_SHAPE_ADDITIVE		= 0x1004,
	CHUNK_SHAPE_CONT_POS		= 0x2000,
	CHUNK_SHAPE_CONT_ROT		= 0x2001,
	CHUNK_SHAPE_CONT_SCALE		= 0x2002,
	CHUNK_SHAPE_CONT_SCALEROT	= 0x2003,
	CHUNK_SHAPE_CONT_VIS		= 0x2004,
};

const uint32	SHAPE_VERSION = 1;

uint32
ShapeC::save( SaveC* pSave )
{
	uint32	ui32Error = IO_OK;
	float32	f32Temp3[3];
	float32	f32Temp4[4];
	uint8	ui8Color[4];
	uint32	i;

	eval_state( 0 );


	// Sace scenegraphitem base.
	pSave->begin_chunk( CHUNK_SHAPE_BASE, SHAPE_VERSION );
		ScenegraphItemI::save( pSave );
	pSave->end_chunk();

	// Save static transformation.
	pSave->begin_chunk( CHUNK_SHAPE_STATIC, SHAPE_VERSION );
		// position
		f32Temp3[0] = m_rPosition[0];
		f32Temp3[1] = m_rPosition[1];
		f32Temp3[2] = m_rPosition[2];
		ui32Error = pSave->write( f32Temp3, sizeof( f32Temp3 ) );
		// rotation
		f32Temp4[0] = m_rRotation[0];
		f32Temp4[1] = m_rRotation[1];
		f32Temp4[2] = m_rRotation[2];
		f32Temp4[3] = m_rRotation[3];
		ui32Error = pSave->write( f32Temp4, sizeof( f32Temp4 ) );
		// scale
		f32Temp3[0] = m_rScale[0];
		f32Temp3[1] = m_rScale[1];
		f32Temp3[2] = m_rScale[2];
		ui32Error = pSave->write( f32Temp3, sizeof( f32Temp3 ) );
		// scale rot
		f32Temp4[0] = m_rScaleRot[0];
		f32Temp4[1] = m_rScaleRot[1];
		f32Temp4[2] = m_rScaleRot[2];
		f32Temp4[3] = m_rScaleRot[3];
		ui32Error = pSave->write( f32Temp4, sizeof( f32Temp4 ) );
	pSave->end_chunk();


	pSave->begin_chunk( CHUNK_SHAPE_MATERIAL, SHAPE_VERSION );
		//ambient
		ui8Color[0] = (uint8)(m_rAmbient[0] * 255.0f);
		ui8Color[1] = (uint8)(m_rAmbient[1] * 255.0f);
		ui8Color[2] = (uint8)(m_rAmbient[2] * 255.0f);
		ui8Color[3] = (uint8)(m_rAmbient[3] * 255.0f);
		ui32Error = pSave->write( ui8Color, 4 );

		//diffuse
		ui8Color[0] = (uint8)(m_rDiffuse[0] * 255.0f);
		ui8Color[1] = (uint8)(m_rDiffuse[1] * 255.0f);
		ui8Color[2] = (uint8)(m_rDiffuse[2] * 255.0f);
		ui8Color[3] = (uint8)(m_rDiffuse[3] * 255.0f);
		ui32Error = pSave->write( ui8Color, 4 );

		//specular
		ui8Color[0] = (uint8)(m_rSpecular[0] * 255.0f);
		ui8Color[1] = (uint8)(m_rSpecular[1] * 255.0f);
		ui8Color[2] = (uint8)(m_rSpecular[2] * 255.0f);
		ui8Color[3] = (uint8)(m_rSpecular[3] * 255.0f);
		ui32Error = pSave->write( ui8Color, 4 );

		// shininess
		ui32Error = pSave->write( &m_f32Shininess, sizeof( m_f32Shininess ) );

		// transparency
		ui32Error = pSave->write( &m_f32Transparency, sizeof( m_f32Transparency ) );

		if( m_f32Transparency > 0.001f )
			m_bTransparent = true;

		// self illumination
		ui32Error = pSave->write( &m_f32SelfIllum, sizeof( m_f32SelfIllum ) );

	pSave->end_chunk();


	// index paths
	for( i = 0; i < m_rPaths.size(); i++ ) {
		pSave->begin_chunk( CHUNK_SHAPE_PATH, SHAPE_VERSION );
			m_rPaths[i]->save( pSave );
		pSave->end_chunk();
	}

	// pos controller
	if( m_pPosCont ) {
		pSave->begin_chunk( CHUNK_SHAPE_CONT_POS, SHAPE_VERSION );
			m_pPosCont->save( pSave );
		pSave->end_chunk();
	}

	// rot controller
	if( m_pRotCont ) {
		pSave->begin_chunk( CHUNK_SHAPE_CONT_ROT, SHAPE_VERSION );
			m_pRotCont->save( pSave );
		pSave->end_chunk();
	}

	// scale controller
	if( m_pScaleCont ) {
		pSave->begin_chunk( CHUNK_SHAPE_CONT_SCALE, SHAPE_VERSION );
			m_pScaleCont->save( pSave );
		pSave->end_chunk();
	}

	// scale rot controller
	if( m_pScaleRotCont ) {
		pSave->begin_chunk( CHUNK_SHAPE_CONT_SCALEROT, SHAPE_VERSION );
			m_pScaleRotCont->save( pSave );
		pSave->end_chunk();
	}

	// visibility controller
	if( m_pVisCont ) {
		pSave->begin_chunk( CHUNK_SHAPE_CONT_VIS, SHAPE_VERSION );
			m_pVisCont->save( pSave );
		pSave->end_chunk();
	}

	if( m_bAdditive ) {
		pSave->begin_chunk( CHUNK_SHAPE_ADDITIVE, SHAPE_VERSION );
		pSave->end_chunk();
	}

	return ui32Error;
}

uint32
ShapeC::load( LoadC* pLoad )
{
	uint32	ui32Error = IO_OK;
	float32	f32Temp3[3];
	float32	f32Temp4[4];
	uint8	ui8Color[4];

	while( (ui32Error = pLoad->open_chunk()) == IO_OK ) {

		switch( pLoad->get_chunk_id() ) {

		case CHUNK_SHAPE_BASE:
			if( pLoad->get_chunk_version() == SHAPE_VERSION )
				ScenegraphItemI::load( pLoad );
			break;

		case CHUNK_SHAPE_STATIC:
			if( pLoad->get_chunk_version() == SHAPE_VERSION ) {

				// position
				ui32Error = pLoad->read( f32Temp3, sizeof( f32Temp3 ) );
				m_rPosition[0] = f32Temp3[0];
				m_rPosition[1] = f32Temp3[1];
				m_rPosition[2] = f32Temp3[2];

				// rotation
				ui32Error = pLoad->read( f32Temp4, sizeof( f32Temp4 ) );
				m_rRotation[0] = f32Temp4[0];
				m_rRotation[1] = f32Temp4[1];
				m_rRotation[2] = f32Temp4[2];
				m_rRotation[3] = f32Temp4[3];

				// scale
				ui32Error = pLoad->read( f32Temp3, sizeof( f32Temp3 ) );
				m_rScale[0] = f32Temp3[0];
				m_rScale[1] = f32Temp3[1];
				m_rScale[2] = f32Temp3[2];

				// scale rot
				ui32Error = pLoad->read( f32Temp4, sizeof( f32Temp4 ) );
				m_rScaleRot[0] = f32Temp4[0];
				m_rScaleRot[1] = f32Temp4[1];
				m_rScaleRot[2] = f32Temp4[2];
				m_rScaleRot[3] = f32Temp4[3];
			}
			break;

		case CHUNK_SHAPE_PATH:
			if( pLoad->get_chunk_version() == SHAPE_VERSION ) {
				PathC*	pPath = new PathC;
				pPath->load( pLoad );
				add_path( pPath );
			}
			break;

		case CHUNK_SHAPE_MATERIAL:
			if( pLoad->get_chunk_version() == SHAPE_VERSION ) {
				//ambient
				ui32Error = pLoad->read( ui8Color, 4 );
				m_rAmbient.convert_from_uint8( ui8Color[0], ui8Color[1], ui8Color[2], ui8Color[3] );

				//diffuse
				ui32Error = pLoad->read( ui8Color, 4 );
				m_rDiffuse.convert_from_uint8( ui8Color[0], ui8Color[1], ui8Color[2], ui8Color[3] );

				//specular
				ui32Error = pLoad->read( ui8Color, 4 );
				m_rSpecular.convert_from_uint8( ui8Color[0], ui8Color[1], ui8Color[2], ui8Color[3] );

				// shininess
				ui32Error = pLoad->read( &m_f32Shininess, sizeof( m_f32Shininess ) );

				// transparency
				ui32Error = pLoad->read( &m_f32Transparency, sizeof( m_f32Transparency ) );
				if( m_f32Transparency > 0.001f )
					m_bTransparent = true;

				// self illumination
				ui32Error = pLoad->read( &m_f32SelfIllum, sizeof( m_f32SelfIllum ) );
			}
			break;

		case CHUNK_SHAPE_CONT_POS:
			if( pLoad->get_chunk_version() == SHAPE_VERSION ) {
				ContVector3C*	pCont = new ContVector3C;
				ui32Error = pCont->load( pLoad );
				m_pPosCont = pCont;
			}
			break;

		case CHUNK_SHAPE_CONT_ROT:
			if( pLoad->get_chunk_version() == SHAPE_VERSION ) {
				ContQuatC*	pCont = new ContQuatC;
				ui32Error = pCont->load( pLoad );
				m_pRotCont = pCont;
			}
			break;

		case CHUNK_SHAPE_CONT_SCALE:
			if( pLoad->get_chunk_version() == SHAPE_VERSION ) {
				ContVector3C*	pCont = new ContVector3C;
				ui32Error = pCont->load( pLoad );
				m_pScaleCont = pCont;
			}
			break;

		case CHUNK_SHAPE_CONT_SCALEROT:
			if( pLoad->get_chunk_version() == SHAPE_VERSION ) {
				ContQuatC*	pCont = new ContQuatC;
				ui32Error = pCont->load( pLoad );
				m_pScaleRotCont = pCont;
			}
			break;

		case CHUNK_SHAPE_CONT_VIS:
			if( pLoad->get_chunk_version() == SHAPE_VERSION ) {
				ContBoolC*	pCont = new ContBoolC;
				ui32Error = pCont->load( pLoad );
				m_pVisCont = pCont;
			}
			break;

		case CHUNK_SHAPE_ADDITIVE:
			if( pLoad->get_chunk_version() == SHAPE_VERSION ) {
				m_bAdditive = true;
			}
			break;

		default:
			assert( 0 );
		}

		pLoad->close_chunk();

		if( ui32Error != IO_OK && ui32Error != IO_END ) {
			return ui32Error;
		}
	}

	if( ui32Error != IO_OK && ui32Error != IO_END ) {
		return ui32Error;
	}

	calc_bbox();

	return IO_OK;
}
