
#include "TCSetC.h"
#include "PajaTypes.h"
#include <assert.h>
#include <memory.h>	// memcpy
#include "minilzo.h"

using namespace PajaTypes;
using namespace FileIO;

//
// coord
//

TextureCoordC::TextureCoordC()
{
	// empty
}

TextureCoordC::TextureCoordC( float32 f32U, float32 f32V, float32 f32W )
{
	m_f32Coords[0] = f32U;
	m_f32Coords[1] = f32V;
	m_f32Coords[2] = f32W;
}

TextureCoordC::TextureCoordC( const TextureCoordC& rCoord )
{
	m_f32Coords[0] = rCoord.m_f32Coords[0];
	m_f32Coords[1] = rCoord.m_f32Coords[1];
	m_f32Coords[2] = rCoord.m_f32Coords[2];
}

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


//
// set
//

TCSetC::TCSetC() :
	m_ui16IndexCount( 0 ),
	m_ui16CoordCount( 0 ),
	m_pIndices( 0 ),
	m_pCoords( 0 ),
	m_eAxis( AXIS_UV ),
	m_ui32Index1( 0 ),
	m_ui32Index2( 1 )
{	
	// empty
}

TCSetC::~TCSetC()
{
	delete m_pCoords;
	delete m_pIndices;
}


TCSetC&
TCSetC::operator=( const TCSetC& rSet )
{
	m_ui16IndexCount = rSet.m_ui16IndexCount;
	m_ui16CoordCount = rSet.m_ui16CoordCount;

	delete m_pIndices;
	m_pIndices = 0;
	if( m_ui16IndexCount ) {
		m_pIndices = new uint16[m_ui16IndexCount];
		memcpy( m_pIndices, rSet.m_pIndices, sizeof( uint16 ) * m_ui16IndexCount );
	}

	delete m_pCoords;
	m_pCoords = 0;
	if( m_ui16CoordCount ) {
		m_pCoords = new float32[(int32)m_ui16CoordCount * 2];
		memcpy( m_pCoords, rSet.m_pCoords, sizeof( float32 ) * (int32)m_ui16CoordCount * 2 );
	}

	m_eAxis = rSet.m_eAxis;
	m_ui32Index1 = rSet.m_ui32Index1;
	m_ui32Index2 = rSet.m_ui32Index2;

	return *this;
}

void
TCSetC::reserve_coords( uint16 ui16Size )
{
	delete m_pCoords;
	m_pCoords = 0;

	if( ui16Size )
		m_pCoords = new float32[(uint32)ui16Size * 2];

	m_ui16CoordCount = ui16Size;
}

void
TCSetC::reserve_indices( uint16 ui16Size )
{
	delete m_pIndices;
	m_pIndices = 0;

	if( ui16Size )
		m_pIndices = new uint16[ui16Size];

	m_ui16IndexCount = ui16Size;
}

void
TCSetC::set_index( uint16 ui16Idx, uint16 ui16Index )
{
	assert( ui16Idx >= 0 && ui16Idx < m_ui16IndexCount );
	m_pIndices[ui16Idx] = ui16Index;
}

void
TCSetC::set_coord( uint16 ui16Idx, const TextureCoordC& rCoord )
{
	assert( ui16Idx >= 0 && ui16Idx < m_ui16CoordCount );
	uint32	ui32Offset = (uint32)ui16Idx * 2;

	m_pCoords[ui32Offset] = rCoord[m_ui32Index1];
	m_pCoords[ui32Offset + 1] = rCoord[m_ui32Index2];
}

uint16
TCSetC::get_index( uint16 ui16Idx )
{
	assert( ui16Idx < m_ui16IndexCount );
	return m_pIndices[ui16Idx];
}

TextureCoordC
TCSetC::get_coord( uint16 ui16Idx )
{
	assert( ui16Idx < m_ui16CoordCount );
	uint32	ui32Offset = (uint32)ui16Idx * 2;

	if( m_eAxis == AXIS_UV )
		return TextureCoordC( m_pCoords[ui32Offset], m_pCoords[ui32Offset + 1], 0 );
	else if( m_eAxis == AXIS_VW )
		return TextureCoordC( 0, m_pCoords[ui32Offset], m_pCoords[ui32Offset + 1] );
	else if( m_eAxis == AXIS_WU )
		return TextureCoordC( m_pCoords[ui32Offset + 1], 0, m_pCoords[ui32Offset] );

	return TextureCoordC();
}

uint16*
TCSetC::get_index_pointer()
{
	return m_pIndices;
}

float32*
TCSetC::get_coord_pointer()
{
	return m_pCoords;
}

void
TCSetC::set_mapping_axis( MappingAxisE eAxis )
{
	m_eAxis = eAxis;

	if( m_eAxis == AXIS_UV ) {
		m_ui32Index1 = 0;
		m_ui32Index2 = 1;
	}
	else if( m_eAxis == AXIS_VW ) {
		m_ui32Index1 = 1;
		m_ui32Index2 = 2;
	}
	else if( m_eAxis == AXIS_WU ) {
		m_ui32Index1 = 2;
		m_ui32Index2 = 0;
	}
}

TCSetC::MappingAxisE
TCSetC::get_mapping_axis()
{
	return m_eAxis;
}

uint16
TCSetC::get_index_count()
{
	return m_ui16IndexCount;
}

uint16
TCSetC::get_coord_count()
{
	return m_ui16CoordCount;
}


uint32
TCSetC::write_compressed( SaveC* pSave, uint8* pBuffer, uint32 ui32BufferSize, uint8* pCompressed, long* pWorkmem )
{
	uint32	ui32Error = IO_OK;
	uint32	ui32CompressedSize;

	if( lzo1x_1_compress( pBuffer, ui32BufferSize, pCompressed, &ui32CompressedSize, pWorkmem ) != LZO_E_OK )
		ui32Error = IO_ERROR_WRITE;

	// write compressed data size
	ui32Error = pSave->write( &ui32CompressedSize, sizeof( ui32CompressedSize ) );

	// write compressed data
	ui32Error = pSave->write( pCompressed, ui32CompressedSize );

	return ui32Error;
}


uint32
TCSetC::save( SaveC* pSave )
{
	uint32	ui32Error = IO_OK;
	uint32	ui32Tmp;

	// find the largest amount of data we need for comression
	uint32	ui32CompressedSize = 0;
	ui32CompressedSize = __max( ui32CompressedSize, (uint32)m_ui16CoordCount * 4 * 2 );
	ui32CompressedSize = __max( ui32CompressedSize, (uint32)m_ui16IndexCount * 2 );
	ui32CompressedSize = ui32CompressedSize + ui32CompressedSize / 64 + 16 + 3;

	uint8*	pCompressed = new uint8[ui32CompressedSize];
	long*	pWorkmem = new long[((LZO1X_1_MEM_COMPRESS) + (sizeof(long) - 1)) / sizeof(long)];

	// coords
	ui32Tmp = m_ui16CoordCount;
	ui32Error = pSave->write( &ui32Tmp, sizeof( ui32Tmp ) );
	if( ui32Tmp )
		ui32Error = write_compressed( pSave, (uint8*)m_pCoords, (uint32)m_ui16CoordCount * 4 * 2, pCompressed, pWorkmem );

	// indices
	ui32Tmp = m_ui16IndexCount;
	ui32Error = pSave->write( &ui32Tmp, sizeof( ui32Tmp ) );
	if( ui32Tmp )
		ui32Error = write_compressed( pSave, (uint8*)m_pIndices, (uint32)m_ui16IndexCount * 2, pCompressed, pWorkmem );

	delete [] pWorkmem;
	delete [] pCompressed;

	return ui32Error;
}


uint32
TCSetC::read_compressed( LoadC* pLoad, uint8* pBuffer, uint32 ui32BufferSize )
{
	uint32	ui32Error = IO_OK;
	uint32	ui32DecompressedSize;
	uint32	ui32CompressedSize;

	// read compressed data size
	ui32Error = pLoad->read( &ui32CompressedSize, sizeof( ui32CompressedSize ) );

	uint8*	pCompressed = new uint8[ui32CompressedSize];

	// write compressed data
	ui32Error = pLoad->read( pCompressed, ui32CompressedSize );

	if( lzo1x_decompress( pCompressed, ui32CompressedSize, pBuffer, &ui32DecompressedSize, NULL ) != LZO_E_OK )
		ui32Error = IO_ERROR_READ;

	if( ui32DecompressedSize != ui32BufferSize ) {
		OutputDebugString( "data size mismatch\n" );
		return IO_ERROR_READ;
	}

	delete [] pCompressed;

	return ui32Error;
}



uint32
TCSetC::load( LoadC* pLoad )
{
	uint32	ui32Error = IO_OK;
	uint32	ui32Tmp;

	// coords
	ui32Error = pLoad->read( &ui32Tmp, sizeof( ui32Tmp ) );
	if( ui32Tmp ) {
		reserve_coords( ui32Tmp );
		ui32Error = read_compressed( pLoad, (uint8*)m_pCoords, (uint32)m_ui16CoordCount * 4 * 2 );
	}

	// coords
	ui32Error = pLoad->read( &ui32Tmp, sizeof( ui32Tmp ) );
	if( ui32Tmp ) {
		reserve_indices( ui32Tmp );
		ui32Error = read_compressed( pLoad, (uint8*)m_pIndices, (uint32)m_ui16IndexCount * 2 );
	}

	return ui32Error;
}