mirror of
https://github.com/thug1src/thug.git
synced 2025-01-21 21:33:46 +00:00
832 lines
28 KiB
C++
832 lines
28 KiB
C++
|
#include <core/defines.h>
|
||
|
|
||
|
#include <gel/collision/collision.h>
|
||
|
#include <gel/collision/colltridata.h>
|
||
|
#include <gel/collision/movcollman.h>
|
||
|
#include <gel/collision/batchtricoll.h>
|
||
|
#include <sys/timer.h>
|
||
|
#include <sk/modules/frontend/frontend.h>
|
||
|
#include <gfx/nx.h>
|
||
|
#include <gfx/NxTexMan.h>
|
||
|
#include <gfx/NxViewMan.h>
|
||
|
#include <gfx/debuggfx.h>
|
||
|
#include <sys/replay/replay.h>
|
||
|
|
||
|
#include "NxMiscFX.h"
|
||
|
|
||
|
|
||
|
namespace Nx
|
||
|
{
|
||
|
|
||
|
Lst::HashTable< sScreenFlashDetails > *p_screen_flash_details_table = NULL;
|
||
|
Lst::HashTable< sSplatInstanceDetails > *p_splat_details_table = NULL;
|
||
|
Lst::HashTable< sSplatTrailInstanceDetails >*p_splat_trail_details_table = NULL;
|
||
|
Lst::HashTable< sShatterInstanceDetails > *p_shatter_details_table = NULL;
|
||
|
|
||
|
static const float DEFAULT_AREA_TEST = 288.0f;
|
||
|
static const float DEFAULT_VELOCITY_VARIANCE = 0.0f;
|
||
|
static const float DEFAULT_SPREAD_FACTOR = 1.0f;
|
||
|
static const float DEFAULT_LIFETIME = 4.0f;
|
||
|
static const float DEFAULT_BOUNCE = -10000.0f;
|
||
|
static const float DEFAULT_BOUNCE_AMPLITUDE = 0.8f;
|
||
|
|
||
|
Mth::Vector shatterVelocity;
|
||
|
float shatterAreaTest = DEFAULT_AREA_TEST * DEFAULT_AREA_TEST;
|
||
|
float shatterVelocityVariance = DEFAULT_VELOCITY_VARIANCE;
|
||
|
float shatterSpreadFactor = DEFAULT_SPREAD_FACTOR;
|
||
|
float shatterLifetime = DEFAULT_LIFETIME;
|
||
|
float shatterBounce = DEFAULT_BOUNCE;
|
||
|
float shatterBounceAmplitude = DEFAULT_BOUNCE_AMPLITUDE;
|
||
|
sTriSubdivideStack triSubdivideStack;
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
int sSplatInstanceDetails::GetOldestSplat( void )
|
||
|
{
|
||
|
int oldest = m_lifetimes[0];
|
||
|
int oldest_idx = 0;
|
||
|
|
||
|
for( uint32 idx = 0; idx < SPLAT_POLYS_PER_MESH; ++idx )
|
||
|
{
|
||
|
if( m_lifetimes[idx] == 0 )
|
||
|
{
|
||
|
return idx;
|
||
|
}
|
||
|
else if( m_lifetimes[idx] < oldest )
|
||
|
{
|
||
|
oldest = m_lifetimes[idx];
|
||
|
oldest_idx = idx;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If we get here there wasn't a 'dead' splat, so return the oldest.
|
||
|
return oldest_idx;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void sTriSubdivideStack::Reset( void )
|
||
|
{
|
||
|
m_offset = 0;
|
||
|
m_block_size = 0;
|
||
|
|
||
|
memset( m_data, 0x03, TRI_SUBDIVIDE_STACK_SIZE );
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void sTriSubdivideStack::Clear( void )
|
||
|
{
|
||
|
m_offset = 0;
|
||
|
m_block_size = 0;
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void sTriSubdivideStack::Push( void *p_data )
|
||
|
{
|
||
|
Dbg_Assert( m_offset + m_block_size < TRI_SUBDIVIDE_STACK_SIZE );
|
||
|
|
||
|
memcpy( m_data + m_offset, p_data, m_block_size );
|
||
|
m_offset += m_block_size;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void sTriSubdivideStack::Pop( void* p_data )
|
||
|
{
|
||
|
Dbg_Assert( m_offset >= m_block_size );
|
||
|
|
||
|
m_offset -= m_block_size;
|
||
|
memcpy( p_data, m_data + m_offset, m_block_size );
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
const void * sTriSubdivideStack::Peek( uint index )
|
||
|
{
|
||
|
int offset = index * m_block_size;
|
||
|
Dbg_MsgAssert( offset < m_offset, ("Index %d is beyond end offset %d", index, m_offset) );
|
||
|
|
||
|
return m_data + offset;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
** Private Functions **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
sShatterInstanceDetails::sShatterInstanceDetails( int num_tris )
|
||
|
{
|
||
|
//Dbg_Message("Allocating %d bytes for position arrays of %d tris", (sizeof(Mth::Vector) * 2 + sizeof(Mth::Matrix)) * num_tris, num_tris);
|
||
|
|
||
|
mp_positions = new Mth::Vector[num_tris];
|
||
|
mp_velocities = new Mth::Vector[num_tris];
|
||
|
mp_matrices = new Mth::Matrix[num_tris];
|
||
|
m_num_triangles = num_tris;
|
||
|
|
||
|
m_gravity = 128.0f;
|
||
|
m_lifetime = shatterLifetime;
|
||
|
m_bounce_level = shatterBounce;
|
||
|
m_bounce_amplitude = shatterBounceAmplitude;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
sShatterInstanceDetails::~sShatterInstanceDetails( void )
|
||
|
{
|
||
|
delete [] mp_positions;
|
||
|
delete [] mp_velocities;
|
||
|
delete [] mp_matrices;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void sShatterInstanceDetails::UpdateParameters( int index, float timestep )
|
||
|
{
|
||
|
Dbg_Assert( index < m_num_triangles );
|
||
|
|
||
|
mp_positions[index] += mp_velocities[index] * timestep;
|
||
|
|
||
|
if(( mp_positions[index][Y] < m_bounce_level ) && ( mp_velocities[index][Y] < 0.0f ))
|
||
|
{
|
||
|
// Hit the floor. Bounce back up.
|
||
|
mp_positions[index][Y] = m_bounce_level + ( m_bounce_level - mp_positions[index][Y] );
|
||
|
mp_velocities[index][Y] = mp_velocities[index][Y] * -m_bounce_amplitude;
|
||
|
|
||
|
// And figure a new rotation matrix.
|
||
|
Mth::Vector axis( -1.0f + ( 2.0f * (float)rand() / RAND_MAX ), -1.0f + ( 2.0f * (float)rand() / RAND_MAX ), -1.0f + ( 2.0f * (float)rand() / RAND_MAX ));
|
||
|
axis.Normalize();
|
||
|
mp_matrices[index].Ident();
|
||
|
mp_matrices[index].Rotate( axis, 0.1f * ((float)rand() / RAND_MAX ));
|
||
|
}
|
||
|
|
||
|
mp_velocities[index][Y] -= m_gravity * timestep;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
int sShatterInstanceDetails::s_query_memory_needed(int num_tris)
|
||
|
{
|
||
|
int size = sizeof(sShatterInstanceDetails);
|
||
|
size += (2 * sizeof(Mth::Vector) + sizeof(Mth::Matrix)) * num_tris;
|
||
|
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
** Public Functions **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void MiscFXInitialize( void )
|
||
|
{
|
||
|
if( p_screen_flash_details_table == NULL )
|
||
|
{
|
||
|
p_screen_flash_details_table = new Lst::HashTable< sScreenFlashDetails >( 4 );
|
||
|
}
|
||
|
|
||
|
if( p_splat_details_table == NULL )
|
||
|
{
|
||
|
p_splat_details_table = new Lst::HashTable< sSplatInstanceDetails >( 4 );
|
||
|
}
|
||
|
|
||
|
if( p_splat_trail_details_table == NULL )
|
||
|
{
|
||
|
p_splat_trail_details_table = new Lst::HashTable< sSplatTrailInstanceDetails >( 4 );
|
||
|
}
|
||
|
|
||
|
if( p_shatter_details_table == NULL )
|
||
|
{
|
||
|
p_shatter_details_table = new Lst::HashTable< sShatterInstanceDetails >( 4 );
|
||
|
}
|
||
|
|
||
|
plat_texture_splat_initialize();
|
||
|
plat_shatter_initialize();
|
||
|
|
||
|
triSubdivideStack.Reset();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void MiscFXCleanup( void )
|
||
|
{
|
||
|
// Can cleanup the screen flash details here, since they are not platform specific.
|
||
|
p_screen_flash_details_table->IterateStart();
|
||
|
sScreenFlashDetails *p_details = p_screen_flash_details_table->IterateNext();
|
||
|
while( p_details )
|
||
|
{
|
||
|
sScreenFlashDetails *p_delete = p_details;
|
||
|
p_details = p_screen_flash_details_table->IterateNext();
|
||
|
|
||
|
p_screen_flash_details_table->FlushItem((uint32)p_delete );
|
||
|
delete p_delete;
|
||
|
}
|
||
|
|
||
|
// Ditto for the tetxure splat trail details.
|
||
|
KillAllTextureSplats();
|
||
|
|
||
|
// Clean up the shatter details.
|
||
|
plat_shatter_cleanup();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void KillAllTextureSplats( void )
|
||
|
{
|
||
|
// This was split into a separate function because it can also be used after turning geometry off,
|
||
|
// to ensure no splats are 'floating'.
|
||
|
p_splat_trail_details_table->IterateStart();
|
||
|
sSplatTrailInstanceDetails *p_trail_details = p_splat_trail_details_table->IterateNext();
|
||
|
while( p_trail_details )
|
||
|
{
|
||
|
sSplatTrailInstanceDetails *p_delete = p_trail_details;
|
||
|
p_trail_details = p_splat_trail_details_table->IterateNext();
|
||
|
|
||
|
p_splat_trail_details_table->FlushItem((uint32)p_delete );
|
||
|
delete p_delete;
|
||
|
}
|
||
|
|
||
|
// Call the platform specific cleanup function.
|
||
|
plat_texture_splat_cleanup();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void AddScreenFlash( int viewport, Image::RGBA from, Image::RGBA to, float duration, float z, uint32 flags, const char *p_texture_name )
|
||
|
{
|
||
|
Replay::WriteScreenFlash(viewport, from, to, duration, z, flags);
|
||
|
|
||
|
// Ensure the supplied viewport is within bounds.
|
||
|
#ifdef __NOPT_ASSERT__
|
||
|
int num_viewports = CViewportManager::sGetNumActiveViewports();
|
||
|
Dbg_Assert( viewport < num_viewports );
|
||
|
#endif // __NOPT_ASSERT__
|
||
|
|
||
|
// Resolve the texture name if present.
|
||
|
CTexture *p_texture = NULL;
|
||
|
if( p_texture_name )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
// Store these details.
|
||
|
sScreenFlashDetails *p_flash = new sScreenFlashDetails;
|
||
|
p_flash->m_from = from;
|
||
|
p_flash->m_to = to;
|
||
|
p_flash->m_duration = duration;
|
||
|
p_flash->m_lifetime = duration;
|
||
|
p_flash->m_z = z;
|
||
|
p_flash->m_flags = flags;
|
||
|
p_flash->mp_texture = p_texture;
|
||
|
p_flash->m_viewport = viewport;
|
||
|
|
||
|
p_screen_flash_details_table->PutItem((uint32)p_flash, p_flash );
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void ScreenFlashUpdate( void )
|
||
|
{
|
||
|
float framelength = Tmr::FrameLength();
|
||
|
|
||
|
if( p_screen_flash_details_table )
|
||
|
{
|
||
|
p_screen_flash_details_table->IterateStart();
|
||
|
sScreenFlashDetails *p_details = p_screen_flash_details_table->IterateNext();
|
||
|
while( p_details )
|
||
|
{
|
||
|
sScreenFlashDetails *p_delete = NULL;
|
||
|
|
||
|
// Don't process if paused.
|
||
|
if( !Mdl::FrontEnd::Instance()->GamePaused() || ( p_details->m_flags & Nx::SCREEN_FLASH_FLAG_IGNORE_PAUSE ))
|
||
|
{
|
||
|
p_details->m_lifetime -= framelength;
|
||
|
if( p_details->m_lifetime > 0.0f )
|
||
|
{
|
||
|
// Calculate the current color.
|
||
|
float mult = p_details->m_lifetime / p_details->m_duration;
|
||
|
p_details->m_current.r = p_details->m_to.r + (int)(((float)p_details->m_from.r - (float)p_details->m_to.r ) * mult );
|
||
|
p_details->m_current.g = p_details->m_to.g + (int)(((float)p_details->m_from.g - (float)p_details->m_to.g ) * mult );
|
||
|
p_details->m_current.b = p_details->m_to.b + (int)(((float)p_details->m_from.b - (float)p_details->m_to.b ) * mult );
|
||
|
p_details->m_current.a = p_details->m_to.a + (int)(((float)p_details->m_from.a - (float)p_details->m_to.a ) * mult );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
p_delete = p_details;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
p_details = p_screen_flash_details_table->IterateNext();
|
||
|
|
||
|
if( p_delete )
|
||
|
{
|
||
|
p_screen_flash_details_table->FlushItem((uint32)p_delete );
|
||
|
delete p_delete;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void ScreenFlashRender( int viewport, uint32 flags )
|
||
|
{
|
||
|
p_screen_flash_details_table->IterateStart();
|
||
|
sScreenFlashDetails *p_details = p_screen_flash_details_table->IterateNext();
|
||
|
while( p_details )
|
||
|
{
|
||
|
if( viewport == p_details->m_viewport )
|
||
|
{
|
||
|
if(( flags & Nx::SCREEN_FLASH_FLAG_BEHIND_PANEL ) == ( p_details->m_flags & Nx::SCREEN_FLASH_FLAG_BEHIND_PANEL ))
|
||
|
{
|
||
|
plat_screen_flash_render( p_details );
|
||
|
}
|
||
|
}
|
||
|
p_details = p_screen_flash_details_table->IterateNext();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void TextureSplatUpdate( void )
|
||
|
{
|
||
|
// Don't process if paused.
|
||
|
if( Mdl::FrontEnd::Instance()->GamePaused() && !Replay::RunningReplay())
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if( p_splat_details_table )
|
||
|
{
|
||
|
int framelength_in_ms = (int)( Tmr::FrameLength() * 1000.0f );
|
||
|
|
||
|
p_splat_details_table->IterateStart();
|
||
|
sSplatInstanceDetails *p_details = p_splat_details_table->IterateNext();
|
||
|
while( p_details )
|
||
|
{
|
||
|
// Initialize to -1 to indicate no active splats so far.
|
||
|
p_details->m_highest_active_splat = -1;
|
||
|
|
||
|
for( int i = 0; i < SPLAT_POLYS_PER_MESH; ++i )
|
||
|
{
|
||
|
if( p_details->m_lifetimes[i] > 0 )
|
||
|
{
|
||
|
p_details->m_lifetimes[i] -= framelength_in_ms;
|
||
|
if( p_details->m_lifetimes[i] <= 0 )
|
||
|
{
|
||
|
// Make sure to set lifetime back to exactly zero to indicate ready for re-use.
|
||
|
p_details->m_lifetimes[i] = 0;
|
||
|
|
||
|
// This splat has just 'expired'. Reset this poly.
|
||
|
plat_texture_splat_reset_poly( p_details, i );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
p_details->m_highest_active_splat = i;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
p_details = p_splat_details_table->IterateNext();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
bool TextureSplat( Mth::Vector& splat_start, Mth::Vector& splat_end, float size, float lifetime, const char *p_texture_name, uint32 trail )
|
||
|
{
|
||
|
Replay::WriteTextureSplat(splat_start,splat_end,size,lifetime,p_texture_name,trail);
|
||
|
|
||
|
// If this is a flagged as a trail splat, see if we have a trail instance already that matches.
|
||
|
sSplatTrailInstanceDetails *p_trail_details = NULL;
|
||
|
if( trail > 0 )
|
||
|
{
|
||
|
uint32 time = Tmr::GetTime();
|
||
|
|
||
|
p_splat_trail_details_table->IterateStart();
|
||
|
p_trail_details = p_splat_trail_details_table->IterateNext();
|
||
|
while( p_trail_details )
|
||
|
{
|
||
|
sSplatTrailInstanceDetails *p_delete = NULL;
|
||
|
|
||
|
if(( time < p_trail_details->m_last_pos_added_time ) || (( time - p_trail_details->m_last_pos_added_time ) > 500 ))
|
||
|
{
|
||
|
// This trail is over half a second old - remove it.
|
||
|
p_delete = p_trail_details;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// This trail had a point added within the last half second, so check it for bone ID.
|
||
|
if( p_trail_details->m_trail_id == trail )
|
||
|
{
|
||
|
// ID's match, so check it for proximity. Seems like fast moving reverts can cause successive calls to be up to 5.5 feet away.
|
||
|
float sq_dist = ( splat_start - p_trail_details->m_last_pos ).LengthSqr();
|
||
|
if( sq_dist < ( 66.0f * 66.0f ))
|
||
|
{
|
||
|
// This trail had a point added within the last half second that is within 3 feet of this point. Select this trail.
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
p_trail_details = p_splat_trail_details_table->IterateNext();
|
||
|
|
||
|
if( p_delete )
|
||
|
{
|
||
|
p_splat_trail_details_table->FlushItem((uint32)p_delete );
|
||
|
delete p_delete;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If there were no trail details, create a new instance and just return.
|
||
|
if( p_trail_details == NULL )
|
||
|
{
|
||
|
p_trail_details = new sSplatTrailInstanceDetails;
|
||
|
p_trail_details->m_trail_id = trail;
|
||
|
p_trail_details->m_last_pos = splat_start;
|
||
|
p_trail_details->m_last_pos_added_time = time;
|
||
|
p_splat_trail_details_table->PutItem((uint32)p_trail_details, p_trail_details );
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Convert the name string to a checksum.
|
||
|
uint32 texture_checksum = Crc::GenerateCRCFromString( p_texture_name );
|
||
|
|
||
|
// Obtain a pointer to the texture.
|
||
|
Nx::CTexture *p_texture = Nx::CTexDictManager::sp_particle_tex_dict->GetTexture( texture_checksum );
|
||
|
Dbg_MsgAssert( p_texture, ("Couldn't find texture %s in particle texture dictionary", p_texture_name) );
|
||
|
|
||
|
Mth::Line is( splat_start, splat_end );
|
||
|
|
||
|
// Make initial line bounding box.
|
||
|
Mth::CBBox line_bbox( is.m_start );
|
||
|
line_bbox.AddPoint( is.m_end );
|
||
|
|
||
|
// Get a list of all collision sectors within all super sectors that the line intersects.
|
||
|
// This is a very fast call, but likely to provide many collision sectors that are not actually within the
|
||
|
// bounding box of the line.
|
||
|
SSec::Manager *ss_man = Nx::CEngine::sGetNearestSuperSectorManager( is );
|
||
|
Nx::CCollStatic **pp_coll_obj_list = ss_man->GetIntersectingCollSectors( is );
|
||
|
|
||
|
// Can't create blood splat if no objects found.
|
||
|
if( !pp_coll_obj_list )
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// The sector table is used to pass a platform independent set of CSector pointers to the below p-line code.
|
||
|
// Garrett: Also added static collision table, just in case CSector points to a CCollMulti
|
||
|
#define SECTOR_TABLE_SIZE 127
|
||
|
static CSector* sector_table[SECTOR_TABLE_SIZE + 1];
|
||
|
static Nx::CCollStatic* collision_table[SECTOR_TABLE_SIZE + 1];
|
||
|
|
||
|
int sector_table_index = 0;
|
||
|
Nx::CCollStatic *p_coll_obj;
|
||
|
while(( p_coll_obj = *pp_coll_obj_list ))
|
||
|
{
|
||
|
if( p_coll_obj->GetGeometry())
|
||
|
{
|
||
|
// Determine whether this collision sector actually falls within the bounding box of our line.
|
||
|
if( p_coll_obj->GetGeometry()->GetBBox().Intersect( line_bbox ))
|
||
|
{
|
||
|
uint32 checksum = p_coll_obj->GetChecksum();
|
||
|
|
||
|
// From the checksum we can get the CSector (the renderable version) from the hash table of the scene.
|
||
|
Nx::CSector *p_sector = Nx::CEngine::sGetSector( checksum );
|
||
|
|
||
|
// Store the pointer in the table.
|
||
|
Dbg_Assert( sector_table_index < SECTOR_TABLE_SIZE );
|
||
|
collision_table[sector_table_index] = p_coll_obj;
|
||
|
sector_table[sector_table_index++] = p_sector;
|
||
|
}
|
||
|
++pp_coll_obj_list;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Mark the end of the sector table with a NULL pointer.
|
||
|
if( sector_table_index > 0 )
|
||
|
{
|
||
|
sector_table[sector_table_index] = NULL;
|
||
|
collision_table[sector_table_index] = NULL;
|
||
|
|
||
|
// Make sure we can can calculate an up vector. If not, just move on.
|
||
|
bool rv;
|
||
|
if ((trail == 0) || (splat_start[X] != p_trail_details->m_last_pos[X]) || (splat_start[Z] != p_trail_details->m_last_pos[Z]))
|
||
|
{
|
||
|
rv = plat_texture_splat( sector_table, collision_table, splat_start, splat_end, size, lifetime, p_texture, p_trail_details );
|
||
|
} else {
|
||
|
rv = false;
|
||
|
}
|
||
|
|
||
|
// Update the trail details if present.
|
||
|
if( p_trail_details )
|
||
|
{
|
||
|
p_trail_details->m_last_pos = splat_start;
|
||
|
p_trail_details->m_last_pos_added_time = Tmr::GetTime();
|
||
|
}
|
||
|
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void TextureSplatRender( void )
|
||
|
{
|
||
|
|
||
|
|
||
|
plat_texture_splat_render();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void ShatterSetParams( Mth::Vector& velocity, float area_test, float velocity_variance, float spread_factor, float lifetime, float bounce, float bounce_amplitude )
|
||
|
{
|
||
|
Replay::WriteShatterParams(velocity, area_test, velocity_variance, spread_factor, lifetime, bounce, bounce_amplitude);
|
||
|
|
||
|
shatterVelocity = velocity;
|
||
|
shatterAreaTest = ( area_test == 0.0f ) ? ( DEFAULT_AREA_TEST * DEFAULT_AREA_TEST ) : ( area_test * area_test );
|
||
|
shatterVelocityVariance = ( velocity_variance == 0.0f ) ? DEFAULT_VELOCITY_VARIANCE : velocity_variance;
|
||
|
shatterSpreadFactor = ( spread_factor == 0.0f ) ? DEFAULT_SPREAD_FACTOR : spread_factor;
|
||
|
shatterLifetime = ( lifetime == 0.0f ) ? DEFAULT_LIFETIME : lifetime;
|
||
|
shatterBounce = ( bounce == 0.0f ) ? DEFAULT_BOUNCE : bounce;
|
||
|
shatterBounceAmplitude = ( bounce_amplitude == 0.0f ) ? DEFAULT_BOUNCE_AMPLITUDE : bounce_amplitude;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void Shatter( CGeom *p_geom )
|
||
|
{
|
||
|
plat_shatter( p_geom );
|
||
|
|
||
|
// After shattering the subdivision stack should be empty.
|
||
|
Dbg_Assert( triSubdivideStack.IsEmpty());
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void ShatterUpdate( void )
|
||
|
{
|
||
|
// Don't process if paused.
|
||
|
if( Mdl::FrontEnd::Instance()->GamePaused() && !Replay::RunningReplay())
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
if (Replay::Paused())
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if( p_shatter_details_table )
|
||
|
{
|
||
|
float framelength = Tmr::FrameLength();
|
||
|
|
||
|
p_shatter_details_table->IterateStart();
|
||
|
sShatterInstanceDetails *p_details = p_shatter_details_table->IterateNext();
|
||
|
while( p_details )
|
||
|
{
|
||
|
sShatterInstanceDetails *p_delete = NULL;
|
||
|
|
||
|
p_details->m_lifetime -= framelength;
|
||
|
if( p_details->m_lifetime <= 0.0f )
|
||
|
{
|
||
|
// Remove this entry from the table and destroy at the bottom of the loop.
|
||
|
p_delete = p_details;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
plat_shatter_update( p_details, framelength );
|
||
|
}
|
||
|
p_details = p_shatter_details_table->IterateNext();
|
||
|
|
||
|
if( p_delete )
|
||
|
{
|
||
|
p_shatter_details_table->FlushItem((uint32)p_delete );
|
||
|
delete p_delete;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void ShatterRender( void )
|
||
|
{
|
||
|
if( p_shatter_details_table )
|
||
|
{
|
||
|
p_shatter_details_table->IterateStart();
|
||
|
sShatterInstanceDetails *p_details = p_shatter_details_table->IterateNext();
|
||
|
while( p_details )
|
||
|
{
|
||
|
plat_shatter_render( p_details );
|
||
|
p_details = p_shatter_details_table->IterateNext();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// FOG
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////
|
||
|
|
||
|
bool CFog::s_enabled = false;
|
||
|
float CFog::s_near_distance = 3000.0f;
|
||
|
float CFog::s_exponent = 10.0f;
|
||
|
Image::RGBA CFog::s_rgba(0x60, 0x60, 0x80, 0x66);
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
void CFog::sEnableFog(bool enable)
|
||
|
{
|
||
|
s_enabled = enable;
|
||
|
s_plat_enable_fog(enable);
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
void CFog::sSetFogNearDistance(float distance)
|
||
|
{
|
||
|
s_near_distance = distance;
|
||
|
s_plat_set_fog_near_distance(distance);
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
void CFog::sSetFogExponent(float exponent)
|
||
|
{
|
||
|
s_exponent = exponent;
|
||
|
s_plat_set_fog_exponent(exponent);
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
void CFog::sSetFogRGBA(Image::RGBA rgba)
|
||
|
{
|
||
|
s_rgba = rgba;
|
||
|
s_plat_set_fog_rgba(rgba);
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
void CFog::sSetFogColor( void )
|
||
|
{
|
||
|
s_plat_set_fog_color();
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
void CFog::sFogUpdate( void )
|
||
|
{
|
||
|
s_plat_fog_update();
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
bool CFog::sIsFogEnabled()
|
||
|
{
|
||
|
return s_enabled;
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
float CFog::sGetFogNearDistance()
|
||
|
{
|
||
|
return s_near_distance;
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
float CFog::sGetFogExponent()
|
||
|
{
|
||
|
return s_exponent;
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
Image::RGBA CFog::sGetFogRGBA()
|
||
|
{
|
||
|
return s_rgba;
|
||
|
}
|
||
|
|
||
|
} // Nx
|