//===========================================================================//
// File:	ScreenPolyManager.cpp                                               //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  -----------------------------------------------------------//
// 07/21/98  DPB  File Creation															  //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc.                //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#include "AdeptHeaders.hpp"

#include "ScreenPolyManager.hpp"
#include <ElementRenderer\StateChange.hpp>
#include <MLR\MLRTexture.hpp>
#include <MLR\MLRTexturePool.hpp>

using namespace ElementRenderer;
using namespace MidLevelRenderer;

//#############################################################################
//########################    ScreenPolyManager    ############################
//#############################################################################

ScreenPolyManager
	*ScreenPolyManager::Instance = NULL;

ScreenPolyManager::ClassData*
	ScreenPolyManager::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ScreenPolyManager::InitializeClass()
{
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			ScreenPolyManagerClassID,
			"Adept::ScreenPolyManager",
			Node::DefaultData
		);
	Register_Object(DefaultData);

	ScreenPolyManager::Instance = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ScreenPolyManager::TerminateClass()
{
	if (ScreenPolyManager::Instance)
	{
		Unregister_Object(ScreenPolyManager::Instance);
		delete ScreenPolyManager::Instance;
	}

	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ScreenPolyManager::ScreenPolyManager():
	Node(DefaultData),
	polyGroupSocket(NULL, false)
{
	nextGroup = 0;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ScreenPolyManager::~ScreenPolyManager()
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ScreenPolyManager::AdoptCamera(CameraElement *camera)
{
	Check_Object(this);
	Check_Object(camera);

	Camera = camera;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MString
	ScreenPolyManager::CreateScreenPoly(
		int *polyIndex,
		Vector4D **corners,
		RGBAColor **colors,
		Vector2DOf<Scalar> **uvs,
		bool **status,
		int priority_level,
		MString texture_name,
		MString alpha_name)

{
	Check_Object(this);

	//This function has to do a ton of shit!

	//First 
	//Create a StateSwitch based upon the parameters
	StateChange *quad_state = new StateChange();
	Register_Object(quad_state);

	StateChange::RenderPass level;
	level = (StateChange::RenderPass)priority_level;
	level = (StateChange::RenderPass)(level + StateChange::PostPass1);
	quad_state->SetRenderPass(level);

	Check_Object(MLRTexturePool::Instance);

	// change later to the right image instances !!!
	if(strcmp(texture_name, "None"))
	{
		MLRTexture *quad_texture = (*MLRTexturePool::Instance)(texture_name, 0);
		if(!quad_texture)
		{
			quad_texture = MLRTexturePool::Instance->Add(texture_name, 0);
		}
		Check_Object(quad_texture);
		quad_state->SetTextureHandle(quad_texture->GetTextureHandle());
	}

	//Sets for all Screen Quads elements
	if(!strcmp(alpha_name, "AlphaInvAlphaMode"))
	{
		quad_state->SetAlphaMode(StateChange::AlphaInvAlphaMode);
	}
	else if(!strcmp(alpha_name, "AlphaOneMode"))
	{
		quad_state->SetAlphaMode(StateChange::AlphaOneMode);
	}

	quad_state->DisableDithering();
	quad_state->DisableBackfaceCulling();
	quad_state->SetFilterMode(StateChange::PointSampleMode);
	quad_state->DisableFog();
	quad_state->SetLightingMode(StateChange::NoLightingMode);
	quad_state->DisablePerspectiveCorrection();
	quad_state->SetWireFrameMode(StateChange::SolidMode);
	quad_state->DisableZBufferWrite();
	quad_state->DisableZBufferCompare();

	//Second 
	//Run through the group list to find a poly group that
	//has the same state.
	SortedChainIteratorOf<ScreenQuadsElement *, MString> iterator(&polyGroupSocket);
	iterator.First();
	ScreenQuadsElement *quad_group;
	ScreenQuadsElement *found_group = NULL;
	bool found = false;
	while((!found) && ((quad_group = iterator.ReadAndNext()) != NULL))
	{
		Check_Pointer(quad_group);
		found = true;
		//Check the group state with the quad_state
		if(quad_state->GetRenderPass() != quad_group->GetStateChange()->GetRenderPass())
		{
			found = false;
		}
		if(quad_state->GetTextureHandle() != quad_group->GetStateChange()->GetTextureHandle())
		{
			found = false;
		}
		found_group = quad_group;
	}

	//Third
	//If a group with an identical StateSwitch is found then
	//get the next available index from the group and set the
	//pointers
	if(found)
	{
		bool poly_found = false;
		int index = 0;
		while(!poly_found)
		{
			found_group->GetQuadData(index, corners, colors, uvs, status);
			if(*(*status) == false)
			{
				poly_found = true;
			}
			index++;
		}
		*(*status) = true;
	}
	//If the group is not found then a new group with using the
	//current state must be created and added to the chain.  Returning
	//0 as the index a the pointers must be set. 
	else
	{
		ScreenQuadsElement *new_quad;

		new_quad = new ScreenQuadsElement(20);
		Register_Object(new_quad);
		new_quad->AdoptStateChange(quad_state);
		new_quad->SetName(texture_name);
		Check_Object(Camera);
		Camera->AttachChild(new_quad);
		new_quad->Sync();
		polyGroupSocket.AddValue(new_quad, texture_name);
		new_quad->GetQuadData(0, corners, colors, uvs, status);
		*(*status) = true;
	}

	//Set the status in the current group of the poly with the given
	//index
	return texture_name;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MString
	ScreenPolyManager::CreateTextString(
		int str_len,
		char *string_text,
		Vector4D **text_corners,
		RGBAColor **text_colors,
		Vector2DOf<Scalar> **text_uvs,
		bool **text_status,
		int priority_level,
		MString string_texture)

{
	Check_Object(this);

	//This function has to do a ton of shit!

	//First 
	//Create a StateSwitch based upon the parameters
	StateChange *quad_state = new StateChange();
	Register_Object(quad_state);

	StateChange::RenderPass level;
	level = (StateChange::RenderPass)priority_level;
	level = (StateChange::RenderPass)(level + StateChange::PostPass1);
	quad_state->SetRenderPass(level);

	Check_Object(MLRTexturePool::Instance);

	// change later to the right image instances !!!
	if(strcmp(string_texture, "None"))
	{
		MLRTexture *quad_texture = (*MLRTexturePool::Instance)(string_texture, 0);
		if(!quad_texture)
		{
			quad_texture = MLRTexturePool::Instance->Add(string_texture, 0);
		}
		Check_Object(quad_texture);
		quad_state->SetTextureHandle(quad_texture->GetTextureHandle());
	}

	//Sets for all Screen Quads elements
	quad_state->SetAlphaMode(StateChange::AlphaInvAlphaMode);
	quad_state->DisableDithering();
	quad_state->DisableBackfaceCulling();
	quad_state->SetFilterMode(StateChange::PointSampleMode);
	quad_state->DisableFog();
	quad_state->SetLightingMode(StateChange::NoLightingMode);
	quad_state->DisablePerspectiveCorrection();
	quad_state->SetWireFrameMode(StateChange::SolidMode);
	quad_state->DisableZBufferWrite();
	quad_state->DisableZBufferCompare();

	ScreenQuadsElement *new_quad;
	bool *temp_status;
	bool status;

	status = true;
	temp_status = &status;
	new_quad = new ScreenQuadsElement(50);
	new_quad->AdoptStateChange(quad_state);
	new_quad->SetName(string_text);
	Camera->AttachChild(new_quad);
	new_quad->Sync();
	MString group_name;
	group_name = string_text;
	char num[4];
	sprintf(num, "%d", nextGroup);
	group_name += num;
	nextGroup ++;
	polyGroupSocket.AddValue(new_quad, group_name);
	new_quad->GetQuadData(0, text_corners, text_colors, text_uvs, text_status);

	int i;

	for(i=0; i<str_len; i++)
	{
		new_quad->SetQuadStatus(i, true);
	}

//	return string_text; 
	return group_name;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ScreenPolyManager::RemovePolyGroup(const MString& group_name)
{
	Check_Object(this);

	ScreenQuadsElement *removed_quad = polyGroupSocket.Find(group_name);
	if(removed_quad)
	{
		polyGroupSocket.Remove(removed_quad);
	}
	delete removed_quad;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
	ScreenPolyManager::GetWValue(Scalar z)
{
	Check_Object(this);
	Scalar w;
	Scalar l, r, t, b, n, f;

	Camera->GetNearPlaneBorders(&l, &r, &t, &b, &n, &f);

	w = 1/(n + z * (f - n));
	return w;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
#if 0
void
	ScreenPolyManager::ReleaseScreenPoly(MString group_name, int poly_index);
{
	Check_Object(this);

	SortedChainIteratorOf<ScreenQuadsElement *, MString> iterator(&polyGroupSocket);
	ScreenQuadsElement *group;

	group = iterator.Find(group_name);

	Check_Pointer(group);
#endif