Files
TeslaRel410/CODE/RP/MUNGA_L4/L4VIDEO.CPP
T
CydandClaude Fable 5 fdd9ac9d97 Initial import: Tesla Release 4.10 (Tesla:BattleTech & Tesla:Red Planet)
Archival snapshot of the Virtual World Entertainment Tesla cockpit
software, 1994-1996: MUNGA engine and L4 pod layer source (Borland
C++ 5.0), BT/RP game code, and game content (models, audio, maps,
gauges, Division renderer data). Includes third-party libraries:
Division dVS/DPL graphics, HMI SOS audio, WATTCP networking.

Files are preserved byte-for-byte (.gitattributes disables all
line-ending conversion). README.md documents the layout, target
hardware, and toolchain.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 13:21:58 -05:00

6709 lines
217 KiB
C++

//===========================================================================//
// File: l4video.cpp //
// Project: MUNGA Brick: Video Renderer Manager //
// Contents: Interface specification Video Renderer Manager //
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// 01/11/95 GAC Initial coding. //
// 07/11/95 KEO Modify video resource format. //
// 02/08/96 KEO Add rubble entry to video resource. //
//---------------------------------------------------------------------------//
// Copyright (C) 1995-1996, Virtual World Entertainment, Inc. //
// All Rights reserved worldwide. //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL. //
//===========================================================================//
#include <mungal4.hpp>
#pragma hdrstop
#if !defined(DOOR_HPP)
# include <door.hpp>
#endif
#if !defined(DOORFRAM_HPP)
# include <doorfram.hpp>
#endif
#if !defined(EYECANDY_HPP)
# include <eyecandy.hpp>
#endif
#if !defined(L4VIDRND_HPP)
# include <l4vidrnd.hpp>
#endif
#if !defined(L4VIDEO_HPP)
# include <l4video.hpp>
#endif
#if !defined(MATRIX_HPP)
# include <matrix.hpp>
#endif
#if !defined(MOVER_HPP)
# include <mover.hpp>
#endif
#if !defined(JMOVER_HPP)
# include <jmover.hpp>
#endif
#if !defined(PLAYER_HPP)
# include <player.hpp>
#endif
#if !defined(CAMSHIP_HPP)
# include <camship.hpp>
#endif
#if !defined(DIRECTOR_HPP)
# include <director.hpp>
#endif
#if !defined(MISSION_HPP)
# include <mission.hpp>
#endif
#if !defined(CULTURAL_HPP)
# include <cultural.hpp>
#endif
#if !defined(NTTMGR_HPP)
# include <nttmgr.hpp>
#endif
#if !defined(APP_HPP)
# include <app.hpp>
#endif
#include <conio.h>
//
// Includes for the DPL libraries
//
#include <dpl.h>
#include <dpl_2d.h>
#include <dpl_vpx.h>
#include <dplutils.h>
#include <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, 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 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" {
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()
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() 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)
{
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";
Verify(special_len > MAX_SPECIAL_SIZE);
}
strncpy(TempBuff, special,special_len);
TempBuff[special_len] = 0;
if(TempBuff[special_len-1] != 0)
{
DEBUG_STREAM<<"Caution, the following SPECIAL was not null terminated\n";
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 << endl << "Damage zone '" <<
*argptr << "' not in table." << 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";
Verify(damagize_material);
}
}
else
{
DEBUG_STREAM<<"SPECIAL GEOGROUP DAMAGE no material name \n";
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";
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";
}
}
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";
Verify(*argptr);
}
}
else
{
DEBUG_STREAM<<"SPECIAL MATERIAL "<<*argptr<<" is not a material modifier\n";
}
}
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";
Verify(*argptr);
}
if(*(++argptr))
v0 = atof(*argptr);
else
{
DEBUG_STREAM<<"SPECIAL TECTURE SCROLL missing v0\n";
Verify(*argptr);
}
if(*(++argptr))
du = atof(*argptr);
else
{
DEBUG_STREAM<<"SPECIAL TECTURE SCROLL missing du\n";
Verify(*argptr);
}
if(*(++argptr))
dv = atof(*argptr);
else
{
DEBUG_STREAM<<"SPECIAL TECTURE SCROLL missing dv\n";
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";
Verify(*argptr);
}
if(*(++argptr))
offset = atoi(*argptr);
else
{
DEBUG_STREAM<<"SPECIAL TEXTURE FAKESIZE missing offset\n";
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";
}
}
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";
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;
/* dPL material name callback function type. */
//typedef char8 *(dpl_MATERIAL_NAME_CALLBACK)(char8 *mat_name);
char8*
substituteMaterial(
char8 *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.
//----------------------------------------------
entry = materialSubstitutionList->GetFirstEntry();
while (entry)
{
search = entry->GetName();
if (search && *search && (pc = strstr(source, search)) != NULL)
{
replace = entry->GetChar();
*buffer = '\0';
len = pc - source;
while (*replace == '<')
{
++replace;
--len;
}
if (len > 0)
{
strncat(buffer, 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);
Str_Copy(source, buffer, MATERIAL_NAME_BUFFER_LENGTH);
break;
}
entry = entry->GetNextEntry();
}
return source;
}
//-----------------------------------------------------------------------------
//--------------------------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"<<hex<<video_object->GetRendererModes());
video_wrapper = new L4VideoObjectWrapper(video_object, False);
Register_Object(video_wrapper);
video_chain->Add(video_wrapper);
}
//Tell(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;
}
//-----------------------------------------------------------------------------
//-------------------Actual DPL video renderer starts below--------------------
//-----------------------------------------------------------------------------
UserHeap* DPLRenderer::DPLHeap = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructor for DPLRenderer
//
DPLRenderer::DPLRenderer(
RendererRate calibration_rate,
RendererComplexity calibration_complexity,
RendererPriority calibration_priority,
InterestType interest_type,
InterestDepth depth_calibration
):
VideoRenderer(
calibration_rate,
calibration_complexity,
calibration_priority,
interest_type,
depth_calibration
),
projectile_list(NULL),
dplObjectCacheSocket(NULL, False),
dplJointToDCSTranslatorSocket(NULL,False),
dplRenderableSocket(NULL)
{
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;
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;
ambientLight = NULL;
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.
//
for( psfx_number = 0; psfx_number < MAX_PSFX_COUNT; psfx_number++)
{
myPSFXDescriptons[psfx_number] = NULL;
}
//
// 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";
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";
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";
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", "", "" );
// cout<<dpl_GetObjectFilePath()<<"\n";
// dpl_SetTexmapFilePath ( ".\\video", "", "" );
// cout<<dpl_GetTexmapFilePath()<<"\n";
// dpl_SetMaterialFilePath ( ".\\video", "", "" );
// 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()
{
dpl_ZONE
*temp_zone;
//
// Make a new zone for use by someone constructing an object, switch it on
// and 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);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 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)
{
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)
{
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)
{
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;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// MarkDCSHiearchy This will 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
{
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
{
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";
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
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() << "'" << endl;
}
}
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() << "'" << endl;
}
}
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() << "'" << endl;
}
}
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 << "'" << endl; }
}
if (master_notation_file->GetEntry(starting_page_name, "prioritytexmappath", &TempStringPtr))
{
dpl_AddToTexmapFilePath((char *)TempStringPtr, dpl_path_system);
if (debug_printing)
{ DEBUG_STREAM << "prioritytexmappath '" << TempStringPtr << "'" << endl; }
}
if (master_notation_file->GetEntry(starting_page_name, "prioritymaterialpath", &TempStringPtr))
{
dpl_AddToMaterialFilePath((char *)TempStringPtr, dpl_path_system);
if (debug_printing)
{ DEBUG_STREAM << "prioritymaterialpath '" << TempStringPtr << "'" << endl; }
}
//
// 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)
{
dpl_OBJECT
*dpl_a_object;
Register_Object(cache_namelist);
for( entry = cache_namelist->GetFirstEntry();
entry;
entry = entry->GetNextEntry())
{
dpl_a_object = dpl_LoadObject((char *)entry->dataReference, dpl_load_normal);
if(!dpl_a_object)
DEBUG_STREAM<<"Unable to cache "<<(char *)entry->dataReference<<"\n";
else
{
if(debug_printing)
cout<<"Caching "<<(char *)entry->dataReference<<"\n";
}
}
Unregister_Object(cache_namelist);
delete cache_namelist;
}
//
// Setup the clip range
//
if(master_notation_file->GetEntry(starting_page_name, "clip" ,&TempStringPtr))
{
sscanf(
TempStringPtr,
"%f %f",
&clipNear,
&clipFar);
dpl_SetViewClipPlanes ( dplMainView, clipNear, clipFar );
if(debug_printing)
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);
dpl_SetViewBackGround ( dplMainView, backgroundRed, backgroundGreen, backgroundBlue);
if(debug_printing)
cout<<"Background Color "<<TempStringPtr<<"\n";
}
//
// setup the projection, pipe and other view related junk
//
if(master_notation_file->GetEntry(starting_page_name, "viewangle" ,&TempStringPtr))
{
sscanf(
TempStringPtr,
"%f",
&viewAngle);
dpl_SetPipeWindow (0, 0, 0, x_size, y_size);
SetViewAngle(viewAngle);
dpl_SetViewPipe ( dplMainView, 0);
if(debug_printing)
cout<<"View Angle "<<TempStringPtr<<"\n";
}
//
// 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;
// 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 );
if(debug_printing)
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)
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);
ambientLight = dpl_NewLight();
Register_Pointer(ambientLight);
dpl_SetLightType ( ambientLight, dpl_light_type_ambient );
dpl_SetLightColor ( ambientLight, red, green, blue );
dpl_FlushLight ( ambientLight );
if(debug_printing)
cout<<"Ambient Light "<<TempStringPtr<<"\n";
}
//
// 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)
{
sceneLightDCS = new (dpl_DCS (*[sceneLightCount]));
Register_Pointer(sceneLightDCS);
sceneLight = new (dpl_LIGHT (*[sceneLightCount]));
Register_Pointer(sceneLight);
}
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)
cout<<"Light "<<(char *)entry->dataReference<<"\n";
//
// Create and rotate a dcs to hold the light, and the light itself
//
Verify(current_entry <= sceneLightCount);
sceneLight[current_entry] = dpl_NewLight();
Register_Pointer(sceneLight[current_entry]);
sceneLightDCS[current_entry] = dpl_NewDCS();
Register_Pointer(sceneLightDCS[current_entry]);
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;
Register_Object(psfx_namelist);
//
// 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)
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])
{
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";
myPSFXDescriptons[psfx_number] = ReadPSFX(psfx_file_name);
Register_Pointer(myPSFXDescriptons[psfx_number]);
}
//
// Get rid of the PSFX entry list
//
Unregister_Object(psfx_namelist);
delete psfx_namelist;
}
//
// Get a the list of special effects
//
if ((specialfx_namelist = master_notation_file->MakeEntryList(starting_page_name, "specialfx")) != NULL)
{
char
*texture_name;
const char
*effect_page_name;
int
status,
spfx_number,
spfx_type,
spfx_count,
spfx_repeats;
float
spfx_size,
spfx_velocity,
spfx_bias,
spfx_y_off,
spfx_cook_r,
spfx_cook_g,
spfx_cook_b,
spfx_varience,
spfx_gravity,
spfx_cool,
spfx_ocool;
dpl_TEXTURE
*effect_texture;
Register_Object(specialfx_namelist);
//
// create all the effects on the current page
//
for( entry = specialfx_namelist->GetFirstEntry();
entry;
entry = entry->GetNextEntry())
{
spfx_number = atoi(entry->GetName()+9);
//
// Get the page with this effect on it
//
effect_page_name = entry->GetChar();
if(debug_printing)
cout<<"specialfx"<<spfx_number<<" "<<effect_page_name<<"\n";
master_notation_file->GetEntry(effect_page_name, "type", &spfx_type);
master_notation_file->GetEntry(effect_page_name, "size", &spfx_size);
master_notation_file->GetEntry(effect_page_name, "velocity", &spfx_velocity);
master_notation_file->GetEntry(effect_page_name, "v_bias", &spfx_bias);
master_notation_file->GetEntry(effect_page_name, "y_off", &spfx_y_off);
master_notation_file->GetEntry(effect_page_name, "variance", &spfx_varience);
master_notation_file->GetEntry(effect_page_name, "gravity", &spfx_gravity);
master_notation_file->GetEntry(effect_page_name, "count", &spfx_count);
master_notation_file->GetEntry(effect_page_name, "repeats", &spfx_repeats);
master_notation_file->GetEntry(effect_page_name, "cook", &TempStringPtr);
sscanf(
TempStringPtr,
"%f %f %f",
&spfx_cook_r,
&spfx_cook_g,
&spfx_cook_b);
master_notation_file->GetEntry(effect_page_name, "cool", &TempStringPtr);
sscanf(
TempStringPtr,
"%f %f",
&spfx_cool,
&spfx_ocool);
//
// install the effect
//
master_notation_file->GetEntry(effect_page_name, "texture" ,&TempStringPtr);
texture_name = SKIPPY_CAST(char*, TempStringPtr);
effect_texture = dpl_LookupTexture ( texture_name, dpl_lookup_normal, &status );
if (effect_texture == NULL)
DEBUG_STREAM<<"couldn't find texture "<<texture_name<<" for an effect\n";
dpl_install_sfx ( spfx_number, // sfx_code
effect_texture, // texture
spfx_type, // type
spfx_size, // size
spfx_velocity, // velocity
spfx_bias, // bias
spfx_y_off, // y-off
spfx_cook_r, // R,G,B
spfx_cook_g,
spfx_cook_b,
spfx_varience, // varience
spfx_gravity, // gravity
spfx_cool, // cool
spfx_ocool, // ocool
spfx_count, // count
spfx_repeats, // reps
0x3); // Fog Immunity
}
//
// 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)
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)
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,","))
{
// cout<<"Mission variable "<<token_count<<": ";
if(strcmp(target_string,"location") == 0)
{
compare_strings[token_count] = (this_resource_file->FindResourceDescription(mission->GetMapID()))->resourceName;
// cout<<target_string<<" = "<<compare_strings[token_count]<<"\n";
}
else if(strcmp(target_string,"time") == 0)
{
compare_strings[token_count] = mission->GetMissionTime();
// cout<<target_string<<" = "<<compare_strings[token_count]<<"\n";
}
else if(strcmp(target_string,"weather") == 0)
{
compare_strings[token_count] = mission->GetMissionWeather();
// cout<<target_string<<" = "<<compare_strings[token_count]<<"\n";
}
else if(strcmp(target_string,"scenario") == 0)
{
compare_strings[token_count] = mission->GetScenarioName();
// cout<<target_string<<" = "<<compare_strings[token_count]<<"\n";
}
else
{
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)
{
cout<<"comparing to: ";
for(i = 0; i<token_count; i++)
{
cout<<compare_strings[i]<<", ";
}
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)
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;
// cout<<match_string<<"!="<<compare_strings[compare_token]<<"\n";
break;
}
else
{
// 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)
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!!" << endl;
}
}
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Read environment
// routine to read in an environment from a notation file and setup lights,
// spfx and such...
//
void
DPLRenderer::DPLReadEnvironment(Mission *mission)
{
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";
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";
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;
}
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() << "'" << endl;
DEBUG_STREAM << "TexmapFilePath '" << dpl_GetTexmapFilePath() << "'" << endl;
DEBUG_STREAM << "MaterialFilePath '" << dpl_GetMaterialFilePath() << "'" << endl;
}
//
// 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()
{
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)
{
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";
}
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";
}
}
}
void
DPLRenderer::LoadBitSliceTexture(
BitMap *bitmap_to_load, // MUNGA 1 bit bitmap to load
int load_position, // Position to load bitmap into
unsigned int *local_storage) // 8192 longword array for storage of the texmap
{
int
x,
y,
bit_number;
Word
*word_pointer;
uint32
turn_on,
turn_off,
*pixel_pointer;
Verify(load_position >= 1);
Verify(load_position <=12);
Check(bitmap_to_load);
Check_Pointer(local_storage);
//
// Figure out the position to start copying the data at
//
word_pointer = bitmap_to_load->Data.MapPointer;
if(load_position & 0x1)
{
pixel_pointer = local_storage + 4096;
}
else
{
pixel_pointer = local_storage;
}
//
// Find the bit position to merge the data into
//
switch(load_position)
{
case 1:
case 2:
turn_on = 0x0000f000;
turn_off = 0xffff0fff;
break;
case 3:
case 4:
turn_on = 0x00000f00;
turn_off = 0xfffff0ff;
break;
case 5:
case 6:
turn_on = 0x00f00000;
turn_off = 0xff0fffff;
break;
case 7:
case 8:
turn_on = 0x000f0000;
turn_off = 0xfff0ffff;
break;
case 9:
case 10:
turn_on = 0xf0000000;
turn_off = 0x0fffffff;
break;
case 11:
case 12:
turn_on = 0x0f000000;
turn_off = 0xf0ffffff;
break;
}
//
// Actually process the texels
//
bit_number = 15;
for(y = 0; y < 32; y++)
{
for(x = 0; x < 128; x++)
{
if((*word_pointer & (1<<bit_number)))
{
*(pixel_pointer++) |= turn_on;
}
else
{
*(pixel_pointer++) &= turn_off;
}
bit_number--;
if(bit_number < 0)
{
bit_number = 15;
word_pointer++;
}
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 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
{
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";
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)
{
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>
dplMainZone, // 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
dplMainZone, // 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";
//
// 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
dplMainZone, // 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
dplMainZone, // 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";
//
// 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
dplMainZone, // 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
dplMainZone, // 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";
//
// 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
dplMainZone, // 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";
//
// 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,
dplMainZone,
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,
dplMainZone,
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,
dplMainZone,
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,
dplMainZone,
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,
dplMainZone,
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,
dplMainZone,
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,
dplMainZone,
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,
dplMainZone,
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
dplMainZone, // 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";
//
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
dplMainZone, // 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
dplMainZone, // 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,
dplMainZone,
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,
dplMainZone,
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,
dplMainZone,
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,
dplMainZone,
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
dplMainZone, // 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
dplMainZone, // 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)
{
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";
//
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";
#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.)
{
char
*object_filename;
#if DEBUG_LEVEL > 0
int
object_count;
#endif
L4VideoObject // should be const
*video_object;
L4VideoObjectWrapper
*video_wrapper;
ChainOf<L4VideoObjectWrapper*>
video_chain(NULL);
L4VideoObject::ResourceType
resource_type;
dpl_DCS
*my_root_dcs;
Enumeration // L4VideoObject::RendererModes
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;
dpl_OBJECT
*this_object;
dpl_ISECT_MODE
intersect_mode;
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" <<hex<<renderer_modes<<dec<< "." << endl);
#endif
if ((resource_type != L4VideoObject::Object) &&
(resource_type != L4VideoObject::Rubble))
{
DEBUG_STREAM << "L4VIDEO.cpp wrong video resource type for object "<<object_filename<<"\n";
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);
CLEAR_VIDEO_LOAD_OBJECT();
if (this_object == NULL)
{
DEBUG_STREAM << "L4VIDEO.cpp couldn't load object "<<object_filename<<"\n";
if (!first_object)
{
continue; // next object
}
}
if (first_object)
{
first_object = False;
RootRenderable *this_static_root =
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>
dplMainZone, // 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_static_root);
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
//------------------------------------------
DPLStaticChildRenderable *this_child =
new DPLStaticChildRenderable(
entity,
dplMainZone,
this_object,
intersect_mode,
intersect_mask,
offset_matrix,
root_DCS);
Register_Object(this_child);
this_DCS = this_child->GetDCS();
this_instance = this_child->GetInstance();
}
else
{
//----------------------------------------
// attach additional objects to root_DCS
// (HACK) temporary implementation (HACK)
//----------------------------------------
DCSInstanceRenderable *another_instance =
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
root_DCS, // 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;
this_instance = another_instance->GetInstance();
}
}
//
// 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:
{
#if DEBUG_LEVEL > 0
StateInstanceSwitchRenderable *undamaged_state =
#endif
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
Register_Object(undamaged_state);
break;
}
case L4VideoObject::Rubble:
{
#if DEBUG_LEVEL > 0
StateInstanceSwitchRenderable *undamaged_state =
#endif
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
Register_Object(undamaged_state);
break;
}
}
//----------------------------------
// 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:
{
dpl_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 = dpl_LoadObject(object_filename, dpl_load_normal);
#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>
dplMainZone); // DPL Zone this stuff will live in (for culling)
Register_Object(projectile);
break;
}
//
// Script for generating renderables for eyecandy
//
case EyeCandyClassID:
{
int effect_number;
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>
dplMainZone, // 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
dplMainZone, // DPL zone everything will be in
Point3D::Identity, // Point offset from the parent DCS
this_root->GetDCS(), // 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:
{
int effect_number;
video_iterator.First();
while ((video_wrapper = video_iterator.ReadAndNext()) != NULL)
{
video_object = video_wrapper->GetVideoObject();
effect_number = atoi(video_object->GetObjectFilename());
if(effect_number < 100 || effect_number >= 1000)
{
DPLIndependantEffect(
entity->localOrigin.linearPosition,
effect_number);
}
else
{
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);
#if DEBUG_LEVEL > 0
CameraShipHUDRenderable *my_camera_hud =
#endif
new CameraShipHUDRenderable(
entity,
CameraShipHUDRenderable::Dynamic,
player_index,
display_rank_window
);
Register_Object(my_camera_hud);
}
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
//
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>
dplMainZone, // 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 DEBUG_LEVEL > 0
DPLEyeRenderable* this_eye =
#endif
new DPLEyeRenderable(
entity,
dplMainZone,
LinearMatrix::Identity,
this_root->GetDCS(),
dplMainView,
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.
//------------------------------------------------
dpl_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);
break;
case 1:
left = dpl_LoadObject(object_filename, dpl_load_normal);
break;
case 2:
right = dpl_LoadObject(object_filename, dpl_load_normal);
break;
case 3:
object_lights = dpl_LoadObject(object_filename, dpl_load_normal);
break;
case 4:
left_lights = dpl_LoadObject(object_filename, dpl_load_normal);
break;
case 5:
right_lights = dpl_LoadObject(object_filename, dpl_load_normal);
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;
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>
dplMainZone, // 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,
dplMainZone,
left,
dpl_isect_mode_obj,
NULL,
my_ident,
door_sill->GetDCS(),
left_door_position);
Register_Object(left_door);
DPLChildPointRenderable* right_door =
new DPLChildPointRenderable(
entity,
dplMainZone,
right,
dpl_isect_mode_obj,
NULL,
my_ident,
door_sill->GetDCS(),
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->GetDCS(), // 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->GetDCS(), // 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->GetDCS(), // 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:
{
dpl_OBJECT
*this_object;
dpl_ISECT_MODE
intersect_mode;
uint32
intersect_mask;
LinearMatrix
offset_matrix = LinearMatrix::Identity;
dpl_DCS
*root_DCS,
*this_DCS;
//
// 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" <<hex<<renderer_modes<<dec<< "." << endl);
#endif
if ((resource_type != L4VideoObject::Object) &&
(resource_type != L4VideoObject::Rubble))
{
DEBUG_STREAM << "L4VIDEO.cpp wrong video resource type for object "<<object_filename<<"\n";
continue; // next object
}
SET_VIDEO_LOAD_OBJECT();
this_object = dpl_LoadObject(object_filename, dpl_load_normal);
CLEAR_VIDEO_LOAD_OBJECT();
if (this_object == NULL)
{
DEBUG_STREAM << "L4VIDEO.cpp couldn't load object "<<object_filename<<"\n";
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::ClassDerivations))
{
//
// 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();
RootRenderable *this_root =
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>
dplMainZone, // 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();
root_DCS = this_root->GetDCS();
}
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.
//
RootRenderable *this_static_root =
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>
dplMainZone, // 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_static_root);
root_DCS = this_static_root->GetDCS();
}
//
// 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 DEBUG_LEVEL > 0
DPLEyeRenderable *this_eye =
#endif
new DPLEyeRenderable(
entity,
dplMainZone,
LinearMatrix::Identity,
root_DCS,
dplMainView,
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
//------------------------------------------
DPLStaticChildRenderable *this_child =
new DPLStaticChildRenderable(
entity,
dplMainZone,
this_object,
intersect_mode,
intersect_mask,
offset_matrix,
root_DCS);
Register_Object(this_child);
this_DCS = this_child->GetDCS();
}
else
{
//----------------------------------------
// attach additional objects to root_DCS
// (HACK) temporary implementation (HACK)
//----------------------------------------
#if DEBUG_LEVEL > 0
DCSInstanceRenderable *another_instance =
#endif
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
root_DCS, // 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 (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;
}
}
//
// 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::ClassDerivations))
{
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)
{
cout<<"Frames "<<frame_count<<"\n";
cout<<((float)target_frame_count/(float)frame_count)*100.0f<<"% of the frames were under the target frame time\n";
cout<<"Average Cull "<<(unsigned long)((float)total_cull/(float)frame_count)<<"\n";
cout<<"Average Draw "<<(unsigned long)((float)total_draw/(float)frame_count)<<"\n";
cout<<"Average Pixel Planes "<<(unsigned long)((float)total_pixelplanes/(float)frame_count)<<"\n";
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
)
{
#define VIDEO_CULLING True // Turns video culling on and off
#define COUNT_RENDERABLES False // Counts renderables per entity and frame
#define COUNT_ENTITIES False // Counts the entities per frame
#define CROSS_CHECK_ENTITIES False // Checks entity dynamic socket for renderables
SET_VIDEO_RENDERER();
Entity
*entity;
Component
*component;
#if PRINT_PICKPOINT_TEST
dpl_INSTANCE
*old_instance;
int
old_damage_zone;
#endif
#if USE_TRACKER_STRUCTURE
dpl_tracker
*this_tracker;
#endif
int
current_app_state;
//
// Update the renderer's frame timer
//
currentFrameTime = Now();
//
// Simple HACK to hold us on a blank screen till the mission is actually started.
//
current_app_state = application->GetApplicationState();
if(application->GetApplicationState() != lastAppState)
{
switch(current_app_state)
{
case Application::RunningMission:
dpl_SetViewFog(
dplMainView,
dpl_fog_type_pixel_lin,
fogRed,
fogGreen,
fogBlue,
fogNear,
fogFar );
dpl_FlushView(dplMainView);
dpl_DisableSyncOnCreate();
break;
case Application::StoppingMission:
#if 0
dpl_SetViewFog(
dplMainView,
dpl_fog_type_pixel_lin,
0.0,
0.0,
0.0,
0.1,
0.2 );
dpl_FlushView(dplMainView);
#endif
break;
}
lastAppState = current_app_state;
}
//
// !!!! This may be the WRONG place to do this, but we'll try it
//
// extern dpl_INSTANCE *dpl_SectPixel(dpl_VIEW *, float32, float32, uint32,
// float32 *, float32 *, float32 *,
// dpl_DCS **, dpl_GEOGROUP **, dpl_GEOMETRY **);
// extern dpl_INSTANCE *dpl_RapidSectPixel(float32, float32, float32, uint32,
// float32 *, float32 *, float32 *,
// dpl_DCS **, dpl_GEOGROUP **, dpl_GEOMETRY **);
//
// If there is a reticle pointer defined, do the pickpoint processing
//
SET_VIDEO_PICKPOINT();
if(vehicleReticle)
{
//
// Check the reticle structure to make sure it's ok, then see if pick
// point processing is turned on.
//
Check(vehicleReticle);
if(vehicleReticle->pickPointingOn)
{
//
// Remember the last thing we were targeted on, then go ahead and do the
// intersection call.
//
#if PRINT_PICKPOINT_TEST
old_instance = dplHitInstance;
old_damage_zone = vehicleReticle->targetDamageZone;
#endif
#if RAPID_SECT_PIXEL
dplHitInstance = dpl_RapidSectPixel (
(((vehicleReticle->reticlePosition.x*aspectRatio)/2.0) + 0.5), // go from reticle coordinant system
(((vehicleReticle->reticlePosition.y*aspectRatio)/2.0) + 0.5), // to the screen coordinant system.
1.0e5,
INTERSECT_ALL,
&vehicleReticle->rayIntersection.x,
&vehicleReticle->rayIntersection.y,
&vehicleReticle->rayIntersection.z,
&dplHitDCS,
&dplHitGeoGroup,
&dplHitGeometry);
#else
dplHitInstance = dpl_SectPixel (
dplMainView,
(vehicleReticle->reticlePosition.x/2.0) + 0.5, // go from reticle coordinant system
(vehicleReticle->reticlePosition.y/2.0) + 0.5, // to the screen coordinant system.
INTERSECT_ALL,
&vehicleReticle->rayIntersection.x,
&vehicleReticle->rayIntersection.y,
&vehicleReticle->rayIntersection.z,
&dplHitDCS,
&dplHitGeoGroup,
&dplHitGeometry);
#endif
}
else
{
//
// When pickpoint is off, we should return something sensable
//
dplHitInstance = 0;
}
//
// Set the reticle variables based on whether we hit anything or not
//
if(dplHitInstance)
{
#if PARTICLE_TEST
DPLIndependantEffect(
vehicleReticle->rayIntersection,
1);
#endif
vehicleReticle->targetEntity = (Entity *)dpl_GetAppSpecific(dplHitDCS);
#if USE_TRACKER_STRUCTURE
this_tracker = (dpl_tracker *)dpl_GetAppSpecific(dplHitGeoGroup);
#endif
if(dpl_GetAppSpecific(dplHitGeoGroup))
{
#if USE_TRACKER_STRUCTURE
vehicleReticle->targetDamageZone = this_tracker->Damage_Zone_Number;
#else
vehicleReticle->targetDamageZone = ((int)dpl_GetAppSpecific(dplHitGeoGroup))-1;
#endif
// vehicleReticle->targetEntity = this_tracker->This_Entity;
}
else
{
vehicleReticle->targetDamageZone = -1;
// vehicleReticle->targetEntity = NULL;
}
}
else
{
vehicleReticle->targetDamageZone = -1;
vehicleReticle->targetEntity = NULL;
}
#if PRINT_PICKPOINT_TEST
//------------------------------------------
// code for testing and debugging pickpoint
//------------------------------------------
// If the object we are targeted on changes, we will print out the data
if(dplHitInstance)
{
if( old_instance != dplHitInstance || old_damage_zone != vehicleReticle->targetDamageZone)
{
cout<<"instance app specific="<<dpl_GetAppSpecific(dplHitInstance)<<"\n";
cout<<"DCS app specific="<<dpl_GetAppSpecific(dplHitDCS)<<"\n";
cout<<"AppSpecific="<<this_tracker<<"\n";
cout<<"DCS="<<dplHitDCS<<"Instance="<<dplHitInstance<<" geogroup="<<dplHitGeoGroup<<" geometry="<<dplHitGeometry<<"\n";
cout<<"Intersect="<<vehicleReticle->rayIntersection<<"\n";
cout<<"Target Entity="<<vehicleReticle->targetEntity<<"\n";
if(vehicleReticle->targetEntity)
cout<<"Target Class="<<vehicleReticle->targetEntity->GetClassID()<<"\n";
#if USE_TRACKER_STRUCTURE
cout<<"Damage zone #="<<vehicleReticle->targetDamageZone<<" "<<this_tracker->dz_name<<"\n";
#else
cout<<"Damage zone #="<<vehicleReticle->targetDamageZone<<"\n";
#endif
}
}
#endif
}
CLEAR_VIDEO_PICKPOINT();
//
// Setup the video culling system, this generates the world to eye matrix for
// the currently linked entity and sets the current frame time to Now()
//
#if VIDEO_CULLING
SET_VIDEO_CULL_SETUP();
SetupCull();
CLEAR_VIDEO_CULL_SETUP();
#endif
//
// If we've asked the system to count renderables, setup the total count
//
SET_VIDEO_RENDERABLES();
#if COUNT_RENDERABLES
int
renderable_socket_count;
renderable_socket_count = 0;
#endif
//
// Execute all the dynamic renderables attached to this renderer.
//
SChainIteratorOf<Component*> renderable_iterator(&dplRenderableSocket);
while ((component = renderable_iterator.ReadAndNext()) != NULL)
{
#if COUNT_RENDERABLES
renderable_socket_count++;
#endif
SET_VIDEO_ALL_RENDERABLES();
component->Execute();
CLEAR_VIDEO_ALL_RENDERABLES();
}
//
// Flip trace for all renderables and report renderable count if enabled
//
CLEAR_VIDEO_RENDERABLES();
#if COUNT_RENDERABLES
cout<<"dplRenderableSocket "<<renderable_socket_count<<"\n";
#endif
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// The block of code below is dead, it remains here only so it can be turned
// on to confirm no renderables have "leaked" back into an entity
// dynamic socket. It should be removed once Red Planet has been scrubbed.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
#if CROSS_CHECK_ENTITIES
int
component_count,
total_components;
total_components = 0;
//
// Iterate through all the entities that are interesting to us
//
while ((entity = all_iterator->ReadAndNext()) != NULL)
{
//
// If enabled, flip this trace on vehicle or player renderables
//
#if defined(TRACE_VIDEO_VEHICLE_RENDERABLES)
if( entity->GetClassID() == MechClassID ||
entity->GetClassID() == VTVClassID ||
entity->GetClassID() == BTPlayerClassID)
{
SET_VIDEO_VEHICLE_RENDERABLES();
}
#endif
//
// Create an iterator to iterate over all the dynamic video components
// in this entity. If renderable counting is turned on, initialize
// a counter for this entities renderables
//
Entity::DynamicVideoSocketIterator component_iterator(entity);
component_count=0;
//
// Iterate through all the dynamic video components for this entity
//
while ((component = component_iterator.ReadAndNext()) != NULL)
{
//
// Execute each of the entities components
//
SET_VIDEO_ALL_RENDERABLES();
component->Execute();
CLEAR_VIDEO_ALL_RENDERABLES();
component_count++;
}
//
// If renderable counting is on, report how many renderables this entity
// had and update the totals
//
if(component_count != 0)
{
cout<<"Class "<<entity->GetClassID()<<" had "<<component_count<<" renderables\n";
total_components +=component_count;
}
//
// If enabled, flip this trace off for vehicle or player renderables
//
#if defined(TRACE_VIDEO_VEHICLE_RENDERABLES)
if( entity->GetClassID() == MechClassID ||
entity->GetClassID() == VTVClassID ||
entity->GetClassID() == BTPlayerClassID)
{
CLEAR_VIDEO_VEHICLE_RENDERABLES();
}
#endif
}
if(total_components != 0)
cout<<"Renderables in entity sockets "<<total_components<<"\n";
#endif
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// The block of code above is dead, it remains here only so it can be turned
// on to confirm no renderables have "leaked" back into an entity
// dynamic socket. It should be removed once Red Planet has been scrubbed.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//
// Tell the user how many entities are interesting.
//
#if COUNT_ENTITIES
cout<<"There were "<<all_iterator->GetSize()<<" in the all iterator\n";
#endif
//
// Do a batch DCS flush if we need to
//
DPLDoDCSBatchFlush();
//
// We use the complete cycle handler to take care of calling DrawScene as soon as
// the renderer completes the the frame it's working on.
//
completeCycleNeeded = True;
CLEAR_VIDEO_RENDERER();
CompleteCycle();
}
//
//#############################################################################
// DPLDelayDCSFlush and DPLDoDCSBatchFlush queue up a list of DCS pointers
// for later 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, 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
{
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(ostream &output)
{
output << "Free memory in card: " << dpl_FreeMemory() << " bytes." << endl;
return;
}
//
//#############################################################################
// DPLReportPerfStats writes performance statistics to cout (stdout).
//#############################################################################
//
void
DPLRenderer::DPLReportPerfStats(ostream &output)
{
//-----------------------------------------------------
// 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" << 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 <<
endl;
if(statistics_started)
{
ReportStatistics();
}
else
{
ResetStatistics();
statistics_started = True;
}
return;
}
//
//#############################################################################
// DPLToggleWireframe toggles the state of dpl global wireframe.
//#############################################################################
//
void
DPLRenderer::DPLToggleWireframe()
{
static Logical wireframe_on = 0;
if ((wireframe_on ^= 1) != 0)
{
DEBUG_STREAM << "wireframe ON" << endl;
dpl_SetRenderProperty(dpl_render_prop_wireframe, dpl_render_value_on, NULL );
}
else
{
DEBUG_STREAM << "wireframe OFF" << endl;
dpl_SetRenderProperty(dpl_render_prop_wireframe, dpl_render_value_off, NULL );
}
}
//
//#############################################################################
// DPLTogglePVision toggles the state of dpl "predator" vision.
//#############################################################################
//
void
DPLRenderer::DPLTogglePVision()
{
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" << endl;
sfx_info.type = -1;
}
else
{
DEBUG_STREAM << "pvision OFF" << endl;
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
)
{
//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." << 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 << " ";
//------------
// 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 << endl << "cancelled." << endl;
return;
}
}
if ((y & 15) == 0)
{ DEBUG_STREAM << "."; }
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 << endl;
}
//----------------------------------
// 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 << "' . . . ";
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." << endl;
++dumped_frames; // increment for next frame dump
return;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// DPLRenderer::DPLFrameDump()
void
DPLRenderer::DPLFrameDump(Logical antialias)
{
dump_frame_buffer(dplMainView, x_size, y_size, antialias);
return;
}
//
//#############################################################################
// CompleteCycle is a polling routine that is called in the background to see
// if the renderer is done with a frame, if it is this routine will complete
// the cycle by doing a final batch DCS flush and call do DrawScene to start
// the renderer on the next frame.
//#############################################################################
//
Logical
DPLRenderer::CompleteCycle()
{
Time
current;
//
// Only do this if it hasn't been done yet.
//
if(completeCycleNeeded)
{
SET_VIDEO_RENDERER_FRAME_DONE();
//
// See if the scene is complete (lets us start another without blocking)
//
if(dpl_DrawSceneComplete())
{
//
// Do a batch flush just in case some objects got created during this
// phase of rendering.
//
DPLDoDCSBatchFlush();
//
// Start the renderer on the next scene
//
dpl_DrawScene();
//
// Record statistics
//
if(statistics_started)
{
total_cull += __last_cull_time;
total_draw += __last_draw_time;
total_pixelplanes += __last_pxpl_time;
total_frame_time += __last_frame_time;
frame_count++;
if(__last_frame_time <= target_frame_time)
target_frame_count++;
if(currentFrameTime > report_time)
{
ReportStatistics();
report_time = currentFrameTime + 60.0f;
}
}
#if DEBUG_LEVEL > 0
//
// Code to try and measure average frame rate
// Only active for builds above d0
//
current = Now();
FrameCount ++;
if((current - StartSample) > 10.0f)
{
float frame_rate;
frame_rate = FrameCount / (current-StartSample);
if(frame_rate < 28.0f)
printf("%4.2f fps\n", frame_rate);
StartSample = Now();
FrameCount = 0;
}
#endif
//
// We've started the next frame, so indicate we don't need to do this again.
//
completeCycleNeeded = False;
CLEAR_VIDEO_RENDERER_FRAME_DONE();
return True;
}
CLEAR_VIDEO_RENDERER_FRAME_DONE();
}
return False;
}
//
//#############################################################################
// 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.
{
// 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 );
// 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)
{
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);
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)
{
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()
{
Check(this);
uint32 *worst_case_texels = MakeBitSliceStorage();
Register_Pointer(worst_case_texels);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Get the Entity Group of Players
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
EntityGroup *player_group = application->GetEntityManager()->FindGroup("Players");
Check(player_group);
ChainIteratorOf<Node*> player_iterator(player_group->groupMembers);
Player *current_player;
BitMap *name_bitmap;
while((current_player = (Player*) player_iterator.ReadAndNext() ) != NULL)
{
Check(current_player);
name_bitmap = application->GetCurrentMission()->
GetLargeNameBitmap(current_player->playerBitmapIndex);
if (name_bitmap && current_player->IsScoringPlayer())
{
Check(name_bitmap);
LoadBitSliceTexture(
name_bitmap, // MUNGA 1 bit bitmap to load
(current_player->playerRanking + 1), // Position to load bitmap into
worst_case_texels // 8192 longword array for storage of the texmap
);
}
}
LoadOrdinalBitmaps(worst_case_texels);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Flush all bitmaps down to the card
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
FlushBitSliceTexture(worst_case_texels);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Free the temporary memory the texmaps used
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Unregister_Pointer(worst_case_texels);
free(worst_case_texels);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
DPLRenderer::LoadOrdinalBitmaps(unsigned int *worst_case_texels)
{
Check(this);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 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::ClassDerivations))
)
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Make Sure index is in the right place
// in case < 8 players!!!!
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int index = 9;
for(int ii=1;ii<5;++ii)
{
//
//~~~~~~~~~~~~~~~~~~
// Index Starts at 1
//~~~~~~~~~~~~~~~~~~
//
BitMap *ordinal_bitmap = application->GetCurrentMission()->GetOrdinalBitmap(ii);
Check(ordinal_bitmap);
LoadBitSliceTexture(
ordinal_bitmap, // MUNGA 1 bit bitmap to load
index, // Position to load bitmap into
worst_case_texels // 8192 longword array for storage of the texmap
);
++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()
{
Check(this);
uint32 *worst_case_texels = MakeBitSliceStorage();
Register_Pointer(worst_case_texels);
int player_count;
player_count = application->GetCurrentMission()->GetPlayerCount();
Check(application);
Check(application->GetCurrentMission());
BitMap *name_bitmap;
for (int ii=0;ii<player_count;++ii)
{
name_bitmap =
application->GetCurrentMission()->GetLargeNameBitmap(ii+1);
if (name_bitmap)
{
Check(name_bitmap);
LoadBitSliceTexture(
name_bitmap, // MUNGA 1 bit bitmap to load
ii+1, // Position to load bitmap into
worst_case_texels // 8192 longword array for storage of the texmap
);
}
}
LoadOrdinalBitmaps(worst_case_texels);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Flush all bitmaps down to the card
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
FlushBitSliceTexture(worst_case_texels);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Free the temporary memory the texmaps used
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Unregister_Pointer(worst_case_texels);
delete[] worst_case_texels;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
DPLRenderer::ShutdownImplementation()
{
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)
cout<<"max projectiles "<<projectile_iterator.GetSize()<<"\n";
cout<<"max cached objects "<<cache_iterator.GetSize()<<"\n";
#endif
// 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(
dpl_OBJECT *graphical_object, // object to hang on the DCS, may be a list later <NULL>
dpl_ZONE *this_zone) // DPL Zone this stuff will live in (for culling)
{
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>
this_zone); // 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::ClassDerivations))
{
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." << 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"<<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 " <<dec<< object_count << ", resource size " << stream_length << "\n");
while ((video_wrapper = video_iterator.ReadAndNext()) != NULL)
{
video_object = video_wrapper->GetVideoObject();
*((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);
}
//===========================================================================//