//===========================================================================//
// File:	renderer.cc                                                         //
// Project: MUNGA           Brick: Renderer Manager	                       //
// Contents: Interface specification Renderer and Renderer Manager			  //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 11/21/94  ECH  Initial coding.                                            //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc.                //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#include "AdeptHeaders.hpp"

#include "RendererManager.hpp"
#include "Map.hpp"
#include "ComponentHeaders.hpp"
#include "Application.hpp"
#include "AttributeWatcher.hpp"

//#############################################################################
//#############################    Renderer    ################################
//#############################################################################

Renderer::ClassData*
	Renderer::DefaultData = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Renderer::InitializeClass()
{
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			RendererClassID,
			"Adept::Renderer",
			Receiver::DefaultData,
			0, NULL
		);
	Register_Object(DefaultData);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Renderer::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Renderer::Renderer(
	ClassData *class_data,
	int renderer_type,
	const char *renderer_name
):
	Receiver(class_data),
	executableComponents(NULL),
	sharedComponents(101, NULL, true),
	componentWebs(NULL)
{
	rendererStatus = LoadingRendererStatus;
	rendererType = renderer_type;
	rendererName = renderer_name;

	lastRenderTime = 0.0f;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Renderer::~Renderer()
{
	Check_Object(this);
	sharedComponents.DeletePlugs();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Renderer::Execute(Time target_render_time)
{
	Check_Object(this);

	//
	//--------------------------------------
	// If the renderer is suspended, skip it
	//--------------------------------------
	//
	if (rendererStatus != ActiveRendererStatus)
		return;

	//
	//-----------------------------
	// Execute the foreground stuff
	//-----------------------------
	//
	ExecuteImplementation(target_render_time);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Component*
	Renderer::CreateComponent(
		ClassID component_class,
		MemoryStream *stream,
		RendererComponentWeb *web,
		Entity *entity
	)
{
	switch (component_class)
	{
	case AttributeWatcherOfIntClassID:
		{
			AttributeWatcherOf<int, IntClassID> *component =
				AttributeWatcherOf<int, IntClassID>::Make(
					stream,
					web,
					entity
				);
			Register_Object(component);
			Verify(!component->IsShared());
			return component;
		}

	case MatcherOfIntClassID:
		return MatcherOf<int>::Create(stream, web);
	}
	STOP(("Unknown component class ID!"));
	return NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Component*
	Renderer::FindSharedComponent(const ComponentID& component_id)
{
	Check_Object(this);
	return sharedComponents.Find(component_id);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Component*
	Renderer::AddSharedComponent(Component *component)
{
	Check_Object(this);
	Check_Object(component);

	//
	//----------------------------------------------
	// Add the new component (it can't be a watcher)
	//----------------------------------------------
	//
	Verify(!component->ShouldSimulationExecute());
	Component *current = FindSharedComponent(component->GetComponentID());
	if (!current)
	{
		sharedComponents.AddValue(component, component->GetComponentID());
	}
	else
	{
		Verify(current == component);
	}
	return component;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Renderer::AddComponentWeb(RendererComponentWeb *web)
{
	Check_Object(this);
	Check_Object(web);
	componentWebs.Add(web);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Renderer::AddExecutableComponent(Component* component)
{
	Check_Object(this);
	Check_Object(component);

	Verify(!executableComponents.IsPlugMember(component));
	executableComponents.Add(component);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Renderer::ExecuteImplementation(Time target_render_time)
{
	Check_Object(this);

	//
	//-----------------------------------
	// Execute the executeable components 
	//-----------------------------------
	//
	ChainIteratorOf<Component*> executables(&executableComponents);
	Component *component;
	while ((component = executables.ReadAndNext()) != NULL)
	{
		Check_Object(component);
		component->Execute();
	}
	lastRenderTime = target_render_time;
}
