mirror of
https://github.com/thug1src/thug.git
synced 2025-01-21 21:33:46 +00:00
792 lines
25 KiB
C++
792 lines
25 KiB
C++
/*****************************************************************************
|
|
** **
|
|
** Neversoft Entertainment. **
|
|
** **
|
|
** Copyright (C) 2000 - All Rights Reserved **
|
|
** **
|
|
******************************************************************************
|
|
** **
|
|
** Project: Skate5 **
|
|
** **
|
|
** Module: Gfx **
|
|
** **
|
|
** File name: p_NxNewParticle.cpp **
|
|
** **
|
|
** Created by: 3/25/03 - SPG **
|
|
** **
|
|
** Description: Ngc new parametric particle system **
|
|
*****************************************************************************/
|
|
|
|
#include <core/defines.h>
|
|
|
|
#include <gfx/Ngc/p_nxnewparticle.h>
|
|
|
|
#include <gfx/NxTexMan.h>
|
|
#include <gfx/Ngc/p_nxtexture.h>
|
|
#include <gfx/Ngc/nx/nx_init.h>
|
|
#include <gfx/Ngc/nx/render.h>
|
|
|
|
#include "gfx/ngc/p_nxparticle.h"
|
|
|
|
#include "dolphin/base/ppcwgpipe.h"
|
|
#include "dolphin/gx/gxvert.h"
|
|
#include <charpipeline/GQRSetup.h>
|
|
|
|
|
|
extern "C"
|
|
{
|
|
|
|
extern float ReciprocalEstimate_ASM( float f );
|
|
|
|
extern void RenderNewParticles( Nx::CParticleStream * p_stream, float lifetime, float midpercent, bool use_mid_color, Image::RGBA * p_color0, Mth::Vector * p0, Mth::Vector * sr, Mth::Vector * su, float * p_params, float nearz );
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
** DBG Information **
|
|
*****************************************************************************/
|
|
|
|
namespace Nx
|
|
{
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
** Externals **
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
** Defines **
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
** Private Types **
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
** Private Data **
|
|
*****************************************************************************/
|
|
|
|
//static int rand_seed;
|
|
//static int rand_a = 314159265;
|
|
//static int rand_b = 178453311;
|
|
|
|
|
|
/*****************************************************************************
|
|
** Public Data **
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
** Private Prototypes **
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
** Private Functions **
|
|
*****************************************************************************/
|
|
|
|
///******************************************************************/
|
|
///* */
|
|
///* */
|
|
///******************************************************************/
|
|
//static void seed_particle_rnd( int s, int a, int b )
|
|
//{
|
|
// rand_seed = s;
|
|
// rand_a = a;
|
|
// rand_b = b;
|
|
//}
|
|
//
|
|
//
|
|
//
|
|
///******************************************************************/
|
|
///* */
|
|
///* */
|
|
///******************************************************************/
|
|
//static int particle_rnd( int n )
|
|
//{
|
|
// rand_seed = rand_seed * rand_a + rand_b;
|
|
// rand_a = ( rand_a ^ rand_seed ) + ( rand_seed >> 4 );
|
|
// rand_b += ( rand_seed >> 3 ) - 0x10101010L;
|
|
// return (int)(( rand_seed & 0xffff ) * n ) >> 16;
|
|
//}
|
|
//
|
|
//
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
void CParticleStream::AdvanceSeed( int num_places )
|
|
{
|
|
// // Seed the random number generator back to the current seed.
|
|
// seed_particle_rnd( m_rand_seed, m_rand_a, m_rand_b );
|
|
//
|
|
// // Each particle will call the random function four times.
|
|
// for( int i = 0; i < ( num_places * 4 ); i++ )
|
|
// {
|
|
// particle_rnd( 1 );
|
|
// }
|
|
//
|
|
// m_rand_seed = rand_seed;
|
|
// m_rand_a = rand_a;
|
|
// m_rand_b = rand_b;
|
|
|
|
// Seed the random number generator back to the current seed.
|
|
uint32 rand_current = m_rand_current;
|
|
|
|
// Each particle will call the random function four times.
|
|
for( int i = 0; i < ( num_places * 4 ); i++ )
|
|
{
|
|
rand_current = ( rand_current & 1 ) ? ( rand_current >> 1 ) ^ 0x3500 : ( rand_current >> 1 );
|
|
}
|
|
|
|
m_rand_current = rand_current;
|
|
}
|
|
|
|
|
|
|
|
//inline DWORD FtoDW( FLOAT f ) { return *((DWORD*)&f); }
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
void CNgcNewParticle::plat_render( void )
|
|
{
|
|
CParticleStream* p_stream;
|
|
int i;
|
|
|
|
// Process the streams.
|
|
if( m_params.m_EmitRate && ( !m_emitting || ( m_params.m_EmitRate != mp_newest_stream->m_rate )))
|
|
{
|
|
if( m_num_streams < m_max_streams )
|
|
{
|
|
// Add new stream to cyclic buffer
|
|
m_num_streams++;
|
|
mp_newest_stream++;
|
|
if( mp_newest_stream == mp_stream + m_max_streams )
|
|
{
|
|
mp_newest_stream = mp_stream;
|
|
}
|
|
|
|
// Initialise new stream.
|
|
mp_newest_stream->m_rate = m_params.m_EmitRate;
|
|
mp_newest_stream->m_interval = 1.0f / m_params.m_EmitRate;
|
|
mp_newest_stream->m_oldest_age = 0.0f;
|
|
mp_newest_stream->m_num_particles = 0;
|
|
// mp_newest_stream->m_rand_seed = rand();
|
|
// mp_newest_stream->m_rand_a = 314159265;
|
|
// mp_newest_stream->m_rand_b = 178453311;
|
|
mp_newest_stream->m_rand_current = rand() & ( 16384 - 1 );
|
|
if ( mp_newest_stream->m_rand_current == 0 ) mp_newest_stream->m_rand_current = 1;
|
|
m_emitting = true;
|
|
}
|
|
else
|
|
{
|
|
m_emitting = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_emitting = m_params.m_EmitRate;
|
|
}
|
|
|
|
if( !m_num_streams )
|
|
return;
|
|
|
|
// Age all streams.
|
|
for( i = 0, p_stream = mp_oldest_stream; i < m_num_streams; ++i )
|
|
{
|
|
// Increase age of oldest particle.
|
|
p_stream->m_oldest_age += 1.0f / 60.0f;
|
|
|
|
// Step pointer within cyclic buffer.
|
|
p_stream++;
|
|
if( p_stream == mp_stream + m_max_streams )
|
|
{
|
|
p_stream = mp_stream;
|
|
}
|
|
}
|
|
|
|
// Births into newest stream.
|
|
if( m_emitting )
|
|
{
|
|
// How many particles so far emitted?
|
|
mp_newest_stream->m_num_particles = (int)( mp_newest_stream->m_oldest_age * mp_newest_stream->m_rate + 1.0f );
|
|
}
|
|
|
|
// Deaths from oldest stream.
|
|
if( mp_oldest_stream->m_oldest_age > m_params.m_Lifetime )
|
|
{
|
|
// Work out number dead.
|
|
int particles_dead = (int)(( mp_oldest_stream->m_oldest_age - m_params.m_Lifetime ) * mp_oldest_stream->m_rate + 1.0f );
|
|
|
|
// Remove dead particles.
|
|
mp_oldest_stream->m_num_particles -= particles_dead;
|
|
|
|
// Should we keep processing the oldest stream?
|
|
if( mp_oldest_stream->m_num_particles > 0 || ( m_num_streams == 1 && m_emitting ))
|
|
{
|
|
// Adjust age of oldest particle.
|
|
mp_oldest_stream->m_oldest_age -= (float)particles_dead * mp_oldest_stream->m_interval;
|
|
|
|
// Advance seed.
|
|
mp_oldest_stream->AdvanceSeed( particles_dead );
|
|
}
|
|
else
|
|
{
|
|
// Remove oldest stream and wrap in cyclic buffer if necessary.
|
|
m_num_streams--;
|
|
mp_oldest_stream++;
|
|
if( mp_oldest_stream == mp_stream + m_max_streams )
|
|
{
|
|
mp_oldest_stream = mp_stream;
|
|
}
|
|
if( !m_num_streams )
|
|
return;
|
|
}
|
|
}
|
|
|
|
// // Now render the streams. after checking the bounding sphere is visible.
|
|
// D3DXVECTOR3 center( m_bsphere[X], m_bsphere[Y], m_bsphere[Z] );
|
|
// if( !NxNgc::frustum_check_sphere( ¢er, m_bsphere[W] ))
|
|
// {
|
|
// return;
|
|
// }
|
|
if( !m_params.m_LocalCoord )
|
|
{
|
|
if ( !NxNgc::frustum_check_sphere( m_bsphere ) ) return;
|
|
}
|
|
// if ( NxNgc::TestSphereAgainstOccluders( &sphere ) )
|
|
|
|
GX::SetChanCtrl( GX_COLOR0A0, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE );
|
|
GX::SetVtxDesc( 2, GX_VA_POS, GX_DIRECT, GX_VA_TEX0, GX_DIRECT );
|
|
|
|
NxNgc::sMaterialHeader mat;
|
|
NxNgc::sMaterialPassHeader pass;
|
|
|
|
mat.m_checksum = 0;
|
|
mat.m_passes = 1;
|
|
mat.m_alpha_cutoff = 0;
|
|
mat.m_flags = 0;
|
|
// mat.m_material_dl_id = 0;
|
|
mat.m_draw_order = 0;
|
|
mat.m_pass_item = 0;
|
|
mat.m_texture_dl_id = 0;
|
|
// mat.m_shininess = 0;
|
|
// mat.m_specular_color = (GXColor){255,255,255,255};
|
|
|
|
pass.m_texture.p_data = mp_texture;
|
|
pass.m_flags = (1<<0)|(1<<5)|(1<<6);
|
|
pass.m_filter = 0;
|
|
pass.m_blend_mode = m_blend;
|
|
pass.m_alpha_fix = m_fix;
|
|
pass.m_uv_wibble_index = 0;
|
|
pass.m_color = (GXColor){64,64,64,255};
|
|
pass.m_k = 0;
|
|
pass.m_u_tile = 0;
|
|
pass.m_v_tile = 0;
|
|
pass.m_uv_enabled = false;
|
|
|
|
multi_mesh( &mat, &pass, true, true );
|
|
GX::SetCurrMtxPosTex03( GX_PNMTX0, GX_IDENTITY, GX_IDENTITY, GX_IDENTITY, GX_IDENTITY );
|
|
|
|
// Get the 'right' vector as the cross product of camera 'at and world 'up'.
|
|
NsMatrix* p_matrix = &NxNgc::EngineGlobals.camera;
|
|
|
|
NsVector up( 0.0f, 1.0f, 0.0f );
|
|
NsVector screen_right;
|
|
NsVector screen_up;
|
|
screen_right.cross( *p_matrix->getAt(), up );
|
|
screen_up.cross( screen_right, *p_matrix->getAt());
|
|
|
|
screen_right.normalize();
|
|
screen_up.normalize();
|
|
|
|
Mth::Vector sr;
|
|
Mth::Vector su;
|
|
sr[X] = screen_right.x;
|
|
sr[Y] = screen_right.y;
|
|
sr[Z] = screen_right.z;
|
|
sr[W] = 1.0f;
|
|
|
|
su[X] = screen_up.x;
|
|
su[Y] = screen_up.y;
|
|
su[Z] = screen_up.z;
|
|
su[W] = 1.0f;
|
|
|
|
GQRSetup6( GQR_SCALE_64, // Pos
|
|
GQR_TYPE_S16,
|
|
GQR_SCALE_64,
|
|
GQR_TYPE_S16 );
|
|
GQRSetup7( 14, // Normal
|
|
GQR_TYPE_S16,
|
|
14,
|
|
GQR_TYPE_S16 );
|
|
|
|
f32 pm[GX_PROJECTION_SZ];
|
|
f32 vp[GX_VIEWPORT_SZ];
|
|
|
|
GX::GetProjectionv( pm );
|
|
GX::GetViewportv( vp );
|
|
NsMatrix * p_mtx = &NxNgc::EngineGlobals.local_to_camera;
|
|
|
|
float params[6];
|
|
params[0] = p_mtx->getAtX();
|
|
params[1] = p_mtx->getAtY();
|
|
params[2] = p_mtx->getPosZ();
|
|
params[3] = p_mtx->getAtZ();
|
|
params[4] = pm[1];
|
|
params[5] = vp[2];
|
|
|
|
// Construct a packet with data for each stream.
|
|
for( i = 0, p_stream = mp_oldest_stream; i < m_num_streams; i++, p_stream++ )
|
|
{
|
|
Dbg_MsgAssert( p_stream->m_num_particles < 65536, ( "particle limit reached" ));
|
|
|
|
// Wrap at end of cyclic buffer.
|
|
if( p_stream == mp_stream + m_max_streams )
|
|
{
|
|
p_stream = mp_stream;
|
|
}
|
|
|
|
#if 1
|
|
RenderNewParticles( p_stream,
|
|
m_params.m_Lifetime,
|
|
m_params.m_ColorMidpointPct,
|
|
m_params.m_UseMidcolor,
|
|
&m_params.m_Color[0],
|
|
&m_s0,
|
|
&sr,
|
|
&su,
|
|
params,
|
|
256.0f );
|
|
|
|
#else
|
|
float t = p_stream->m_oldest_age;
|
|
float midpoint_time = m_params.m_Lifetime * ( m_params.m_ColorMidpointPct * 0.01f );
|
|
|
|
// Seed the random number generators for this stream.
|
|
// seed_particle_rnd( p_stream->m_rand_seed, p_stream->m_rand_a, p_stream->m_rand_b );
|
|
uint32 rand_current = p_stream->m_rand_current;
|
|
|
|
for( int p = 0; p < p_stream->m_num_particles; ++p )
|
|
{
|
|
// Generate random vector. Each component in the range [1.0, 2.0].
|
|
// Mth::Vector r( 1.0f + ((float)particle_rnd( 16384 ) / 16384 ),
|
|
// 1.0f + ((float)particle_rnd( 16384 ) / 16384 ),
|
|
// 1.0f + ((float)particle_rnd( 16384 ) / 16384 ),
|
|
// 1.0f + ((float)particle_rnd( 16384 ) / 16384 ));
|
|
|
|
Mth::Vector r;
|
|
r[X] = 1.0f + ((float)( rand_current = ( ( rand_current & 1 ) ? ( rand_current >> 1 ) ^ 0x3500 : ( rand_current >> 1 ) ) ) / 16384.0f );
|
|
r[Y] = 1.0f + ((float)( rand_current = ( ( rand_current & 1 ) ? ( rand_current >> 1 ) ^ 0x3500 : ( rand_current >> 1 ) ) ) / 16384.0f );
|
|
r[Z] = 1.0f + ((float)( rand_current = ( ( rand_current & 1 ) ? ( rand_current >> 1 ) ^ 0x3500 : ( rand_current >> 1 ) ) ) / 16384.0f );
|
|
r[W] = 1.0f + ((float)( rand_current = ( ( rand_current & 1 ) ? ( rand_current >> 1 ) ^ 0x3500 : ( rand_current >> 1 ) ) ) / 16384.0f );
|
|
|
|
float color_interpolator;
|
|
Image::RGBA col0, col1;
|
|
|
|
if( m_params.m_UseMidcolor )
|
|
{
|
|
if( t > midpoint_time )
|
|
{
|
|
color_interpolator = ( t - midpoint_time ) * ReciprocalEstimate_ASM( m_params.m_Lifetime - midpoint_time );
|
|
col0 = m_params.m_Color[1];
|
|
col1 = m_params.m_Color[2];
|
|
}
|
|
else
|
|
{
|
|
color_interpolator = t * ReciprocalEstimate_ASM( midpoint_time );
|
|
col0 = m_params.m_Color[0];
|
|
col1 = m_params.m_Color[1];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
color_interpolator = t * ReciprocalEstimate_ASM( m_params.m_Lifetime );
|
|
col0 = m_params.m_Color[0];
|
|
col1 = m_params.m_Color[2];
|
|
}
|
|
|
|
|
|
//; Calculate the position of the particle, from:
|
|
// pos = ( m_p0 + ( t * m_p1 ) + (( t * t ) * m_p2 )) + ( m_s0 + ( t * m_s1 ) + (( t * t ) * m_s2 )).Scale( r );
|
|
Mth::Vector pos = ( m_p0 + ( t * m_p1 ) + (( t * t ) * m_p2 )) + ( m_s0 + ( t * m_s1 ) + (( t * t ) * m_s2 )).Scale( r );
|
|
|
|
GXColor matcol;
|
|
matcol.r = col0.r + (uint8)( ( (float)col1.r - (float)col0.r ) * color_interpolator );
|
|
matcol.g = col0.g + (uint8)( ( (float)col1.g - (float)col0.g ) * color_interpolator );
|
|
matcol.b = col0.b + (uint8)( ( (float)col1.b - (float)col0.b ) * color_interpolator );
|
|
matcol.a = col0.a + (uint8)( ( (float)col1.a - (float)col0.a ) * color_interpolator );
|
|
|
|
GX::SetChanMatColor( GX_COLOR0A0, matcol );
|
|
GX::SetChanAmbColor( GX_COLOR0A0, matcol );
|
|
|
|
// NsVector sr;
|
|
// sr.x = screen_right.x * pos[W];
|
|
// sr.y = screen_right.y * pos[W];
|
|
// sr.z = screen_right.z * pos[W];
|
|
//
|
|
// float sx, sy, sz;
|
|
// float tx, ty, tz;
|
|
// float sc;
|
|
// GX::Project( pos[X], pos[Y], pos[Z], (Mtx)p_mtx, pm, vp, &sx, &sy, &sz );
|
|
// GX::Project( pos[X]+sr.x, pos[Y]+sr.y, pos[Z]+sr.z, (Mtx)p_mtx, pm, vp, &tx, &ty, &tz );
|
|
// sc = tx - sx; //sqrtf( ( ( tx - sx ) * ( tx - sx ) ) + ( ( ty - sy ) * ( ty - sy ) ) + ( ( tz - sz ) * ( tz - sz ) ) );
|
|
|
|
// Calculate size.
|
|
// float x = p_mtx->getRightX()*pos[W];
|
|
float z = p_mtx->getAtX()*pos[X] + p_mtx->getAtY()*pos[Y] + p_mtx->getAtZ()*pos[Z] + p_mtx->getPosZ();
|
|
float xc = pos[W] * pm[1]; // + z * pm[2];
|
|
float wc = ( 1.0f / z );
|
|
float sc = xc * vp[2] * wc; // + vp[0] + vp[2]/2;
|
|
|
|
sc = fabsf( sc );
|
|
|
|
int size = (int)(sc * 6.0f);
|
|
if ( size <= 255 )
|
|
{
|
|
GX::SetPointSize( size, GX_TO_ONE );
|
|
GX::Begin( GX_POINTS, GX_VTXFMT0, 1 );
|
|
GXWGFifo.f32 = pos[X];
|
|
GXWGFifo.f32 = pos[Y];
|
|
GXWGFifo.f32 = pos[Z];
|
|
GXWGFifo.f32 = 0.0f;
|
|
GXWGFifo.f32 = 0.0f;
|
|
GX::End();
|
|
}
|
|
else
|
|
{
|
|
if ( sc > 256.0f )
|
|
{
|
|
pos[W] = ( pos[W] * 256.0f ) / sc;
|
|
}
|
|
|
|
NsVector sr;
|
|
sr.x = screen_right.x * pos[W];
|
|
sr.y = screen_right.y * pos[W];
|
|
sr.z = screen_right.z * pos[W];
|
|
NsVector su;
|
|
su.x = screen_up.x * pos[W];
|
|
su.y = screen_up.y * pos[W];
|
|
su.z = screen_up.z * pos[W];
|
|
|
|
float v0x = pos[X] - su.x;
|
|
float v0y = pos[Y] - su.y;
|
|
float v0z = pos[Z] - su.z;
|
|
|
|
float v1x = pos[X] + su.x;
|
|
float v1y = pos[Y] + su.y;
|
|
float v1z = pos[Z] + su.z;
|
|
|
|
// Send coordinates.
|
|
GX::Begin( GX_QUADS, GX_VTXFMT0, 4 );
|
|
GXWGFifo.f32 = v1x - sr.x;
|
|
GXWGFifo.f32 = v1y - sr.y;
|
|
GXWGFifo.f32 = v1z - sr.z;
|
|
GXWGFifo.f32 = 0.0f;
|
|
GXWGFifo.f32 = 0.0f;
|
|
|
|
GXWGFifo.f32 = v1x + sr.x;
|
|
GXWGFifo.f32 = v1y + sr.y;
|
|
GXWGFifo.f32 = v1z + sr.z;
|
|
GXWGFifo.f32 = 1.0f;
|
|
GXWGFifo.f32 = 0.0f;
|
|
|
|
GXWGFifo.f32 = v0x + sr.x;
|
|
GXWGFifo.f32 = v0y + sr.y;
|
|
GXWGFifo.f32 = v0z + sr.z;
|
|
GXWGFifo.f32 = 1.0f;
|
|
GXWGFifo.f32 = 1.0f;
|
|
|
|
GXWGFifo.f32 = v0x - sr.x;
|
|
GXWGFifo.f32 = v0y - sr.y;
|
|
GXWGFifo.f32 = v0z - sr.z;
|
|
GXWGFifo.f32 = 0.0f;
|
|
GXWGFifo.f32 = 1.0f;
|
|
GX::End();
|
|
}
|
|
|
|
|
|
|
|
// Reduce t by particle interval.
|
|
t -= p_stream->m_interval;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
void CNgcNewParticle::update_position( void )
|
|
{
|
|
// Convert 3-point -> PVA format
|
|
float t1 = m_params.m_Lifetime * m_params.m_MidpointPct * 0.01f;
|
|
float t2 = m_params.m_Lifetime;
|
|
Mth::Vector u, a_;
|
|
|
|
Mth::Vector x0 = m_params.m_BoxPos[0];
|
|
x0[3] = m_params.m_Radius[0];
|
|
Mth::Vector x1 = m_params.m_BoxPos[1];
|
|
x1[3] = m_params.m_Radius[1];
|
|
Mth::Vector x2 = m_params.m_BoxPos[2];
|
|
x2[3] = m_params.m_Radius[2];
|
|
|
|
if( m_params.m_UseMidpoint )
|
|
{
|
|
u = ( t2 * t2 * ( x1 - x0 ) - t1 * t1 * ( x2 - x0 )) / ( t1 * t2 * ( t2 - t1 ));
|
|
a_ = ( t1 * ( x2 - x0 ) - t2 * ( x1 - x0 )) / ( t1 * t2 * ( t2 - t1 ));
|
|
}
|
|
else
|
|
{
|
|
u = ( x2 - x0 ) / t2;
|
|
a_.Set( 0, 0, 0, 0 );
|
|
}
|
|
|
|
m_p0 = x0 - 1.5f * m_s0;
|
|
m_p1 = u - 1.5f * m_s1;
|
|
m_p2 = a_ - 1.5f * m_s2;
|
|
m_p0[3] = x0[3] - 1.5f * m_s0[3];
|
|
m_p1[3] = u[3] - 1.5f * m_s1[3];
|
|
m_p2[3] = a_[3] - 1.5f * m_s2[3];
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
void CNgcNewParticle::plat_update( void )
|
|
{
|
|
|
|
if (m_params.m_LocalCoord)
|
|
{
|
|
update_position();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
void CNgcNewParticle::plat_build( void )
|
|
{
|
|
// Adjust some of the stream params to improve performance.
|
|
m_params.m_EmitRate = m_params.m_EmitRate * 0.25f;
|
|
|
|
// Initialise streams.
|
|
m_max_streams = 5;
|
|
m_num_streams = 0;
|
|
|
|
mp_stream = new CParticleStream[m_max_streams];
|
|
mp_newest_stream = mp_stream + m_max_streams - 1;
|
|
mp_oldest_stream = mp_stream;
|
|
m_emitting = false;
|
|
|
|
// Create a (semi-transparent) material used to render the mesh.
|
|
// mp_material = new NxNgc::sMaterial;
|
|
// memset( mp_material, 0, sizeof( NxNgc::sMaterial ));
|
|
|
|
// mp_material->m_flags[0] = MATFLAG_TRANSPARENT | MATFLAG_TEXTURED;
|
|
// mp_material->m_passes = 1;
|
|
// mp_material->m_alpha_cutoff = 1;
|
|
// mp_material->m_no_bfc = true;
|
|
// mp_material->m_color[0][0] = 0.5f;
|
|
// mp_material->m_color[0][1] = 0.5f;
|
|
// mp_material->m_color[0][2] = 0.5f;
|
|
// mp_material->m_color[0][3] = m_params.m_FixedAlpha * ( 1.0f / 128.0f );
|
|
// mp_material->m_reg_alpha[0] = NxNgc::GetBlendMode( m_params.m_BlendMode );
|
|
//
|
|
// // Get texture.
|
|
// Nx::CTexture* p_texture;
|
|
// Nx::CNgcTexture* p_Ngc_texture;
|
|
// mp_material->mp_tex[0] = NULL;
|
|
// p_texture = Nx::CTexDictManager::sp_particle_tex_dict->GetTexture( m_params.m_Texture );
|
|
// p_Ngc_texture = static_cast<Nx::CNgcTexture*>( p_texture );
|
|
// if( p_Ngc_texture )
|
|
// {
|
|
// mp_material->mp_tex[0] = p_Ngc_texture->GetEngineTexture();
|
|
// }
|
|
|
|
// Have already set m_Lifetime, which is called m_life in newflat.
|
|
|
|
// x-component will be overwritten by vu1 code, so can store midtime there
|
|
// *(float *)&m_systemDmaData.m_tagx = m_params.m_UseMidcolor ?
|
|
// m_params.m_Lifetime * m_params.m_ColorMidpointPct * 0.01f :
|
|
// 0.0f;
|
|
|
|
|
|
// Set Texture & blend mode.
|
|
Nx::CTexture *p_texture;
|
|
Nx::CNgcTexture *p_Ngc_texture;
|
|
|
|
p_texture = Nx::CTexDictManager::sp_particle_tex_dict->GetTexture( m_params.m_Texture );
|
|
p_Ngc_texture = static_cast<Nx::CNgcTexture*>( p_texture );
|
|
if ( p_Ngc_texture )
|
|
{
|
|
mp_texture = p_Ngc_texture->GetEngineTexture();
|
|
}
|
|
m_blend = get_texture_blend( m_params.m_BlendMode );
|
|
m_fix = m_params.m_FixedAlpha;
|
|
|
|
|
|
// and now a load of redundant duplication of data, which should later be removed...
|
|
|
|
// Convert 3-point -> PVA format.
|
|
float t1 = m_params.m_Lifetime * m_params.m_MidpointPct * 0.01f;
|
|
float t2 = m_params.m_Lifetime;
|
|
Mth::Vector x0,x1,x2,u,a_;
|
|
|
|
x0 = m_params.m_BoxDims[0];
|
|
x0[3] = m_params.m_RadiusSpread[0];
|
|
x1 = m_params.m_BoxDims[1];
|
|
x1[3] = m_params.m_RadiusSpread[1];
|
|
x2 = m_params.m_BoxDims[2];
|
|
x2[3] = m_params.m_RadiusSpread[2];
|
|
|
|
if( m_params.m_UseMidpoint )
|
|
{
|
|
u = ( t2 * t2 * ( x1 - x0 ) - t1 * t1 * ( x2 - x0 )) / ( t1 * t2 * ( t2 - t1 ));
|
|
a_ = ( t1 * ( x2 - x0 ) - t2 * ( x1 - x0 )) / ( t1 * t2 * ( t2 - t1 ));
|
|
}
|
|
else
|
|
{
|
|
u = ( x2 - x0 ) / t2;
|
|
a_.Set(0,0,0,0);
|
|
}
|
|
|
|
m_s0 = x0;
|
|
m_s1 = u;
|
|
m_s2 = a_;
|
|
|
|
x0 = m_params.m_BoxPos[0];
|
|
x0[3] = m_params.m_Radius[0];
|
|
x1 = m_params.m_BoxPos[1];
|
|
x1[3] = m_params.m_Radius[1];
|
|
x2 = m_params.m_BoxPos[2];
|
|
x2[3] = m_params.m_Radius[2];
|
|
|
|
if( m_params.m_UseMidpoint )
|
|
{
|
|
u = ( t2 * t2 * ( x1 - x0 ) - t1 * t1 * ( x2 - x0 )) / ( t1 * t2 * ( t2 - t1 ));
|
|
a_ = ( t1 * ( x2 - x0 ) - t2 * ( x1 - x0 )) / ( t1 * t2 * ( t2 - t1 ));
|
|
}
|
|
else
|
|
{
|
|
u = ( x2 - x0 ) / t2;
|
|
a_.Set(0,0,0,0);
|
|
}
|
|
|
|
m_p0 = x0 - 1.5f * m_s0;
|
|
m_p1 = u - 1.5f * m_s1;
|
|
m_p2 = a_ - 1.5f * m_s2;
|
|
m_p0[3] = x0[3] - 1.5f * m_s0[3];
|
|
m_p1[3] = u[3] - 1.5f * m_s1[3];
|
|
m_p2[3] = a_[3] - 1.5f * m_s2[3];
|
|
|
|
update_position();
|
|
|
|
// Color.
|
|
if( m_params.m_UseMidcolor )
|
|
{
|
|
// float q0 = 100.0f / ( m_params.m_Lifetime * m_params.m_ColorMidpointPct );
|
|
// float q1 = 100.0f / ( m_params.m_Lifetime * ( 100.0f - m_params.m_ColorMidpointPct ));
|
|
|
|
// m_systemDmaData.m_c0[0] = ((float)m_params.m_Color[1].r - (float)m_params.m_Color[0].r) * q0;
|
|
// m_systemDmaData.m_c0[1] = ((float)m_params.m_Color[1].g - (float)m_params.m_Color[0].g) * q0;
|
|
// m_systemDmaData.m_c0[2] = ((float)m_params.m_Color[1].b - (float)m_params.m_Color[0].b) * q0;
|
|
// m_systemDmaData.m_c0[3] = ((float)m_params.m_Color[1].a - (float)m_params.m_Color[0].a) * q0;
|
|
|
|
// m_systemDmaData.m_c1[0] = (float)m_params.m_Color[1].r;
|
|
// m_systemDmaData.m_c1[1] = (float)m_params.m_Color[1].g;
|
|
// m_systemDmaData.m_c1[2] = (float)m_params.m_Color[1].b;
|
|
// m_systemDmaData.m_c1[3] = (float)m_params.m_Color[1].a;
|
|
|
|
// m_systemDmaData.m_c2[0] = ((float)m_params.m_Color[2].r - (float)m_params.m_Color[1].r) * q1;
|
|
// m_systemDmaData.m_c2[1] = ((float)m_params.m_Color[2].g - (float)m_params.m_Color[1].g) * q1;
|
|
// m_systemDmaData.m_c2[2] = ((float)m_params.m_Color[2].b - (float)m_params.m_Color[1].b) * q1;
|
|
// m_systemDmaData.m_c2[3] = ((float)m_params.m_Color[2].a - (float)m_params.m_Color[1].a) * q1;
|
|
}
|
|
else // else suppress mid-colour
|
|
{
|
|
// float q = 1.0f / m_params.m_Lifetime;
|
|
|
|
// m_systemDmaData.m_c1[0] = (float)m_params.m_Color[0].r;
|
|
// m_systemDmaData.m_c1[1] = (float)m_params.m_Color[0].g;
|
|
// m_systemDmaData.m_c1[2] = (float)m_params.m_Color[0].b;
|
|
// m_systemDmaData.m_c1[3] = (float)m_params.m_Color[0].a;
|
|
|
|
// m_systemDmaData.m_c2[0] = ((float)m_params.m_Color[2].r - (float)m_params.m_Color[0].r) * q;
|
|
// m_systemDmaData.m_c2[1] = ((float)m_params.m_Color[2].g - (float)m_params.m_Color[0].g) * q;
|
|
// m_systemDmaData.m_c2[2] = ((float)m_params.m_Color[2].b - (float)m_params.m_Color[0].b) * q;
|
|
// m_systemDmaData.m_c2[3] = ((float)m_params.m_Color[2].a - (float)m_params.m_Color[0].a) * q;
|
|
}
|
|
|
|
// Rotation matrix.
|
|
// m_rotation = m_params.m_RotMatrix;
|
|
m_rotation.Identity();
|
|
|
|
#if 0
|
|
// invert rotation and apply to spatial params
|
|
// leaving this code a bit shoddy and slow until full transition to new-style params
|
|
Mth::Matrix mat;
|
|
mat=m_rotation;
|
|
mat.Transpose();
|
|
Mth::Vector vec;
|
|
|
|
vec = m_systemDmaData.m_p0 + 1.5f * m_systemDmaData.m_s0;
|
|
vec *= mat;
|
|
m_systemDmaData.m_p0 = vec - 1.5f * m_systemDmaData.m_s0;
|
|
|
|
vec = m_systemDmaData.m_p1 + 1.5f * m_systemDmaData.m_s1;
|
|
vec *= mat;
|
|
m_systemDmaData.m_p1 = vec - 1.5f * m_systemDmaData.m_s1;
|
|
|
|
vec = m_systemDmaData.m_p2 + 1.5f * m_systemDmaData.m_s2;
|
|
vec *= mat;
|
|
m_systemDmaData.m_p2 = vec - 1.5f * m_systemDmaData.m_s2;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
void CNgcNewParticle::plat_destroy( void )
|
|
{
|
|
if( mp_stream )
|
|
{
|
|
delete [] mp_stream;
|
|
}
|
|
|
|
// if( mp_material )
|
|
// {
|
|
// delete mp_material;
|
|
// }
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
** Public Functions **
|
|
*****************************************************************************/
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
} // namespace Nx
|
|
|
|
|
|
|
|
|
|
|