#include "mungal4.h"
#pragma hdrstop

#include "..\munga\door.h"
#include "..\munga\doorfram.h"
#include "..\munga\eyecandy.h"
#include "l4vidrnd.h"
#include "l4video.h"
#include "..\munga\matrix.h"
#include "..\munga\mover.h"
#include "..\munga\jmover.h"
#include "..\munga\player.h"
#include "..\munga\camship.h"
#include "..\munga\director.h"
#include "..\munga\mission.h"
#include "..\munga\cultural.h"
#include "..\munga\nttmgr.h"
#include "..\munga\app.h"
#include "l4particles.h"
#include "DXUtils.h"

using namespace std;
#include <conio.h>
#include <vector>
#include <hash_map>
#include <map>

LPDIRECT3D9 gD3D = NULL;

//STUBBED: DPL RB 1/14/07
// when this is resolved it can be removed
#include "..\DPLSTUB.h"

#include <d3dx9.h>
#define char8	unsigned char
#define uint32	unsigned __int32

// basic macro to help with releasing things
#define SAFE_RELEASE(handle) if (handle) { handle->Release(); handle = NULL; }

#define PILL_COUNT			20
#define PILL_SIZE			(y_size*0.03125)			// 32 @ 1280x1024
#define PILL_SPACING		(PILL_SIZE*0.625)			// 20 @ 1280x1024
#define LOAD_COLOR			0xFF6565FF
#define FADE_IN				0.05f
#define PILL_ON				0.05f
#define FADE_OUT			0.5f
#define LOAD_TEXT_HEIGHT	PILL_SIZE					// 32 @ 1280x1024
#define LOAD_TEXT_WIDTH		(LOAD_TEXT_HEIGHT*12.125)	// 388 @ 1280x1024
#define PS_OFF				0
#define	PS_FADINGIN			1
#define PS_ON				2
#define PS_FADINGOUT		3
#define LOAD_TEXT_VERT		(PILL_SIZE/2.0)

#ifdef LOGFRAMERATE
FILE *FRAMERATE_LOG;
#endif

//
// Includes for the DPL libraries
//
// RB 1/15/07
//#include <dpl\dpl.h>
//#include <dpl\dpl_2d.h>
//#include <dpl\dpl_vpx.h>
//#include <dpl\dplutils.h>
//#include <dpl\matrix.h>
//
// You can enable or disable these traces here for quicker rebuilding during
// profile testing, but for production they should be all turned off!
//
//#define	TRACE_VIDEO_CULL_SETUP
//#define	TRACE_VIDEO_VEHICLE_RENDERABLES
// #define	TRACE_VIDEO_ALL_RENDERABLES
//
// These are other traces you can use to extract data
//
#if defined(TRACE_VIDEO_LOAD_OBJECT)
	static BitTrace Video_Load_Object("Video Load Object");
	#define SET_VIDEO_LOAD_OBJECT() Video_Load_Object.Set()
	#define CLEAR_VIDEO_LOAD_OBJECT() Video_Load_Object.Clear()
#else
	#define SET_VIDEO_LOAD_OBJECT()
	#define CLEAR_VIDEO_LOAD_OBJECT()
#endif

#if defined(TRACE_VIDEO_CONSTRUCT_ROOT)
	static BitTrace Video_Construct_Root("Video Construct Root");
	#define SET_VIDEO_CONSTRUCT_ROOT() Video_Construct_Root.Set()
	#define CLEAR_VIDEO_CONSTRUCT_ROOT() Video_Construct_Root.Clear()
#else
	#define SET_VIDEO_CONSTRUCT_ROOT()
	#define CLEAR_VIDEO_CONSTRUCT_ROOT()
#endif
//
// This is the time spent fetching and processing the pickpoint information
// from the DPL renderer.
//
#if defined(TRACE_VIDEO_PICKPOINT)
	static BitTrace Video_Pickpoint("Video Pickpoint");
	#define SET_VIDEO_PICKPOINT() Video_Pickpoint.Set()
	#define CLEAR_VIDEO_PICKPOINT() Video_Pickpoint.Clear()
#else
	#define SET_VIDEO_PICKPOINT()
	#define CLEAR_VIDEO_PICKPOINT()
#endif
//
// Traces the time spent setting up the video culling parameters
//
#if defined(TRACE_VIDEO_CULL_SETUP)
	static BitTrace Video_Cull_Setup("Video Cull Setup");
#	define SET_VIDEO_CULL_SETUP() Video_Cull_Setup.Set()
#	define CLEAR_VIDEO_CULL_SETUP() Video_Cull_Setup.Clear()
#else
#	define SET_VIDEO_CULL_SETUP()
#	define CLEAR_VIDEO_CULL_SETUP()
#endif
//
// This trace covers the entire time spent executing renderables as one
// transition.  It goes up when the execute implimentation starts running
// over the all iterator and goes down when it's done.
//
#if defined(TRACE_VIDEO_RENDERABLES)
	static BitTrace Video_Renderables("Video Renderables");
	#define SET_VIDEO_RENDERABLES() Video_Renderables.Set()
	#define CLEAR_VIDEO_RENDERABLES() Video_Renderables.Clear()
#else
	#define SET_VIDEO_RENDERABLES()
	#define CLEAR_VIDEO_RENDERABLES()
#endif
//
// Traces time spent executing renderables that belong to a vehicle entity
// (currently Mech, VTV or BTPlayer)
//
#if defined(TRACE_VIDEO_VEHICLE_RENDERABLES)
	static BitTrace Video_Vehicle_Renderables("Video Vehicle Renderables");
#	define SET_VIDEO_VEHICLE_RENDERABLES() Video_Vehicle_Renderables.Set()
#	define CLEAR_VIDEO_VEHICLE_RENDERABLES() Video_Vehicle_Renderables.Clear()
#else
#	define SET_VIDEO_VEHICLE_RENDERABLES()
#	define CLEAR_VIDEO_VEHICLE_RENDERABLES()
#endif
//
// This trace will transition as each individual renderable is executed.
// It will buzz and cause serious impact to the accuracy of the trace but is
// good for identifying time-eating individual renderables
//
#if defined(TRACE_VIDEO_ALL_RENDERABLES)
	static BitTrace Video_All_Renderables("Video All Renderables");
#	define SET_VIDEO_ALL_RENDERABLES() Video_All_Renderables.Set()
#	define CLEAR_VIDEO_ALL_RENDERABLES() Video_All_Renderables.Clear()
#else
#	define SET_VIDEO_ALL_RENDERABLES()
#	define CLEAR_VIDEO_ALL_RENDERABLES()
#endif
//
// This is the routine that does a DPL_FlushArticulations on the batch of
// DCS's that we've been holding during rendering, std::flushing them all to
// the card in a big batch
//
#if defined(TRACE_VIDEO_BATCH_FLUSH)
	static BitTrace Video_Batch_Flush("Video Batch Flush");
#	define SET_VIDEO_BATCH_FLUSH() Video_Batch_Flush.Set()
#	define CLEAR_VIDEO_BATCH_FLUSH() Video_Batch_Flush.Clear()
#else
#	define SET_VIDEO_BATCH_FLUSH()
#	define CLEAR_VIDEO_BATCH_FLUSH()
#endif
//
// This trace shows the time spent doing the "frame done" processing where the
// renderer waits for the DPL card to become ready and then issues a command
// to start the scene drawing.  An additional batch std::flush can happen here.
// If USE_ONE_VIDEO_TRACE is turned on, data from this trace will show up as
// part of the Video_Renderer trace.
//
#if defined(TRACE_VIDEO_RENDERER_FRAME_DONE)
#	if defined(USE_ONE_VIDEO_TRACE)
#		define SET_VIDEO_RENDERER_FRAME_DONE() Video_Renderer.Set()
#		define CLEAR_VIDEO_RENDERER_FRAME_DONE() Video_Renderer.Clear()
#	else
		static BitTrace Video_Renderer_Frame_Done("Video Renderer Frame Done");
#		define SET_VIDEO_RENDERER_FRAME_DONE() Video_Renderer_Frame_Done.Set()
#		define CLEAR_VIDEO_RENDERER_FRAME_DONE() Video_Renderer_Frame_Done.Clear()
#	endif
#else
#	define SET_VIDEO_RENDERER_FRAME_DONE()
#	define CLEAR_VIDEO_RENDERER_FRAME_DONE()
#endif
//
// The following traces are specifically designed for profileing the low level
// DPL routines in Division's libraries.  You need to link to a special "profile"
// version of the division libraries for these to work.  If you enable them
// with a production libdpl you will get NO traces.  If you disable them and
// try to link to a profile version of libdpl you will get link errors.  Sorry
// but this is the most efficient way of connecting the c++ trace routines to
// the C code of division's libraries.
//
// There are switches in the DPL libraries that handle turning these functions
// on and off in the profile version.
//
//#define 	TRACE_DPL_LOAD_OBJECT
//#define 	TRACE_DPL_TRANSPUTER_LINK			// will buzz
//#define	TRACE_DPL_DO_OUTSW               // will buzz
//#define	TRACE_DPL_OUTINT32               // will buzz

#if defined(TRACE_DPL_LOAD_OBJECT)
	static BitTrace DPL_Load_Object("DPL Load Object");

	extern "C"
	{
		void Set_DPL_Load_Object();
		void Clear_DPL_Load_Object();
	}

	void
		Set_DPL_Load_Object()
	{
		DPL_Load_Object.Set();
	}

	void
		Clear_DPL_Load_Object()
	{
		DPL_Load_Object.Clear();
	}
#endif

#if defined(TRACE_DPL_TRANSPUTER_LINK)
	static BitTrace DPL_Transputer_Link("DPL Transputer Link");

	extern "C"
	{
		void Set_DPL_Transputer_Link();
		void Clear_DPL_Transputer_Link();
	}

	void
		Set_DPL_Transputer_Link()
	{
		DPL_Transputer_Link.Set();
	}

	void
		Clear_DPL_Transputer_Link()
	{
		DPL_Transputer_Link.Clear();
	}
#endif

#if defined(TRACE_DPL_DO_OUTSW)
	static BitTrace DPL_do_outsw("DPL do_outsw");

	extern "C"
	{
		void Set_DPL_do_outsw();
		void Clear_DPL_do_outsw();
	}

	void
		Set_DPL_do_outsw()
	{
		DPL_do_outsw.Set();
	}

	void
		Clear_DPL_do_outsw()
	{
		DPL_do_outsw.Clear();
	}
#endif

#if defined(TRACE_DPL_OUTINT32)
	static BitTrace DPL_outint32("DPL outint32");

	extern "C"
	{
		void Set_DPL_outint32();
		void Clear_DPL_outint32();
	}

	void
		Set_DPL_outint32()
	{
		DPL_outint32.Set();
	}

	void
		Clear_DPL_outint32()
	{
		DPL_outint32.Clear();
	}
#endif

//
// The following trace will probably be obsolete soon
//

#if 0
#if defined(TRACE_VIDEO_FIRST_FRAME_DONE)
	static BitTrace Video_First_Frame_Done("Video First Frame Done");
#	define SET_VIDEO_FIRST_FRAME_DONE() Video_First_Frame_Done.Set()
#	define CLEAR_VIDEO_FIRST_FRAME_DONE() Video_First_Frame_Done.Clear()
#else
#	define SET_VIDEO_FIRST_FRAME_DONE()
#	define CLEAR_VIDEO_FIRST_FRAME_DONE()
#endif
#endif

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Definitions of various debugging switches
//
#define	DEBUG_SPECIAL_CALLBACK	0			// 0 = none, 1 = print special, 2 = real noisy
#define	DEBUG_CREATE_CALLBACK	0			//	0 = none,
#define	PRINT_THE_PFX				False		// Set to true and the pfx definition will print when it is read in.
#define 	RAPID_SECT_PIXEL			True		// True if you want to use the rapidsectpixel call for intersections
#define 	PARTICLE_TEST				False		// True to issue a stream of particles at the detected intersect point
#define	PRINT_PICKPOINT_TEST		False		// True to print data whenever the intersect changes
#define	NOISY_RENDERER				False		// True enables a lot of printouts as the renderer makes/kills object
#define	USE_TRACKER_STRUCTURE	False		// True to enable the full tracker structure that holds damage zone names & such
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Definitions of system constants used only in this file
//
#define MAX_SPECIAL_ARGUMENTS 25				// Maximum number of arguments a "special" callback can handle
#define MAX_SPECIAL_SIZE 512              // Maximum size (characters) of a "special"
#define dpl_arg_sep '~' 						// seperator used when parsing dpl argument string
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Entity
	*Entity_Being_Created = 0;		// !!! temp, till callback handlers become a class
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// These extern "c" routines and constants are from startdpl or from dpl
// itself and need to be here.
//
extern "C" {
	//STUBBED: DPL RB 1/15/07
	//extern const int
	//	x_size,						// x size of the screen (from startdpl)
	//	y_size;             		// y size of the screen (startdpl)
	void
		dpl_TexmapTexels2D (		// A routine from DPL we normally couldn't access
			dpl_TEXMAP *tm,
			uint32 *texels,
			int32  u_size,
			int32  v_size,
			int32  bytes_per_texel);
	int
		screen_resolution(			// Sets up the screen resolution (startdpl)
			char *dpl_argv ),
		explode_args( 					// Parses DPLARG system environmental (startdpl)
			char **argv,
			char *dpl_args,
			char sep );
	char
		*dpl_TypeToString(			// Converts a DPL type code into a string (libdpl)
			dpl_TYPE t);
	int32
		dpl_DrawSceneComplete(void);	// missing definition (libdpl)
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// see DPLReportPerfStats()
//STUBBED: VIDEO RB 1/15/07
//extern "C" const int32 __sect_time;
//extern "C" const int32 __last_cull_time;
//extern "C" const int32 __last_draw_time;
//extern "C" const int32 __last_frame_time;
//extern "C" const int32 __last_pxpl_time;
//extern "C" const int32 __last_frame_prims;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// dump_frame_buffer() std::declaration
void dump_frame_buffer(
		dpl_VIEW *eye,
		int32 x_size,
		int32 y_size,
		Logical antialias);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// The following are definitions of DPL callback functions.  These are called
// by the dpl file loader as it is loading graphics files so we can do material
// substitution and set special attributes on geometry & such.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// The "special" callback is called whenever a "special" field is processed in
// incomming geometry.
// dPL special callback function type.
//	typedef void (dpl_SPECIAL_CALLBACK)(dpl_TYPE type, void *handle,
//												char8 *special, uint32 special_len);

static void
	TestSpecialCallBack(
		dpl_TYPE type,
		void *handle,
		char8 *special,
		uint32 special_len)
{
//STUBBED: DPL RB 1/14/07
//	char
//		*args[MAX_SPECIAL_ARGUMENTS],
//		**argptr,
//		*argstring;
//	int
//		argcount;
//	float
//		u0,
//		v0,
//		du,
//		dv;
//	int32
//		immunity;
//	char
////		NameBuff[80],
//		TempBuff[MAX_SPECIAL_SIZE + 1];
//	#if USE_TRACKER_STRUCTURE
//	dpl_tracker
//		*this_tracker;
//	#endif
//
//	if(special_len > MAX_SPECIAL_SIZE)
//	{
//		DEBUG_STREAM<<"SPECIAL was bigger than "<<MAX_SPECIAL_SIZE<<"\n" << std::flush;
//		Verify(special_len > MAX_SPECIAL_SIZE);
//	}
//	strncpy(TempBuff, (const char*)special, special_len);
//	TempBuff[special_len] = 0;
//	if(TempBuff[special_len-1] != 0)
//	{
//		DEBUG_STREAM<<"Caution, the following SPECIAL was not null terminated\n" << std::flush;
//		printf("SPECIAL->%08x: %s, %s\n", handle, dpl_TypeToString(type), TempBuff);
//	}
//	#if DEBUG_SPECIAL_CALLBACK >= 1
//	printf("SPECIAL->%08x: %s, %s\n", handle, dpl_TypeToString(type), TempBuff);
//	#endif
////
//// Scan all the argument start points into an array for easier processing.
//// also avoids non-reentrand problem with strtok
////
//	argstring = TempBuff;
//	for(argcount = 0; argcount<MAX_SPECIAL_ARGUMENTS; argcount++)
//	{
//		args[argcount] = strtok(argstring," ");
//		if(!args[argcount])
//			break;
//		argstring = NULL;
//	}
//	args[MAX_SPECIAL_ARGUMENTS-1] = 0;
////
//// Decode the dpl_type the special was found in, all I know of are listed here
//// though some we may never see.
////
//	switch(type)
//	{
//		case dpl_type_error:
//			break;
//		case dpl_type_scene:
//			break;
//		case dpl_type_zones:
//			break;
//		case dpl_type_view:
//			break;
//		case dpl_type_instance:
//			break;
//		case dpl_type_dcs:
//			break;
//		case dpl_type_light:
//			break;
//		case dpl_type_object:
//			for(argptr = args;
//				 *argptr;
//				 argptr++)
//			{
//				if (strcmp(*argptr, "ADDITIVE_LODS") == 0)
//				{
//					#if DEBUG_SPECIAL_CALLBACK >= 2
//					Tell("Calling SetObjectAdditiveLODs on an object\n");
//					#endif
//					// REMOVE dpl_SetObjectAdditiveLODs to run with older renderers
//					dpl_SetObjectAdditiveLODs ( (dpl_OBJECT *)handle);
//				}
//			}
//			break;
//		case dpl_type_lod:
//			break;
//		case dpl_type_geogroup:
//			#if USE_TRACKER_STRUCTURE
//			this_tracker	=	(dpl_tracker *)dpl_GetAppSpecific(handle);
//			#endif
//			for(argptr = args;
//				 *argptr;
//				 argptr++)
//			{
//				if (strncmp(*argptr, "dz_", 3) == 0)
//				{
//					#if DEBUG_SPECIAL_CALLBACK >= 2
//					Tell("Doing SPECIAL GEOGROUP Damage zone ");
//					#endif
//
//					#if USE_TRACKER_STRUCTURE
//					if (this_tracker)
//					{
//						#if DEBUG_SPECIAL_CALLBACK >= 2
//						Tell("marked\n");
//						#endif
//						strncpy(this_tracker->dz_name, *argptr, MAX_DZ_NAME_LENGTH);
//						this_tracker->dz_name[MAX_DZ_NAME_LENGTH - 1] = 0;
//					#endif
//						//---------------------------------------------
//						// lookup damage zone index in global namelist
//						//---------------------------------------------
//						if (Entity_Being_Created->damageZones)
//						{
//							Check_Pointer(Entity_Being_Created->damageZones);
//
//							int
//								damage_zone_index;
//
//							damage_zone_index =
//								Entity_Being_Created->GetDamageZoneIndex(*argptr);
//
//							if (damage_zone_index != -1)
//							{
//								#if USE_TRACKER_STRUCTURE
//								this_tracker->Damage_Zone_Number = damage_zone_index;
//								#else
//								if(dpl_GetAppSpecific(handle))
//									Fail("AppSpecific already set\n");
//								dpl_PutAppSpecific(handle, (void *)(damage_zone_index+1));
//								#endif
//							}
//							else
//							{
//								DEBUG_STREAM << std::endl << "Damage zone '" <<
//									*argptr << "' not in table." << std::endl;
//							}
//						}
//					#if USE_TRACKER_STRUCTURE
//					}
//					else
//					{
//						#if DEBUG_SPECIAL_CALLBACK >= 2
//						Tell("NOT marked\n");
//						#endif
//					}
//               #endif
//				}
//				else if(strcmp(*argptr,"PUNCH") == 0)
//				{
//					#if DEBUG_SPECIAL_CALLBACK >= 2
//					Tell("Doing SPECIAL GEOGROUP Punchize\n");
//					#endif
//					dpl_Punchize((dpl_GEOGROUP *)handle);
//				}
//				else if(strcmp(*argptr,"DAMAGE") == 0)
//				{
//					#if DEBUG_SPECIAL_CALLBACK >= 2
//					Tell("Doing SPECIAL GEOGROUP damagize\n");
//					#endif
//					if(*(++argptr))
//					{
//						int
//							status;
//						dpl_MATERIAL *damagize_material = dpl_LookupMaterial ( *argptr, dpl_lookup_normal, &status );
//						if(damagize_material)
//						{
//							dpl_Damagize((dpl_GEOGROUP *)handle, damagize_material);
//						}
//						else
//						{
//							DEBUG_STREAM<<"SPECIAL GEOGROUP DAMAGE couldn't find material "<<*argptr<<"\n" << std::flush;
//							Verify(damagize_material);
//						}
//					}
//					else
//					{
//						DEBUG_STREAM<<"SPECIAL GEOGROUP DAMAGE no material name \n" << std::flush;
//						Verify(*argptr);
//					}
//				}
//				else if(strcmp(*argptr,"WIREFRAME") == 0)
//				{
//					#if DEBUG_SPECIAL_CALLBACK >= 2
//					Tell("Doing SPECIAL GEOGROUP WIREFRAME\n");
//					#endif
//					dpl_SetGeogroupWireframe((dpl_GEOGROUP *)handle, True);
//				}
//				else if(strcmp(*argptr,"GEOMETRIZE") == 0)
//				{
//					#if DEBUG_SPECIAL_CALLBACK >= 2
//					Tell("Doing SPECIAL GEOGROUP geometrize\n");
//					#endif
//					if(*(++argptr))
//					{
//						dpl_GEOMETRY
//							*geometry_ptr;
//						long
//							geometrize_code;
//						int
//							geometry_id	= 0;
//						sscanf(
//							*argptr,
//							"%lx",
//							&geometrize_code);
//						do
//						{
//							geometry_ptr = dpl_GetGeogroupGeometry((dpl_GEOGROUP *)handle,geometry_id);
//							if(geometry_ptr)
//							{
//								dpl_Geometrize(geometry_ptr,geometrize_code);
//							}
//							geometry_id++;
//						} while(geometry_ptr);
//					}
//					else
//					{
//						DEBUG_STREAM<<"SPECIAL GEOGROUP GEOMETRIZE has no geometrize code\n" << std::flush;
//						Verify(*argptr);
//					}
//				}
//				else if(strcmp(*argptr,"DRAWLAST") == 0)
//				{
//					#if DEBUG_SPECIAL_CALLBACK >= 2
//					Tell("Doing SPECIAL GEOGROUP DRAWLAST\n");
//					#endif
//					dpl_SetGeogroupDrawLast((dpl_GEOGROUP *)handle, True);
//					dpl_FlushGeogroup((dpl_GEOGROUP *)handle);
//				}
//				else if(strcmp(*argptr,"BLINK") == 0)
//				{
//					#if DEBUG_SPECIAL_CALLBACK >= 2
//					Tell("SPECIAL GEOGROUP BLINK is not supported\n");
//					#endif
//				}
//				else
//				{
//					DEBUG_STREAM<<"SPECIAL GEOGROUP "<<*argptr<<" is not a geogroup modifier\n" << std::flush;
//				}
//			}
//			break;
//		case dpl_type_geometry:
//			break;
//		case dpl_type_material:
//			for(argptr = args;
//				 *argptr;
//				 argptr++)
//			{
//				if(strcmp(*argptr,"IMMUNE") == 0)
//				{
//					#if DEBUG_SPECIAL_CALLBACK >= 2
//					Tell("Doing SPECIAL MATERIAL IMMUNE\n");
//					#endif
//					if(*(++argptr))
//					{
//						immunity = atol(*argptr);
//						dpl_SetMaterialFogImmunity ( (dpl_MATERIAL *)handle, immunity );
//						dpl_FlushMaterial((dpl_MATERIAL *)handle);
//					}
//					else
//					{
//						DEBUG_STREAM<<"SPECIAL MATERIAL IMMUNE has no immune code\n" << std::flush;
//						Verify(*argptr);
//					}
//				}
//				else
//				{
//					DEBUG_STREAM<<"SPECIAL MATERIAL "<<*argptr<<" is not a material modifier\n" << std::flush;
//				}
//			}
//			break;
//		case dpl_type_texture:
//			for(argptr = args;
//				 *argptr;
//				 argptr++)
//			{
//				if(strcmp(*argptr,"SCROLL") == 0)
//				{
//					#if DEBUG_SPECIAL_CALLBACK >= 2
//					Tell("Doing SCROLL\n");
//					#endif
//					u0 = v0 = du = dv = 0.0;
//					if(*(++argptr))
//						u0 = atof(*argptr);
//					else
//					{
//						DEBUG_STREAM<<"SPECIAL TECTURE SCROLL missing u0\n" << std::flush;
//						Verify(*argptr);
//					}
//					if(*(++argptr))
//						v0 = atof(*argptr);
//					else
//					{
//						DEBUG_STREAM<<"SPECIAL TECTURE SCROLL missing v0\n" << std::flush;
//						Verify(*argptr);
//					}
//					if(*(++argptr))
//						du = atof(*argptr);
//					else
//					{
//						DEBUG_STREAM<<"SPECIAL TECTURE SCROLL missing du\n" << std::flush;
//						Verify(*argptr);
//					}
//					if(*(++argptr))
//						dv = atof(*argptr);
//					else
//					{
//						DEBUG_STREAM<<"SPECIAL TECTURE SCROLL missing dv\n" << std::flush;
//						Verify(*argptr);
//					}
//					dpl_SetTextureScroll (
//						(dpl_TEXTURE *)handle,
//						u0,
//						v0,
//						du,
//						dv);
//					dpl_FlushTexture((dpl_TEXTURE *)handle);
//				}
//				else if(strcmp(*argptr,"FAKESIZE") == 0)
//				{
//					#if DEBUG_SPECIAL_CALLBACK >= 2
//					Tell("Doing SPECIAL TEXURE FAKESIZE\n");
//					#endif
//					int
//						size, offset;
//					if(*(++argptr))
//						size = atoi(*argptr);
//					else
//					{
//						DEBUG_STREAM<<"SPECIAL TEXTURE FAKESIZE missing size\n" << std::flush;
//						Verify(*argptr);
//					}
//					if(*(++argptr))
//						offset = atoi(*argptr);
//					else
//					{
//						DEBUG_STREAM<<"SPECIAL TEXTURE FAKESIZE missing offset\n" << std::flush;
//						Verify(*argptr);
//					}
//					dpl_FakeTextureSize((dpl_TEXTURE *)handle,size,offset);
//					dpl_FlushTexture((dpl_TEXTURE *)handle);
//				}
//				else
//				{
//					DEBUG_STREAM<<"SPECIAL TEXTURE "<<*argptr<<" is not a texture modifier\n" << std::flush;
//				}
//			}
//			break;
//		case dpl_type_texmap:
//			break;
//		case dpl_type_ramp:
//			break;
//	}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// The TestCreateCallBack callback is called whenever a dpl node of the indicated
// type is created while loading a DPL graphics file.
/* dPL create/delete callback function type. */
//typedef void (dpl_CREATE_DELETE_CALLBACK)(dpl_TYPE type, void *handle);

static void
	TestCreateCallBack(
		dpl_TYPE type,
		#if DEBUG_CREATE_CALLBACK>=1
			void *handle
		#else
			void *
		#endif
	)
{
	//
	// get a pointer to the node structure (first part of most dpl types)
	//
	#if DEBUG_CREATE_CALLBACK >=1
	printf("CREATE->%08x: %s\n", handle, dpl_TypeToString(type));
	#endif
	switch(type)
	{
		case dpl_type_error:
			break;
		case dpl_type_scene:
			break;
		case dpl_type_zones:
			break;
		case dpl_type_view:
			break;
		case dpl_type_instance:
			break;
		case dpl_type_dcs:
			break;
		case dpl_type_light:
			break;
		case dpl_type_object:
			break;
		case dpl_type_lod:
			break;
		case dpl_type_geogroup:
		#if USE_TRACKER_STRUCTURE
		{
			dpl_tracker *this_tracker			=	new dpl_tracker;
			this_tracker->This_Entity			=	Entity_Being_Created;
			this_tracker->dz_name[0]			=	0;
			this_tracker->Damage_Zone_Number	=	-1;	// no damage zone (default)
			if(dpl_GetAppSpecific(handle))
				DEBUG_STREAM<<"app_specific hook already set!\n" << std::flush;
			dpl_PutAppSpecific(handle, this_tracker);

			break;
		}
		#endif
		case dpl_type_geometry:
			break;
		case dpl_type_material:
			break;
		case dpl_type_texture:
			break;
		case dpl_type_texmap:
			break;
		case dpl_type_ramp:
			break;
	}
}

//#############################################################################
// Code to setup and handle material substitutions.
//#############################################################################
//
NameList
	*materialSubstitutionList = NULL;

const char *opMaterialName(const char *fileName, int opId)
{
	hash_map<string, hash_map<int, string>>::const_iterator fileIter = gOpNames->find(string(fileName));

	if (fileIter != gOpNames->end())
	{
		hash_map<int, string>::const_iterator matIter = (*fileIter).second.find(opId);

		if (matIter != (*fileIter).second.end())
		{
			return (*matIter).second.c_str();
		}
	}

	return NULL;
}

void loadTables()
{
	gOpNames = new hash_map<string, hash_map<int, string>>();
	gReplacementData = new hash_map<string, ReplacementMaterialData>();

	FILE * opNames = fopen("VIDEO\\REPLACEMATS.tbl", "rb");

	size_t numMats;

	fread(&numMats, sizeof(size_t), 1, opNames);

	for (int i = 0; i < (int)numMats; i++)
	{
		int opNum, fileNameLen, matNameLen;

		fread(&opNum, sizeof(int), 1, opNames);
		fread(&fileNameLen, sizeof(int), 1, opNames);

		char *fileName = new char[fileNameLen];

		fread(fileName, sizeof(char), fileNameLen, opNames);

		fread(&matNameLen, sizeof(int), 1, opNames);

		char *matName = new char[matNameLen];

		fread(matName, sizeof(char), matNameLen, opNames);

		hash_map<string, hash_map<int, string>>::const_iterator fileIter = gOpNames->find(string(fileName));

		if (fileIter != gOpNames->end())
		{
			hash_map<int, string>::const_iterator matIter = (*fileIter).second.find(opNum);

			if (matIter != (*fileIter).second.end())
			{
				(*gOpNames)[string(fileName)][opNum] = string(matName);
			} else
			{
				(*gOpNames)[string(fileName)].insert(pair<int, string>(opNum, string(matName)));
			}
		} else
		{
			hash_map<int, string> fileMap;
			fileMap.insert(pair<int, string>(opNum, string(matName)));

			gOpNames->insert(pair<string, hash_map<int, string>>(string(fileName), fileMap));
		}

		delete [] fileName;
		delete [] matName;
	}

	fclose(opNames);

	FILE *replacementData = fopen("VIDEO\\MATREPLACETABLE.tbl", "rb");

	fread(&numMats, sizeof(size_t), 1, replacementData);

	for (int i = 0; i < (int)numMats; i++)
	{
		int matNameLen, texNameLen;

		fread(&matNameLen, sizeof(int), 1, replacementData);
		
		char *matName = new char[matNameLen];
		fread(matName, sizeof(char), matNameLen, replacementData);

		fread(&texNameLen, sizeof(int), 1, replacementData);

		char *texName = new char[texNameLen];
		fread(texName, sizeof(char), texNameLen, replacementData);

		ReplacementMaterialData data;
		data.texName = string(texName);

		fread(&data, sizeof(float), 3, replacementData);

		gReplacementData->insert(pair<string, ReplacementMaterialData>(string(matName), data));

		delete [] matName;
		delete [] texName;
	}

	fclose(replacementData);
}

/* dPL material name callback function type. */
//typedef char8 *(dpl_MATERIAL_NAME_CALLBACK)(char8 *mat_name);
char*
	substituteMaterial(
		char *source
	)
{
	static char
		buffer[MATERIAL_NAME_BUFFER_LENGTH];
	NameList::Entry
		*entry;
	const char
		*search,
		*replace,
		*pc;
	int
		len;
	//----------------------------------------------
	// perform text substitution
	// first match in the sub list gets substituted
	// materialSubstitutionList  is a pre-prepared global namelist.
	//----------------------------------------------
	if (materialSubstitutionList == NULL)
	{
		return source;
	}

	entry = materialSubstitutionList->GetFirstEntry();
	while (entry)
	{
		search = entry->GetName();
		if (search && *search && (pc = strstr((char*)source, search)) != NULL)
		{
			replace = entry->GetChar();
			*buffer = '\0';

			len = (char*)pc - source;
			while (*replace == '<')
			{
				++replace;
				--len;
			}
			if (len > 0)
			{
				strncat(buffer, (const char*)source, len);
			}

			pc += strlen(search);
			len = strlen(replace);
			while (len && *(replace+len-1) == '>')
			{
				--len;
				if (*pc)  { ++pc; }
			}
			if (len > 0)
			{
				strncat(buffer, replace, len);
			}

			Str_Cat(buffer, pc, MATERIAL_NAME_BUFFER_LENGTH);
			
			delete [] source;
			source = new char[strlen(buffer) + 1];

			Str_Copy((char*)source, buffer, MATERIAL_NAME_BUFFER_LENGTH);
			break;
		}
		entry = entry->GetNextEntry();
	}
	return source;
}

vector<MONITORINFO> DPLRenderer::MonitorsCreateAll(int &monitorCount)
{
	monitorCount = gD3D->GetAdapterCount();

	vector<MONITORINFO> allMonitors(monitorCount);

	for(UINT i = 0; i < monitorCount; i++)
	{
		HMONITOR monitorHandle = gD3D->GetAdapterMonitor(i);
		MONITORINFO info;
		info.cbSize = sizeof(MONITORINFO);
		GetMonitorInfo(monitorHandle, &info);
		allMonitors[i] = info;
	}

	return allMonitors;
}

void DPLRenderer::SetCoreRenderStates()
{
	
	mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_USEW);

	float size = 1.0f;
	mDevice->SetRenderState(D3DRS_POINTSIZE, *(DWORD*)(&size));
	
	mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);

	D3DXMATRIX view_matrix, proj_matrix;
	D3DXMatrixIdentity(&view_matrix);
	D3DXMatrixOrthoLH(&proj_matrix, x_size, y_size, 1.0f, 1000.0f);
	mDevice->SetTransform(D3DTS_VIEW, &view_matrix);
	mDevice->SetTransform(D3DTS_PROJECTION, &proj_matrix);

	mDevice->SetRenderState(D3DRS_LIGHTING, false);
	mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);

	mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
	mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
	mDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);

	mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
	mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
	mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_TFACTOR);

	mDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
	mDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
	mDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);

	mDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
	mDevice->SetSamplerState(1, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
	mDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
	mDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
	mDevice->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
	mDevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
}
//-----------------------------------------------------------------------------
//--------------------------DPL video resource object--------------------------
//-----------------------------------------------------------------------------
//#############################################################################
//############################    L4VideoObject    ############################
//#############################################################################

L4VideoObject::L4VideoObject(
	const char *filename,
	ResourceType resource_type,
	Enumeration renderer_modes,	// RendererModes
	float blink_period,
	float percent_time_on
)
{
	Check_Pointer(filename);

	Str_Copy(objectFilename, filename, sizeof(objectFilename));
	//---------------------------------------------------------------
	// pad objectFilename with nulls so all .res files are identical
	//---------------------------------------------------------------
	char
		*p = objectFilename + strlen(filename) + 1,
		*c = objectFilename + sizeof(objectFilename);

	for (; p < c; ++p)
		{ *p = '\0'; }

	resourceType = resource_type;
	rendererModes = renderer_modes;
	blinkPeriod = blink_period;
	percentTimeOn = percent_time_on;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
L4VideoObject::~L4VideoObject()
{
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
	L4VideoObject::TestInstance() const
{
	Verify( strlen(objectFilename) < sizeof(objectFilename) );
	return True;
}

//#############################################################################
//########################    L4VideoObjectWrapper    #########################
//#############################################################################

L4VideoObjectWrapper::L4VideoObjectWrapper(
	L4VideoObject *video_object,
	Logical delete_object
)
{
	Check_Pointer(video_object);	// do not use Check()

	videoObject = video_object;
	deleteObject = delete_object;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
L4VideoObjectWrapper::~L4VideoObjectWrapper()
{
	if (deleteObject)
	{
		Unregister_Pointer(videoObject);
		delete videoObject;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
	L4VideoObjectWrapper::TestInstance() const
{
	if (videoObject)
	{
		Check_Pointer(videoObject);	// do not use Check()
	}
	return True;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// static
int L4VideoObjectWrapper::BuildVideoObjectChainFromResource(ChainOf<L4VideoObjectWrapper*> *video_chain, ResourceDescription *video_resource)
{
	//do not Check(this) - static
	Check(video_chain);
	Check(video_resource);

	const char *video_pointer;
	int object_count, index;
	long object_size;
	L4VideoObject *video_object;
	L4VideoObjectWrapper *video_wrapper;

	//----------------------------------------------------
	// convert video resource into chain of video objects
	//----------------------------------------------------
	video_pointer = (char *)video_resource->resourceAddress;
	Check_Pointer(video_pointer);

	object_count = *((int *)video_pointer);
	video_pointer += sizeof(int);

	object_size = sizeof(L4VideoObject);
	Verify(video_resource->resourceSize == sizeof(int) + object_count * object_size);

	//Tell("video chain: ("<<object_count<<")");

	for (index = 0; index < object_count; ++index)
	{
		video_object = (L4VideoObject *)video_pointer;
		//do not register (done through resource)
		video_pointer += object_size;

		//Tell("  '"<<video_object->GetObjectFilename()<<"' 0x"<<std::hex<<video_object->GetRendererModes());

		video_wrapper = new L4VideoObjectWrapper(video_object, False);
		Register_Object(video_wrapper);

		video_chain->Add(video_wrapper);
	}

	//Tell(std::dec<<"\n");

	return object_count;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// static
void
	L4VideoObjectWrapper::DeleteVideoObjectChain(
		ChainOf<L4VideoObjectWrapper*> *video_chain
	)
{
	//do not Check(this) - static
	Check(video_chain);

	ChainIteratorOf<L4VideoObjectWrapper*>
		video_iterator(video_chain);
	L4VideoObjectWrapper
		*video_wrapper;

	while ((video_wrapper = video_iterator.ReadAndNext()) != NULL)
	{
		Check(video_wrapper);

		Unregister_Object(video_wrapper);
		delete video_wrapper;
	}
	return;
}

void DPLRenderer::FindBestAdapterIndices(bool isWindowed)
{
	bool spanDisable = false;
	bool *spanDisablePtr = NULL;

	//Get all available monitor indices & stats
	int monitorCount = 0;
	std::vector<MONITORINFO> monitors = this->MonitorsCreateAll(monitorCount);
	int monitorReserved = 0x10000000;

	//Test for primary gauge override
	char* gaugeAdapterString = getenv("PRIMGAUGE");
	if (gaugeAdapterString != NULL)
	{
		mPrimaryIndex = new int;
		*mPrimaryIndex = atoi(gaugeAdapterString);
		DEBUG_STREAM << "Primary gauge override- adapter " << *mPrimaryIndex << std::endl;
	}

	//Test for secondary gauge override
	gaugeAdapterString = getenv("SECGAUGE");
	if (gaugeAdapterString != NULL)
	{
		mSecondaryIndex = new int;
		*mSecondaryIndex = atoi(gaugeAdapterString);
		DEBUG_STREAM << "Secondary gauge override- adapter " << *mSecondaryIndex << std::endl;
	}

	//Only do gauge overrides if we're using gauges during this execution
	if (!Application::DoSuppressGauges())
	{
		//Test for gauge1 override
		gaugeAdapterString = getenv("MFDGAUGE");
		if (gaugeAdapterString != NULL)
		{
			mAux1Index = new int;
			*mAux1Index = atoi(gaugeAdapterString);
			DEBUG_STREAM << "MFD Gauge Override- adapter " << *mAux1Index << std::endl;
		}

		//Test for span disable override
		spanDisablePtr = NULL;
		gaugeAdapterString = getenv("SPANDISABLE");
		if (gaugeAdapterString != NULL)
		{
			spanDisable = atoi(gaugeAdapterString);
			spanDisablePtr = &spanDisable;
			DEBUG_STREAM << "Spanning Override: Span ";

			if (*spanDisablePtr)
			{
				DEBUG_STREAM << "Disabled";
			} else
			{
				DEBUG_STREAM << "Enabled";
			}

			DEBUG_STREAM << std::endl;
		} 

		if (spanDisablePtr == NULL || *spanDisablePtr)
		{
			//Test for gauge2 override
			gaugeAdapterString = getenv("MFDGAUGE2");
			if (gaugeAdapterString != NULL)
			{
				mAux2Index = new int;
				*mAux2Index = atoi(gaugeAdapterString);
				DEBUG_STREAM << "MFD Gauge #2 Override- adapter " << *mAux2Index << std::endl;
			}
		}

		//Disable spanning if they overrode the 2nd gauge
		if (spanDisablePtr == NULL && mAux2Index != NULL)
		{
			DEBUG_STREAM << "MFD Gauge #2 was overridden... forcing spanning disabled." << std::endl;
			spanDisable = true;
			spanDisablePtr = &spanDisable;
		}
	}

	//Remove all monitors explicitly assigned somewhere from the list of available monitors
	if (mPrimaryIndex != NULL && (*mPrimaryIndex) >= 0 && (*mPrimaryIndex) < monitorCount)
	{
		monitors[*mPrimaryIndex].dwFlags |= monitorReserved;
	}

	if (mSecondaryIndex != NULL && (*mSecondaryIndex) >= 0 && (*mSecondaryIndex) < monitorCount)
	{
		monitors[*mSecondaryIndex].dwFlags |= monitorReserved;
	}

	if (mAux1Index != NULL && (*mAux1Index) >= 0 && (*mAux1Index) < monitorCount)
	{
		monitors[*mAux1Index].dwFlags |= monitorReserved;
	}

	if (mAux2Index != NULL && (*mAux2Index) >= 0 && (*mAux2Index) < monitorCount)
	{
		monitors[*mAux2Index].dwFlags |= monitorReserved;
	}

	if (mPrimaryIndex == NULL)
	{
		DEBUG_STREAM << "Trying to find the monitor marked as active in Windows..." << std::endl;
		//Set up the monitor so marked as the primary (unless none are marked)
		for (int i = 0; i < monitorCount; i++)
		{
			int flags = monitors[i].dwFlags;

			if ((flags & (MONITORINFOF_PRIMARY | monitorReserved)) == MONITORINFOF_PRIMARY)
			{
				DEBUG_STREAM << "Monitor " << i << " was set as active in Windows... setting it as the primary monitor." << endl;
				mPrimaryIndex = new int;
				*mPrimaryIndex = i;
				monitors[i].dwFlags |= monitorReserved;
				break;
			}
		}
	}

	//Do gauges next, since they're the easiest to pick out
	if (!Application::DoSuppressGauges() && !isWindowed && monitorCount > 2)
	{
		DEBUG_STREAM << "Gauges are on, we are not in windowed mode, and we have " << monitorCount << " available monitors, so will try to find MFDs..." << std::endl;

		if (mAux1Index == NULL && (spanDisablePtr == NULL || !(*spanDisablePtr)))
		{
			DEBUG_STREAM << "Don't have a MFD #1 monitor yet, and spanning is not explicitly disabled, so will try to find a really wide monitor for both MFDs..." << std::endl;

			//try to find a really wide monitor to use as gauge1
			for (int i = 0; i < monitorCount; i++)
			{
				if ((monitors[i].dwFlags & monitorReserved) == 0)
				{
					RECT size = monitors[i].rcMonitor;

					float aspect = ( (double)(size.right - size.left) / (double)(size.bottom - size.top));

					if (aspect > 2.5f)
					{
						//Really wide!  Probably a spanning monitor
						DEBUG_STREAM << "Monitor " << i << " is really wide, so will try to use it as the MFDs." << std::endl; 

						mAux1Index = new int;
						*mAux1Index = i;
						monitors[i].dwFlags |= monitorReserved;
						
						if (spanDisablePtr == NULL)
						{
							DEBUG_STREAM << "Explicitly setting spanning to enabled..." << std::endl;
							spanDisable = FALSE;
							spanDisablePtr = &(spanDisable);
						}
						break;
					}
				}
			}
		}

		int possibleAux2Index = -1;
		if (mAux1Index == NULL && (spanDisablePtr == NULL || *spanDisablePtr))
		{
			DEBUG_STREAM << "MFDs not found yet, and spanning isn't explicitly enabled.  Will try to find two same-size monitors to use as MFDs..." << std::endl;
			map<pair<int,int>,vector<int>> sameSizeMonitors;

			//Group the unclaimed monitors by resolution
			for (int i = 0; i < monitorCount; i++)
			{
				if ((monitors[i].dwFlags & monitorReserved) == 0)
				{
					int width = monitors[i].rcMonitor.right - monitors[i].rcMonitor.left;
					int height = monitors[i].rcMonitor.bottom - monitors[i].rcMonitor.top;

					pair<int, int> resolution(width, height);
					if (sameSizeMonitors.find(resolution) == sameSizeMonitors.end())
					{
						sameSizeMonitors[resolution] = vector<int>();
					}

					sameSizeMonitors[resolution].insert(sameSizeMonitors[resolution].begin(), i);
				}
			}

			//Retrieve the bucket of monitors with at least two monitors and the smallest resolution (y res counts more than x res)
			vector<int> bestMonitors;
			int smallestYRes = -1;
			int bestXRes = -1;
			for (map<pair<int,int>,vector<int>>::iterator it = sameSizeMonitors.begin(); it != sameSizeMonitors.end(); it++)
			{
				if ((*it).second.size() >= 2)
				{
					int yRes = (*it).first.second;
					int xRes = (*it).first.first;

					if (smallestYRes >= 0)
					{
						DEBUG_STREAM << "Multiple sets of identically-sized monitors are available.  Will use smallest set..." << std::endl;
					}

					if (smallestYRes < 0 || yRes < smallestYRes || (yRes == smallestYRes && xRes < bestXRes))
					{
						smallestYRes = yRes;
						bestXRes = xRes;
						bestMonitors = (*it).second;
					}
				}
			}

			int aux1Candidate = -1;
			int aux2Candidate = -1;

			int aux1Right = 0;
			int aux2Right = 0;

			if (bestMonitors.size() > 2)
			{
				DEBUG_STREAM << "More than 2 monitors in the set of smallest, identically-sized monitors...  Will use the furthest right as right MFD, one just to the left of that as left MFD..." << std::endl;
			}

			//The second aux screen is the one furthest to the right
			//the first aux screen is the one just to the left of that one
			for (vector<int>::iterator it = bestMonitors.begin(); it != bestMonitors.end(); it++)
			{
				int i = (*it);

				if ((monitors[i].dwFlags & monitorReserved) == 0)
				{
					int right = monitors[i].rcMonitor.right;
					if (aux2Candidate < 0 || aux2Right < right)
					{
						aux1Candidate = aux2Candidate;
						aux1Right = aux2Right;
						aux2Candidate = i;
						aux2Right = right;
					} else if (aux1Candidate < 0 || aux1Right < right)
					{
						aux1Candidate = i;
						aux1Right = right;
					}
				}
			}

			if (aux1Candidate >= 0 && aux2Candidate >= 0)
			{
				DEBUG_STREAM << "Got two decent same-size monitors, will use as MFDs... Left is " << aux1Candidate << " and right is " << aux2Candidate << "." << std::endl;
				mAux1Index = new int;
				*mAux1Index = aux1Candidate;
				monitors[aux1Candidate].dwFlags |= monitorReserved;

				mAux2Index = new int;
				*mAux2Index = aux2Candidate;
				monitors[aux2Candidate].dwFlags |= monitorReserved;

				spanDisable = true;
				spanDisablePtr = &spanDisable;
			} else
			{
				DEBUG_STREAM << "Could not find two identical monitors to use for MFDs." << std::endl;
			}
		}

		if (mAux2Index == NULL && mAux1Index != NULL && (spanDisablePtr == NULL || *spanDisablePtr))
		{
			DEBUG_STREAM << "We have a left MFD and no right MFD, and spanning is not explicitly enabled.  Will try to find identically-sized right MFD." << std::endl;
			//find a monitor that is identical to the first gauge monitor
			//if multiple, use the furthest to the right
			int bestMonitorIndex = -1;
			int bestMonitorRight = 0;
			int aux1Width = (monitors[*mAux1Index].rcMonitor.right - monitors[*mAux1Index].rcMonitor.left);
			int aux1Height = (monitors[*mAux1Index].rcMonitor.bottom - monitors[*mAux1Index].rcMonitor.top);

			for (int i = 0; i < monitorCount; i++)
			{
				if ((monitors[i].dwFlags & monitorReserved) == 0)
				{
					int monitorWidth = (monitors[i].rcMonitor.right - monitors[i].rcMonitor.left);
					int monitorHeight = (monitors[i].rcMonitor.bottom - monitors[i].rcMonitor.top);

					if (monitorWidth == aux1Width && monitorHeight == aux1Height)
					{
						if (bestMonitorIndex >= 0)
						{
							DEBUG_STREAM << "Found more than one monitor identically sized to the left MFD.  Will use furthest-right monitor." << std::endl;
						}

						if (bestMonitorIndex < 0 || bestMonitorRight < monitors[i].rcMonitor.right)
						{
							bestMonitorIndex = i;
							bestMonitorRight = monitors[i].rcMonitor.right;
						}
					}
				}
			}

			if (bestMonitorIndex >= 0)
			{
				DEBUG_STREAM << "Using monitor " << bestMonitorIndex << "as right MFD monitor." << std::endl;
				mAux2Index = new int;
				*mAux2Index = bestMonitorIndex;
				monitors[bestMonitorIndex].dwFlags |= monitorReserved;
			} else
			{
				DEBUG_STREAM << "Could not find decent monitor for right MFD." << std::endl;
			}
		}
	} else
	{
		DEBUG_STREAM << "Either MFDs are explicitly disabled, we're running in windowed mode, or we don't have enough monitors attached to this machine.  MFD monitors will not be detected." << std::endl;
	}

	if (mPrimaryIndex == NULL)
	{
		DEBUG_STREAM << "Still no appropriate primary monitor- will find tallest monitor to use." << std::endl;
		//Pick the monitor with the highest y resolution (leftmost if there's a tie)
		int bestMonitorIndex = -1;
		int bestMonitorHeight = 0;
		int bestMonitorX = 0;

		for (int i = 0; i < monitorCount; i++)
		{
			if ((monitors[i].dwFlags & monitorReserved) == 0)
			{
				int height = (monitors[i].rcMonitor.bottom - monitors[i].rcMonitor.top);
				if (bestMonitorIndex < 0 || height > bestMonitorHeight || (height == bestMonitorHeight && monitors[i].rcMonitor.left < bestMonitorX))
				{
					bestMonitorIndex = i;
					bestMonitorHeight = height;
					bestMonitorX = monitors[i].rcMonitor.left;
				}
			}
		}

		if (bestMonitorIndex >= 0)
		{
			DEBUG_STREAM << "Using monitor " << bestMonitorIndex << " as primary monitor." << std::endl;
			mPrimaryIndex = new int;
			*mPrimaryIndex = bestMonitorIndex;
			monitors[bestMonitorIndex].dwFlags |= monitorReserved;
		} else
		{
			DEBUG_STREAM << "Could not find decent primary monitor.  Likely no unclaimed monitors." << std::endl;
		}
	}

	if (mPrimaryIndex != NULL && isWindowed)
	{
		DEBUG_STREAM << "Game is currently running windowed mode- will set all remaining undefined monitors to be the same as the primary monitor." << std::endl;
		if (mSecondaryIndex == NULL)
		{
			mSecondaryIndex = new int;
			*mSecondaryIndex = *mPrimaryIndex;
		}

		if (mAux1Index == NULL && mAux2Index == NULL)
		{
			mAux1Index = new int;
			*mAux1Index = *mPrimaryIndex;

			mAux2Index = new int;
			*mAux2Index = *mPrimaryIndex;
		}
	} else if (!isWindowed && mSecondaryIndex == NULL)
	{
		DEBUG_STREAM << "Detecting secondary monitor- will attempt to use furthest-left remaining monitor." << std::endl;
		//Pick the leftmost remaining monitor
		int leftmostIndex = -1;
		int leftmostX = 0;

		for (int i = 0; i < monitorCount; i++)
		{
			if ((monitors[i].dwFlags & monitorReserved) == 0)
			{
				if (leftmostIndex < 0 || monitors[i].rcMonitor.left < leftmostX)
				{
					leftmostIndex = i;
					leftmostX = monitors[i].rcMonitor.left;
				}
			}
		}

		if (leftmostIndex >= 0)
		{
			DEBUG_STREAM << "Using monitor " << leftmostIndex << " as secondary monitor." << std::endl;
			mSecondaryIndex = new int;
			*mSecondaryIndex = leftmostIndex;
		} else
		{
			DEBUG_STREAM << "Could not find appropriate secondary monitor.  Likely no unclaimed monitors remain." << std::endl;
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructor for DPLRenderer
//
DPLRenderer::DPLRenderer(
	HWND hWnd,
	unsigned int screenWidth,
	unsigned int screenHeight,
	bool fullscreen,
	InterestType interest_type,
	InterestDepth depth_calibration
):
	VideoRenderer(
		 1.0f,
		 1.0f,
		 RendererPriority::DefaultRendererPriority,
		 interest_type,
		 depth_calibration
		),
	projectile_list(NULL),
	dplObjectCacheSocket(NULL, False),
	dplJointToDCSTranslatorSocket(NULL,False),
	dplRenderableSocket(NULL),
	mRenderables(NULL),
	x_size(screenWidth),
	y_size(screenHeight),
	mReticle(NULL),
	mCamShipHUD(NULL),
	mStaticObjectsHead(NULL),
	mStaticObjectsCount(0),
	mPrimaryIndex(NULL),
	mSecondaryIndex(NULL),
	mAux1Index(NULL),
	mAux2Index(NULL)
{
   __int64 frequency = HiResCounterFreq();
#ifdef LOGFRAMERATE
   FRAMERATE_LOG = fopen("framerate.log", "wb");
   fwrite(&frequency, sizeof(__int64), 1, FRAMERATE_LOG);
#endif

	mCamera = NULL;

	loadTables();

	// clear out our render lists
	memset(mRenderLists, 0, sizeof(mRenderLists));
	memset(mNameTextures, 0, sizeof(mNameTextures));
	memset(mOrdinalTextures, 0, sizeof(mOrdinalTextures));

	D3DXCreateMatrixStack(0, &m_MatrixStack);
	m_MatrixStack->LoadIdentity();

	gD3D = Direct3DCreate9(D3D_SDK_VERSION);
	if (!gD3D)
	{
		DEBUG_STREAM<<"Couldn't create Direct3D interface!"<<std::endl<<std::flush << std::flush;
		PostQuitMessage(1);
	}

	this->FindBestAdapterIndices(!fullscreen);

	memset(&mPresentParams, 0, sizeof(D3DPRESENT_PARAMETERS));

	mPresentParams.BackBufferCount = 1;
	mPresentParams.MultiSampleType = (D3DMULTISAMPLE_TYPE)atol(getenv("MULTISAMPLE"));
	if (mPresentParams.MultiSampleType > 0)
	{
	   gD3D->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, !fullscreen, mPresentParams.MultiSampleType, &mPresentParams.MultiSampleQuality);
	   mPresentParams.MultiSampleQuality--;
	}
	mPresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
	mPresentParams.hDeviceWindow = hWnd;
	mPresentParams.Flags = 0;
	mPresentParams.FullScreen_RefreshRateInHz = (fullscreen)?60:D3DPRESENT_RATE_DEFAULT;
	mPresentParams.PresentationInterval = D3DPRESENT_RATE_DEFAULT;
	mPresentParams.BackBufferFormat = D3DFMT_X8R8G8B8;
	mPresentParams.EnableAutoDepthStencil = TRUE;
	mPresentParams.AutoDepthStencilFormat = D3DFMT_D24X8;
	mPresentParams.Windowed = !fullscreen;
	if (fullscreen)
	{
		mPresentParams.BackBufferWidth = screenWidth;
		mPresentParams.BackBufferHeight = screenHeight;
	}

	HRESULT hr;

	//DEBUG_STREAM<<"**************************"<<std::endl<<"**************************"<<std::endl;
	//for (UINT adapter = 0; adapter<=3; adapter++)
	//{
	//	DEBUG_STREAM<<"\tAdapter "<<adapter<<": ";
	//	D3DFORMAT format = (adapter == 0 ? D3DFMT_X8R8G8B8 : D3DFMT_R5G6B5);

	//	UINT modes = gD3D->GetAdapterModeCount(adapter, format);
	//	DEBUG_STREAM<<modes<<" display modes"<<std::endl;

	//	for (UINT mode=0; mode<modes; mode++)
	//	{
	//		D3DDISPLAYMODE displayMode;
	//		hr = gD3D->EnumAdapterModes(adapter, format, mode, &displayMode);
	//		if (FAILED(hr))
	//		{
	//			DEBUG_STREAM<<"\t\tFailed to retrieve display mode "<<mode<<"."<<std::endl;
	//			continue;
	//		}

	//		DEBUG_STREAM<<"\t\t"<<displayMode.Format<<": "<<displayMode.Width<<" x "<<displayMode.Height<<" @ "<<displayMode.RefreshRate<<" Hz"<<std::endl;
	//	}

	//	DEBUG_STREAM<<std::endl;
	//}
	//DEBUG_STREAM<<"**************************"<<std::endl<<"**************************"<<std::endl<<std::flush;
	
	if (mPrimaryIndex == NULL)
	{
		DEBUG_STREAM<<"Unable to locate a suitable primary device index."<<std::endl<<std::flush;
		PostQuitMessage(1);
		return;
	}

	V(gD3D->CreateDevice(*mPrimaryIndex, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &mPresentParams, &mDevice));
	if (FAILED(hr))
	{
		DEBUG_STREAM<<"Couldn't create HARDWARE_VERTEXPROCESSING device."<<std::endl<<std::flush;

		V(gD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &mPresentParams, &mDevice));
		if (FAILED(hr))
		{
			PostQuitMessage(1);
		}
	}

	mDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0xFF000000, 0.0f, 0);
	mDevice->Present(NULL, NULL, NULL, NULL);

	ParticleEngine::Initialize(mDevice);

	SetCoreRenderStates();

//STUBBED: DPL RB 1/14/07
	char
		Eye_Type[50],
		*Eye_Arg,			// Controls generation of the eye point
		*DPL_Arg;	  		// Points to DPLARG environment pointer once we get it
	int
		psfx_number;
//	int
//		i;            		// Temporary loop counter
	float
		eye_x,
		eye_y,
		eye_z,
		eye_x_rot,
		eye_y_rot,
		eye_z_rot;
//
// Initialize a bunch of the variables to their starting values
//
	eyeRelative				=	False;
	completeCycleNeeded	=	False;
	lastAppState			=	0;
	fogUpdating 			= True;
	fogRed					=	0.0f;
	fogBlue					=	0.0f;
	fogGreen					=	0.0f;
	fogNear					=	0.0f;
	fogFar					=	0.0f;
	currentFogFar			=	0.0f;
	currentFogNear			=	0.0f;
	searchLightFogRed			=	0.0f;
	searchLightFogGreen		=	0.0f;
	searchLightFogBlue		=	0.0f;
	searchLightFogNear		=	0.0f;
	searchLightFogFar			=	0.0f;
	noSearchLightFogRed		=	0.0f;
	noSearchLightFogGreen	=	0.0f;
	noSearchLightFogBlue		=	0.0f;
	noSearchLightFogNear		=	0.0f;
	noSearchLightFogFar		=	0.0f;
	clipNear					=	0.0f;
	clipFar					=	0.0f;
	backgroundRed			=	0.0f;
	backgroundGreen		=	0.0f;
	backgroundBlue			=	0.0f;
	viewAngle				=	30.0f;
	dplMainView				=	NULL;
	dplDeathZone			=	NULL;
	dplMainZone				=	NULL;
	vehicleReticle			=	NULL;
	dplHitInstance			=	NULL;
	dplHitDCS				=	NULL;
	dplHitGeoGroup			=	NULL;
	dplHitGeometry			=	NULL;
	delayedDCSCount		=	0;
	myUniqueID				=	0;
	sceneLightDCS			= NULL;
	sceneLight				= NULL;
	sceneLightCount		=	0;

	worldToEyeMatrix		=	LinearMatrix::Identity;		// the current world to eye transform for our linked entity
	currentFrameTime		=	Now();							// the time at the start of renderable execution

	Verify(!DPLHeap);
//	DPLHeap = new UserHeap("DPL Heap", 2000000);
	Register_Object(DPLHeap);

	//
	// Clear the myPSFXDescriptons array to all zeros so we can detect attempts
	// to use uninitialized items.
	//
	memset(myPSFXDescriptons, 0, sizeof(myPSFXDescriptons));

	//
	// These guys will come out of a world environment variable eventually
	//
	eye_x				=	0.0f;
	eye_y				=	10.0f;
	eye_z				=	0.0f;
	eye_x_rot		=	0.0f;
	eye_y_rot		=	0.0f;
	eye_z_rot		=	0.0f;
//
// Get pointers to environmentals containing DPL startup arguments and
// eye positioning information.  If L4EYES is present set the renderer
// variable that controls the hooking up of the eye position.
//
	Eye_Type[0] =	0;
	DPL_Arg		=	getenv("DPLARG");
	Eye_Arg		=	getenv("L4EYES");
	if(Eye_Arg)
	{
		sscanf(
			Eye_Arg,
			"%f %f %f %f %f %f %s",
			&eye_x,
			&eye_y,
			&eye_z,
			&eye_x_rot,
			&eye_y_rot,
			&eye_z_rot,
			Eye_Type);

		printf("%f, %f, %f  %f, %f, %f\n",
				  eye_x,
				  eye_y,
				  eye_z,
				  eye_x_rot,
				  eye_y_rot,
				  eye_z_rot);

		Disconnected_Eye	=	True;		// tells vidrend:: to request outside view of linked entity
		if(*Eye_Type == 'r')
		{
			DEBUG_STREAM<<"DPLRenderer::DPLRenderer Eye will be offset relative to vehicle\n" << std::flush;
			eyeRelative	=	True;
		}
	}
//
// If the argument was empty, we can't render !!! should exit sensiblly
//
	if(!DPL_Arg)
	{
		DEBUG_STREAM << "DPLARG must be set for the Division card to come up\n" << std::flush;
		Verify(DPL_Arg);
	}
//
// If we're still here, try to interpret and setup the screen resolution
// requested by DPLARG.  The screen_resolution function is Phil's routine
// in startdpl.
//
//	if (screen_resolution ( DPL_Arg ) == 0)
//	{
//		DEBUG_STREAM << "DPLARG is bad, I couldn't understand video format\n" << std::flush;
//		Verify(DPL_Arg);
//	}
//
// Breakdown the DPLARGS string using expload_args from startdpl, then feed
// the results to the dpl_Init routine to get DPL up and running.
//
	char *argv[32];
//	int argc = explode_args ( argv, DPL_Arg, dpl_arg_sep );
//	dpl_Init							( argc, argv );
	//
	// Setup the file paths for geometry and texture loading
	//
//	dpl_SetObjectFilePath   ( ".\\video", "\\video", "..\\video" );
//	dpl_SetTexmapFilePath   ( ".\\video", "\\video", "..\\video" );
//	dpl_SetMaterialFilePath ( ".\\video", "\\video", "..\\video" );
//	dpl_SetObjectFilePath   ( ".\\video", "", "" );
//	std::cout<<dpl_GetObjectFilePath()<<"\n";
//	dpl_SetTexmapFilePath   ( ".\\video", "", "" );
//	std::cout<<dpl_GetTexmapFilePath()<<"\n";
//	dpl_SetMaterialFilePath ( ".\\video", "", "" );
//	std::cout<<dpl_GetMaterialFilePath()<<"\n";
	//
	// Set the extensions and the DPL routines that will load them
	//
//	dpl_SetExtnObjectLoadFunc (".bgf",  dpl_bgfRead);
//	dpl_SetExtnTexmapLoadFunc (".vtx",  dpl_vtxRead);
//	dpl_SetExtnTexmapLoadFunc (".tga",  dpl_tgaRead);
//	dpl_SetExtnTexmapLoadFunc (".int",  dpl_sgiRead);
//	dpl_SetExtnTexmapLoadFunc (".inta", dpl_sgiRead);
//	dpl_SetExtnTexmapLoadFunc (".rgb",  dpl_sgiRead);
//	dpl_SetExtnTexmapLoadFunc (".rgba", dpl_sgiRead);
	//
	// Setup the dpl callback routines for handling specials, object creation and
	// material name munging.
	//
//	dpl_SetSpecialCallback(TestSpecialCallBack);
//	dpl_SetCreateNodeCallback(TestCreateCallBack);
	//	dpl_SetMaterialNameCallback(TestMaterialCallBack);
	//
	// Create the one zone everything will live in !!!! more zones later for smart culling
	//
//	dplMainZone		=	dpl_NewZone();
	Check_Pointer(dplMainZone);
//	dplDeathZone	=	dpl_NewZone();
	Check_Pointer(dplDeathZone);
//
// Create the view we will use for our eyepoint
//
//	dplMainView	=	dpl_NewView();
	Check_Pointer(dplMainView);
//
// This creates a DCS and links it to the view, I probably should just let the
// eye renderable do this but it's convenient since it can be used as the
// eye point for testing.
//
//	dplTestEyeDCS	=	dpl_NewDCS();
	Check_Pointer		( dplTestEyeDCS);
//	dpl_RotateDCS   	( dplTestEyeDCS, eye_z_rot, dpl_Z );
//	dpl_RotateDCS   	( dplTestEyeDCS, eye_x_rot, dpl_X );
//	dpl_RotateDCS   	( dplTestEyeDCS, eye_y_rot, dpl_Y );
//	dpl_TranslateDCS	( dplTestEyeDCS, eye_x, eye_y, eye_z);

//	dpl_SetDCSZone		( dplTestEyeDCS, dplMainZone );
//	dpl_SetViewDCS		( dplMainView,   dplTestEyeDCS);
//
// Do some setup work on the zone
//
//	dpl_SetZoneAllViewsOn 	( dplMainZone );
//	dpl_SetZoneAllViewsOn 	( dplDeathZone );
//
// Setup some defaults so we can safely render a blank screen now

	//

//
//	dpl_SetViewClipPlanes	( dplMainView, 1.0f, 2.0f );
//	dpl_SetViewBackGround	( dplMainView, 0.0f, 0.0f, 0.0f);
//	dpl_SetPipeWindow			(0, 0, 0, x_size, y_size);
//	dpl_SetViewProjection	( dplMainView, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f/(tan( 0.5235987666667f)));
//	dpl_SetViewPipe			( dplMainView, 0);
//	dpl_AddViewToScene		( dplMainView );
//	dpl_SetViewFog				(dplMainView, dpl_fog_type_pixel_lin, 0.0, 0.0, 0.0, 0.01, 0.05 );
//
//	DPLReadEnvironment();
//
//	dpl_FlushDCS				( dplTestEyeDCS);
//	dpl_FlushView				( dplMainView);
//	dpl_FlushZone				( dplMainZone);
//	dpl_FlushZone				( dplDeathZone);
//
// Call DrawScene to force the system do draw a blank screen
//
//	dpl_DrawScene();
//
// Start a clock used to keep track of the frame rate
//
	StartSample		= Now();
	FrameCount		= 0;
	ResetStatistics();
   statistics_started = False;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dpl_ZONE*
	DPLRenderer::MakeNewZone()
{
	//STUBBED: DPL RB 1/14/07
	dpl_ZONE *temp_zone;
	////
	//// Make a new zone for use by someone constructing an object, switch it on
	//// and std::flush it out to the card.
	////
	//temp_zone		=	dpl_NewZone();
	//Check_Pointer(temp_zone);
	//dpl_SetZoneAllViewsOn 	(temp_zone);
	//dpl_FlushZone				(temp_zone);
	////
	//// HACK !!! at this point we should put the zone into a chain so we can
	//// find it to switch it on and off later.
	////
	return(temp_zone);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// AddDynamicRenderable puts a renderable into this renderer's dynamic execution
// socket so it will be run every frame.
//
void DPLRenderer::AddDynamicRenderable(Component *my_renderable)
{
	Check(my_renderable);
	Check(&dplRenderableSocket);
	dplRenderableSocket.Add(my_renderable);
}

void DPLRenderer::AddToPassList(d3d_OBJECT *object, int pass)
{
	if (pass >= PASS_TOTAL_COUNT)
		return;

	for (d3d_OBJECT *iter = mRenderLists[pass]; iter; iter = iter->GetNext(pass))
		if ((void*)iter == (void*)object)
			return;

	object->SetPrevious(NULL, pass);
	object->SetNext(mRenderLists[pass], pass);

	if (mRenderLists[pass] != NULL)
		mRenderLists[pass]->SetPrevious(object, pass);
	
	mRenderLists[pass] = object;
}

hyper DPLRenderer::HashAdd(hyper input, char data)
{
	const hyper multiplier = 37;
	return (input * multiplier) + data;
}

hyper DPLRenderer::HashDrawOp(L4DRAWOP *op)
{
	char diffR = (char)(op->material.Diffuse.r * 255);
	char diffG = (char)(op->material.Diffuse.g * 255);
	char diffB = (char)(op->material.Diffuse.b * 255);
	char diffA = (char)(op->material.Diffuse.a * 255);

	char ambA = (char)(op->material.Ambient.a * 255);
	char ambR = (char)(op->material.Ambient.r * 255);
	char ambG = (char)(op->material.Ambient.g * 255);
	char ambB = (char)(op->material.Ambient.b * 255);

	char spcA = (char)(op->material.Specular.a * 255);
	char spcR = (char)(op->material.Specular.r * 255);
	char spcG = (char)(op->material.Specular.g * 255);
	char spcB = (char)(op->material.Specular.b * 255);
	char spcP = (char)(op->material.Power * 255);

	char emiA = (char)(op->material.Emissive.a * 255);
	char emiR = (char)(op->material.Emissive.r * 255);
	char emiG = (char)(op->material.Emissive.g * 255);
	char emiB = (char)(op->material.Emissive.b * 255);

	const hyper startValue = 37;
	hyper hash = startValue;
	
	hash = HashAdd(hash, diffA);
	hash = HashAdd(hash, diffR);
	hash = HashAdd(hash, diffG);
	hash = HashAdd(hash, diffB);
	hash = HashAdd(hash, ambA);
	hash = HashAdd(hash, ambR);
	hash = HashAdd(hash, ambG);
	hash = HashAdd(hash, ambB);
	hash = HashAdd(hash, spcA);
	hash = HashAdd(hash, spcR);
	hash = HashAdd(hash, spcG);
	hash = HashAdd(hash, spcB);
	hash = HashAdd(hash, spcP);
	hash = HashAdd(hash, emiA);
	hash = HashAdd(hash, emiR);
	hash = HashAdd(hash, emiG);
	hash = HashAdd(hash, emiB);
	hash = HashAdd(hash, (char)op->drawAsDecal);
	hash = HashAdd(hash, (char)op->alphaTest);
	hash = HashAdd(hash, (char)op->drawAsSky);

	char *pointerPointer = (char*)(&(op->texture.texture));

	for (int i = 0; i < 4; i++)
	{
		hash = HashAdd(hash, pointerPointer[i]);
	}

	return hash;
}

void DPLRenderer::AddStaticObject(d3d_OBJECT *object)
{
	object->SetPrevious(NULL, -1);
	object->SetNext(mStaticObjectsHead, -1);

	if (mStaticObjectsHead != NULL)
		mStaticObjectsHead->SetPrevious(object, -1);

	mStaticObjectsHead = object;
	mStaticObjectsCount++;
}

void DPLRenderer::RecurseStaticObject(HierarchicalDrawComponent *obj)
{
   if (obj->IsStatic())
   {
      if (obj->GetDrawObj() != NULL && obj->GetDrawObj()->GetMesh() != NULL)
      {
		//Only load it for a static object if it has a valid mesh-
		//we'll handle valid sphere lists later
         this->AddStaticObject(obj->GetDrawObj());
         obj->ResetDrawObj();
      }

      std::vector<HierarchicalDrawComponent *>::const_iterator child_it = obj->Enumerate();

      while (child_it != obj->End())
      {
         RecurseStaticObject(*child_it);
         ++child_it;
      }
   }
}

d3d_OBJECT * DPLRenderer::ConsolidateSingleObject(LPD3DXMESH *meshes, D3DXMATRIX *transforms, UINT startingMesh, UINT meshCount, hash_map<DWORD, hyper> subsetHash, hash_map<hyper, DWORD> hashToOp, vector<L4DRAWOP*> finalOps)
{
	HRESULT hr;
	LPD3DXMESH outMesh;

	V( D3DXConcatenateMeshes(meshes + startingMesh, meshCount, D3DXMESH_MANAGED, transforms + startingMesh, NULL, NULL, mDevice, &outMesh) );

	DWORD *adjacency = new DWORD[outMesh->GetNumFaces() * 3];
	V( outMesh->GenerateAdjacency(0.05f, adjacency) );

	DWORD *attributes;
	int numFaces = outMesh->GetNumFaces();
	V( outMesh->LockAttributeBuffer(0, &attributes) );
	for (int i = 0; i < numFaces; i++)
	{
		stdext::hash_map<DWORD, hyper>::const_iterator face_it = subsetHash.find(attributes[i]);

		if (face_it == subsetHash.end())
		{
			//Freak out
			
		}

		stdext::hash_map<hyper, DWORD>::const_iterator subset_it = hashToOp.find((*face_it).second);

		if (subset_it == hashToOp.end())
		{
			//Freak out
		}

		attributes[i] = (*subset_it).second;
	}
	V( outMesh->UnlockAttributeBuffer() );

	V( outMesh->OptimizeInplace(D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT, adjacency, adjacency, NULL, NULL) );
	
	d3d_OBJECT *consolObj = new d3d_OBJECT(mDevice, outMesh, adjacency, finalOps.size());

	for (int drawOpInd = 0; drawOpInd < consolObj->GetDrawOpCount(); drawOpInd++)
	{
		L4DRAWOP *op = consolObj->GetDrawOp(drawOpInd);
		L4DRAWOP *source = finalOps[drawOpInd];

		op->material = source->material;
		op->texture = source->texture;
		op->drawAsDecal = source->drawAsDecal;
		op->alphaTest = source->alphaTest;		
		op->drawAsSky = source->drawAsSky;
		
		if (op->texture.texture != NULL)		
		{			
			op->texture.texture->AddRef();
		}
	}

	delete [] adjacency;

	return consolObj;
}

void DPLRenderer::ConsolidateStaticObjects()
{
	HRESULT hr;

	HierarchicalDrawComponent *drawComp;
	SChainIteratorOf<HierarchicalDrawComponent*> iterator(&mRenderables);
	while ((drawComp = iterator.ReadAndNext()) != NULL)
	{
		if (drawComp->IsStatic())
		{
			drawComp->Execute();
			this->RecurseStaticObject(drawComp);
		}
	}

	LPD3DXMESH *meshes = new LPD3DXMESH[mStaticObjectsCount];
	D3DXMATRIX *transforms = new D3DXMATRIX[mStaticObjectsCount];

	int i = 0;
	int opCount = 0;

	std::vector<L4DRAWOP*> finalOps;
	stdext::hash_map<hyper, DWORD> hashToOp;
	stdext::hash_map<DWORD, hyper> subsetHash;

	int vertCount = 0;
	int startMesh = 0;
	int meshCount = 0;

	for (d3d_OBJECT *obj = mStaticObjectsHead; obj; obj = obj->GetNext(-1), i++)
	{
		if (vertCount + obj->GetMesh()->GetNumVertices() > 65535)
		{
			this->mConsolidatedStaticObjects.push_back(this->ConsolidateSingleObject(meshes, transforms, startMesh, meshCount, subsetHash, hashToOp, finalOps));
			vertCount = 0;
			startMesh = meshCount;
			meshCount = 0;
			opCount = 0;

			//Clear the draw ops lists
			finalOps.clear();
			hashToOp.clear();
			subsetHash.clear();
		}

		meshes[i] = obj->GetMesh();
		transforms[i] = obj->GetLocalToWorld();

		vertCount += meshes[i]->GetNumVertices();
		meshCount++;

		for (int opNum = 0; opNum < obj->GetDrawOpCount(); opNum++)
		{
			hyper hash = this->HashDrawOp(obj->GetDrawOp(opNum));
			stdext::hash_map<hyper, DWORD>::const_iterator hash_it = hashToOp.find(hash);

			if (hash_it == hashToOp.end())
			{
				finalOps.insert(finalOps.end(), obj->GetDrawOp(opNum));
				hashToOp.insert(std::pair<hyper, DWORD>(hash, (DWORD)(finalOps.size() - 1)));
				hash_it = hashToOp.find(hash);
			}

			subsetHash.insert(std::pair<DWORD, hyper>((DWORD)opCount, hash));
			opCount++;
		}
	}

	if (meshCount > 0)
	{
		this->mConsolidatedStaticObjects.push_back(this->ConsolidateSingleObject(meshes, transforms, startMesh, meshCount, subsetHash, hashToOp, finalOps));
	}

	d3d_OBJECT *obj = mStaticObjectsHead;
	while (obj != NULL)
	{
		d3d_OBJECT *next = obj->GetNext(-1);

		delete obj;
		obj = next;
	}

	mStaticObjectsHead = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// RemoveDynamicRenderable removes a renderable from the dynamic execution
// socket.
//
void
	DPLRenderer::RemoveDynamicRenderable(Component *my_renderable)
{
	Check(my_renderable);
	Check(&dplRenderableSocket);
	PlugIterator	remover(my_renderable);
	remover.RemoveSocket(&dplRenderableSocket);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
	DPLRenderer::SetFogStyle(FogStyle my_fog)
{
	//STUBBED: DPL RB 1/14/07
	switch(my_fog)
	{
		case updateFogSetting:
			fogUpdating = True;
			break;
		case noUpdateFogSetting:
			fogUpdating = False;
			break;
		case searchLightOnFogStyle:
			fogRed	=	searchLightFogRed;
			fogGreen =	searchLightFogGreen;
			fogBlue	=	searchLightFogBlue;
			fogNear	=	searchLightFogNear;
			fogFar	=	searchLightFogFar;
			if(fogUpdating)
			{
            mDevice->SetRenderState(D3DRS_FOGCOLOR, D3DCOLOR_XRGB((int)(255 * fogRed), (int)(255 * fogGreen), (int)(255 * fogBlue)));
	//			dpl_SetViewFog(
	//				dplMainView,
	//				dpl_fog_type_pixel_lin,
	//				fogRed,
	//				fogGreen,
	//				fogBlue,
	//				fogNear,
	//				fogFar );
	//			dpl_FlushView(dplMainView);
			}
			break;
		case searchLightOffFogStyle:
			fogRed	=	noSearchLightFogRed;
			fogGreen =	noSearchLightFogGreen;
			fogBlue	=	noSearchLightFogBlue;
			fogNear	=	noSearchLightFogNear;
			fogFar	=	noSearchLightFogFar;
			if(fogUpdating)
			{
            mDevice->SetRenderState(D3DRS_FOGCOLOR, D3DCOLOR_XRGB((int)(255 * fogRed), (int)(255 * fogGreen), (int)(255 * fogBlue)));
	//			dpl_SetViewFog(
	//				dplMainView,
	//				dpl_fog_type_pixel_lin,
	//				fogRed,
	//				fogGreen,
	//				fogBlue,
	//				fogNear,
	//				fogFar );
	//			dpl_FlushView(dplMainView);
			}
			break;
		case winnersCircleFogStyle:
			//
			// HACK!!  This really shouldn't reset the clip planes, but since
			// it only happens at the end of the review, it should be safe for now.
			//
	//		dpl_SetViewClipPlanes	( dplMainView, 0.25f, 1100.0f );
	//		dpl_SetViewFog(
	//					dplMainView,
	//					dpl_fog_type_pixel_lin,
	//					0.32,
	//					0.3,
	//					0.65,
	//					100.0f,
	//					1050.0f );
	//		dpl_FlushView(dplMainView);
			break;
	}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
	DPLRenderer::GetCurrentFogSettings(
		float	*fog_Red,
		float	*fog_Green,
		float *fog_Blue,
		float *fog_Near,
		float *fog_Far)
{
	*fog_Red	=	fogRed;
	*fog_Green =	fogGreen;
	*fog_Blue	=	fogBlue;
	*fog_Near	=	fogNear;
	*fog_Far	=	fogFar;
}

void DPLRenderer::SetCurrentFogLimits(
		float fog_Near,
		float fog_Far)
{
	currentFogNear = fog_Near;
	currentFogFar = fog_Far;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//	MarkDCSHiearchy	This will std::decend a DCS tree and set the appSpecific hook
// in every DCS equal to the entity pointer "entity", it calls itself recursively
// to do this.
//
void
	DPLRenderer::MarkDCSHiearchy(
		dpl_DCS	*root_DCS,				// Root of the hiearchy to mark
		Entity	*entity)             // Entity pointer to mark it with
{
	//STUBBED: DPL RB 1/14/07
	//int
	//	dcs_counter;
	//dpl_DCS
	//	*child_DCS;
	////
	//// First, mark this DCS
	////
	//if(dpl_GetAppSpecific(root_DCS))
	//	Fail("DPLRenderer::MarkDCSHiearchy tried to mark a DCS that was already marked!\n");
	//dpl_PutAppSpecific(root_DCS,entity);
	////
	//// Now call this routine on all this dcs's children
	////
	//dcs_counter = 0;
	//while((child_DCS=dpl_GetDCSChildDCS(root_DCS,dcs_counter)) != NULL)
	//{
	//	MarkDCSHiearchy(child_DCS, entity);
	//	dcs_counter++;
	//}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ReadPSFX
// reads a pfx file into a supplied array
// Most of this routine was a direct copy of phil's code and as such is a bit
// on the messy side.
//
dpl_PARTICLESTART_EFFECT_INFO*
	DPLRenderer::ReadPSFX(
		const char	*file_name)		// Name of the file containing the PSFX description
{
//STUBBED: DPL RB 1/14/07
//	FILE
//		*fp;
//	int
//		i,
//		status;
//	char
//		line[256],
//		*cp;
//	//
//	// Open the file containing the psfx, fail if it doesn't exist
//	//
//	strcpy(line,"video\\");
//	strcat(line,file_name);
//	fp	=	fopen ( line, "rt" );
//	if(!fp)
//	{
//		DEBUG_STREAM<<"Could not open pfx file "<<line<<" effects using it will fail\n" << std::flush;
//		return(NULL);
////		Fail("Required PFX file not found\n");
//	}
//	//
//	//	Allocate the memory for the pfx to be stored in.
//	//
	dpl_PARTICLESTART_EFFECT_INFO	*psfx_info	=	new  dpl_PARTICLESTART_EFFECT_INFO;
//	if(!psfx_info)
//	{
//		Fail("ran out of RAM trying to read a pfx file\n");
//	}
//	//
//	// This is the format of the psfx file we are going to read
//	//
//	#if 0
//	format of psfx file is (NO BLANK LINES UNTIL END!)
//	%s texture
//	%d identifier %d maximum_issue %f release_period %f rate
//	%f px %f py %f pz %f pv
//	%f velx %f vely %f velz %f velxv %f velyv %f velzv
//	%f rad %f radv %f exp %f expv %f dexp %f dexpv
//	%f accelx %f accely %f accelz %f accelxv %f accelyv %f accelzv
//	%f atten %f attenv
//	%f sRi %f sGi %f sBi %f sAi %f sRiv %f sGiv %f sBiv %f sAiv
//	%f sRo %f sGo %f sBo %f sAo %f sRov %f sGov %f sBov %f sAov
//	%f eRi %f eGi %f eBi %f eAi %f eRiv %f eGiv %f eBiv %f eAiv
//	%f eRo %f eGo %f eBo %f eAo %f eRov %f eGov %f eBov %f eAov
//	%f color_warp %f alpha_warp
//	%f duration %f durationv
//	#endif
//	//
//	// Read in the texture name, null terminate it and look it up,
//	// we don't complain if it fails since it is possible to do one of these
//	// effects with no texture on it.
//	//
//	cp = fgets ( line, 255, fp );
//	for (i=0; i<255; i++ )
//	{
//		if (cp[i] == '\n')
//			cp[i]=0x0;
//	}
//	psfx_info->tex = dpl_LookupTexture ( cp, dpl_lookup_normal, &status );
//	#if PRINT_THE_PFX
//	printf ( "texture => %s\n", cp );
//	#endif
//	//
//	// The remander of these statements get the rest of the PFX data
//	//
//	cp = fgets ( line, 255, fp );
//	status = sscanf  ( cp,
//		"%x %d %f %f\n",
//		&psfx_info->identifier, &psfx_info->maximum_issue, &psfx_info->release_period, &psfx_info->rate );
//	if(status < 4)
//	{
//		std::cout<<"pfx file "<<file_name<<" did not read correctly\n";
//		return(NULL);
//	}
//
//	cp = fgets ( line, 255, fp );
//	status = sscanf  ( cp, "%f %f %f %f\n", &psfx_info->px, &psfx_info->py, &psfx_info->pz, &psfx_info->pv );
//	if(status < 4)
//	{
//		std::cout<<"pfx file "<<file_name<<" did not read correctly\n";
//		return(NULL);
//	}
//
//	cp = fgets ( line, 255, fp );
//	status = sscanf  ( cp, "%f %f %f %f %f %f\n",
//	&psfx_info->velx, &psfx_info->vely, &psfx_info->velz,
//	&psfx_info->velxv, &psfx_info->velyv, &psfx_info->velzv );
//	if(status < 6)
//	{
//		std::cout<<"pfx file "<<file_name<<" did not read correctly\n";
//		return(NULL);
//	}
//
//	cp = fgets ( line, 255, fp );
//	status = sscanf  ( cp, "%f %f %f %f %f %f\n",
//	&psfx_info->rad, &psfx_info->radv, &psfx_info->exp, &psfx_info->expv, &psfx_info->dexp, &psfx_info->dexpv );
//	if(status < 6)
//	{
//		std::cout<<"pfx file "<<file_name<<" did not read correctly\n";
//		return(NULL);
//	}
//
//	cp = fgets ( line, 255, fp );
//	status = sscanf  ( cp, "%f %f %f %f %f %f\n",
//	&psfx_info->accelx, &psfx_info->accely, &psfx_info->accelz,
//	&psfx_info->accelxv, &psfx_info->accelyv, &psfx_info->accelzv );
//	if(status < 6)
//	{
//		std::cout<<"pfx file "<<file_name<<" did not read correctly\n";
//		return(NULL);
//	}
//
//	cp = fgets ( line, 255, fp );
//	status = sscanf  ( cp, "%f %f\n", &psfx_info->atten, &psfx_info->attenv );
//	if(status < 2)
//	{
//		std::cout<<"pfx file "<<file_name<<" did not read correctly\n";
//		return(NULL);
//	}
//
//	cp = fgets ( line, 255, fp );
//	status = sscanf  ( cp, "%f %f %f %f %f %f %f %f\n",
//	&psfx_info->sRi,&psfx_info->sGi,&psfx_info->sBi,&psfx_info->sAi,&psfx_info->sRiv,&psfx_info->sGiv,&psfx_info->sBiv,&psfx_info->sAiv );
//	if(status < 8)
//	{
//		std::cout<<"pfx file "<<file_name<<" did not read correctly\n";
//		return(NULL);
//	}
//
//	cp = fgets ( line, 255, fp );
//	status = sscanf  ( cp, "%f %f %f %f %f %f %f %f\n",
//	&psfx_info->sRo,&psfx_info->sGo,&psfx_info->sBo,&psfx_info->sAo,&psfx_info->sRov,&psfx_info->sGov,&psfx_info->sBov,&psfx_info->sAov );
//	if(status < 8)
//	{
//		std::cout<<"pfx file "<<file_name<<" did not read correctly\n";
//		return(NULL);
//	}
//
//	cp = fgets ( line, 255, fp );
//	status = sscanf  ( cp, "%f %f %f %f %f %f %f %f\n",
//	&psfx_info->eRi,&psfx_info->eGi,&psfx_info->eBi,&psfx_info->eAi,&psfx_info->eRiv,&psfx_info->eGiv,&psfx_info->eBiv,&psfx_info->eAiv );
//	if(status < 8)
//	{
//		std::cout<<"pfx file "<<file_name<<" did not read correctly\n";
//		return(NULL);
//	}
//
//	cp = fgets ( line, 255, fp );
//	status = sscanf  ( cp, "%f %f %f %f %f %f %f %f\n",
//	&psfx_info->eRo,&psfx_info->eGo,&psfx_info->eBo,&psfx_info->eAo,&psfx_info->eRov,&psfx_info->eGov,&psfx_info->eBov,&psfx_info->eAov );
//	if(status < 8)
//	{
//		std::cout<<"pfx file "<<file_name<<" did not read correctly\n";
//		return(NULL);
//	}
//
//	cp = fgets ( line, 255, fp );
//	status = sscanf  ( cp, "%f %f\n", &psfx_info->colour_warp, &psfx_info->alpha_warp );
//	if(status < 2)
//	{
//		std::cout<<"pfx file "<<file_name<<" did not read correctly\n";
//		return(NULL);
//	}
//
//	cp = fgets ( line, 255, fp );
//	status = sscanf  ( cp, "%f %f\n", &psfx_info->dur, &psfx_info->durv );
//	if(status < 2)
//	{
//		std::cout<<"pfx file "<<file_name<<" did not read correctly\n";
//		return(NULL);
//	}
//
//	fclose (fp);
//	#if PRINT_THE_PFX
//	printf ( "Read psfx ->\n" );
//	/*{{{  trace the psfx*/
//	printf ( "psfx_info->tex = 0x%x\n",
//	psfx_info->tex );
//	printf ( "identifier = 0x%x ",
//	psfx_info->identifier );
//	printf ( "maximum_issue = %d ",
//	psfx_info->maximum_issue );
//	printf ( "release_period = %f\n",
//	psfx_info->release_period );
//	printf ( "rate = %f ",
//	psfx_info->rate );
//	printf ( "px = %f ",
//	psfx_info->px );
//	printf ( "py = %f ",
//	psfx_info->py );
//	printf ( "pz = %f ",
//	psfx_info->pz );
//	printf ( "pv = %f\n",
//	psfx_info->pv );
//	printf ( "velx = %f ",
//	psfx_info->velx );
//	printf ( "vely = %f ",
//	psfx_info->vely );
//	printf ( "velz = %f\n",
//	psfx_info->velz );
//	printf ( "velxv = %f ",
//	psfx_info->velxv );
//	printf ( "velyv = %f ",
//	psfx_info->velyv );
//	printf ( "velzv = %f\n",
//	psfx_info->velzv );
//	printf ( "rad = %f ",
//	psfx_info->rad );
//	printf ( "radv = %f\n",
//	psfx_info->radv );
//	printf ( "exp = %f ",
//	psfx_info->exp );
//	printf ( "expv = %f ",
//	psfx_info->expv );
//	printf ( "dexp = %f ",
//	psfx_info->dexp );
//	printf ( "dexpv = %f\n",
//	psfx_info->dexpv );
//	printf ( "accelx = %f ",
//	psfx_info->accelx );
//	printf ( "accely = %f ",
//	psfx_info->accely );
//	printf ( "accelz = %f ",
//	psfx_info->accelz );
//	printf ( "accelxv = %f ",
//	psfx_info->accelxv );
//	printf ( "accelyv = %f ",
//	psfx_info->accelyv );
//	printf ( "accelzv = %f\n",
//	psfx_info->accelzv );
//	printf ( "atten = %f ",
//	psfx_info->atten );
//	printf ( "attenv = %f\n",
//	psfx_info->attenv );
//	printf ( "sRi = %f ",
//	psfx_info->sRi );
//	printf ( "sGi = %f ",
//	psfx_info->sGi );
//	printf ( "sBi = %f ",
//	psfx_info->sBi );
//	printf ( "sAi = %f\n",
//	psfx_info->sAi );
//	printf ( "sRiv = %f ",
//	psfx_info->sRiv );
//	printf ( "sGiv = %f ",
//	psfx_info->sGiv );
//	printf ( "sBiv = %f ",
//	psfx_info->sBiv );
//	printf ( "sAiv = %f\n",
//	psfx_info->sAiv );
//	printf ( "sRo = %f ",
//	psfx_info->sRo );
//	printf ( "sGo = %f ",
//	psfx_info->sGo );
//	printf ( "sBo = %f ",
//	psfx_info->sBo );
//	printf ( "sAo = %f\n",
//	psfx_info->sAo );
//	printf ( "sRov = %f ",
//	psfx_info->sRov );
//	printf ( "sGov = %f ",
//	psfx_info->sGov );
//	printf ( "sBov = %f ",
//	psfx_info->sBov );
//	printf ( "sAov = %f\n",
//	psfx_info->sAov );
//	printf ( "eRi = %f ",
//	psfx_info->eRi );
//	printf ( "eGi = %f ",
//	psfx_info->eGi );
//	printf ( "eBi = %f ",
//	psfx_info->eBi );
//	printf ( "eAi = %f\n",
//	psfx_info->eAi );
//	printf ( "eRiv = %f ",
//	psfx_info->eRiv );
//	printf ( "eGiv = %f ",
//	psfx_info->eGiv );
//	printf ( "eBiv = %f ",
//	psfx_info->eBiv );
//	printf ( "eAiv = %f\n",
//	psfx_info->eAiv );
//	printf ( "eRo = %f ",
//	psfx_info->eRo );
//	printf ( "eGo = %f ",
//	psfx_info->eGo );
//	printf ( "eBo = %f ",
//	psfx_info->eBo );
//	printf ( "eAo = %f\n",
//	psfx_info->eAo );
//	printf ( "eRov = %f ",
//	psfx_info->eRov );
//	printf ( "eGov = %f ",
//	psfx_info->eGov );
//	printf ( "eBov = %f ",
//	psfx_info->eBov );
//	printf ( "eAov = %f\n",
//	psfx_info->eAov );
//	printf ( "colour_warp = %f ",
//	psfx_info->colour_warp );
//	printf ( "alpha_warp = %f ",
//	psfx_info->alpha_warp );
//	printf ( "dur = %f ",
//	psfx_info->dur );
//	printf ( "durv = %f\n",
//	psfx_info->durv );
//   #endif
	return(psfx_info);
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// New INI file handler
// routine to read in an environment from a notation file and setup lights,
// spfx and such...
//
void
	DPLRenderer::DPLReadINIPage(
		NotationFile		*master_notation_file,
		const char			*starting_page_name,
		Mission 				*mission,
		Logical				debug_printing)
{
//STUBBED: DPL RB 1/14/07
	float
		red,
		green,
		blue,
		x_rotate,
		y_rotate,
		z_rotate;
	NameList
		*cache_namelist,
		*light_namelist,
		*psfx_namelist,
		*specialfx_namelist,
		*include_pages,
		*path_pages;
	NameList::Entry
		*entry;
	const char
		*next_include_page_name,
		*TempStringPtr,
		*compare_source;

	if (debug_printing)
		std::cout<<"DPLReadINIPage processing "<<starting_page_name<<"\n";
	//
	//---------------------------------------------------
	// Process all the DPL gunk found on this page first
	//---------------------------------------------------
   //
	if ((path_pages = master_notation_file->MakeEntryList(starting_page_name, "objectpath")) != NULL)
	{
		Register_Object(path_pages);
		//
		// Recursively process all the include pages
		//
		for(	entry = path_pages->GetFirstEntry();
				entry;
				entry = entry->GetNextEntry())
		{
//			dpl_AddToObjectFilePath((char *)entry->dataReference, dpl_path_user);
			if (debug_printing)
			{
//				DEBUG_STREAM << "objectpath '" << dpl_GetObjectFilePath() << "'" << std::endl << std::flush;
			}
		}
		Unregister_Object(path_pages);
		delete path_pages;
	}
	if ((path_pages = master_notation_file->MakeEntryList(starting_page_name, "texmappath")) != NULL)
	{
		Register_Object(path_pages);
		//
		// Recursively process all the include pages
		//
		for(	entry = path_pages->GetFirstEntry();
				entry;
				entry = entry->GetNextEntry())
		{
//			dpl_AddToTexmapFilePath((char *)entry->dataReference, dpl_path_user);
			if (debug_printing)
			{
//				DEBUG_STREAM << "texmappath '" << dpl_GetTexmapFilePath() << "'" << std::endl << std::flush;
			}
		}
		Unregister_Object(path_pages);
		delete path_pages;
	}
	if ((path_pages = master_notation_file->MakeEntryList(starting_page_name, "materialpath")) != NULL)
	{
		Register_Object(path_pages);
		//
		// Recursively process all the include pages
		//
		for(	entry = path_pages->GetFirstEntry();
				entry;
				entry = entry->GetNextEntry())
		{
//			dpl_AddToMaterialFilePath((char *)entry->dataReference, dpl_path_user);
			if (debug_printing)
			{
//				DEBUG_STREAM << "materialpath '" << dpl_GetMaterialFilePath() << "'" << std::endl << std::flush;
			}
		}
		Unregister_Object(path_pages);
		delete path_pages;
	}

	if (master_notation_file->GetEntry(starting_page_name, "priorityobjectpath", &TempStringPtr))
	{
//		dpl_AddToObjectFilePath((char *)TempStringPtr, dpl_path_system);
		if (debug_printing)
			{ DEBUG_STREAM << "priorityobjectpath '" << TempStringPtr << "'" << std::endl << std::flush; }
	}
	if (master_notation_file->GetEntry(starting_page_name, "prioritytexmappath", &TempStringPtr))
	{
//		dpl_AddToTexmapFilePath((char *)TempStringPtr, dpl_path_system);
		if (debug_printing)
			{ DEBUG_STREAM << "prioritytexmappath '" << TempStringPtr << "'" << std::endl << std::flush; }
	}
	if (master_notation_file->GetEntry(starting_page_name, "prioritymaterialpath", &TempStringPtr))
	{
//		dpl_AddToMaterialFilePath((char *)TempStringPtr, dpl_path_system);
		if (debug_printing)
			{ DEBUG_STREAM << "prioritymaterialpath '" << TempStringPtr << "'" << std::endl << std::flush; }
	}
	//
	// Get a the list of dpl objects that should be loaded into cache and load them
	//
	if ((cache_namelist = master_notation_file->MakeEntryList(starting_page_name, "cache")) != NULL)
	{
		d3d_OBJECT *d3d_a_object;
		Register_Object(cache_namelist);
		for(entry = cache_namelist->GetFirstEntry(); entry; entry = entry->GetNextEntry())
		{
			d3d_a_object = d3d_OBJECT::LoadObject(mDevice, (char *)entry->dataReference);
			if(!d3d_a_object)
				DEBUG_STREAM<<"Unable to cache "<<(char *)entry->dataReference<<"\n" << std::flush;
			else
			{
				if(debug_printing)
					std::cout<<"Caching "<<(char *)entry->dataReference<<"\n";
			}
		}
		Unregister_Object(cache_namelist);
		delete cache_namelist;
	}
	//
	// Get the clip range
	//
	if(master_notation_file->GetEntry(starting_page_name,	"clip"	,&TempStringPtr))
	{
		sscanf(TempStringPtr, "%f %f", &clipNear, &clipFar);
		if(debug_printing)
			std::cout<<"Clip Range "<<TempStringPtr<<"\n";
	}


	//
	// Background color
	//
	if(master_notation_file->GetEntry(starting_page_name,	"backgnd"	,&TempStringPtr))
	{
		sscanf(TempStringPtr, "%f %f %f", &backgroundRed, &backgroundGreen, &backgroundBlue);
		if(debug_printing)
			std::cout<<"Background Color "<<TempStringPtr<<"\n";
	}
	//
	// Get the projection, pipe and other view related junk
	//
	if(master_notation_file->GetEntry(starting_page_name,	"viewangle"	,&TempStringPtr))
	{
		sscanf(TempStringPtr, "%f", &viewAngle);
		if(debug_printing)
			std::cout<<"View Angle "<<TempStringPtr<<"\n";
	}
	//
	// now that we have the viewing angle, screen size, and clip ranges, setup the projection matrix
	//
	D3DXMatrixIdentity(&mProjectionMatrix);
	D3DXMatrixPerspectiveFovLH(&mProjectionMatrix, viewAngle * (PI/180.0f), (float)x_size / (float)y_size, clipNear, clipFar);	
	mProjectionMatrix(0, 0) *= -1;

	mDecalEpsilon = 0.0000005f;
	mDecalProjectionMatrix = mProjectionMatrix;
	mDecalProjectionMatrix._33 -= mDecalEpsilon;


	//
	// setup the fog
	//
	if(master_notation_file->GetEntry(starting_page_name,	"fog"	,&TempStringPtr))
	{
		sscanf(TempStringPtr, "%f %f %f %f %f", &fogNear, &fogFar, &fogRed, &fogGreen, &fogBlue);
		searchLightFogRed = fogRed;
		searchLightFogGreen = fogGreen;
		searchLightFogBlue = fogBlue;
		searchLightFogNear = fogNear;
		searchLightFogFar = fogFar;
		noSearchLightFogRed = fogRed;
		noSearchLightFogGreen = fogGreen;
		noSearchLightFogBlue = fogBlue;
		noSearchLightFogNear = fogNear;
		noSearchLightFogFar = fogFar;
		currentFogNear = fogNear;
		currentFogFar = fogFar;
		// Force a 0-0 black fog on startup
//		dpl_SetViewFog(dplMainView, dpl_fog_type_pixel_lin, 0.0, 0.0, 0.0, 0.01, 0.05);
		//TODO: for fog testing, just set the values here
		mDevice->SetRenderState(D3DRS_FOGENABLE, TRUE);
		mDevice->SetRenderState(D3DRS_FOGCOLOR, D3DCOLOR_XRGB((int)(255 * fogRed), (int)(255 * fogGreen), (int)(255 * fogBlue)));
		mDevice->SetRenderState(D3DRS_FOGTABLEMODE, D3DFOG_LINEAR);

		if(debug_printing)
			std::cout<<"Fog "<<TempStringPtr<<"\n";
	}
	//
	// setup the no searchlight fog if any
	//
	if(master_notation_file->GetEntry(starting_page_name,	"nosearchlightfog"	,&TempStringPtr))
	{
		sscanf(TempStringPtr, "%f %f %f %f %f", &noSearchLightFogNear, &noSearchLightFogFar, &noSearchLightFogRed, &noSearchLightFogGreen, &noSearchLightFogBlue);
		if(debug_printing)
			std::cout<<"nosearchlightfog "<<TempStringPtr<<"\n";
	}
	//
	// setup the ambient light
	//
	if(master_notation_file->GetEntry(starting_page_name,	"ambient"	,&TempStringPtr))
	{
		sscanf(TempStringPtr, "%f %f %f ", &red, &green, &blue);
		mDevice->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB((int)(255 * red), (int)(255 * green), (int)(255 * blue)));
		if(debug_printing)
			std::cout<<"Ambient Light "<<TempStringPtr<<"\n";
	}

	//
	// Set up the day/night cloud color
	//
	if (master_notation_file->GetEntry(starting_page_name, "clouds", &TempStringPtr))
	{
		sscanf(TempStringPtr, "%f %f %f ", &this->mCloudRed, &this->mCloudGreen, &this->mCloudBlue);
	}

	if (master_notation_file->GetEntry(starting_page_name, "cloudemit", &TempStringPtr))
	{
		sscanf(TempStringPtr, "%f %f %f ", &this->mCloudEmitRed, &this->mCloudEmitGreen, &this->mCloudEmitBlue);
	}

	//
	// Get a the list of lights from this page
	//
	if ((light_namelist = master_notation_file->MakeEntryList(starting_page_name, "light")) != NULL)
	{
		Register_Object(light_namelist);
		//
		// HACK !!! All the lights must (temporarily) be defined on a single page.
		// The lights and their DCS's should really be stored in a light object on
		// a chain, or as an actual entity in the simulation.  This line will throw
		// an exception if this rule is violated
		//
		if(light_namelist->EntryCount() != 0)
		{
			if(sceneLightCount != 0)
			{
				Fail("All lights must be defined on a single INI file page!\n");
			}
			//
			// Create storage space for the dpl_LIGHT and dpl_DCS structures
			//
			sceneLightCount	= light_namelist->EntryCount();
			if (sceneLightCount)
			{
				sceneLight = new D3DLIGHT9[sceneLightCount];
				memset(sceneLight, 0, sizeof(D3DLIGHT9) * sceneLightCount);
			}
			
			int current_entry = 0;
			for(entry = light_namelist->GetFirstEntry(); entry; entry = entry->GetNextEntry(), ++current_entry)
			{
				//
				// Read the parameters for the light
				//
				sscanf(
					(char *)entry->dataReference,
					"%f %f %f %f %f %f",
					&red,
					&green,
					&blue,
					&x_rotate,
					&y_rotate,
					&z_rotate);
				if(debug_printing)
					std::cout<<"Light "<<(char *)entry->dataReference<<"\n";
				//
				// Create and rotate a dcs to hold the light, and the light itself
				//
				sceneLight[current_entry].Type = D3DLIGHT_DIRECTIONAL;
				sceneLight[current_entry].Diffuse.r = red;
				sceneLight[current_entry].Diffuse.g = green;
				sceneLight[current_entry].Diffuse.b = blue;
				sceneLight[current_entry].Diffuse.a = 1.0f;
				
				D3DXMATRIX rot, rotX, rotY, rotZ;
				D3DXMatrixRotationX(&rotX, x_rotate * (PI/180.0f));
				D3DXMatrixRotationY(&rotY, y_rotate * (PI/180.0f));
				D3DXMatrixRotationZ(&rotZ, z_rotate * (PI/180.0f));
				rot = rotZ * rotX * rotY;

				D3DXVECTOR3 dir(0, 0, -1);
				D3DXVECTOR4 vec;
				D3DXVec3Transform(&vec, &dir, &rot);
				dir = D3DXVECTOR3(vec.x, vec.y, vec.z);
				D3DXVec3Normalize(&dir, &dir);
				sceneLight[current_entry].Direction.x = dir.x;
				sceneLight[current_entry].Direction.y = dir.y;
				sceneLight[current_entry].Direction.z = dir.z;

				mDevice->SetLight(current_entry, &sceneLight[current_entry]);
				mDevice->LightEnable(current_entry, TRUE);

//				sceneLight[current_entry]		=	dpl_NewLight();
//				sceneLightDCS[current_entry]	=	dpl_NewDCS();

//				dpl_AddDCSToScene	( sceneLightDCS[current_entry] );
//				dpl_SetLightType  ( sceneLight[current_entry],	dpl_light_type_directional );
//				dpl_SetLightColor ( sceneLight[current_entry],	red, green, blue);
//				dpl_SetLightDCS 	( sceneLight[current_entry],	sceneLightDCS[current_entry] );
//				dpl_RotateDCS   	( sceneLightDCS[current_entry],	z_rotate, dpl_Z );
//				dpl_RotateDCS   	( sceneLightDCS[current_entry],	x_rotate, dpl_X );
//				dpl_RotateDCS   	( sceneLightDCS[current_entry],	y_rotate, dpl_Y );
//				dpl_FlushLight		( sceneLight[current_entry] );
//				dpl_FlushDCS		( sceneLightDCS[current_entry] );
			}
		}
		//
		// Get rid of the light entry list
		//
		Unregister_Object(light_namelist);
		delete light_namelist;
	}
	////
	//// Get a the list of PSFX effects we should load into RAM
	////
	//if ((psfx_namelist = master_notation_file->MakeEntryList(starting_page_name, "psfx")) != NULL)
	//{
	//	const char *psfx_file_name;
	//	int psfx_number;
	//	//
	//	// create all the PSFX on the current page
	//	//
	//	for(	entry = psfx_namelist->GetFirstEntry();
	//			entry;
	//			entry = entry->GetNextEntry())
	//	{
	//		psfx_number		=	atoi(entry->GetName()+4);
	//		psfx_file_name	=	entry->GetChar();
	//		if(debug_printing)
	//			std::cout<<"psfx"<<psfx_number<<" "<<psfx_file_name<<"\n";
	//		if(psfx_number < 0 || psfx_number > MAX_PSFX_COUNT-1)
	//		{
	//			Fail("PSFX id number was not in the allowed range");
	//		}
	//		//
	//		// See if we are overwriting an existing psfx
	//		//
	//		if(myPSFXDescriptons[psfx_number])
	//		{
	//			std::cout<<"psfx#"<<psfx_number<<" already existed from an earlier page, redefining it\n";
	//			delete myPSFXDescriptons[psfx_number];
	//			Unregister_Pointer(myPSFXDescriptons[psfx_number]);
	//		}
	////		DEBUG_STREAM<<"Loading PSFX# "<<psfx_number<<" from file "<<psfx_file_name<<"\n" << std::flush;
	//		myPSFXDescriptons[psfx_number]	=	ReadPSFX(psfx_file_name);
	//		Register_Pointer(myPSFXDescriptons[psfx_number]);
	//	}
	//	//
	//	// Get rid of the PSFX entry list
	//	//
	//	delete psfx_namelist;
	//}
	//
	// Get a the list of special effects
	//
	if ((specialfx_namelist = master_notation_file->MakeEntryList(starting_page_name, "effect")) != NULL)
	{
		const char *effect_page_name;
		int status, spfx_number, version;
		INDIE_EFFECT spfx;
		memset(&spfx, 0, sizeof(PARTICLE_EFFECT));

		Register_Object(specialfx_namelist);
		//
		// create all the effects on the current page
		//
		for(	entry = specialfx_namelist->GetFirstEntry();
				entry;
				entry = entry->GetNextEntry())
		{
			//
			// Get the page with this effect on it
			//
			effect_page_name = entry->GetChar();
			if(debug_printing)
				std::cout<<"specialfx"<<spfx_number<<" "<<effect_page_name<<"\n";
			
			master_notation_file->GetEntry(effect_page_name, "id", &spfx_number);

			version = 1;
			master_notation_file->GetEntry(effect_page_name, "version", &version);
			if (version < 2)
				continue;

			master_notation_file->GetEntry(effect_page_name, "texbounds", &TempStringPtr);
			sscanf(TempStringPtr, "%f %f %f %f", &spfx.textureBounds.left, &spfx.textureBounds.top, &spfx.textureBounds.right, &spfx.textureBounds.bottom);

			master_notation_file->GetEntry(effect_page_name, "rotate", (int*)&spfx.rotate);
			master_notation_file->GetEntry(effect_page_name, "size", &spfx.fragSize);
			master_notation_file->GetEntry(effect_page_name, "velocity", &spfx.velocity);
			master_notation_file->GetEntry(effect_page_name, "varianceX", &spfx.varianceX);
			master_notation_file->GetEntry(effect_page_name, "varianceY", &spfx.varianceY);
			master_notation_file->GetEntry(effect_page_name, "varianceZ", &spfx.varianceZ);
			master_notation_file->GetEntry(effect_page_name, "gravity", &spfx.gravity);
			master_notation_file->GetEntry(effect_page_name, "count", &spfx.fragCount);
			master_notation_file->GetEntry(effect_page_name, "life", &spfx.fragLifetime);
			if (!master_notation_file->GetEntry(effect_page_name, "max_repeat", &spfx.maxRepeat))
				spfx.maxRepeat = 30.0;
			NameList *color_list = master_notation_file->MakeEntryList(effect_page_name, "color");
			int i = 0;
			for (NameList::Entry *color_entry = color_list->GetFirstEntry(); color_entry; color_entry = color_entry->GetNextEntry())
			{
				memset(&spfx.colors[i], 0, sizeof(COLOR_POINT));
				spfx.colors[i].active = true;

				int a, r, g, b;
				sscanf(color_entry->GetChar(), "%f %d %d %d %d", &spfx.colors[i].time, &a, &r, &g, &b);

				spfx.colors[i].color.argb = D3DCOLOR_ARGB(a, r, g, b);
				i++;
			}

			for (;i < COLOR_POINT_COUNT; i++)
			{
				memset(&spfx.colors[i], 0, sizeof(COLOR_POINT));
			}

			//
			// install the effect
			//
			int isIndie = 0;
			master_notation_file->GetEntry(effect_page_name, "independent", &isIndie);
			if (isIndie)
			{
				master_notation_file->GetEntry(effect_page_name, "maxIssue", &spfx.maxIssue);
				master_notation_file->GetEntry(effect_page_name, "releasePeriod", &spfx.releasePeriod);
				master_notation_file->GetEntry(effect_page_name, "duration", &spfx.duration);

				spfx.id = 1000 + spfx_number;
				myPSFXDescriptons[spfx_number] = spfx;
			}
			else
				ParticleEngine::InstallEffect(spfx_number, *((PARTICLE_EFFECT*)&spfx));
		}
		//
		// Get rid of the effect entry list
		//
		Unregister_Object(specialfx_namelist);
		delete specialfx_namelist;
	}
	//--------------------------------------------------
	// Make a list of all the include pages on this page
	//--------------------------------------------------
	if ((include_pages = master_notation_file->MakeEntryList(starting_page_name, "include")) != NULL)
	{
		Register_Object(include_pages);
		//
		// Recursively process all the include pages
		//
		for(	entry = include_pages->GetFirstEntry();
				entry;
				entry = entry->GetNextEntry())
		{
			// Get the name of the next include page
			next_include_page_name = (char *)entry->dataReference;
			// Process the next page recursively through this routine
			DPLReadINIPage(
				master_notation_file,
				next_include_page_name,
				mission,
				debug_printing);
			if(debug_printing)
				std::cout<<"DPLReadINIPage returned to "<<starting_page_name<<"\n";
		}
		Unregister_Object(include_pages);
		delete include_pages;
	}
	//
	// Process a compare and branch if there is one on this page
	//
	if(master_notation_file->GetEntry(starting_page_name,	"compare"	,&compare_source))
	{
		Logical
			match;
		NameList
			*branch_pages;
		CString
			compare_strings[10],
			wild_card("*"),
			token_string,
         target_string,
			master_compare_string(compare_source);
		int
			token_count;
		ResourceFile
			*this_resource_file;
		//
		// Get a pointer to our resource file so we can find the name of the map
		// resource later in this process.
		//
		Check(application);
		this_resource_file	=	application->GetResourceFile();
		Check(this_resource_file);
		//
		// Print the compare string
		//
		if(debug_printing)
			std::cout<<"compare = "<<master_compare_string<<"\n";
		//
		// Break the compare string apart, fetch the mission variables for each
		// item in it and store them in the compare_strings array for later.
		//
		token_count = 0;
		while(target_string = master_compare_string.GetNthToken(token_count,","))
		{
//			std::cout<<"Mission variable "<<token_count<<": ";
			if(strcmp(target_string,"location") == 0)
			{
				compare_strings[token_count]	= (this_resource_file->FindResourceDescription(mission->GetMapID()))->resourceName;
//				std::cout<<target_string<<" = "<<compare_strings[token_count]<<"\n";
			}
			else if(strcmp(target_string,"time") == 0)
			{
				compare_strings[token_count]	= mission->GetMissionTime();
//				std::cout<<target_string<<" = "<<compare_strings[token_count]<<"\n";
			}
			else if(strcmp(target_string,"weather") == 0)
			{
				compare_strings[token_count]	= mission->GetMissionWeather();
//				std::cout<<target_string<<" = "<<compare_strings[token_count]<<"\n";
			}
			else if(strcmp(target_string,"scenario") == 0)
			{
				compare_strings[token_count]	= mission->GetScenarioName();
//				std::cout<<target_string<<" = "<<compare_strings[token_count]<<"\n";
			}
			else
			{
				std::cout<<"Mission variable "<<token_count<<": "<<target_string<<" IS AN UNKNOWN MISSION VARIABLE\n";
			}
			token_count++;
		}
		//
		// Print the version of the compare string with the actual mission variables
		// in it
		//
		int i;
		if(debug_printing)
		{
			std::cout<<"comparing to: ";
			for(i = 0; i<token_count; i++)
			{
				std::cout<<compare_strings[i]<<", ";
			}
			std::cout<<"\n";
		}
		//
		// Now compare all the branch pages till we have done them all or found a match
		//
		branch_pages = master_notation_file->MakeEntryList(starting_page_name,"branch");
		Register_Object(branch_pages);
		for(	entry = branch_pages->GetFirstEntry();
				entry;
				entry = entry->GetNextEntry())
		{
			CString
				branch_command,
				match_string;
			int
				compare_token;
			//
			// Get the text of the branch command and print it
			//
			branch_command = (char *)entry->dataReference;
			if(debug_printing)
				std::cout<<"branch = "<<branch_command<<"\n";
			//
			// Grab each token out of the branch string and compare it to the
			// corrisponding item in compare_strings.  This also checks for the
			// wildcard cararcter.  Any failure to match skips this branch string.
			//
			match = True;
			for(compare_token = 0; compare_token<token_count; compare_token++)
			{
				match_string = branch_command.GetNthToken(compare_token,",");
				if(match_string != compare_strings[compare_token] && match_string != wild_card)
				{
					match = False;
//					std::cout<<match_string<<"!="<<compare_strings[compare_token]<<"\n";
					break;
				}
				else
				{
//					std::cout<<match_string<<"=="<<compare_strings[compare_token]<<"\n";
				}
			}
			//
			// See if we had a successful match
			//
			if(match)
			{
				// Match! Get the name of the page to branch to and do it.
				match_string = branch_command.GetNthToken(compare_token,",");
				DPLReadINIPage(
					master_notation_file,
					match_string,
					mission,
					debug_printing);
				if(debug_printing)
					std::cout<<"DPLReadINIPage returned to "<<starting_page_name<<"\n";
				// now break out of the loop because we only allow one page to match
				break;
			}
		}
		Unregister_Object(branch_pages);
		delete branch_pages;

		//
		// If we found no match, yell about it
		//
		if(!match)
		{
			DEBUG_STREAM << "BRANCH ERROR IN '" <<
				master_notation_file->GetFileName() <<
				"' NO MATCH FOUND!!" <<	std::endl;
		}
	}
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Read environment
// routine to read in an environment from a notation file and setup lights,
// spfx and such...
//
void
	DPLRenderer::DPLReadEnvironment(Mission 				*mission)
{
//STUBBED: DPL RB 1/14/07
	char *L4DPLcfg;
//	const char
//		*cc;

	NotationFile *renderer_environment;

	Logical debug_printing;
	//
	// Get the name of the notation file from an environmental
	//
	L4DPLcfg = getenv("L4DPLCFG");
	if (!L4DPLcfg)
	{
		DEBUG_STREAM<<"L4DPLCFG not defined, using dpldflt.ini!\n" << std::flush;
		L4DPLcfg = "dpldflt.ini";
	}
	//
	// Read the environment out of a notation file
	//
	renderer_environment = new NotationFile(L4DPLcfg);
	Register_Object(renderer_environment);
	if (renderer_environment->PageCount() == 0)
	{
		DEBUG_STREAM<<"Renderer config notation file "<<L4DPLcfg<<"was empty, can't continue\n" << std::flush;
		Verify(renderer_environment->PageCount() == 0);
	}
	//
	// Register the notation file and check it
	//
	Check(renderer_environment);
	if (renderer_environment->PageExists("main"))
	{
		if (!(renderer_environment->GetLogicalEntry("main", "debug", &debug_printing)))
		{
			debug_printing=False;
		}
		DPLReadINIPage(renderer_environment, "main", mission, debug_printing);
#if 0
		if ((cc = dpl_GetObjectFilePath()) == NULL || *cc == NULL)
		{
			dpl_SetObjectFilePath	( ".\\video", NULL, NULL );
		}
		if ((cc = dpl_GetTexmapFilePath()) == NULL || *cc == NULL)
		{
			dpl_SetTexmapFilePath	( ".\\video", NULL, NULL );
		}
		if ((cc = dpl_GetMaterialFilePath()) == NULL || *cc == NULL)
		{
			dpl_SetMaterialFilePath	( ".\\video", NULL, NULL );
		}
#endif
	}
	else
	{
		if (!(renderer_environment->GetLogicalEntry("dpl_config", "debug", &debug_printing)))
		{
			debug_printing=False;
		}
		std::cout<<"READING OLD FORMAT INI FILE '"<<renderer_environment->GetFileName()<<"'---hope this works\n";
//		dpl_SetObjectFilePath   ( ".\\video", NULL, NULL );
//		dpl_SetTexmapFilePath   ( ".\\video", NULL, NULL );
//		dpl_SetMaterialFilePath ( ".\\video", NULL, NULL );
		DPLReadINIPage(renderer_environment, "dpl_config", mission, debug_printing);
	}
	if (debug_printing)
	{
//		DEBUG_STREAM << "ObjectFilePath   '" << dpl_GetObjectFilePath() << "'" << std::endl << std::flush;
//		DEBUG_STREAM << "TexmapFilePath   '" << dpl_GetTexmapFilePath() << "'" << std::endl << std::flush;
//		DEBUG_STREAM << "MaterialFilePath '" << dpl_GetMaterialFilePath() << "'" << std::endl << std::flush;
	}
	//
	// Close the notation file
	//
	Verify( !renderer_environment->IsDirty() );
	Unregister_Object(renderer_environment);
	delete renderer_environment;
	//
	// Flush all the things we've set/changed here
	//
//	dpl_FlushView(dplMainView);
	return;
}
//
//#############################################################################
// Destructor for the video renderer
//#############################################################################
//
DPLRenderer::~DPLRenderer()
{
	delete gOpNames;
	delete gReplacementData;

	if (mPrimaryIndex != NULL)
	{
		delete mPrimaryIndex;
	}

	if (mSecondaryIndex != NULL)
	{
		delete mSecondaryIndex;
	}

	if (mAux1Index != NULL)
	{
		delete mAux1Index;
	}

	if (mAux2Index != NULL)
	{
		delete mAux2Index;
	}

	SAFE_RELEASE(mDevice);
	SAFE_RELEASE(gD3D);
	//STUBBED: DPL RB 1/14/07
	//int
	//	psfx_number;
	////------------------------------------------------------
	//// release allocated memory used by dump_frame_buffer()
	////------------------------------------------------------
	//dump_frame_buffer(NULL, NULL, NULL, NULL);
	////
	//// Delete any memory allocated to hold psfx effect descriptions
	////
	//for(	psfx_number = 0; psfx_number < MAX_PSFX_COUNT; psfx_number++)
	//{
	//	if(myPSFXDescriptons[psfx_number])
	//	{
	//		delete myPSFXDescriptons[psfx_number];
	//		Unregister_Pointer(myPSFXDescriptons[psfx_number]);
	//		myPSFXDescriptons[psfx_number]	=	NULL;
	//	}
	//}
	////
	////~~~~~~~~~~~~~~~~~~
	//// Delete all Lights
	////~~~~~~~~~~~~~~~~~~
	////
	//if (ambientLight)
	//{
	//	Check_Pointer(ambientLight);
	//	Unregister_Pointer(ambientLight);
	//	dpl_DeleteLight(ambientLight);
	//}
	//if (sceneLightDCS && sceneLight)
	//{
	//	Check_Pointer(sceneLightDCS);
	//	for(int ii=0;ii<sceneLightCount;++ii)
	//	{
	//		Check_Pointer(sceneLight[ii]);
	//		Check_Pointer(sceneLightDCS[ii]);
	//		dpl_RemoveDCSFromScene(sceneLightDCS[ii]);
	//		dpl_DeleteDCS(sceneLightDCS[ii]);
	//		Unregister_Pointer(sceneLight[ii]);
	//		Unregister_Pointer(sceneLightDCS[ii]);
	//	}
	//	Unregister_Pointer(sceneLight);
	//	delete[] sceneLight;
	//	Unregister_Pointer(sceneLightDCS);
	//	delete[] sceneLightDCS;
	//}

	//Unregister_Object(DPLHeap);
	//delete DPLHeap;
 //  DPLHeap = NULL;
}
//
//#############################################################################
// TestInstance
//#############################################################################
//
Logical
	DPLRenderer::TestInstance() const
{
	VideoRenderer::TestInstance();

	Verify(dplMainView != NULL);
	Verify(dplMainZone != NULL);

	return True;
}
//
//#############################################################################
// FlushBitSliceTexture
// Sends the bitslice texture to the division card.
// LoadBitSliceTexture
// Handles building of a bitmap into a texture map for the Division card, this
// specifically deals with merging a 1 bit bitmap into a 4 bit bitslice texmap.
//#############################################################################
//
void
	DPLRenderer::FlushBitSliceTexture(
		unsigned int	*local_storage)
{
	//STUBBED: DPL RB 1/14/07
	//int
	//	status;
	//dpl_TEXTURE *temp_texture =
	//	dpl_LookupTexture("bmap:bmap1_tex", dpl_lookup_normal, &status);
	//if(temp_texture == NULL)
	//{
	//	DEBUG_STREAM<<"WARNING, textures for player names not defined\n" << std::flush;
	//}
	//else
	//{
	//	dpl_TEXMAP *temp_texmap =
	//		dpl_GetTextureTexmap(temp_texture);
	//	if(temp_texmap != NULL)
	//	{
	//		dpl_TexmapTexels2D ( temp_texmap, local_storage,
	//									128,
	//									64,
	//									4 );
	//		dpl_FlushTexmap(temp_texmap);
	//	}
	//	else
	//	{
	//		DEBUG_STREAM<<"WARNING, texmap for player names not defined\n" << std::flush;
	//	}
	//}
}
void DPLRenderer::LoadBitSliceTexture(BitMap *bitmap_to_load, LPDIRECT3DTEXTURE9 local_storage)
{
	// lock the texture and grab a pointer to the data
	D3DLOCKED_RECT lockedRect;
	local_storage->LockRect(0, &lockedRect, NULL, D3DLOCK_DISCARD);

	//
	// Figure out the position to start copying the data at
	//
	Word *word_pointer = bitmap_to_load->Data.MapPointer;
	__int16 *pixel_pointer = (__int16*)lockedRect.pBits;

	//
	// Actually process the texels
	//
	int bit_mask = 0x8000;
	for(int y = 0; y < 32; y++)
	{
		for(int x = 0; x < 128; x++)
		{
			if (*word_pointer & bit_mask)
				*(pixel_pointer++) = 0xFFFF;
			else
				*(pixel_pointer++) = 0x0000;
			bit_mask >>= 1;
			if (bit_mask == 0)
			{
				bit_mask = 0x8000;
				word_pointer++;
			}
		}
	}

	// unlock the texture now that we're done updating it
	local_storage->UnlockRect(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CacheExplosionScripts
// Handles code to preload the morph and other caches with things needed by
// explosion scripts.  Should be called at startup, once for each.
//
void
	DPLRenderer::CacheExplosionScripts(
		int	script_select)						// The script to be cached
{
//STUBBED: DPL RB 1/14/07
//	dpl_OBJECT
//		*object;
//	//
//	// Load the morph targets into the MUNGA object cache
//	//
//	switch(script_select)
//	{
//		case	104:		// Thor death explosion
//		case	106:		// Thor death explosion
//		{
//			dpl_LoadObject("flamebig.bgf", dpl_load_normal);
//			dpl_LoadObject("thrdbr.bgf"	, dpl_load_normal);
//			dpl_LoadObject("ldbr.bgf"		, dpl_load_normal);
//			dpl_LoadObject("flamesml.bgf", dpl_load_normal);
////			DEBUG_STREAM << "explosion "<< script_select<<" cached\n" << std::flush;
//			break;
//		}
//	}
}
//
//#############################################################################
// ExplosionScripts
// Contains several scripts for running various types of explosion effects.
//#############################################################################
//
void
	DPLRenderer::ExplosionScripts(
		Entity					*entity,				// The entity we are dealing with
		ResourceDescription*  ,//model_resource,	// Pointer to the video resource
		ViewFrom					 ,//view_type, 			// Type of reference (inside/outside...etc.)
		int						script_select)
{
//STUBBED: DPL RB 1/14/07
//	dpl_OBJECT
//		*object_1;
//	//
//	// Construct a root renderable to hang the explosion effects on
//	//
//	RootRenderable *this_root =
//		new RootRenderable(
//			entity,							// Entity to attach the renderable to
//			RootRenderable::Dynamic,	// How/when to execute the renderable
//			NULL,								// object to hang on the DCS, may be a list later <NULL>
//			false,					// DPL Zone this stuff will live in (for culling)
//			dpl_isect_mode_obj,			// type of intersections to do on this object
//			NULL);							// intersection mask for the object
//	Register_Object(this_root);
//	//
//	// Select which script to construct
//	//
//	switch(script_select)
//	{
//		case	0:		// Shock wave
//		{
//			//
//			// Load object(s) we will be using for the explosions
//			//
//			object_1		 = dpl_LoadObject("shock.bgf", dpl_load_normal);
//			//
//			// Setup control variables and transforms we need
//			//
//			Vector3D			scaling_velocity_1(3.5, 3.5, 3.5);
//			Vector3D			velocity_accel_1(0.0, 0.0, 0.0);
//			LinearMatrix	explosion_1_offset(True);
//			//
//			// Create the scaling explosion renderables
//			//
//			ScalingExplosionRenderable  *explosion_1 =
//				new ScalingExplosionRenderable(
//					entity,											// Entity to attach the renderable to
//					ScalingExplosionRenderable::Dynamic,	// How/when to execute the renderable
//					object_1,											// This will be the scaling explosion object
//					false,									// DPL Zone this stuff will live in (for culling)
//					dpl_isect_mode_obj,							// type of intersections to do on this object
//					NULL,												// intersection mask for the object
//					this_root->GetDCS(),							// the parent DCS we will be offsetting from
//					&explosion_1_offset,								// offset matrix to be applied prior to joint DCS
//					&scaling_velocity_1,      					// Effect control vector, Y is acceleration, X, Z are velocity
//					&velocity_accel_1,
//					0.0f,
//					NULL);                     				// -.25 gravity is normal
//			Register_Object(explosion_1);
//			//
//			// Create a sweep renderable to drive the material morph
//			//
//			SweepRenderable *sweep_1 =
//				new SweepRenderable(
//					entity,							// Entity to attach the renderable to
//					SweepRenderable::Dynamic,	// How/when to execute the renderable
//					0.5f,								// How long to take to sweep from 0 to 1
//					1,									// number of times to cycle before stopping
//					NULL);
//			Register_Object(sweep_1);
//			//
//			// Lookup a texture that we can use for the morphing materials
//			//
//			int
//				status;
//			dpl_TEXTURE *effect_texture =
//				dpl_LookupTexture ( "btfx:firesmoke1_scr_tex", dpl_lookup_normal, &status );
//			if (effect_texture == NULL)
//				DEBUG_STREAM<<"couldn't find texture btfx:firesmoke1_scr_tex for an effect\n" << std::flush;
//			//
//			// Setup a morph material renderable for each explosion shape
//			//
//			MorphMaterialRenderable *morph_material_1 =
//				new MorphMaterialRenderable(
//					entity,										// Entity to attach the renderable to
//					MorphMaterialRenderable::Dynamic,	// How/when to execute the renderable
//					1.0f,1.0f,1.0f,							// Material's ambient component
//					1.0f,1.0f,1.0f,							// Material's emissive component
//					1.0f,1.0f,1.0f,							// Material's diffuse component
//					0.0f,0.0f,0.0f,0.0,						// Material's specular component
//					4.0f,0.2f,-0.05f,							// Material's opacity
//					effect_texture,							// Material's texture pointer
//					0.0f,											// Material's Z dither value
//					0,												// Material's Fog Imunity value
//					0.5f,0.5f,0.5f,							// Material's ambient component
//					0.5f,0.5f,0.5f,							// Material's emissive component
//					0.5f,0.5f,0.5f,							// Material's diffuse component
//					0.0f,0.0f,0.0f,0.0,						// Material's specular component
////					0.25f,0.25f,-0.05f,						// Material's opacity
//					0.1f,0.1f,-0.05f,						// Material's opacity
//					0.0f,											// Material's Z dither value
//					sweep_1->GetSweepAttribute());
//			Register_Object(morph_material_1);
//			dpl_INSTANCE *explosion_1_instance = dpl_GetDCSInstance(explosion_1->GetDCS(), 1);
//			if(!explosion_1_instance)
//				Fail("explosion_1_instance came back null\n");
//			dpl_SetInstanceFrontMaterial(explosion_1_instance,	morph_material_1->GetMaterial());
//			dpl_FlushInstance(explosion_1_instance);
//			break;
//		}
//		case	1:		// Big explosion
//		{
//			//
//			// Load object(s) we will be using for the explosions
//			//
//			object_1		 = dpl_LoadObject("exp.bgf", dpl_load_normal);
//			//
//			// Setup control variables and transforms we need
//			//
//			Vector3D			scaling_velocity_1(0.15, 0.15, 0.15);
//			Vector3D			scaling_velocity_2(0.18, 0.22, 0.18);
//			Vector3D			velocity_accel_1(0.0, 0.0, 0.0);
//			Vector3D			velocity_accel_2(0.0, 0.0, 0.0);
//			LinearMatrix	explosion_1_offset(True);
//			LinearMatrix	explosion_2_offset(True);
//			Point3D			explosion_2_translate(0.0f, 0.0f, 0.0f);
//			EulerAngles		explosion_2_rotate(0.0f, 1.0f, 0.0f);
//			explosion_2_offset = explosion_2_rotate;
//         explosion_2_offset = explosion_2_translate;
//			//
//			// Create the scaling explosion renderables
//			//
//			ScalingExplosionRenderable  *explosion_1 =
//				new ScalingExplosionRenderable(
//					entity,											// Entity to attach the renderable to
//					ScalingExplosionRenderable::Dynamic,	// How/when to execute the renderable
//					object_1,											// This will be the scaling explosion object
//					false,									// DPL Zone this stuff will live in (for culling)
//					dpl_isect_mode_obj,							// type of intersections to do on this object
//					NULL,												// intersection mask for the object
//					this_root->GetDCS(),							// the parent DCS we will be offsetting from
//					&explosion_1_offset,								// offset matrix to be applied prior to joint DCS
//					&scaling_velocity_1,      					// Effect control vector, Y is acceleration, X, Z are velocity
//					&velocity_accel_1,
//					0.0f,
//					NULL);                     				// -.25 gravity is normal
//			Register_Object(explosion_1);
//			ScalingExplosionRenderable  *explosion_2 =
//				new ScalingExplosionRenderable(
//					entity,											// Entity to attach the renderable to
//					ScalingExplosionRenderable::Dynamic,	// How/when to execute the renderable
//					object_1,											// This will be the scaling explosion object
//					false,									// DPL Zone this stuff will live in (for culling)
//					dpl_isect_mode_obj,							// type of intersections to do on this object
//					NULL,												// intersection mask for the object
//					this_root->GetDCS(),							// the parent DCS we will be offsetting from
//					&explosion_2_offset,								// offset matrix to be applied prior to joint DCS
//					&scaling_velocity_2,      					// Effect control vector, Y is acceleration, X, Z are velocity
//					&velocity_accel_2,
//					0.0f,
//					NULL);
//			Register_Object(explosion_2);
//			//
//			// Create a sweep renderable to drive the material morph
//			//
//			SweepRenderable *sweep_1 =
//				new SweepRenderable(
//					entity,							// Entity to attach the renderable to
//					SweepRenderable::Dynamic,	// How/when to execute the renderable
//					3.0f,
//					1,									// number of times to cycle before stopping
//					NULL);							// How long to take to sweep from 0 to 1
//			Register_Object(sweep_1);
//			SweepRenderable *sweep_2 =
//				new SweepRenderable(
//					entity,							// Entity to attach the renderable to
//					SweepRenderable::Dynamic,	// How/when to execute the renderable
//					2.0f,
//					1,									// number of times to cycle before stopping
//					NULL);							// How long to take to sweep from 0 to 1
//			Register_Object(sweep_2);
//			//
//			// Lookup a texture that we can use for the morphing materials
//			//
//			int
//				status;
//			dpl_TEXTURE *effect_texture =
//				dpl_LookupTexture ( "btfx:firesmoke1_scr_tex", dpl_lookup_normal, &status );
//			if (effect_texture == NULL)
//				DEBUG_STREAM<<"couldn't find texture btfx:firesmoke1_scr_tex for an effect\n" << std::flush;
//			//
//			// Setup a morph material renderable for each explosion shape
//			//
//			#if 0
//					0.9f,0.0f,0.0f,							// Material's ambient component
//					1.0f,1.0f,0.0f,							// Material's emissive component
//					1.0f,0.7f,0.2f,							// Material's diffuse component
//					0.0f,0.0f,0.0f,0.0,						// Material's specular component
//					8.0f,0.2f,-0.05f,							// Material's opacity
//			#endif
//			MorphMaterialRenderable *morph_material_1 =
//				new MorphMaterialRenderable(
//					entity,										// Entity to attach the renderable to
//					MorphMaterialRenderable::Dynamic,	// How/when to execute the renderable
//					0.9f,0.0f,0.0f,							// Material's ambient component
//					1.0f,0.2f,0.0f,							// Material's emissive component
//					1.0f,0.2f,0.0f,							// Material's diffuse component
//					0.0f,0.0f,0.0f,0.0,						// Material's specular component
//					10.0f,0.6f,-0.05f,							// Material's opacity
//					effect_texture,							// Material's texture pointer
//					0.0f,											// Material's Z dither value
//					0,												// Material's Fog Imunity value
//					0.3f,0.0f,0.0f,							// Material's ambient component
//					0.5f,0.0f,0.0f,							// Material's emissive component
//					0.2f,0.0f,0.0f,							// Material's diffuse component
//					0.0f,0.0f,0.0f,0.0,						// Material's specular component
//					0.25f,0.25f,-0.05f,							// Material's opacity
//					15.0f,											// Material's Z dither value
//					sweep_1->GetSweepAttribute());
//			Register_Object(morph_material_1);
//			MorphMaterialRenderable *morph_material_2 =
//				new MorphMaterialRenderable(
//					entity,										// Entity to attach the renderable to
//					MorphMaterialRenderable::Dynamic,	// How/when to execute the renderable
//					0.9f,0.0f,0.0f,							// Material's ambient component
//					1.0f,0.6f,0.3f,							// Material's emissive component
//					1.0f,0.4f,0.2f,							// Material's diffuse component
//					0.0f,0.0f,0.0f,0.0,						// Material's specular component
//					8.0f,0.2f,-0.05f,							// Material's opacity
//					effect_texture,							// Material's texture pointer
//					0.0f,											// Material's Z dither value
//					0,												// Material's Fog Imunity value
//					0.1f,0.0f,0.0f,							// Material's ambient component
//					0.0f,0.0f,0.0f,							// Material's emissive component
//					0.1f,0.0f,0.0f,							// Material's diffuse component
//					0.0f,0.0f,0.0f,0.0,						// Material's specular component
//					0.25f,0.25f,-0.05f,						// Material's opacity
//					15.0f,											// Material's Z dither value
//					sweep_2->GetSweepAttribute());
//			Register_Object(morph_material_2);
//			//
//			// Override the materials in the two explosion shapes using these morph materials
//			//
//			dpl_INSTANCE *explosion_1_instance = dpl_GetDCSInstance(explosion_1->GetDCS(), 1);
//			dpl_INSTANCE *explosion_2_instance = dpl_GetDCSInstance(explosion_2->GetDCS(), 1);
//
//			if(!explosion_1_instance)
//				Fail("explosion_1_instance came back null\n");
//			if(!explosion_2_instance)
//				Fail("explosion_2_instance came back null\n");
//
//			dpl_SetInstanceFrontMaterial(explosion_1_instance,	morph_material_1->GetMaterial());
//			dpl_SetInstanceFrontMaterial(explosion_2_instance,	morph_material_2->GetMaterial());
//
//			dpl_FlushInstance(explosion_1_instance);
//			dpl_FlushInstance(explosion_2_instance);
//			break;
//		}
//		case	2:		// Big explosion
//		{
//			//
//			// Load object(s) we will be using for the explosions
//			//
//			object_1		 = dpl_LoadObject("exp.bgf", dpl_load_normal);
//			//
//			// Setup control variables and transforms we need
//			//
//			Vector3D			scaling_velocity_1(1.0, 0.2, 1.0);
//			Vector3D			scaling_velocity_2(0.75, 0.75, 0.75);
//			Vector3D			velocity_accel_1(-0.00725, -0.004, -0.00725);
////			Vector3D			velocity_accel_1(-0.00925, -0.00925, -0.00925);
//			Vector3D			velocity_accel_2(-0.01388, -0.01388, -0.01388);
//			LinearMatrix	explosion_1_offset(True);
//			LinearMatrix	explosion_2_offset(True);
//			Point3D			explosion_2_translate(0.0f, 0.0f, 0.0f);
//			EulerAngles		explosion_2_rotate(0.0f, 1.0f, 0.0f);
//			explosion_2_offset = explosion_2_rotate;
//         explosion_2_offset = explosion_2_translate;
//			//
//			// Create the scaling explosion renderables
//			//
//			ScalingExplosionRenderable  *explosion_1 =
//				new ScalingExplosionRenderable(
//					entity,											// Entity to attach the renderable to
//					ScalingExplosionRenderable::Dynamic,	// How/when to execute the renderable
//					object_1,											// This will be the scaling explosion object
//					false,									// DPL Zone this stuff will live in (for culling)
//					dpl_isect_mode_obj,							// type of intersections to do on this object
//					NULL,												// intersection mask for the object
//					this_root->GetDCS(),							// the parent DCS we will be offsetting from
//					&explosion_1_offset,								// offset matrix to be applied prior to joint DCS
//					&scaling_velocity_1,      					// Effect control vector, Y is acceleration, X, Z are velocity
//					&velocity_accel_1,
//					0.0f,
//					NULL);                     				// -.25 gravity is normal
//			Register_Object(explosion_1);
//			ScalingExplosionRenderable  *explosion_2 =
//				new ScalingExplosionRenderable(
//					entity,											// Entity to attach the renderable to
//					ScalingExplosionRenderable::Dynamic,	// How/when to execute the renderable
//					object_1,											// This will be the scaling explosion object
//					false,									// DPL Zone this stuff will live in (for culling)
//					dpl_isect_mode_obj,							// type of intersections to do on this object
//					NULL,												// intersection mask for the object
//					this_root->GetDCS(),							// the parent DCS we will be offsetting from
//					&explosion_2_offset,								// offset matrix to be applied prior to joint DCS
//					&scaling_velocity_2,      					// Effect control vector, Y is acceleration, X, Z are velocity
//					&velocity_accel_2,
//					0.0f,
//					NULL);
//			Register_Object(explosion_2);
//			//
//			// Create a sweep renderable to drive the material morph
//			//
//			SweepRenderable *sweep_1 =
//				new SweepRenderable(
//					entity,							// Entity to attach the renderable to
//					SweepRenderable::Dynamic,	// How/when to execute the renderable
//					3.0f,                      // How long to take to sweep from 0 to 1
//					1,									// number of times to cycle before stopping
//					NULL);
//			Register_Object(sweep_1);
//			SweepRenderable *sweep_2 =
//				new SweepRenderable(
//					entity,							// Entity to attach the renderable to
//					SweepRenderable::Dynamic,	// How/when to execute the renderable
//					2.0f,								// How long to take to sweep from 0 to 1
//					1,									// number of times to cycle before stopping
//					NULL);
//			Register_Object(sweep_2);
//			//
//			// Lookup a texture that we can use for the morphing materials
//			//
//			int
//				status;
//			dpl_TEXTURE *effect_texture =
//				dpl_LookupTexture ( "btfx:firesmoke1_scr_tex", dpl_lookup_normal, &status );
//			if (effect_texture == NULL)
//				DEBUG_STREAM<<"couldn't find texture btfx:firesmoke1_scr_tex for an effect\n" << std::flush;
//			//
//			// Setup a morph material renderable for each explosion shape
//			//
//			#if 0
//					0.9f,0.0f,0.0f,							// Material's ambient component
//					1.0f,1.0f,0.0f,							// Material's emissive component
//					1.0f,0.7f,0.2f,							// Material's diffuse component
//					0.0f,0.0f,0.0f,0.0,						// Material's specular component
//					8.0f,0.2f,-0.05f,							// Material's opacity
//			#endif
//			MorphMaterialRenderable *morph_material_1 =
//				new MorphMaterialRenderable(
//					entity,										// Entity to attach the renderable to
//					MorphMaterialRenderable::Dynamic,	// How/when to execute the renderable
//					0.9f,0.0f,0.0f,							// Material's ambient component
//					1.0f,0.2f,0.0f,							// Material's emissive component
//					1.0f,0.2f,0.0f,							// Material's diffuse component
//					0.0f,0.0f,0.0f,0.0,						// Material's specular component
//					8.0f,0.2f,-0.05f,							// Material's opacity
//					effect_texture,							// Material's texture pointer
//					0.0f,											// Material's Z dither value
//					0,												// Material's Fog Imunity value
//					0.3f,0.0f,0.0f,							// Material's ambient component
//					0.5f,0.0f,0.0f,							// Material's emissive component
//					0.2f,0.0f,0.0f,							// Material's diffuse component
//					0.0f,0.0f,0.0f,0.0,						// Material's specular component
//					0.25f,0.25f,-0.05f,							// Material's opacity
//					15.0f,											// Material's Z dither value
//					sweep_1->GetSweepAttribute());
//			Register_Object(morph_material_1);
//			MorphMaterialRenderable *morph_material_2 =
//				new MorphMaterialRenderable(
//					entity,										// Entity to attach the renderable to
//					MorphMaterialRenderable::Dynamic,	// How/when to execute the renderable
//					0.9f,0.0f,0.0f,							// Material's ambient component
//					1.0f,0.6f,0.4f,							// Material's emissive component
//					1.0f,0.3f,0.2f,							// Material's diffuse component
//					0.0f,0.0f,0.0f,0.0,						// Material's specular component
//					8.0f,0.2f,-0.05f,							// Material's opacity
//					effect_texture,							// Material's texture pointer
//					0.0f,											// Material's Z dither value
//					0,												// Material's Fog Imunity value
//					0.1f,0.0f,0.0f,							// Material's ambient component
//					0.0f,0.0f,0.0f,							// Material's emissive component
//					0.0f,0.0f,0.0f,							// Material's diffuse component
//					0.0f,0.0f,0.0f,0.0,						// Material's specular component
//					0.25f,0.25f,-0.05f,						// Material's opacity
//					15.0f,											// Material's Z dither value
//					sweep_2->GetSweepAttribute());
//			Register_Object(morph_material_2);
//			//
//			// Override the materials in the two explosion shapes using these morph materials
//			//
//			dpl_INSTANCE *explosion_1_instance = dpl_GetDCSInstance(explosion_1->GetDCS(), 1);
//			dpl_INSTANCE *explosion_2_instance = dpl_GetDCSInstance(explosion_2->GetDCS(), 1);
//
//			if(!explosion_1_instance)
//				Fail("explosion_1_instance came back null\n");
//			if(!explosion_2_instance)
//				Fail("explosion_2_instance came back null\n");
//
//			dpl_SetInstanceFrontMaterial(explosion_1_instance,	morph_material_1->GetMaterial());
//			dpl_SetInstanceFrontMaterial(explosion_2_instance,	morph_material_2->GetMaterial());
//
//			dpl_FlushInstance(explosion_1_instance);
//			dpl_FlushInstance(explosion_2_instance);
//			break;
//		}
//		case	3:		// Sparks
//		{
//			//
//			// Load object(s) we will be using for the explosions
//			//
//			object_1		 = dpl_LoadObject("spk1.bgf", dpl_load_normal);
//			//
//			// Setup control variables and transforms we need
//			//
//			Vector3D			scaling_velocity_1(0.1, 0.1, 0.1);
//			Vector3D			velocity_accel_1(0.0, 0.0, 0.0);
//			LinearMatrix	explosion_1_offset(True);
//			//
//			// Create the scaling explosion renderables
//			//
//			ScalingExplosionRenderable  *explosion_1 =
//				new ScalingExplosionRenderable(
//					entity,											// Entity to attach the renderable to
//					ScalingExplosionRenderable::Dynamic,	// How/when to execute the renderable
//					object_1,											// This will be the scaling explosion object
//					false,									// DPL Zone this stuff will live in (for culling)
//					dpl_isect_mode_obj,							// type of intersections to do on this object
//					NULL,												// intersection mask for the object
//					this_root->GetDCS(),							// the parent DCS we will be offsetting from
//					&explosion_1_offset,								// offset matrix to be applied prior to joint DCS
//					&scaling_velocity_1,      					// Effect control vector, Y is acceleration, X, Z are velocity
//					&velocity_accel_1,
//					-0.15f,
//					NULL);                     				// -.25 gravity is normal
//			Register_Object(explosion_1);
//			//
//			// Create a sweep renderable to drive the material morph
//			//
//			SweepRenderable *sweep_1 =
//				new SweepRenderable(
//					entity,							// Entity to attach the renderable to
//					SweepRenderable::Dynamic,	// How/when to execute the renderable
//					0.5f,								// How long to take to sweep from 0 to 1
//					1,									// number of times to cycle before stopping
//					NULL);
//			Register_Object(sweep_1);
//			//
//			// Lookup a texture that we can use for the morphing materials
//			//
//			int
//				status;
//			dpl_TEXTURE *effect_texture =
//				dpl_LookupTexture ( "btfx:firesmoke1_scr_tex", dpl_lookup_normal, &status );
//			if (effect_texture == NULL)
//				DEBUG_STREAM<<"couldn't find texture btfx:firesmoke1_scr_tex for an effect\n" << std::flush;
//			//
//			// Setup a morph material renderable for each explosion shape
//			//
//			MorphMaterialRenderable *morph_material_1 =
//				new MorphMaterialRenderable(
//					entity,										// Entity to attach the renderable to
//					MorphMaterialRenderable::Dynamic,	// How/when to execute the renderable
//					1.0f,1.0f,0.0f,							// Material's ambient component
//					1.0f,1.0f,0.0f,							// Material's emissive component
//					1.0f,1.0f,0.0f,							// Material's diffuse component
//					0.0f,0.0f,0.0f,0.0,						// Material's specular component
//					1.0f,1.0f,1.0f,							// Material's opacity
//					effect_texture,							// Material's texture pointer
//					0.0f,											// Material's Z dither value
//					2,												// Material's Fog Imunity value
//					0.9f,0.0f,0.0f,							// Material's ambient component
//					0.9f,0.0f,0.0f,							// Material's emissive component
//					0.9f,0.0f,0.0f,							// Material's diffuse component
//					0.0f,0.0f,0.0f,0.0,						// Material's specular component
//					1.0f,1.0f,1.0f,							// Material's opacity
//					0.0f,											// Material's Z dither value
//					sweep_1->GetSweepAttribute());
//			Register_Object(morph_material_1);
//			dpl_INSTANCE *explosion_1_instance = dpl_GetDCSInstance(explosion_1->GetDCS(), 1);
//			if(!explosion_1_instance)
//				Fail("explosion_1_instance came back null\n");
//			dpl_SetInstanceFrontMaterial(explosion_1_instance,	morph_material_1->GetMaterial());
//			dpl_FlushInstance(explosion_1_instance);
//			break;
//		}
//		case 4:	// A huge mech explodes (yawn)
//		{
//			Point3D			null_offset(0.0f, 0.0f, 0.0f);
//			LinearMatrix	null_offset_matrix(True);
//			Point3D			local_height(0.0f, 6.2f, 0.0f);	// height of Thor
//			LinearMatrix	local_offset(True);
//			local_offset = local_height;
//			DPLStaticChildRenderable *local_root =
//				new DPLStaticChildRenderable(
//					entity,
//					false,
//					NULL,
//					dpl_isect_mode_obj,
//					NULL,
//					local_offset,
//					this_root->GetDCS());
//			Register_Object(local_root);
//			//
//			// Load morph sources we need for the effect
//			//
//			dpl_OBJECT	*thor_debris_object	= dpl_LoadObject("thrdbr.bgf", dpl_load_normal);
//			dpl_OBJECT	*large_debris_object	= dpl_LoadObject("ldbr.bgf", dpl_load_normal);
//			dpl_OBJECT	*small_flames_object	= dpl_LoadObject("flamesml.bgf", dpl_load_normal);
//			//
//			// Load morph targets we need for the effect
//			//
//			//------------------------------------------------
//			// Renderables to handle the chunks and fireballs
//			//------------------------------------------------
//#if 0
//			OneShotDelayRenderable *fireball_delay =
//				new OneShotDelayRenderable(
//					entity,									// Entity to attach the renderable to
//					OneShotDelayRenderable::Dynamic,	// How/when to execute the renderable
//					0.25f);									// How long to wait before raising the trigger
//			Register_Object(fireball_delay);
//			Point3D my_offset(0.0, 4.0, 0.0);
//			#if DEBUG_LEVEL > 0
//			DPLPSFXRenderable*		initial_boom	=
//			#endif
//				new DPLPSFXRenderable(
//					entity,								// Entity to attach the renderable to
//					DPLPSFXRenderable::Dynamic,	// How/when to execute the renderable
//					fireball_delay->GetTriggerAttribute(),							// address containing the trigger
//					myPSFXDescriptons[7],			// pointer to the PFX description
//					this_root->GetDCS(),				// DCS the effect is relative to (may be NULL)
//					&my_offset);						// Offset (or world coordinants if DCS is NULL)
//			Register_Object(initial_boom);
//			#if DEBUG_LEVEL > 0
//			DPLEffectRenderable *chunks_effect	=
//			#endif
//				new DPLEffectRenderable(
//					entity,											// Entity to attach the renderable to
//					OneShotDelayRenderable::Dynamic,			// How/when to execute the renderable
//					fireball_delay->GetTriggerAttribute(),	// address containing the trigger
//					3,	// Chunks									// DPL effect number to trigger
//					local_root->GetDCS(),						// DCS the effect is relative to (may be NULL)
//					&null_offset); 	   						// Offset (or world coordinants if DCS is NULL)
//			Register_Object(chunks_effect);
//			Point3D	fireball_offset(1.0f, 5.0f, 1.0f);
//			#if DEBUG_LEVEL > 0
//			DPLEffectRenderable *fireball_effect	=
//			#endif
//				new DPLEffectRenderable(
//					entity,											// Entity to attach the renderable to
//					OneShotDelayRenderable::Dynamic,			// How/when to execute the renderable
//					fireball_delay->GetTriggerAttribute(),	// address containing the trigger
//					15,	// Fireball								// DPL effect number to trigger
//					local_root->GetDCS(),						// DCS the effect is relative to (may be NULL)
//					&fireball_offset); 	   						// Offset (or world coordinants if DCS is NULL)
//			Register_Object(fireball_effect);
//#endif
//			OneShotDelayRenderable *fireball_delay_2 =
//				new OneShotDelayRenderable(
//					entity,									// Entity to attach the renderable to
//					OneShotDelayRenderable::Dynamic,	// How/when to execute the renderable
//					0.55f);									// How long to wait before raising the trigger
//			Register_Object(fireball_delay_2);
//			Point3D	fireball_offset_2(-1.0f, 5.0f, -1.0f);
//			#if DEBUG_LEVEL > 0
//			DPLEffectRenderable *fireball_effect_2	=
//			#endif
//				new DPLEffectRenderable(
//					entity,											// Entity to attach the renderable to
//					OneShotDelayRenderable::Dynamic,			// How/when to execute the renderable
//					fireball_delay_2->GetTriggerAttribute(),	// address containing the trigger
//					15,	// Fireball								// DPL effect number to trigger
//					local_root->GetDCS(),						// DCS the effect is relative to (may be NULL)
//					&fireball_offset_2); 						// Offset (or world coordinants if DCS is NULL)
//			Register_Object(fireball_effect_2);
//			//-----------------------------------------------
//			// Renderables to handle static debris
//			//-----------------------------------------------
//			OneShotDelayRenderable	*static_debris_delay =
//				new OneShotDelayRenderable(
//					entity,												// Entity to attach the renderable to
//					OneShotDelayRenderable::Dynamic,				// How/when to execute the renderable
//					0.25f);												// How long to wait before raising the trigger
//			Register_Object(static_debris_delay);
//			DPLStaticChildRenderable *mech_debris =
//				new DPLStaticChildRenderable(
//					entity,
//					false,
//					thor_debris_object,
//					dpl_isect_mode_obj,
//					NULL,
//					null_offset_matrix,
//					this_root->GetDCS());
//			Register_Object(mech_debris);
//			#if DEBUG_LEVEL > 0
//			MakeDCSFall	*mech_debris_fall =
//			#endif
//				new MakeDCSFall(
//					entity,												// Entity to attach the renderable to
//					MakeDCSFall::Dynamic,							// How/when to execute the renderable
//					mech_debris->GetDCS(),							// the DCS to control
//					-0.025f,												// Gravity in meters/sec squared
//					static_debris_delay->GetTriggerAttribute());		// true if the instance is on, false if off
//			Register_Object(mech_debris_fall);
//			// Find the instance with the static_thr in it and hook up the instance switch
//			dpl_INSTANCE *mech_debris_instance = dpl_GetDCSInstance(mech_debris->GetDCS(), 1);
//			#if DEBUG_LEVEL > 0
//			InstanceSwitchRenderable	*mech_debris_instance_switch =
//			#endif
//				new InstanceSwitchRenderable(
//					entity,									 		// Entity to attach the renderable to
//					InstanceSwitchRenderable::Dynamic,		// How/when to execute the renderable
//					mech_debris_instance,				 		// the instance to control
//					True,										 		// Instance is on when trigger is...
//					static_debris_delay->GetTriggerAttribute());
//			Register_Object(mech_debris_instance_switch);
//
//			DPLStaticChildRenderable *large_debris =
//				new DPLStaticChildRenderable(
//					entity,
//					false,
//					large_debris_object,
//					dpl_isect_mode_obj,
//					NULL,
//					null_offset_matrix,
//					mech_debris->GetDCS());
//			Register_Object(large_debris);
//			// Find the instance with the static_thr in it and hook up the instance switch
//			dpl_INSTANCE *large_debris_instance = dpl_GetDCSInstance(large_debris->GetDCS(), 1);
//			#if DEBUG_LEVEL > 0
//			InstanceSwitchRenderable	*large_debris_instance_switch =
//         #endif
//				new InstanceSwitchRenderable(
//					entity,									 		// Entity to attach the renderable to
//					InstanceSwitchRenderable::Dynamic,		// How/when to execute the renderable
//					large_debris_instance,				 		// the instance to control
//					True,										 		// Instance is on when trigger is...
//					static_debris_delay->GetTriggerAttribute());
//			Register_Object(large_debris_instance_switch);
//			//-----------------------------------------------
//			// Renderables to handle fires
//			//-----------------------------------------------
//			OneShotDelayRenderable	*fires_delay =
//				new OneShotDelayRenderable(
//					entity,												// Entity to attach the renderable to
//					OneShotDelayRenderable::Dynamic,				// How/when to execute the renderable
//					0.25f);												// How long to wait before raising the trigger
//			Register_Object(fires_delay);
//			DPLStaticChildRenderable *fires =
//				new DPLStaticChildRenderable(
//					entity,
//					false,
//					NULL,
//					dpl_isect_mode_obj,
//					NULL,
//					null_offset_matrix,
//					this_root->GetDCS());
//			Register_Object(fires);
//			#if DEBUG_LEVEL > 0
//			MakeDCSFall	*fires_fall =
//			#endif
//				new MakeDCSFall(
//					entity,												// Entity to attach the renderable to
//					MakeDCSFall::Dynamic,							// How/when to execute the renderable
//					fires->GetDCS(),							// the DCS to control
//					-0.01f,												// Gravity in meters/sec squared
//					fires_delay->GetTriggerAttribute());		// true if the instance is on, false if off
//			Register_Object(fires_fall);
//			DPLStaticChildRenderable *small_flames =
//				new DPLStaticChildRenderable(
//					entity,
//					false,
//					small_flames_object,
//					dpl_isect_mode_obj,
//					NULL,
//					null_offset_matrix,
//					fires->GetDCS());
//			Register_Object(small_flames);
//			// Find the instance with the static_thr in it and hook up the instance switch
//			dpl_INSTANCE *small_flames_instance = dpl_GetDCSInstance(small_flames->GetDCS(), 1);
//			#if DEBUG_LEVEL > 0
//			InstanceSwitchRenderable	*small_flames_instance_switch =
//			#endif
//				new InstanceSwitchRenderable(
//					entity,									 		// Entity to attach the renderable to
//					InstanceSwitchRenderable::Dynamic,		// How/when to execute the renderable
//					small_flames_instance,				 		// the instance to control
//					True,										 		// Instance is on when trigger is...
//					fires_delay->GetTriggerAttribute());
//			Register_Object(small_flames_instance_switch);
//
//			dpl_OBJECT	*big_flames_object	= dpl_LoadObject("flamebig.bgf", dpl_load_normal);
//			DPLStaticChildRenderable *big_flames =
//				new DPLStaticChildRenderable(
//					entity,
//					false,
//					big_flames_object,
//					dpl_isect_mode_obj,
//					NULL,
//					null_offset_matrix,
//					fires->GetDCS());
//			Register_Object(big_flames);
//			// Make big flames object billboard along y-axis
//			dpl_SetDCSReorientAxes(big_flames->GetDCS(), dpl_reorient_axes_y);
//			dpl_FlushDCS(big_flames->GetDCS());
//			// Find the instance with the static_thr in it and hook up the instance switch
//			dpl_INSTANCE *big_flames_instance = dpl_GetDCSInstance(big_flames->GetDCS(), 1);
//			#if DEBUG_LEVEL > 0
//			InstanceSwitchRenderable	*big_flames_instance_switch =
//			#endif
//				new InstanceSwitchRenderable(
//					entity,									 		// Entity to attach the renderable to
//					InstanceSwitchRenderable::Dynamic,		// How/when to execute the renderable
//					big_flames_instance,					 		// the instance to control
//					True,										 		// Instance is on when trigger is...
//					fires_delay->GetTriggerAttribute());
//			Register_Object(big_flames_instance_switch);
//			//
//			// These renderables create the rising smoke column using a pfx effect.
//         //
//#if 0
//			Point3D my_offset2(0.0, 5.0, 0.0);
//			#if DEBUG_LEVEL > 0
//			OnePSFXRenderable	*this_effect=
//			#endif
//				new OnePSFXRenderable(
//					entity,								// Entity to attach the renderable to
//					OnePSFXRenderable::Static,		// How/when to execute the renderable
//					myPSFXDescriptons[1],			// name of file with the PFX description in it
//					this_root->GetDCS(),				// DCS the effect is relative to (may be NULL)
//					&my_offset2);						// Offset (or world coordinants if DCS is NULL)
//			Register_Object(this_effect);
//#endif
//			break;
//		}
//		//----------------------------------------
//		case 5:	// Sfx #105 - Delayed ground hit
//		//----------------------------------------
//		{
//			//
//			// Create the delayed ground hit renderables
//			//
//			Point3D	null_offset(0.0f, 0.0f, 0.0f);
//			OneShotDelayRenderable *ground_hit_delay =
//				new OneShotDelayRenderable(
//					entity,									// Entity to attach the renderable to
//					OneShotDelayRenderable::Dynamic,	// How/when to execute the renderable
//					0.15f);									// How long to wait before raising the trigger
//			Register_Object(ground_hit_delay);
//			#if DEBUG_LEVEL > 0
//			DPLEffectRenderable *ground_hit_effect	=
//         #endif
//				new DPLEffectRenderable(
//					entity,											// Entity to attach the renderable to
//					OneShotDelayRenderable::Dynamic,			// How/when to execute the renderable
//					ground_hit_delay->GetTriggerAttribute(),	// address containing the trigger
//					12,	// GroundHit							// DPL effect number to trigger
//					this_root->GetDCS(),							// DCS the effect is relative to (may be NULL)
//					&null_offset); 		 						// Offset (or world coordinants if DCS is NULL)
//			Register_Object(ground_hit_effect);
//			break;
//		}
//		//------------------------------------------
//		case 6:	// Sfx #106 - Thor death explosion
//		//------------------------------------------
//		{
//			#if 0
//			int status;		// used with dpl calls
//			Point3D			null_offset(0.0f, 0.0f, 0.0f);
//			LinearMatrix	null_offset_matrix(True);
//			Point3D			local_height(0.0f, 6.2f, 0.0f);	// height of Thor
//			LinearMatrix	local_offset(True);
//			local_offset = local_height;
//			DPLStaticChildRenderable *local_root =
//				new DPLStaticChildRenderable(
//					entity,
//					false,
//					NULL,
//					dpl_isect_mode_obj,
//					NULL,
//					local_offset,
//					this_root->GetDCS());
//			Register_Object(local_root);
//#if 0
//			//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
//			//
//			// Show static thor (TEMPORARY for testing)
//			//
//			dpl_OBJECT *static_thr_object = dpl_LoadObject("thr.bgf", dpl_load_normal);
//			DPLStaticChildRenderable *static_thr =
//				new DPLStaticChildRenderable(
//					entity,
//					false,
//					static_thr_object,
//					dpl_isect_mode_obj,
//					NULL,
//					null_offset_matrix,
//					local_root->GetDCS());
//			Register_Object(static_thr);
//			// This defines how long the static_thr stays visible
//			OneShotDelayRenderable	*static_thr_delay =
//				new OneShotDelayRenderable(
//					entity,										// Entity to attach the renderable to
//					OneShotDelayRenderable::Dynamic,		// How/when to execute the renderable
//					0.5f);										// How long to wait before raising the trigger
//			// Find the instance with the static_thr in it and hook up the instance switch
//			dpl_INSTANCE *static_thr_instance = dpl_GetDCSInstance(static_thr->GetDCS(), 1);
//			InstanceSwitchRenderable	*static_thr_instance_switch =
//				new InstanceSwitchRenderable(
//					entity,									 		// Entity to attach the renderable to
//					InstanceSwitchRenderable::Dynamic,		// How/when to execute the renderable
//					static_thr_instance,					 		// the instance to control
//					False,									 		// Instance is on when trigger is...
//					static_thr_delay->GetTriggerAttribute());
//			//
//			//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//#endif
//			//
//			// Load objects we will be using for the explosion effect
//			//
//			DPLObjectWrapper *flash_object_wrapper =
//				new DPLObjectWrapper(
//					entity,						// Entity to attach the renderable to
//					"exdisk_A.bgf",					// Name of the DPL object to load into the wrapper
//					dpl_load_nocache);		// Type of loading to perform on this object
//			Register_Object(flash_object_wrapper);
//			dpl_OBJECT	*flash_object_a	=	flash_object_wrapper->GetDPLObject();
//			dpl_OBJECT	*flash_object_b	= dpl_LoadObject("exdisk_B.bgf", dpl_load_normal);
//			dpl_OBJECT	*flash_object_c	= dpl_LoadObject("exdisk_C.bgf", dpl_load_normal);
//			DPLObjectWrapper *debris_object_wrapper =
//				new DPLObjectWrapper(
//					entity,						// Entity to attach the renderable to
//					"thrtor_A.bgf",					// Name of the DPL object to load into the wrapper
//					dpl_load_nocache);		// Type of loading to perform on this object
//			Register_Object(debris_object_wrapper);
//			dpl_OBJECT	*morph_debris_a	=	debris_object_wrapper->GetDPLObject();
//			dpl_OBJECT	*morph_debris_b	= dpl_LoadObject("thrtor_B.bgf", dpl_load_normal);
//			dpl_OBJECT	*morph_debris_c	= dpl_LoadObject("thrtor_C.bgf", dpl_load_normal);
//			DPLObjectWrapper *hips_object_wrapper =
//				new DPLObjectWrapper(
//					entity,						// Entity to attach the renderable to
//					"thrhip_A.bgf",					// Name of the DPL object to load into the wrapper
//					dpl_load_nocache);		// Type of loading to perform on this object
//			Register_Object(hips_object_wrapper);
//			dpl_OBJECT	*morph_hips_a	=	hips_object_wrapper->GetDPLObject();
//			dpl_OBJECT	*morph_hips_b		= dpl_LoadObject("thrhip_B.bgf", dpl_load_normal);
//			dpl_OBJECT	*morph_hips_c		= dpl_LoadObject("thrhip_C.bgf", dpl_load_normal);
//			dpl_OBJECT	*thor_debris_object	= dpl_LoadObject("thrdbr.bgf", dpl_load_normal);
//			dpl_OBJECT	*large_debris_object	= dpl_LoadObject("ldbr.bgf", dpl_load_normal);
//			dpl_OBJECT	*small_flames_object	= dpl_LoadObject("flamesml.bgf", dpl_load_normal);
//			dpl_OBJECT	*big_flames_object	= dpl_LoadObject("flamebig.bgf", dpl_load_normal);
//			//----------------------------------------------
//			// Renderables to perform morphing flash object
//			//----------------------------------------------
//			SweepRenderable *flash_morph_sweep =
//				new SweepRenderable(
//					entity,												// Entity to attach the renderable to
//					SweepRenderable::Dynamic,						// How/when to execute the renderable
//					1.0f,													// How long to take to sweep from 0 to 1
//					1,														// number of times to cycle before stopping
//					NULL,													// trigger
//					-0.5f,												// Initial value
//					2.0f);												// Final value
//			ChildMorphRenderable	*flash_morph =
//				new ChildMorphRenderable(
//					entity,												// Entity to attach the renderable to
//					ChildMorphRenderable::Dynamic,				// How/when to execute the renderable
//					flash_object_a,									// destination
//					flash_object_b,									// start object
//					flash_object_c,									// end object
//					flash_morph_sweep->GetSweepAttribute(),	// pointer to control variable
//					dpl_morph_vertices | dpl_morph_colors, 	// Defines type of morph to do
//					false,										// DPL Zone this stuff will live in (for culling)
//					dpl_isect_mode_obj,								// type of intersections to do on this object
//					NULL,													// intersection mask for the object
//					this_root->GetDCS());							// the parent DCS we will be offsetting from
//			// Make flash object billboard along y-axis
//			dpl_SetDCSReorientAxes(flash_morph->GetDCS(), dpl_reorient_axes_y);
//			dpl_FlushDCS(flash_morph->GetDCS());
//			// This defines how long the flash stays up
//			OneShotDelayRenderable	*flash_delay =
//				new OneShotDelayRenderable(
//					entity,										// Entity to attach the renderable to
//					OneShotDelayRenderable::Dynamic,		// How/when to execute the renderable
//					1.0f);										// How long to wait before raising the trigger
//			Register_Object(flash_delay);
//			// Find the instance with the flash in it and hook up the instance switch
//			dpl_INSTANCE *flash_morph_instance = dpl_GetDCSInstance(flash_morph->GetDCS(), 1);
//			InstanceSwitchRenderable	*flash_instance_switch =
//				new InstanceSwitchRenderable(
//					entity,									 		// Entity to attach the renderable to
//					InstanceSwitchRenderable::Dynamic,		// How/when to execute the renderable
//					flash_morph_instance,				 		// the instance to control
//					False,									 		// Instance is on when trigger is...
//					flash_delay->GetTriggerAttribute());
//			//---------------------------------------------------
//			// Create a material morph to fade flash object away
//			//---------------------------------------------------
//			OneShotDelayRenderable	*flash_fade_delay =
//				new OneShotDelayRenderable(
//					entity,												// Entity to attach the renderable to
//					OneShotDelayRenderable::Dynamic,				// How/when to execute the renderable
//					0.5f);												// How long to wait before raising the trigger
//			SweepRenderable *flash_fade_sweep =
//				new SweepRenderable(
//					entity,								// Entity to attach the renderable to
//					SweepRenderable::Dynamic,		// How/when to execute the renderable
//					0.4f, 								// How long to take to sweep from 0 to 1
//					1,										// number of times to cycle before stopping
//					flash_fade_delay->GetTriggerAttribute());		// trigger variable
//			Register_Object(flash_fade_sweep);
//			// Lookup texture for smoke column
//			dpl_TEXTURE *flash_texture =
//				dpl_LookupTexture("btfx:bexp9_tex", dpl_lookup_normal, &status);
//			if (flash_texture == NULL)
//				DEBUG_STREAM<<"couldn't find texture btfx:bexp9_tex for an effect\n" << std::flush;
//			//
//			MorphMaterialRenderable *flash_fade_material =
//				new MorphMaterialRenderable(
//					entity,										// Entity to attach the renderable to
//					MorphMaterialRenderable::Dynamic,	// How/when to execute the renderable
//					1.0f,1.0f,1.0f,							// Material's ambient component
//					1.0f,1.0f,1.0f,							// Material's emissive component
//					1.0f,1.0f,1.0f,							// Material's diffuse component
//					0.0f,0.0f,0.0f,0.0f,						// Material's specular component
//					1.0f,1.0f,1.0f,							// Material's opacity
//					flash_texture,								// Material's texture pointer
//					0.0f,											// Material's Z dither value
//					1,												// Material's Fog Imunity value
//					1.0f,1.0f,1.0f,							// Material's ambient component
//					1.0f,1.0f,1.0f,							// Material's emissive component
//					1.0f,1.0f,1.0f,							// Material's diffuse component
//					0.0f,0.0f,0.0f,0.0f,						// Material's specular component
//					0.0f,0.0f,0.0f,							// Material's opacity
//					0.0f, 										// Material's Z dither value
//					flash_fade_sweep->GetSweepAttribute());
//			Register_Object(flash_fade_material);
////			dpl_INSTANCE *flash_morph_instance = dpl_GetDCSInstance(flash_morph->GetDCS(), 1);
//			if (!flash_morph_instance)
//				Fail("flash_morph_instance came back null\n");
//			dpl_SetInstanceFrontMaterial(flash_morph_instance, flash_fade_material->GetMaterial());
//			dpl_FlushInstance(flash_morph_instance);
//			//------------------------------------------------
//			// Renderables to handle the chunks and fireballs
//			//------------------------------------------------
//			OneShotDelayRenderable *fireball_delay =
//				new OneShotDelayRenderable(
//					entity,									// Entity to attach the renderable to
//					OneShotDelayRenderable::Dynamic,	// How/when to execute the renderable
//					0.25f);									// How long to wait before raising the trigger
//			Register_Object(fireball_delay);
//			DPLEffectRenderable *chunks_effect	=
//				new DPLEffectRenderable(
//					entity,											// Entity to attach the renderable to
//					OneShotDelayRenderable::Dynamic,			// How/when to execute the renderable
//					fireball_delay->GetTriggerAttribute(),	// address containing the trigger
//					3,	// Chunks									// DPL effect number to trigger
//					local_root->GetDCS(),						// DCS the effect is relative to (may be NULL)
//					&null_offset); 	   						// Offset (or world coordinants if DCS is NULL)
//			Register_Object(chunks_effect);
//			Point3D	fireball_offset(1.0f, 5.0f, 1.0f);
//			DPLEffectRenderable *fireball_effect	=
//				new DPLEffectRenderable(
//					entity,											// Entity to attach the renderable to
//					OneShotDelayRenderable::Dynamic,			// How/when to execute the renderable
//					fireball_delay->GetTriggerAttribute(),	// address containing the trigger
//					15,	// Fireball								// DPL effect number to trigger
//					local_root->GetDCS(),						// DCS the effect is relative to (may be NULL)
//					&fireball_offset); 	   						// Offset (or world coordinants if DCS is NULL)
//			Register_Object(fireball_effect);
//			OneShotDelayRenderable *fireball_delay_2 =
//				new OneShotDelayRenderable(
//					entity,									// Entity to attach the renderable to
//					OneShotDelayRenderable::Dynamic,	// How/when to execute the renderable
//					0.55f);									// How long to wait before raising the trigger
//			Register_Object(fireball_delay_2);
//			Point3D	fireball_offset_2(-1.0f, 5.0f, -1.0f);
//			DPLEffectRenderable *fireball_effect_2	=
//				new DPLEffectRenderable(
//					entity,											// Entity to attach the renderable to
//					OneShotDelayRenderable::Dynamic,			// How/when to execute the renderable
//					fireball_delay_2->GetTriggerAttribute(),	// address containing the trigger
//					15,	// Fireball								// DPL effect number to trigger
//					local_root->GetDCS(),						// DCS the effect is relative to (may be NULL)
//					&fireball_offset_2); 						// Offset (or world coordinants if DCS is NULL)
//			Register_Object(fireball_effect_2);
//			//------------------------------------------------------
//			// Renderables to handle the torso debris explode morph
//			//------------------------------------------------------
//			OneShotDelayRenderable	*morph_debris_delay =
//				new OneShotDelayRenderable(
//					entity,												// Entity to attach the renderable to
//					OneShotDelayRenderable::Dynamic,				// How/when to execute the renderable
//					0.25f,												// How long to wait before raising the trigger
//					4.25f);												// Duration of trigger
//			SweepRenderable *debris_morph_sweep =
//				new SweepRenderable(
//					entity,												// Entity to attach the renderable to
//					SweepRenderable::Dynamic,						// How/when to execute the renderable
//					4.0f,													// How long to take to sweep from 0 to 1
//					1,														// number of times to cycle before stopping
//					morph_debris_delay->GetTriggerAttribute(),		// trigger variable
//					0.0f,													// initial value of sweep
//					9.0f,													// final value of sweep
//					SweepRenderable::Y_SQR_X);						// function to apply
//			ChildMorphRenderable	*debris_morph	=
//				new ChildMorphRenderable(
//					entity,												// Entity to attach the renderable to
//					ChildMorphRenderable::Dynamic,				// How/when to execute the renderable
//					morph_debris_a,									// destination
//					morph_debris_b,									// start object
//					morph_debris_c,									// end object
//					debris_morph_sweep->GetSweepAttribute(),	// pointer to control variable
//					dpl_morph_vertices, 								// Defines type of morph to do
//					false,										// DPL Zone this stuff will live in (for culling)
//					dpl_isect_mode_obj,								// type of intersections to do on this object
//					NULL,													// intersection mask for the object
//					local_root->GetDCS());							// the parent DCS we will be offsetting from
//			MakeDCSFall	*debris_make_fall =
//				new MakeDCSFall(
//					entity,												// Entity to attach the renderable to
//					MakeDCSFall::Dynamic,							// How/when to execute the renderable
//					debris_morph->GetDCS(),							// the DCS to control
//					-9.81f,												// Gravity in meters/sec squared
//					morph_debris_delay->GetTriggerAttribute());		// true if the instance is on, false if off
//			// Find the instance with the debris in it and hook up the instance switch
//			dpl_INSTANCE *debris_morph_instance = dpl_GetDCSInstance(debris_morph->GetDCS(), 1);
//			InstanceSwitchRenderable	*debris_morph_instance_switch =
//				new InstanceSwitchRenderable(
//					entity,												// Entity to attach the renderable to
//					InstanceSwitchRenderable::Dynamic,			// How/when to execute the renderable
//					debris_morph_instance,							// the instance to control
//					True,													// Instance is on when trigger is...
//					morph_debris_delay->GetTriggerAttribute());
//			//-----------------------------------------------------
//			// Renderables to handle the hips debris explode morph
//			//-----------------------------------------------------
//			ChildMorphRenderable	*hips_morph	=
//				new ChildMorphRenderable(
//					entity,												// Entity to attach the renderable to
//					ChildMorphRenderable::Dynamic,				// How/when to execute the renderable
//					morph_hips_a,										// destination
//					morph_hips_b,										// start object
//					morph_hips_c,										// end object
//					debris_morph_sweep->GetSweepAttribute(),	// pointer to control variable
//					dpl_morph_vertices, 								// Defines type of morph to do
//					false,										// DPL Zone this stuff will live in (for culling)
//					dpl_isect_mode_obj,								// type of intersections to do on this object
//					NULL,													// intersection mask for the object
//					local_root->GetDCS());							// the parent DCS we will be offsetting from
//			MakeDCSFall	*hips_make_fall =
//				new MakeDCSFall(
//					entity,												// Entity to attach the renderable to
//					MakeDCSFall::Dynamic,							// How/when to execute the renderable
//					hips_morph->GetDCS(),							// the DCS to control
//					-9.81f,												// Gravity in meters/sec squared
//					morph_debris_delay->GetTriggerAttribute());		// true if the instance is on, false if off
//			// Find the instance with the debris in it and hook up the instance switch
//			dpl_INSTANCE *hips_morph_instance = dpl_GetDCSInstance(hips_morph->GetDCS(), 1);
//			InstanceSwitchRenderable	*hips_morph_instance_switch =
//				new InstanceSwitchRenderable(
//					entity,												// Entity to attach the renderable to
//					InstanceSwitchRenderable::Dynamic,			// How/when to execute the renderable
//					hips_morph_instance,								// the instance to control
//					True,													// Instance is on when trigger is...
//					morph_debris_delay->GetTriggerAttribute());
//			//-----------------------------------------------
//			// Renderables to handle static debris and fires
//			//-----------------------------------------------
//			OneShotDelayRenderable	*static_debris_delay =
//				new OneShotDelayRenderable(
//					entity,												// Entity to attach the renderable to
//					OneShotDelayRenderable::Dynamic,				// How/when to execute the renderable
//					0.25f);												// How long to wait before raising the trigger
//			DPLStaticChildRenderable *mech_debris =
//				new DPLStaticChildRenderable(
//					entity,
//					false,
//					thor_debris_object,
//					dpl_isect_mode_obj,
//					NULL,
//					null_offset_matrix,
//					this_root->GetDCS());
//			Register_Object(mech_debris);
//			MakeDCSFall	*mech_debris_fall =
//				new MakeDCSFall(
//					entity,												// Entity to attach the renderable to
//					MakeDCSFall::Dynamic,							// How/when to execute the renderable
//					mech_debris->GetDCS(),							// the DCS to control
//					-0.01f,												// Gravity in meters/sec squared
//					static_debris_delay->GetTriggerAttribute());		// true if the instance is on, false if off
//			// Find the instance with the static_thr in it and hook up the instance switch
//			dpl_INSTANCE *mech_debris_instance = dpl_GetDCSInstance(mech_debris->GetDCS(), 1);
//			InstanceSwitchRenderable	*mech_debris_instance_switch =
//				new InstanceSwitchRenderable(
//					entity,									 		// Entity to attach the renderable to
//					InstanceSwitchRenderable::Dynamic,		// How/when to execute the renderable
//					mech_debris_instance,				 		// the instance to control
//					True,										 		// Instance is on when trigger is...
//					static_debris_delay->GetTriggerAttribute());
//
//			DPLStaticChildRenderable *large_debris =
//				new DPLStaticChildRenderable(
//					entity,
//					false,
//					large_debris_object,
//					dpl_isect_mode_obj,
//					NULL,
//					null_offset_matrix,
//					mech_debris->GetDCS());
//			Register_Object(large_debris);
//			// Find the instance with the static_thr in it and hook up the instance switch
//			dpl_INSTANCE *large_debris_instance = dpl_GetDCSInstance(large_debris->GetDCS(), 1);
//			InstanceSwitchRenderable	*large_debris_instance_switch =
//				new InstanceSwitchRenderable(
//					entity,									 		// Entity to attach the renderable to
//					InstanceSwitchRenderable::Dynamic,		// How/when to execute the renderable
//					large_debris_instance,				 		// the instance to control
//					True,										 		// Instance is on when trigger is...
//					static_debris_delay->GetTriggerAttribute());
//
//			DPLStaticChildRenderable *small_flames =
//				new DPLStaticChildRenderable(
//					entity,
//					false,
//					small_flames_object,
//					dpl_isect_mode_obj,
//					NULL,
//					null_offset_matrix,
//					mech_debris->GetDCS());
//			Register_Object(small_flames);
//			// Find the instance with the static_thr in it and hook up the instance switch
//			dpl_INSTANCE *small_flames_instance = dpl_GetDCSInstance(small_flames->GetDCS(), 1);
//			InstanceSwitchRenderable	*small_flames_instance_switch =
//				new InstanceSwitchRenderable(
//					entity,									 		// Entity to attach the renderable to
//					InstanceSwitchRenderable::Dynamic,		// How/when to execute the renderable
//					small_flames_instance,				 		// the instance to control
//					True,										 		// Instance is on when trigger is...
//					static_debris_delay->GetTriggerAttribute());
//
//			DPLStaticChildRenderable *big_flames =
//				new DPLStaticChildRenderable(
//					entity,
//					false,
//					big_flames_object,
//					dpl_isect_mode_obj,
//					NULL,
//					null_offset_matrix,
//					mech_debris->GetDCS());
//			Register_Object(big_flames);
//			// Make big flames object billboard along y-axis
//			dpl_SetDCSReorientAxes(big_flames->GetDCS(), dpl_reorient_axes_y);
//			dpl_FlushDCS(big_flames->GetDCS());
//			// Find the instance with the static_thr in it and hook up the instance switch
//			dpl_INSTANCE *big_flames_instance = dpl_GetDCSInstance(big_flames->GetDCS(), 1);
//			InstanceSwitchRenderable	*big_flames_instance_switch =
//				new InstanceSwitchRenderable(
//					entity,									 		// Entity to attach the renderable to
//					InstanceSwitchRenderable::Dynamic,		// How/when to execute the renderable
//					big_flames_instance,					 		// the instance to control
//					True,										 		// Instance is on when trigger is...
//					static_debris_delay->GetTriggerAttribute());
//			//-------------------------------------------------------------
//			// Renderables to handle the rising smoke column (first shape)
//			//-------------------------------------------------------------
//#if 1
//			OneShotDelayRenderable *first_one_shot =
//				new OneShotDelayRenderable(
//					entity,									// Entity to attach the renderable to
//					OneShotDelayRenderable::Dynamic,	// How/when to execute the renderable
//					0.0f);									// How long to wait before raising the trigger
//			Register_Object(first_one_shot);
//			Point3D my_offset(0.0, 6.0, 0.0);
//			#if DEBUG_LEVEL > 0
//			DPLPSFXRenderable*		this_effect	=
//         #endif
//				new DPLPSFXRenderable(
//					entity,								// Entity to attach the renderable to
//					DPLPSFXRenderable::Dynamic,	// How/when to execute the renderable
//					first_one_shot->GetTriggerAttribute(),							// address containing the trigger
//					myPSFXDescriptons[1],			// pointer to the PFX description
//					this_root->GetDCS(),				// DCS the effect is relative to (may be NULL)
//					&my_offset);						// Offset (or world coordinants if DCS is NULL)
//			Register_Object(this_effect);
//
//// the below code will be removed in favor of PFX effects once they are tested
//#else
////			OneShotDelayRenderable	*smoke_1_morph_delay =
////				new OneShotDelayRenderable(
////					entity,												// Entity to attach the renderable to
////					OneShotDelayRenderable::Dynamic,				// How/when to execute the renderable
////					0.25f);												// How long to wait before raising the trigger
//			SweepRenderable *smoke_1_sweep =
//				new SweepRenderable(
//					entity,												// Entity to attach the renderable to
//					SweepRenderable::Dynamic,						// How/when to execute the renderable
//					40.0f,												// How long to take to sweep from 0 to 1
//					1,														// number of times to cycle before stopping
//					static_debris_delay->GetTriggerAttribute(),
//					0.2f,
//					2.5f);
//			ChildMorphRenderable	*smoke_1_morph	=
//				new ChildMorphRenderable(
//					entity,												// Entity to attach the renderable to
//					ChildMorphRenderable::Dynamic,				// How/when to execute the renderable
//					smoke_1_a,											// destination
//					smoke_b,												// start object
//					smoke_c,												// end object
//					smoke_1_sweep->GetSweepAttribute(),		  	// pointer to control variable
//					dpl_morph_vertices, 								// Defines type of morph to do
//					false,										// DPL Zone this stuff will live in (for culling)
//					dpl_isect_mode_obj,								// type of intersections to do on this object
//					NULL,													// intersection mask for the object
//					this_root->GetDCS());							// the parent DCS we will be offsetting from
//			// Find the instance with the flash in it and hook up the instance switch
//			dpl_INSTANCE *smoke_1_instance = dpl_GetDCSInstance(smoke_1_morph->GetDCS(), 1);
//			InstanceSwitchRenderable	*smoke_1_instance_switch =
//				new InstanceSwitchRenderable(
//					entity,												// Entity to attach the renderable to
//					InstanceSwitchRenderable::Dynamic,			// How/when to execute the renderable
//					smoke_1_instance,									// the instance to control
//					True,													// Instance is on when trigger is...
//					static_debris_delay->GetTriggerAttribute());
//			//--------------------------------------------------------------
//			// Renderables to handle the rising smoke column (second shape)
//			//--------------------------------------------------------------
//#if 0
//			OneShotDelayRenderable	*smoke_2_morph_delay =
//				new OneShotDelayRenderable(
//					entity,												// Entity to attach the renderable to
//					OneShotDelayRenderable::Dynamic,				// How/when to execute the renderable
//					6.0f);												// How long to wait before raising the trigger
//			SweepRenderable *smoke_2_sweep =
//				new SweepRenderable(
//					entity,												// Entity to attach the renderable to
//					SweepRenderable::Dynamic,						// How/when to execute the renderable
//					30.0f,  												// How long to take to sweep from 0 to 1
//					1,														// number of times to cycle before stopping
//					smoke_2_morph_delay->GetTriggerAttribute(),
//					0.1f,
//					1.0f);
//			ChildMorphRenderable	*smoke_2_morph	=
//				new ChildMorphRenderable(
//					entity,												// Entity to attach the renderable to
//					ChildMorphRenderable::Dynamic,				// How/when to execute the renderable
//					smoke_2_a,											// destination
//					smoke_b,												// start object
//					smoke_c,												// end object
//					smoke_2_sweep->GetSweepAttribute(),			// pointer to control variable
//					dpl_morph_vertices,								// Defines type of morph to do
//					false,										// DPL Zone this stuff will live in (for culling)
//					dpl_isect_mode_obj,								// type of intersections to do on this object
//					NULL,													// intersection mask for the object
//					this_root->GetDCS());							// the parent DCS we will be offsetting from
//			// Find the instance with the flash in it and hook up the instance switch
//			dpl_INSTANCE *smoke_2_instance = dpl_GetDCSInstance(smoke_2_morph->GetDCS(), 1);
//			InstanceSwitchRenderable	*smoke_2_morph_instance_switch =
//				new InstanceSwitchRenderable(
//					entity,												// Entity to attach the renderable to
//					InstanceSwitchRenderable::Dynamic,			// How/when to execute the renderable
//					smoke_2_instance,									// the instance to control
//					True,													// Instance is on when trigger is...
//					smoke_2_morph_delay->GetTriggerAttribute());
//#endif
//			//-------------------------------------------
//			// Set dither Z on material for smoke column
//			//-------------------------------------------
//			dpl_MATERIAL *damage_material =
//				dpl_LookupMaterial ("btfx:smoke1_mtl",
//					dpl_lookup_normal,
//					&status);
//			if (damage_material == 0)
//			{
//				std::cout << "couldn't find material\n";
//			}
//			else
//			{
//				dpl_SetMaterialDitherZ(damage_material, 10.0f);
//				dpl_FlushMaterial(damage_material);
//			}
//			//---------------------------------------------------
//			// Create a material morph to fade smoke column away
//			//---------------------------------------------------
//			OneShotDelayRenderable	*smoke_fade_delay =
//				new OneShotDelayRenderable(
//					entity,												// Entity to attach the renderable to
//					OneShotDelayRenderable::Dynamic,				// How/when to execute the renderable
//					25.0f);												// How long to wait before raising the trigger
//			SweepRenderable *smoke_fade_sweep =
//				new SweepRenderable(
//					entity,								// Entity to attach the renderable to
//					SweepRenderable::Dynamic,		// How/when to execute the renderable
//					18.5f, 								// How long to take to sweep from 0 to 1
//					1,										// number of times to cycle before stopping
//					smoke_fade_delay->GetTriggerAttribute());		// trigger variable
//			Register_Object(smoke_fade_sweep);
//			// Lookup texture for smoke column
//			dpl_TEXTURE *smoke_texture =
//				dpl_LookupTexture("btfx:smoke1_scr_tex", dpl_lookup_normal, &status);
//			if (smoke_texture == NULL)
//				DEBUG_STREAM<<"couldn't find texture btfx:smoke1_scr_tex for an effect\n" << std::flush;
//			//
//			MorphMaterialRenderable *smoke_fade_material =
//				new MorphMaterialRenderable(
//					entity,										// Entity to attach the renderable to
//					MorphMaterialRenderable::Dynamic,	// How/when to execute the renderable
//					1.0f,1.0f,1.0f,							// Material's ambient component
//					0.7f,0.4f,0.4f,							// Material's emissive component
//					0.3714f,0.2899f,0.3714f,				// Material's diffuse component
//					0.0f,0.0f,0.0f,0.0f,						// Material's specular component
//					0.7f,0.99f,0.0f,							// Material's opacity
//					smoke_texture,								// Material's texture pointer
//					10.0f,										// Material's Z dither value
//					3,												// Material's Fog Imunity value
//					1.0f,1.0f,1.0f,							// Material's ambient component
//					0.7f,0.4f,0.4f,							// Material's emissive component
//					0.3714f,0.2899f,0.3714f,				// Material's diffuse component
//					0.0f,0.0f,0.0f,0.0f,						// Material's specular component
//					0.0f,0.99f,0.0f,							// Material's opacity
//					10.0f, 										// Material's Z dither value
//					smoke_fade_sweep->GetSweepAttribute());
//			Register_Object(smoke_fade_material);
////			dpl_INSTANCE *smoke_1_instance = dpl_GetDCSInstance(smoke_1_morph->GetDCS(), 1);
//			if (!smoke_1_instance)
//				Fail("smoke_1_instance came back null\n");
//			dpl_SetInstanceFrontMaterial(smoke_1_instance, smoke_fade_material->GetMaterial());
//			dpl_FlushInstance(smoke_1_instance);
//#endif
//			#else
//			DEBUG_STREAM <<"Explosion effect 104 called, this is disabled and shouldn't be used!\n" << std::flush;
//			#endif
//			break;
//		}
//		default:
//		{
//			break;
//		}
//	}
}
//
//#############################################################################
// MakeEntityRenderables handles creating all the renderables necessary to
// display an object.  This routine contains default behaviors for creating
// some types of simple objects.  The idea is that if a higher level routine
// can't figure out how to make renderables for something this routine will be
// called and the default behavior will be used.
//#############################################################################
//
void
	DPLRenderer::MakeEntityRenderables(
		Entity				*entity,			// The entity we are dealing with
		ResourceDescription	*model_resource,	// Pointer to the video resource
		ViewFrom			view_type) 			// Type of reference (inside/outside...etc.)
{
//STUBBED: DPL RB 1/14/07
	char *object_filename;
	#if DEBUG_LEVEL > 0
		int object_count;
	#endif
	L4VideoObject *video_object;
	L4VideoObjectWrapper *video_wrapper;
	ChainOf<L4VideoObjectWrapper*> video_chain(NULL);
	L4VideoObject::ResourceType resource_type;
//	dpl_DCS *my_root_dcs;
	Enumeration renderer_modes;
	//
	// Set the Entity_Being_Created global so the C language callback will
	// be able to mark the geometry with damage zone values if necessary.
	//
	Entity_Being_Created = entity;
//	my_root_dcs = NULL;
	//
	// convert video resource into chain of video objects and make an iterator
	// for that chain
	//
	if (model_resource)
	{
		#if DEBUG_LEVEL > 0
			object_count =
		#endif
		L4VideoObjectWrapper::BuildVideoObjectChainFromResource(&video_chain, model_resource);
	}
	ChainIteratorOf<L4VideoObjectWrapper*> video_iterator(video_chain);
	//
	// Switch to allow us to have scripts at this level for constructing certain
	// types of video objects (whether or not they have a video resource)
	//
	switch (entity->GetClassID())
	{
		//
		// Dropzones have no graphical appearance so we do nothing
		//
		case DropZoneClassID:
			break;
		//
		// Player objects have no graphical appearance unless one is created
		// at a higher (game specific) level, so we do nothing here.
		//
		case PlayerClassID:
			break;
		// this entity has no visual appearance
		case AudioEntityClassID:
			break;
		//
		// Cultural and landmark are the only ones with "destroyed" processing
		// This is similar to the default case but does not allow us to be
		// inside the entity, does not allow us to be a mover,
		//
		case CulturalIconClassID:
		case LandmarkClassID:
		{
			dpl_INSTANCE *this_instance;
			d3d_OBJECT *this_object;
			dpl_ISECT_MODE intersect_mode;
			HierarchicalDrawComponent *component = NULL;
			uint32 intersect_mask;
			LinearMatrix offset_matrix = LinearMatrix::Identity;
			//dpl_DCS *root_DCS, *this_DCS;
			//
			// Make sure the object has a video resource
			//
			if (!model_resource)
			{
				VideoRenderer::MakeEntityRenderables(entity, model_resource, view_type);
				Entity_Being_Created = NULL;
				return;
			}
//			intersect_mode = dpl_isect_mode_geometry;
			intersect_mask = INTERSECT_ALL;
			Logical first_object = True;
			video_iterator.First();
			while ((video_wrapper = video_iterator.ReadAndNext()) != NULL)
			{
				video_object		= video_wrapper->GetVideoObject();
				object_filename	= video_object->GetObjectFilename();
				resource_type		= video_object->GetResourceType();
				renderer_modes		= video_object->GetRendererModes();

				#if NOISY_RENDERER
				Tell("L4VIDEO.cpp loading object " << object_filename);
				Tell(" type " << resource_type);
				Tell(" mode 0x" <<std::hex<<renderer_modes<<std::dec<< "." << std::endl);
				#endif

				if ((resource_type != L4VideoObject::Object) &&
					 (resource_type != L4VideoObject::Rubble))
				{
					DEBUG_STREAM << "L4VIDEO.cpp wrong video resource type for object "<<object_filename<<"\n" << std::flush;
					continue;	// next object
				}

				SET_VIDEO_LOAD_OBJECT();
				// HACK !!! load the object as uncached so entity identification will work right
//				this_object = dpl_LoadObject(object_filename, dpl_load_normal);
				this_object = d3d_OBJECT::LoadObject(mDevice, object_filename);
				CLEAR_VIDEO_LOAD_OBJECT();

				if (this_object == NULL)
				{
					DEBUG_STREAM << "L4VIDEO.cpp couldn't load object "<<object_filename<<"\n" << std::flush;
					if (!first_object)
					{
						continue;	// next object
					}
				}
				if (first_object)
				{
					first_object = False;
					component = new RootRenderable(
							entity,							// Entity to attach the renderable to
							RootRenderable::Static,		// How/when to execute the renderable
							this_object,					// object to hang on the DCS, may be a list later <NULL>
							false,					// DPL Zone this stuff will live in (for culling)
							intersect_mode,				// type of intersections to do on this object
							intersect_mask);				// intersection mask for the object
					//root_DCS = this_static_root->GetDCS();
					//------------------------------------------------------
					// if root object billboards (all others billboard too)
					//------------------------------------------------------
					//this_DCS = root_DCS;
//					this_instance = this_static_root->GetInstance();
					//
					// Set my_root_dcs because we want this guy's hiearchy to be marked
					// with his entity pointer
					//
//					my_root_dcs = root_DCS;
				}
				else
				{
					if (renderer_modes | L4VideoObject::BillboardObject)
					{
						//------------------------------------------
						// attach additional object to separate DCS
						// because it is billboarded
						//------------------------------------------
						component = new DPLStaticChildRenderable(
								entity,
								false,
								this_object,
								intersect_mode,
								intersect_mask,
								offset_matrix,
								NULL);
//						this_DCS = this_child->GetDCS();
//						this_instance = this_child->GetInstance();
					}
					else
					{
						//----------------------------------------
						// attach additional objects to root_DCS
						// (HACK) temporary implementation (HACK)
						//----------------------------------------
						component = new DCSInstanceRenderable(
								entity,									// Entity to attach the renderable to
								DCSInstanceRenderable::Static,	// How/when to execute the renderable
								this_object,							// object to connect to the instance
								NULL,								// the DCS to add the instance to
								intersect_mode,						// type of intersections to do on this object
								intersect_mask,						// intersection mask for the object
								True);            					// initial visibility setting
						//this_DCS = NULL;
//						this_instance = another_instance->GetInstance();
					}
				}
				// add the new object to our renderables list
				if (component)
					mRenderables.Add(component);
				component = NULL;
				//
				// Hook up the object to an instance switch renderable responsive to state
				//
				StateIndicator* simulation_state = (StateIndicator *)entity->GetAttributePointer("SimulationState");
				switch(resource_type)
				{
					case L4VideoObject::Object:
					{
						component = new StateInstanceSwitchRenderable(
								entity,													// Entity to attach the renderable to
								StateInstanceSwitchRenderable::Watcher,		// How/when to execute the renderable
								this_instance,											// the instance to control
								False,													// true to turn on in this state, false for off
								simulation_state,										// State dial we use to control the on/off
								CulturalIcon::BurningState);						//	State that we look for
						break;
					}
					case  L4VideoObject::Rubble:
					{
						component = new StateInstanceSwitchRenderable(
								entity,													// Entity to attach the renderable to
								StateInstanceSwitchRenderable::Watcher,		// How/when to execute the renderable
								this_instance,											// the instance to control
								True,														// true to turn on in this state, false for off
								simulation_state,										// State dial we use to control the on/off
								CulturalIcon::BurningState);						//	State that we look for
						break;
					}
				}
				if (component)
					mRenderables.Add(component);
				//----------------------------------
				// billboard object if so indicated
				//----------------------------------
//				if (this_DCS && (renderer_modes & L4VideoObject::BillboardObject))
//				{
//					int axes = dpl_reorient_axes_none;

//					if (renderer_modes & L4VideoObject::BillboardXAxis)
//					{
//						axes |= dpl_reorient_axes_x;
//					}
//					if (renderer_modes & L4VideoObject::BillboardYAxis)
//					{
//						axes |= dpl_reorient_axes_y;
//					}
//					if (renderer_modes & L4VideoObject::BillboardZAxis)
//					{
//						axes |= dpl_reorient_axes_z;
//					}
//					dpl_SetDCSReorientAxes(this_DCS, (dpl_REORIENT_AXES)axes);
//					dpl_FlushDCS(this_DCS);
//				}
			}
			break;
		}
		//
		// Case to handle rivets using the fast projectile code
		//
		case RivetClassID:
		{
			d3d_OBJECT
				*this_object;
			video_iterator.First();
				video_wrapper 		= video_iterator.ReadAndNext();
				Check(video_wrapper);
				video_object 		= video_wrapper->GetVideoObject();
				Check_Pointer(video_object);
				object_filename	= video_object->GetObjectFilename();
				this_object 		= d3d_OBJECT::LoadObject(GetDevice(), object_filename);
			#if DEBUG_LEVEL > 0
			ProjectileRootRenderable *projectile =
         #endif
				new ProjectileRootRenderable(
					entity,										// Entity to attach the renderable to
					ProjectileRootRenderable::Dynamic,	// How/when to execute the renderable
					this_object,								// object to hang on the DCS, may be a list later <NULL>
					false);								// DPL Zone this stuff will live in (for culling)
			Register_Object(projectile);
			break;
		}
		//
		// Script for generating renderables for eyecandy
		//
		case EyeCandyClassID:
		{
			int effect_number;

			dpl_ISECT_MODE dpl_isect_mode_obj;
			RootRenderable *this_root =
				new RootRenderable(
					entity,							// Entity to attach the renderable to
					RootRenderable::Dynamic,	// How/when to execute the renderable
					NULL,								// object to hang on the DCS, may be a list later <NULL>
					false,					// DPL Zone this stuff will live in (for culling)
					dpl_isect_mode_obj,			// type of intersections to do on this object
					NULL);							// intersection mask for the object
			Register_Object(this_root);
			StateIndicator* simulation_state = (StateIndicator *)entity->GetAttributePointer("SimulationState");

			video_iterator.First();
			while ((video_wrapper = video_iterator.ReadAndNext()) != NULL)
			{
				video_object = video_wrapper->GetVideoObject();
				effect_number = atoi(video_object->GetObjectFilename());
				#if DEBUG_LEVEL > 0
				DPLSFXRenderable *this_effect =
				#endif
					new DPLSFXRenderable(
						entity,							// Entity to attach the effect to
						false,					// DPL zone everything will be in
						Point3D::Identity,			// Point offset from the parent DCS
						this_root,			// Parent DCS (can be NULL for world)
						simulation_state,				// Trigger effect when this state changes
						EyeCandy::effectOn,			// Trigger effect when in this state
						effect_number,					// Type of effect to trigger
						.01);								// Effect repeat speed.
				Register_Object(this_effect);
			}
			break;
		}
		//
		// Script for generating an explosion of type specified in the resource file
		//
		case ExplosionClassID:
		{
			DEBUG_STREAM << "Explosion Created in MakeEntityRenderables:" << std::endl << std::flush;
			int effect_number;

			video_iterator.First();
			while ((video_wrapper = video_iterator.ReadAndNext()) != NULL)
			{
				video_object = video_wrapper->GetVideoObject();
				effect_number = atoi(video_object->GetObjectFilename());
				DEBUG_STREAM << "   ** effect_number = " << effect_number << std::endl << std::flush;
				if(effect_number < 100 || effect_number >= 1000)
				{
					DEBUG_STREAM << "   ** DPLIndependantEffect(["
							<< entity->localOrigin.linearPosition.x
							<< ", " << entity->localOrigin.linearPosition.y
							<< ", " << entity->localOrigin.linearPosition.z << "], " << effect_number << ");" << std::endl << std::flush;
					DPLIndependantEffect(
						entity->localOrigin.linearPosition,
						effect_number);
				}
				else
				{
					DEBUG_STREAM << "   ** ExplosionScripts(*entity*, RES["
						<< model_resource->resourceID << " - " << model_resource->resourceName << "], "
						<< "ViewFrom::" << (view_type == ViewFrom::insideEntity ? "insideEntity" : (view_type == ViewFrom::outsideEntity ? "outsideEntity" : "collisionEntity")) 
						<< ", " << (effect_number - 100) << ");" << std::endl << std::flush;
					ExplosionScripts(
						entity,				// The entity we are dealing with
						model_resource,	// Pointer to the video resource
						view_type, 			// Type of reference (inside/outside...etc.)
						effect_number - 100);
				}
			}
			break;
		}
		case CameraDirectorClassID:
		{
			//
			//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			// Create the CameraDirector HUD Renderable if not a Replicant
			//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			//
			if (entity->GetInstance() == CameraDirector::MasterInstance)
			{
				CameraDirector *camera_director = (CameraDirector*) entity;
				Check_Pointer(camera_director);

				int *player_index = &camera_director->goalPlayerIndex;
				Check_Pointer(player_index);

				Logical *display_rank_window = &camera_director->displayRankingWindow;
				Check_Pointer(display_rank_window);

				mCamShipHUD = new CameraShipHUDRenderable(entity, CameraShipHUDRenderable::Dynamic, player_index, display_rank_window);
			}
			break;
		}
		//
		//	Script for a drivable camera, the camera is invisible to other players
		//
		case CameraShipClassID:
		{
			if(view_type == insideEntity)
			{
				//
				// Build an empty root renderable and an eye renderable
				//
				dpl_ISECT_MODE dpl_isect_mode_obj;
				RootRenderable *this_root =
					new RootRenderable(
						entity,							// Entity to attach the renderable to
						RootRenderable::Dynamic,	// How/when to execute the renderable
						NULL,								// object to hang on the DCS, may be a list later <NULL>
						false,					// DPL Zone this stuff will live in (for culling)
						dpl_isect_mode_obj,			// type of intersections to do on this object
						NULL);							// intersection mask for the object
				Register_Object(this_root);

				#if 0 //DEBUG_LEVEL > 0
				DPLEyeRenderable* this_eye	=
				#endif
					mCamera =
						new DPLEyeRenderable(
							entity,
							LinearMatrix::Identity,
							this_root,
							NULL
						);
				Register_Object(this_eye);
			}
			break;
		}
		//
		// Script for doorframe, so it can be used in any game
		//
		case DoorFrameClassID:
		{
			Verify( object_count == 6 );
			//------------------------------------------------
			// First video object is root shape for the door
			// followed by left door shape, right door shape,
			// door lights, left door lights, and right door
			// lights.
			//------------------------------------------------
			d3d_OBJECT
				*object,
				*left,
				*right,
				*object_lights,
				*left_lights,
				*right_lights;
			int object_number = 0;

			video_iterator.First();
			while ((video_wrapper = video_iterator.ReadAndNext()) != NULL)
			{
				video_object = video_wrapper->GetVideoObject();
				object_filename = video_object->GetObjectFilename();

				#if NOISY_RENDERER
				Tell("L4VIDEO.cpp loading door object "<<object_filename<<"\n");
				#endif
				switch (object_number)
				{
					case 0:
//						object		 = dpl_LoadObject(object_filename, dpl_load_normal);
						object = d3d_OBJECT::LoadObject(mDevice, object_filename);
						break;
					case 1:
//						left			 = dpl_LoadObject(object_filename, dpl_load_normal);
						left = d3d_OBJECT::LoadObject(mDevice, object_filename);
						break;
					case 2:
//						right			 = dpl_LoadObject(object_filename, dpl_load_normal);
						right = d3d_OBJECT::LoadObject(mDevice, object_filename);
						break;
					case 3:
//						object_lights = dpl_LoadObject(object_filename, dpl_load_normal);
						object_lights = d3d_OBJECT::LoadObject(mDevice, object_filename);
						break;
					case 4:
//						left_lights	 = dpl_LoadObject(object_filename, dpl_load_normal);
						left_lights = d3d_OBJECT::LoadObject(mDevice, object_filename);
						break;
					case 5:
//						right_lights = dpl_LoadObject(object_filename, dpl_load_normal);
						right_lights = d3d_OBJECT::LoadObject(mDevice, object_filename);
						break;
					default:
						// ignore any additional objects
						break;
				}
				++object_number;
			}
			//
			//	HACK Hard Coded Doorframes SubsystemArray access
			//
			Door *left_door_sub = (Door*) entity->GetSubsystem(0);
			Point3D*	left_door_position = &left_door_sub->currentPosition;
			Door *right_door_sub = (Door*) entity->GetSubsystem(1);
			Point3D*	right_door_position = &right_door_sub->currentPosition;
			dpl_ISECT_MODE dpl_isect_mode_obj;
			RootRenderable *door_sill =
				new RootRenderable(
					entity,							// Entity to attach the renderable to
					RootRenderable::Static,		// How/when to execute the renderable
					object,							// object to hang on the DCS, may be a list later <NULL>
					false,					// DPL Zone this stuff will live in (for culling)
					dpl_isect_mode_obj,			// type of intersections to do on this object
					NULL);							// intersection mask for the object
			Register_Object(door_sill);
			//
			// Set my_root_dcs because we want this guy's hiearchy to be marked
			// with his entity pointer
			//
//			my_root_dcs = door_sill->GetDCS();
			LinearMatrix	my_ident(True);
			DPLChildPointRenderable* left_door =
				new DPLChildPointRenderable(
					entity,
					false,
					left,
					dpl_isect_mode_obj,
					NULL,
					my_ident,
					door_sill,
					left_door_position);
			Register_Object(left_door);
			DPLChildPointRenderable* right_door =
				new DPLChildPointRenderable(
					entity,
					false,
					right,
					dpl_isect_mode_obj,
					NULL,
					my_ident,
					door_sill,
					right_door_position);
			Register_Object(right_door);
			#if DEBUG_LEVEL > 0
			DCSInstanceRenderable *door_sill_lights_instance =
			#endif
				new DCSInstanceRenderable(
					entity,									// Entity to attach the renderable to
					DCSInstanceRenderable::Static,	// How/when to execute the renderable
					object_lights,							// object to connect to the instance
					door_sill,					// the DCS to add the instance to
					dpl_isect_mode_obj,					// type of intersections to do on this object
					NULL,										// intersection mask for the object
					True);            					// initial visibility setting
			Register_Object(door_sill_lights_instance);
			#if DEBUG_LEVEL > 0
			DCSInstanceRenderable *left_door_lights_instance =
			#endif
				new DCSInstanceRenderable(
					entity,									// Entity to attach the renderable to
					DCSInstanceRenderable::Static,	// How/when to execute the renderable
					left_lights,							// object to connect to the instance
					left_door,					// the DCS to add the instance to
					dpl_isect_mode_obj,					// type of intersections to do on this object
					NULL,										// intersection mask for the object
					True);            					// initial visibility setting
			Register_Object(left_door_lights_instance);
			#if DEBUG_LEVEL > 0
			DCSInstanceRenderable *right_door_lights_instance =
			#endif
				new DCSInstanceRenderable(
					entity,									// Entity to attach the renderable to
					DCSInstanceRenderable::Static,	// How/when to execute the renderable
					right_lights,							// object to connect to the instance
					right_door,				// the DCS to add the instance to
					dpl_isect_mode_obj,					// type of intersections to do on this object
					NULL,										// intersection mask for the object
					True);            					// initial visibility setting
			Register_Object(right_door_lights_instance);
			break;
		}
		//
		// This is the script run on anything that isn't already listed above
		//
		default:
		{
			d3d_OBJECT *this_object;
			dpl_ISECT_MODE intersect_mode;
			uint32 intersect_mask;
			LinearMatrix offset_matrix = LinearMatrix::Identity;
			Component *component = NULL;
			HierarchicalDrawComponent *rootCom = NULL;
			HierarchicalDrawComponent *thisCom = NULL;
			//
			// First, establish that this level doesn't know what to do
			// if the object has no video resource.
			//
			if (!model_resource)
			{
				VideoRenderer::MakeEntityRenderables(entity, model_resource, view_type);
				Entity_Being_Created = NULL;
				return;
			}
			//
			// If we're inside the entity, set up the intersect mode and mask so we
			// won't intersect ourselves with the pickpoint.  Other items get full
			// geometry intersection.
			//
			if (view_type == insideEntity)
			{
//				intersect_mode =	dpl_isect_mode_obj;
				intersect_mask	=  NULL;
			}
			else
			{
//				intersect_mode =	dpl_isect_mode_geometry;
				intersect_mask	=  INTERSECT_ALL;
			}

			Logical first_object = True;

			video_iterator.First();
			while ((video_wrapper = video_iterator.ReadAndNext()) != NULL)
			{
				video_object = video_wrapper->GetVideoObject();
				object_filename = video_object->GetObjectFilename();
				resource_type = video_object->GetResourceType();
				renderer_modes = video_object->GetRendererModes();

				#if NOISY_RENDERER
				Tell("L4VIDEO.cpp loading object " << object_filename);
				Tell(" type " << resource_type);
				Tell(" mode 0x" <<std::hex<<renderer_modes<<std::dec<< "." << std::endl);
				#endif

				if ((resource_type != L4VideoObject::Object) && (resource_type != L4VideoObject::Rubble))
				{
					DEBUG_STREAM << "L4VIDEO.cpp wrong video resource type for object "<<object_filename<<"\n" << std::flush;
					continue;	// next object
				}

				SET_VIDEO_LOAD_OBJECT();
				this_object = d3d_OBJECT::LoadObject(mDevice, object_filename);
				CLEAR_VIDEO_LOAD_OBJECT();

				if (this_object == NULL)
				{
					DEBUG_STREAM << "L4VIDEO.cpp couldn't load object "<<object_filename<<"\n" << std::flush;
					if (!first_object)
					{
						continue;	// next object
					}
				}
				if (first_object)
				{
					first_object = False;
					//
					// Determine if the entity is a mover or not, which tells us what type of
					// renderable to use to construct it.
					//
					if (entity->IsDerivedFrom(*Mover::GetClassDerivations()))
					{
						//
						// It's a mover, construct it with a dynamic root renderable so it can move
						// also remember it's DCS so we can hook other shapes to it later.
						//
						SET_VIDEO_CONSTRUCT_ROOT();
						rootCom = new RootRenderable(
								entity,						// Entity to attach the renderable to
								RootRenderable::Dynamic,	// How/when to execute the renderable
								this_object,				// object to hang on the DCS, may be a list later <NULL>
								false,				// DPL Zone this stuff will live in (for culling)
								intersect_mode,				// type of intersections to do on this object
								intersect_mask);			// intersection mask for the object
						Register_Object(this_root);
						CLEAR_VIDEO_CONSTRUCT_ROOT();
					}
					else
					{
						//
						// It's a static, construct it with a static RootRenderable and
						// remember it's DCS so we can hook other shapes to it later.
						//
						rootCom = new RootRenderable(
								entity,						// Entity to attach the renderable to
								RootRenderable::Static,		// How/when to execute the renderable
								this_object,				// object to hang on the DCS, may be a list later <NULL>
								false,				// DPL Zone this stuff will live in (for culling)
								intersect_mode,				// type of intersections to do on this object
								intersect_mask);			// intersection mask for the object
					}
					//
					// Set my_root_dcs because we want this guy's hiearchy to be marked
					// with his entity pointer
					//
//					my_root_dcs = root_DCS;
					//
					// If we are inside the entity, then we must build an eyepoint for it too.
					// since there is no special construction, we build the eyepoint with a
					// zero offset.
					//
					if (view_type == insideEntity)
					{
						EulerAngles *eyepoint_rotation = (EulerAngles *)entity->GetAttributePointer("EyepointRotation");
						#if 0 //DEBUG_LEVEL > 0
						DPLEyeRenderable *this_eye	=
						#endif
							mCamera =
							new DPLEyeRenderable(
								entity,
								LinearMatrix::Identity,
								rootCom,
								eyepoint_rotation);
						Register_Object(this_eye);
					}
					//------------------------------------------------------
					// if root object billboards (all others billboard too)
					//------------------------------------------------------
//					this_DCS = root_DCS;
				}
				else
				{
					if (renderer_modes & L4VideoObject::BillboardObject)
					{
						//------------------------------------------
						// attach additional object to separate DCS
						// because it is billboarded
						//------------------------------------------
						thisCom = new DPLStaticChildRenderable(
								entity,
								false,
								this_object,
								intersect_mode,
								intersect_mask,
								offset_matrix,
								rootCom);
						Register_Object(this_child);
//						this_DCS = this_child->GetDCS();
					}
					else
					{
						//----------------------------------------
						// attach additional objects to root_DCS
						// (HACK) temporary implementation (HACK)
						//----------------------------------------
						thisCom = new DCSInstanceRenderable(
								entity,								// Entity to attach the renderable to
								DCSInstanceRenderable::Static,		// How/when to execute the renderable
								this_object,						// object to connect to the instance
								rootCom,							// the DCS to add the instance to
								intersect_mode,						// type of intersections to do on this object
								intersect_mask,						// intersection mask for the object
								True);            					// initial visibility setting
						Register_Object(another_instance);
//						this_DCS = NULL;
					}
				}
				//----------------------------------
				// billboard object if so indicated
				//----------------------------------
				if (thisCom && (renderer_modes & L4VideoObject::BillboardObject))
				{
//					int axes = dpl_reorient_axes_none;

					if (renderer_modes & L4VideoObject::BillboardXAxis)
					{
//						axes |= dpl_reorient_axes_x;
					}
					if (renderer_modes & L4VideoObject::BillboardYAxis)
					{
//						axes |= dpl_reorient_axes_y;
					}
					if (renderer_modes & L4VideoObject::BillboardZAxis)
					{
//						axes |= dpl_reorient_axes_z;
					}
//					dpl_SetDCSReorientAxes(this_DCS, (dpl_REORIENT_AXES)axes);
//					dpl_FlushDCS(this_DCS);
				}

				//MOVED THIS TO ROOTRENDERABLE - Was this a hack?
				//mRenderables.Add(component);
			}
			break;
		}
	}
	//
	// release the video chain memory
	//
	L4VideoObjectWrapper::DeleteVideoObjectChain(&video_chain);
	//
	// Clear the entity pointer passed to the callback system
	//
	Entity_Being_Created = NULL;
	//
	// If my_root_dcs is non-null, mark the entity's DCS hiearchy with it's
	// entity pointer.
	//
//	if(my_root_dcs)
//	{
//		MarkDCSHiearchy(my_root_dcs,entity);
//#if 0
//		if(entity->GetClassID() == DemolitionPackClassID)
//		{
//			Point3D temp_point(0.0,0.0,0.0);
//			#if DEBUG_LEVEL > 0
//			OnePSFXRenderable	*this_effect=
//			#endif
//				new OnePSFXRenderable(
//					entity,								// Entity to attach the renderable to
//					OnePSFXRenderable::Static,		// How/when to execute the renderable
//					myPSFXDescriptons[3],			// name of file with the PFX description in it
//					my_root_dcs,						// DCS the effect is relative to (may be NULL)
//					&temp_point);						// Offset (or world coordinants if DCS is NULL)
//			Register_Object(this_effect);
//		}
//#endif
//	}
	Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// This should be called prior to the rendering of a frame to setup the culling
// data the renderer keeps (mostly the world to eye transform)
//
void
	DPLRenderer::SetupCull()
{
	Entity
		*linked_entity;
	LinearMatrix
		site_to_world,
		world_to_site,
		eye_rotation,
		eye_inverted;
	EntitySegment
		*eyepoint_segment;
	EulerAngles
		*eyepoint_rotation;
	//
	// To test the functionality, this is not as efficient as it could be.
	// when it gets fully patched into the renderer it will be improved.
	//
	// Figure out what type of entity this is.
	//
	linked_entity		=	GetLinkedEntity();
	eyepoint_rotation	= (EulerAngles*)linked_entity->GetAttributePointer("EyepointRotation");
	if(linked_entity->IsDerivedFrom(*JointedMover::GetClassDerivations()))
	{
		JointedMover
			*linked_jointed_mover;

		linked_jointed_mover 	= Cast_Object(JointedMover*, linked_entity);
		eyepoint_segment			= linked_jointed_mover->GetSegment("siteeyepoint");
		if(!eyepoint_segment)
		{
			Fail("DPLRenderer::SetupCull jointed mover had no siteeyepoint\n");
		}
		if(!eyepoint_rotation)
		{
			Fail("DPLRenderer::SetupCull jointed mover had no EyepointRotation attribute\n");
		}
		linked_jointed_mover->GetSegmentToWorld(*eyepoint_segment, &site_to_world);
		if(eyepoint_rotation)
		{
			world_to_site.Invert(site_to_world);
			eye_rotation 				= *eyepoint_rotation;
			eye_inverted.Invert(eye_rotation);
			worldToEyeMatrix.Multiply(world_to_site, eye_inverted);
		}
		else
		{
			worldToEyeMatrix.Invert(site_to_world);
		}
	}
	else
	{
		site_to_world = linked_entity->localOrigin;
		if(eyepoint_rotation)
		{
			world_to_site.Invert(site_to_world);
			eye_rotation 				= *eyepoint_rotation;
			eye_inverted.Invert(eye_rotation);
			worldToEyeMatrix.Multiply(world_to_site, eye_inverted);
		}
		else
		{
			worldToEyeMatrix.Invert(site_to_world);
		}
	}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
	DPLRenderer::ResetStatistics()
{
	total_cull 			= 0;
	total_draw 			= 0;
	total_pixelplanes = 0;
	total_frame_time 	= 0;
	frame_count 		= 0;
	target_frame_time	= 56000;
	target_frame_count= 0;
	report_time = currentFrameTime + 60.0f;
}
void
	DPLRenderer::ReportStatistics()
{
	if(frame_count != 0)
	{
		std::cout<<"Frames "<<frame_count<<"\n";
		std::cout<<((float)target_frame_count/(float)frame_count)*100.0f<<"% of the frames were under the target frame time\n";
		std::cout<<"Average Cull "<<(unsigned long)((float)total_cull/(float)frame_count)<<"\n";
		std::cout<<"Average Draw "<<(unsigned long)((float)total_draw/(float)frame_count)<<"\n";
		std::cout<<"Average Pixel Planes "<<(unsigned long)((float)total_pixelplanes/(float)frame_count)<<"\n";
		std::cout<<"Average Frame Time "<<(unsigned long)((float)total_frame_time/(float)frame_count)<<"\n";
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Execute Method, performs the rendering of one frame
//
void DPLRenderer::ExecuteImplementation(RendererComplexity, RendererOrigin::InterestingEntityIterator* all_iterator)
{
	Component *component;
	HRESULT hr;

	// timing variables
   __int64 ticks = HiResNowTicks();
#ifdef LOGFRAMERATE
   fputc(0, FRAMERATE_LOG);
   fwrite(&ticks, sizeof(__int64), 1, FRAMERATE_LOG);
#endif
	
		
	int currentAppState = application->GetApplicationState();
	switch (currentAppState)
	{
		case Application::CreatingMission:
		case Application::LoadingMission:
		case Application::WaitingForLaunch:
			//if (mLoadingScreenThread == NULL)
			//{
			//	mLoadingScreenRunning = true;
			//	mLoadingScreenThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ExecuteLoadScreenThread, this, 0, NULL);
			//}

			//hr = mDevice->TestCooperativeLevel();
			//if (hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICENOTRESET)
			//{
			//	mPrimaryDeviceReseting = true;
			//	DEBUG_STREAM << this << " RESETTING DEVICE - WAITING FOR FRAME TO FINISH" << std::endl << std::flush;
			//	while (mRenderingLoadingFrame)
			//	{
			//		Sleep(100);
			//	}

			//	DEBUG_STREAM << this << " RESETTING DEVICE - DONE WAITING FOR FRAME TO FINISH" << std::endl << std::flush;

			//	int bbCount = mPresentParams.BackBufferCount;
			//	int bbWidth = mPresentParams.BackBufferWidth;
			//	int bbHeight = mPresentParams.BackBufferHeight;

			//	ParticleEngine::Destroy();
			//	V(mDevice->Reset(&mPresentParams));
			//	ParticleEngine::Initialize(mDevice);
			//	this->SetCoreRenderStates();

			//	mPresentParams.BackBufferCount = bbCount;
			//	mPresentParams.BackBufferWidth = bbWidth;
			//	mPresentParams.BackBufferHeight = bbHeight;

			//	mPrimaryDeviceReseting = false;
			//}

			ticks = HiResNowTicks();
#ifdef LOGFRAMERATE
			fputc(1, FRAMERATE_LOG);
			fwrite(&ticks, sizeof(__int64), 1, FRAMERATE_LOG);
#endif
			return;

		case Application::LaunchingMission:
		case Application::RunningMission:
			break;
	}
	if (lastAppState != currentAppState && currentAppState == Application::LaunchingMission)
	{
		this->mDevice->SetRenderState(D3DRS_LIGHTING, true);
		this->mDevice->SetTransform(D3DTS_PROJECTION, &this->mProjectionMatrix);
		this->mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, D3DCOLOR_ARGB(128, 255, 255, 255));
		this->mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
	}
	lastAppState = currentAppState;
	
	// before we execute everything we need to clear
	// the render lists
	memset(mRenderLists, 0, sizeof(mRenderLists));

	HierarchicalDrawComponent *drawComp;
	SChainIteratorOf<HierarchicalDrawComponent*> iterator(&mRenderables);
	while ((drawComp = iterator.ReadAndNext()) != NULL)
		drawComp->Execute();

	if (mReticle)
		mReticle->Execute();

	if (mCamShipHUD)
		mCamShipHUD->Execute();

	gNumBatches = 0;
	static Time lastFrameTime = mTargetRenderTime;
	Scalar dT = mTargetRenderTime - lastFrameTime;
	lastFrameTime = mTargetRenderTime;
	currentFrameTime = Now();

	DWORD currentFog;
	mDevice->GetRenderState(D3DRS_FOGCOLOR, &currentFog);
	hr = mDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, currentFog, 1.0f, 0);

	hr = mDevice->BeginScene();

	mDevice->SetFVF(L4VERTEX_FVF);

	D3DXMATRIX viewTransform;
	mDevice->GetTransform(D3DTS_VIEW, &viewTransform);

	//
	// Start with the opaque pass
	//
	mDevice->SetRenderState(D3DRS_FOGSTART, *((DWORD*)(&currentFogNear)));
	mDevice->SetRenderState(D3DRS_FOGEND, *((DWORD*)(&currentFogFar)));
	mDevice->SetRenderState(D3DRS_ZWRITEENABLE, true);
	mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
	mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
	mDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
	mDevice->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_DISABLE);

	d3d_OBJECT::ResetState(mDevice);

	if (!l4_application->IsDead())
	{
		std::list<d3d_OBJECT*>::const_iterator iter;

		for (iter = this->mConsolidatedStaticObjects.begin(); iter != this->mConsolidatedStaticObjects.end(); ++iter)
		{
			(*iter)->Draw(PASS_OPAQUE, &viewTransform, mTargetRenderTime);
		}
	}

	for (d3d_OBJECT *obj = mRenderLists[PASS_OPAQUE]; obj != NULL; obj = obj->GetNext(PASS_OPAQUE))
		obj->Draw(PASS_OPAQUE, &viewTransform, mTargetRenderTime);

	//
	// Next up is the decal pass
	//

	mDevice->SetTransform(D3DTS_PROJECTION, &mDecalProjectionMatrix);

	if (!l4_application->IsDead())
	{
		std::list<d3d_OBJECT*>::const_iterator iter;

		for (iter = this->mConsolidatedStaticObjects.begin(); iter != this->mConsolidatedStaticObjects.end(); ++iter)
		{
			(*iter)->Draw(PASS_DECAL, &viewTransform, mTargetRenderTime);
		}
	}

	for (d3d_OBJECT *obj = mRenderLists[PASS_DECAL]; obj != NULL; obj = obj->GetNext(PASS_DECAL))
			obj->Draw(PASS_DECAL, &viewTransform, mTargetRenderTime);

	// 
	// The sphere pass
	//
	
	//Set it up so the fog won't affect spheres' colors so much- extend the near fog plane out
	float fogModNear = currentFogFar;
	float fogModFar = fogModNear + (currentFogFar - currentFogNear);
	mDevice->SetRenderState(D3DRS_FOGSTART, *((DWORD*)(&fogModNear)));
	mDevice->SetRenderState(D3DRS_FOGEND, *((DWORD*)(&fogModFar)));

	for (d3d_OBJECT *obj = mRenderLists[PASS_SPHERE]; obj != NULL; obj = obj->GetNext(PASS_SPHERE))
		obj->Draw(PASS_SPHERE, &viewTransform, mTargetRenderTime);

	//
	// The sky pass
	//
		
	//Further extend the fog distance
	fogModNear = currentFogNear * 3;
	fogModFar = currentFogFar * 6;

	mDevice->SetRenderState(D3DRS_FOGSTART, *((DWORD*)(&fogModNear)));
	mDevice->SetRenderState(D3DRS_FOGEND, *((DWORD*)(&fogModFar)));

	mDevice->SetTransform(D3DTS_PROJECTION, &mProjectionMatrix);


	if (!l4_application->IsDead())
	{
		std::list<d3d_OBJECT*>::const_iterator iter;

		for (iter = this->mConsolidatedStaticObjects.begin(); iter != this->mConsolidatedStaticObjects.end(); ++iter)
		{
			(*iter)->Draw(PASS_SKY, &viewTransform, mTargetRenderTime);
		}
	}

	for (d3d_OBJECT *obj = mRenderLists[PASS_SKY]; obj != NULL; obj = obj->GetNext(PASS_SKY))
		obj->Draw(PASS_SKY, &viewTransform, mTargetRenderTime);

	//Reactivate fog
	mDevice->SetRenderState(D3DRS_FOGSTART, *((DWORD*)(&currentFogNear)));
	mDevice->SetRenderState(D3DRS_FOGEND, *((DWORD*)(&currentFogFar)));

	//
	// Finally we do the alpha blend pass
	//
	mDevice->SetRenderState(D3DRS_ZWRITEENABLE,false);
	mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,true);
	mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);

	if (!l4_application->IsDead())
	{
		std::list<d3d_OBJECT*>::const_iterator iter;

		for (iter = this->mConsolidatedStaticObjects.begin(); iter != this->mConsolidatedStaticObjects.end(); ++iter)
		{
			(*iter)->Draw(PASS_ALPHABLEND, &viewTransform, mTargetRenderTime);
		}
	}

	for (d3d_OBJECT *obj = mRenderLists[PASS_ALPHABLEND]; obj != NULL; obj = obj->GetNext(PASS_ALPHABLEND))
		obj->Draw(PASS_ALPHABLEND, &viewTransform, mTargetRenderTime);

	//
	// And don't forget particles too
	//
	D3DXMATRIX ident;
	mDevice->SetTransform(D3DTS_WORLD, D3DXMatrixIdentity(&ident));


	if (!l4_application->IsDead())
	{
		ParticleEngine::RenderParticles(&viewTransform, dT);

		for (int i=0; i<MAX_INDIE_EMITTERS; ++i)
			myPSFXEmitters[i].Execute();
	}

	//
	// Wrap it up by doing the 2D pass
	//
	mDevice->SetFVF(L4VERTEX_2D_FVF);
	mDevice->SetRenderState(D3DRS_ZWRITEENABLE, true);
	mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
	mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
	mDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE);
	mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
	mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
	mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_TEXTURE);
	mDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
	mDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);

	if (mReticle && !l4_application->IsDead())
		mReticle->Render(0, &viewTransform);

	if (mCamShipHUD)
		mCamShipHUD->Render(0, &viewTransform);

	hr = mDevice->EndScene();

	hr = mDevice->Present(NULL, NULL, NULL, NULL);
	if (hr == D3DERR_DEVICELOST)
	{
		int bbCount = mPresentParams.BackBufferCount;
		int bbWidth = mPresentParams.BackBufferWidth;
		int bbHeight = mPresentParams.BackBufferHeight;

		ParticleEngine::Destroy();
		V(mDevice->Reset(&mPresentParams));
		ParticleEngine::Initialize(mDevice);
		this->SetCoreRenderStates();

		mPresentParams.BackBufferCount = bbCount;
		mPresentParams.BackBufferWidth = bbWidth;
		mPresentParams.BackBufferHeight = bbHeight;
	}

	ticks = HiResNowTicks();

#ifdef LOGFRAMERATE
	fputc(1, FRAMERATE_LOG);
	fwrite(&ticks, sizeof(__int64), 1, FRAMERATE_LOG);
#endif
}

void DPLRenderer::ExecuteIdle()
{
	HRESULT hr;

	hr = mDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0xFF000000, 1.0f, 0);

	hr = mDevice->BeginScene();

	hr = mDevice->EndScene();

	if (mDevice->Present(NULL, NULL, NULL, NULL) == D3DERR_DEVICELOST)
	{
		int bbCount = mPresentParams.BackBufferCount;
		int bbWidth = mPresentParams.BackBufferWidth;
		int bbHeight = mPresentParams.BackBufferHeight;

		ParticleEngine::Destroy();
		V(mDevice->Reset(&mPresentParams));
		ParticleEngine::Initialize(mDevice);
		this->SetCoreRenderStates();

		mPresentParams.BackBufferCount = bbCount;
		mPresentParams.BackBufferWidth = bbWidth;
		mPresentParams.BackBufferHeight = bbHeight;
	}
}
//
//#############################################################################
// DPLDelayDCSFlush and DPLDoDCSBatchFlush queue up a list of DCS pointers
// for later std::flushing in one big batch.
//#############################################################################
//
void
	DPLRenderer::DPLDelayDCSFlush(
		dpl_DCS	*my_dcs)			// The DCS we want to remember for later
{
	//
	// Make sure the array hasn't become overfilled somehow and make
	// sure the DCS is valid.
	//
	Verify(delayedDCSCount <= DELAY_DCS_FLUSH_ARRAY_SIZE);
	Check_Pointer(my_dcs);
	//
	// If the array is full, std::flush it out to make space for this DCS
	//
	if(delayedDCSCount == DELAY_DCS_FLUSH_ARRAY_SIZE)
	{
		DPLDoDCSBatchFlush();
	}
	//
	// Add the New DCS to the list
	//
	delayDCSFlushArray[delayedDCSCount++]	=	my_dcs;
}
void
	DPLRenderer::DPLDoDCSBatchFlush()			// Flush the dcs's remembered by DPLDelayDCSFlush
{
	//STUBBED: DPL RB 1/14/07
	//SET_VIDEO_BATCH_FLUSH();
	////
	//// Make sure the array hasn't become overfilled somehow
	////
	//Verify(delayedDCSCount <= DELAY_DCS_FLUSH_ARRAY_SIZE);
	////
	//// Flush the array and reset the counters that go with it
	////
	//if(delayedDCSCount != 0)
	//{
	//	delayDCSFlushArray[delayedDCSCount] = NULL;
	//	dpl_FlushDCSArticulations(delayDCSFlushArray);
	//	delayedDCSCount							= 0;
	//}
	//CLEAR_VIDEO_BATCH_FLUSH();
}
//
//#############################################################################
// DPLReportFreeMemory writes current free memory in graphics card to any
// output stream.
//#############################################################################
//
void
	DPLRenderer::DPLReportFreeMemory(std::ostream &output)
{
//STUBBED: DPL RB 1/14/07
//	output << "Free memory in card:  " << dpl_FreeMemory() << " bytes." << std::endl;
	return;
}
//
//#############################################################################
// DPLReportPerfStats writes performance statistics to std::cout (stdout).
//#############################################################################
//
void
	DPLRenderer::DPLReportPerfStats(std::ostream &output)
{
	//STUBBED: DPL RB 1/15/07
	////-----------------------------------------------------
	//// HACK - copied from camera.c must re-copy if changed
	////
	//// case '?':
	////		printf ("sect time %d dcs 0x%x inst 0x%x\n",
	////			 __sect_time, sect_dcs, sect_inst );
	////-----------------------------------------------------
	//output << "sect time " << __sect_time <<
	//	" dcs and inst not available" << std::endl;

	////------------------------------------------------------------
	//// HACK - copied from dpl_vpx.c must re-copy if changed
	////
	//// void dpl_PerfStats(void)
	//// 	printf ( "cull %d draw %d frame %d pxpl %d prims %d\n",
	//// 			__last_cull_time,
	//// 			__last_draw_time,
	//// 			__last_frame_time,
	//// 			__last_pxpl_time,
	//// 			__last_frame_prims );
	////------------------------------------------------------------
	//output <<
	//	"cull "   << __last_cull_time <<
	//	" draw "  << __last_draw_time <<
	//	" frame " << __last_frame_time <<
	//	" pxpl "  << __last_pxpl_time <<
	//	" prims " << __last_frame_prims <<
	//	std::endl;
	//if(statistics_started)
	//{
	//	ReportStatistics();
	//}
	//else
	//{
	//	ResetStatistics();
 //     statistics_started	=	True;
	//}
	//return;
}
//
//#############################################################################
// DPLToggleWireframe toggles the state of dpl global wireframe.
//#############################################################################
//
void
	DPLRenderer::DPLToggleWireframe()
{
	//STUBBBED: DPL RB 1/14/07
	//static Logical wireframe_on = 0;

	//if ((wireframe_on ^= 1) != 0)
	//{
	//	DEBUG_STREAM << "wireframe ON" << std::endl << std::flush;
	//	dpl_SetRenderProperty(dpl_render_prop_wireframe, dpl_render_value_on, NULL );
	//}
	//else
	//{
	//	DEBUG_STREAM << "wireframe OFF" << std::endl << std::flush;
	//	dpl_SetRenderProperty(dpl_render_prop_wireframe, dpl_render_value_off, NULL );
	//}
}
//
//#############################################################################
// DPLTogglePVision toggles the state of dpl "predator" vision.
//#############################################################################
//
void
	DPLRenderer::DPLTogglePVision()
{
	//STUBBED: DPL RB 1/14/07
	//static Logical pvision_on = 0;
	//dpl_EXPLOSION_EFFECT_INFO sfx_info;

	//sfx_info.x = sfx_info.y = sfx_info.z = 0;
	//if ((pvision_on ^= 1) != 0)
	//{
	//	DEBUG_STREAM << "pvision ON" << std::endl << std::flush;
	//	sfx_info.type = -1;
	//}
	//else
	//{
	//	DEBUG_STREAM << "pvision OFF" << std::endl << std::flush;
	//	sfx_info.type = -2;
	//}
	//dpl_Effect(dpl_effect_type_explosion, NULL, &sfx_info);
	//return;
}
//
//#############################################################################
// DPLFrameDump writes screen image to targa file.
//#############################################################################
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// oneD_filter()  antialiased framegrab support
void
	oneD_filter(
		uint32 *linebuffer,
		unsigned short *rframe,
		unsigned short *gframe,
		unsigned short *bframe,
		int32 y,
		int32 x_size
	)
{
	int32
		pos,
		i,
		r, g, b;
	unsigned char
		*clinebuf = (unsigned char *)linebuffer;

	pos = y * x_size;

	for (i=0; i<x_size; ++i)
	{
		r = rframe[pos];
		g = gframe[pos];
		b = bframe[pos];
		++pos;

		*clinebuf++ = (unsigned char)((r >> 8) & 0xff);
		*clinebuf++ = (unsigned char)((g >> 8) & 0xff);
		*clinebuf++ = (unsigned char)((b >> 8) & 0xff);
	}
	return;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// dump_frame_buffer()
void
	dump_frame_buffer(
		dpl_VIEW *eye,
		int32 x_size,
		int32 y_size,
		Logical antialias
	)
{
	//STUBBED: DPL RB 1/14/07
	////do not check eye here

	////----------------------------------------
	//// control variable and operating buffers
	////----------------------------------------
	//static uint32
	//	dumped_frames = 0,
	//	*line_buffer = NULL;
	//static unsigned short
	//	*rframebuffer = NULL,
	//	*gframebuffer = NULL,
	//	*bframebuffer = NULL;

	//if (eye == NULL)
	//{
	//	//--------------------------
	//	// release allocated memory
	//	//--------------------------
	//	if (line_buffer)
	//	{
	//		Unregister_Pointer(line_buffer);
	//		delete line_buffer;
	//	}
	//	if (rframebuffer)
	//	{
	//		Unregister_Pointer(rframebuffer);
	//		delete rframebuffer;
	//	}
	//	if (gframebuffer)
	//	{
	//		Unregister_Pointer(gframebuffer);
	//		delete gframebuffer;
	//	}
	//	if (bframebuffer)
	//	{
	//		Unregister_Pointer(bframebuffer);
	//		delete bframebuffer;
	//	}
	//	return;
	//}
	//Check_Pointer(eye);

	////-----------------------------------------------------------------
	//// AA kernel definition:
	////
	////		normalized screen coordinates are -1.0 .. +1.0
	////		these map (in NTSC) to 705 and 512.
	////		So a pixel in x is
	////			2.0 / 704 = 2.841e-3
	////		in y			 = 3.906e-3
	////		for the re-use 5-sample kernel we displace by 0.5 pixels ...
	////-----------------------------------------------------------------
	//static const int32 kernel_size = 4;

	//static const float xk = 2.0f / x_size;
	//static const float yk = 2.0f / y_size;
	//static const float ox = xk / 4.0f;
	//static const float oy = yk / 4.0f;
	//static const float jx = 0.0f;		// ox / 4.0f
	//static const float jy = 0.0f;    // oy / 4.0f

	//static const float x_kernel[4] = { -(ox+jx), ox-jx, jx-ox,    jx+ox };
	//static const float y_kernel[4] = {   oy-jy,  oy+jy, -(jy+oy), jy-oy };
	//static const int   kernel_weights[4] = { 64, 64, 64, 64 };

	////---------------------
	//// operating variables
	////---------------------
	//int32 passes	= (antialias)?kernel_size:1;
	//int32 size		= x_size * y_size;
	//int32 frameptr;
	//int32 i, x, y;

	//DEBUG_STREAM << "Dump frame buffer (antialias=" <<
	//	((antialias)?"True":"False") << ") - press Esc to cancel." << std::endl;

	////----------------------------
	//// allocate operating buffers
	////----------------------------
	//if (line_buffer == NULL)
	//{
	//	//-----------------------------------------------------------------------
	//	// NOTE - must call dump_frame_buffer(NULL, NULL, NULL, NULL) to release
	//	//-----------------------------------------------------------------------
	//	line_buffer  = new uint32[1024];
	//	Register_Pointer(line_buffer);
	//	rframebuffer = new unsigned short[size];
	//	Register_Pointer(rframebuffer);
	//	gframebuffer = new unsigned short[size];
	//	Register_Pointer(gframebuffer);
	//	bframebuffer = new unsigned short[size];
	//	Register_Pointer(bframebuffer);
	//}

	////------------------------------
	//// clear out r g b framebuffers
	////------------------------------
	//frameptr = 0;
	//for (i=0; i<size; ++i)
	//{
	//	rframebuffer[frameptr] = 0x0;
	//	gframebuffer[frameptr] = 0x0;
	//	bframebuffer[frameptr] = 0x0;
	//	++frameptr;
	//}

	//dpl_RedrawScene();
	//dpl_RedrawScene();

	////--------------------------------
	//// perform AA framecapture passes
	////--------------------------------
	//int this_weight;
	//float32 x0, y0, x1, y1, zeye;

	//for (i=0; i<passes; ++i)
	//{
	//	DEBUG_STREAM << "  pass " << (i+1) << " of " << passes << " " << std::flush;

	//	//------------
	//	// jitter eye
	//	//------------
	//	dpl_GetViewProjection(eye, &x0, &y0, &x1, &y1, &zeye);
	//	dpl_SetViewProjection(eye,
	//									x0 + x_kernel[i],
	//									y0 + y_kernel[i],
	//									x1 + x_kernel[i],
	//									y1 + y_kernel[i], zeye);
	//	dpl_FlushView(eye);

	//	//--------------
	//	// redraw frame
	//	//--------------
	//	dpl_RedrawScene();
	//	dpl_RedrawScene();

	//	//--------------------
	//	// capture accumulate
	//	//--------------------
	//	this_weight = kernel_weights[i];
	//	frameptr = 0;

	//	for (y=0; y<y_size; ++y )
	//	{
	//		unsigned char *linep = (unsigned char *)&line_buffer[0];

	//		//------------------------------
	//		// Esc key cancelles frame dump
	//		//------------------------------
	//		if (kbhit())
	//		{
	//			if (getch() == 27)
	//			{
	//				DEBUG_STREAM << std::endl << "cancelled." << std::endl << std::flush;
	//				return;
	//			}
	//		}

	//		if ((y & 15) == 0)
	//			{ DEBUG_STREAM << "." << std::flush; }

	//		dpl_ReadFrameStore(eye, (uint32 *)linep, 0, y, x_size, 1);

	//		for (x=0; x<x_size; ++x)
	//		{
	//			rframebuffer[frameptr] += (unsigned short)(linep[2] * this_weight);
	//			gframebuffer[frameptr] += (unsigned short)(linep[1] * this_weight);
	//			bframebuffer[frameptr] += (unsigned short)(linep[0] * this_weight);
	//			++frameptr;
	//			linep += 4;
	//		}
	//	}
	//	DEBUG_STREAM << std::endl << std::flush;
	//}

	////----------------------------------
	//// write frame buffer to targa file
	////----------------------------------
	//FILE *fp;
	//char fname[64];
	//unsigned char tga_hdr[18];

	//sprintf(fname, "dump%d.tga", dumped_frames);

	//tga_hdr[0] = 0x00;
	//tga_hdr[1] = 0x00;
	//tga_hdr[2] = 0x02;
	//tga_hdr[3] = 0x00;

	//tga_hdr[4] = 0x00;
	//tga_hdr[5] = 0x00;
	//tga_hdr[6] = 0x00;
	//tga_hdr[7] = 0x00;

	//tga_hdr[8] = 0x00;
	//tga_hdr[9] = 0x00;
	//tga_hdr[10] = 0x00;
	//tga_hdr[11] = 0x00;

	//tga_hdr[12] = (unsigned char)(x_size & 0xff);
	//tga_hdr[13] = (unsigned char)((x_size >> 8) & 0xff);
	//tga_hdr[14] = (unsigned char)(y_size & 0xff);
	//tga_hdr[15] = (unsigned char)((y_size >> 8) & 0xff);

	//tga_hdr[16] = 0x18;
	//tga_hdr[17] = 0x00;

	//DEBUG_STREAM << "Writing image to file '" << fname << "' . . . " << std::flush;
	//fp = fopen(fname, "wb");
	//fwrite(tga_hdr, 18, 1, fp);

	//for (y=0; y<y_size; ++y )
	//{
	//	oneD_filter(line_buffer,
	//					rframebuffer,
	//					gframebuffer,
	//					bframebuffer,
	//					(y_size-1) - y,
	//					x_size);
	//	fwrite(line_buffer, x_size*3, 1, fp);
	//}
	//fclose(fp);
	//DEBUG_STREAM << "done." << std::endl << std::flush;

	//++dumped_frames;	// increment for next frame dump
	//return;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// DPLRenderer::DPLFrameDump()
void
	DPLRenderer::DPLFrameDump(Logical antialias)
{
	//STUBBED: DPL RB 1/15/07
	//dump_frame_buffer(dplMainView, x_size, y_size, antialias);
	//return;
}
//
//#############################################################################
// DPLIndependantPFX lets you start up an effect in absolute space that is
// run to termination automatically by the renderer.
//#############################################################################
//
void
	DPLRenderer::DPLIndependantPFX(
		Point3D							location,			// Location in space to trigger the effect
		dpl_PARTICLESTART_EFFECT_INFO	*psfx_definition,	// Description of the pfx
		dpl_DCS							*my_DCS,			// Optional DCS to link to
		int								subid)				// inserted into third byte of effect id.

{
//STUBBED: DPL RB 1/14/07
	// we put our id into the lower 16 bits because (at least) the upper 8 bits are flags
	// HACK...for testing pfx bug

	//dpl_PARTICLESTART_EFFECT_INFO tempParticle;
	//tempParticle = *psfx_definition;
	//tempParticle.identifier = (psfx_definition->identifier & 0xffff0000) | GetUniqueID() | ((subid << 16) & 0x00ff0000);
	//tempParticle.px = location.x;
	//tempParticle.py = location.y;
	//tempParticle.pz = location.z;
	//dpl_Effect(dpl_effect_type_particlestart, my_DCS, &tempParticle);


//	std::cout<<"psfx identifier used was "<<tempParticle.identifier<<"\n";
}
//
//#############################################################################
// DPLIndependantEffect lets you start up an effect in absolute space that is
// run to termination automatically by the renderer.
//#############################################################################
//
void
	DPLRenderer::DPLIndependantEffect(
		Point3D	location,
		int		effect_number,
		dpl_DCS	*my_DCS,          // Optional DCS to link to
		int		subid)
{
	//STUBBED: DPL RB 1/14/07
	if(effect_number >= 1000)
	{
   		effect_number -= 1000;
		if(effect_number < 0 || effect_number > MAX_PSFX_COUNT-1)
		{
			Fail("PSFX id number was not in the allowed range");
		}
//		DPLIndependantPFX(location,myPSFXDescriptons[effect_number],my_DCS,subid);

		// find a free emitter
		ParticleEmitter *emitter = NULL;
		for (int i=0; i<MAX_INDIE_EMITTERS; ++i)
		{
			if (!myPSFXEmitters[i].IsActive())
			{
				emitter = &myPSFXEmitters[i];
				break;
			}
		}

		if (emitter != NULL)
		{
			emitter->SetEffect(&myPSFXDescriptons[effect_number]);
			emitter->SetPosition(location.x, location.y, location.z);
			emitter->Start();
		}

		return;
	}

	//dpl_EXPLOSION_EFFECT_INFO my_explosion;
	//my_explosion.type		=	effect_number;
	//my_explosion.x			=	location.x;
	//my_explosion.y			=	location.y;
	//my_explosion.z			=	location.z;
	//dpl_Effect ( dpl_effect_type_explosion, my_DCS, &my_explosion );
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void DPLRenderer::SetViewAngle(Degree new_angle)
{
	//STUBBED: DPL RB 1/14/07
	//Check(this);
	////
	////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//// Convert From Degree To Radian
	////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	////
	//Radian view_angle;
	//view_angle = new_angle;
	//viewAngle = view_angle;
	//viewRatio = tan(viewAngle/2.0f);
	////
	////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//// Calc Aspect Ratio and Set View Projection
	////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	////
	//aspectRatio	=	(float) y_size / (float) x_size;
	//dpl_SetViewProjection	( dplMainView, -1.0f, -aspectRatio, 1.0f, aspectRatio, 1.0f/viewRatio);
	//dpl_FlushView(dplMainView);
}
//
//#############################################################################
// Startup the implementation of the Division video renderer
//#############################################################################
//
void
	DPLRenderer::LoadMissionImplementation(Mission	*mission)
{
	Check(this);
	Tell("DPLVideoRenderer::StartImplementation has been called\n");
	DPLReadEnvironment(mission);

	LoadNameBitmaps();
}
//##############################################################################
// Name Bitmap Support
//

void DPLRenderer::SortAndReloadNameBitmaps()
{
	//
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Get the Entity Group of Players
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	EntityGroup *player_group = application->GetEntityManager()->FindGroup("Players");
	ChainIteratorOf<Node*> player_iterator(player_group->groupMembers);
	Player *current_player;
	while ((current_player = (Player*)player_iterator.ReadAndNext()) != NULL)
	{
		BitMap *name_bitmap = application->GetCurrentMission()->GetLargeNameBitmap(current_player->playerBitmapIndex);
		if (name_bitmap && current_player->IsScoringPlayer())
		{
			int index = current_player->playerRanking + 1;
			if (mNameTextures[index])
				mNameTextures[index]->Release();

			mDevice->CreateTexture(128, 32, 1, 0, D3DFMT_A4R4G4B4, D3DPOOL_MANAGED, &mNameTextures[index], NULL);

			LoadBitSliceTexture(name_bitmap, mNameTextures[index]);
		}
	}
	
	LoadOrdinalBitmaps();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void DPLRenderer::LoadOrdinalBitmaps()
{
	//
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Check if we have a Director on this machine,
	// if so, create load the ordinal Bitmaps only
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	//
	if (application->GetMissionPlayer()->GetInstance() == CameraDirector::MasterInstance &&
		application->GetMissionPlayer()->IsDerivedFrom(*CameraDirector::GetClassDerivations()))
	{
		//
		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// Make Sure index is in the right place
		// in case < 8 players!!!!
		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		//
		int index = 0;
		for(int ii=1; ii<5; ++ii)
		{
			//
			//~~~~~~~~~~~~~~~~~~
			// Index Starts at 1
			//~~~~~~~~~~~~~~~~~~
			//
			BitMap *ordinal_bitmap = application->GetCurrentMission()->GetOrdinalBitmap(ii);
			
			if (mOrdinalTextures[index])
				mOrdinalTextures[index]->Release();

			mDevice->CreateTexture(128, 32, 1, 0, D3DFMT_A4R4G4B4, D3DPOOL_MANAGED, &mOrdinalTextures[index], NULL);

			LoadBitSliceTexture(ordinal_bitmap, mOrdinalTextures[index]);
			
			++index;
		}
	}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
unsigned int*
	DPLRenderer::MakeBitSliceStorage()
{
	Check(this);
	//
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Allocate some temporary memory
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	uint32 *worst_case_texels = new uint32[128*64];
	if(!worst_case_texels)
	{
		Fail("Could not allocate RAM for worst case texels\n");
	}
	//
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Zero Out Memory so Empty Texture space is Black
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	for(int ii=0;ii<8192;++ii)
	{
		worst_case_texels[ii] = 0;
	}

	return worst_case_texels;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void DPLRenderer::LoadNameBitmaps()
{
	int player_count = application->GetCurrentMission()->GetPlayerCount();
	for (int ii=0; ii<player_count; ++ii)
	{
		BitMap *name_bitmap = application->GetCurrentMission()->GetLargeNameBitmap(ii + 1);
		if (name_bitmap)
		{
			if (mNameTextures[ii])
				mNameTextures[ii]->Release();

			HRESULT hr;
			
			V(mDevice->CreateTexture(128, 32, 1, 0, D3DFMT_A4R4G4B4, D3DPOOL_MANAGED, &mNameTextures[ii], NULL));

			LoadBitSliceTexture(name_bitmap, mNameTextures[ii]);
		}
	}

	LoadOrdinalBitmaps();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	DPLRenderer::ShutdownImplementation()
{
//STUBBED: DPL RB 1/14/07
//	Tell("DPLVideoRenderer::StopImplementation has been called\n");
//	dpl_EnableSyncOnCreate();
//	SChainIteratorOf<InnerProjectileRenderable*> projectile_iterator(&projectile_list);
//	TreeIteratorOf<DPLObjectCacheLine*, CString> cache_iterator(&dplObjectCacheSocket);
//#if defined(LAB_ONLY)
//	std::cout<<"max projectiles "<<projectile_iterator.GetSize()<<"\n";
//	std::cout<<"max cached objects "<<cache_iterator.GetSize()<<"\n";
//#endif
////	std::cout<<"DPL renderer has "<<dpl_FreeMemory()<<" free\n";
}
void
	DPLRenderer::SuspendImplementation()
{
	Tell("DPLVideoRenderer::SuspendImplementation has been called\n");
}
void
	DPLRenderer::ResumeImplementation()
{
	Tell("DPLVideoRenderer::ResumeImplementation has been called\n");
}
//-----------------------------------------------------------------------------
//--------------------------Id's for psfx effects---------------------------------
//-----------------------------------------------------------------------------
int
	DPLRenderer::GetUniqueID()
{
	myUniqueID = (myUniqueID + 1) & 0x0000ffff;
	return(myUniqueID);
}
//-----------------------------------------------------------------------------
//--------------------------MUNGA caching of objects---------------------------
//-----------------------------------------------------------------------------
dpl_OBJECT*
	DPLRenderer::GetCachedObject(
		const CString 	&object_name)					// Name of the object we want to get
{
	dpl_OBJECT
		*object_pointer;
	//
	// Get this object from the cache by name
	//
	DPLObjectCacheLine *my_cache_line;

	if ((my_cache_line = dplObjectCacheSocket.Find(object_name)) == NULL)
		return NULL;

	//
	// Remove the cache line from the cache
	//
	object_pointer = my_cache_line->objectPointer;
	delete my_cache_line;

	//
	// Return the object pointer
	//
	return(object_pointer);
}

void
	DPLRenderer::PutCachedObject(
		const CString  &object_name,					// Name of the object we will cache
		dpl_OBJECT		*object_pointer)				// pointer to the object being cached
{
	//
	// Create the cache line data structure
	//
	#if 0
	typedef PlugOf<dpl_OBJECT*> DPLObjectCacheLine;

	DPLObjectCacheLine *my_cache_line = new DPLObjectCacheLine(object_pointer);
	#endif

	DPLObjectCacheLine	*my_cache_line =
		new DPLObjectCacheLine(
			object_name,
			object_pointer);
	Register_Object(my_cache_line);

	//
	// Store this cache line in the cache
	//
	dplObjectCacheSocket.AddValue(my_cache_line, object_name);

}
//-----------------------------------------------------------------------------
//--------------------------Projectile Speedup---------------------------------
//-----------------------------------------------------------------------------
InnerProjectileRenderable*
	DPLRenderer::GetProjectile(
		d3d_OBJECT				*graphical_object,	// object to hang on the DCS, may be a list later <NULL>
		bool isDeathZone)				// DPL Zone this stuff will live in (for culling)
{
	//STUBBED: DPL RB 1/14/07
	//InnerProjectileRenderable
	//	*return_projectile;
	//dpl_INSTANCE
	//	*temp_instance;
	////
	//// Are there projectiles in the list?
	////
	//SChainIteratorOf<InnerProjectileRenderable*> iterator(&projectile_list);
	//if ((return_projectile = iterator.GetCurrent()) != NULL)
	//{
	//	// Yes, remove it from the list set it's instance and return it
	//	iterator.Remove();
	//	temp_instance = return_projectile->GetInstance();
	//	if(graphical_object != dpl_GetInstanceObject(temp_instance))
	//	{
	//		dpl_SetInstanceObject		(temp_instance,	graphical_object);
	//		dpl_FlushInstance				(temp_instance);
	//	}
	//	return(return_projectile);
	//}
	//else
	//{
	//	// no, make a new one and return that
		InnerProjectileRenderable	*projectile =
			new InnerProjectileRenderable(
				graphical_object,		// object to hang on the DCS, may be a list later <NULL>
				isDeathZone);				// DPL Zone this stuff will live in (for culling)
		return(projectile);
	//}
}
void
	DPLRenderer::ReleaseProjectile(
		InnerProjectileRenderable* inner_projectile)
{
	// add the projectile back to the list
	//projectile_list.Add(inner_projectile);
}
//-----------------------------------------------------------------------------
//--------------------------Joint to DCS translator----------------------------
//-----------------------------------------------------------------------------
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// DPLJointToDCSTranslator is a class that contains a joint number to dcs
// pointer translation table.  This lets a renderer find the dcs that goes
// with a particular segment.
//
	DPLJointToDCSTranslator::DPLJointToDCSTranslator(
		Entity	*entity,						// The entity to translate
		dpl_DCS	*dcs_array[])				// Array of DCS's to translate
{
	JointedMover
		*my_jointed_mover;
	//
	// Make sure this is a jointed mover, then cast the entity pointer over
	//
	if (entity->IsDerivedFrom(*JointedMover::GetClassDerivations()))
	{
		my_jointed_mover = (JointedMover*)entity;
	}
	else
	{
		Fail("DPLJointToDCSTranslator was called on an entity NOT a JointedMover\n");
	}
	//
	// Find out how many joints the entity has, then allocate enough RAM for a
	// DCS pointer to every joint.
	//
	JointSubsystem* joint_subsystem = my_jointed_mover->GetJointSubsystem();
	Check(joint_subsystem);
	translation_array = new (dpl_DCS(*[joint_subsystem->GetJointCount()]));
	Register_Pointer(translation_array);
	//
	// Setup to iterate the entity segment table
	//
	EntitySegment::SegmentTableIterator segment_iterator(my_jointed_mover->segmentTable);
	EntitySegment *current_segment;
	while ((current_segment = segment_iterator.ReadAndNext()) != NULL)
	{
		//
		// For each segment, see if it has a joint index, if it does, put the
		// DCS for that joint into the translation array
      //
		Check(current_segment);
		int joint_index = current_segment->GetJointIndex();
		if(joint_index != -1)
		{
			translation_array[joint_index] = dcs_array[current_segment->GetIndex()];
		}
	}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DPLJointToDCSTranslator::~DPLJointToDCSTranslator()
{
	Unregister_Pointer(translation_array);
	delete[] translation_array;
	translation_array = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Logical
	DPLJointToDCSTranslator::TestInstance() const
{
	return True;
}
//-----------------------------------------------------------------------------
//--------------------------Resource creation support--------------------------
//-----------------------------------------------------------------------------
//#############################################################################
//#############    DPLRenderer::CreateModelVideoStreamResource    #############
//#############################################################################

ResourceDescription::ResourceID
	DPLRenderer::CreateModelVideoStreamResource(
		ResourceFile *resource_file,
		const char *model_name,
		NotationFile *model_file,
		const ResourceDirectories * /*directories*/
	)
{
	ResourceDescription *res_description =
		resource_file->FindResourceDescription(
			model_name,
			ResourceDescription::VideoModelResourceType
		);

	if (res_description == NULL)
	{
		NameList *video_entries = model_file->MakeEntryList("video");

		if (video_entries != NULL)
		{
			Register_Object(video_entries);

			//----------------------------------------------
			// parse video model data and store in resource
			//----------------------------------------------
			Tell("Building video resource for model '" << model_name << "'.\n");

			NameList::Entry
				*entry,
				*next_entry;
			const char
				*entry_name,
				*entry_pointer,
				*argument_start;
			int
				length;
			char
				argument[40],
				*argument_pointer;
			L4VideoObject::ResourceType
				resource_type;
			Enumeration	//(see L4VideoObject::RendererModes)
				renderer_modes;
			enum
			{
				parsing_filename,
				seeking_switch,
				parsing_switch,
				parsing_billboard
			}	state;
			L4VideoObject
				*video_object;
			L4VideoObjectWrapper
				*video_wrapper;
			ChainOf<L4VideoObjectWrapper*>
				video_chain(NULL);
			char
				*video_stream,
				*video_pointer;
			int
				object_count;
			long
				object_size,
				stream_length;

			//------------------------------------------------
			// parse each entry in [video] page of model file
			//------------------------------------------------
			next_entry = video_entries->GetFirstEntry();
			while (next_entry)
			{
				entry = next_entry;
				Check(entry);
				next_entry = entry->GetNextEntry();	// so 'continue' works
				entry_name = entry->GetName();
				if (entry_name && *entry_name)
				{
					//--------------------------------------------
					// could be "skeleton" or "object" or comment
					//--------------------------------------------
					if (strcmp(entry_name, "object") == 0)
					{
						resource_type = L4VideoObject::Object;
					}
					else if (strcmp(entry_name, "rubble") == 0)
					{
						resource_type = L4VideoObject::Rubble;
					}
					else if (strcmp(entry_name, "skeleton") == 0)
					{
						resource_type = L4VideoObject::Skeleton;
					}
					else if (Comment_Line(entry_name))
					{
						// do nothing - skip comments
						continue;
					}
					else if (strncmp(entry_name, "skeleton", 8) == 0)
					{
						// do nothing - skip temporary skeleton entries
						continue;
					}
					else if (strncmp(entry_name, "destroyed", 9) == 0)
					{
						// do nothing - skip destroyed skeleton entries
						continue;
					}
					else if (strncmp(entry_name, "dzm", 3) == 0)
					{
						// do nothing - skip damage zone material entries
						continue;
					}
					else
					{
//						resource_type = L4VideoObject::Unknown;
						DEBUG_STREAM << "Unknown entry '" << entry_name <<
							"' in model '" << model_name << "' ignored." << std::endl;
						continue;
					}
					//---------------------------------
					// parse and process each argument
					//---------------------------------
					entry_pointer = entry->GetChar();
					while (entry_pointer && *entry_pointer)
					{
						//-------------------------
						// skip leading whitespace
						//-------------------------
						while (*entry_pointer != '\0' && isspace(*entry_pointer))
						{
							++entry_pointer;
						}
						//---------------------------
						// exit loop if nothing left
						//---------------------------
						if (*entry_pointer == '\0')
						{
							break;
						}
						//-------------------------------------------
						// parse the next argument into local buffer
						//-------------------------------------------
						argument_start	= entry_pointer;
						while (*entry_pointer != '\0' && !isspace(*entry_pointer))
						{
							++entry_pointer;
						}
						length = entry_pointer - argument_start;
						Verify( length < sizeof(argument) );
						strncpy(argument, argument_start, length);
						argument[length] = '\0';
						//----------------------
						// parse local argument
						//----------------------
						argument_pointer 	= argument;
						renderer_modes		= L4VideoObject::Normal;
						state 				= parsing_filename;
						while (*argument_pointer != '\0')
						{
							switch (state)
							{
								case parsing_filename:
									switch (*argument_pointer)
									{
										#if 0
										case	'.':
											if ((resource_type == L4VideoObject::Object) ||
												 (resource_type == L4VideoObject::Rubble))
											{
												*argument_pointer = '\0';	// terminate filename
												state = seeking_switch;
											}
											break;
										#endif
										case	'/':
											*argument_pointer = '\0';	// terminate filename
											state = parsing_switch;
											break;
										default:
											// later check for valid filename character...
											break;
									}
									break;
								case seeking_switch:
									if (*argument_pointer == '/')
										{ state = parsing_switch; }
									break;
								case parsing_switch:
									switch (*argument_pointer)
									{
										case	'b':
										case	'B':
											state = parsing_billboard;
											break;
										case	'i':
										case	'I':
											renderer_modes |= L4VideoObject::IntersectImmune;
											state = seeking_switch;
											break;
										default:
											state = seeking_switch;
											break;
									}
									break;
								case parsing_billboard:
									switch (*argument_pointer)
									{
										case	'x':
										case	'X':
											renderer_modes |= L4VideoObject::BillboardXAxis;
											break;
										case	'y':
										case	'Y':
											renderer_modes |= L4VideoObject::BillboardYAxis;
											break;
										case	'z':
										case	'Z':
											renderer_modes |= L4VideoObject::BillboardZAxis;
											break;
										case	'/':
											state = parsing_switch;
											break;
										default:
											state = seeking_switch;
											break;
									}
									break;
								// no default:
							}
							++argument_pointer;
						}
						//-----------------------------------------------
						// create video resource object and add to chain
						//-----------------------------------------------
						video_object =
							new L4VideoObject(
								argument,
								resource_type,
								renderer_modes
							);
						Register_Pointer(video_object);	// not _Object!

						video_wrapper =
							new L4VideoObjectWrapper(
								video_object,
								True	// delete object when done
							);
						Register_Object(video_wrapper);

						//Tell("  adding video object '"<<argument<<"' type ");
						//Tell(resource_type<<" mode 0x"<<std::hex<<renderer_modes<<"\n");
						video_chain.Add(video_wrapper);

					}	// arguments processed for this entry
				}
			}	// all arguments processed

			//----------------------------------------------
			// convert chain of video resources into stream
			//----------------------------------------------
			ChainIteratorOf<L4VideoObjectWrapper*>
				video_iterator(video_chain);

			object_count = video_iterator.GetSize();

			object_size = sizeof(L4VideoObject);
			stream_length = sizeof(int) + object_count * object_size;

			video_stream = new char[stream_length];
			Register_Pointer(video_stream);

			video_pointer = video_stream;
			*((int *)video_pointer) = object_count;
			video_pointer += sizeof(int);

			Tell("  count " <<std::dec<< object_count << ", resource size " << stream_length << "\n");

			while ((video_wrapper = video_iterator.ReadAndNext()) != NULL)
			{
				video_object = video_wrapper->GetVideoObject();
				if (!stricmp(video_object->GetObjectFilename(), "bp1.bgf"))
					video_pointer += 1 - 1;
				*((L4VideoObject *)video_pointer) = *video_object;
				video_pointer += object_size;
			}
			//--------------------------------------------------
			// store stream of video resources in resource file
			//--------------------------------------------------
			res_description =
				resource_file->AddResource(
					model_name,
					ResourceDescription::VideoModelResourceType,
					1,
					ResourceDescription::Preload,
					video_stream,
					stream_length
				);
			//--------------------------
			// release allocated memory
			//--------------------------
			// video_chain
			L4VideoObjectWrapper::DeleteVideoObjectChain(&video_chain);
			// video_stream
			Unregister_Pointer(video_stream);
			delete video_stream;
			// video_entries
			Unregister_Object(video_entries);
			delete video_entries;
		}
		else
		{
			//-------------------------------
			// no [video] page in model file
			//-------------------------------
			return (ResourceDescription::NullResourceID);
		}
	}
	return (res_description->resourceID);
}
//===========================================================================//
