//
// DX9CameraPlugin.cpp
//
// DX9Camera Plugin
//
// Copyright (c) 2000-2004 memon/moppi productions
//

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <d3d9.h>
#include <d3dx9math.h>

// Demopaja headers
#include "DemopajaVersion.h"
#include "PajaTypes.h"
#include "ClassDescC.h"
#include "ImportableI.h"
#include "DX9DeviceC.h"
#include "Dx9ViewportC.h"
#include "FileIO.h"
#include "AutoGizmoC.h"
#include "Vector2C.h"
#include "BBox2C.h"
#include "EffectMaskI.h"
#include "noise.h"

#include "DX9CameraPlugin.h"

using namespace PajaTypes;
using namespace PluginClass;
using namespace PajaSystem;
using namespace Edit;
using namespace Composition;
using namespace Import;
using namespace FileIO;

using namespace DX9CameraPlugin;

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 );
}

//////////////////////////////////////////////////////////////////////////
//
//  DX9Camera effect class descriptor.
//

DX9CameraDescC::DX9CameraDescC()
{
	// empty
}

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

void*
DX9CameraDescC::create()
{
	return (void*)DX9CameraEffectC::create_new();
}

int32
DX9CameraDescC::get_classtype() const
{
	return CLASS_TYPE_EFFECT;
}

SuperClassIdC
DX9CameraDescC::get_super_class_id() const
{
	return SUPERCLASS_EFFECT;
}

ClassIdC
DX9CameraDescC::get_class_id() const
{
	return CLASS_DX9CAMERA_EFFECT;
};

const char*
DX9CameraDescC::get_name() const
{
	return CLASS_DX9CAMERA_EFFECT_NAME;
}

const char*
DX9CameraDescC::get_desc() const
{
	return CLASS_DX9CAMERA_EFFECT_DESC;
}

const char*
DX9CameraDescC::get_author_name() const
{
	return "Mikko \"memon\" Mononen";
}

const char*
DX9CameraDescC::get_copyright_message() const
{
	return "Copyright (c) 2000-2004 Moppi Productions";
}

const char*
DX9CameraDescC::get_url() const
{
	return "http://www.demopaja.org/";
}

const char*
DX9CameraDescC::get_help_filename() const
{
	return "res://ImageHelp.html";
}

uint32
DX9CameraDescC::get_required_device_driver_count() const
{
	return 1;
}

const ClassIdC&
DX9CameraDescC::get_required_device_driver( uint32 ui32Idx )
{
	return PajaSystem::CLASS_DX9_DEVICEDRIVER;
}


uint32
DX9CameraDescC::get_ext_count() const
{
	return 0;
}

const char*
DX9CameraDescC::get_ext( uint32 ui32Index ) const
{
	return 0;
}


//////////////////////////////////////////////////////////////////////////
//
// Global descriptors, which will be returned to the Demopaja.
//

DX9CameraDescC			g_rDX9CameraDesc;

#ifndef DEMOPAJAPLAYER

//////////////////////////////////////////////////////////////////////////
//
// The DLL
//

BOOL APIENTRY
DllMain( HANDLE hModule, DWORD ulReasonForCall, LPVOID lpReserved )
{
    switch( ulReasonForCall )
	{
		case DLL_PROCESS_ATTACH:
		case DLL_THREAD_ATTACH:
		case DLL_THREAD_DETACH:
		case DLL_PROCESS_DETACH:
			break;
    }
    return TRUE;
}


//
// Returns number of classes inside this plugin DLL.
//

__declspec( dllexport )
int32
get_classdesc_count()
{
	return 1;
}


//
// Returns class descriptors of the plugin classes.
//

__declspec( dllexport )
ClassDescC*
get_classdesc( int32 i )
{
	if( i == 0 )
		return &g_rDX9CameraDesc;
	return 0;
}


//
// Returns the API version this DLL was made with.
//

__declspec( dllexport )
int32
get_api_version()
{
	return DEMOPAJA_VERSION;
}

//
// Returns the DLL name.
//

__declspec( dllexport )
char*
get_dll_name()
{
	return "DX9CameraPlugin.dll - Image Plugin (c)2000-2004 memon/moppi productions";
}

#endif



//////////////////////////////////////////////////////////////////////////
//
// The effect
//

DX9CameraEffectC::DX9CameraEffectC()
{
	//
	// Create Transform gizmo.
	//
	m_pTraGizmo = AutoGizmoC::create_new( this, "Transform", ID_GIZMO_TRANS );

	m_pTraGizmo->add_parameter(	ParamVector2C::create_new( m_pTraGizmo, "Position", Vector2C(), ID_TRANSFORM_POS,
						PARAM_STYLE_EDITBOX | PARAM_STYLE_ABS_POSITION, PARAM_ANIMATABLE ) );
	
	m_pTraGizmo->add_parameter(	ParamVector2C::create_new( m_pTraGizmo, "Scale", Vector2C( 1, 1 ), ID_TRANSFORM_SCALE,
						PARAM_STYLE_EDITBOX | PARAM_STYLE_PERCENT, PARAM_ANIMATABLE, Vector2C(), Vector2C(), 0.01f ) );


	//
	// Create Attributes gizmo.
	//
	m_pAttGizmo = AutoGizmoC::create_new( this, "Attributes", ID_GIZMO_ATTRIB );


	m_pAttGizmo->add_parameter( ParamVector2C::create_new( m_pAttGizmo, "Size", Vector2C( 320, 200 ), ID_ATTRIBUTE_SIZE,
		PARAM_STYLE_EDITBOX, PARAM_ANIMATABLE, Vector2C(), Vector2C(), 1 ) );

	m_pAttGizmo->add_parameter( ParamIntC::create_new( m_pAttGizmo, "Camera", 0, ID_ATTRIBUTE_CAMERA,
		PARAM_STYLE_COMBOBOX, PARAM_ANIMATABLE, 0, 1 ) );

	m_pAttGizmo->add_parameter( ParamFloatC::create_new( m_pAttGizmo, "Focal Distance", 100.0f, ID_ATTRIBUTE_FOCAL_DISTANCE,
						PARAM_STYLE_EDITBOX, PARAM_ANIMATABLE, 0, 0, 1.0f ) );

	m_pAttGizmo->add_parameter( ParamFloatC::create_new( m_pAttGizmo, "Focal Range", 100.0f, ID_ATTRIBUTE_FOCAL_RANGE,
						PARAM_STYLE_EDITBOX, PARAM_ANIMATABLE, 0, 0, 1.0f ) );

	ParamIntC*	pFogMode = ParamIntC::create_new( m_pAttGizmo, "Fog Enable", 0, ID_ATTRIBUTE_FOG_TYPE, PARAM_STYLE_COMBOBOX, PARAM_ANIMATABLE, 0, 1 );
	pFogMode->add_label( 0, "Off" );
	pFogMode->add_label( 1, "On" );
	m_pAttGizmo->add_parameter( pFogMode );

	m_pAttGizmo->add_parameter( ParamFloatC::create_new( m_pAttGizmo, "Fog Start", 100.0f, ID_ATTRIBUTE_FOG_START,
						PARAM_STYLE_EDITBOX, PARAM_ANIMATABLE, 0, 0, 1.0f ) );

	m_pAttGizmo->add_parameter( ParamFloatC::create_new( m_pAttGizmo, "Fog End", 500.0f, ID_ATTRIBUTE_FOG_END,
						PARAM_STYLE_EDITBOX, PARAM_ANIMATABLE, 0, 0, 1.0f ) );

	m_pAttGizmo->add_parameter(	ParamColorC::create_new( m_pAttGizmo, "Fog Color", ColorC( 1, 1, 1, 1 ), ID_ATTRIBUTE_FOG_COLOR,
							PARAM_STYLE_COLORPICKER_RGB, PARAM_ANIMATABLE ) );

	m_pAttGizmo->add_parameter( ParamFloatC::create_new( m_pAttGizmo, "Noise Amount", 0.0f, ID_ATTRIBUTE_NOISE_AMOUNT,
						PARAM_STYLE_EDITBOX | PARAM_STYLE_PERCENT, PARAM_ANIMATABLE, 0, 1.0f, 0.01f ) );

	m_pAttGizmo->add_parameter( ParamFloatC::create_new( m_pAttGizmo, "Noise Scale", 0.0f, ID_ATTRIBUTE_NOISE_SCALE,
						PARAM_STYLE_EDITBOX | PARAM_STYLE_PERCENT, PARAM_ANIMATABLE, 0, 1.0f, 0.01f ) );

	m_pAttGizmo->add_parameter( ParamFileC::create_new( m_pAttGizmo, "Scene", NULL_SUPERCLASS, CLASS_DX9ASE_IMPORT, ID_ATTRIBUTE_FILE ) );

	//
	// Create Time gizmo.
	//
	m_pTimeGizmo = AutoGizmoC::create_new( this, "Timing", ID_GIZMO_TIME );
	
	m_pTimeGizmo->add_parameter( ParamFloatC::create_new( m_pTimeGizmo, "Frame", 0, ID_TIME_FRAME,
						PARAM_STYLE_EDITBOX, PARAM_ANIMATABLE, 0, 0, 1.0f ) );
}

DX9CameraEffectC::DX9CameraEffectC( EditableI* pOriginal ) :
	EffectI( pOriginal ),
	m_pTraGizmo( 0 ),
	m_pAttGizmo( 0 ),
	m_pTimeGizmo( 0 )
{
	// Empty. The parameters are not created in the clone constructor.
}

DX9CameraEffectC::~DX9CameraEffectC()
{
	// Return if this is a clone.
	if( get_original() )
		return;

	// Release gizmos.
	m_pTraGizmo->release();
	m_pAttGizmo->release();
	m_pTimeGizmo->release();
}

DX9CameraEffectC*
DX9CameraEffectC::create_new()
{
	return new DX9CameraEffectC;
}

DataBlockI*
DX9CameraEffectC::create()
{
	return new DX9CameraEffectC;
}

DataBlockI*
DX9CameraEffectC::create( EditableI* pOriginal )
{
	return new DX9CameraEffectC( pOriginal );
}

void
DX9CameraEffectC::copy( EditableI* pEditable )
{
	EffectI::copy( pEditable );

	// Make deep copy.
	DX9CameraEffectC*	pEffect = (DX9CameraEffectC*)pEditable;
	m_pTraGizmo->copy( pEffect->m_pTraGizmo );
	m_pAttGizmo->copy( pEffect->m_pAttGizmo );
	m_pTimeGizmo->copy( pEffect->m_pTimeGizmo );
}

void
DX9CameraEffectC::restore( EditableI* pEditable )
{
	EffectI::restore( pEditable );

	// Make shallow copy.
	DX9CameraEffectC*	pEffect = (DX9CameraEffectC*)pEditable;
	m_pTraGizmo = pEffect->m_pTraGizmo;
	m_pAttGizmo = pEffect->m_pAttGizmo;
	m_pTimeGizmo = pEffect->m_pTimeGizmo;
}

int32
DX9CameraEffectC::get_gizmo_count()
{
	// Return number of gizmos inside this effect.
	return GIZMO_COUNT;
}

GizmoI*
DX9CameraEffectC::get_gizmo( PajaTypes::int32 i32Index )
{
	// Returns specified gizmo.
	// Since the ID's are zero based, we can use them as indices.
	switch( i32Index ) {
	case ID_GIZMO_TRANS:
		return m_pTraGizmo;
	case ID_GIZMO_ATTRIB:
		return m_pAttGizmo;
	case ID_GIZMO_TIME:
		return m_pTimeGizmo;
	}

	return 0;
}

ClassIdC
DX9CameraEffectC::get_class_id()
{
	// Return the class ID. Should be same as in the class descriptor.
	return CLASS_DX9CAMERA_EFFECT;
}

const char*
DX9CameraEffectC::get_class_name()
{
	// Return the class name. Should be same as in the class descriptor.
	return CLASS_DX9CAMERA_EFFECT_NAME;
}

void
DX9CameraEffectC::set_default_file( int32 i32Time, FileHandleC* pHandle )
{
	// Sets the default file.

	// Get the file parameter.
	ParamFileC*	pParam = (ParamFileC*)m_pAttGizmo->get_parameter( ID_ATTRIBUTE_FILE );

	// Begin Undo block.
	UndoC*	pOldUndo = pParam->begin_editing( get_undo() );
		// Set the file.
		pParam->set_file( i32Time, pHandle );
	// End undo block.
	pParam->end_editing( pOldUndo );
}

ParamI*
DX9CameraEffectC::get_default_param( int32 i32Param )
{
	// Return specified default parameter.
	if( i32Param == DEFAULT_PARAM_POSITION )
		return m_pTraGizmo->get_parameter( ID_TRANSFORM_POS );
	else if( i32Param == DEFAULT_PARAM_SCALE )
		return m_pTraGizmo->get_parameter( ID_TRANSFORM_SCALE );
	return 0;
}

uint32
DX9CameraEffectC::update_notify( EditableI* pCaller )
{
	ParamI*	pParam = 0;
	GizmoI*	pGizmo = 0;
	if( pCaller->get_base_class_id() == BASECLASS_PARAMETER )
		pParam = (ParamI*)pCaller;
	if( pParam )
		pGizmo = pParam->get_parent();

	if( pParam && pGizmo && pGizmo->get_id() == ID_GIZMO_ATTRIB && pParam->get_id() == ID_ATTRIBUTE_FILE )
	{
		// The file has changed. Change Time.
		ParamFileC*		pFile = (ParamFileC*)m_pAttGizmo->get_parameter_by_id( ID_ATTRIBUTE_FILE );
		ParamFloatC*	pFrame = (ParamFloatC*)m_pTimeGizmo->get_parameter_by_id( ID_TIME_FRAME );
		ParamIntC*		pCamera = (ParamIntC*)m_pAttGizmo->get_parameter_by_id( ID_ATTRIBUTE_CAMERA );

		UndoC*		pOldUndo;
		UndoC*		pUndo = pFile->get_undo();

		FileHandleC*		pHandle = 0;
		DX9ASEImportC*	pImp = 0;

		pHandle = pFile->get_file( 0 );
		if( pHandle )
			pImp = (DX9ASEImportC*)pHandle->get_importable();

		if( pImp )
		{
			int32	i32FPS, i32TicksPerFrame, i32FirstFrame, i32LastFrame;
			pImp->get_time_parameters( i32FPS, i32TicksPerFrame, i32FirstFrame, i32LastFrame );

			// Update camera labels.
			pOldUndo = pCamera->begin_editing( pUndo );
			pCamera->clear_labels();
			for( uint32 i = 0; i < pImp->get_camera_count(); i++ ) {
				CameraC*	pCam = pImp->get_camera( i );
				if( !pCam )
					continue;
				pCamera->add_label( i, pCam->get_name() );
			}
			pCamera->set_min_max( 0, pImp->get_camera_count() - 1 );
			pCamera->end_editing( pOldUndo );
		}
	}

	// Relay update
	return EffectI::update_notify( pCaller );
}

void
DX9CameraEffectC::initialize( uint32 ui32Reason, PajaSystem::DemoInterfaceC* pInterface )
{
	EffectI::initialize( ui32Reason, pInterface );

	D3DXMatrixIdentity( &m_matCamera );
	D3DXMatrixIdentity( &m_matProj );

	// init perlin noise
	noise1( 0 );
}


void
DX9CameraEffectC::eval_state( int32 i32Time )
{
	if( !m_pDemoInterface )
		return;

	DeviceContextC* pContext = m_pDemoInterface->get_device_context();
	TimeContextC* pTimeContext = m_pDemoInterface->get_time_context();

	Matrix2C	rPosMat, rScaleMat, rPivotMat;
	Vector2C	rScale;
	Vector2C	rPos;

	// Get parameters which affect the transformation.
	((ParamVector2C*)m_pTraGizmo->get_parameter( ID_TRANSFORM_POS ))->get_val( i32Time, rPos );
	((ParamVector2C*)m_pTraGizmo->get_parameter( ID_TRANSFORM_SCALE ))->get_val( i32Time, rScale );

	rPosMat.set_trans( rPos );
	rScaleMat.set_scale( rScale ) ;

	m_rTM = rScaleMat * rPosMat;

	//
	// calc bounding box
	//
	Vector2C	rSize;
	((ParamVector2C*)m_pAttGizmo->get_parameter_by_id( ID_ATTRIBUTE_SIZE ))->get_val( i32Time, rSize );
	rSize *= 0.5f;

	Vector2C	rMin, rMax;

	rMin = -rSize;
	rMax = rSize;

	rMin *= m_rTM;
	rMax *= m_rTM;

	m_rBBox[0] = rMin;
	m_rBBox[1] = rMax;
	m_rBBox.normalize();


	CameraC*	pCam = 0;

	//
	// Calculate current frame.
	//
	DX9ASEImportC*	pImp = 0;
	FileHandleC*		pHandle;
	int32						i32FileTime;

	((ParamFileC*)m_pAttGizmo->get_parameter_by_id( ID_ATTRIBUTE_FILE ))->get_file( i32Time, pHandle, i32FileTime );

	if( pHandle )
		pImp = (DX9ASEImportC*)pHandle->get_importable();
	
	if( pImp )
	{
		// If "Frame" parameter is animated, use it instead of FPS setting.
		ParamFloatC*	pParamFrame = (ParamFloatC*)m_pTimeGizmo->get_parameter_by_id( ID_TIME_FRAME );
		ControllerC*	pCont = pParamFrame->get_controller();
		if( pCont && pCont->get_key_count() ) {
			float32	f32Frame;
			pParamFrame->get_val( i32Time, f32Frame );

			float32	f32StartFrame = pImp->get_start_label();
			float32	f32EndFrame = pImp->get_end_label();

			if( (f32EndFrame - f32StartFrame) >= 0 ) {
				i32FileTime = (int32)(((f32Frame - f32StartFrame) / (f32EndFrame - f32StartFrame)) * pImp->get_duration());
			}
		}

		pImp->eval_state( i32FileTime );
	
		// get camera
		int32	i32Val;
		((ParamIntC*)m_pAttGizmo->get_parameter_by_id( ID_ATTRIBUTE_CAMERA ))->get_val( i32Time, i32Val );
		pCam = pImp->get_camera( i32Val );
	}

	// Focal distance
	((ParamFloatC*)m_pAttGizmo->get_parameter_by_id( ID_ATTRIBUTE_FOCAL_DISTANCE ))->get_val( i32Time, m_f32FocalDistance );
	// Focal range
	((ParamFloatC*)m_pAttGizmo->get_parameter_by_id( ID_ATTRIBUTE_FOCAL_RANGE ))->get_val( i32Time, m_f32FocalRange );


	float32	f32NoiseAmount = 0;
	float32	f32NoiseScale = 0;

	// Fog Type
	((ParamIntC*)m_pAttGizmo->get_parameter_by_id( ID_ATTRIBUTE_FOG_TYPE ))->get_val( i32Time, m_i32FogType );
	// Fog Start
	((ParamFloatC*)m_pAttGizmo->get_parameter_by_id( ID_ATTRIBUTE_FOG_START ))->get_val( i32Time, m_f32FogStart );
	// Fog End
	((ParamFloatC*)m_pAttGizmo->get_parameter_by_id( ID_ATTRIBUTE_FOG_END ))->get_val( i32Time, m_f32FogEnd );
	// Fog Color
	((ParamColorC*)m_pAttGizmo->get_parameter_by_id( ID_ATTRIBUTE_FOG_COLOR ))->get_val( i32Time, m_FogColor );
	// Noise amount
	((ParamFloatC*)m_pAttGizmo->get_parameter_by_id( ID_ATTRIBUTE_NOISE_AMOUNT ))->get_val( i32Time, f32NoiseAmount );
	// Noise scale
	((ParamFloatC*)m_pAttGizmo->get_parameter_by_id( ID_ATTRIBUTE_NOISE_SCALE ))->get_val( i32Time, f32NoiseScale );

/*
	ParamIntC*	pFogMode = ParamIntC::create_new( m_pAttGizmo, "Fog Enable", 0, ID_ATTRIBUTE_FOG_TYPE, PARAM_STYLE_COMBOBOX, PARAM_ANIMATABLE, 0, 1 );
	pFogMode->add_label( 0, "Off" );
	pFogMode->add_label( 1, "On" );
	m_pAttGizmo->add_parameter( pFogMode );

	m_pAttGizmo->add_parameter( ParamFloatC::create_new( m_pAttGizmo, "Fog Type", 100.0f, ,
						PARAM_STYLE_EDITBOX, PARAM_ANIMATABLE, 0, 0, 1.0f ) );

	m_pAttGizmo->add_parameter( ParamFloatC::create_new( m_pAttGizmo, "Fog Start", 100.0f, ID_ATTRIBUTE_FOG_START,
						PARAM_STYLE_EDITBOX, PARAM_ANIMATABLE, 0, 0, 1.0f ) );

	m_pAttGizmo->add_parameter( ParamFloatC::create_new( m_pAttGizmo, "Fog End", 100.0f, ID_ATTRIBUTE_FOG_END,
						PARAM_STYLE_EDITBOX, PARAM_ANIMATABLE, 0, 0, 1.0f ) );

	m_pAttGizmo->add_parameter(	ParamColorC::create_new( m_pAttGizmo, "Fog Color", ColorC( 1, 1, 1, 1 ), ID_ATTRIBUTE_FOG_COLOR,
							PARAM_STYLE_COLORPICKER_RGB, PARAM_ANIMATABLE ) );
*/
	// set aspectratio
	float32	f32Aspect = 1.0f;
	if( rScale[0] != 0 && rScale[1] != 0 ) {
		f32Aspect = (float32)fabs( rScale[0] / rScale[1] );
	}
	else {
		f32Aspect = 1.0f;
	}

	// Get the DX9 device.
	DX9DeviceC*	pDevice = (DX9DeviceC*)pContext->query_interface( CLASS_DX9_DEVICEDRIVER );
	if( !pDevice )
		return;

	LPDIRECT3DDEVICE9	pD3DDevice = pDevice->get_d3ddevice();

	// Get the DX9 viewport.
	DX9ViewportC*	pViewport = (DX9ViewportC*)pDevice->query_interface( GRAPHICSDEVICE_VIEWPORT_INTERFACE );
	if( !pViewport )
		return;

	//
	// setup camera
	//

	if( !pImp || !pCam )
		return;


	int32	i32Frame = pImp->get_current_frame();

	pCam->eval_state( i32Frame );

	Vector3C	rCamPos, rCamTgt;
	float		f32FOV;
	float32		f32Roll = 0.0f;

	rCamPos = pCam->get_position();
	rCamTgt = pCam->get_target_position();
	f32FOV = pCam->get_fov();
//	f32Roll = pCam->get_roll();

	float32	f32CamNear = pCam->get_near_plane();
	if( f32CamNear < 1.0f )
		f32CamNear = 1.0f;
	float32	f32CamFar = pCam->get_far_plane();

	pViewport->set_perspective( m_rBBox, f32FOV / (float32)M_PI * (float32)180.0f, f32Aspect, f32CamNear, f32CamFar );

	pD3DDevice->GetTransform( D3DTS_PROJECTION, &m_matProj );

	D3DXMATRIX	matRoll;
	D3DXMatrixRotationZ( &matRoll, -f32Roll );

  D3DXVECTOR3 vEye( rCamPos[0], rCamPos[1], rCamPos[2] );
  D3DXVECTOR3 vAt( rCamTgt[0], rCamTgt[1], rCamTgt[2] );
  D3DXVECTOR3 vUp( 0, 1, 0 );
  D3DXMatrixLookAtLH( &m_matCamera, &vEye, &vAt, &vUp );

//	D3DXMatrixMultiply( &m_matCamera, &matRoll, &m_matCamera );

	pD3DDevice->SetTransform( D3DTS_VIEW, &m_matCamera );

	Vector3C	Diff = rCamTgt - rCamPos;

//	TRACE( "can focal: %f\n", Diff.length() );
}

LPD3DXMATRIX
DX9CameraEffectC::get_camera_matrix()
{
	return &m_matCamera;
}

LPD3DXMATRIX
DX9CameraEffectC::get_proj_matrix()
{
	return &m_matProj;
}

float32
DX9CameraEffectC::get_focal_distance()
{
	return m_f32FocalDistance;
}

float32
DX9CameraEffectC::get_focal_range()
{
	return m_f32FocalRange;
}

int32
DX9CameraEffectC::get_fog_type()
{
	return m_i32FogType;
}

float32
DX9CameraEffectC::get_fog_start()
{
	return m_f32FogStart;
}

float32
DX9CameraEffectC::get_fog_end()
{
	return m_f32FogEnd;
}

ColorC
DX9CameraEffectC::get_fog_color()
{
	return m_FogColor;
}

BBox2C
DX9CameraEffectC::get_bbox()
{
	// Return the bounding box.
	return m_rBBox;
}

const Matrix2C&
DX9CameraEffectC::get_transform_matrix() const
{
	// Return the trnasformation matrix.
	return m_rTM;
}

bool
DX9CameraEffectC::hit_test( const Vector2C& rPoint )
{
	return m_rBBox.contains( rPoint );
}


enum DX9CameraEffectChunksE {
	CHUNK_IMAGE_BASE =				0x10,
	CHUNK_IMAGE_TRANSGIZMO =	0x20,
	CHUNK_IMAGE_ATTRIBGIZMO =	0x30,
	CHUNK_IMAGE_TIMEGIZMO =	0x40,
};

const uint32	IMAGE_VERSION = 1;

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

	// EffectI base class
	pSave->begin_chunk( CHUNK_IMAGE_BASE, IMAGE_VERSION );
		ui32Error = EffectI::save( pSave );
	pSave->end_chunk();

	// Transform
	pSave->begin_chunk( CHUNK_IMAGE_TRANSGIZMO, IMAGE_VERSION );
		ui32Error = m_pTraGizmo->save( pSave );
	pSave->end_chunk();

	// Attribute
	pSave->begin_chunk( CHUNK_IMAGE_ATTRIBGIZMO, IMAGE_VERSION );
		ui32Error = m_pAttGizmo->save( pSave );
	pSave->end_chunk();

	// time
	pSave->begin_chunk( CHUNK_IMAGE_TIMEGIZMO, IMAGE_VERSION );
	ui32Error = m_pTimeGizmo->save( pSave );
	pSave->end_chunk();

	return ui32Error;
}

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

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

		switch( pLoad->get_chunk_id() ) {
		case CHUNK_IMAGE_BASE:
			// EffectI base class
			if( pLoad->get_chunk_version() == IMAGE_VERSION )
				ui32Error = EffectI::load( pLoad );
			break;

		case CHUNK_IMAGE_TRANSGIZMO:
			// Transform
			if( pLoad->get_chunk_version() == IMAGE_VERSION )
				ui32Error = m_pTraGizmo->load( pLoad );
			break;

		case CHUNK_IMAGE_ATTRIBGIZMO:
			// Attribute
			if( pLoad->get_chunk_version() == IMAGE_VERSION )
				ui32Error = m_pAttGizmo->load( pLoad );
			break;

		case CHUNK_IMAGE_TIMEGIZMO:
			// Attribute
			if( pLoad->get_chunk_version() == IMAGE_VERSION )
				ui32Error = m_pTimeGizmo->load( pLoad );
			break;

		default:
			assert( 0 );
		}

		pLoad->close_chunk();

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

	return ui32Error;
}
