/*
**	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/>.
*/

/***********************************************************************************************
 ***                            Confidential - Westwood Studios                              ***
 ***********************************************************************************************
 *                                                                                             *
 *                 Project Name : Commando                                                     *
 *                                                                                             *
 *                     $Archive:: /Commando/Code/Combat/hud.cpp                               $*
 *                                                                                             *
 *                      $Author:: Byon_g                                                      $*
 *                                                                                             *
 *                     $Modtime:: 2/11/02 2:27p                                               $*
 *                                                                                             *
 *                    $Revision:: 228                                                         $*
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 * Functions:                                                                                  *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#include "hud.h"

#include <stdio.h>

#include "wwprofile.h"
#include "assets.h"
#include "font3d.h"
#include "combat.h"
#include "soldier.h"
#include "debug.h"
#include "ccamera.h"
#include "vehicle.h"
#include "weapons.h"
#include "radar.h"
#include "texture.h"
#include "phys.h"
#include "render2d.h"
#include "hudinfo.h"
#include "globalsettings.h"
#include "translatedb.h"
#include "playerdata.h"
#include "playertype.h"
#include "sniper.h"
#include "render2dsentence.h"
#include "input.h"
#include "building.h"
#include "objectives.h"
#include "weaponbag.h"
#include "string_ids.h"
#include "gametype.h"
#include "stylemgr.h"


static void Generate_WChar_Text_From_Number(WCHAR* text,int digits,int min_digits,int value)
{
	text[digits]=0;
	while (digits) {
		digits--;
		text[digits]=value%10+'0';
		value/=10;
		min_digits--;
		if (value==0 && (min_digits == 0)) break;
	}
	if ((min_digits==0) && digits) {
		int i=0;
		while (WCHAR c=text[digits++]) {
			text[i++]=c;
		}
		text[i]=0;
	}
}

/*
**
*/
Vector2	INFO_UV_SCALE( 1.0f/256.0f, 1.0f/256.0f );

Vector2 INFO_OFFSET( 7, -179 );
Vector2 FRAME_1_UV_UL( 96, 105 );
Vector2 FRAME_1_UV_LR( 214, 255 );
Vector2 FRAME_1_OFFSET( -3, -1 );
Vector2 FRAME_2_UV_UL( 215, 125 );
Vector2 FRAME_2_UV_LR( 255, 192 );
Vector2 FRAME_2_OFFSET( 114, 57 );
Vector2 FRAME_3_UV_UL( 218, 192 );
Vector2 FRAME_3_UV_LR( 255, 201 );
Vector2 FRAME_3_OFFSET( 154, 115 );
Vector2 FRAME_4_UV_UL( 216, 200 );
Vector2 FRAME_4_UV_LR( 255, 255 );
Vector2 FRAME_4_OFFSET( 191, 115 );
Vector2 FRAME_5_UV_UL( 80, 203 );
Vector2 FRAME_5_UV_LR( 100, 258 );
Vector2 FRAME_5_OFFSET( 230, 116 );
Vector2 FRAME_6_UV_UL( 216, 101 );
Vector2 FRAME_6_UV_LR( 240, 125 );
Vector2 FRAME_6_OFFSET( 74, 149 );
Vector2 HEALTH_BACK_UV_UL( 183, 241 );
Vector2 HEALTH_BACK_UV_LR( 186, 248 );
Vector2 HEALTH_BACK_UL( 98, 122 );
Vector2 HEALTH_BACK_LR( 224, 168 );
Vector2 GRADIENT_BLACK_UV_UL( 3, 135 );
Vector2 GRADIENT_BLACK_UV_LR( 44, 144 );
Vector2 HEALTH_TEXT_BACK_UL( 77, 124 );
Vector2 HEALTH_TEXT_BACK_LR( 163, 150 );
Vector2 HEALTH_UV_UL( 94, 52 );
Vector2 HEALTH_UV_LR( 249, 100 );
Vector2 HEALTH_OFFSET( 73, 121 );
Vector2 SHIELD_UV_UL( 66, 97 );
Vector2 SHIELD_UV_LR( 96, 132 );
Vector2 SHIELD_OFFSET( 211, 140 );
Vector2 KEY_1_UV_UL( 30, 180 );
Vector2 KEY_1_UV_LR( 57, 197 );
Vector2 KEY_1_OFFSET( 32, 134 );
Vector2 KEY_2_UV_UL( 0, 181 );
Vector2 KEY_2_UV_LR( 30, 197 );
Vector2 KEY_2_OFFSET( 41, 140 );
Vector2 KEY_3_UV_UL( 69, 133 );
Vector2 KEY_3_UV_LR( 97, 149 );
Vector2 KEY_3_OFFSET( 50, 148 );
Vector2 HEALTH_CROSS_1_UV_UL( 33, 199 );
Vector2 HEALTH_CROSS_1_UV_LR( 63, 226 );
Vector2 HEALTH_CROSS_1_OFFSET( 77, 124 );
Vector2 HEALTH_CROSS_2_UV_UL( 33, 228 );
Vector2 HEALTH_CROSS_2_UV_LR( 63, 258 );
Vector2 HEALTH_CROSS_2_OFFSET( 77, 124 );
Vector2 TIME_BACK_UL( 150, 97 );
Vector2 TIME_BACK_LR( 213, 116 );
Vector2 TIME_CLOCK_UV_UL( 46, 125 );
Vector2 TIME_CLOCK_UV_LR( 66, 148 );
Vector2 TIME_CLOCK_OFFSET( 186, 94 );
Vector2 WEAPON_BOX_UV_UL( 0, 0 );
Vector2 WEAPON_BOX_UV_LR( 95, 95 );
Vector2 WEAPON_BOX_OFFSET( 195, -53 );
Vector2 POWER_OUT_ICON_UV_UL( 0, 95 );
Vector2 POWER_OUT_ICON_UV_LR( 30, 129 );
Vector2 POWER_OUT_ICON_OFFSET( 143, 41 );
Vector2 REPAIR_ICON_UV_UL( 31, 97 );
Vector2 REPAIR_ICON_UV_LR( 61, 126 );
Vector2 REPAIR_ICON_OFFSET( 181, 43 );
Vector2 GDI_ICON_UV_UL( 14, 222 );
Vector2 GDI_ICON_UV_LR( 34, 238 );
Vector2 GDI_ICON_OFFSET( 217, 77 );
Vector2 NOD_ICON_UV_UL( 14, 205 );
Vector2 NOD_ICON_UV_LR( 34, 221 );
Vector2 NOD_ICON_OFFSET( 238, 76 );
Vector2 NEUTRAL_ICON_UV_UL( 14, 238 );
Vector2 NEUTRAL_ICON_UV_LR( 33, 257 );
Vector2 NEUTRAL_ICON_OFFSET( 260, 77 );
Vector2 BULLET_ICON_UV_UL( 2, 211 );
Vector2 BULLET_ICON_UV_LR( 13, 255 );
Vector2 BULLET_ICON_OFFSET( -20, -30 );
Vector2 RADAR_CENTER_OFFSET( 55, 78 );
Vector2 DAMAGE_1_UV_UL( 65, 184 );
Vector2 DAMAGE_1_UV_LR( 78, 255 );
Vector2 DAMAGE_2_UV_UL( 200, 3 );
Vector2 DAMAGE_2_UV_LR( 248, 51 );
Vector2 HORIZ_DAMAGE_SIZE( 81, 14 );
Vector2 VERT_DAMAGE_SIZE( 15, 78 );
Vector2 DIAG_DAMAGE_SIZE( 53, 59 );
Vector2 HV_DAMAGE_OFFSET( 170, 168 );
Vector2 DIAG_DAMAGE_OFFSET( 119, 117 );
//Vector2 POWERUP_BOX_UV_UL( 48, 0 );
//Vector2 POWERUP_BOX_UV_LR( 129, 54 );
Vector2 POWERUP_BOX_UV_UL( 50, 1 );
Vector2 POWERUP_BOX_UV_LR( 127, 52 );
Vector2 RADAR_RINGS_UV_UL( 95, 0 );
Vector2 RADAR_RINGS_UV_LR( 197, 53 );
Vector2 RADAR_RINGS_L_OFFSET( -51, -50 );
Vector2 RADAR_RINGS_R_OFFSET( 0, -50 );
Vector2 RADAR_STAR_UV_UL( 241, 103 );
Vector2 RADAR_STAR_UV_LR( 249, 111 );
Vector2 RADAR_STAR_OFFSET( 280, 50 );
Vector2 RADAR_SQUARE_UV_UL( 247, 85 );
Vector2 RADAR_SQUARE_UV_LR( 255, 93 );
Vector2 RADAR_SQUARE_OFFSET( 290, 50 );
Vector2 RADAR_TRIANGLE_UV_UL( 247, 93 );
Vector2 RADAR_TRIANGLE_UV_LR( 255, 101 );
Vector2 RADAR_TRIANGLE_OFFSET( 300, 50 );
Vector2 RADAR_CIRCLE_UV_UL( 247, 77 );
Vector2 RADAR_CIRCLE_UV_LR( 255, 85 );
Vector2 RADAR_CIRCLE_OFFSET( 310, 50 );
Vector2 RADAR_BRACKET_UV_UL( 241, 114 );
Vector2 RADAR_BRACKET_UV_LR( 249, 122 );
Vector2 RADAR_BRACKET_OFFSET( 320, 50 );
Vector2 RADAR_SWEEP_UV_UL( 80, 182 );
Vector2 RADAR_SWEEP_UV_LR( 95, 191 );
Vector2 RADAR_SWEEP_OFFSET( 330, 50 );

Vector2 TARGET_HEALTH_L_UV_UL( 0, 165 );
Vector2 TARGET_HEALTH_L_UV_LR( 20, 181 );
Vector2 TARGET_HEALTH_R_UV_UL( 20, 165 );
//Vector2 TARGET_HEALTH_R_UV_LR( 96, 181 );
Vector2 TARGET_HEALTH_R_UV_LR( 96, 173 );
Vector2 TARGET_HEALTH_OFFSET( 123, 5 );
Vector2 TARGET_NAME_UV_UL( 1, 149 );
Vector2 TARGET_NAME_UV_LR( 91, 164 );
Vector2 TARGET_NAME_OFFSET( 125, 24 );


	// Reticle
#define	RETICLE_WIDTH	(64.0f/640.0f)
#define	RETICLE_HEIGHT	(64.0f/480.0f)


//

Vector2 TARGET_ENTERABLE_UV_UL( 45, 209 );
Vector2 TARGET_ENTERABLE_UV_LR( 51, 215 );
Vector2 TARGET_ENTERABLE_SIZE( 32, 32 );
float	  TARGET_ENTERABLE_BOUNCE	 = 4;

/*
**
*/
//#define		LARGE_FONT		"FONT24x36.TGA"
#define		LARGE_FONT		"FONT12x16.TGA"
#define		MEDIUM_FONT		"FONT12x16.TGA"
#define		SMALL_FONT		"FONT6x8.TGA"

enum
{
	HUD_HELP_TEXT_DISPLAYING = 0,
	HUD_HELP_TEXT_FADING,
	HUD_HELP_TEXT_DONE
};

/*
**
*/
#define		HUD_MAIN_TEXTURE		"HUD_MAIN.TGA"
#define		HUD_CHATPBOX_TEXTURE	"HUD_CHATPBOX.TGA"
#define		HUD_WEAPONS_TEXTURE	"hud_TibRVoltR.tga"			/* This should be removed */
Render2DClass *			InfoRenderer;
Render2DSentenceClass * HUDHelpTextRenderer;
Vector2						HUDHelpTextExtents (0, 0);
float							HUDHelpTextTimer = 0;
int							HUDHelpTextState = HUD_HELP_TEXT_DISPLAYING;


/*
**
*/
unsigned long COLOR( float alpha, unsigned long color = 0x00FFFFFF )
{
	alpha = WWMath::Clamp( alpha, 0, 1 ) * 255.0f;
	color &= 0x00FFFFFF;
	color |= ((int)alpha) << 24;
	return color;
}

unsigned long Get_Health_Color( float percent )
{
	Vector3	color = HUDGlobalSettingsDef::Get_Instance()->Get_Health_High_Color();
	if ( percent <= 0.5f ) {
		color = HUDGlobalSettingsDef::Get_Instance()->Get_Health_Med_Color();
	}
	if ( percent <= 0.25f ) {
		color = HUDGlobalSettingsDef::Get_Instance()->Get_Health_Low_Color();
	}

	return color.Convert_To_ARGB();
}

/*
** Powerup Display
*/
struct PowerupIconStruct {

	PowerupIconStruct( void ) : Renderer( NULL ), Number( 0 )	{}

	~PowerupIconStruct( void )	{
		if ( Renderer != NULL ) {
			delete Renderer;
			Renderer = NULL;
		}
	}

	WideStringClass	Name;
	int				Number;
	Render2DClass * Renderer;
	RectClass		UV;
	RectClass		IconBox;
	float			Timer;
};

// Two lists.  A right one for weapons, health, and armor
static	DynamicVectorClass<PowerupIconStruct*>	RightPowerupIconList;
// and a left one for keys
static	DynamicVectorClass<PowerupIconStruct*>	LeftPowerupIconList;

Render2DClass * PowerupBoxRenderer;
Render2DSentenceClass * PowerupTextRenderer;

#define		MAX_ICONS		5
#define		POWERUP_TIME	6

static	void	Powerup_Init( void )
{
	PowerupBoxRenderer = new Render2DClass();
	PowerupBoxRenderer->Set_Texture( HUD_CHATPBOX_TEXTURE );
	PowerupBoxRenderer->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );
	PowerupBoxRenderer->Enable_Additive( true );

	FontCharsClass * font = StyleMgrClass::Peek_Font( StyleMgrClass::FONT_INGAME_TXT );
	PowerupTextRenderer = new Render2DSentenceClass();
	PowerupTextRenderer->Set_Font( font );

	WWASSERT( LeftPowerupIconList.Count() == 0 );
	WWASSERT( RightPowerupIconList.Count() == 0 );
}

static	void	Powerup_Shutdown( void )
{
	delete PowerupBoxRenderer;
	PowerupBoxRenderer = NULL;

	delete PowerupTextRenderer;
	PowerupTextRenderer = NULL;

	int i;
	for ( i = 0; i < LeftPowerupIconList.Count(); i++ ) {
		delete LeftPowerupIconList[i];
	}
	LeftPowerupIconList.Delete_All();
	for ( i = 0; i < RightPowerupIconList.Count(); i++ ) {
		delete RightPowerupIconList[i];
	}
	RightPowerupIconList.Delete_All();
}

static	void	Powerup_Add( const WCHAR * name, int number, const char * texture_name, const RectClass & uv, const Vector2 & offset, bool right_list = true )
{
	PowerupIconStruct * data = new PowerupIconStruct();
	data->Renderer = new Render2DClass();
	StringClass new_name(true);
	Strip_Path_From_Filename( new_name, texture_name );
	data->Renderer->Set_Texture( new_name );
	data->Renderer->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );
//	data->Renderer->Enable_Additive( true );

//	SurfaceClass::SurfaceDescription surface_desc;
//	data->Renderer->Peek_Texture()->Get_Level_Description( surface_desc );
//	float size = surface_desc.Width;		// Assume square
	float size = data->Renderer->Peek_Texture()->Get_Width(); // Assume square
	data->UV = uv;
	if ( size > 0 ) {
		data->UV.Scale( Vector2( 1/size, 1/size ) );
	}
	data->IconBox = uv;
	data->IconBox += offset + Vector2( 0, -40.0f ) - data->IconBox.Upper_Left();
	data->Name = name;
	data->Number = number;
 	data->Timer = POWERUP_TIME;

	if ( right_list ) {
		RightPowerupIconList.Add( data );
	} else {
		LeftPowerupIconList.Add( data );
	}
}

void 	Powerup_Reset( void )
{
	while ( LeftPowerupIconList.Count() ) {
		delete LeftPowerupIconList[0];
		LeftPowerupIconList.Delete(0);
	}
	while ( RightPowerupIconList.Count() ) {
		delete RightPowerupIconList[0];
		RightPowerupIconList.Delete(0);
	}
}

#define		POWERUP_BOX_BASE		POWERUP_BOX_WIDTH + 6, 112
#define		POWERUP_BOX_WIDTH		80
#define		POWERUP_BOX_HEIGHT		55
#define		POWERUP_BOX_SPACING		(POWERUP_BOX_HEIGHT + 10)
#define		POWERUP_BOX_UV			127,0,207,55

static	void	Powerup_Update( void )
{
	PowerupBoxRenderer->Reset();
	PowerupTextRenderer->Reset();

	RectClass box_uv( POWERUP_BOX_UV_UL, POWERUP_BOX_UV_LR );
	box_uv.Scale( Vector2( 1.0f/128.0f, 1.0f/128.0f ) );

#define	ANIMATE_TIME	1.0f

	// Two timers
	static float LeftAnimateTimer = 0;
	static float RightAnimateTimer = 0;

	if ( LeftPowerupIconList.Count() > 0 && LeftPowerupIconList[0]->Timer < 0 ) {
		LeftAnimateTimer += TimeManager::Get_Frame_Seconds();
		if ( LeftAnimateTimer > ANIMATE_TIME ) {
			LeftAnimateTimer = 0;
			if ( LeftPowerupIconList.Count() ) {
				delete LeftPowerupIconList[0];
				LeftPowerupIconList.Delete(0);
			}
		}
	} else {
		LeftAnimateTimer = 0;
	}

	if ( RightPowerupIconList.Count() > 0 && RightPowerupIconList[0]->Timer < 0 ) {
		RightAnimateTimer += TimeManager::Get_Frame_Seconds();
		if ( RightAnimateTimer > ANIMATE_TIME ) {
			RightAnimateTimer = 0;
			if ( RightPowerupIconList.Count() ) {
				delete RightPowerupIconList[0];
				RightPowerupIconList.Delete(0);
			}
		}
	} else {
		RightAnimateTimer = 0;
	}

 	RectClass box( POWERUP_BOX_UV_UL, POWERUP_BOX_UV_LR );
	Vector2 start = Render2DClass::Get_Screen_Resolution().Lower_Right() - Vector2( POWERUP_BOX_BASE );
	box += start - box.Lower_Left();
	box -= Vector2( box.Left - 6, +75 );

	int i;
	for ( i = 0; i < MAX_ICONS && i < LeftPowerupIconList.Count(); i++ ) {

		LeftPowerupIconList[i]->Timer -= TimeManager::Get_Frame_Seconds();

		RectClass draw_box = box;

		int green = 0xFF00FF00;
		int white = 0xFFFFFFFF;

		// Slide the bottom (first) icon away
		if ( i == 0 && LeftAnimateTimer > 0.0f ) {
			green = COLOR( WWMath::Clamp( 1.0f - (LeftAnimateTimer/ANIMATE_TIME), 0, 1 ), green ) ;
			white = COLOR( WWMath::Clamp( 1.0f - (LeftAnimateTimer/ANIMATE_TIME), 0, 1 ), white ) ;
		}

#if 0		// No boxes
		// The box is drawn additive, so his color is green alpha
		int box_color = (white & 0xFF000000) | ((white >> 16) & 0x0000FF00);
		PowerupBoxRenderer->Add_Quad( draw_box, box_uv, box_color );
#endif

		// Draw powerup name
		PowerupTextRenderer->Build_Sentence( LeftPowerupIconList[i]->Name );
		PowerupTextRenderer->Set_Location( Vector2( draw_box.Left + 1, draw_box.Top + POWERUP_BOX_HEIGHT - 15 ) );
		PowerupTextRenderer->Draw_Sentence( white );

#if 0
		// Draw powerup count
		if ( LeftPowerupIconList[i]->Number != 0 ) {
			WideStringClass num(0,true);
			num.Format( L"%d", LeftPowerupIconList[i]->Number );
			PowerupTextRenderer->Build_Sentence( num );
			PowerupTextRenderer->Set_Location( Vector2( draw_box.Right - 12, draw_box.Top + 1 ) );
			PowerupTextRenderer->Draw_Sentence( white );
		}
#endif

		RectClass	icon_box = LeftPowerupIconList[i]->IconBox;
		icon_box += draw_box.Upper_Left();

		LeftPowerupIconList[i]->Renderer->Reset();
		LeftPowerupIconList[i]->Renderer->Add_Quad( icon_box, LeftPowerupIconList[i]->UV, white );

		// Drop the remaining icons down
		if ( i == 0 && LeftAnimateTimer > ANIMATE_TIME * 0.5f ) {
			box += Vector2( 0, ((2*LeftAnimateTimer/ANIMATE_TIME)-1) * POWERUP_BOX_SPACING );
		}

		box -= Vector2( 0, POWERUP_BOX_SPACING );
	}

	// Setup box for right
 	box = RectClass( POWERUP_BOX_UV_UL, POWERUP_BOX_UV_LR );
	start = Render2DClass::Get_Screen_Resolution().Lower_Right() - Vector2( POWERUP_BOX_BASE );
	box += start - box.Lower_Left();

	for ( i = 0; i < MAX_ICONS && i < RightPowerupIconList.Count(); i++ ) {

		RightPowerupIconList[i]->Timer -= TimeManager::Get_Frame_Seconds();

		RectClass draw_box = box;

		int green = 0xFF00FF00;
		int white = 0xFFFFFFFF;

		// Slide the bottom (first) icon away
		if ( i == 0 && RightAnimateTimer > 0.0f ) {
			green = COLOR( WWMath::Clamp( 1.0f - (RightAnimateTimer/ANIMATE_TIME), 0, 1 ), green ) ;
			white = COLOR( WWMath::Clamp( 1.0f - (RightAnimateTimer/ANIMATE_TIME), 0, 1 ), white ) ;
		}

#if 0		// No boxes
		// The box is drawn additive, so his color is green alpha
		int box_color = (white & 0xFF000000) | ((white >> 16) & 0x0000FF00);
		PowerupBoxRenderer->Add_Quad( draw_box, box_uv, box_color );
#endif

		// Draw powerup name
		PowerupTextRenderer->Build_Sentence( RightPowerupIconList[i]->Name );
		float left_edge = draw_box.Left + 1;
		Vector2 extents = PowerupTextRenderer->Get_Text_Extents( RightPowerupIconList[i]->Name );
		if ( left_edge + extents.X + 1> Render2DClass::Get_Screen_Resolution().Right ) {
			left_edge = Render2DClass::Get_Screen_Resolution().Right - extents.X - 1;
		}
		PowerupTextRenderer->Set_Location( Vector2( left_edge, draw_box.Top + POWERUP_BOX_HEIGHT - 15 ) );
		PowerupTextRenderer->Draw_Sentence( white );

		// Draw powerup count
		if ( RightPowerupIconList[i]->Number != 0 ) {
			WideStringClass num(0,true);
			num.Format( L"%d", RightPowerupIconList[i]->Number );
			PowerupTextRenderer->Build_Sentence( num );
			PowerupTextRenderer->Set_Location( Vector2( draw_box.Right - 12, draw_box.Top + 1 ) );
			PowerupTextRenderer->Draw_Sentence( white );
		}

		RectClass	icon_box = RightPowerupIconList[i]->IconBox;
		icon_box += draw_box.Upper_Left();

		RightPowerupIconList[i]->Renderer->Reset();
		RightPowerupIconList[i]->Renderer->Add_Quad( icon_box, RightPowerupIconList[i]->UV, green );

		// Drop the remaining icons down
		if ( i == 0 && RightAnimateTimer > ANIMATE_TIME * 0.5f ) {
			box += Vector2( 0, ((2*RightAnimateTimer/ANIMATE_TIME)-1) * POWERUP_BOX_SPACING );
		}

		box -= Vector2( 0, POWERUP_BOX_SPACING );
	}

}

static	void	Powerup_Render( void )
{
#if 0		// No boxes
	PowerupBoxRenderer->Render();
#endif

	int i;
	for ( i = 0; i < MAX_ICONS && i < LeftPowerupIconList.Count(); i++ ) {
		LeftPowerupIconList[i]->Renderer->Render();
	}
	for ( i = 0; i < MAX_ICONS && i < RightPowerupIconList.Count(); i++ ) {
		RightPowerupIconList[i]->Renderer->Render();
	}

	PowerupTextRenderer->Render();
}


/*
** Weapon Display
*/
Render2DClass * WeaponBoxRenderer;
Render2DClass * WeaponImageRenderer;
Render2DTextClass * WeaponClipCountRenderer;
Render2DTextClass * WeaponTotalCountRenderer;
Render2DSentenceClass * WeaponNameRenderer;
Vector2			WeaponBase;

WeaponClass *	_LastHUDWeapon = NULL;
int				_LastVehicleSeat = -1;


#define		WEAPON_OFFSET			100, 110
//#define		WEAPON_BOX_UV			0,0,95,95

#define		SNIPER_UV				90,0,255,53
#define		SNIPER_OFFSET			-80,-4


static void HUD_Help_Text_Init( void )
{
	//
	//	Load the font...
	//
	FontCharsClass *font = StyleMgrClass::Peek_Font( StyleMgrClass::FONT_INGAME_BIG_TXT );
	WWASSERT (font != NULL);

	//
	//	Configure the renderer
	//
	HUDHelpTextRenderer = new Render2DSentenceClass;
	HUDHelpTextRenderer->Set_Font( font );
	HUDHelpTextExtents.Set (0, 0);
	HUDHelpTextTimer = 0;
	HUDHelpTextState = HUD_HELP_TEXT_DISPLAYING;
	return ;
}

static	void	HUD_Help_Text_Render( void )
{
	const float HUD_HELP_TEXT_FADE_TIME = 2.0F;
	const float HUD_HELP_TEXT_DISPLAY_TIME = 2.0F;

	const WideStringClass &string = HUDInfo::Get_HUD_Help_Text();
	bool is_empty = string.Is_Empty();

	//
	//	Rebuild the renderer (if necessary)
	//
	if (HUDInfo::Is_HUD_Help_Text_Dirty()) {
		HUDHelpTextState = HUD_HELP_TEXT_DISPLAYING;
		HUDInfo::Set_Is_HUD_Help_Text_Dirty( false );
		HUDHelpTextRenderer->Reset();
		if (is_empty == false) {
			HUDHelpTextRenderer->Build_Sentence( string );
			HUDHelpTextTimer = HUD_HELP_TEXT_DISPLAY_TIME;
		}
		HUDHelpTextExtents = HUDHelpTextRenderer->Get_Text_Extents (string);
	}

	//
	//	Draw the text if there's something to draw
	//
	if ( is_empty == false ) {
		HUDHelpTextRenderer->Reset_Polys();

		//
		//	Render the text above the reticle
		//
		Vector2 reticle_offset = COMBAT_CAMERA->Get_Camera_Target_2D_Offset();

		const RectClass &screen_rect = Render2DClass::Get_Screen_Resolution();
		float x_pos = screen_rect.Center ().X - (HUDHelpTextExtents.X * 0.5F);
		float y_pos = screen_rect.Center ().Y - (HUDHelpTextExtents.Y);
		y_pos -= (RETICLE_HEIGHT * screen_rect.Height () * 0.25F);

		HUDHelpTextRenderer->Set_Location( Vector2( x_pos, y_pos ) );
		HUDHelpTextRenderer->Draw_Sentence( RGB_TO_INT32 (0, 0, 0) );
		HUDHelpTextRenderer->Set_Location( Vector2( x_pos-1, y_pos-1 ) );
		HUDHelpTextRenderer->Draw_Sentence( VRGB_TO_INT32 (HUDInfo::Get_HUD_Help_Text_Color ()) );

		//
		//	Fade the text out (if necessary)
		//
		if (HUDHelpTextState == HUD_HELP_TEXT_FADING) {
			float percent = WWMath::Clamp ((HUDHelpTextTimer / HUD_HELP_TEXT_FADE_TIME), 0.0F, 1.0F);
			HUDHelpTextRenderer->Force_Alpha (percent * 0.5F);
		} else {
			HUDHelpTextRenderer->Force_Alpha (0.5F);
		}

		//
		//	Render the quads
		//
		HUDHelpTextRenderer->Render();

		//
		//	Advance to the next state
		//
		HUDHelpTextTimer -= TimeManager::Get_Frame_Seconds ();
		if (HUDHelpTextTimer <= 0) {
			HUDHelpTextState ++;

			//
			//	Clear the text if necessary
			//
			if (HUDHelpTextState >= HUD_HELP_TEXT_DONE) {
				HUDInfo::Set_HUD_Help_Text( L"" );
				HUDHelpTextRenderer->Reset();
			} else if (HUDHelpTextState == HUD_HELP_TEXT_FADING) {
				HUDHelpTextTimer = HUD_HELP_TEXT_FADE_TIME;
			}
		}
	}

	return ;
}

static	void	HUD_Help_Text_Shutdown( void )
{
	delete HUDHelpTextRenderer;
	HUDHelpTextRenderer = NULL;
	return ;
}

static	void	Weapon_Init( void )
{
	WeaponBoxRenderer = new Render2DClass();
	WeaponBoxRenderer->Set_Texture( HUD_MAIN_TEXTURE );
	WeaponBoxRenderer->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );
	RectClass box_uv( WEAPON_BOX_UV_UL, WEAPON_BOX_UV_LR );
	RectClass draw_box = box_uv;
	box_uv.Scale( Vector2( 1.0f/256.0f, 1.0f/256.0f ) );
	draw_box += Render2DClass::Get_Screen_Resolution().Lower_Right() - Vector2( WEAPON_OFFSET ) - draw_box.Upper_Left();
	WeaponBoxRenderer->Add_Quad( draw_box, box_uv );
	WeaponBase = draw_box.Upper_Left();

	WeaponImageRenderer = new Render2DClass();
	WeaponImageRenderer->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );

	FontCharsClass *chars_font = StyleMgrClass::Peek_Font( StyleMgrClass::FONT_INGAME_TXT );
	WeaponNameRenderer = new Render2DSentenceClass();
	WeaponNameRenderer->Set_Font( chars_font );
//	WeaponNameRenderer->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );

	Font3DInstanceClass * font = WW3DAssetManager::Get_Instance()->Get_Font3DInstance( LARGE_FONT );
	SET_REF_OWNER( font );
	WeaponClipCountRenderer = new Render2DTextClass( font );
	WeaponClipCountRenderer->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );
	font->Release_Ref();

	font = WW3DAssetManager::Get_Instance()->Get_Font3DInstance( SMALL_FONT );
	SET_REF_OWNER( font );
	WeaponTotalCountRenderer = new Render2DTextClass( font );
	WeaponTotalCountRenderer->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );
	font->Release_Ref();

	_LastHUDWeapon = NULL;
	_LastVehicleSeat = -1;


}

static	void	Weapon_Shutdown( void )
{
	delete WeaponBoxRenderer;
	WeaponBoxRenderer = NULL;

	delete WeaponImageRenderer;
	WeaponImageRenderer = NULL;

	delete WeaponNameRenderer;
	WeaponNameRenderer = NULL;

	delete WeaponClipCountRenderer;
	WeaponClipCountRenderer = NULL;

	delete WeaponTotalCountRenderer;
	WeaponTotalCountRenderer = NULL;
}

#define		CLIP_ROUNDS_OFFSET		15,27
#define		TOTAL_ROUNDS_OFFSET		65,34
#define		WEAPON_NAME_OFFSET		-10, 95

float	LastClipCount = 0;
float	CenterClipCountTimer = 0;
const float	CENTER_CLIP_COUNT_TIME	= 2.0f;

enum {
	SEAT_DRIVER = 0,
	SEAT_GUNNER,
	SEAT_PASENGER,
};

const char * _Seat_Textures[3] = {
	"hud_driverseat.tga",	// SEAT_DRIVER = 0,
	"hud_gunseat.tga",	// SEAT_GUNNER,
	"hud_passseat.tga",	// SEAT_PASENGER,
};

static	void	Weapon_Reset( void ) 
{
	_LastHUDWeapon = (WeaponClass *)0xFFFFFFFF;		// force weapon to re-draw next
	_LastVehicleSeat = -1;	// force vehicle seat to re-draw next
}

static	void	Weapon_Update( void ) 
{
	WeaponClass * weapon = NULL;
	if ( COMBAT_STAR ) {
		weapon = COMBAT_STAR->Get_Weapon();

		if ( COMBAT_STAR->Get_Vehicle() ) {
			weapon = COMBAT_STAR->Get_Vehicle()->Get_Weapon();
		}

	}

	WeaponClipCountRenderer->Reset();
	WeaponTotalCountRenderer->Reset();

	if ( weapon != NULL ) {
//		StringClass	text;
//		text.Format( "%03d", weapon->Get_Clip_Rounds() );
		WCHAR tmp_text[5];
		if ( weapon->Get_Clip_Rounds() == -1 ) {
			//text.Format( "999", weapon->Get_Total_Rounds() );
			tmp_text[0]='9';
			tmp_text[1]='9';
			tmp_text[2]='9';
			tmp_text[3]=0;
		} else {
			Generate_WChar_Text_From_Number(tmp_text,3,3,weapon->Get_Clip_Rounds());
		}

		WeaponClipCountRenderer->Set_Location( WeaponBase + Vector2( CLIP_ROUNDS_OFFSET ) );
		WeaponClipCountRenderer->Draw_Text( tmp_text );

		if ( LastClipCount != weapon->Get_Clip_Rounds() ) {
			LastClipCount = weapon->Get_Clip_Rounds();
			CenterClipCountTimer = CENTER_CLIP_COUNT_TIME;
		}

		if ( CenterClipCountTimer > 0 ) {
			// Also draw the above at the center

			Vector2	center_clip_count_offset = Render2DClass::Get_Screen_Resolution().Center();
			center_clip_count_offset.X *= 1.5;

			float fade = WWMath::Clamp( CenterClipCountTimer, 0, 1 );

			RectClass uv;
			uv.Set( BULLET_ICON_UV_UL, BULLET_ICON_UV_LR );
			RectClass draw = uv;
			uv.Scale( INFO_UV_SCALE );
			draw += center_clip_count_offset + BULLET_ICON_OFFSET - draw.Upper_Left();
			InfoRenderer->Add_Quad( draw, uv, COLOR( fade ) );

			WeaponClipCountRenderer->Set_Location( draw.Upper_Right() + Vector2( 4, 15 ) );
			WeaponClipCountRenderer->Draw_Text( tmp_text, COLOR( fade ) );

			CenterClipCountTimer -= TimeManager::Get_Frame_Seconds();
		}


		if ( weapon->Get_Total_Rounds() == -1 ) {
			//text.Format( "999", weapon->Get_Total_Rounds() );
			tmp_text[0]='9';
			tmp_text[1]='9';
			tmp_text[2]='9';
			tmp_text[3]=0;
		} else {
//			text.Format( "%03d", weapon->Get_Total_Rounds() - weapon->Get_Clip_Rounds() );
			Generate_WChar_Text_From_Number(tmp_text,3,3,weapon->Get_Total_Rounds() - weapon->Get_Clip_Rounds());
		}
		WeaponTotalCountRenderer->Set_Location( WeaponBase + Vector2( TOTAL_ROUNDS_OFFSET ) );
		WeaponTotalCountRenderer->Draw_Text( tmp_text );
	}

	// If in vehicle, don't draw the weapon icon and name,
	// draw a seat icon and the vehicle name
	if ( COMBAT_STAR->Get_Vehicle() ) {
		int seat = SEAT_PASENGER;

		if ( COMBAT_STAR->Get_Vehicle()->Get_Driver() == COMBAT_STAR ) {
			seat = SEAT_DRIVER;
		} else if ( COMBAT_STAR->Get_Vehicle()->Get_Gunner() == COMBAT_STAR ) {
			seat = SEAT_GUNNER;
		}

		if ( _LastVehicleSeat != seat ) {
			_LastVehicleSeat = seat;
			_LastHUDWeapon = (WeaponClass *)0xFFFFFFFF;		// force weapon to re-draw next

			WeaponImageRenderer->Reset();
			StringClass filename = _Seat_Textures[seat];
			WeaponImageRenderer->Set_Texture( filename );
			Vector2		offset( 16, 34 );
			RectClass icon_box( 0,0,64,64 );
			icon_box += WeaponBase + offset - icon_box.Upper_Left();
			WeaponImageRenderer->Add_Quad( icon_box );

			// Draw Name Backdrop
			WeaponNameRenderer->Reset();
			WideStringClass name(COMBAT_STAR->Get_Vehicle()->Get_Vehicle_Name(),true);
			WeaponNameRenderer->Build_Sentence( name );
			Vector2 text_size = WeaponNameRenderer->Get_Text_Extents( name );
			WeaponNameRenderer->Set_Location( Render2DClass::Get_Screen_Resolution().Lower_Right() - text_size );
			WeaponNameRenderer->Draw_Sentence();

		}

	} else if ( _LastHUDWeapon != weapon ) {		// Update the weapon icon
		WWPROFILE( "Weapon Change" );
		_LastHUDWeapon = weapon;
		_LastVehicleSeat = -1;	// force vehicle seat to re-draw next


		WeaponImageRenderer->Reset();
		WeaponNameRenderer->Reset();

		if ( weapon != NULL ) {

			StringClass filename( HUD_WEAPONS_TEXTURE, true );
			RectClass	uv( 0,64,128,128 );
			Vector2		offset( -24, 38  );

			const WeaponDefinitionClass * def = weapon->Get_Definition();
			if ( !def->IconTextureName.Is_Empty() ) {
				Strip_Path_From_Filename( filename, def->IconTextureName );
				uv = def->IconTextureUV;
				offset = def->IconOffset;

#if 0		// Used to find offsets
				static	Vector2	tweak_add(0,0);
				Vector2 add(0,0);
				add.X += Input::Get_Amount( INPUT_FUNCTION_MOVE_LEFT ) - Input::Get_Amount( INPUT_FUNCTION_MOVE_RIGHT );
				add.Y += Input::Get_Amount( INPUT_FUNCTION_MOVE_FORWARD ) - Input::Get_Amount( INPUT_FUNCTION_MOVE_BACKWARD );
				tweak_add -= add;
				offset += tweak_add;
				_LastHUDWeapon = NULL;
				if ( add.Length() != 0 ) {
					Debug_Say(( "%s offset %f %f\n", def->Get_Name(), offset.X, offset.Y ));
				}
#endif
			}

			RectClass icon_box = uv;
			icon_box += WeaponBase + offset - icon_box.Upper_Left();

			{
				StringClass new_name(true);
				Strip_Path_From_Filename( new_name, filename );
				WeaponImageRenderer->Set_Texture( new_name );
			}

//			SurfaceClass::SurfaceDescription surface_desc;
//			WeaponImageRenderer->Peek_Texture()->Get_Level_Description( surface_desc );
//			float size = surface_desc.Width;		// Assume square
			float size = WeaponImageRenderer->Peek_Texture()->Get_Width(); // Assume square
			if ( size > 0 ) {
				uv.Scale( Vector2( 1/size, 1/size ) );
			}

			int color = 0xFF00FF00; // green
			WeaponImageRenderer->Add_Quad( icon_box, uv, color );

			// Draw Name Backdrop

			// Right justify Name

			WideStringClass name(0,true); // = L"Rocket Launcher";
			name = TranslateDBClass::Get_String( def->IconNameID );
			WeaponNameRenderer->Build_Sentence( name );
			Vector2 text_size = WeaponNameRenderer->Get_Text_Extents( name ) + Vector2( 1, 0 );
			WeaponNameRenderer->Set_Location( Render2DClass::Get_Screen_Resolution().Lower_Right() - text_size );
			WeaponNameRenderer->Draw_Sentence();
		}
	}
}

static	void	Weapon_Render( void )
{
	WeaponBoxRenderer->Render();
	WeaponImageRenderer->Render();
	WeaponNameRenderer->Render();
	WeaponClipCountRenderer->Render();
	WeaponTotalCountRenderer->Render();
}


/*
** Weapon Chart Display
*/
Render2DClass * WeaponChartBoxRenderer;
static	DynamicVectorClass<Render2DClass *>	WeaponChartIcons;
Render2DSentenceClass * WeaponChartKeynameRenderer;
float	WeaponChartTimer;
#define	WEAPON_CHART_TIME	3.0f

static	void	Weapon_Chart_Init( void )
{
	WeaponChartBoxRenderer = new Render2DClass();
	WeaponChartBoxRenderer->Enable_Texturing( false );
	WeaponChartBoxRenderer->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );

	FontCharsClass *chars_font = StyleMgrClass::Peek_Font( StyleMgrClass::FONT_INGAME_TXT );
	WeaponChartKeynameRenderer = new Render2DSentenceClass();
	WeaponChartKeynameRenderer->Set_Font( chars_font );
}

static	void	Weapon_Chart_Shutdown( void )
{
	delete WeaponChartBoxRenderer;
	WeaponChartBoxRenderer = NULL;

	for ( int i = 0; i < WeaponChartIcons.Count(); i++) {
		delete WeaponChartIcons[i];
		WeaponChartIcons[i] = NULL;
	}
	WeaponChartIcons.Delete_All();

	delete WeaponChartKeynameRenderer;
	WeaponChartKeynameRenderer = NULL;
}

Vector2	WeaponChartBase( 0.11f, 0.05f );
Vector2	WeaponChartSpacing( 0.075f, 0.05f );
float		WeaponChartIconScale = 0.45f / 640.0f;

static	void	Clear_Weapon_Chart_Icons( void )
{
	if ( WeaponChartIcons.Count != 0 ) {
		int i;
		for ( i = 0; i < WeaponChartIcons.Count(); i++) {
			delete WeaponChartIcons[i];
			WeaponChartIcons[i] = NULL;
		}
		WeaponChartIcons.Delete_All();
		WeaponChartKeynameRenderer->Reset();
	}
}

static	void	Build_Weapon_Chart_Icons( void )
{
	WeaponBagClass * weapon_bag = COMBAT_STAR->Get_Weapon_Bag();

	Clear_Weapon_Chart_Icons();

	float screen_scale = Render2DClass::Get_Screen_Resolution().Width();
	Vector2	pos = WeaponChartBase * screen_scale;

	// For each column...
	for ( int column = 1; column <= 10; column++ ) {

		// Add column header
		int key = Input::Get_Primary_Key_For_Function(INPUT_FUNCTION_SELECT_WEAPON_0 + (column%10) );
		WideStringClass name(0,true);
		Input::Get_Translated_Key_Name( key, name );
		WeaponChartKeynameRenderer->Build_Sentence( name );
		Vector2 text_size = WeaponChartKeynameRenderer->Get_Text_Extents( name );
		Vector2 text_offset = pos - text_size/2 - Vector2( 0, WeaponChartSpacing.Y * screen_scale * 0.75f );
		text_offset.X = (int)text_offset.X;
		text_offset.Y = (int)text_offset.Y;
		WeaponChartKeynameRenderer->Set_Location( text_offset );
		WeaponChartKeynameRenderer->Draw_Sentence();

		// Draw weapons in that column
		for ( int i = 0; i < weapon_bag->Get_Count(); i++ ) {
			WeaponClass *	weapon = weapon_bag->Peek_Weapon( i );
			if ( weapon != NULL ) {

				if ( (int)weapon->Get_Key_Number() != (column%10) ) {
					continue;
				}

				StringClass filename( HUD_WEAPONS_TEXTURE, true );
				RectClass	uv( 0,64,128,128 );
				Vector2		offset( -40, 40 );

				const WeaponDefinitionClass * def = weapon->Get_Definition();
				if ( !def->IconTextureName.Is_Empty() ) {
					Strip_Path_From_Filename( filename, def->IconTextureName );
					uv = def->IconTextureUV;
					offset = def->IconOffset;
				}

				RectClass icon_box = uv;
	//			icon_box += pos - icon_box.Upper_Left();
	//			icon_box += offset - icon_box.Upper_Left() + pos;
				icon_box += pos - icon_box.Center();
				icon_box.Scale_Relative_Center( WeaponChartIconScale * screen_scale );
				pos.Y += WeaponChartSpacing.Y * screen_scale;

				// Draw Icon
				Render2DClass * renderer = new Render2DClass();
				WeaponChartIcons.Add( renderer );
				renderer->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );
				StringClass new_name(true);
				Strip_Path_From_Filename( new_name, filename );
				renderer->Set_Texture( new_name );
				if ( renderer->Peek_Texture() != NULL ) {
//					SurfaceClass::SurfaceDescription surface_desc;
//					renderer->Peek_Texture()->Get_Level_Description( surface_desc );
//					float size = surface_desc.Width;		// Assume square
					float size = renderer->Peek_Texture()->Get_Width(); // Assume square
					if ( size > 0 ) {
						uv.Scale( Vector2( 1/size, 1/size ) );
					}
				}
				renderer->Add_Quad( icon_box, uv );
			}
		}

		// Goto next column
		pos.Y = WeaponChartBase.Y * screen_scale;
		pos.X += WeaponChartSpacing.X * screen_scale;
	}

}

bool	ForceChartRebuild = false;

void	HUDClass::Force_Weapon_Chart_Update( void )
{
	ForceChartRebuild = true;
}

void	HUDClass::Force_Weapon_Chart_Display( void )
{
	WeaponChartTimer = WEAPON_CHART_TIME;
}

static	void	Weapon_Chart_Update( void )
{
	if ( COMBAT_STAR == NULL || COMBAT_STAR->Get_Weapon_Bag() == NULL || COMBAT_STAR->Get_Vehicle() != NULL ) {
		Clear_Weapon_Chart_Icons();
		return;
	}

	int i;
	WeaponBagClass * weapon_bag = COMBAT_STAR->Get_Weapon_Bag();
	if ( weapon_bag->HUD_Is_Changed() ) {
		weapon_bag->HUD_Reset_Changed();
		WeaponChartTimer = WEAPON_CHART_TIME;
	}

	WeaponChartTimer -= TimeManager::Get_Frame_Seconds();

	if ( WeaponChartTimer <= 0 ) {
		return;
	}

	// Rebuild the icons if necessary
	// subtract 1 because the first is always null
	if ( ForceChartRebuild || (weapon_bag->Get_Count()-1 != WeaponChartIcons.Count()) ) {
		ForceChartRebuild = false;
		Debug_Say(( "Build icons\n" ));
		Build_Weapon_Chart_Icons();
	}

	float alpha = WWMath::Clamp( WeaponChartTimer, 0, 1 );

	WeaponChartBoxRenderer->Reset();

	// For each column...
	int index = 0;
	for ( int column = 1; column <= 10; column++ ) {

		// Update intensities in that column
		for ( i = 0; i < weapon_bag->Get_Count(); i++ ) {
			WeaponClass *	weapon = weapon_bag->Peek_Weapon( i );
			if ( weapon != NULL ) {

				if ( (int)weapon->Get_Key_Number() != (column%10) ) {
					continue;
				}

				long color = 0x000FF00;		// Dim
				if ( weapon_bag->Get_Index() == i ) {
					color = 0x0000FF00;			// Bright
				}

				// Draw yellow if empty or reloading
//				if ( weapon->Is_Reloading() || weapon->Is_Switching() || weapon->Get_Total_Rounds() == 0 ) {
//				if ( weapon->Is_Switching() || weapon->Get_Total_Rounds() == 0 ) {
				if ( weapon->Get_Total_Rounds() == 0 ) {
					color = 0x00FFFF00;		// Dim yellow
					if ( weapon_bag->Get_Index() == i ) {
						color = 0x00FFFF00;			// Bright yellow
					}
				}

#if 01
				if ( weapon_bag->Get_Index() == i ) {
					color = COLOR( alpha, color );
				} else {
					color = COLOR( alpha * 0.5f, color );
				}
#endif


				WeaponChartIcons[index]->Force_Color( color );
				index++;
			}
		}
	}

	WeaponChartKeynameRenderer->Force_Alpha( alpha );
}

static	void	Weapon_Chart_Render( void )
{
	if ( WeaponChartTimer <= 0 ) {
		return;
	}

	WeaponChartBoxRenderer->Render();
	for ( int i = 0; i < WeaponChartIcons.Count(); i++) {
		WeaponChartIcons[i]->Render();
	}
	WeaponChartKeynameRenderer->Render();
}

/*
** Damage Display
*/
Render2DClass * DamageRenderer;

const int NUM_DAMAGE_INDICATORS	= 8;
float	DamageIndicatorIntensity[ NUM_DAMAGE_INDICATORS ];
bool	DamageIndicatorIntensityChanging;
bool	DamageIndicatorOrientation;

static	void	Damage_Reset( void ) 
{
	for ( int i = 0; i < NUM_DAMAGE_INDICATORS; i++ ) {
		DamageIndicatorIntensity[ i ] = 0;
	}
	DamageIndicatorIntensityChanging = true;
	CombatManager::Clear_Star_Damage_Direction();
}

static	void	Damage_Init( void ) 
{
	DamageRenderer = new Render2DClass();
	DamageRenderer->Set_Texture( HUD_MAIN_TEXTURE );
	DamageRenderer->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );
	DamageRenderer->Enable_Additive( true );

	Damage_Reset();
}

static	void	Damage_Shutdown( void )
{
	delete DamageRenderer;
	DamageRenderer = NULL;
}

static	void	Damage_Add_Indicator( int index, float start_x, float start_y, float end_x, float end_y )
{
	Vector2	vert[4];
	vert[0] = Vector2( start_x, start_y );
	vert[1] = Vector2( start_x, end_y );
	vert[2] = Vector2( end_x, start_y );
	vert[3] = Vector2( end_x, end_y );

	if ( !CombatManager::Is_First_Person() ) {
		for ( int i = 0; i < 4; i++ ) {
			vert[i].X *= WWMath::Fabs(1 + vert[i].Y);		// Skew
			vert[i].Y /= 2;										// Squash vertical
			vert[i].Y += 0.25f;									// Lower
		}
	}

	for ( int i = 0; i < 4; i++ ) {
		// Numbers are -0.5 to 0.5, switch them to pixels, to match the info_renderer mode
		vert[i].X	= (vert[i].X + 0.5f) * Render2DClass::Get_Screen_Resolution().Width();
		vert[i].Y	= (vert[i].Y + 0.5f) * Render2DClass::Get_Screen_Resolution().Height();
	}

	RectClass uv( DAMAGE_1_UV_UL, DAMAGE_1_UV_LR );
	if ( index & 1 ) {
		uv = RectClass( DAMAGE_2_UV_UL, DAMAGE_2_UV_LR );
	}
	uv.Scale( INFO_UV_SCALE );

	unsigned long color_bits = (int)(DamageIndicatorIntensity[index] * 255) & 0x000000FF;
  	unsigned long color = color_bits | color_bits<<8 | color_bits<<16;

	switch (index) {
		case 3:
		case 4:	DamageRenderer->Add_Quad(	vert[1], vert[3], vert[0], vert[2], uv, color );
					break;
		case 5:
		case 6:	DamageRenderer->Add_Quad(	vert[0], vert[1], vert[2], vert[3], uv, color );
					break;
		case 7:
		case 0:	DamageRenderer->Add_Quad(	vert[2], vert[0], vert[3], vert[1], uv, color );
					break;
		case 1:
		case 2:	DamageRenderer->Add_Quad(	vert[3], vert[2], vert[1], vert[0], uv, color );
					break;
	}

}

static	void	Damage_Update( void )
{
	DamageRenderer->Reset();

	if (Input::Are_Damage_Indicators_Enabled () == false) {
		return ;
	}

	int new_damage = CombatManager::Get_Star_Damage_Direction();
	//new_damage = 0xFF;

	if ( new_damage != 0 ) {
		DamageIndicatorIntensityChanging = true;
	}

	if ( !DamageIndicatorIntensityChanging &&
		DamageIndicatorOrientation == CombatManager::Is_First_Person() ) {
		return;
	}

//	DamageRenderer->Reset();

	DamageIndicatorOrientation = CombatManager::Is_First_Person();
	DamageIndicatorIntensityChanging = false;

	// Update the intensities
	CombatManager::Clear_Star_Damage_Direction();
	for ( int i = 0; i < NUM_DAMAGE_INDICATORS; i++ ) {
		if ( new_damage & (1<<i) ) {					// Apply new damage
			DamageIndicatorIntensity[ i ] = 1;
			DamageIndicatorIntensityChanging = true;
		} else {
			if ( DamageIndicatorIntensity[ i ] > 0 ) {
				DamageIndicatorIntensity[ i ] -= TimeManager::Get_Frame_Seconds();	// and fade it away
				DamageIndicatorIntensity[ i ] = WWMath::Clamp( DamageIndicatorIntensity[ i ], 0, 1 );
				DamageIndicatorIntensityChanging = true;
			}
		}
	}

	// Redraw the indicators

#if 0
	const float HORIZ_WIDTH		=	 58.0f/640.0f;
	const float HORIZ_HEIGHT	=	 20.0f/480.0f;
	const float VERT_WIDTH		=	 20.0f/640.0f;
	const float VERT_HEIGHT		=	 58.0f/480.0f;
	const float OFFSET_X		=	220.0f/640.0f;
	const float OFFSET_Y		=	190.0f/480.0f;

	const float DIAG_WIDTH		=	 46.0f/640.0f;
	const float DIAG_HEIGHT		=	 46.0f/480.0f;
	const float DIAG_OFFSET_X	=	160.0f/640.0f;
	const float DIAG_OFFSET_Y	=	130.0f/480.0f;
#else
	float HORIZ_WIDTH		=	HORIZ_DAMAGE_SIZE.U/640.0f;
	float HORIZ_HEIGHT		=	HORIZ_DAMAGE_SIZE.V/480.0f;
	float VERT_WIDTH		=	VERT_DAMAGE_SIZE.U/640.0f;
	float VERT_HEIGHT		=	VERT_DAMAGE_SIZE.V/480.0f;
	float OFFSET_X			=	HV_DAMAGE_OFFSET.U/640.0f;
	float OFFSET_Y			=	HV_DAMAGE_OFFSET.V/480.0f;

	float DIAG_WIDTH		=	DIAG_DAMAGE_SIZE.U/640.0f;
	float DIAG_HEIGHT		=	DIAG_DAMAGE_SIZE.V/480.0f;
	float DIAG_OFFSET_X		=	DIAG_DAMAGE_OFFSET.U/640.0f;
	float DIAG_OFFSET_Y		=	DIAG_DAMAGE_OFFSET.V/480.0f;
#endif

	Damage_Add_Indicator( 0,	-HORIZ_WIDTH/2,					-OFFSET_Y-HORIZ_HEIGHT/2,		HORIZ_WIDTH/2,					-OFFSET_Y+HORIZ_HEIGHT/2		);
	Damage_Add_Indicator( 2,	OFFSET_X-VERT_WIDTH/2,			-VERT_HEIGHT/2,					OFFSET_X+VERT_WIDTH/2,			VERT_HEIGHT/2					);
	Damage_Add_Indicator( 4,	-HORIZ_WIDTH/2,					OFFSET_Y-HORIZ_HEIGHT/2,		HORIZ_WIDTH/2,					OFFSET_Y+HORIZ_HEIGHT/2			);
	Damage_Add_Indicator( 6,	-OFFSET_X-VERT_WIDTH/2,			-VERT_HEIGHT/2,					-OFFSET_X+VERT_WIDTH/2,			VERT_HEIGHT/2					);
	Damage_Add_Indicator( 1,	DIAG_OFFSET_X-DIAG_WIDTH/2,		-DIAG_OFFSET_Y-DIAG_HEIGHT/2,	DIAG_OFFSET_X+DIAG_WIDTH/2,		-DIAG_OFFSET_Y+DIAG_HEIGHT/2	);
	Damage_Add_Indicator( 3,	DIAG_OFFSET_X-DIAG_WIDTH/2,		DIAG_OFFSET_Y-DIAG_HEIGHT/2,	DIAG_OFFSET_X+DIAG_WIDTH/2,		DIAG_OFFSET_Y+DIAG_HEIGHT/2 	);
	Damage_Add_Indicator( 5,	-DIAG_OFFSET_X-DIAG_WIDTH/2,	DIAG_OFFSET_Y-DIAG_HEIGHT/2,	-DIAG_OFFSET_X+DIAG_WIDTH/2,	DIAG_OFFSET_Y+DIAG_HEIGHT/2		);
	Damage_Add_Indicator( 7,	-DIAG_OFFSET_X-DIAG_WIDTH/2,	-DIAG_OFFSET_Y-DIAG_HEIGHT/2,	-DIAG_OFFSET_X+DIAG_WIDTH/2,	-DIAG_OFFSET_Y+DIAG_HEIGHT/2	);
}

void	HUDClass::Damage_Render( void )
{
	DamageRenderer->Render();
}

/*
** Target Display
*/
Render2DClass * TargetRenderer;
Render2DClass * TargetBoxRenderer;
Render2DSentenceClass * TargetNameRenderer;
Render2DSentenceClass * InfoDebugRenderer;
WideStringClass TargetNameString;			// Cache the current target name string so that we know when the string changes
Vector2 TargetNameLocation;	// Cache the name location as well

static	void	Target_Init( void )
{
	TargetRenderer = new Render2DClass();
	TargetRenderer->Set_Texture( HUD_MAIN_TEXTURE );
	TargetRenderer->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );

	TargetBoxRenderer = new Render2DClass();
	TargetBoxRenderer->Enable_Texturing( false );
	TargetBoxRenderer->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );

	FontCharsClass *chars_font = StyleMgrClass::Peek_Font( StyleMgrClass::FONT_INGAME_TXT );
	TargetNameRenderer = new Render2DSentenceClass();
	TargetNameRenderer->Set_Font( chars_font );
	InfoDebugRenderer = new Render2DSentenceClass();
	InfoDebugRenderer->Set_Font( chars_font );
//	TargetNameRenderer->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );
}


static	void	Target_Shutdown( void )
{
	delete TargetRenderer;
	TargetRenderer = NULL;

	delete TargetBoxRenderer;
	TargetBoxRenderer = NULL;

	delete TargetNameRenderer;
	TargetNameRenderer = NULL;
	TargetNameString="";

	delete InfoDebugRenderer;
	InfoDebugRenderer = NULL;

}

		bool	InfoDebug = false;

static RectClass Get_Target_Box( PhysicalGameObj * obj );
static void	Target_Box_Edge( const Vector2 & a, const Vector2 & b, unsigned int color );

static	void	Target_Update( void )
{
	TargetRenderer->Reset();
	TargetBoxRenderer->Reset();
//	TargetNameRenderer->Reset();
	InfoDebugRenderer->Reset();

	HUDInfo::Update_Info_Object();

	static float box_zoom_size = 0;

	DamageableGameObj * d_obj = HUDInfo::Get_Info_Object();
	if ( d_obj != NULL ) {

		PhysicalGameObj * p_obj = d_obj->As_PhysicalGameObj();
		BuildingGameObj * building = d_obj->As_BuildingGameObj();

		DamageableGameObj * obj = d_obj;

		if ( obj && COMBAT_STAR ) {

			box_zoom_size += TimeManager::Get_Frame_Seconds() * 4;
			box_zoom_size = WWMath::Clamp( box_zoom_size, 0, 1 );

			int color = HUDGlobalSettingsDef::Get_Instance()->Get_No_Relation_Color().Convert_To_ARGB();
			if ( p_obj != NULL ) {
				if ( COMBAT_STAR->Is_Teammate(p_obj) ) {
					color = HUDGlobalSettingsDef::Get_Instance()->Get_Friendly_Color().Convert_To_ARGB();
				} else if ( COMBAT_STAR->Is_Enemy(p_obj) ) {
					color = HUDGlobalSettingsDef::Get_Instance()->Get_Enemy_Color().Convert_To_ARGB();
				}
			}

			if ( building != NULL ) {
//				if ( building->Is_GDI() ) {
				if ( COMBAT_STAR->Is_Teammate(building) ) {
					color = HUDGlobalSettingsDef::Get_Instance()->Get_Friendly_Color().Convert_To_ARGB();
//				} else if ( building->Is_Nod() ) {
				} else if ( COMBAT_STAR->Is_Enemy(building) ) {
					color = HUDGlobalSettingsDef::Get_Instance()->Get_Enemy_Color().Convert_To_ARGB();
				}
			}

			RectClass box = Render2DClass::Get_Screen_Resolution();

			if ( obj->As_PhysicalGameObj() ) {
				box = Get_Target_Box( obj->As_PhysicalGameObj() );
			} else {
				// Build a box for the buildings
				box.Scale_Relative_Center( 0.3f );
				// center on cursor reticle
				Vector2 new_center = (COMBAT_CAMERA->Get_Camera_Target_2D_Offset() * 0.5f );
				new_center.Y *= -1.0f;
				new_center += Vector2( 0.5f, 0.5f );
				new_center.X *= Render2DClass::Get_Screen_Resolution().Right;
				new_center.Y *= Render2DClass::Get_Screen_Resolution().Bottom;
				box += new_center - box.Center();
			}

			// Scale the box to let it zoom in
			if ( box_zoom_size < 1 ) {
				box.Scale_Relative_Center( 1 + ((1-box_zoom_size) * 0.3f) );
			}
			box.Snap_To_Units( Vector2( 1, 1 ) );

			// Clamp box to fit on screen;
			RectClass res = Render2DClass::Get_Screen_Resolution();
			if ( box.Top < 0 ) {
				box.Top = 0;
			}
			if ( box.Left < 0 ) {
				box.Left = 0;
			}
			if ( box.Right > res.Right-1 ) {
				box.Right = res.Right-1;
			}
			// Leave room for info at the bottom
			if ( box.Bottom > res.Bottom - 26 ) {
				box.Bottom = res.Bottom - 26;
			}

			Target_Box_Edge( box.Upper_Left(), box.Upper_Right(), color );
			Target_Box_Edge( box.Upper_Left(), box.Lower_Left(), color );
			Target_Box_Edge( box.Lower_Right(), box.Upper_Right(), color );
			Target_Box_Edge( box.Lower_Right(), box.Lower_Left(), color );

			RectClass	uv( TARGET_HEALTH_R_UV_UL, TARGET_HEALTH_R_UV_LR );
			RectClass	draw = uv;
			RectClass	draw2;
			bool draw_health = obj->Is_Health_Bar_Displayed();
			if ( draw_health ) {
				float health_percent = 0;
	//			float health = 0;
				const DefenseObjectClass	* def = obj->Get_Defense_Object();
				if ( def ) {
	//				health = def->Get_Health();
	//				health_percent = WWMath::Clamp( def->Get_Health() / def->Get_Health_Max(), 0, 1 );

					float health_max = def->Get_Health_Max();
					float shield_max = def->Get_Shield_Strength_Max();
					float max = health_max + shield_max;
					float health = def->Get_Health();
					float shield = def->Get_Shield_Strength();
	//				if ( health_max && ((health/health_max) < 0.25) ) {
	//					shield *= ((health/health_max) / 0.25f);
	//				}
					// Display less shield as health drops
					if ( health_max ) {
						shield *= (health/health_max);
					}
					float total = health + shield;
					if ( max != 0 ) {
						health_percent = total / max;
						health_percent = WWMath::Clamp( health_percent, 0, 1 );
					}
				}
				int health_color = Get_Health_Color( health_percent );

				// Draw Health
				static float power_flash = 0;
				power_flash += TimeManager::Get_Frame_Seconds();
				power_flash = WWMath::Wrap( power_flash, 0, 2 );

				RectClass uv3( POWER_OUT_ICON_UV_UL, POWER_OUT_ICON_UV_LR );
				RectClass draw3 = uv3;
				uv3.Scale( INFO_UV_SCALE );

				RectClass	black( HEALTH_BACK_UV_UL, HEALTH_BACK_UV_LR );
				black.Scale( INFO_UV_SCALE );

				uv.Scale( INFO_UV_SCALE );
	//			draw += box.Upper_Left() - draw.Lower_Left() - Vector2( 0, 1 );
				draw += box.Lower_Left() - draw.Upper_Left() + Vector2( 0, 18 );
	//			draw += Vector2( (box.Width() - draw.Width())/2 + 10, 0 );		// Center
				draw += Vector2( (box.Width() - draw.Width())/2 + 2, 0 );		// Center
				draw3 += draw.Center() - draw3.Center();

				// Draw background
				draw.Inflate( Vector2( 1, 1 ) );
				TargetRenderer->Add_Quad( draw, black );
				draw.Inflate( Vector2( -1, -1 ) );

				draw.Right = draw.Left + draw.Width() * health_percent;
				uv.Right = uv.Left + uv.Width() * health_percent;
				TargetRenderer->Add_Quad( draw, uv, health_color );
				// power out
				if ( power_flash < 1 ) {
	//				TargetRenderer->Add_Quad( draw3, uv3 );
				}

				uv.Set( TARGET_HEALTH_L_UV_UL, TARGET_HEALTH_L_UV_LR );
				draw2 = uv;
	#if 0
				uv.Scale( INFO_UV_SCALE );
				draw2 += draw.Upper_Left() - draw2.Upper_Right();
				TargetRenderer->Add_Quad( draw2, uv, health_color );

				WideStringClass num(0,true);
				if ( health < 1 && health > 0 ) {
					health = 1;
				}
				num.Format( L"%d", (int)health );
				TargetNameRenderer->Build_Sentence( num );
				Vector2 text_size = TargetNameRenderer->Get_Text_Extents( num );
				text_size.U -= 1;
				text_size.V = -1;
				draw -= text_size;
				draw.Snap_To_Units( Vector2( 1, 1 ) );
				TargetNameRenderer->Set_Location( draw.Upper_Left() );
				TargetNameRenderer->Draw_Sentence( health_color );
	#endif
			}

			// Draw Name
			uv.Set( TARGET_NAME_UV_UL, TARGET_NAME_UV_LR );
			draw = uv;
			uv.Scale( INFO_UV_SCALE );
			draw += box.Lower_Left() - draw.Upper_Left() + Vector2( 0, 1 );
			draw += Vector2( (box.Width() - draw.Width())/2 + 10, 0 );
			draw.Snap_To_Units( Vector2( 1, 1 ) );
			TargetRenderer->Add_Quad( draw, uv, color );

			if ( obj->Get_Translated_Name_ID() != 0 ) {
				TDBObjClass *translate_obj = TranslateDBClass::Find_Object( obj->Get_Translated_Name_ID() );
				if ( translate_obj ) {
					WideStringClass translate_string=translate_obj->Get_String();

					if ( building != NULL && HUDInfo::Get_Info_Object_Is_MCT() ) {
						translate_string=TRANSLATE( IDS_Enc_Struct_Nod_MCT_Name );
					}

					Vector2 string_loc=draw.Upper_Left() + Vector2( 3.0f,1.0f );
					if (translate_string!=TargetNameString) {
						TargetNameRenderer->Reset();
						TargetNameString=translate_string;
						TargetNameLocation = string_loc;
						TargetNameRenderer->Build_Sentence( TargetNameString );
						TargetNameRenderer->Set_Location( TargetNameLocation );
						TargetNameRenderer->Set_Base_Location( TargetNameLocation );
						TargetNameRenderer->Draw_Sentence( color );
					}
					if (string_loc!=TargetNameLocation) {
						TargetNameLocation=string_loc;
						TargetNameRenderer->Set_Base_Location( TargetNameLocation );
					}
				}
				else {
					TargetNameRenderer->Reset();
					TargetNameString="";
					TargetNameLocation = Vector2(0.0f,0.0f);
				}
			}
			else {
				TargetNameRenderer->Reset();
				TargetNameString="";
				TargetNameLocation = Vector2(0.0f,0.0f);
			}

			// Draw Team Icon
			int team = PLAYERTYPE_GDI;
			if ( p_obj != NULL ) {
				team = p_obj->Get_Player_Type();
			}

			if ( building != NULL ) {
				if ( building->Is_GDI() ) {
					team = PLAYERTYPE_GDI;
				} else if ( building->Is_Nod() ) {
					team = PLAYERTYPE_NOD;
				} else {
					team = PLAYERTYPE_NEUTRAL;
				}
			}

			if ( team == PLAYERTYPE_NOD ) {
				uv.Set( NOD_ICON_UV_UL, NOD_ICON_UV_LR );
			} else if ( team == PLAYERTYPE_GDI ) {
				uv.Set( GDI_ICON_UV_UL, GDI_ICON_UV_LR );
			} else {
				uv.Set( NEUTRAL_ICON_UV_UL, NEUTRAL_ICON_UV_LR );
			}
			draw2 = uv;
			uv.Scale( INFO_UV_SCALE );
			draw2 += draw.Upper_Left() - draw2.Upper_Right();
			TargetRenderer->Add_Quad( draw2, uv );

			// Draw chevrons
			bool draw_chevrons = false;
			if ( p_obj != NULL && p_obj->Is_HUD_Pokable_Indicator_Enabled() ) {
				draw_chevrons = true;
			}
			if ( obj->As_SmartGameObj() != NULL &&
				  obj->As_SmartGameObj()->As_VehicleGameObj() != NULL &&
				  COMBAT_STAR->Is_Permitted_To_Enter_Vehicle() &&
				  obj->As_SmartGameObj()->As_VehicleGameObj()->Is_Entry_Permitted( COMBAT_STAR ) ) {
				draw_chevrons = true;
			}
			if ( draw_chevrons ) {
				RectClass enterable_box( Vector2(0,0), TARGET_ENTERABLE_SIZE );
				enterable_box += Vector2( box.Center().X - enterable_box.Center().X ,
								box.Top - enterable_box.Bottom );
				static float enterable_bounce = 0;
				enterable_bounce += TimeManager::Get_Frame_Seconds() * 5;
				enterable_bounce = WWMath::Wrap( enterable_bounce, 0, DEG_TO_RADF( 360 ) );
				enterable_box += Vector2( 0, TARGET_ENTERABLE_BOUNCE * (WWMath::Sin( enterable_bounce ) - 1) );

				uv.Set( TARGET_ENTERABLE_UV_UL, TARGET_ENTERABLE_UV_LR );
				uv.Scale( INFO_UV_SCALE );

				color = Get_Health_Color( 1 );

//				TargetRenderer->Add_Quad( enterable_box, uv );
				enterable_box -= Vector2( 0, enterable_box.Height() * 0.6f );
				TargetRenderer->Add_Tri(	enterable_box.Upper_Right(), enterable_box.Upper_Left(), enterable_box.Center(),
					uv.Upper_Right(), uv.Upper_Left(), uv.Center(), color );
				enterable_box += Vector2( 0, enterable_box.Height() * 0.6f );
				TargetRenderer->Add_Tri(	enterable_box.Upper_Right(), enterable_box.Upper_Left(), enterable_box.Center(),
					uv.Upper_Right(), uv.Upper_Left(), uv.Center(), color );
				enterable_box += Vector2( 0, enterable_box.Height() * 0.6f );
				TargetRenderer->Add_Tri(	enterable_box.Upper_Right(), enterable_box.Upper_Left(), enterable_box.Center(),
					uv.Upper_Right(), uv.Upper_Left(), uv.Center(), color );
			}
		}

		if ( InfoDebug ) {
			StringClass	info(0,true);
			obj->Get_Information( info );

			WideStringClass str(0,true);
			str.Convert_From( info );
			InfoDebugRenderer->Build_Sentence( str );
			InfoDebugRenderer->Set_Location( Vector2( 520, 240 ) );
//			InfoDebugRenderer->Set_Base_Location( Vector2( 520, 240 ) );
			InfoDebugRenderer->Draw_Sentence();
		}

	} else {
		TargetNameRenderer->Reset();
		TargetNameString="";
		TargetNameLocation = Vector2(0.0f,0.0f);

		box_zoom_size = 0;
		HUDInfo::Clear_Info_Object();
	}
}

static	void	Target_Render( void )
{
	TargetRenderer->Render();
	TargetBoxRenderer->Render();
	TargetNameRenderer->Render();
	InfoDebugRenderer->Render();
}

static RectClass Get_Target_Box( PhysicalGameObj * obj )
{
	// Lets draw a box around the target
	WWASSERT( obj );
	PhysClass * po = obj->Peek_Physical_Object();

	Vector2	top(0,0);
	Vector2	bottom(0,0);

	if ( po != NULL ) {
		// Get the Obj AABox in Camera Space
		AABoxClass obj_box;
		po->Get_Shadow_Blob_Box( &obj_box );
		Matrix3D obj_tm = po->Get_Transform();

		Matrix3D boxview_tm;
		Matrix3D boxview_inv_tm;
		boxview_tm.Look_At(COMBAT_CAMERA->Get_Transform().Get_Translation(),obj_tm * obj_box.Center,0.0f);
		boxview_tm.Get_Orthogonal_Inverse(boxview_inv_tm);
		Matrix3D obj_to_boxview_tm = boxview_inv_tm * obj_tm;

		AABoxClass boxview_box;
		obj_to_boxview_tm.Transform_Center_Extent_AABox( obj_box.Center, obj_box.Extent, &boxview_box.Center, &boxview_box.Extent );

		Matrix3D camera_tm = COMBAT_CAMERA->Get_Transform();
		Matrix3D camera_inv_tm;
		camera_tm.Get_Orthogonal_Inverse(camera_inv_tm);
		Matrix3D boxview_to_camera_tm = camera_inv_tm * boxview_tm;

		AABoxClass camera_box;
		boxview_to_camera_tm.Transform_Center_Extent_AABox( boxview_box.Center, boxview_box.Extent, &camera_box.Center, &camera_box.Extent);

		camera_box.Extent.Z = 0.0f;
		Vector3 ctop = camera_box.Center - camera_box.Extent;
		Vector3 cbottom = camera_box.Center + camera_box.Extent;

		Vector3	temp;
		COMBAT_CAMERA->Project_Camera_Space_Point( temp, ctop );
		top.X = temp.X;
		top.Y = temp.Y;
		COMBAT_CAMERA->Project_Camera_Space_Point( temp, cbottom );
		bottom.X = temp.X;
		bottom.Y = temp.Y;
	}

	// Get Box in proper convention
	RectClass	screen = Render2DClass::Get_Screen_Resolution();
	top.X = top.X * 0.5f + 0.5f;
	top.Y = top.Y * -0.5f + 0.5f;
	bottom.X = bottom.X * 0.5f + 0.5f;
	bottom.Y = bottom.Y * -0.5f + 0.5f;
	float temp = top.Y;
	top.Y = bottom.Y;
	bottom.Y = temp;
	static RectClass info_box;
	info_box.Set( top.X * screen.Right, top.Y * screen.Bottom, bottom.X * screen.Right, bottom.Y * screen.Bottom );			// convention 0,0 - 1,1

	return info_box;
}

static void	Target_Box_Edge( const Vector2 & a, const Vector2 & b, unsigned int color )
{
	float percent = 0.2f;
	Vector2 a_ = b - a;
	a_ *= percent;
	a_ += a;
	TargetBoxRenderer->Add_Line( a, a_, 2, color );
	Vector2 b_ = a - b;
	b_ *= percent;
	b_ += b;
	TargetBoxRenderer->Add_Line( b, b_, 2, color );
}

/*
** Score Display
*/
/*
Render2DTextClass * ScoreRenderer;

static	void	Score_Init( void )
{
	Font3DInstanceClass * font = WW3DAssetManager::Get_Instance()->Get_Font3DInstance( LARGE_FONT );
	SET_REF_OWNER( font );
	ScoreRenderer = new Render2DTextClass( font );
	ScoreRenderer->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );
	font->Release_Ref();
}

static	void	Score_Shutdown( void )
{
	delete ScoreRenderer;
	ScoreRenderer = NULL;
}

static	void	Score_Update( void )
{
	ScoreRenderer->Reset();

	//TSS2001e if ( COMBAT_STAR ) {
	if ( COMBAT_STAR && COMBAT_STAR->Get_Player_Data() ) {
		int score = COMBAT_STAR->Get_Player_Data()->Get_Score();
//		WideStringClass	scorestring;
//		scorestring.Format( L"%d", score );
		WCHAR score_string[12];	// 12 digits ought to be enough...
		Generate_WChar_Text_From_Number(score_string,sizeof(score_string),false,score);

		Vector2 position = Render2DClass::Get_Screen_Resolution().Center();
		position.Y = Render2DClass::Get_Screen_Resolution().Bottom;
		Vector2 size = ScoreRenderer->Get_Text_Extents( score_string );
		size.X *= 0.5f;
		position -= size;
		ScoreRenderer->Set_Location( position );
		ScoreRenderer->Draw_Text( score_string );
	}

}

static	void	Score_Render( void )
{
	ScoreRenderer->Render();
}
*/

/*
** Objective Display
*/
DynamicVectorClass<Render2DClass *>	ObjectivePogRenderers;
Render2DClass * ObjectiveArrowRenderer;
Render2DSentenceClass * ObjectiveTextRenderer;

int	CurrentObjectiveIndex = 0;
void * CurrentObjective = NULL;
static int CachedObjectiveIndex=-1;
int CachedRange=0;

#define	OBJECTIVE_ARROW_TEXTURE		"HUD_obje_arrow.TGA"

static	void	Objective_Init( void )
{
	ObjectiveArrowRenderer = new Render2DClass();
	ObjectiveArrowRenderer->Set_Texture( OBJECTIVE_ARROW_TEXTURE );
	ObjectiveArrowRenderer->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );

	FontCharsClass *font = StyleMgrClass::Peek_Font( StyleMgrClass::FONT_INGAME_TXT );
	ObjectiveTextRenderer = new Render2DSentenceClass();
	ObjectiveTextRenderer->Set_Font( font );

	CurrentObjectiveIndex=0;
	CurrentObjective=NULL;
	CachedObjectiveIndex=-1;
	CachedRange=0;
}

static	void	Objective_Release_Pogs( void )
{
	for ( int i = 0; i < ObjectivePogRenderers.Count(); i++ ) {
		delete ObjectivePogRenderers[i];
		ObjectivePogRenderers[i] = NULL;
	}
	ObjectivePogRenderers.Delete_All();
}

static	void	Objective_Shutdown( void )
{
	Objective_Release_Pogs();

	delete ObjectiveArrowRenderer;
	ObjectiveArrowRenderer = NULL;

	delete ObjectiveTextRenderer;
	ObjectiveTextRenderer = NULL;
}

#define	POG_FLY_TIME	2.0f

static	void	Objective_Update( void )
{
	RectClass	pog_box( 0, 0, 64, 64 );
	pog_box += Render2DClass::Get_Screen_Resolution().Upper_Right() - pog_box.Upper_Right();
	pog_box += Vector2( -16, 8 );

#define	POG_SPACING		Vector2( 10, 0 )

	bool rebuild = false;

	int objective_count = ObjectiveManager::Get_Num_HUD_Objectives();
	if ( objective_count > 0 ) {
		// maintain the index
		if ( CurrentObjective != ObjectiveManager::Get_Objective( CurrentObjectiveIndex ) ) {
			CurrentObjectiveIndex = 0;
			rebuild = true;
#if 0 // no, just go for the first
			// Try to find the last objective
			for ( int i = 0; i < objective_count; i++ ) {
				if ( CurrentObjective == ObjectiveManager::Get_Objective( i ) ) {
					CurrentObjectiveIndex = i;
				}
			}
#endif
		}

		if ( IS_MISSION && Input::Get_State( INPUT_FUNCTION_CYCLE_POG ) ) {
			rebuild = true;
			CurrentObjectiveIndex++;
			if ( CurrentObjectiveIndex >= objective_count ) {
				CurrentObjectiveIndex = 0;
			}
		}

 		CurrentObjective = ObjectiveManager::Get_Objective( CurrentObjectiveIndex );
	} else {
		if (CurrentObjectiveIndex!=0 || CurrentObjective!=NULL) {
			rebuild=true;
		}
		CurrentObjectiveIndex = 0;
		CurrentObjective = NULL;
	}

	// re-Create the Pogs, if needed
	if ( rebuild || ObjectiveManager::Are_HUD_Objectives_Changed() )
	{
//		Debug_Say(( "Rebuild Hud Pogs\n" ));

		Objective_Release_Pogs();
		// Reset text
		ObjectiveTextRenderer->Reset();
		CachedRange=0;
		CachedObjectiveIndex=-1;

		int count = objective_count;
		pog_box += POG_SPACING * (float)count;

		bool dont_clear = false;

		for ( int i = count - 1; i >= 0; i-- ) {
			int index = (i + CurrentObjectiveIndex) % objective_count;
			pog_box -= POG_SPACING;
			// Add Pog
			Render2DClass * renderer = new Render2DClass();
			if ( renderer ) {
				renderer->Set_Texture( ObjectiveManager::Get_HUD_Objectives_Pog_Texture_Name( index ) );
				renderer->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );
				float	age = ObjectiveManager::Get_HUD_Objectives_Age( index );
				if ( age < POG_FLY_TIME ) {
					Vector2 offset = Render2DClass::Get_Screen_Resolution().Center() - Render2DClass::Get_Screen_Resolution().Upper_Right();
					offset.X *= 0.75f;
					float fly = WWMath::Clamp( (2.0f-(2.0f*age/POG_FLY_TIME)), 0, 1 );
					offset *= fly;
					pog_box += offset;
					renderer->Add_Quad( pog_box );
					pog_box -= offset;
					dont_clear = true;

					// AND, make an extra renderer for the radar star
					Render2DClass * renderer = new Render2DClass();
					if ( renderer ) {
						renderer->Set_Texture( "HUD_STAR.TGA" );
						renderer->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );

						RectClass	star_box( -32, -32, 32, 32 );
						star_box.Scale( fly );

						Vector2	star_fly_start = Render2DClass::Get_Screen_Resolution().Center();
						Vector2	star_fly_end = Render2DClass::Get_Screen_Resolution().Lower_Left();
						star_fly_start.X *= 0.85f;
						star_fly_start.Y *= 1.175f;
						star_fly_end.X += 40.0f;
						star_fly_end.Y *= 0.8f;

						star_box += star_fly_end;
						Vector2	offset = star_fly_start - star_fly_end;
						offset *= fly;
						star_box += offset;

						Vector3 color3( 0,1,0 );
						if ( ObjectiveManager::Get_Objective(index) != NULL ) {
							color3 = ObjectiveManager::Get_Objective(index)->Type_To_Color();
						}
						unsigned int color = color3.Convert_To_ARGB();
						renderer->Add_Quad( star_box, color  );
						ObjectivePogRenderers.Add( renderer );
					}

				} else {
					renderer->Add_Quad( pog_box );
				}
				ObjectivePogRenderers.Add( renderer );
			}
		}
		if ( !dont_clear ) {
			ObjectiveManager::Clear_HUD_Objectives_Changed();
		}
	}

	ObjectiveArrowRenderer->Reset();

	float range = 0;
	int count = objective_count;
	if ( count > 0 ) {
		// Create Arrow
		float angle = 0;
		Vector3	objective_pos = ObjectiveManager::Get_HUD_Objectives_Location( CurrentObjectiveIndex );

		if ( COMBAT_STAR ) {
			Vector3 rel_pos;
			Matrix3D::Inverse_Transform_Vector( COMBAT_STAR->Get_Transform(), objective_pos, &rel_pos );
			angle = ::atan2( rel_pos.Y, rel_pos.X );
			range = rel_pos.Length();
		}

		Vector2 arrow_vertex;
		arrow_vertex.X = WWMath::Fast_Sin( angle + DEG_TO_RAD( 180 + 45 ) );
		arrow_vertex.Y = WWMath::Fast_Cos( angle + DEG_TO_RAD( 180 + 45 ) );
		Vector2 verts[4];
		verts[0] = Vector2( arrow_vertex.X, arrow_vertex.Y );
		verts[1] = Vector2( arrow_vertex.Y, -arrow_vertex.X );
		verts[2] = Vector2( -arrow_vertex.Y, arrow_vertex.X );
		verts[3] = Vector2( -arrow_vertex.X, -arrow_vertex.Y );
		Vector2 offset;
		offset.Y = WWMath::Fast_Sin( -angle + DEG_TO_RAD( -90 ) );
		offset.X = WWMath::Fast_Cos( -angle + DEG_TO_RAD( -90 ) );
		offset *= 35;
		offset += pog_box.Center();

		const float SIN_45=0.70710678118654752440084436210485f;
		for ( int i = 0; i < 4; i++ ) {
			verts[i] *= 0.5f * 16 / SIN_45;//::sin( DEG_TO_RAD( 45 ) );
			verts[i] += offset;
		}
		ObjectiveArrowRenderer->Add_Quad( verts[0], verts[1], verts[2], verts[3] );
	}

	int irange=(int)(range);
	irange=(irange/10)*10;
	if (CachedObjectiveIndex!=CurrentObjectiveIndex || irange!=CachedRange) {
		ObjectiveTextRenderer->Reset();

		if (objective_count>0) {
			CachedRange=irange;
			CachedObjectiveIndex=CurrentObjectiveIndex;

			// Draw message
			Vector2 position = pog_box.Lower_Left();
			position += Vector2( 0, -15 );
			WideStringClass str(ObjectiveManager::Get_HUD_Objectives_Message( CurrentObjectiveIndex ),true);
			ObjectiveTextRenderer->Build_Sentence( str );
			Vector2 text_size = ObjectiveTextRenderer->Get_Text_Extents( str );
			position.X = (int)(pog_box.Center().X - (text_size.X/2));
			ObjectiveTextRenderer->Set_Location( position );
			ObjectiveTextRenderer->Draw_Sentence();

			// Draw range
			position = pog_box.Lower_Left();
			str.Format( TRANSLATE(IDS_HUD_RANGE), irange );
			ObjectiveTextRenderer->Build_Sentence( str );
			text_size = ObjectiveTextRenderer->Get_Text_Extents( str );
			position.X = (int)(pog_box.Center().X - (text_size.X/2));
			ObjectiveTextRenderer->Set_Location( position );
			ObjectiveTextRenderer->Draw_Sentence();
		}
		else {
			CachedRange=0;
			CachedObjectiveIndex=-1;
		}
	}
}

static	void	Objective_Render( void )
{
	for ( int i = 0; i < ObjectivePogRenderers.Count(); i++ ) {
		ObjectivePogRenderers[i]->Render();
	}
	ObjectiveArrowRenderer->Render();
	ObjectiveTextRenderer->Render();
}

/*
** Info Display
*/
struct InfoEditorField {
	const char * Name;
	Vector2	*	 Value;
	bool operator == (InfoEditorField const & rec) const	{ return false; }
	bool operator != (InfoEditorField const & rec) const	{ return true; }
};

static	DynamicVectorClass<InfoEditorField>	InfoEditorFieldList;

#define	INFO_EDITOR_ADD(x)	  field.Name = #x; field.Value = &x; InfoEditorFieldList.Add( field );

static	void	Info_Editor_Init( void )
{
#if 0
	InfoEditorField field;

	INFO_EDITOR_ADD( INFO_OFFSET );
	INFO_EDITOR_ADD( FRAME_1_UV_UL );
	INFO_EDITOR_ADD( FRAME_1_UV_LR );
	INFO_EDITOR_ADD( FRAME_1_OFFSET );
	INFO_EDITOR_ADD( FRAME_2_UV_UL );
	INFO_EDITOR_ADD( FRAME_2_UV_LR );
	INFO_EDITOR_ADD( FRAME_2_OFFSET );
	INFO_EDITOR_ADD( FRAME_3_UV_UL );
	INFO_EDITOR_ADD( FRAME_3_UV_LR );
	INFO_EDITOR_ADD( FRAME_3_OFFSET );
	INFO_EDITOR_ADD( FRAME_4_UV_UL );
	INFO_EDITOR_ADD( FRAME_4_UV_LR );
	INFO_EDITOR_ADD( FRAME_4_OFFSET );
	INFO_EDITOR_ADD( FRAME_5_UV_UL );
	INFO_EDITOR_ADD( FRAME_5_UV_LR );
	INFO_EDITOR_ADD( FRAME_5_OFFSET );
	INFO_EDITOR_ADD( FRAME_6_UV_UL );
	INFO_EDITOR_ADD( FRAME_6_UV_LR );
	INFO_EDITOR_ADD( FRAME_6_OFFSET );
	INFO_EDITOR_ADD( HEALTH_BACK_UV_UL );
	INFO_EDITOR_ADD( HEALTH_BACK_UV_LR );
	INFO_EDITOR_ADD( HEALTH_BACK_UL );
	INFO_EDITOR_ADD( HEALTH_BACK_LR );
	INFO_EDITOR_ADD( GRADIENT_BLACK_UV_UL );
	INFO_EDITOR_ADD( GRADIENT_BLACK_UV_LR );
	INFO_EDITOR_ADD( HEALTH_TEXT_BACK_UL );
	INFO_EDITOR_ADD( HEALTH_TEXT_BACK_LR );
	INFO_EDITOR_ADD( HEALTH_UV_UL );
	INFO_EDITOR_ADD( HEALTH_UV_LR );
	INFO_EDITOR_ADD( HEALTH_OFFSET );
	INFO_EDITOR_ADD( SHIELD_UV_UL );
	INFO_EDITOR_ADD( SHIELD_UV_LR );
	INFO_EDITOR_ADD( SHIELD_OFFSET );
	INFO_EDITOR_ADD( KEY_1_UV_UL );
	INFO_EDITOR_ADD( KEY_1_UV_LR );
	INFO_EDITOR_ADD( KEY_1_OFFSET );
	INFO_EDITOR_ADD( KEY_2_UV_UL );
	INFO_EDITOR_ADD( KEY_2_UV_LR );
	INFO_EDITOR_ADD( KEY_2_OFFSET );
	INFO_EDITOR_ADD( KEY_3_UV_UL );
	INFO_EDITOR_ADD( KEY_3_UV_LR );
	INFO_EDITOR_ADD( KEY_3_OFFSET );
	INFO_EDITOR_ADD( HEALTH_CROSS_1_UV_UL );
	INFO_EDITOR_ADD( HEALTH_CROSS_1_UV_LR );
	INFO_EDITOR_ADD( HEALTH_CROSS_1_OFFSET );
	INFO_EDITOR_ADD( HEALTH_CROSS_2_UV_UL );
	INFO_EDITOR_ADD( HEALTH_CROSS_2_UV_LR );
	INFO_EDITOR_ADD( HEALTH_CROSS_2_OFFSET );
	INFO_EDITOR_ADD( TIME_BACK_UL );
	INFO_EDITOR_ADD( TIME_BACK_LR );
	INFO_EDITOR_ADD( TIME_CLOCK_UV_UL );
	INFO_EDITOR_ADD( TIME_CLOCK_UV_LR );
	INFO_EDITOR_ADD( TIME_CLOCK_OFFSET );
	INFO_EDITOR_ADD( WEAPON_BOX_UV_UL );
	INFO_EDITOR_ADD( WEAPON_BOX_UV_LR );
	INFO_EDITOR_ADD( WEAPON_BOX_OFFSET );
	INFO_EDITOR_ADD( POWER_OUT_ICON_UV_UL );
	INFO_EDITOR_ADD( POWER_OUT_ICON_UV_LR );
	INFO_EDITOR_ADD( POWER_OUT_ICON_OFFSET );
	INFO_EDITOR_ADD( REPAIR_ICON_UV_UL );
	INFO_EDITOR_ADD( REPAIR_ICON_UV_LR );
	INFO_EDITOR_ADD( REPAIR_ICON_OFFSET );
	INFO_EDITOR_ADD( GDI_ICON_UV_UL );
	INFO_EDITOR_ADD( GDI_ICON_UV_LR );
	INFO_EDITOR_ADD( GDI_ICON_OFFSET );
	INFO_EDITOR_ADD( NOD_ICON_UV_UL );
	INFO_EDITOR_ADD( NOD_ICON_UV_LR );
	INFO_EDITOR_ADD( NOD_ICON_OFFSET );
	INFO_EDITOR_ADD( NEUTRAL_ICON_UV_UL );
	INFO_EDITOR_ADD( NEUTRAL_ICON_UV_LR );
	INFO_EDITOR_ADD( NEUTRAL_ICON_OFFSET );
	INFO_EDITOR_ADD( BULLET_ICON_UV_UL );
	INFO_EDITOR_ADD( BULLET_ICON_UV_LR );
	INFO_EDITOR_ADD( BULLET_ICON_OFFSET );
	INFO_EDITOR_ADD( RADAR_CENTER_OFFSET );
	INFO_EDITOR_ADD( DAMAGE_1_UV_UL );
	INFO_EDITOR_ADD( DAMAGE_1_UV_LR );
	INFO_EDITOR_ADD( DAMAGE_2_UV_UL );
	INFO_EDITOR_ADD( DAMAGE_2_UV_LR );
	INFO_EDITOR_ADD( HORIZ_DAMAGE_SIZE );
	INFO_EDITOR_ADD( VERT_DAMAGE_SIZE );
	INFO_EDITOR_ADD( DIAG_DAMAGE_SIZE );
	INFO_EDITOR_ADD( HV_DAMAGE_OFFSET );
	INFO_EDITOR_ADD( DIAG_DAMAGE_OFFSET );
	INFO_EDITOR_ADD( POWERUP_BOX_UV_UL );
	INFO_EDITOR_ADD( POWERUP_BOX_UV_LR );
	INFO_EDITOR_ADD( RADAR_RINGS_UV_UL );
	INFO_EDITOR_ADD( RADAR_RINGS_UV_LR );
	INFO_EDITOR_ADD( RADAR_RINGS_L_OFFSET );
	INFO_EDITOR_ADD( RADAR_RINGS_R_OFFSET );
	INFO_EDITOR_ADD( RADAR_STAR_UV_UL );
	INFO_EDITOR_ADD( RADAR_STAR_UV_LR );
	INFO_EDITOR_ADD( RADAR_STAR_OFFSET );
	INFO_EDITOR_ADD( RADAR_SQUARE_UV_UL );
	INFO_EDITOR_ADD( RADAR_SQUARE_UV_LR );
	INFO_EDITOR_ADD( RADAR_SQUARE_OFFSET);
	INFO_EDITOR_ADD( RADAR_TRIANGLE_UV_UL);
	INFO_EDITOR_ADD( RADAR_TRIANGLE_UV_LR);
	INFO_EDITOR_ADD( RADAR_TRIANGLE_OFFSET );
	INFO_EDITOR_ADD( RADAR_CIRCLE_UV_UL );
	INFO_EDITOR_ADD( RADAR_CIRCLE_UV_LR );
	INFO_EDITOR_ADD( RADAR_CIRCLE_OFFSET );
	INFO_EDITOR_ADD( RADAR_BRACKET_UV_UL );
	INFO_EDITOR_ADD( RADAR_BRACKET_UV_LR );
	INFO_EDITOR_ADD( RADAR_BRACKET_OFFSET );
	INFO_EDITOR_ADD( RADAR_SWEEP_UV_UL );
	INFO_EDITOR_ADD( RADAR_SWEEP_UV_LR );
	INFO_EDITOR_ADD( RADAR_SWEEP_OFFSET );
	INFO_EDITOR_ADD( TARGET_HEALTH_L_UV_UL );
	INFO_EDITOR_ADD( TARGET_HEALTH_L_UV_LR );
	INFO_EDITOR_ADD( TARGET_HEALTH_R_UV_UL );
	INFO_EDITOR_ADD( TARGET_HEALTH_R_UV_LR );
	INFO_EDITOR_ADD( TARGET_HEALTH_OFFSET );
	INFO_EDITOR_ADD( TARGET_NAME_UV_UL );
	INFO_EDITOR_ADD( TARGET_NAME_UV_LR );
	INFO_EDITOR_ADD( TARGET_NAME_OFFSET );
#endif
}

static	void	Info_Editor_Update( void )
{
return;
	bool changed = false;
	static	int index = 0;

	static float _move = 0;
	float move = Input::Get_Amount( INPUT_FUNCTION_MOVE_LEFT ) - Input::Get_Amount( INPUT_FUNCTION_MOVE_RIGHT );
	if ( _move != move ) {
		_move = move;
		index += (int)-move;
		index = (int)WWMath::Wrap( index, (float)0, (float)(InfoEditorFieldList.Count()) );
		if ( move != 0 ) {
			changed = true;
		}
	}

	float _forward = 0;
	float forward = Input::Get_Amount( INPUT_FUNCTION_MOVE_FORWARD ) - Input::Get_Amount( INPUT_FUNCTION_MOVE_BACKWARD );
	forward *= 10;
	forward = WWMath::Clamp( forward, -1, 1 );
	if ( _forward != forward ) {
		_forward = forward;
		InfoEditorFieldList[index].Value->V += forward;
		if ( forward != 0 ) {
			changed = true;
		}
	}

	float _left = 0;
	float left = Input::Get_Amount( INPUT_FUNCTION_TURN_LEFT ) - Input::Get_Amount( INPUT_FUNCTION_TURN_RIGHT );
	left *= 10;
	left = WWMath::Clamp( left, -1, 1 );
	if ( _left != left ) {
		_left = left;
		InfoEditorFieldList[index].Value->U += left;
		if ( left != 0 ) {
			changed = true;
		}
	}

	if ( changed ) {
		Debug_Say(( "Vector2 %s( %d, %d );\n", InfoEditorFieldList[index].Name, (int)InfoEditorFieldList[index].Value->U, (int)InfoEditorFieldList[index].Value->V ));
	}

}

static	void	Info_Editor_Shutdown( void )
{
	while ( InfoEditorFieldList.Count() > 0 ) {
		Debug_Say(( "Vector2 %s( %d, %d );\n", InfoEditorFieldList[0].Name, (int)InfoEditorFieldList[0].Value->U, (int)InfoEditorFieldList[0].Value->V ));
		InfoEditorFieldList.Delete(0);
	}
}


/*
**
*/
Render2DTextClass * InfoHealthCountRenderer;
Render2DTextClass * InfoShieldCountRenderer;

Vector2	InfoBase(0,0);

float	LastHealth = 0;
float	CenterHealthTimer = 0;
const float	CENTER_HEALTH_TIME	= 2.0f;

static	void	Info_Init( void )
{
	Info_Editor_Init();

	InfoRenderer = new Render2DClass();
	InfoRenderer->Set_Texture( HUD_MAIN_TEXTURE );
	InfoRenderer->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );

	Font3DInstanceClass * font = WW3DAssetManager::Get_Instance()->Get_Font3DInstance( LARGE_FONT );
	SET_REF_OWNER( font );
	InfoHealthCountRenderer = new Render2DTextClass( font );
	InfoHealthCountRenderer->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );
	font->Release_Ref();

	font = WW3DAssetManager::Get_Instance()->Get_Font3DInstance( SMALL_FONT );
	SET_REF_OWNER( font );
	InfoShieldCountRenderer = new Render2DTextClass( font );
	InfoShieldCountRenderer->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );
	font->Release_Ref();

	InfoBase = Render2DClass::Get_Screen_Resolution().Lower_Left() + Vector2( INFO_OFFSET );
}

static	void	Info_Shutdown( void )
{
	Info_Editor_Shutdown() ;

	delete InfoRenderer;
	InfoRenderer = NULL;

	delete InfoHealthCountRenderer;
	InfoHealthCountRenderer = NULL;

	delete InfoShieldCountRenderer;
	InfoShieldCountRenderer = NULL;
}

static	void	Info_Update_Health_Shield( void )
{
	// Draw Health
	float health = 0;
	float health_percent = 0;
	float shield = 0;
	float shield_percent = 0;

	if ( COMBAT_STAR ) {
		const DefenseObjectClass	* def = COMBAT_STAR->Get_Defense_Object();
		if ( COMBAT_STAR->Get_Vehicle() ) {
			def = COMBAT_STAR->Get_Vehicle()->Get_Defense_Object();
		}
		if ( def && def->Get_Health_Max() ) {
			health = def->Get_Health();
			health_percent = WWMath::Clamp( def->Get_Health() / def->Get_Health_Max(), 0, 1 );
		}
		if ( def && def->Get_Shield_Strength_Max() ) {
			shield = def->Get_Shield_Strength();
			shield_percent = WWMath::Clamp( def->Get_Shield_Strength() / def->Get_Shield_Strength_Max(), 0, 1 );
		}
	}

	RectClass uv;
	RectClass draw;

	// Draw Health Bar
	uv.Set( HEALTH_UV_UL, HEALTH_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + HEALTH_OFFSET - draw.Upper_Left();

	// Scale bars
	static float _last_health_percent = 0;
	float diff = health_percent - _last_health_percent;
	float max_change = TimeManager::Get_Frame_Seconds();
	_last_health_percent += WWMath::Clamp( diff, -max_change, max_change );
	uv.Right = uv.Left + uv.Width() * _last_health_percent;
	draw.Right = draw.Left + draw.Width() * _last_health_percent;

	// Get bar color
	float color_percent = MAX( _last_health_percent, health_percent );
	InfoRenderer->Add_Quad( draw, uv, Get_Health_Color( color_percent ) );

	uv.Set( GRADIENT_BLACK_UV_UL, GRADIENT_BLACK_UV_LR );
	uv.Scale( INFO_UV_SCALE );
	draw.Set( HEALTH_TEXT_BACK_UL, HEALTH_TEXT_BACK_LR );
	draw += InfoBase;
	InfoRenderer->Add_Quad( draw, uv );

	// Draw Cross
	static float flash = 0;
	flash += TimeManager::Get_Frame_Seconds() * 4;
	if ( flash > 2 ) {
		flash -= 2;
	}
	if ( health_percent > 0.25f ) {
		flash = 0;
	}
	float intensity = flash;
	if ( flash > 1 ) {
		intensity = 2 - flash;
	}

	int health_color = Get_Health_Color( color_percent );

	uv.Set( HEALTH_CROSS_1_UV_UL, HEALTH_CROSS_1_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + HEALTH_CROSS_1_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv, COLOR( intensity, health_color ) );

	RectClass	uv2;
	uv2.Set( HEALTH_CROSS_2_UV_UL, HEALTH_CROSS_2_UV_LR );
	uv2.Scale( INFO_UV_SCALE );
	InfoRenderer->Add_Quad( draw, uv2, COLOR( 1-intensity, health_color ) );

	// Draw Health Number
	InfoHealthCountRenderer->Reset();
//	StringClass	text;
	if ( health < 1 && health > 0 ) {
		health = 1;
	}
	//text.Format( "%03d", (int)health );
	long lhealth=WWMath::Float_To_Long(health);
	WCHAR tmp_text[5];
	Generate_WChar_Text_From_Number(tmp_text,4,3,lhealth);

	InfoHealthCountRenderer->Set_Location( draw.Upper_Right() + Vector2( 4,4) );
	InfoHealthCountRenderer->Draw_Text( tmp_text, health_color );

	if ( health != LastHealth || health_percent <= 0.25f ) {
		LastHealth = health;
		CenterHealthTimer = CENTER_HEALTH_TIME;
	}

	if ( CenterHealthTimer > 0 ) {
		// Also draw the above at the center

		Vector2	health_center_offset = Render2DClass::Get_Screen_Resolution().Center();
		health_center_offset.X *= 0.5;
		health_center_offset.Y -= draw.Height() / 2;

		health_center_offset -= HEALTH_CROSS_1_OFFSET;

		float fade = WWMath::Clamp( CenterHealthTimer, 0, 1 );

	 	uv.Set( GRADIENT_BLACK_UV_UL, GRADIENT_BLACK_UV_LR );
		uv.Scale( INFO_UV_SCALE );
		draw.Set( HEALTH_TEXT_BACK_UL, HEALTH_TEXT_BACK_LR );
		draw += health_center_offset;
		InfoRenderer->Add_Quad( draw, uv, COLOR( fade ) );

		uv.Set( HEALTH_CROSS_1_UV_UL, HEALTH_CROSS_1_UV_LR );
		draw = uv;
		uv.Scale( INFO_UV_SCALE );
		draw += health_center_offset + HEALTH_CROSS_1_OFFSET - draw.Upper_Left();
		InfoRenderer->Add_Quad( draw, uv, COLOR( fade * intensity, health_color ) );
		InfoRenderer->Add_Quad( draw, uv2, COLOR( fade * (1-intensity), health_color ) );

		InfoHealthCountRenderer->Set_Location( draw.Upper_Right() + Vector2( 4,4) );
		InfoHealthCountRenderer->Draw_Text( tmp_text, COLOR( fade, health_color ) );
		CenterHealthTimer -= TimeManager::Get_Frame_Seconds();
	}

	// Draw Shield
	static float _last_shield_percent = 0;
	diff = shield_percent - _last_shield_percent;
	max_change = TimeManager::Get_Frame_Seconds();
	_last_shield_percent += WWMath::Clamp( diff, -max_change, max_change );
	shield_percent = _last_shield_percent;
	uv.Right = uv.Left + uv.Width() * shield_percent;
	draw.Right = draw.Left + draw.Width() * shield_percent;

	if ( shield_percent > 0 ) {
		#define	TOTAL_SHIELD_MOVEMENT		80
		for ( float percent = 0; percent < shield_percent; percent += 0.1f ) {
			uv.Set( SHIELD_UV_UL, SHIELD_UV_LR );
			draw = uv;
			uv.Scale( INFO_UV_SCALE );
			draw += InfoBase + SHIELD_OFFSET - draw.Upper_Left();
			draw += Vector2( (int)(-percent * TOTAL_SHIELD_MOVEMENT), 0 );
			InfoRenderer->Add_Quad( draw, uv );
		}

		uv.Set( SHIELD_UV_UL, SHIELD_UV_LR );
		draw = uv;
		uv.Scale( INFO_UV_SCALE );
		draw += InfoBase + SHIELD_OFFSET - draw.Upper_Left();
		draw += Vector2( (int)(-shield_percent * TOTAL_SHIELD_MOVEMENT), 0 );
		InfoRenderer->Add_Quad( draw, uv );

		// Draw Shield Number
		InfoShieldCountRenderer->Reset();
//		StringClass	text;
//		text.Format( "%03d", (int)shield );
		long lshield=WWMath::Float_To_Long(shield);
		WCHAR tmp_text[5];
		Generate_WChar_Text_From_Number(tmp_text,4,3,lshield);
		InfoShieldCountRenderer->Set_Location( draw.Upper_Left() + Vector2( 4,4) );
		InfoShieldCountRenderer->Draw_Text( tmp_text );
	} else {
		InfoShieldCountRenderer->Reset();
	}
}

static	void	Info_Update( void )
{
//	Info_Editor_Update();

	// Clear the renderer
	InfoRenderer->Reset();

	// Draw the Frame
	RectClass uv;
	uv.Set( FRAME_1_UV_UL, FRAME_1_UV_LR );
	RectClass draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + FRAME_1_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv );

	uv.Set( FRAME_2_UV_UL, FRAME_2_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + FRAME_2_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv );

	uv.Set( FRAME_3_UV_UL, FRAME_3_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + FRAME_3_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv );

	uv.Set( FRAME_4_UV_UL, FRAME_4_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + FRAME_4_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv );

	uv.Set( FRAME_5_UV_UL, FRAME_5_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + FRAME_5_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv );

	uv.Set( FRAME_6_UV_UL, FRAME_6_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + FRAME_6_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv );

	uv.Set( HEALTH_BACK_UV_UL, HEALTH_BACK_UV_LR );
	uv.Scale( INFO_UV_SCALE );
	draw.Set( HEALTH_BACK_UL, HEALTH_BACK_LR );
	draw += InfoBase;
	InfoRenderer->Add_Quad( draw, uv );

	// Draw Health and Shield
	Info_Update_Health_Shield();

	if ( COMBAT_STAR ) {

		if ( COMBAT_STAR->Has_Key( 1 ) ) {
			uv.Set( KEY_1_UV_UL, KEY_1_UV_LR );
			draw = uv;
			uv.Scale( INFO_UV_SCALE );
			draw += InfoBase + KEY_1_OFFSET - draw.Upper_Left();
			InfoRenderer->Add_Quad( draw, uv );
		}

		if ( COMBAT_STAR->Has_Key( 2 ) ) {
			uv.Set( KEY_2_UV_UL, KEY_2_UV_LR );
			draw = uv;
			uv.Scale( INFO_UV_SCALE );
			draw += InfoBase + KEY_2_OFFSET - draw.Upper_Left();
			InfoRenderer->Add_Quad( draw, uv );
		}

		if ( COMBAT_STAR->Has_Key( 3 ) ) {
			uv.Set( KEY_3_UV_UL, KEY_3_UV_LR );
			draw = uv;
			uv.Scale( INFO_UV_SCALE );
			draw += InfoBase + KEY_3_OFFSET - draw.Upper_Left();
			InfoRenderer->Add_Quad( draw, uv );
		}
	}

#if 0
return;

	uv.Set( TARGET_HEALTH_L_UV_UL, TARGET_HEALTH_L_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + TARGET_HEALTH_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv );

	uv.Set( TARGET_HEALTH_R_UV_UL, TARGET_HEALTH_R_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + TARGET_HEALTH_OFFSET - draw.Upper_Left() + Vector2( 0, 20 );
	InfoRenderer->Add_Quad( draw, uv );

	uv.Set( TARGET_NAME_UV_UL, TARGET_NAME_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + TARGET_NAME_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv );


	uv.Set( GRADIENT_BLACK_UV_UL, GRADIENT_BLACK_UV_LR );
	uv.Scale( INFO_UV_SCALE );
	draw.Set( TIME_BACK_UL, TIME_BACK_LR );
	draw += InfoBase;
	InfoRenderer->Add_Quad( draw, uv );

	uv.Set( TIME_CLOCK_UV_UL, TIME_CLOCK_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + TIME_CLOCK_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv );

	uv.Set( WEAPON_BOX_UV_UL, WEAPON_BOX_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + WEAPON_BOX_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv );

	uv.Set( POWER_OUT_ICON_UV_UL, POWER_OUT_ICON_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + POWER_OUT_ICON_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv );

	uv.Set( REPAIR_ICON_UV_UL, REPAIR_ICON_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + REPAIR_ICON_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv );

	uv.Set( GDI_ICON_UV_UL, GDI_ICON_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + GDI_ICON_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv );

	uv.Set( NOD_ICON_UV_UL, NOD_ICON_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + NOD_ICON_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv );

	uv.Set( NEUTRAL_ICON_UV_UL, NEUTRAL_ICON_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + NEUTRAL_ICON_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv );

	// Radar
	uv.Set( RADAR_STAR_UV_UL, RADAR_STAR_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + RADAR_STAR_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv );

	uv.Set( RADAR_STAR_UV_UL, RADAR_STAR_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + RADAR_STAR_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv );

	uv.Set( RADAR_SQUARE_UV_UL, RADAR_SQUARE_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + RADAR_SQUARE_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv );

	uv.Set( RADAR_TRIANGLE_UV_UL, RADAR_TRIANGLE_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + RADAR_TRIANGLE_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv );

	uv.Set( RADAR_CIRCLE_UV_UL, RADAR_CIRCLE_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + RADAR_CIRCLE_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv );

	uv.Set( RADAR_BRACKET_UV_UL, RADAR_BRACKET_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + RADAR_BRACKET_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv );

	uv.Set( RADAR_SWEEP_UV_UL, RADAR_SWEEP_UV_LR );
	draw = uv;
	uv.Scale( INFO_UV_SCALE );
	draw += InfoBase + RADAR_SWEEP_OFFSET - draw.Upper_Left();
	InfoRenderer->Add_Quad( draw, uv );
#endif
}

static	void	Info_Render( void )
{
	InfoRenderer->Render();
	InfoHealthCountRenderer->Render();
	InfoShieldCountRenderer->Render();
}


/*
** OLD HUD STUFF
*/
static bool		_HUDEnabled = true;
static bool		_HUDInited = false;

#ifdef ATI_DEMO_HACK
typedef enum {
	DEMO_HUD_IMAGE=0,
	DEMO_HUD_IMAGE2,
	NUM_RENDER_IMAGES,
};
#else
typedef enum {
	RETICLE	= 0,
	RETICLE_HIT,
	ACTION_STATUSBAR_RENDERER,
	DEMO_HUD_IMAGE,
	DEMO_HUD_IMAGE2,
	NUM_RENDER_IMAGES,
};
#endif
Render2DClass		*	RenderImages[ NUM_RENDER_IMAGES ];

/*
**
*/
static bool	Is_HUD_Displayed( void );

/*
**
*/
void 	HUDClass::Init(bool render_available)
{
	for( int i = 0; i < NUM_RENDER_IMAGES; i++ ) {
		RenderImages[i] = NULL;
	}

	// Reticles
#ifndef ATI_DEMO_HACK
	RenderImages[RETICLE] = new Render2DClass();
	RenderImages[RETICLE]->Set_Texture( "HD_reticle.tga" );
	RenderImages[RETICLE]->Set_Hidden( true );
	RenderImages[RETICLE_HIT] = new Render2DClass();
	RenderImages[RETICLE_HIT]->Set_Texture( "HD_reticle_hit.tga" );
	RenderImages[RETICLE_HIT]->Set_Hidden( true );
	// Action Status Bar (arming/disarming explosives, etc)
	RenderImages[ACTION_STATUSBAR_RENDERER] = new Render2DClass();
	RenderImages[ACTION_STATUSBAR_RENDERER]->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );
#else
	RectClass rect=Render2DClass::Get_Screen_Resolution();

	RenderImages[DEMO_HUD_IMAGE] = new Render2DClass();
	RenderImages[DEMO_HUD_IMAGE]->Reset();
	RenderImages[DEMO_HUD_IMAGE]->Set_Texture( "renegade_demo.tga" );
	RenderImages[DEMO_HUD_IMAGE]->Set_Hidden( false );
	RenderImages[DEMO_HUD_IMAGE]->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );
	RenderImages[DEMO_HUD_IMAGE]->Add_Quad( RectClass( float(8),float(-8),float(256+8),float(128-8)), RectClass(0.0f,0.0f,1.0f,0.5f),0xffffffff);
	RenderImages[DEMO_HUD_IMAGE2] = new Render2DClass();
	RenderImages[DEMO_HUD_IMAGE2]->Reset();
	RenderImages[DEMO_HUD_IMAGE2]->Set_Texture( "renegade_demo.tga" );
	RenderImages[DEMO_HUD_IMAGE2]->Set_Hidden( false );
	RenderImages[DEMO_HUD_IMAGE2]->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );
	RenderImages[DEMO_HUD_IMAGE2]->Add_Quad( RectClass( rect.Right+float(-256-8),rect.Bottom+float(-128+8),rect.Right+float(-8),rect.Bottom+float(8)), RectClass(0.0f,0.5f,1.0f,1.0f),0xffffffff);
#endif

	if (render_available) {
		_HUDEnabled = true;

		SniperHUDClass::Init();
		Powerup_Init();
		Weapon_Init();
		Weapon_Chart_Init();
		Info_Init();
		Damage_Init();
		Target_Init();
		//Score_Init();
		Objective_Init();

		HUD_Help_Text_Init();

		_HUDInited = true;
	}
}

/*
**
*/
void 	HUDClass::Shutdown()
{
	if (_HUDInited) {

		Objective_Shutdown();
		//Score_Shutdown();
		Target_Shutdown();
		Damage_Shutdown();
		Info_Shutdown();
		Weapon_Chart_Shutdown();
		Weapon_Shutdown();
		Powerup_Shutdown();
		HUD_Help_Text_Shutdown();
		SniperHUDClass::Shutdown();

		for( int i = 0; i < NUM_RENDER_IMAGES; i++ ) {
			if ( RenderImages[i] ) {
				delete RenderImages[i];
				RenderImages[i] = NULL;
			}
		}

		_HUDInited = false;
	}
}

void 	HUDClass::Reset( void )
{
	Powerup_Reset();
	Damage_Reset();
	Weapon_Reset();
}

void 	HUDClass::Render()
{
	WWPROFILE( "HUD Render" );

#ifdef ATI_DEMO_HACK
	RenderImages[DEMO_HUD_IMAGE]->Render();
	RenderImages[DEMO_HUD_IMAGE2]->Render();
#else
	if ( COMBAT_CAMERA && COMBAT_CAMERA->Draw_Sniper() ) {
		SniperHUDClass::Render();
	}

	// Only render if Combat is active, and Menu is not,  and we have a star who is not sniping
	if ( Is_HUD_Displayed() ) {

		Powerup_Render();
		Weapon_Render();
		Weapon_Chart_Render();
		Info_Render();
		Damage_Render();
		Target_Render();
		//Score_Render();
		HUD_Help_Text_Render();
		Objective_Render();
		RadarManager::Render();

		for( int i = 0; i < NUM_RENDER_IMAGES; i++ ) {
			if ( RenderImages[i] ) {
				RenderImages[i]->Render();
			}
		}
	}
#endif
}


static bool	Is_HUD_Displayed( void )
{
	return (	_HUDEnabled &&
				COMBAT_STAR &&
				!COMBAT_STAR->Is_Dead() &&
				!COMBAT_STAR->Is_Destroyed() );
}

/*
**	called each time through the main loop
*/
void 	HUDClass::Think()
{
	WWPROFILE( "HUD Think" );

#ifndef ATI_DEMO_HACK
	if ( COMBAT_CAMERA && COMBAT_CAMERA->Draw_Sniper() ) {
		SniperHUDClass::Update();
	}

	if ( !Is_HUD_Displayed() ) {
		return;
	}

	if ( HUDInfo::Display_Action_Status_Bar() ) {

		RenderImages[ACTION_STATUSBAR_RENDERER]->Set_Hidden( false );
		RenderImages[ACTION_STATUSBAR_RENDERER]->Reset();
		RenderImages[ACTION_STATUSBAR_RENDERER]->Enable_Texturing( false );

		//
		//	Plot the rectangle
		//
		const RectClass &screen_rect = Render2DClass::Get_Screen_Resolution();
		RectClass status_bar_rect (0.4F, 0.95F, 0.6F, 0.98F);
		status_bar_rect.Left		= int(status_bar_rect.Left * screen_rect.Width());
		status_bar_rect.Right	= int(status_bar_rect.Right * screen_rect.Width());
		status_bar_rect.Top		= int(status_bar_rect.Top * screen_rect.Height());
		status_bar_rect.Bottom	= int(status_bar_rect.Bottom  * screen_rect.Height());
		RenderImages[ACTION_STATUSBAR_RENDERER]->Add_Line( status_bar_rect.Upper_Left (), status_bar_rect.Upper_Right (), 1, 0xFFFFFFFF );
		RenderImages[ACTION_STATUSBAR_RENDERER]->Add_Line( status_bar_rect.Upper_Right (), status_bar_rect.Lower_Right (), 1, 0xFFFFFFFF );
		RenderImages[ACTION_STATUSBAR_RENDERER]->Add_Line( status_bar_rect.Lower_Right (), status_bar_rect.Lower_Left (), 1, 0xFFFFFFFF );
		RenderImages[ACTION_STATUSBAR_RENDERER]->Add_Line( status_bar_rect.Lower_Left (), status_bar_rect.Upper_Left (), 1, 0xFFFFFFFF );

		//
		//	Deflate the rectangle
		//
		status_bar_rect.Right -= 1.0F;
		status_bar_rect.Bottom -= 1.0F;

		//
		//	Plot the status rectangle
		//
		float width					= status_bar_rect.Width() * HUDInfo::Get_Action_Status_Value();
		status_bar_rect.Right	= status_bar_rect.Left + int(width);
		DWORD color					= VRGB_TO_INT32( Vector3( 1.0F, 0.25F, 0 ) );
		RenderImages[ACTION_STATUSBAR_RENDERER]->Add_Quad( status_bar_rect, color );

	} else {
		RenderImages[ACTION_STATUSBAR_RENDERER]->Set_Hidden( true );
	}

	SmartGameObj * star = COMBAT_STAR;
	if ( COMBAT_STAR->Get_Vehicle() ) {
		star = COMBAT_STAR->Get_Vehicle();
	}

	Info_Update();
	Powerup_Update();
	Weapon_Update();
	Weapon_Chart_Update();
	Damage_Update();
	Target_Update();
	//Score_Update();
	Objective_Update();

	// Radar
	Matrix3D tm;
	star->Get_Transform().Get_Inverse( tm );
	if ( star->As_VehicleGameObj() && COMBAT_CAMERA && !COMBAT_CAMERA->Is_2D_Targeting() ) {
		// Make a tm facing target
		Matrix3D gun;
		gun.Obj_Look_At( star->Get_Transform().Get_Translation(), star->Get_Targeting_Pos(), 0 );
		gun.Get_Inverse( tm );
	}

	PhysicalGameObj * obj = NULL;
	if ( HUDInfo::Get_Info_Object() ) {
		obj = HUDInfo::Get_Info_Object()->As_PhysicalGameObj();
	}
	RadarManager::Set_Bracket_Object( obj );
	Vector2	radar_center = InfoBase + RADAR_CENTER_OFFSET;
	RadarManager::Update( tm, radar_center );

	unsigned long reticle_color = HUDGlobalSettingsDef::Get_Instance()->Get_No_Relation_Color().Convert_To_ARGB();

	if ( HUDInfo::Get_Weapon_Target_Object() != NULL ) {
		reticle_color = HUDGlobalSettingsDef::Get_Instance()->Get_Friendly_Color().Convert_To_ARGB();
		PhysicalGameObj * pgo = HUDInfo::Get_Weapon_Target_Object()->As_PhysicalGameObj();
		if ( pgo && pgo->Is_Enemy( star ) ) {
			reticle_color = HUDGlobalSettingsDef::Get_Instance()->Get_Enemy_Color().Convert_To_ARGB();
		}
	}

	WeaponClass * weapon = star->Get_Weapon();
	if ( weapon ) {
		if ( weapon->Is_Reloading() || weapon->Is_Switching() || !weapon->Is_Loaded() ) {
			reticle_color = 0xFFFFFF00; // yellow
		}
	}

	Vector2 reticle_offset = COMBAT_CAMERA->Get_Camera_Target_2D_Offset();
	RenderImages[RETICLE]->Reset();
	RenderImages[RETICLE]->Add_Quad( RectClass( reticle_offset.X - RETICLE_WIDTH/2, reticle_offset.Y - RETICLE_HEIGHT/2, reticle_offset.X + RETICLE_WIDTH/2, reticle_offset.Y + RETICLE_HEIGHT/2 ), reticle_color);

	//RenderImages[RETICLE]->Set_Hidden( false );
	//TSS092401
	if ( CombatManager::Is_Gameplay_Permitted() ) {
		RenderImages[RETICLE]->Set_Hidden( false );
	} else {
		RenderImages[RETICLE]->Set_Hidden( true );
	}

	//TSS092401 if ( weapon ) {
	if ( CombatManager::Is_Gameplay_Permitted() && (weapon != NULL) && CombatManager::Is_Hit_Reticle_Enabled() ) {
		WWPROFILE( "Reticle" );
		Vector3 pos3d = HUDInfo::Get_Weapon_Target_Position();
		Vector3 reticle_hit_offset;
		COMBAT_CAMERA->Project( reticle_hit_offset, pos3d );
//		weapon_hitting = HUDInfo::Get_Weapon_Target_Object() != NULL;
		RenderImages[RETICLE_HIT]->Reset();
		RenderImages[RETICLE_HIT]->Add_Quad( RectClass( reticle_hit_offset.X - RETICLE_WIDTH/2, reticle_hit_offset.Y - RETICLE_HEIGHT/2, reticle_hit_offset.X + RETICLE_WIDTH/2, reticle_hit_offset.Y + RETICLE_HEIGHT/2 ), reticle_color);
		RenderImages[RETICLE_HIT]->Set_Hidden( false );
	} else {
		RenderImages[RETICLE_HIT]->Set_Hidden( true );
	}


#if 0
	// Display points
	if ( _HUDTimer > 0 ) {
		WWPROFILE( "Points" );
		_HUDTimer -= TimeManager::Get_Frame_Seconds();

		StringClass	pointstring;
		int points = _HUDPoints;
		if ( points ) {
			Vector2 position = Render2DClass::Get_Screen_Resolution().Lower_Right();
			position /= 2;
			float scale = WWMath::Clamp( 2 * _HUDTimer / HUD_POINTS_TIME, 0, 1 );
			position.Y *= 0.3f + (scale/2);
			pointstring.Format( "%d", points );
			((Render2DTextClass *)RenderImages[TEXT_RENDERER])->Set_Location( position );

			Font3DInstanceClass * font = ((Render2DTextClass *)RenderImages[TEXT_RENDERER])->Peek_Font();
			if ( font ) {
				font->Set_Scale( 2 + (scale * 3) );
				position.X -= font->String_Width( pointstring ) / 2;
				position.Y -= font->Char_Height() / 2;
				((Render2DTextClass *)RenderImages[TEXT_RENDERER])->Set_Location( position );
				((Render2DTextClass *)RenderImages[TEXT_RENDERER])->Draw_Text( pointstring, COLOR( scale ) );
				font->Set_Scale( 1 );
			}
		}
	}
#endif
#endif // ATI_DEMO_HACK
}

void	HUDClass::Toggle_Hide_Points( void )
{
//	_HUDHidePoints = !_HUDHidePoints;
}

void	HUDClass::Display_Points( float points )
{
/*	if ( !_HUDHidePoints ) {
		_HUDPoints = points;
		_HUDTimer = HUD_POINTS_TIME;
	}*/
}

bool	HUDClass::Is_Enabled( void )
{
	return _HUDEnabled;
}

void	HUDClass::Enable( bool enable )
{
	_HUDEnabled = enable;
}

#define	SNIPER_AMMO_UV		3, 139,79,191
#define	SNIPER_AMMO_OFFSET	-10,-4
#define	NUKE_UV				193,187,244,246
#define	NUKE_OFFSET			10,-4
#define	ION_UV				101,196,164,246
#define	ION_OFFSET			10,-4

void	HUDClass::Add_Powerup_Weapon( int id, int rounds )
{
	const WeaponDefinitionClass	* def = WeaponManager::Find_Weapon_Definition( id );
	if ( def ) {
		if ( !def->IconTextureName.Is_Empty() ) {
			Powerup_Add( TranslateDBClass::Get_String( def->IconNameID ), rounds,
				def->IconTextureName, def->IconTextureUV, def->IconOffset );
		}
	}
}

void	HUDClass::Add_Powerup_Ammo( int id, int rounds )
{
	Add_Powerup_Weapon( id, rounds );
#if 0
	const WeaponDefinitionClass	* wdef = WeaponManager::Find_Weapon_Definition( id );
	if ( wdef ) {
		const AmmoDefinitionClass	* def = WeaponManager::Find_Ammo_Definition( wdef->PrimaryAmmoDefID );
		if ( def ) {
			if ( !def->IconTextureName.Is_Empty() ) {
				Powerup_Add( TranslateDBClass::Get_String( def->IconNameID ), rounds,
						def->IconTextureName, def->IconTextureUV, def->IconOffset );
			}
		}
	}
#endif
}

void	HUDClass::Add_Shield_Grant( float strength )
{
	const char * texture_name = "hud_armor3.tga";
	if ( strength > 75 ) {
		texture_name = "hud_armor1.tga";
	} else if ( strength > 30 ) {
		texture_name = "hud_armor2.tga";
	}
	Powerup_Add( TranslateDBClass::Get_String(IDS_Power_up_Armor_00),  (int)strength, texture_name, RectClass( 0,0,64,64 ),	Vector2( 10,40 ) );
}

void	HUDClass::Add_Health_Grant( float amount )
{
	const char * texture_name = "hud_health1.tga";
	if ( amount > 75 ) {
		texture_name = "hud_health3.tga";
	} else if ( amount > 30 ) {
		texture_name = "hud_health2.tga";
	}
	Powerup_Add( TranslateDBClass::Get_String(IDS_Power_up_Health_00),  (int)amount, texture_name, RectClass( 0,0,64,64 ),	Vector2( 10,40 ) );
}

void	HUDClass::Add_Shield_Upgrade_Grant( float strength )
{
	Powerup_Add( TranslateDBClass::Get_String(IDS_Power_up_Armor_Upgrade),  (int)strength, "hud_armedal.tga", RectClass( 0,0,64,64 ),	Vector2( 10,40 ), false );
}

void	HUDClass::Add_Health_Upgrade_Grant( float amount )
{
	Powerup_Add( TranslateDBClass::Get_String(IDS_Power_up_Health_Upgrade),  (int)amount, "hud_hemedal.tga", RectClass( 0,0,64,64 ),	Vector2( 10,40 ), false );
}

void	HUDClass::Add_Key_Grant( int key )
{
	const char * texture_name = "hud_keycard_green.tga";
	if ( key == 3 ) {
		texture_name = "hud_keycard_red.tga";
	} else if ( key == 2 ) {
		texture_name = "hud_keycard_yellow.tga";
	}
	Powerup_Add( TranslateDBClass::Get_String(IDS_Power_up_SecurityCard),  0, texture_name, RectClass( 0,0,64,64 ),	Vector2( 10,40 ), false );
}

void	HUDClass::Add_Objective( int type )
{
	if ( type == ObjectiveManager::TYPE_PRIMARY ) {
		Powerup_Add( TranslateDBClass::Get_String(IDS_Enc_Obj_Priority_0_Primary),  0, "p_eva1.tga", RectClass( 0,0,64,64 ),	Vector2( 10,40 ), false );
	} else if ( type == ObjectiveManager::TYPE_SECONDARY ) {
		Powerup_Add( TranslateDBClass::Get_String(IDS_Enc_Obj_Priority_0_Secondary),  0, "p_eva2.tga", RectClass( 0,0,64,64 ),	Vector2( 10,40 ), false );
	}
}

void	HUDClass::Add_Data_Link( void )
{
	int cur = TimeManager::Get_Total_Seconds() * 2.0f;
	static int last = 0;
	// Don't accept too fast;
	if ( cur == last ) {
		return;
	}
	last = cur;
	Powerup_Add( TranslateDBClass::Get_String(IDS_Power_up_DataDisc_01),  0, "hud_cd_rom.tga", RectClass( 0,0,64,64 ),	Vector2( 10,40 ), false );
}

void	HUDClass::Add_Map_Reveal( void )
{
	Add_Data_Link();
//	Powerup_Add( TranslateDBClass::Get_String(IDS_Power_up_DataDisc_01),  0, "hud_cd_rom.tga", RectClass( 0,0,64,64 ),	Vector2( 10,40 ), false );
//	Powerup_Add( TranslateDBClass::Get_String(IDS_Enc_Pow_Bonus_Map_Name),  0, "hud_cd_rom.tga", RectClass( 0,0,64,64 ),	Vector2( 10,40 ), false );
}

/*
**
*/
enum	{
	CHUNKID_VARIABLES			=	1117011622,
	CHUNKID_MARKER_ENTRY,

	MICROCHUNKID_ENABLED		=	1,
};

/*
**
*/
bool	HUDClass::Save( ChunkSaveClass &csave )
{
	csave.Begin_Chunk( CHUNKID_VARIABLES );
		WRITE_MICRO_CHUNK( csave, 	MICROCHUNKID_ENABLED,	_HUDEnabled );
	csave.End_Chunk();

	return true;
}

bool	HUDClass::Load( ChunkLoadClass &cload )
{
	while (cload.Open_Chunk()) {
		switch(cload.Cur_Chunk_ID()) {

			case CHUNKID_VARIABLES:
				while (cload.Open_Micro_Chunk()) {
					switch(cload.Cur_Micro_Chunk_ID()) {
						READ_MICRO_CHUNK( cload, 	MICROCHUNKID_ENABLED,	_HUDEnabled );
						default:
							Debug_Say(("Unhandled Chunk:%d File:%s Line:%d\r\n",cload.Cur_Chunk_ID(),__FILE__,__LINE__));
							break;
					}
					cload.Close_Micro_Chunk();
				}
				break;

			default:
				Debug_Say(("Unhandled Chunk:%d File:%s Line:%d\r\n",cload.Cur_Chunk_ID(),__FILE__,__LINE__));
				break;

		}
		cload.Close_Chunk();
	}
	return true;
}