/*
**	Command & Conquer Renegade(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program is free software: you can redistribute it and/or modify
**	it under the terms of the GNU General Public License as published by
**	the Free Software Foundation, either version 3 of the License, or
**	(at your option) any later version.
**
**	This program is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**	GNU General Public License for more details.
**
**	You should have received a copy of the GNU General Public License
**	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/***********************************************************************************************
 ***              C O N F I D E N T I A L  ---  W E S T W O O D  S T U D I O S               ***
 ***********************************************************************************************
 *                                                                                             *
 *                 Project Name : Combat																		  *
 *                                                                                             *
 *                     $Archive:: /Commando/Code/wwui/stylemgr.cpp          $*
 *                                                                                             *
 *                       Author:: Patrick Smith                                                *
 *                                                                                             *
 *                     $Modtime:: 1/26/02 1:23p                                              $*
 *                                                                                             *
 *                    $Revision:: 33                                                          $*
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 * Functions:                                                                                  *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

// Disable warning about exception handling not being enabled. It's used as part of STL - in a part of STL we don't use.
#pragma warning(disable : 4530)

#include "stylemgr.h"
#include "render2d.h"
#include "assetmgr.h"
#include "texture.h"
#include "font3d.h"
#include "render2dsentence.h"
#include "ini.h"
#include "ffactory.h"
#include "wwaudio.h"


////////////////////////////////////////////////////////////////
//	Local constants
////////////////////////////////////////////////////////////////
static const char *	DEFAULT_BACKDROP_NAME	= "GRADENT_TEST.TGA";


struct FONT_DESC
{
	const char *	name;
	int				point_size;
	bool				is_bold;
};


static FONT_DESC	DEFAULT_FONTS[StyleMgrClass::FONT_MAX] =
{
	{ "Regatta Condensed LET",	52,	false },
	{ "Arial MT",					12,	true },
	{ "Arial MT",					8,		true },
	{ "Arial MT",					8,		false },
	{ "Arial MT",					8,		false },
	{ "Regatta Condensed LET",	32,	false },
	{ "Regatta Condensed LET",	20,	false },
	{ "Arial MT",					9,		true },
	{ "Arial MT",					12,	true },
	
	{ "Arial MT",					10,	false },
	{ "Arial MT",					10,	true },

	{ "Arial MT",					8,		false },
	{ "Arial MT",					16,	false },
	{ "Arial MT",					14,	false },
	{ "Arial MT",					9,		true }


	/*{ "Arial Unicode MS",	52,	false },
	{ "Arial Unicode MS",	12,	true },
	{ "Arial Unicode MS",	12,		true },
	{ "Arial Unicode MS",	12,		false },
	{ "Arial Unicode MS",	12,		false },
	{ "Arial Unicode MS",	32,	false },
	{ "Arial Unicode MS",	20,	false },
	{ "Arial Unicode MS",	13,		true },
	{ "Arial Unicode MS",	14,	true }*/

};


////////////////////////////////////////////////////////////////
//	Local constants
////////////////////////////////////////////////////////////////
TextureClass *				StyleMgrClass::BackdropTexture			= NULL;

uint32						StyleMgrClass::TitleColor					= RGB_TO_INT32 (255, 255, 255);
uint32						StyleMgrClass::TitleHilightColor			= RGB_TO_INT32 (255, 255, 0);
uint32						StyleMgrClass::TitleShadowColor			= RGB_TO_INT32 (0, 0, 0);
uint32						StyleMgrClass::TextColor					= RGB_TO_INT32 (255, 213, 40);
uint32						StyleMgrClass::TextShadowColor			= RGBA_TO_INT32 (0, 0, 0, 200);
uint32						StyleMgrClass::LineColor					= RGB_TO_INT32 (255, 174, 40);
uint32						StyleMgrClass::BkColor						= RGBA_TO_INT32 (255, 174, 40, 40);
uint32						StyleMgrClass::DisabledTextColor			= RGBA_TO_INT32 (255, 213, 40, 140);
uint32						StyleMgrClass::DisabledTextShadowColor	= RGBA_TO_INT32 (0, 0, 0, 96);
uint32						StyleMgrClass::DisabledLineColor			= RGBA_TO_INT32 (230, 160, 35, 128);
uint32						StyleMgrClass::DisabledBkColor			= RGBA_TO_INT32 (255, 174, 40, 30);
uint32						StyleMgrClass::HilightColor				= RGB_TO_INT32 (70, 70, 70);

uint32						StyleMgrClass::TabTextColor				= RGB_TO_INT32 (255, 255, 255);
uint32						StyleMgrClass::TabGlowColor				= RGB_TO_INT32 (16, 10, 0);

FontCharsClass *			StyleMgrClass::Fonts[FONT_MAX]			= { NULL };
float							StyleMgrClass::ScaleX						= 1.0F;
float							StyleMgrClass::ScaleY						= 1.0F;

DynamicVectorClass<StringClass>	StyleMgrClass::FontFileList;
StringClass								StyleMgrClass::EventAudioList[StyleMgrClass::EVENT_AUDIO_MAX];


////////////////////////////////////////////////////////////////
//
//	Initialize
//
////////////////////////////////////////////////////////////////
void
StyleMgrClass::Initialize (void)
{
	//
	//	Compute the scale
	//
	ScaleX = Render2DClass::Get_Screen_Resolution().Width () / 800.0F;
	ScaleY = Render2DClass::Get_Screen_Resolution().Height () / 600.0F;

	//
	//	Load each font
	//
	for (int index = 0; index < FONT_MAX; index ++) {

		//
		//	Scale the point size to fit this resolution
		//
		float point_size = ((float)DEFAULT_FONTS[index].point_size) * ScaleY;

		//
		//	Create the font
		//
		Fonts[index] = WW3DAssetManager::Get_Instance()->Get_FontChars (DEFAULT_FONTS[index].name,
								point_size, DEFAULT_FONTS[index].is_bold);
	}

	//
	//	Load the backdrop texture name
	//
	BackdropTexture = WW3DAssetManager::Get_Instance()->Get_Texture (DEFAULT_BACKDROP_NAME, TextureClass::MIP_LEVELS_1);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Initialize_From_INI
//
////////////////////////////////////////////////////////////////
void
StyleMgrClass::Initialize_From_INI (const char *filename)
{
	Shutdown ();

	//
	//	Compute the scale
	//
	ScaleX = Render2DClass::Get_Screen_Resolution().Width () / 800.0F;
	ScaleY = Render2DClass::Get_Screen_Resolution().Height () / 600.0F;

	//
	//	Get the INI file
	//
	INIClass *ini_file = NULL;
	FileClass *file_obj = _TheFileFactory->Get_File (filename);
	if (file_obj != NULL && file_obj->Is_Available( ) ) {
		ini_file = new INIClass (*file_obj);
		_TheFileFactory->Return_File (file_obj);
	}

	if (ini_file != NULL) {

		const char *FONT_FILE_SECTION	= "Font File List";
		const char *FONT_NAME_SECTION	= "Font Names";

		const char *FONT_INI_ENTRIES[FONT_MAX] = 
		{		
			"FONT_TITLE",
			"FONT_LG_CONTROLS",
			"FONT_CONTROLS",
			"FONT_LISTS",
			"FONT_TOOLTIPS",
			"FONT_MENU",
			"FONT_SM_MENU",
			"FONT_HEADER",
			"FONT_BIG_HEADER",
			"FONT_CREDITS",
			"FONT_CREDITS_BOLD",
			"FONT_INGAME_TXT",
			"FONT_INGAME_BIG_TXT",
			"FONT_INGAME_SUBTITLE_TXT",
			"FONT_INGAME_HEADER_TXT"
		};

		//
		//	Load each font into windows
		//
		int count = ini_file->Entry_Count (FONT_FILE_SECTION);
		for (int index = 0; index < count; index ++) {
			StringClass	filename (0, true);
			ini_file->Get_String (filename, FONT_FILE_SECTION, ini_file->Get_Entry (FONT_FILE_SECTION, index));

			//
			//	Install the font into windows
			//
			::AddFontResource (filename);
			FontFileList.Add (filename);
		}

		//
		//	Read information about each font and load it into the system
		//
		for (index = 0; index < FONT_MAX; index ++) {
			
			//
			//	Read information about this font
			//
			StringClass font_entry;
			ini_file->Get_String (font_entry, FONT_NAME_SECTION, FONT_INI_ENTRIES[index]);
			
			//
			//	Parse the information
			//
			StringClass font_name	= ::strtok (font_entry.Peek_Buffer (), ",");
			StringClass font_size	= ::strtok (NULL, ",");
			StringClass font_bold	= ::strtok (NULL, ",");
			bool is_bold				= (::atoi (font_bold) != 0);

			//
			//	Scale the point size to fit this resolution
			//
			float point_size = ((float)::atoi (font_size)) * ScaleY;			
			
			//
			//	Remove bold from "small" fonts if they're scaled down
			//
			point_size = max (point_size, 8.0F);
			if (point_size < 10.0F && ScaleY < 1.0F) {
				is_bold = false;
			}

			//
			//	Create the font
			//
			Fonts[index] = WW3DAssetManager::Get_Instance()->Get_FontChars (font_name,
									point_size, is_bold);

		}

		//
		//	Audio section constants
		//
		const char *AUDIO_SECTION		= "Audio";
		const char *AUDIO_CLICK			= "AUDIO_CLICK";
		const char *AUDIO_MOUSEOVER	= "AUDIO_MOUSEOVER";
		const char *AUDIO_BACK			= "AUDIO_BACK";
		const char *AUDIO_POPUP			= "AUDIO_POPUP";

		//
		//	Read information about the sound effects
		//
		ini_file->Get_String (EventAudioList[EVENT_MOUSE_CLICK], AUDIO_SECTION, AUDIO_CLICK);
		ini_file->Get_String (EventAudioList[EVENT_MOUSE_OVER],	AUDIO_SECTION, AUDIO_MOUSEOVER);
		ini_file->Get_String (EventAudioList[EVENT_MENU_BACK],	AUDIO_SECTION, AUDIO_BACK);
		ini_file->Get_String (EventAudioList[EVENT_POPUP],			AUDIO_SECTION, AUDIO_POPUP);

		//
		//	Free the ini file
		//
		delete ini_file;
		ini_file = NULL;
	}

	return ;
}


////////////////////////////////////////////////////////////////
//
//	Shutdown
//
////////////////////////////////////////////////////////////////
void
StyleMgrClass::Shutdown (void)
{
	//
	//	Free each font
	//
	for (int index = 0; index < FONT_MAX; index ++) {
		REF_PTR_RELEASE (Fonts[index]);
	}

	//
	//	Unregister this font with windows
	//
	for (index = 0; index < FontFileList.Count (); index ++) {
		::RemoveFontResource (FontFileList[index]);
	}

	//
	//	Free the backdrop texture
	//
	REF_PTR_RELEASE (BackdropTexture);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Get_Font
//
////////////////////////////////////////////////////////////////
FontCharsClass *
StyleMgrClass::Get_Font (FONT_STYLE style)
{
	FontCharsClass *font = Fonts[style];
	if (font != NULL) {
		font->Add_Ref ();
	}
	return font;
}


////////////////////////////////////////////////////////////////
//
//	Render_Backdrop
//
////////////////////////////////////////////////////////////////
void
StyleMgrClass::Render_Backdrop (Render2DClass *renderer, const RectClass &rect)
{
	//
	//	Simply set the texture, and render a quad filling the rectangle
	//
	renderer->Set_Texture (BackdropTexture);
	renderer->Add_Quad (rect, RectClass (0, 0, 1, 1));
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Assign_Font
//
////////////////////////////////////////////////////////////////
void
StyleMgrClass::Assign_Font (Render2DSentenceClass *renderer, FONT_STYLE style)
{
	renderer->Set_Font (Fonts[style]);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Render_Text
//
////////////////////////////////////////////////////////////////
/*void
StyleMgrClass::Render_Text
(
	const WCHAR *			text,
	Render2DTextClass *	renderer,
	int						x_pos,
	int						y_pos,
	bool						do_shadow,
	const RectClass *		clipping_rect,
	bool						is_enabled
)
{
	//
	//	If necessary, assign the clipping rectangle
	//
	if (clipping_rect != NULL) {
		renderer->Set_Clipping_Rect (*clipping_rect);
	}

	//
	//	Determine what color to render the text in
	//
	int text_color		= TextColor;
	int shadow_color	= TextShadowColor;
	if (is_enabled == false) {
		text_color		= DisabledTextColor;
		shadow_color	= DisabledTextShadowColor;
	}

	//
	//	Render the shadow (if necessary)
	//
	if (do_shadow) {
		renderer->Set_Location (Vector2 (x_pos - 1, y_pos + 1));
		renderer->Draw_Text (text, shadow_color);
	}

	//
	//	Set the position where text will be drawn
	//
	renderer->Set_Location (Vector2 (x_pos, y_pos));

	//
	//	Draw the text
	//
	renderer->Draw_Text (text, text_color);
	return ;
}*/


////////////////////////////////////////////////////////////////
//
//	Render_Title_Text
//
////////////////////////////////////////////////////////////////
void
StyleMgrClass::Render_Title_Text
(
	const WCHAR *				text,
	Render2DSentenceClass *	renderer,
	const RectClass &			rect
)
{
	//
	//	Set the clipping rectangle
	//
	//renderer->Set_Clipping_Rect (rect);

	//
	//	Get the extents of the text we will be drawing
	//
	Vector2 text_extent = renderer->Get_Text_Extents (text);

	//
	//	Center the text
	//
	int x_pos = int(rect.Left + (rect.Width () / 2) - (text_extent.X / 2));
	int y_pos = int(rect.Top + (rect.Height () / 2) - (text_extent.Y / 2));
	
	//
	//	Build the textures for the text we'll be drawing
	//
	renderer->Build_Sentence (text);

	//
	//	Draw the shadow
	//
	renderer->Set_Location (Vector2 (x_pos - 1, y_pos - 1));
	renderer->Draw_Sentence (TitleShadowColor);

	//
	//	Draw the hilight
	//
	renderer->Set_Location (Vector2 (x_pos + 1, y_pos + 1));
	renderer->Draw_Sentence (TitleHilightColor);

	//
	//	Draw the text
	//
	renderer->Set_Location (Vector2 (x_pos, y_pos));
	renderer->Draw_Sentence (TitleColor);		
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Render_Text
//
////////////////////////////////////////////////////////////////
void
StyleMgrClass::Render_Text
(
	const WCHAR *				text,
	Render2DSentenceClass *	renderer,
	const RectClass &			rect,	
	bool							do_shadow,
	bool							do_clip,
	JUSTIFICATION				justify,
	bool							is_enabled,
	bool							is_vcentered
)
{
	//
	//	Determine what color to render the text in
	//
	int text_color		= TextColor;
	int shadow_color	= TextShadowColor;
	if (is_enabled == false) {
		text_color		= DisabledTextColor;
		shadow_color	= DisabledTextShadowColor;
	}

	Render_Text (text, renderer, text_color, shadow_color, rect, do_shadow, do_clip, justify, is_vcentered);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Render_Text
//
////////////////////////////////////////////////////////////////
void
StyleMgrClass::Render_Text
(
	const WCHAR *				text,
	Render2DSentenceClass *	renderer,
	uint32						text_color,
	uint32						shadow_color,
	const RectClass &			rect,	
	bool							do_shadow,
	bool							do_clip,
	JUSTIFICATION				justify,
	bool							is_vcentered
)
{
	//
	//	If necessary, assign the clipping rectangle
	//
	if (do_clip) {
		renderer->Set_Clipping_Rect (rect);
	}

	//
	//	Get the extents of the text we will be drawing
	//
	Vector2 text_extent = renderer->Get_Text_Extents (text);

	//
	//	Assume left justification
	//
	int x_pos = rect.Left + 1;
	int y_pos = int(rect.Top + (rect.Height () / 2) - (text_extent.Y / 2));
	if (is_vcentered == false) {
		y_pos = rect.Top;
	}

	//
	//	Handle other justifications
	//
	if (justify == RIGHT_JUSTIFY) {
		
		//
		//	Caclulate right justification
		//
		x_pos = int(rect.Right - text_extent.X);
	} else if (justify == CENTER_JUSTIFY) {

		//
		//	Calculate center justification
		//
		x_pos = int(rect.Left + (rect.Width () / 2) - (text_extent.X / 2));
	}

	//
	//	Construct the textures needed to render the text
	//
	renderer->Build_Sentence (text);

	//
	//	Render the shadow (if necessary)
	//
	if (do_shadow) {
		renderer->Set_Location (Vector2 (x_pos - 1, y_pos + 1));
		renderer->Draw_Sentence (shadow_color);
	}

	//
	//	Render the text
	//
	renderer->Set_Location (Vector2 (x_pos, y_pos));
	renderer->Draw_Sentence (text_color);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Render_Text
//
////////////////////////////////////////////////////////////////
/*void
StyleMgrClass::Render_Text
(
	const WCHAR *			text,
	Render2DTextClass *	renderer,
	uint32					text_color,
	uint32					shadow_color,
	const RectClass &		rect,	
	bool						do_shadow,
	bool						do_clip,
	JUSTIFICATION			justify
)
{
	//
	//	If necessary, assign the clipping rectangle
	//
	if (do_clip) {
		renderer->Set_Clipping_Rect (rect);
	}

	//
	//	Get the extents of the text we will be drawing
	//
	Vector2 text_extent = renderer->Get_Text_Extents (text);

	//
	//	Assume left justification
	//
	int x_pos = rect.Left + 1;
	int y_pos = int(rect.Top + (rect.Height () / 2) - (text_extent.Y / 2));

	//
	//	Handle other justifications
	//
	if (justify == RIGHT_JUSTIFY) {
		
		//
		//	Caclulate right justification
		//
		x_pos = int(rect.Right - text_extent.X);
	} else if (justify == CENTER_JUSTIFY) {

		//
		//	Calculate center justification
		//
		x_pos = int(rect.Left + (rect.Width () / 2) - (text_extent.X / 2));
	}

	//
	//	Render the shadow (if necessary)
	//
	if (do_shadow) {
		renderer->Set_Location (Vector2 (x_pos - 1, y_pos + 1));
		renderer->Draw_Text (text, shadow_color);
	}

	//
	//	Render the text
	//
	renderer->Set_Location (Vector2 (x_pos, y_pos));
	renderer->Draw_Text (text, text_color);
	return ;
}*/



////////////////////////////////////////////////////////////////
//
//	Render_Text
//
////////////////////////////////////////////////////////////////
/*void
StyleMgrClass::Render_Text
(
	const WCHAR *				text,
	Render2DSentenceClass *	renderer,
	uint32						text_color,
	uint32						shadow_color,
	const RectClass &			rect,	
	bool							do_shadow,
	bool							do_clip,
	JUSTIFICATION				justify
)
{
	//
	//	If necessary, assign the clipping rectangle
	//
	if (do_clip) {
		renderer->Set_Clipping_Rect (rect);
	}

	//
	//	Get the extents of the text we will be drawing
	//
	Vector2 text_extent = renderer->Get_Text_Extents (text);

	//
	//	Assume left justification
	//
	int x_pos = rect.Left + 1;
	int y_pos = int(rect.Top + (rect.Height () / 2) - (text_extent.Y / 2));

	//
	//	Handle other justifications
	//
	if (justify == RIGHT_JUSTIFY) {
		
		//
		//	Caclulate right justification
		//
		x_pos = int(rect.Right - text_extent.X);
	} else if (justify == CENTER_JUSTIFY) {

		//
		//	Calculate center justification
		//
		x_pos = int(rect.Left + (rect.Width () / 2) - (text_extent.X / 2));
	}

	//
	//	Build up the text we want to render
	//
	renderer->Build_Sentence (text);

	//
	//	Render the shadow (if necessary)
	//
	if (do_shadow) {
		renderer->Set_Location (Vector2 (x_pos - 1, y_pos + 1));
		renderer->Draw_Sentence (shadow_color);
	}

	//
	//	Render the text
	//
	renderer->Set_Location (Vector2 (x_pos, y_pos));
	renderer->Draw_Sentence (text_color);
	return ;
}*/

////////////////////////////////////////////////////////////////
//
//	Render_Wrapped_Text
//
////////////////////////////////////////////////////////////////
void
StyleMgrClass::Render_Wrapped_Text
(
	const WCHAR *				text,
	Render2DSentenceClass *	renderer,
	const RectClass &			rect,
	bool							do_shadow,
	bool							do_vcenter,
	bool							is_enabled	
)
{
	//
	//	Determine what color to render the text in
	//
	int text_color		= TextColor;
	int shadow_color	= TextShadowColor;
	if (is_enabled == false) {
		text_color		= DisabledTextColor;
		shadow_color	= DisabledTextShadowColor;
	}

	//
	//	Render the text
	//
	Render_Wrapped_Text (text, renderer, text_color, shadow_color, rect, do_shadow, do_vcenter);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Render_Wrapped_Text
//
////////////////////////////////////////////////////////////////
void
StyleMgrClass::Render_Wrapped_Text_Ex
(
	const WCHAR *				text,
	Render2DSentenceClass *	renderer,
	const RectClass &			rect,
	bool							do_shadow,
	bool							do_vcenter,
	bool							is_enabled,
	JUSTIFICATION				justify
)
{
	//
	//	Determine what color to render the text in
	//
	int text_color		= TextColor;
	int shadow_color	= TextShadowColor;
	if (is_enabled == false) {
		text_color		= DisabledTextColor;
		shadow_color	= DisabledTextShadowColor;
	}

	//
	//	Render the text
	//
	Render_Wrapped_Text_Ex (text, renderer, text_color, shadow_color, rect,
		do_shadow, do_vcenter, justify);
	return ;
}



////////////////////////////////////////////////////////////////
//
//	Render_Wrapped_Text
//
////////////////////////////////////////////////////////////////
void
StyleMgrClass::Render_Wrapped_Text_Ex
(
	const WCHAR *				text,
	Render2DSentenceClass *	renderer,
	uint32						text_color,
	uint32						shadow_color, 
	const RectClass &			rect,
	bool							do_shadow,
	bool							do_vcenter,
	JUSTIFICATION				justify
)
{
	//
	//	Enable wrapping
	//
	renderer->Set_Wrapping_Width (rect.Width ());
	renderer->Set_Clipping_Rect (rect);

	//
	//	First, get the number of lines of text
	//
	int row_count = 0;
	renderer->Get_Formatted_Text_Extents (text, &row_count);

	//
	//	Calculate where to start spitting out the text
	//
	float text_height		= renderer->Peek_Font ()->Get_Char_Height ();
	RectClass curr_rect	= rect;
	if (do_vcenter) {
		curr_rect.Top = int(rect.Center ().Y - ((row_count * text_height) * 0.5F));
	}

	//
	//	Handy macro
	//
	#define COPY_LINE(dest,	src_start, src_end)	\
			if (src_end == NULL) {						\
				dest = src_start;							\
			} else {											\
				uint32 bytes	= ((uint32)src_end - (uint32)src_start);	\
				uint32 len		= bytes / sizeof (WCHAR);						\
				::memcpy (dest.Get_Buffer (len + 1), src_start, bytes);	\
				dest.Peek_Buffer ()[len] = 0;										\
			}

	//
	//	Loop over all the lines of text and check for wrapping...
	//
	const WCHAR *line_start = renderer->Find_Row_Start (text, 0);
	while (line_start != NULL) {

		//
		//	Lookup the start of the next line...
		//
		const WCHAR *line_end = renderer->Find_Row_Start (line_start, 1);
		
		//
		//	Copy this line of text into the control
		//
		WideStringClass curr_text;
		COPY_LINE (curr_text, line_start, line_end);

		//
		//	Render this row of text
		//
		Render_Text (curr_text, renderer, text_color, shadow_color, curr_rect,
			do_shadow, false, justify, false);

		//
		//	Advance to the next line...
		//
		line_start = line_end;
		curr_rect.Top	+= text_height;
	}


	return ;
}


////////////////////////////////////////////////////////////////
//
//	Render_Wrapped_Text
//
////////////////////////////////////////////////////////////////
void
StyleMgrClass::Render_Wrapped_Text
(
	const WCHAR *				text,
	Render2DSentenceClass *	renderer,
	uint32						text_color,
	uint32						shadow_color, 
	const RectClass &			rect,
	bool							do_shadow,
	bool							do_vcenter
)
{
	//
	//	Enable wrapping
	//
	renderer->Set_Wrapping_Width (rect.Width ());
	renderer->Set_Clipping_Rect (rect);

	//
	//	Assume left justification
	//
	int x_pos = rect.Left + 1;
	int y_pos = rect.Top + 1;

	//
	//	Center the text vertically if necessary
	//
	if (do_vcenter) {
		Vector2 extents = renderer->Get_Formatted_Text_Extents (text);
		y_pos = rect.Top + (rect.Height () / 2.0F) - (extents.Y / 2.0F);
	}

	//
	//	Build the textures for the text we'll be drawing
	//
	renderer->Build_Sentence (text);

	//
	//	Render the shadow (if necessary)
	//
	if (do_shadow) {
		renderer->Set_Location (Vector2 (x_pos - 1, y_pos + 1));
		renderer->Draw_Sentence (shadow_color);
	}

	//
	//	Render the text
	//
	renderer->Set_Location (Vector2 (x_pos, y_pos));
	renderer->Draw_Sentence (text_color);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Configure_Hilighter
//
////////////////////////////////////////////////////////////////
void
StyleMgrClass::Configure_Hilighter (Render2DClass *renderer)
{
	renderer->Enable_Alpha (false);
	renderer->Enable_Texturing (false);
	
	//
	//	Setup an additive shader
	//
	ShaderClass *shader = renderer->Get_Shader ();
	shader->Set_Dst_Blend_Func (ShaderClass::DSTBLEND_ONE);
	shader->Set_Src_Blend_Func (ShaderClass::SRCBLEND_ONE);	
	//shader->Set_Primary_Gradient (ShaderClass::GRADIENT_ADD);
	//shader->Set_Secondary_Gradient (ShaderClass::SECONDARY_GRADIENT_DISABLE);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Render_Hilight
//
////////////////////////////////////////////////////////////////
void
StyleMgrClass::Render_Hilight (Render2DClass *renderer, const RectClass &rect)
{
	renderer->Add_Quad (rect, HilightColor);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Render_Glow
//
////////////////////////////////////////////////////////////////
void
StyleMgrClass::Render_Glow
(
	const WCHAR *				text,
	Render2DSentenceClass *	renderer,
	const RectClass &			rect,
	int							radius_x,
	int							radius_y,
	int							color,
	JUSTIFICATION				justify
)
{
	//
	//	Get the extents of the text we will be drawing
	//
	Vector2 text_extent = renderer->Get_Text_Extents (text);

	//
	//	Assume centered text
	//
	int x_pos = int(rect.Left + (rect.Width () / 2) - (text_extent.X / 2));
	int y_pos = int(rect.Top + (rect.Height () / 2) - (text_extent.Y / 2));

	if (justify == LEFT_JUSTIFY) {
		
		//
		//	Caclulate left justification
		//
		x_pos = int(rect.Left + 1);
	} else if (justify == RIGHT_JUSTIFY) {
		
		//
		//	Caclulate right justification
		//
		x_pos = int(rect.Right - text_extent.X);
	}

	//
	//	Setup an additive shader
	//
	renderer->Make_Additive ();
	
	//
	//	Figure out how many passes we should do to get the
	// desired result
	//
	float max_radius	= max (radius_x, radius_y);
	int pass_count		= 4;//max_radius / 3;
	//pass_count			= min (pass_count, 5);
	//pass_count			= max (pass_count, 3);

	int step_count		= 7;//max_radius;
	//step_count			= min (step_count, 10);
	//step_count			= max (step_count, 4);
	float angle_inc	= DEG_TO_RADF (360) / step_count;

	float x_inc = radius_x / pass_count;
	float y_inc = radius_y / pass_count;

	float curr_radiusx = 2.0F;
	float curr_radiusy = 2.0F;

	//
	//	Do four passes to get from the inner radius to the outer radius
	//
	for (int pass_index = 0; pass_index < pass_count; pass_index ++) {
		
		//
		//	Circle the characters around using the given radius
		//
		float angle = 0;
		for (int index = 0; index < step_count; index ++) {
			
			float new_x_pos = float(x_pos + (WWMath::Cos(angle) * curr_radiusx));
			float new_y_pos = float(y_pos + (WWMath::Sin(angle) * curr_radiusy));

			angle += angle_inc;

			//
			//	Render the text
			//
			renderer->Set_Location (Vector2 (new_x_pos, new_y_pos));
			renderer->Draw_Sentence (color);
		}

		curr_radiusx += x_inc;
		curr_radiusy += y_inc;
	}
	
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Configure_Renderer
//
////////////////////////////////////////////////////////////////
void
StyleMgrClass::Configure_Renderer (Render2DClass *renderer)
{
	//
	//	Set the coordinate range for the renderer
	//
	renderer->Set_Coordinate_Range (Render2DClass::Get_Screen_Resolution ());

	//
	//	Turn depth-buffer reading on for this renderer
	//
	//ShaderClass *shader = renderer->Get_Shader ();
	//shader->Set_Depth_Compare (ShaderClass::PASS_LEQUAL);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Play_Sound
//
////////////////////////////////////////////////////////////////
void
StyleMgrClass::Play_Sound (EVENT_AUDIO event)
{
	if (	WWAudioClass::Get_Instance () == NULL ||
			EventAudioList[event].Get_Length () == 0)
	{
		return ;
	}

	//
	//	Parse the information
	//
	StringClass tmp_copy (EventAudioList[event], true);
	StringClass filename		= ::strtok (tmp_copy.Peek_Buffer (), ",");
	StringClass vol_string	= ::strtok (NULL, ",");
	float volume				= ::atoi (vol_string) / 100.0F;

	//
	//	Play the sound effect
	//
	WWAudioClass::Get_Instance ()->Simple_Play_2D_Sound_Effect (filename, 1.0F, volume);
	return ;
}
