summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Angus <tim@ngus.net>2005-11-24 19:00:52 +0000
committerTim Angus <tim@ngus.net>2005-11-24 19:00:52 +0000
commit63f0272dd145b10c349163ba465fcbcf5ac48e0d (patch)
tree0c34ea6411a1056213f2b0923d771a2726901313
parente80ad4bf122eb05a5ed0c920e36cf656f98dc6e5 (diff)
* 3D particles
* Brass ejections now done via particle system * static_tranform particle move type * thirdPersonOnly particle and trail system property * Trail jitter now done in two dimensions
-rw-r--r--Makefile1
-rw-r--r--src/cgame/cg_animmapobj.c93
-rw-r--r--src/cgame/cg_attachment.c53
-rw-r--r--src/cgame/cg_ents.c2
-rw-r--r--src/cgame/cg_event.c2
-rw-r--r--src/cgame/cg_local.h110
-rw-r--r--src/cgame/cg_main.c7
-rw-r--r--src/cgame/cg_particles.c351
-rw-r--r--src/cgame/cg_players.c20
-rw-r--r--src/cgame/cg_trails.c102
-rw-r--r--src/cgame/cg_weapons.c171
-rw-r--r--src/game/g_utils.c2
-rw-r--r--src/game/g_weapon.c2
-rw-r--r--src/game/q_math.c11
-rw-r--r--src/game/q_shared.h1
15 files changed, 520 insertions, 408 deletions
diff --git a/Makefile b/Makefile
index 9a74bf50..ed1c6d6d 100644
--- a/Makefile
+++ b/Makefile
@@ -48,6 +48,7 @@ CGOBJ = \
$(GDIRNAME)/q_shared.o \
$(CGDIRNAME)/cg_consolecmds.o \
$(CGDIRNAME)/cg_buildable.o \
+ $(CGDIRNAME)/cg_animation.o \
$(CGDIRNAME)/cg_animmapobj.o \
$(CGDIRNAME)/cg_draw.o \
$(CGDIRNAME)/cg_drawtools.o \
diff --git a/src/cgame/cg_animmapobj.c b/src/cgame/cg_animmapobj.c
index 18f49b53..f0e964bf 100644
--- a/src/cgame/cg_animmapobj.c
+++ b/src/cgame/cg_animmapobj.c
@@ -13,93 +13,6 @@
#include "cg_local.h"
-/*
-===============
-CG_RunAMOLerpFrame
-
-Sets cg.snap, cg.oldFrame, and cg.backlerp
-cg.time should be between oldFrameTime and frameTime after exit
-===============
-*/
-static void CG_RunAMOLerpFrame( lerpFrame_t *lf )
-{
- int f, numFrames;
- animation_t *anim;
-
- // debugging tool to get no animations
- if( cg_animSpeed.integer == 0 )
- {
- lf->oldFrame = lf->frame = lf->backlerp = 0;
- return;
- }
-
- // if we have passed the current frame, move it to
- // oldFrame and calculate a new frame
- if( cg.time >= lf->frameTime )
- {
- lf->oldFrame = lf->frame;
- lf->oldFrameTime = lf->frameTime;
-
- // get the next frame based on the animation
- anim = lf->animation;
- if( !anim->frameLerp )
- return; // shouldn't happen
-
- if( cg.time < lf->animationTime )
- lf->frameTime = lf->animationTime; // initial lerp
- else
- lf->frameTime = lf->oldFrameTime + anim->frameLerp;
-
- f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;
- numFrames = anim->numFrames;
- if( anim->flipflop )
- numFrames *= 2;
-
- if( f >= numFrames )
- {
- f -= numFrames;
- if( anim->loopFrames )
- {
- f %= anim->loopFrames;
- f += anim->numFrames - anim->loopFrames;
- }
- else
- {
- f = numFrames - 1;
- // the animation is stuck at the end, so it
- // can immediately transition to another sequence
- lf->frameTime = cg.time;
- }
- }
-
- if( anim->reversed )
- lf->frame = anim->firstFrame + anim->numFrames - 1 - f;
- else if( anim->flipflop && f >= anim->numFrames )
- lf->frame = anim->firstFrame + anim->numFrames - 1 - ( f % anim->numFrames );
- else
- lf->frame = anim->firstFrame + f;
-
- if( cg.time > lf->frameTime )
- {
- lf->frameTime = cg.time;
- if( cg_debugAnim.integer )
- CG_Printf( "Clamp lf->frameTime\n" );
- }
- }
-
- if( lf->frameTime > cg.time + 200 )
- lf->frameTime = cg.time;
-
- if( lf->oldFrameTime > cg.time )
- lf->oldFrameTime = cg.time;
-
- // calculate current lerp value
- if( lf->frameTime == lf->oldFrameTime )
- lf->backlerp = 0;
- else
- lf->backlerp = 1.0 - (float)( cg.time - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime );
-}
-
/*
===============
@@ -108,7 +21,7 @@ CG_DoorAnimation
*/
static void CG_DoorAnimation( centity_t *cent, int *old, int *now, float *backLerp )
{
- CG_RunAMOLerpFrame( &cent->lerpFrame );
+ CG_RunLerpFrame( &cent->lerpFrame );
*old = cent->lerpFrame.oldFrame;
*now = cent->lerpFrame.frame;
@@ -194,7 +107,7 @@ static void CG_AMOAnimation( centity_t *cent, int *old, int *now, float *backLer
cent->lerpFrame.frameTime += delta;
}
- CG_RunAMOLerpFrame( &cent->lerpFrame );
+ CG_RunLerpFrame( &cent->lerpFrame );
cent->miscTime = cg.time;
}
@@ -209,7 +122,7 @@ static void CG_AMOAnimation( centity_t *cent, int *old, int *now, float *backLer
CG_animMapObj
==================
*/
-void CG_animMapObj( centity_t *cent )
+void CG_AnimMapObj( centity_t *cent )
{
refEntity_t ent;
entityState_t *es;
diff --git a/src/cgame/cg_attachment.c b/src/cgame/cg_attachment.c
index d8f20d90..a256318b 100644
--- a/src/cgame/cg_attachment.c
+++ b/src/cgame/cg_attachment.c
@@ -29,6 +29,9 @@ qboolean CG_AttachmentPoint( attachment_t *a, vec3_t v )
if( !a )
return qfalse;
+ // if it all breaks, then use the last point we know was correct
+ VectorCopy( a->lastValidAttachmentPoint, v );
+
switch( a->type )
{
case AT_STATIC:
@@ -85,6 +88,8 @@ qboolean CG_AttachmentPoint( attachment_t *a, vec3_t v )
if( a->hasOffset )
VectorAdd( v, a->offset, v );
+ VectorCopy( v, a->lastValidAttachmentPoint );
+
return qtrue;
}
@@ -106,7 +111,6 @@ qboolean CG_AttachmentDir( attachment_t *a, vec3_t v )
switch( a->type )
{
case AT_STATIC:
- //FIXME: hmmmmmmm
return qfalse;
break;
@@ -150,6 +154,53 @@ qboolean CG_AttachmentDir( attachment_t *a, vec3_t v )
/*
===============
+CG_AttachmentAxis
+
+Return the attachment axis
+===============
+*/
+qboolean CG_AttachmentAxis( attachment_t *a, vec3_t axis[ 3 ] )
+{
+ centity_t *cent;
+
+ if( !a )
+ return qfalse;
+
+ switch( a->type )
+ {
+ case AT_STATIC:
+ return qfalse;
+ break;
+
+ case AT_TAG:
+ if( !a->tagValid )
+ return qfalse;
+
+ AxisCopy( a->re.axis, axis );
+ break;
+
+ case AT_CENT:
+ if( !a->centValid )
+ return qfalse;
+
+ cent = &cg_entities[ a->centNum ];
+ AnglesToAxis( cent->lerpAngles, axis );
+ break;
+
+ case AT_PARTICLE:
+ return qfalse;
+ break;
+
+ default:
+ CG_Printf( S_COLOR_RED "ERROR: Invalid attachmentType_t in attachment\n" );
+ break;
+ }
+
+ return qtrue;
+}
+
+/*
+===============
CG_AttachmentVelocity
If the attachment can have velocity, return it
diff --git a/src/cgame/cg_ents.c b/src/cgame/cg_ents.c
index 8c047e27..b622d2f3 100644
--- a/src/cgame/cg_ents.c
+++ b/src/cgame/cg_ents.c
@@ -1087,7 +1087,7 @@ static void CG_AddCEntity( centity_t *cent )
break;
case ET_ANIMMAPOBJ:
- CG_animMapObj( cent );
+ CG_AnimMapObj( cent );
break;
case ET_MODELDOOR:
diff --git a/src/cgame/cg_event.c b/src/cgame/cg_event.c
index 9273922f..dfafc18e 100644
--- a/src/cgame/cg_event.c
+++ b/src/cgame/cg_event.c
@@ -744,7 +744,6 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
centity_t *source = &cg_entities[ es->generic1 ];
centity_t *target = &cg_entities[ es->clientNum ];
vec3_t sourceOffset = { 0.0f, 0.0f, 28.0f };
- vec3_t targetOffset = { 0.0f, 0.0f, -2.0f };
if( !CG_IsTrailSystemValid( &source->muzzleTS ) )
{
@@ -757,7 +756,6 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
CG_AttachToCent( &source->muzzleTS->frontAttachment );
CG_AttachToCent( &source->muzzleTS->backAttachment );
CG_SetAttachmentOffset( &source->muzzleTS->frontAttachment, sourceOffset );
- CG_SetAttachmentOffset( &source->muzzleTS->backAttachment, targetOffset );
source->muzzleTSDeathTime = cg.time + cg_teslaTrailTime.integer;
}
diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h
index 069dd604..8b619648 100644
--- a/src/cgame/cg_local.h
+++ b/src/cgame/cg_local.h
@@ -113,6 +113,30 @@ typedef enum
//======================================================================
+// when changing animation, set animationTime to frameTime + lerping time
+// The current lerp will finish out, then it will lerp to the new animation
+typedef struct
+{
+ int oldFrame;
+ int oldFrameTime; // time when ->oldFrame was exactly on
+
+ int frame;
+ int frameTime; // time when ->frame will be exactly on
+
+ float backlerp;
+
+ float yawAngle;
+ qboolean yawing;
+ float pitchAngle;
+ qboolean pitching;
+
+ int animationNumber; // may include ANIM_TOGGLEBIT
+ animation_t *animation;
+ int animationTime; // time when the first frame of the animation will be exact
+} lerpFrame_t;
+
+//======================================================================
+
//attachment system
typedef enum
{
@@ -138,6 +162,8 @@ typedef struct attachment_s
qboolean hasOffset;
vec3_t offset;
+ vec3_t lastValidAttachmentPoint;
+
//AT_STATIC
vec3_t origin;
@@ -157,7 +183,8 @@ typedef struct attachment_s
//======================================================================
//particle system stuff
-#define MAX_SHADER_FRAMES 32
+#define MAX_PS_SHADER_FRAMES 32
+#define MAX_PS_MODELS 8
#define MAX_EJECTORS_PER_SYSTEM 4
#define MAX_PARTICLES_PER_EJECTOR 4
@@ -172,17 +199,11 @@ typedef struct attachment_s
#define PARTICLES_INFINITE -1
#define PARTICLES_SAME_AS_INITIAL -2
-/*
-===============
-
-COMPILE TIME STRUCTURES
-
-===============
-*/
-
+//COMPILE TIME STRUCTURES
typedef enum
{
PMT_STATIC,
+ PMT_STATIC_TRANSFORM,
PMT_TAG,
PMT_CENT_ANGLES,
PMT_NORMAL
@@ -257,12 +278,20 @@ typedef struct baseParticle_s
char onDeathSystemName[ MAX_QPATH ];
qhandle_t onDeathSystemHandle;
+ char childTrailSystemName[ MAX_QPATH ];
+ qhandle_t childTrailSystemHandle;
+
//particle invariant stuff
- char shaderNames[ MAX_QPATH ][ MAX_SHADER_FRAMES ];
- qhandle_t shaders[ MAX_SHADER_FRAMES ];
+ char shaderNames[ MAX_PS_SHADER_FRAMES ][ MAX_QPATH ];
+ qhandle_t shaders[ MAX_PS_SHADER_FRAMES ];
int numFrames;
float framerate;
+ char modelNames[ MAX_PS_MODELS ][ MAX_QPATH ];
+ qhandle_t models[ MAX_PS_MODELS ];
+ int numModels;
+ animation_t modelAnimation;
+
qboolean overdrawProtection;
qboolean realLight;
qboolean cullOnStartSolid;
@@ -289,18 +318,12 @@ typedef struct baseParticleSystem_s
baseParticleEjector_t *ejectors[ MAX_EJECTORS_PER_SYSTEM ];
int numEjectors;
+ qboolean thirdPersonOnly;
qboolean registered; //whether or not the assets for this particle have been loaded
} baseParticleSystem_t;
-/*
-===============
-
-RUN TIME STRUCTURES
-
-===============
-*/
-
+//RUN TIME STRUCTURES
typedef struct particleSystem_s
{
baseParticleSystem_t *class;
@@ -341,6 +364,8 @@ typedef struct particle_s
int birthTime;
int lifeTime;
+ qboolean atRest;
+
vec3_t origin;
vec3_t velocity;
@@ -355,6 +380,10 @@ typedef struct particle_s
pLerpValues_t alpha;
pLerpValues_t rotation;
+ qhandle_t model;
+ lerpFrame_t lf;
+ vec3_t lastAxis[ 3 ];
+
qboolean valid;
int frameWhenInvalidated;
@@ -432,6 +461,7 @@ typedef struct baseTrailSystem_s
baseTrailBeam_t *beams[ MAX_BEAMS_PER_SYSTEM ];
int numBeams;
+ qboolean thirdPersonOnly;
qboolean registered; //whether or not the assets for this trail have been loaded
} baseTrailSystem_t;
@@ -458,9 +488,8 @@ typedef struct trailBeamNode_s
byte alpha;
byte color[ 3 ];
- float jitters[ MAX_TRAIL_BEAM_JITTERS ];
- float jitter;
-
+ vec2_t jitters[ MAX_TRAIL_BEAM_JITTERS ];
+
struct trailBeamNode_s *prev;
struct trailBeamNode_s *next;
@@ -476,7 +505,7 @@ typedef struct trailBeam_s
trailBeamNode_t *nodes;
int lastEvalTime;
-
+
qboolean valid;
int nextJitterTimes[ MAX_TRAIL_BEAM_JITTERS ];
@@ -491,28 +520,6 @@ typedef struct trailBeam_s
// because corpses after respawn are outside the normal
// client numbering range
-// when changing animation, set animationTime to frameTime + lerping time
-// The current lerp will finish out, then it will lerp to the new animation
-typedef struct
-{
- int oldFrame;
- int oldFrameTime; // time when ->oldFrame was exactly on
-
- int frame;
- int frameTime; // time when ->frame will be exactly on
-
- float backlerp;
-
- float yawAngle;
- qboolean yawing;
- float pitchAngle;
- qboolean pitching;
-
- int animationNumber; // may include ANIM_TOGGLEBIT
- animation_t *animation;
- int animationTime; // time when the first frame of the animation will be exact
-} lerpFrame_t;
-
//TA: smoothing of view and model for WW transitions
#define MAXSMOOTHS 32
@@ -866,8 +873,6 @@ typedef struct weaponInfo_s
qhandle_t crossHair;
int crossHairSize;
- void (*ejectBrassFunc)( centity_t * );
-
sfxHandle_t readySound;
qboolean disableIn3rdPerson;
@@ -1207,9 +1212,6 @@ typedef struct
qhandle_t gibSpark1;
qhandle_t gibSpark2;
- qhandle_t machinegunBrassModel;
- qhandle_t shotgunBrassModel;
-
qhandle_t level2ZapTS;
qhandle_t friendShader;
@@ -1712,9 +1714,14 @@ void CG_HumanBuildableExplosion( vec3_t origin, vec3_t dir );
void CG_AlienBuildableExplosion( vec3_t origin, vec3_t dir );
//
+// cg_animation.c
+//
+void CG_RunLerpFrame( lerpFrame_t *lf );
+
+//
// cg_animmapobj.c
//
-void CG_animMapObj( centity_t *cent );
+void CG_AnimMapObj( centity_t *cent );
void CG_ModelDoor( centity_t *cent );
//
@@ -1869,6 +1876,7 @@ void CG_DefragmentMemory( void );
//
qboolean CG_AttachmentPoint( attachment_t *a, vec3_t v );
qboolean CG_AttachmentDir( attachment_t *a, vec3_t v );
+qboolean CG_AttachmentAxis( attachment_t *a, vec3_t axis[ 3 ] );
qboolean CG_AttachmentVelocity( attachment_t *a, vec3_t v );
int CG_AttachmentCentNum( attachment_t *a );
diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c
index 663ace40..dbb2b1ea 100644
--- a/src/cgame/cg_main.c
+++ b/src/cgame/cg_main.c
@@ -796,9 +796,6 @@ static void CG_RegisterGraphics( void )
cgs.media.upgradeClassIconShader = trap_R_RegisterShader( "icons/icona_upgrade.tga" );
- cgs.media.machinegunBrassModel = trap_R_RegisterModel( "models/weapons/shells/rifle_shell.md3" );
- cgs.media.shotgunBrassModel = trap_R_RegisterModel( "models/weapons/shells/shotgun_shell.md3" );
-
cgs.media.gibAbdomen = trap_R_RegisterModel( "models/gibs/abdomen.md3" );
cgs.media.gibArm = trap_R_RegisterModel( "models/gibs/arm.md3" );
cgs.media.gibChest = trap_R_RegisterModel( "models/gibs/chest.md3" );
@@ -1800,10 +1797,10 @@ void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum )
cg.loading = qtrue; // force players to load instead of defer
- CG_LoadParticleSystems( );
+ CG_LoadTrailSystems( );
CG_UpdateMediaFraction( 0.05f );
- CG_LoadTrailSystems( );
+ CG_LoadParticleSystems( );
CG_UpdateMediaFraction( 0.05f );
CG_RegisterSounds( );
diff --git a/src/cgame/cg_particles.c b/src/cgame/cg_particles.c
index a6ef99e5..02d4b5f8 100644
--- a/src/cgame/cg_particles.c
+++ b/src/cgame/cg_particles.c
@@ -93,7 +93,7 @@ static void CG_DestroyParticle( particle_t *p, vec3_t impactNormal )
{
particleSystem_t *ps;
- ps = CG_SpawnNewParticleSystem( p->class->childSystemHandle );
+ ps = CG_SpawnNewParticleSystem( p->class->onDeathSystemHandle );
if( CG_IsParticleSystemValid( &ps ) )
{
@@ -126,6 +126,7 @@ static particle_t *CG_SpawnNewParticle( baseParticle_t *bp, particleEjector_t *p
particleEjector_t *pe = parent;
particleSystem_t *ps = parent->parent;
vec3_t attachmentPoint, attachmentVelocity;
+ vec3_t transform[ 3 ];
for( i = 0; i < MAX_PARTICLES; i++ )
{
@@ -155,11 +156,31 @@ static particle_t *CG_SpawnNewParticle( baseParticle_t *bp, particleEjector_t *p
p->rotation.initial = CG_RandomiseValue( bp->rotation.initial, bp->rotation.initialRandFrac );
p->rotation.final = CG_RandomiseValue( bp->rotation.final, bp->rotation.finalRandFrac );
+ if( bp->numModels )
+ {
+ p->model = bp->models[ rand( ) % bp->numModels ];
+
+ if( bp->modelAnimation.frameLerp < 0 )
+ {
+ bp->modelAnimation.frameLerp = p->lifeTime / bp->modelAnimation.numFrames;
+ bp->modelAnimation.initialLerp = p->lifeTime / bp->modelAnimation.numFrames;
+ }
+ }
+
if( !CG_AttachmentPoint( &ps->attachment, attachmentPoint ) )
return NULL;
VectorCopy( attachmentPoint, p->origin );
- VectorAdd( p->origin, bp->displacement, p->origin );
+
+ if( CG_AttachmentAxis( &ps->attachment, transform ) )
+ {
+ vec3_t transDisplacement;
+
+ VectorMatrixMultiply( bp->displacement, transform, transDisplacement );
+ VectorAdd( p->origin, transDisplacement, p->origin );
+ }
+ else
+ VectorAdd( p->origin, bp->displacement, p->origin );
for( j = 0; j <= 2; j++ )
p->origin[ j ] += ( crandom( ) * bp->randDisplacement );
@@ -173,6 +194,26 @@ static particle_t *CG_SpawnNewParticle( baseParticle_t *bp, particleEjector_t *p
VectorCopy( bp->velMoveValues.dir, p->velocity );
break;
+ case PMT_STATIC_TRANSFORM:
+ if( !CG_AttachmentAxis( &ps->attachment, transform ) )
+ {
+ CG_Printf( S_COLOR_RED "ERROR: a particle with velocityType "
+ "static_transform is not attached to something which can "
+ "provide a transformation\n" );
+ return NULL;
+ }
+
+ if( bp->velMoveValues.dirType == PMD_POINT )
+ {
+ vec3_t transPoint;
+
+ VectorMatrixMultiply( bp->velMoveValues.point, transform, transPoint );
+ VectorSubtract( transPoint, p->origin, p->velocity );
+ }
+ else if( bp->velMoveValues.dirType == PMD_LINEAR )
+ VectorMatrixMultiply( bp->velMoveValues.dir, transform, p->velocity );
+ break;
+
case PMT_TAG:
case PMT_CENT_ANGLES:
if( bp->velMoveValues.dirType == PMD_POINT )
@@ -186,7 +227,11 @@ static particle_t *CG_SpawnNewParticle( baseParticle_t *bp, particleEjector_t *p
case PMT_NORMAL:
if( !ps->normalValid )
+ {
+ CG_Printf( S_COLOR_RED "ERROR: a particle with velocityType "
+ "normal has no normal\n" );
return NULL;
+ }
VectorCopy( ps->normal, p->velocity );
@@ -225,6 +270,18 @@ static particle_t *CG_SpawnNewParticle( baseParticle_t *bp, particleEjector_t *p
}
}
+ //this particle has a child trail system attached
+ if( bp->childTrailSystemName[ 0 ] != '\0' )
+ {
+ trailSystem_t *ts = CG_SpawnNewTrailSystem( bp->childTrailSystemHandle );
+
+ if( CG_IsTrailSystemValid( &ts ) )
+ {
+ CG_SetAttachmentParticle( &ts->frontAttachment, p );
+ CG_AttachToParticle( &ts->frontAttachment );
+ }
+ }
+
break;
}
}
@@ -415,11 +472,11 @@ qhandle_t CG_RegisterParticleSystem( char *name )
baseParticleEjector_t *bpe;
baseParticle_t *bp;
- for( i = 0; i < MAX_PARTICLE_SYSTEMS; i++ )
+ for( i = 0; i < MAX_BASEPARTICLE_SYSTEMS; i++ )
{
bps = &baseParticleSystems[ i ];
- if( !strcmp( bps->name, name ) )
+ if( !Q_stricmpn( bps->name, name, MAX_QPATH ) )
{
//already registered
if( bps->registered )
@@ -436,6 +493,9 @@ qhandle_t CG_RegisterParticleSystem( char *name )
for( k = 0; k < bp->numFrames; k++ )
bp->shaders[ k ] = trap_R_RegisterShader( bp->shaderNames[ k ] );
+ for( k = 0; k < bp->numModels; k++ )
+ bp->models[ k ] = trap_R_RegisterModel( bp->modelNames[ k ] );
+
//recursively register any children
if( bp->childSystemName[ 0 ] != '\0' )
{
@@ -450,6 +510,9 @@ qhandle_t CG_RegisterParticleSystem( char *name )
//the system deals with it
CG_RegisterParticleSystem( bp->onDeathSystemName );
}
+
+ if( bp->childTrailSystemName[ 0 ] != '\0' )
+ bp->childTrailSystemHandle = CG_RegisterTrailSystem( bp->childTrailSystemName );
}
}
@@ -571,6 +634,13 @@ static qboolean CG_ParseParticle( baseParticle_t *bp, char **text_p )
}
else if( !Q_stricmp( token, "shader" ) )
{
+ if( bp->numModels > 0 )
+ {
+ CG_Printf( S_COLOR_RED "ERROR: 'shader' not allowed in "
+ "conjunction with 'model'\n", token );
+ break;
+ }
+
token = COM_Parse( text_p );
if( !token )
break;
@@ -581,15 +651,86 @@ static qboolean CG_ParseParticle( baseParticle_t *bp, char **text_p )
bp->framerate = atof_neg( token, qfalse );
token = COM_ParseExt( text_p, qfalse );
+ if( !*token )
+ break;
- while( token && token[ 0 ] != 0 )
+ while( *token && bp->numFrames < MAX_PS_SHADER_FRAMES )
{
Q_strncpyz( bp->shaderNames[ bp->numFrames++ ], token, MAX_QPATH );
token = COM_ParseExt( text_p, qfalse );
}
- if( !token )
+ continue;
+ }
+ else if( !Q_stricmp( token, "model" ) )
+ {
+ if( bp->numFrames > 0 )
+ {
+ CG_Printf( S_COLOR_RED "ERROR: 'model' not allowed in "
+ "conjunction with 'shader'\n", token );
break;
+ }
+
+ token = COM_ParseExt( text_p, qfalse );
+ if( !*token )
+ break;
+
+ while( *token && bp->numModels < MAX_PS_MODELS )
+ {
+ Q_strncpyz( bp->modelNames[ bp->numModels++ ], token, MAX_QPATH );
+ token = COM_ParseExt( text_p, qfalse );
+ }
+
+ continue;
+ }
+ else if( !Q_stricmp( token, "modelAnimation" ) )
+ {
+ token = COM_Parse( text_p );
+ if( !*token )
+ break;
+
+ bp->modelAnimation.firstFrame = atoi_neg( token, qfalse );
+
+ token = COM_Parse( text_p );
+ if( !*token )
+ break;
+
+ bp->modelAnimation.numFrames = atoi( token );
+ bp->modelAnimation.reversed = qfalse;
+ bp->modelAnimation.flipflop = qfalse;
+
+ // if numFrames is negative the animation is reversed
+ if( bp->modelAnimation.numFrames < 0 )
+ {
+ bp->modelAnimation.numFrames = -bp->modelAnimation.numFrames;
+ bp->modelAnimation.reversed = qtrue;
+ }
+
+ token = COM_Parse( text_p );
+ if( !*token )
+ break;
+
+ bp->modelAnimation.loopFrames = atoi( token );
+
+ token = COM_Parse( text_p );
+ if( !*token )
+ break;
+
+ if( !Q_stricmp( token, "sync" ) )
+ {
+ bp->modelAnimation.frameLerp = -1;
+ bp->modelAnimation.initialLerp = -1;
+ }
+ else
+ {
+ float fps = atof_neg( token, qfalse );
+
+ if( fps == 0.0f )
+ fps = 1.0f;
+
+ bp->modelAnimation.frameLerp = 1000 / fps;
+ bp->modelAnimation.initialLerp = 1000 / fps;
+ }
continue;
}
@@ -602,6 +743,8 @@ static qboolean CG_ParseParticle( baseParticle_t *bp, char **text_p )
if( !Q_stricmp( token, "static" ) )
bp->velMoveType = PMT_STATIC;
+ else if( !Q_stricmp( token, "static_transform" ) )
+ bp->velMoveType = PMT_STATIC_TRANSFORM;
else if( !Q_stricmp( token, "tag" ) )
bp->velMoveType = PMT_TAG;
else if( !Q_stricmp( token, "cent" ) )
@@ -701,6 +844,8 @@ static qboolean CG_ParseParticle( baseParticle_t *bp, char **text_p )
if( !Q_stricmp( token, "static" ) )
bp->accMoveType = PMT_STATIC;
+ else if( !Q_stricmp( token, "static_transform" ) )
+ bp->accMoveType = PMT_STATIC_TRANSFORM;
else if( !Q_stricmp( token, "tag" ) )
bp->accMoveType = PMT_TAG;
else if( !Q_stricmp( token, "cent" ) )
@@ -978,6 +1123,16 @@ static qboolean CG_ParseParticle( baseParticle_t *bp, char **text_p )
continue;
}
+ else if( !Q_stricmp( token, "childTrailSystem" ) )
+ {
+ token = COM_Parse( text_p );
+ if( !token )
+ break;
+
+ Q_strncpyz( bp->childTrailSystemName, token, MAX_QPATH );
+
+ continue;
+ }
else if( !Q_stricmp( token, "}" ) )
return qtrue; //reached the end of this particle
else
@@ -1176,6 +1331,8 @@ static qboolean CG_ParseParticleSystem( baseParticleSystem_t *bps, char **text_p
}
continue;
}
+ else if( !Q_stricmp( token, "thirdPersonOnly" ) )
+ bps->thirdPersonOnly = qtrue;
else if( !Q_stricmp( token, "ejector" ) ) //acceptable text
continue;
else if( !Q_stricmp( token, "}" ) )
@@ -1609,6 +1766,13 @@ static void CG_EvaluateParticlePhysics( particle_t *p )
vec3_t mins, maxs;
float deltaTime, bounce, radius, dot;
trace_t trace;
+ vec3_t transform[ 3 ];
+
+ if( p->atRest )
+ {
+ VectorClear( p->velocity );
+ return;
+ }
switch( bp->accMoveType )
{
@@ -1620,6 +1784,26 @@ static void CG_EvaluateParticlePhysics( particle_t *p )
break;
+ case PMT_STATIC_TRANSFORM:
+ if( !CG_AttachmentAxis( &ps->attachment, transform ) )
+ {
+ CG_Printf( S_COLOR_RED "ERROR: a particle with accelerationType "
+ "static_transform is not attached to something which can "
+ "provide a transformation\n" );
+ return;
+ }
+
+ if( bp->accMoveValues.dirType == PMD_POINT )
+ {
+ vec3_t transPoint;
+
+ VectorMatrixMultiply( bp->accMoveValues.point, transform, transPoint );
+ VectorSubtract( transPoint, p->origin, acceleration );
+ }
+ else if( bp->accMoveValues.dirType == PMD_LINEAR )
+ VectorMatrixMultiply( bp->accMoveValues.dir, transform, acceleration );
+ break;
+
case PMT_TAG:
case PMT_CENT_ANGLES:
if( bp->accMoveValues.dirType == PMD_POINT )
@@ -1720,6 +1904,11 @@ static void CG_EvaluateParticlePhysics( particle_t *p )
VectorScale( p->velocity, bounce, p->velocity );
+ if( trace.plane.normal[ 2 ] > 0.0f &&
+ ( p->velocity[ 2 ] < 40.0f ||
+ p->velocity[ 2 ] < -cg.frametime * p->velocity[ 2 ] ) )
+ p->atRest = qtrue;
+
VectorCopy( trace.endpos, p->origin );
}
@@ -1827,71 +2016,129 @@ Actually render a particle
*/
static void CG_RenderParticle( particle_t *p )
{
- refEntity_t re;
- float timeFrac;
- int index;
- baseParticle_t *bp = p->class;
- vec3_t alight, dlight, lightdir;
- int i;
+ refEntity_t re;
+ float timeFrac, scale;
+ int index;
+ baseParticle_t *bp = p->class;
+ particleSystem_t *ps = p->parent->parent;
+ baseParticleSystem_t *bps = ps->class;
+ vec3_t alight, dlight, lightdir;
+ int i;
+ vec3_t up = { 0.0f, 0.0f, 1.0f };
memset( &re, 0, sizeof( refEntity_t ) );
- for( i = 0; i <= 3; re.shaderRGBA[ i++ ] = 0xFF );
-
timeFrac = CG_CalculateTimeFrac( p->birthTime, p->lifeTime, 0 );
- re.reType = RT_SPRITE;
- re.shaderTime = p->birthTime / 1000.0f; //FIXME: allow user to change?
-
- re.shaderRGBA[ 3 ] = (byte)( (float)0xFF *
- CG_LerpValues( p->alpha.initial,
- p->alpha.final,
- CG_CalculateTimeFrac( p->birthTime,
- p->lifeTime,
- p->alpha.delay ) ) );
-
- re.radius = CG_LerpValues( p->radius.initial,
+ scale = CG_LerpValues( p->radius.initial,
p->radius.final,
CG_CalculateTimeFrac( p->birthTime,
p->lifeTime,
p->radius.delay ) );
- re.rotation = CG_LerpValues( p->rotation.initial,
- p->rotation.final,
- CG_CalculateTimeFrac( p->birthTime,
- p->lifeTime,
- p->rotation.delay ) );
+ if( bp->numFrames ) //shader based
+ {
+ re.reType = RT_SPRITE;
- // if the view would be "inside" the sprite, kill the sprite
- // so it doesn't add too much overdraw
- if( Distance( p->origin, cg.refdef.vieworg ) < re.radius && bp->overdrawProtection )
- return;
+ re.shaderTime = p->birthTime / 1000.0f; //FIXME: allow user to change?
- //apply environmental lighting to the particle
- if( bp->realLight )
- {
- trap_R_LightForPoint( p->origin, alight, dlight, lightdir );
- for( i = 0; i <= 2; i++ )
- re.shaderRGBA[ i ] = (int)alight[ i ];
- }
+ //apply environmental lighting to the particle
+ if( bp->realLight )
+ {
+ trap_R_LightForPoint( p->origin, alight, dlight, lightdir );
+ for( i = 0; i <= 2; i++ )
+ re.shaderRGBA[ i ] = (int)alight[ i ];
+ }
+ else
+ for( i = 0; i <= 3; re.shaderRGBA[ i++ ] = 0xFF );
- if( bp->framerate == 0.0f )
- {
- //sync animation time to lifeTime of particle
- index = (int)( timeFrac * ( bp->numFrames + 1 ) );
+ re.shaderRGBA[ 3 ] = (byte)( (float)0xFF *
+ CG_LerpValues( p->alpha.initial,
+ p->alpha.final,
+ CG_CalculateTimeFrac( p->birthTime,
+ p->lifeTime,
+ p->alpha.delay ) ) );
+
+ re.radius = scale;
+
+ re.rotation = CG_LerpValues( p->rotation.initial,
+ p->rotation.final,
+ CG_CalculateTimeFrac( p->birthTime,
+ p->lifeTime,
+ p->rotation.delay ) );
- if( index >= bp->numFrames )
- index = bp->numFrames - 1;
+ // if the view would be "inside" the sprite, kill the sprite
+ // so it doesn't add too much overdraw
+ if( Distance( p->origin, cg.refdef.vieworg ) < re.radius && bp->overdrawProtection )
+ return;
+
+ if( bp->framerate == 0.0f )
+ {
+ //sync animation time to lifeTime of particle
+ index = (int)( timeFrac * ( bp->numFrames + 1 ) );
+
+ if( index >= bp->numFrames )
+ index = bp->numFrames - 1;
+
+ re.customShader = bp->shaders[ index ];
+ }
+ else
+ {
+ //looping animation
+ index = (int)( bp->framerate * timeFrac * p->lifeTime * 0.001 ) % bp->numFrames;
+ re.customShader = bp->shaders[ index ];
+ }
- re.customShader = bp->shaders[ index ];
}
- else
+ else if( bp->numModels ) //model based
{
- //looping animation
- index = (int)( bp->framerate * timeFrac * p->lifeTime * 0.001 ) % bp->numFrames;
- re.customShader = bp->shaders[ index ];
+ re.reType = RT_MODEL;
+
+ re.hModel = p->model;
+
+ if( p->atRest )
+ AxisCopy( p->lastAxis, re.axis );
+ else
+ {
+ // convert direction of travel into axis
+ VectorNormalize2( p->velocity, re.axis[ 0 ] );
+
+ if( re.axis[ 0 ][ 0 ] == 0.0f && re.axis[ 0 ][ 1 ] == 0.0f )
+ AxisCopy( axisDefault, re.axis );
+ else
+ {
+ ProjectPointOnPlane( re.axis[ 2 ], up, re.axis[ 0 ] );
+ VectorNormalize( re.axis[ 2 ] );
+ CrossProduct( re.axis[ 2 ], re.axis[ 0 ], re.axis[ 1 ] );
+ }
+
+ AxisCopy( re.axis, p->lastAxis );
+ }
+
+ if( scale != 1.0f )
+ {
+ VectorScale( re.axis[ 0 ], scale, re.axis[ 0 ] );
+ VectorScale( re.axis[ 1 ], scale, re.axis[ 1 ] );
+ VectorScale( re.axis[ 2 ], scale, re.axis[ 2 ] );
+ re.nonNormalizedAxes = qtrue;
+ }
+ else
+ re.nonNormalizedAxes = qfalse;
+
+ p->lf.animation = &bp->modelAnimation;
+
+ //run animation
+ CG_RunLerpFrame( &p->lf );
+
+ re.oldframe = p->lf.oldFrame;
+ re.frame = p->lf.frame;
+ re.backlerp = p->lf.backlerp;
}
+ if( bps->thirdPersonOnly &&
+ CG_AttachmentCentNum( &ps->attachment ) == cg.snap->ps.clientNum )
+ re.renderfx |= RF_THIRD_PERSON;
+
VectorCopy( p->origin, re.origin );
trap_R_AddRefEntityToScene( &re );
diff --git a/src/cgame/cg_players.c b/src/cgame/cg_players.c
index 1ef18f8b..dce04324 100644
--- a/src/cgame/cg_players.c
+++ b/src/cgame/cg_players.c
@@ -903,13 +903,13 @@ static void CG_SetLerpFrameAnimation( clientInfo_t *ci, lerpFrame_t *lf, int new
/*
===============
-CG_RunLerpFrame
+CG_RunPlayerLerpFrame
Sets cg.snap, cg.oldFrame, and cg.backlerp
cg.time should be between oldFrameTime and frameTime after exit
===============
*/
-static void CG_RunLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation, float speedScale )
+static void CG_RunPlayerLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation, float speedScale )
{
int f, numFrames;
animation_t *anim;
@@ -1035,15 +1035,15 @@ static void CG_PlayerAnimation( centity_t *cent, int *legsOld, int *legs, float
// do the shuffle turn frames locally
if( cent->pe.legs.yawing && ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) == LEGS_IDLE )
- CG_RunLerpFrame( ci, &cent->pe.legs, LEGS_TURN, speedScale );
+ CG_RunPlayerLerpFrame( ci, &cent->pe.legs, LEGS_TURN, speedScale );
else
- CG_RunLerpFrame( ci, &cent->pe.legs, cent->currentState.legsAnim, speedScale );
+ CG_RunPlayerLerpFrame( ci, &cent->pe.legs, cent->currentState.legsAnim, speedScale );
*legsOld = cent->pe.legs.oldFrame;
*legs = cent->pe.legs.frame;
*legsBackLerp = cent->pe.legs.backlerp;
- CG_RunLerpFrame( ci, &cent->pe.torso, cent->currentState.torsoAnim, speedScale );
+ CG_RunPlayerLerpFrame( ci, &cent->pe.torso, cent->currentState.torsoAnim, speedScale );
*torsoOld = cent->pe.torso.oldFrame;
*torso = cent->pe.torso.frame;
@@ -1075,9 +1075,9 @@ static void CG_PlayerNonSegAnimation( centity_t *cent, int *nonSegOld,
// do the shuffle turn frames locally
if( cent->pe.nonseg.yawing && ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) == NSPA_STAND )
- CG_RunLerpFrame( ci, &cent->pe.nonseg, NSPA_TURN, speedScale );
+ CG_RunPlayerLerpFrame( ci, &cent->pe.nonseg, NSPA_TURN, speedScale );
else
- CG_RunLerpFrame( ci, &cent->pe.nonseg, cent->currentState.legsAnim, speedScale );
+ CG_RunPlayerLerpFrame( ci, &cent->pe.nonseg, cent->currentState.legsAnim, speedScale );
*nonSegOld = cent->pe.nonseg.oldFrame;
*nonSeg = cent->pe.nonseg.frame;
@@ -2347,13 +2347,13 @@ void CG_Corpse( centity_t *cent )
else if( !ci->nonsegmented )
{
memset( &cent->pe.legs, 0, sizeof( lerpFrame_t ) );
- CG_RunLerpFrame( ci, &cent->pe.legs, es->legsAnim, 1 );
+ CG_RunPlayerLerpFrame( ci, &cent->pe.legs, es->legsAnim, 1 );
legs.oldframe = cent->pe.legs.oldFrame;
legs.frame = cent->pe.legs.frame;
legs.backlerp = cent->pe.legs.backlerp;
memset( &cent->pe.torso, 0, sizeof( lerpFrame_t ) );
- CG_RunLerpFrame( ci, &cent->pe.torso, es->torsoAnim, 1 );
+ CG_RunPlayerLerpFrame( ci, &cent->pe.torso, es->torsoAnim, 1 );
torso.oldframe = cent->pe.torso.oldFrame;
torso.frame = cent->pe.torso.frame;
torso.backlerp = cent->pe.torso.backlerp;
@@ -2361,7 +2361,7 @@ void CG_Corpse( centity_t *cent )
else
{
memset( &cent->pe.nonseg, 0, sizeof( lerpFrame_t ) );
- CG_RunLerpFrame( ci, &cent->pe.nonseg, es->legsAnim, 1 );
+ CG_RunPlayerLerpFrame( ci, &cent->pe.nonseg, es->legsAnim, 1 );
legs.oldframe = cent->pe.nonseg.oldFrame;
legs.frame = cent->pe.nonseg.frame;
legs.backlerp = cent->pe.nonseg.backlerp;
diff --git a/src/cgame/cg_trails.c b/src/cgame/cg_trails.c
index e80225e4..6f9aefcf 100644
--- a/src/cgame/cg_trails.c
+++ b/src/cgame/cg_trails.c
@@ -25,12 +25,12 @@ static trailBeam_t trailBeams[ MAX_TRAIL_BEAMS ];
/*
===============
-CG_CalculateBeamTextureCoordinates
+CG_CalculateBeamNodeProperties
Fills in trailBeamNode_t.textureCoord
===============
*/
-static void CG_CalculateBeamTextureCoordinates( trailBeam_t *tb )
+static void CG_CalculateBeamNodeProperties( trailBeam_t *tb )
{
trailBeamNode_t *i = NULL;
trailSystem_t *ts;
@@ -129,20 +129,30 @@ Renders a beam
*/
static void CG_RenderBeam( trailBeam_t *tb )
{
- trailBeamNode_t *i = NULL;
- trailBeamNode_t *prev = NULL;
- trailBeamNode_t *next = NULL;
- vec3_t up;
- polyVert_t verts[ ( MAX_TRAIL_BEAM_NODES - 1 ) * 4 ];
- int numVerts = 0;
- baseTrailBeam_t *btb;
+ trailBeamNode_t *i = NULL;
+ trailBeamNode_t *prev = NULL;
+ trailBeamNode_t *next = NULL;
+ vec3_t up;
+ polyVert_t verts[ ( MAX_TRAIL_BEAM_NODES - 1 ) * 4 ];
+ int numVerts = 0;
+ baseTrailBeam_t *btb;
+ trailSystem_t *ts;
+ baseTrailSystem_t *bts;
if( !tb || !tb->nodes )
return;
btb = tb->class;
+ ts = tb->parent;
+ bts = ts->class;
- CG_CalculateBeamTextureCoordinates( tb );
+ if( bts->thirdPersonOnly &&
+ ( CG_AttachmentCentNum( &ts->frontAttachment ) == cg.snap->ps.clientNum ||
+ CG_AttachmentCentNum( &ts->backAttachment ) == cg.snap->ps.clientNum ) &&
+ !cg.renderingThirdPerson )
+ return;
+
+ CG_CalculateBeamNodeProperties( tb );
i = tb->nodes;
@@ -171,7 +181,7 @@ static void CG_RenderBeam( trailBeam_t *tb )
if( prev )
{
- VectorMA( i->position, i->halfWidth + i->jitter, up, verts[ numVerts ].xyz );
+ VectorMA( i->position, i->halfWidth, up, verts[ numVerts ].xyz );
verts[ numVerts ].st[ 0 ] = i->textureCoord;
verts[ numVerts ].st[ 1 ] = 1.0f;
@@ -185,7 +195,7 @@ static void CG_RenderBeam( trailBeam_t *tb )
numVerts++;
- VectorMA( i->position, -i->halfWidth + i->jitter, up, verts[ numVerts ].xyz );
+ VectorMA( i->position, -i->halfWidth, up, verts[ numVerts ].xyz );
verts[ numVerts ].st[ 0 ] = i->textureCoord;
verts[ numVerts ].st[ 1 ] = 0.0f;
@@ -202,7 +212,7 @@ static void CG_RenderBeam( trailBeam_t *tb )
if( next )
{
- VectorMA( i->position, -i->halfWidth + i->jitter, up, verts[ numVerts ].xyz );
+ VectorMA( i->position, -i->halfWidth, up, verts[ numVerts ].xyz );
verts[ numVerts ].st[ 0 ] = i->textureCoord;
verts[ numVerts ].st[ 1 ] = 0.0f;
@@ -216,7 +226,7 @@ static void CG_RenderBeam( trailBeam_t *tb )
numVerts++;
- VectorMA( i->position, i->halfWidth + i->jitter, up, verts[ numVerts ].xyz );
+ VectorMA( i->position, i->halfWidth, up, verts[ numVerts ].xyz );
verts[ numVerts ].st[ 0 ] = i->textureCoord;
verts[ numVerts ].st[ 1 ] = 1.0f;
@@ -444,7 +454,10 @@ static void CG_ApplyJitters( trailBeam_t *tb )
if( tb->nextJitterTimes[ j ] <= cg.time )
{
for( i = tb->nodes; i; i = i->next )
- i->jitters[ j ] = ( crandom( ) * btb->jitters[ j ].magnitude );
+ {
+ i->jitters[ j ][ 0 ] = ( crandom( ) * btb->jitters[ j ].magnitude );
+ i->jitters[ j ][ 1 ] = ( crandom( ) * btb->jitters[ j ].magnitude );
+ }
tb->nextJitterTimes[ j ] = cg.time + btb->jitters[ j ].period;
}
@@ -464,12 +477,46 @@ static void CG_ApplyJitters( trailBeam_t *tb )
for( i = start; i; i = i->next )
{
- i->jitter = 0.0f;
+ vec3_t forward, right, up;
+ trailBeamNode_t *prev;
+ trailBeamNode_t *next;
+ float upJitter = 0.0f, rightJitter = 0.0f;
+
+ prev = i->prev;
+ next = i->next;
+
+ if( prev && next )
+ {
+ //this node has two neighbours
+ GetPerpendicularViewVector( cg.refdef.vieworg, next->position, prev->position, up );
+ VectorSubtract( next->position, prev->position, forward );
+ }
+ else if( !prev && next )
+ {
+ //this is the front
+ GetPerpendicularViewVector( cg.refdef.vieworg, next->position, i->position, up );
+ VectorSubtract( next->position, i->position, forward );
+ }
+ else if( prev && !next )
+ {
+ //this is the back
+ GetPerpendicularViewVector( cg.refdef.vieworg, i->position, prev->position, up );
+ VectorSubtract( i->position, prev->position, forward );
+ }
+
+ VectorNormalize( forward );
+ CrossProduct( forward, up, right );
+ VectorNormalize( right );
for( j = 0; j < btb->numJitters; j++ )
- i->jitter += i->jitters[ j ];
+ {
+ upJitter += i->jitters[ j ][ 0 ];
+ rightJitter += i->jitters[ j ][ 1 ];
+ }
+
+ VectorMA( i->position, upJitter, up, i->position );
+ VectorMA( i->position, rightJitter, right, i->position );
- //mmmm... nice
if( i == end )
break;
}
@@ -513,7 +560,8 @@ static void CG_UpdateBeam( trailBeam_t *tb )
if( !tb->nodes->next && CG_Attached( &ts->frontAttachment ) )
{
// this is the first node to be added
- CG_AttachmentPoint( &ts->frontAttachment, i->refPosition );
+ if( !CG_AttachmentPoint( &ts->frontAttachment, i->refPosition ) )
+ CG_DestroyTrailSystem( &ts );
}
else
VectorCopy( i->prev->refPosition, i->refPosition );
@@ -536,8 +584,12 @@ static void CG_UpdateBeam( trailBeam_t *tb )
return;
}
- CG_AttachmentPoint( &ts->frontAttachment, front );
- CG_AttachmentPoint( &ts->backAttachment, back );
+ if( !CG_AttachmentPoint( &ts->frontAttachment, front ) )
+ CG_DestroyTrailSystem( &ts );
+
+ if( !CG_AttachmentPoint( &ts->backAttachment, back ) )
+ CG_DestroyTrailSystem( &ts );
+
VectorSubtract( back, front, dir );
for( j = 0, i = tb->nodes; i; i = i->next, j++ )
@@ -585,7 +637,9 @@ static void CG_UpdateBeam( trailBeam_t *tb )
}
}
- CG_AttachmentPoint( &ts->frontAttachment, tb->nodes->refPosition );
+ if( !CG_AttachmentPoint( &ts->frontAttachment, tb->nodes->refPosition ) )
+ CG_DestroyTrailSystem( &ts );
+
VectorCopy( tb->nodes->refPosition, tb->nodes->position );
}
@@ -940,6 +994,8 @@ static qboolean CG_ParseTrailSystem( baseTrailSystem_t *bts, char **text_p, cons
}
continue;
}
+ else if( !Q_stricmp( token, "thirdPersonOnly" ) )
+ bts->thirdPersonOnly = qtrue;
else if( !Q_stricmp( token, "beam" ) ) //acceptable text
continue;
else if( !Q_stricmp( token, "}" ) )
@@ -1118,7 +1174,7 @@ qhandle_t CG_RegisterTrailSystem( char *name )
baseTrailSystem_t *bts;
baseTrailBeam_t *btb;
- for( i = 0; i < MAX_TRAIL_SYSTEMS; i++ )
+ for( i = 0; i < MAX_BASETRAIL_SYSTEMS; i++ )
{
bts = &baseTrailSystems[ i ];
diff --git a/src/cgame/cg_weapons.c b/src/cgame/cg_weapons.c
index 935342ac..7df8b0fa 100644
--- a/src/cgame/cg_weapons.c
+++ b/src/cgame/cg_weapons.c
@@ -18,147 +18,6 @@
#include "cg_local.h"
/*
-==========================
-CG_MachineGunEjectBrass
-==========================
-*/
-static void CG_MachineGunEjectBrass( centity_t *cent )
-{
- localEntity_t *le;
- refEntity_t *re;
- vec3_t velocity, xvelocity;
- vec3_t offset, xoffset;
- float waterScale = 1.0f;
- vec3_t v[ 3 ];
-
- if( cg_brassTime.integer <= 0 )
- return;
-
- le = CG_AllocLocalEntity( );
- re = &le->refEntity;
-
- velocity[ 0 ] = 0;
- velocity[ 1 ] = -50 + 40 * crandom( );
- velocity[ 2 ] = 100 + 50 * crandom( );
-
- le->leType = LE_FRAGMENT;
- le->startTime = cg.time;
- le->endTime = le->startTime + cg_brassTime.integer + ( cg_brassTime.integer / 4 ) * random( );
-
- le->pos.trType = TR_GRAVITY;
- le->pos.trTime = cg.time - ( rand( ) & 15 );
-
- AnglesToAxis( cent->lerpAngles, v );
-
- offset[ 0 ] = 8;
- offset[ 1 ] = -4;
- offset[ 2 ] = 24;
-
- xoffset[ 0 ] = offset[ 0 ] * v[ 0 ][ 0 ] + offset[ 1 ] * v[ 1 ][ 0 ] + offset[ 2 ] * v[ 2 ][ 0 ];
- xoffset[ 1 ] = offset[ 0 ] * v[ 0 ][ 1 ] + offset[ 1 ] * v[ 1 ][ 1 ] + offset[ 2 ] * v[ 2 ][ 1 ];
- xoffset[ 2 ] = offset[ 0 ] * v[ 0 ][ 2 ] + offset[ 1 ] * v[ 1 ][ 2 ] + offset[ 2 ] * v[ 2 ][ 2 ];
- VectorAdd( cent->lerpOrigin, xoffset, re->origin );
-
- VectorCopy( re->origin, le->pos.trBase );
-
- if( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER )
- waterScale = 0.10f;
-
- xvelocity[ 0 ] = velocity[ 0 ] * v[ 0 ][ 0 ] + velocity[ 1 ] * v[ 1 ][ 0 ] + velocity[ 2 ] * v[ 2 ][ 0 ];
- xvelocity[ 1 ] = velocity[ 0 ] * v[ 0 ][ 1 ] + velocity[ 1 ] * v[ 1 ][ 1 ] + velocity[ 2 ] * v[ 2 ][ 1 ];
- xvelocity[ 2 ] = velocity[ 0 ] * v[ 0 ][ 2 ] + velocity[ 1 ] * v[ 1 ][ 2 ] + velocity[ 2 ] * v[ 2 ][ 2 ];
- VectorScale( xvelocity, waterScale, le->pos.trDelta );
-
- AxisCopy( axisDefault, re->axis );
- re->hModel = cgs.media.machinegunBrassModel;
-
- le->bounceFactor = 0.4 * waterScale;
-
- le->angles.trType = TR_LINEAR;
- le->angles.trTime = cg.time;
- le->angles.trBase[ 0 ] = rand( ) & 31;
- le->angles.trBase[ 1 ] = rand( ) & 31;
- le->angles.trBase[ 2 ] = rand( ) & 31;
- le->angles.trDelta[ 0 ] = 2;
- le->angles.trDelta[ 1 ] = 1;
- le->angles.trDelta[ 2 ] = 0;
-
- le->leFlags = LEF_TUMBLE;
- le->leBounceSoundType = LEBS_BRASS;
- le->leMarkType = LEMT_NONE;
-}
-
-/*
-==========================
-CG_ShotgunEjectBrass
-==========================
-*/
-static void CG_ShotgunEjectBrass( centity_t *cent )
-{
- localEntity_t *le;
- refEntity_t *re;
- vec3_t velocity, xvelocity;
- vec3_t offset, xoffset;
- vec3_t v[ 3 ];
- float waterScale = 1.0f;
-
- if( cg_brassTime.integer <= 0 )
- return;
-
- le = CG_AllocLocalEntity( );
- re = &le->refEntity;
-
- velocity[ 0 ] = 60 + 60 * crandom( );
- velocity[ 1 ] = 40 + 10 * crandom( );
- velocity[ 2 ] = 100 + 50 * crandom( );
-
- le->leType = LE_FRAGMENT;
- le->startTime = cg.time;
- le->endTime = le->startTime + cg_brassTime.integer * 3 + cg_brassTime.integer * random( );
-
- le->pos.trType = TR_GRAVITY;
- le->pos.trTime = cg.time;
-
- AnglesToAxis( cent->lerpAngles, v );
-
- offset[ 0 ] = 8;
- offset[ 1 ] = 0;
- offset[ 2 ] = 24;
-
- xoffset[ 0 ] = offset[ 0 ] * v[ 0 ][ 0 ] + offset[ 1 ] * v[ 1 ][ 0 ] + offset[ 2 ] * v[ 2 ][ 0 ];
- xoffset[ 1 ] = offset[ 0 ] * v[ 0 ][ 1 ] + offset[ 1 ] * v[ 1 ][ 1 ] + offset[ 2 ] * v[ 2 ][ 1 ];
- xoffset[ 2 ] = offset[ 0 ] * v[ 0 ][ 2 ] + offset[ 1 ] * v[ 1 ][ 2 ] + offset[ 2 ] * v[ 2 ][ 2 ];
- VectorAdd( cent->lerpOrigin, xoffset, re->origin );
- VectorCopy( re->origin, le->pos.trBase );
-
- if( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER )
- waterScale = 0.10f;
-
- xvelocity[ 0 ] = velocity[ 0 ] * v[ 0 ][ 0 ] + velocity[ 1 ] * v[ 1 ][ 0 ] + velocity[ 2 ] * v[ 2 ][ 0 ];
- xvelocity[ 1 ] = velocity[ 0 ] * v[ 0 ][ 1 ] + velocity[ 1 ] * v[ 1 ][ 1 ] + velocity[ 2 ] * v[ 2 ][ 1 ];
- xvelocity[ 2 ] = velocity[ 0 ] * v[ 0 ][ 2 ] + velocity[ 1 ] * v[ 1 ][ 2 ] + velocity[ 2 ] * v[ 2 ][ 2 ];
- VectorScale( xvelocity, waterScale, le->pos.trDelta );
-
- AxisCopy( axisDefault, re->axis );
- re->hModel = cgs.media.shotgunBrassModel;
- le->bounceFactor = 0.3f;
-
- le->angles.trType = TR_LINEAR;
- le->angles.trTime = cg.time;
- le->angles.trBase[ 0 ] = rand( )&31;
- le->angles.trBase[ 1 ] = rand( )&31;
- le->angles.trBase[ 2 ] = rand( )&31;
- le->angles.trDelta[ 0 ] = 1;
- le->angles.trDelta[ 1 ] = 0.5;
- le->angles.trDelta[ 2 ] = 0;
-
- le->leFlags = LEF_TUMBLE;
- le->leBounceSoundType = LEBS_BRASS;
- le->leMarkType = LEMT_NONE;
-}
-
-
-/*
=================
CG_RegisterUpgrade
@@ -809,19 +668,6 @@ void CG_RegisterWeapon( int weaponNum )
//FIXME:
for( i = WPM_NONE + 1; i < WPM_NUM_WEAPONMODES; i++ )
weaponInfo->wim[ i ].loopFireSound = qfalse;
-
- switch( weaponNum )
- {
- case WP_MACHINEGUN:
- case WP_MGTURRET:
- case WP_CHAINGUN:
- weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass;
- break;
-
- case WP_SHOTGUN:
- weaponInfo->ejectBrassFunc = CG_ShotgunEjectBrass;
- break;
- }
}
/*
@@ -1670,23 +1516,6 @@ void CG_FireWeapon( centity_t *cent, weaponMode_t weaponMode )
if( wi->wim[ weaponMode ].flashSound[ c ] )
trap_S_StartSound( NULL, es->number, CHAN_WEAPON, wi->wim[ weaponMode ].flashSound[ c ] );
}
-
- // do brass ejection
- if( wi->ejectBrassFunc && cg_brassTime.integer > 0 )
- {
- if( es->eType == ET_BUILDABLE )
- {
- //yucko hack to get turret brass ejecting with the barrel instead of the base
- vec3_t temp;
-
- VectorCopy( cent->lerpAngles, temp );
- VectorCopy( es->angles2, cent->lerpAngles );
- wi->ejectBrassFunc( cent );
- VectorCopy( temp, cent->lerpAngles );
- }
- else
- wi->ejectBrassFunc( cent );
- }
}
diff --git a/src/game/g_utils.c b/src/game/g_utils.c
index fa4b5f23..1f4fa6df 100644
--- a/src/game/g_utils.c
+++ b/src/game/g_utils.c
@@ -987,7 +987,7 @@ gentity_t *G_ClosestEnt( vec3_t origin, gentity_t **entities, int numEntities )
{
gentity_t *ent = entities[ i ];
- if( ( nd = VectorDistance( origin, ent->s.origin ) ) < d )
+ if( ( nd = Distance( origin, ent->s.origin ) ) < d )
{
d = nd;
closestEnt = ent;
diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c
index a28da78b..3f523071 100644
--- a/src/game/g_weapon.c
+++ b/src/game/g_weapon.c
@@ -1131,7 +1131,7 @@ void G_UpdateZaps( int msec )
source = zap->targets[ j - 1 ];
if( target->health <= 0 || !target->inuse || //early out
- VectorDistance( source->s.origin, target->s.origin ) > LEVEL2_AREAZAP_RANGE )
+ Distance( source->s.origin, target->s.origin ) > LEVEL2_AREAZAP_RANGE )
{
target = zap->targets[ j ] = G_FindNewZapTarget( source );
diff --git a/src/game/q_math.c b/src/game/q_math.c
index 78209fd1..83410479 100644
--- a/src/game/q_math.c
+++ b/src/game/q_math.c
@@ -1279,6 +1279,17 @@ void MatrixMultiply( float in1[ 3 ][ 3 ], float in2[ 3 ][ 3 ], float out[ 3 ][ 3
in1[ 2 ][ 2 ] * in2[ 2 ][ 2 ];
}
+/*
+================
+VectorMatrixMultiply
+================
+*/
+void VectorMatrixMultiply( const vec3_t p, vec3_t m[ 3 ], vec3_t out )
+{
+ out[ 0 ] = m[ 0 ][ 0 ] * p[ 0 ] + m[ 1 ][ 0 ] * p[ 1 ] + m[ 2 ][ 0 ] * p[ 2 ];
+ out[ 1 ] = m[ 0 ][ 1 ] * p[ 0 ] + m[ 1 ][ 1 ] * p[ 1 ] + m[ 2 ][ 1 ] * p[ 2 ];
+ out[ 2 ] = m[ 0 ][ 2 ] * p[ 0 ] + m[ 1 ][ 2 ] * p[ 1 ] + m[ 2 ][ 2 ] * p[ 2 ];
+}
void AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
{
diff --git a/src/game/q_shared.h b/src/game/q_shared.h
index e9c09c48..6b1c8932 100644
--- a/src/game/q_shared.h
+++ b/src/game/q_shared.h
@@ -771,6 +771,7 @@ void MakeNormalVectors( const vec3_t forward, vec3_t right, vec3_t up );
//int PlaneTypeForNormal (vec3_t normal);
void MatrixMultiply(float in1[3][3], float in2[3][3], float out[3][3]);
+void VectorMatrixMultiply( const vec3_t p, vec3_t m[ 3 ], vec3_t out );
void AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
void PerpendicularVector( vec3_t dst, const vec3_t src );