//===========================================================================//
// File:	videorenderer.cpp                                                   //
// Project: MUNGA           Brick: Video Renderer 	                          //
// Contents: Abstracted Base Video Renderer											  //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 03/04/97  JTR  Initial coding.                                            //
//---------------------------------------------------------------------------//
// Copyright (C) 1997, Virtual World Entertainment, Inc.                     //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#include "AdeptHeaders.hpp"

#include "VideoHeaders.hpp"
#include "RendererManager.hpp"
#include "ResourceImagePool.hpp"
#include "Application.hpp"
#include "Interface.hpp"
#include "CollisionGrid.hpp"
#include "Application.hpp"
#include "GUIObject.hpp"
#include "GUIManager.hpp"
#include "LightComponent.hpp"
#include "MultiLODComponent.hpp"
#include "lightManager.hpp"

#include <Adept\CameraComponent.hpp>

#include <MLR\MLRTexturePool.hpp>
#include <MLR\MLRShape.hpp>

#include <ElementRenderer\StateChange.hpp>
#include <ElementRenderer\CameraElement.hpp>

using namespace ElementRenderer;

using MidLevelRenderer::MLRTexturePool;

//#############################################################################
// Shared Data Support
//
VideoRenderer::ClassData*
	VideoRenderer::DefaultData = NULL;
VideoRenderer
	*VideoRenderer::Instance = NULL;

HGOSHEAP
	VideoRenderer::s_Heap = NULL;
int
	VideoRenderer::s_MipBias = 0;

static bool __stdcall CheckMip0() {return VideoRenderer::s_MipBias == 0;}
static bool __stdcall CheckMip1() {return VideoRenderer::s_MipBias == 1;}
static bool __stdcall CheckMip2() {return VideoRenderer::s_MipBias == 2;}
static void __stdcall EnableMip0() {VideoRenderer::s_MipBias = 0;}
static void __stdcall EnableMip1() {VideoRenderer::s_MipBias = 1;}
static void __stdcall EnableMip2() {VideoRenderer::s_MipBias = 2;}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	VideoRenderer::InitializeClass(Stuff::NotationFile *startup_ini)
{
	Verify(!s_Heap);
	s_Heap = gos_CreateMemoryHeap("Video Renderer", 0, g_LibraryHeap);
	Check_Pointer(s_Heap);

	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			VideoRendererClassID,
			"Adept::VideoRenderer",
			Renderer::DefaultData,
			0,
			NULL
		);
	Check_Object(DefaultData);

	AddDebuggerMenuItem("Libraries\\Graphics Options\\High Detail Textures", CheckMip0, EnableMip0, 0 );
	AddDebuggerMenuItem("Libraries\\Graphics Options\\Medium Detail Textures", CheckMip1, EnableMip1, 0 );
	AddDebuggerMenuItem("Libraries\\Graphics Options\\Low Detail Textures", CheckMip2, EnableMip2, 0 );

	if (startup_ini)
	{
		Check_Object(startup_ini);
		Stuff::Page *page = startup_ini->FindPage("Graphics Options");
		if (page)
		{
			Check_Object(page);
			page->GetEntry("MipBias", &s_MipBias);
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	VideoRenderer::TerminateClass(Stuff::NotationFile *startup_ini)
{
	if (startup_ini)
	{
		Check_Object(startup_ini);
		Stuff::Page *page = startup_ini->SetPage("Graphics Options");
		Check_Object(page);
		page->SetEntry("MipBias", s_MipBias);
	}

	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;

	Check_Pointer(s_Heap);
	gos_DestroyMemoryHeap(s_Heap);
	s_Heap = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
VideoRenderer::VideoRenderer(ClassData *default_data):
	Renderer(
		default_data,
		RendererManager::VideoRendererType,
		"VideoRenderer"
	),
		secondaryCameras(NULL, false)
{
	Check_Pointer(this);
	gos_PushCurrentHeap(MidLevelRenderer::TexturePoolHeap);
	Verify(!MLRTexturePool::Instance);
	ResourceImagePool *pool = new ResourceImagePool;
	Check_Object(pool);
	MLRTexturePool::Instance = new MLRTexturePool(pool);
	Check_Object(MLRTexturePool::Instance);
	gos_PopCurrentHeap();

	Verify(!GUITextManager::GetInstance());
	GlobalPointers::AddGlobalPointer(new GUITextManager(GUITextManager::DefaultData), GUITextManagerGlobalPointerIndex);
	Check_Object(GUITextManager::GetInstance());

	Verify(GUIObject::ScreenQuadGroups == NULL);
	GUIObject::ScreenQuadGroups = new ChainOf<ScreenQuadObject *>(NULL);
	Check_Object(GUIObject::ScreenQuadGroups);

	sceneCamera = NULL;
	sceneRoot = NULL;
	Check_Object(this);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
VideoRenderer::~VideoRenderer()
{
	Check_Object(this);
	if(GUITextManager::GetInstance())
	{
		Unregister_Object(GUITextManager::GetInstance());
		delete GUITextManager::GetInstance();
		GlobalPointers::ClearPointer(GUITextManagerGlobalPointerIndex);
	}

	GUIObject::ScreenQuadGroups->DeletePlugs();
	Unregister_Object(GUIObject::ScreenQuadGroups);
	delete GUIObject::ScreenQuadGroups;
	GUIObject::ScreenQuadGroups = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	VideoRenderer::SetRendererStatus(RendererStatus status)
{
	Check_Object(this);
	switch (status)
	{
	case InactiveRendererStatus:
		{
			Check_Object(this);
			sceneRoot = NULL;
			sceneCamera = NULL;

			{
				HashIteratorOf<MidLevelRenderer::MLRShape*, ResourceID> iterator(ShapeComponent::s_shapeHash);
				MidLevelRenderer::MLRShape* shape;
				while ((shape = iterator.ReadAndNext()) != NULL)
				{
					Check_Object(shape);
					Verify(shape->GetReferenceCount() == 1);
					shape->DetachReference();
				}
			}

			gos_PushCurrentHeap(MidLevelRenderer::TexturePoolHeap);
			Check_Object(MLRTexturePool::Instance);
			delete MLRTexturePool::Instance;
			ResourceImagePool *pool = new ResourceImagePool;
			Check_Object(pool);
			MLRTexturePool::Instance = new MLRTexturePool(pool);
			Check_Object(MLRTexturePool::Instance);
			gos_PopCurrentHeap();

			GUIObject::ScreenQuadGroups->DeletePlugs();
		}
		break;
	}

	Renderer::SetRendererStatus(status);
}

//sanghoon begin
#include <ddraw.h>
#include <d3d.h>

#include "GameOS\render.hpp"
extern IDirectDrawSurface7*	SH_TargetBufferSurface;
extern IDirect3DDevice7*		d3dDevice7;
//sanghoon end


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	VideoRenderer::ExecuteImplementation(Time target_render_time)
{
	//
	//-----------------------------------
	// Execute the executeable components 
	//-----------------------------------
	//
	LOG_BLOCK("Update Renderers::Video");
	Renderer::ExecuteImplementation(target_render_time);
	if (!sceneCamera)
		return;

	//
	//-----------------
	// Cast the shadows
	//-----------------
	//
	Check_Object(sceneCamera);
	TiledLightManager::Instance->CastShadows(sceneCamera->GetElement());

	//
	//------------------------
	// Execute the rasterizers
	//------------------------
	//

	SortedChainIteratorOf<CameraComponent *, int> camera_iterator(&secondaryCameras);
	CameraComponent *camera;

	//sanghoon begin
	if(hsh_initialized){
		if((camera = camera_iterator.ReadAndNext()) != NULL)
		{
			Check_Object(camera);
			if(camera->GetElement()->GetScene() != NULL)
			{
extern LPDIRECTDRAWSURFACE7 BackBufferSurface;
#if 0
extern IDirectDrawSurface7*	SH_TargetBufferSurface;
				IDirectDrawSurface7*	cur_render_target;
				d3dDevice7->GetRenderTarget(&cur_render_target);
				d3dDevice7->SetRenderTarget(SH_TargetBufferSurface,0);
				
				D3DVIEWPORT7			viewData;
				viewData.dwX		= 0;
				viewData.dwY		= 0;
				viewData.dwWidth	= 128.0f;
				viewData.dwHeight	= 128.0f;
				viewData.dvMinZ		= 0.0f;
				viewData.dvMaxZ		= 1.0f;
				d3dDevice7->SetViewport( &viewData );
				/*
				Scalar left  = 240.0f/800.0f;
				Scalar top   = 240.0f/600.0f;
				Scalar width = 239.0f/800.0f;
				Scalar height= 239.0f/600.0f;
				*/
				/*
				Scalar left  = 120.0f/800.0f;
				Scalar top   = 120.0f/600.0f;
				Scalar width = 119.0f/800.0f;
				Scalar height= 119.0f/600.0f;
				*/
				Scalar left  = 120.0f/128.0f;
				Scalar top   = 120.0f/128.0f;
				Scalar width = 119.0f/128.0f;
				Scalar height= 119.0f/128.0f;

				camera->SetViewPort(left,top,width,height);
				camera->GetElement()->SetHSHSpecialFlag(true);

				camera->Execute();

				CopyTargetImage(1);
				d3dDevice7->SetRenderTarget(cur_render_target,0);

				viewData.dwX		= 0;
				viewData.dwY		= 0;
				viewData.dwWidth	= Environment.screenWidth;
				viewData.dwHeight	= Environment.screenHeight;
				viewData.dvMinZ		= 0.0f;
				viewData.dvMaxZ		= 1.0f;
				d3dDevice7->SetViewport( &viewData );
#else
				if(g_f3dtarget){
#if 1
					Scalar left  = 120.0f/Environment.screenWidth;
					Scalar top   = 120.0f/Environment.screenHeight;
					Scalar width = 119.0f/Environment.screenWidth;
					Scalar height= 119.0f/Environment.screenHeight;
#else
					Scalar left  = 120.0f/1024.0f;
					Scalar top   = 120.0f/768.0f;
					Scalar width = 119.0f/1024.0f;
					Scalar height= 119.0f/768.0f;
#endif
					camera->SetViewPort(left,top,width,height);
					camera->GetElement()->SetHSHSpecialFlag(true);
					camera->Execute();
					RECT rc={0,10,120,112};
					SH_TargetBufferSurface->BltFast(0,10,BackBufferSurface,&rc,0);
					CopyTargetImage(1);
				}
#endif
			}
		}
	}
	//sanghoon end

	sceneCamera->Execute();

    extern int g_nMR;
	CameraComponent *cameraTarget;
    
    if (g_nMR == 2) { // mission replay
        cameraTarget = GetSecondaryCamera(0);
    } else { // non mission replay
        cameraTarget = NULL;
    }

	while((camera = camera_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(camera);
        if (cameraTarget != camera) {
		    if(camera->GetElement()->GetScene() != NULL)
		    {
			    camera->GetElement()->SetHSHSpecialFlag(false);
			    camera->Execute();
		    }
        }
	}
	//sanghoon begin
#if 1
	//Draw swirling effect here.
	extern LPDIRECT3DDEVICE7	d3dDevice7;

	extern IDirectDrawSurface7*	SH_SwirlTexture;
	extern void DrawSwrling(LPDIRECT3DDEVICE7	pd3dDevice,LPDIRECTDRAWSURFACE7	pTexture,bool);
	extern bool sh_isdeathmode;
	static preload_isdeathmode=true;;
	if(sh_isdeathmode){
		DrawSwrling(d3dDevice7,SH_SwirlTexture,preload_isdeathmode);
		preload_isdeathmode=false;
	}else{
		preload_isdeathmode=true;
	}
#endif
	//sanghoon end
//sanghoon end
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Component*
	VideoRenderer::CreateComponent(
		ClassID component_class,
		MemoryStream *stream,
		RendererComponentWeb *rend_web,
		Entity *entity
	)
{
	VideoComponentWeb *web = Cast_Object(VideoComponentWeb*, rend_web);
	Component *component;
	switch (component_class)
	{
		case ShapeComponentClassID:
			{
				VIDEOCOMPONENT_LOAD("Shape");
				component = ShapeComponent::Create(stream, web);
				Verify(!component->IsShared());
			}
			break;

		case CameraComponentClassID:
			{
				VIDEOCOMPONENT_LOAD("Camera");
				component = CameraComponent::Make(stream, web, entity);
				Check_Object(component);
				Verify(!component->IsShared());
			}
			break;

		case SwitchComponentClassID:
			{
				VIDEOCOMPONENT_LOAD("Switch");
				component = SwitchComponent::Make(stream, web);
				Check_Object(component);
				Verify(!component->IsShared());
			}
			break;

		case LODComponentClassID:
			{
				VIDEOCOMPONENT_LOAD("LOD");
				component = LODComponent::Make(stream, web);
				Check_Object(component);
				Verify(!component->IsShared());
			}
			break;

		case ScalableShapeComponentClassID:
			{
				VIDEOCOMPONENT_LOAD("Scalable Shape");
				component = ScalableShapeComponent::Create(stream, web);
				Verify(!component->IsShared());
			}
			break;

		case gosFXComponentClassID:
			{
				VIDEOCOMPONENT_LOAD("gosFX");
				component = gosFXComponent::Create(stream, web);
				Verify(!component->IsShared());
			}
			break;

		case BeamComponentClassID:
			{
				VIDEOCOMPONENT_LOAD("Beam");
				component = BeamComponent::Create(stream, web);
				Verify(!component->IsShared());
			}
			break;

		case SlidingShapeComponentClassID:
			{
				VIDEOCOMPONENT_LOAD("Sliding Shape");
				component = SlidingShapeComponent::Create(stream, web, entity);
				Verify(!component->IsShared());
			}
			break;

		case MultiLODComponentClassID:
			{
				VIDEOCOMPONENT_LOAD("MultiLOD");
				component = MultiLODComponent::Make(stream, web);
				Check_Object(component);
				Verify(!component->IsShared());
			}
			break;

		case LightComponentClassID:
			{
				VIDEOCOMPONENT_LOAD("Light");
				component = LightComponent::Create(stream, web);
				Verify(!component->IsShared());
			}
			break;

		case ConeComponentClassID:
			{
				VIDEOCOMPONENT_LOAD("Cone");
				component = ConeComponent::Create(stream, web);
				Verify(!component->IsShared());
			}
			break;

		case GroupComponentClassID:
			{
				VIDEOCOMPONENT_LOAD("Group");
				component = GroupComponent::Make(stream, web);
				Verify(!component->IsShared());
			}
			break;

		default:
			component = 
				Renderer::CreateComponent(
					component_class,
					stream,
					web,
					entity
				);
			break;
	}
	return component;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	VideoRenderer::EntityIsInteresting(
		Entity *entity,
		bool render_me
	)
{
	Check_Object(this);
	Check_Object(entity);

	//
	//----------------------------------------------------------------------
	// If this object already has a web, we just have to turn the web on/off
	//----------------------------------------------------------------------
	//
	VideoComponentWeb *web =
		static_cast<VideoComponentWeb*>(entity->GetComponentWeb(rendererType));
	Element* node = entity->GetElement();
	Check_Object(node);
	if (web)
	{
		Check_Object(web);
		web->SetInterest(render_me);
		if (!render_me)
			return;
	}

	//
	//--------------------------------------
	// Create a component web for the entity
	//--------------------------------------
	//
	else
	{
		const ResourceID &resources = 
			entity->GetRendererDataResourceID(rendererType);

		//
		//---------------------------------------------------------------------
		// If there are no resources, or if we aren't to be rendered, just sync
		// the matrices
		//---------------------------------------------------------------------
		//
		if (!resources || !render_me)
		{
			entity->NeedMatrixSync();
			if (!node->AreBoundsLocked())
				node->NeedNewBounds();
			entity->SyncMatrices(true);
			return;
		}

		//
		//----------------------------------------------------------------------
		// We will be building a web, so allocate it and attach it to the entity
		//----------------------------------------------------------------------
		//
		gos_PushCurrentHeap(s_Heap);
		web =
			new VideoComponentWeb(
				VideoComponentWeb::DefaultData,
   				entity,
   				this,
   				resources,
   				NULL
   			);
		Check_Object(web);
		entity->SetComponentWeb(rendererType, web);

		//
		//-------------------------------------------------
		// Now, load up the web from the specified resource
		//-------------------------------------------------
		//
		Resource script(resources);
		web->LoadFromStream(&script);

		//
		//----------------------------------------------------------------------
		// Now, spin through and hook up the specified components to the locator
		//----------------------------------------------------------------------
		//
		ComponentID component_id;
		component_id.scriptResourceID = resources;
		script >> component_id.componentNumber;
		while (component_id.componentNumber != -1)
		{
			Component *component = web->FindComponent(component_id);
			Check_Object(component);
			VideoComponent *child = Cast_Object(VideoComponent*, component);
			Element *child_node = child->GetElement();
			Check_Object(child_node);
			node->AttachChild(child_node);
			script >> component_id.componentNumber;
		}
		gos_PopCurrentHeap();
	}

	//
	//-----------------------
	// Execute the components
	//-----------------------
	//
	entity->NeedMatrixSync();
	entity->SyncMatrices(true);
	web->ExecuteWatcherComponents();
	Verify(entity->GetElement()->GetCullMode() != ElementRenderer::Element::NeverCullMode);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	VideoRenderer::EntityIsUninteresting(Entity *entity)
{
	Check_Object(this);
	Check_Object(entity);

	//
	//----------------------------------
	// Delete the entity's component web
	//----------------------------------
	//
	Check_Object(RendererManager::Instance);
	VideoComponentWeb *web =
		static_cast<VideoComponentWeb*>(entity->GetComponentWeb(rendererType));
	if (web)
	{
		STOP(("Not implemented"));
#if 0
		Locator *locator = Cast_Object(Locator*, entity->GetLocator());
		locator->AlwaysCulled();
		InterestZone *zone = entity->GetInterestZone();
		Check_Object(zone);
		LightingZone *lighting = zone->GetLightingZone();
		Check_Object(lighting);
		Check_Object(web);
		lighting->DetachWeb(web);
#endif
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	VideoRenderer::ProjectMouseCursorIntoCameras()
{
	Check_Object(this);

	//
	//----------------------
	// Ask gos for the mouse
	//----------------------
	//
	Vector2DOf<Scalar> cursor;
	gos_GetMouseInfo(&cursor.x, &cursor.y, NULL, NULL, NULL, NULL);

	//
	//-----------------------------
	// Clean out the interface data
	//-----------------------------
	//
	Check_Object(sceneCamera);
	EntityComponentWeb *web =
		Cast_Object(EntityComponentWeb*, sceneCamera->GetComponentWeb());
	Interface *intface = Cast_Object(Interface*, web->GetEntity());
	intface->reticuleEntity.Remove();

	//
	//-----------------------
	// Figure out the eyeline
	//-----------------------
	//
	Line3D world_line;
	sceneCamera->ComputeEyeLine(&world_line, cursor);
	#if defined(_ARMOR)
		bool result = intface->ClipCameraLine(&world_line);
		Verify(result);
	#else
		intface->ClipCameraLine(&world_line);
	#endif
	Entity::CollisionQuery query(
		&world_line,
		&intface->reticuleNormal,
		Entity::CanBeShotFlag,
		NULL
	);
	Entity *reticule_entity;
	Check_Object(CollisionGrid::Instance);
	reticule_entity = CollisionGrid::Instance->ProjectLine(&query);
	if (reticule_entity != NULL)
	{
		Check_Object(reticule_entity);
		intface->reticuleEntity.Add(reticule_entity);
		Point3D trans;
		world_line.FindEnd(&trans);
		intface->reticuleOffset.MultiplyByInverse(
			trans,
			reticule_entity->GetLocalToWorld()
		);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	VideoRenderer::ProjectPointOnScreen(
		Stuff::Vector2DOf<Stuff::Scalar> *cursor,
		const Stuff::Point3D &location
	)
{
	Check_Object(this);
	Check_Pointer(cursor);
	Check_Object(&location);

	//
	//---------------------------------------------
	// Have the camera tell use where this might be
	//---------------------------------------------
	//
	Check_Object(sceneCamera);
	return sceneCamera->ComputeCursor(cursor, location);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	VideoRenderer::ComputeEyeLine(
		const Stuff::Vector2DOf<Stuff::Scalar> &cursor,
		Line3D *world_line
	)
{
	Check_Object(this);
	Check_Pointer(&cursor);
	Check_Object(world_line);

	//
	//---------------------------------------
	// Have the camera cast a ray from cursor
	//---------------------------------------
	//
	Check_Object(sceneCamera);
	sceneCamera->ComputeEyeLine(world_line, cursor);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	VideoRenderer::SetSceneRoot(Element *element)
{
	Check_Object(this);

	//
	//----------------------------------------------------
	// If we are clearing out the root, just set the value
	//----------------------------------------------------
	//
	if (!element)
	{
		sceneRoot = NULL;
		sceneCamera = NULL;
	}

	//
	//-------------------------------------------
	// Otherwise we are setting a real scene root
	//-------------------------------------------
	//
	else
	{
		Check_Object(element);
		sceneRoot = Cast_Object(GroupElement*, element);
		if (sceneCamera)
		{
			Check_Object(sceneCamera);
			sceneCamera->GetElement()->SetScene(element);
		}
	}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	VideoRenderer::SetCamera(CameraComponent *camera)
{
	Check_Object(this);
	sceneCamera = camera;

	if (camera != NULL)
		GUIObject::AdoptCamera(camera->GetElement());
	else
		GUIObject::RemoveCamera();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	VideoRenderer::AddSecondaryCamera(CameraComponent *camera)
{
	Check_Object(this);
	
	SortedChainIteratorOf<CameraComponent *, int> iterator(&secondaryCameras);
	int camera_id = iterator.GetSize();

	secondaryCameras.AddValue(camera, camera_id);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraComponent*
	VideoRenderer::GetSecondaryCamera(int camera_id)
{
	Check_Object(this);
	
	return secondaryCameras.Find(camera_id);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	VideoRenderer::TestInstance()
{
	Verify(IsDerivedFrom(DefaultData));
}
