thug/Code/Gfx/NGPS/p_nxparticlenewflat.cpp
2016-02-14 08:39:12 +11:00

548 lines
19 KiB
C++

//****************************************************************************
//* MODULE: Gfx
//* FILENAME: p_nxParticle.cpp
//* OWNER: Paul Robinson
//* CREATION DATE: 3/27/2002
//****************************************************************************
#include <core/defines.h>
#include "gfx/ngps/nx/render.h"
#include "gfx/ngps/nx/dma.h"
#include "gfx/ngps/nx/vif.h"
#include "gfx/ngps/nx/vu1.h"
#include "gfx/ngps/nx/gif.h"
#include "gfx/ngps/nx/gs.h"
#include "gfx/ngps/nx/line.h"
#include <gfx/NxTexMan.h>
#include <gfx/ngps/p_nxtexture.h>
#include "gfx/ngps/nx/immediate.h"
#include "gfx/ngps/nx/vu1code.h"
#include "gfx/ngps/nx/mesh.h"
#include "gfx/ngps/nx/group.h"
#include "gfx/ngps/p_nxparticlenewflat.h"
namespace Nx
{
/******************************************************************/
/* */
/* */
/******************************************************************/
CPs2ParticleNewFlat::CPs2ParticleNewFlat()
{
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CPs2ParticleNewFlat::CPs2ParticleNewFlat( uint32 checksum, int max_streams, uint32 texture_checksum, uint32 blendmode_checksum, int fix )
{
m_checksum = checksum;
m_max_streams = max_streams;
m_num_streams = 0;
// Get the texture.
Nx::CTexture *p_texture;
Nx::CPs2Texture *p_ps2_texture;
mp_engine_texture = NULL;
p_texture = Nx::CTexDictManager::sp_particle_tex_dict->GetTexture( texture_checksum );
p_ps2_texture = static_cast<Nx::CPs2Texture*>( p_texture );
if ( p_ps2_texture )
{
mp_engine_texture = p_ps2_texture->GetSingleTexture();
}
// Set blendmode.
m_blend = NxPs2::CImmediateMode::sGetTextureBlend( blendmode_checksum, fix );
// Allocate space for span information & streams.
m_num_spans = 1; // Currently defaulting to 1 span.
mp_span = new CParticleSpan[m_num_spans];
mp_stream = new CParticleStream[m_max_streams];
mp_newest_stream = mp_stream + m_max_streams - 1;
mp_oldest_stream = mp_stream;
m_life = 0.5f * (m_life_min + m_life_max);
m_emitting = false;
// set up system dma data, apart from new coefficients, which are calculated in plat_build_path()
m_systemDmaData.m_GScontext[0] = 0x00008004;
m_systemDmaData.m_GScontext[1] = 0x10000000;
m_systemDmaData.m_GScontext[2] = 0x0000000E;
m_systemDmaData.m_GScontext[3] = 0x00000000;
*(uint64 *)&m_systemDmaData.m_GScontext[4] = m_blend;
m_systemDmaData.m_GScontext[6] = 0x00000042;
if (mp_engine_texture)
{
m_systemDmaData.m_u0 = 8;
m_systemDmaData.m_v0 = (mp_engine_texture->GetHeight()<<4) - 8;
m_systemDmaData.m_u1 = (mp_engine_texture->GetWidth() <<4) - 8;
m_systemDmaData.m_v1 = 8;
//m_systemDmaData.m_GScontext[16] = ((mp_engine_texture->GetHeight()<<4) - 8) << 16 | 8;
*(uint64 *)&m_systemDmaData.m_GScontext[8] = mp_engine_texture->m_RegTEX0;
*(uint64 *)&m_systemDmaData.m_GScontext[12] = mp_engine_texture->m_RegTEX1;
}
m_systemDmaData.m_GScontext[10] = 0x00000006;
m_systemDmaData.m_GScontext[14] = 0x00000014;
m_systemDmaData.m_GScontext[16] = 0x0005000B /* | m_alphaCutoff<<4 */; //101 0000 xxxx xxxx 1011
m_systemDmaData.m_GScontext[18] = 0x00000047;
m_systemDmaData.m_tagy = 0x60AB4000;
m_systemDmaData.m_tagz = 0x00434312;
m_mid_time = -1.0f;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CPs2ParticleNewFlat::~CPs2ParticleNewFlat()
{
delete [] mp_span;
delete [] mp_stream;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2ParticleNewFlat::plat_get_position( int entry, int list, float * x, float * y, float * z )
{
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2ParticleNewFlat::plat_set_position( int entry, int list, float x, float y, float z )
{
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2ParticleNewFlat::plat_add_position( int entry, int list, float x, float y, float z )
{
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int CPs2ParticleNewFlat::plat_get_num_particle_colors( void ) { return 1; };
int CPs2ParticleNewFlat::plat_get_num_vertex_lists( void ) { return 0; };
void CPs2ParticleNewFlat::plat_set_sr( int entry, uint8 value ) { m_start_color.r = value; }
void CPs2ParticleNewFlat::plat_set_sg( int entry, uint8 value ) { m_start_color.g = value; }
void CPs2ParticleNewFlat::plat_set_sb( int entry, uint8 value ) { m_start_color.b = value; }
void CPs2ParticleNewFlat::plat_set_sa( int entry, uint8 value ) { m_start_color.a = value >> 1; }
void CPs2ParticleNewFlat::plat_set_mr( int entry, uint8 value ) { m_mid_color.r = value; }
void CPs2ParticleNewFlat::plat_set_mg( int entry, uint8 value ) { m_mid_color.g = value; }
void CPs2ParticleNewFlat::plat_set_mb( int entry, uint8 value ) { m_mid_color.b = value; }
void CPs2ParticleNewFlat::plat_set_ma( int entry, uint8 value ) { m_mid_color.a = value >> 1; }
void CPs2ParticleNewFlat::plat_set_er( int entry, uint8 value ) { m_end_color.r = value; }
void CPs2ParticleNewFlat::plat_set_eg( int entry, uint8 value ) { m_end_color.g = value; }
void CPs2ParticleNewFlat::plat_set_eb( int entry, uint8 value ) { m_end_color.b = value; }
void CPs2ParticleNewFlat::plat_set_ea( int entry, uint8 value ) { m_end_color.a = value >> 1; }
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2ParticleNewFlat::plat_render( void )
{
CParticleStream *p_stream;
int i;
//--------------------------------------------------------------------------------------------------------------------
// process the streams
if (m_emit_rate && (!m_emitting || (m_emit_rate != 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_emit_rate;
mp_newest_stream->m_interval = 1.0f/m_emit_rate;
mp_newest_stream->m_oldest_age = 0.0f;
mp_newest_stream->m_num_particles = 0;
mp_newest_stream->m_seed[0] = rand();
mp_newest_stream->m_seed[1] = rand();
mp_newest_stream->m_seed[2] = rand();
mp_newest_stream->m_seed[3] = rand();
m_emitting = true;
}
else
{
m_emitting = false;
}
}
else
{
m_emitting = m_emit_rate;
}
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_life)
{
// work out number dead
int particles_dead = (int)((mp_oldest_stream->m_oldest_age - m_life) * 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
if (mp_engine_texture)
{
// Mick: If this is textured, we reset the TEX0, TEX1 regs as the texture might move
// Since 2D textures are dynamically packed every frame
*(uint64 *)&m_systemDmaData.m_GScontext[8] = mp_engine_texture->m_RegTEX0;
*(uint64 *)&m_systemDmaData.m_GScontext[12] = mp_engine_texture->m_RegTEX1;
}
// matrix is system rotation times view transform
m_systemDmaData.m_matrix = m_rotation * NxPs2::render::WorldToIntViewport;
// in the per-frame setup dma we must have:
// dma tag
// base
// offset
// set the group
NxPs2::dma::SetList(NxPs2::sGroup::pParticles);
// the system and streams will be loaded to a double-buffered input area of VUMem1
// ref the system data, and include an unpack for the system and streams:
NxPs2::dma::Tag(NxPs2::dma::ref, (sizeof(CSystemDmaDataFlat)>>4), (uint)&m_systemDmaData);
NxPs2::vif::STCYCL(1,1);
NxPs2::vif::UNPACK(0, V4_32, (sizeof(CSystemDmaDataFlat)>>4)+m_num_streams*2, REL, SIGNED, 0);
// construct a packet with data for each stream
NxPs2::dma::BeginTag(NxPs2::dma::cnt, 0);
for (i=0,p_stream=mp_oldest_stream; i<m_num_streams; i++,p_stream++)
{
Dbg_MsgAssert(m_num_particles<65536, ("particle limit reached (65536)"));
// wrap at end of cyclic buffer
if (p_stream == mp_stream + m_max_streams)
{
p_stream = mp_stream;
}
((float *)NxPs2::dma::pLoc)[0] = p_stream->m_oldest_age;
((float *)NxPs2::dma::pLoc)[1] = p_stream->m_interval;
((uint32 *)NxPs2::dma::pLoc)[2] = p_stream->m_num_particles;
((uint32 *)NxPs2::dma::pLoc)[3] = (p_stream==mp_newest_stream) ? 0x8000 : 0;
((uint32 *)NxPs2::dma::pLoc)[4] = p_stream->m_seed[0];
((uint32 *)NxPs2::dma::pLoc)[5] = p_stream->m_seed[1];
((uint32 *)NxPs2::dma::pLoc)[6] = p_stream->m_seed[2];
((uint32 *)NxPs2::dma::pLoc)[7] = p_stream->m_seed[3];
//printf("stream %d, num particles=%d, oldest age=%f\n", s, p_stream->m_num_particles, p_stream->m_oldest_age);
// step dma pointer
NxPs2::dma::pLoc += 8*4;
// count particles
NxPs2::render::sTotalNewParticles += p_stream->m_num_particles;
}
NxPs2::vif::MSCAL(10); // sprites
NxPs2::dma::EndTag();
NxPs2::dma::SetList(NxPs2::sGroup::pEpilogue);
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2ParticleNewFlat::plat_build_path( void )
{
float midTime;
// set m_life
m_life = 0.5f * (m_life_min + m_life_max);
// set clamped local midtime variable
if (m_mid_time <= 0.0f)
{
midTime = 0.0f;
}
else if (m_mid_time >= 100.0f)
{
midTime = m_life;
}
else
{
midTime = m_mid_time * 0.01f * m_life;
}
// x-component will be overwritten by vu1 code, so can store midtime there
*(float *)&m_systemDmaData.m_tagx = midTime;
// constant part
m_systemDmaData.m_s0x = m_emit_w;
m_systemDmaData.m_s0y = 0.0f;
m_systemDmaData.m_s0z = m_emit_h;
m_systemDmaData.m_s0w = 0.0f;
m_systemDmaData.m_c0x = m_pos[0] - 1.5f * m_systemDmaData.m_s0x;
m_systemDmaData.m_c0y = m_pos[1] - 1.5f * m_systemDmaData.m_s0y;
m_systemDmaData.m_c0z = m_pos[2] - 1.5f * m_systemDmaData.m_s0z;
m_systemDmaData.m_c0w = m_sw - 1.5f * m_systemDmaData.m_s0w;
// linear part
Mth::Vector vel(m_tx,m_ty,m_tz,0.0f);
float speed = 60.0f * 0.5 * (m_speed_min + m_speed_max);
vel.Normalize();
vel *= speed;
m_systemDmaData.m_s1x = speed * Mth::PI/2.0f * m_emit_angle_spread;
m_systemDmaData.m_s1y = 60.0f * (m_speed_max - m_speed_min);
m_systemDmaData.m_s1z = speed * Mth::PI/2.0f * m_emit_angle_spread;
m_systemDmaData.m_s1w = 0.0f;
m_systemDmaData.m_c1x = vel[0] - 1.5f * m_systemDmaData.m_s1x;
m_systemDmaData.m_c1y = vel[1] - 1.5f * m_systemDmaData.m_s1y;
m_systemDmaData.m_c1z = vel[2] - 1.5f * m_systemDmaData.m_s1z;
m_systemDmaData.m_c1w = (m_ew-m_sw) / m_life - 1.5f * m_systemDmaData.m_s1w;
// quadratic part
m_systemDmaData.m_s2x = 0.0f;
m_systemDmaData.m_s2y = 0.0f;
m_systemDmaData.m_s2z = 0.0f;
m_systemDmaData.m_s2w = 0.0f;
m_systemDmaData.m_c2x = m_fx*0.5f*(60.0f*60.0f) - 1.5f * m_systemDmaData.m_s2x;
m_systemDmaData.m_c2y = m_fy*0.5f*(60.0f*60.0f) - 1.5f * m_systemDmaData.m_s2y;
m_systemDmaData.m_c2z = m_fz*0.5f*(60.0f*60.0f) - 1.5f * m_systemDmaData.m_s2z;
m_systemDmaData.m_c2w = 0.0f - 1.5f * m_systemDmaData.m_s2w;
// cubic part
//m_systemDmaData.m_s3x = 0.0f;
//m_systemDmaData.m_s3y = 0.0f;
//m_systemDmaData.m_s3z = 0.0f;
//m_systemDmaData.m_s3w = 0.0f;
//m_systemDmaData.m_c3x = 0.0f - 1.5f * m_systemDmaData.m_s3x;
//m_systemDmaData.m_c3y = 0.0f - 1.5f * m_systemDmaData.m_s3y;
//m_systemDmaData.m_c3z = 0.0f - 1.5f * m_systemDmaData.m_s3z;
//m_systemDmaData.m_c3w = 0.0f - 1.5f * m_systemDmaData.m_s3w;
// colour
if (m_mid_time >= 0.0f) // if using mid-colour
{
float q0 = 1.0f / midTime;
float q1 = 1.0f / (m_life - midTime);
m_systemDmaData.m_c0r = ((float)m_mid_color.r - (float)m_start_color.r) * q0;
m_systemDmaData.m_c0g = ((float)m_mid_color.g - (float)m_start_color.g) * q0;
m_systemDmaData.m_c0b = ((float)m_mid_color.b - (float)m_start_color.b) * q0;
m_systemDmaData.m_c0a = ((float)m_mid_color.a - (float)m_start_color.a) * q0;
m_systemDmaData.m_c1r = (float)m_mid_color.r;
m_systemDmaData.m_c1g = (float)m_mid_color.g;
m_systemDmaData.m_c1b = (float)m_mid_color.b;
m_systemDmaData.m_c1a = (float)m_mid_color.a;
m_systemDmaData.m_c2r = ((float)m_end_color.r - (float)m_mid_color.r) * q1;
m_systemDmaData.m_c2g = ((float)m_end_color.g - (float)m_mid_color.g) * q1;
m_systemDmaData.m_c2b = ((float)m_end_color.b - (float)m_mid_color.b) * q1;
m_systemDmaData.m_c2a = ((float)m_end_color.a - (float)m_mid_color.a) * q1;
}
else // else suppress mid-colour
{
float q = 1.0f / m_life;
m_systemDmaData.m_c1r = (float)m_start_color.r;
m_systemDmaData.m_c1g = (float)m_start_color.g;
m_systemDmaData.m_c1b = (float)m_start_color.b;
m_systemDmaData.m_c1a = (float)m_start_color.a;
m_systemDmaData.m_c2r = ((float)m_end_color.r - (float)m_start_color.r) * q;
m_systemDmaData.m_c2g = ((float)m_end_color.g - (float)m_start_color.g) * q;
m_systemDmaData.m_c2b = ((float)m_end_color.b - (float)m_start_color.b) * q;
m_systemDmaData.m_c2a = ((float)m_end_color.a - (float)m_start_color.a) * q;
}
// rotation matrix, hardwired to the identity for now
m_rotation.Identity();
// temp test
//m_rotation[0][0] = 0.8;
//m_rotation[0][1] = 0.6;
//m_rotation[1][0] = -0.6;
//m_rotation[1][1] = 0.8;
// 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[0] = m_systemDmaData.m_c0x + 1.5f * m_systemDmaData.m_s0x;
vec[1] = m_systemDmaData.m_c0y + 1.5f * m_systemDmaData.m_s0y;
vec[2] = m_systemDmaData.m_c0z + 1.5f * m_systemDmaData.m_s0z;
vec[3] = 0;
vec *= mat;
m_systemDmaData.m_c0x = vec[0] - 1.5f * m_systemDmaData.m_s0x;
m_systemDmaData.m_c0y = vec[1] - 1.5f * m_systemDmaData.m_s0y;
m_systemDmaData.m_c0z = vec[2] - 1.5f * m_systemDmaData.m_s0z;
vec[0] = m_systemDmaData.m_c1x + 1.5f * m_systemDmaData.m_s1x;
vec[1] = m_systemDmaData.m_c1y + 1.5f * m_systemDmaData.m_s1y;
vec[2] = m_systemDmaData.m_c1z + 1.5f * m_systemDmaData.m_s1z;
vec[3] = 0;
vec *= mat;
m_systemDmaData.m_c1x = vec[0] - 1.5f * m_systemDmaData.m_s1x;
m_systemDmaData.m_c1y = vec[1] - 1.5f * m_systemDmaData.m_s1y;
m_systemDmaData.m_c1z = vec[2] - 1.5f * m_systemDmaData.m_s1z;
vec[0] = m_systemDmaData.m_c2x + 1.5f * m_systemDmaData.m_s2x;
vec[1] = m_systemDmaData.m_c2y + 1.5f * m_systemDmaData.m_s2y;
vec[2] = m_systemDmaData.m_c2z + 1.5f * m_systemDmaData.m_s2z;
vec[3] = 0;
vec *= mat;
m_systemDmaData.m_c2x = vec[0] - 1.5f * m_systemDmaData.m_s2x;
m_systemDmaData.m_c2y = vec[1] - 1.5f * m_systemDmaData.m_s2y;
m_systemDmaData.m_c2z = vec[2] - 1.5f * m_systemDmaData.m_s2z;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CParticleStream::AdvanceSeed(int num_places)
{
for (int i=0; i<num_places; i++)
{
m_seed[0] = m_seed[3]<<1 | ((m_seed[3]>>4 ^ m_seed[3]>>22) & 1);
m_seed[1] ^= m_seed[0];
m_seed[2] ^= m_seed[1];
m_seed[3] ^= m_seed[2];
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int CPs2ParticleNewFlat::GetNumParticles()
{
int i, total=0;
CParticleStream *p_stream;
for (i=0, p_stream=mp_oldest_stream; i<m_num_streams; i++)
{
// add this stream to tally
total += p_stream->m_num_particles;
// step pointer within cyclic buffer
p_stream++;
if (p_stream == mp_stream + m_max_streams)
{
p_stream = mp_stream;
}
}
return total;
}
} // Nx