/* ==================== CG_MakeExplosion ==================== */ localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir, qhandle_t hModel, qhandle_t shader, int offset, int duration, bool isSprite ) { float ang; localEntity_t *ex; vec3_t tmpVec, newOrigin; if ( duration <= 0 ) { Com_Error( ERR_DROP, "CG_MakeExplosion: duration = %i", duration ); } // skew the time a bit so they aren't all in sync offset += rand() & 63; ex = CG_AllocLocalEntity(); if ( isSprite ) { ex->leType = LE_SPRITE_EXPLOSION; // randomly rotate sprite orientation ex->refEntity.rotation = rand() % 360; VectorScale( dir, 16, tmpVec ); VectorAdd( tmpVec, origin, newOrigin ); } else { ex->leType = LE_EXPLOSION; VectorCopy( origin, newOrigin ); // set axis with random rotate if ( !dir ) { AxisClear( ex->refEntity.axis ); } else { ang = rand() % 360; VectorCopy( dir, ex->refEntity.axis[0] ); RotateAroundDirection( ex->refEntity.axis, ang ); } } // calc the timings ex->startTime = cg.time + offset; ex->endTime = ex->startTime + duration; // bias the time so all shader effects start correctly ex->refEntity.shaderTime = ex->startTime / 1000.0f; ex->refEntity.hModel = hModel; ex->refEntity.customShader = shader; // set origin VectorCopy( newOrigin, ex->refEntity.origin ); VectorCopy( newOrigin, ex->refEntity.oldorigin ); ex->color[0] = ex->color[1] = ex->color[2] = 1; return ex; }
/* ==================== CG_MakeExplosion ==================== */ localEntity_t *CG_MakeExplosion( bvec3_t origin, avec3_t dir, qhandle_t hModel, qhandle_t shader, int msec, qboolean isSprite ) { afixed ang; localEntity_t *ex; int offset; bvec3_t tmpVec, newOrigin; if ( msec <= 0 ) { CG_Error( "CG_MakeExplosion: msec = %i", msec ); } // skew the time a bit so they aren't all in sync offset = rand() & 63; ex = CG_AllocLocalEntity(); if ( isSprite ) { ex->leType = LE_SPRITE_EXPLOSION; // randomly rotate sprite orientation ex->refEntity.rotation =MAKE_AFIXED(rand() % 360); FIXED_VEC3SCALE_R( dir, BFIXED(16,0), tmpVec ); VectorAdd( tmpVec, origin, newOrigin ); } else { ex->leType = LE_EXPLOSION; VectorCopy( origin, newOrigin ); // set axis with random rotate if ( !dir ) { AxisClear( ex->refEntity.axis ); } else { ang = MAKE_AFIXED(rand() % 360); VectorCopy( dir, ex->refEntity.axis[0] ); RotateAroundDirection( ex->refEntity.axis, ang ); } } ex->startTime = cg.time - offset; ex->endTime = ex->startTime + msec; // bias the time so all shader effects start correctly ex->refEntity.shaderTime = MSECTIME_G(ex->startTime); ex->refEntity.hModel = hModel; ex->refEntity.customShader = shader; // set origin VectorCopy( newOrigin, ex->refEntity.origin ); VectorCopy( newOrigin, ex->refEntity.oldorigin ); ex->color[0] = ex->color[1] = ex->color[2] = GFIXED_1; return ex; }
qboolean FX_ParticleDraw(fxPrimitive_t *_self) { fxParticle_t *p = (fxParticle_t *)_self; polyVert_t verts[4]; vec3_t axis[3]; int i; float scale; scale = p->size * 2.0f; // ef1 is 0.5f, but you have 2.0f for(i = 0; i < 3; i++) { VectorCopy(fx_refDef->viewaxis[i], axis[i]); } if(p->rotation) RotateAroundDirection(axis, p->rotation); for(i = 0; i < 4; i++) { // Loop through each vert in the quad VectorMA( p->origin, quad_template[i][0] * scale, axis[1], verts[i].xyz ); VectorMA( verts[i].xyz, quad_template[i][1] * scale, axis[2], verts[i].xyz ); //Setup the UVs verts[i].st[0] = quad_st_template[i][0]; verts[i].st[1] = quad_st_template[i][1]; //Setup the vertex modulation verts[i].modulate[0] = (byte)((p->RGB[0] * 255)); verts[i].modulate[1] = (byte)((p->RGB[1] * 255)); verts[i].modulate[2] = (byte)((p->RGB[2] * 255)); // TODO: Use alpha chan? (copy from Elite Forces SDK?) // FIXME: NO EFFECT WTF if((p->flags & (1<<FXFLAG_USEALPHA))) { verts[i].modulate[3] = (byte)(p->alpha * 255); } else { verts[i].modulate[3] = 255; } } re.AddPolyToScene(p->shader, 4, verts, 1); return qtrue; }
void FXParticle::Draw( void ) { polyVert_t verts[4]; vec3_t axis[3]; float scale; int i; if ( m_flags & FXF_NODRAW ) return; scale = m_scale * 0.5f; for ( i = 0; i < 3; i++ ) VectorCopy( cg.refdef.viewaxis[i], axis[i] ); //This is done to spare non-rolling particles the odd angle snapping <?> if (m_roll) RotateAroundDirection( axis, m_roll ); for ( i = 0; i < 4; i++ ) { VectorMA( m_origin, sprite_template[i][0] * scale, axis[1], verts[i].xyz ); VectorMA( verts[i].xyz, sprite_template[i][1] * scale, axis[2], verts[i].xyz ); //Setup the UVs verts[i].st[0] = sprite_texture_template[i][0]; verts[i].st[1] = sprite_texture_template[i][1]; //Setup the vertex modulation verts[i].modulate[0] = (byte)(m_RGB[0] * 255); verts[i].modulate[1] = (byte)(m_RGB[1] * 255); verts[i].modulate[2] = (byte)(m_RGB[2] * 255); if ( m_flags & FXF_USE_ALPHA_CHAN ) verts[i].modulate[3] = (byte)(m_alpha * 255); else verts[i].modulate[3] = 255; } //Add it into the renderer cgi_R_AddPolyToScene( m_shader, 4, verts ); }
void FXQuad::Draw( void ) { polyVert_t verts[NUM_QUADVERTS]; vec3_t vr, vu; vec3_t axis[3]; float scale; int i; scale = m_scale * 0.5f; MakeNormalVectors( m_normal, vr, vu ); VectorCopy( m_normal, axis[0] ); VectorCopy( vr, axis[1] ); VectorCopy( vu, axis[2] ); RotateAroundDirection( axis, m_roll ); //Construct the quad for ( i = 0; i < NUM_QUADVERTS; i++ ) { VectorMA( m_origin, quad_template[i][0] * ( scale ), axis[1], verts[i].xyz ); VectorMA( verts[i].xyz, quad_template[i][1] * ( scale ), axis[2], verts[i].xyz ); verts[i].modulate[0] = m_RGB[0] * 255; verts[i].modulate[1] = m_RGB[1] * 255; verts[i].modulate[2] = m_RGB[2] * 255; if ( m_flags & FXF_USE_ALPHA_CHAN ) verts[i].modulate[3] = (byte)(m_alpha * 255); else verts[i].modulate[3] = 255; verts[i].st[0] = quad_st_template[i][0]; verts[i].st[1] = quad_st_template[i][1]; } cgi_R_AddPolyToScene( m_shader, NUM_QUADVERTS, verts ); }
/* ==================== CG_MakeExplosion ==================== */ localEntity_t *CG_MakeExplosion(vec3_t origin, vec3_t dir, qhandle_t hModel, qhandle_t shader, int msec, qboolean isSprite) { float ang; localEntity_t *ex; int offset; vec3_t tmpVec, newOrigin; if (msec <= 0) { CG_Error("CG_MakeExplosion: msec = %i", msec); } // skew the time a bit so they aren't all in sync offset = rand() & 63; ex = CG_AllocLocalEntity(); if (isSprite) { ex->leType = LE_SPRITE_EXPLOSION; // randomly rotate sprite orientation ex->refEntity.rotation = rand() % 360; VectorScale(dir, 16, tmpVec); VectorAdd(tmpVec, origin, newOrigin); } else { ex->leType = LE_EXPLOSION; VectorCopy(origin, newOrigin); // set axis with random rotate if (!dir) { AxisClear(ex->refEntity.axis); } else { ang = rand() % 360; VectorCopy(dir, ex->refEntity.axis[0]); RotateAroundDirection(ex->refEntity.axis, ang); } } ex->startTime = cg.time - offset; ex->endTime = ex->startTime + msec; // bias the time so all shader effects start correctly ex->refEntity.shaderTime = ex->startTime / 1000.0f; ex->refEntity.hModel = hModel; ex->refEntity.customShader = shader; // set origin VectorCopy(newOrigin, ex->refEntity.origin); VectorCopy(newOrigin, ex->refEntity.oldorigin); // Ridah, move away from the wall as the sprite expands ex->pos.trType = TR_LINEAR; ex->pos.trTime = cg.time; VectorCopy(newOrigin, ex->pos.trBase); VectorScale(dir, 48, ex->pos.trDelta); // done. ex->color[0] = ex->color[1] = ex->color[2] = 1.0; return ex; }
/* ==================== CG_MakeExplosion ==================== */ localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir, qhandle_t hModel, int numFrames, qhandle_t shader, int msec, qboolean isSprite, float scale, int flags ) { float ang = 0; localEntity_t *ex; int offset; vec3_t tmpVec, newOrigin; if ( msec <= 0 ) { trap->Error( ERR_DROP, "CG_MakeExplosion: msec = %i", msec ); } // skew the time a bit so they aren't all in sync offset = rand() & 63; ex = CG_AllocLocalEntity(); if ( isSprite ) { ex->leType = LE_SPRITE_EXPLOSION; ex->refEntity.rotation = rand() % 360; ex->radius = scale; VectorScale( dir, 16, tmpVec ); VectorAdd( tmpVec, origin, newOrigin ); } else { ex->leType = LE_EXPLOSION; VectorCopy( origin, newOrigin ); // set axis with random rotate when necessary if ( !dir ) { AxisClear( ex->refEntity.axis ); } else { if ( !(flags & LEF_NO_RANDOM_ROTATE) ) ang = rand() % 360; VectorCopy( dir, ex->refEntity.axis[0] ); RotateAroundDirection( ex->refEntity.axis, ang ); } } ex->startTime = cg.time - offset; ex->endTime = ex->startTime + msec; // bias the time so all shader effects start correctly ex->refEntity.shaderTime = ex->startTime / 1000.0f; ex->refEntity.hModel = hModel; ex->refEntity.customShader = shader; ex->lifeRate = (float)numFrames / msec; ex->leFlags = flags; //Scale the explosion if (scale != 1) { ex->refEntity.nonNormalizedAxes = qtrue; VectorScale( ex->refEntity.axis[0], scale, ex->refEntity.axis[0] ); VectorScale( ex->refEntity.axis[1], scale, ex->refEntity.axis[1] ); VectorScale( ex->refEntity.axis[2], scale, ex->refEntity.axis[2] ); } // set origin VectorCopy ( newOrigin, ex->refEntity.origin); VectorCopy ( newOrigin, ex->refEntity.oldorigin ); ex->color[0] = ex->color[1] = ex->color[2] = 1.0; return ex; }
/* ================ CG_AddMissile ================ */ static void CG_AddMissile( localEntity_t *le ) { refEntity_t *re; const weaponInfo_t *weapon; trace_t trace; centity_t *other; qboolean inWater; // just existing for server entity deletion if ( le->leFlags & LEF_FINISHED ) { return; } // get weapon info if ( le->ti.weapon > WP_NUM_WEAPONS ) { le->ti.weapon = 0; } weapon = &cg_weapons[le->ti.weapon]; re = &le->refEntity; // calculate position BG_EvaluateTrajectory( &le->pos, cg.time, re->origin ); // special case for flames if ( re->reType == RT_SPRITE ) { int deltaTime; // check for water if ( trap_CM_PointContents( re->origin, 0 ) & CONTENTS_WATER ) { // do a trace to get water surface normals CG_Trace( &trace, re->oldorigin, NULL, NULL, re->origin, le->owner, MASK_WATER ); CG_FreeLocalEntity( le ); CG_MakeExplosion( trace.endpos, trace.plane.normal, cgs.media.ringFlashModel, cgs.media.vaporShader, 500, qfalse, qtrue ); return; } // change radius over time deltaTime = cg.time - le->startTime; re->radius = deltaTime * deltaTime * ( random()*0.4f + 0.8f ) / 2000.0f + 9; // do a trace sometimes if ( le->ti.trailTime++ > 5 ) { le->ti.trailTime = 0; CG_Trace( &trace, re->oldorigin, NULL, NULL, re->origin, le->owner, MASK_SHOT ); VectorCopy( re->origin, re->oldorigin ); // hit something if ( trace.fraction < 1.0 ) { CG_MissileHitWall( le->ti.weapon, 0, trace.endpos, trace.plane.normal, IMPACTSOUND_DEFAULT ); CG_FreeLocalEntity( le ); return; } } // add to refresh list trap_R_AddRefEntityToScene( re ); return; } // add trails if ( weapon->missileTrailFunc ) weapon->missileTrailFunc( &le->ti, cg.time ); // add dynamic light if ( weapon->missileDlight ) { trap_R_AddLightToScene( re->origin, weapon->missileDlight, weapon->missileDlightColor[0], weapon->missileDlightColor[1], weapon->missileDlightColor[2] ); } // flicker between two skins re->skinNum = cg.clientFrame & 1; // convert direction of travel into axis if ( VectorNormalize2( le->pos.trDelta, re->axis[0] ) == 0 ) { re->axis[0][2] = 1; } // spin as it moves if ( le->pos.trType != TR_STATIONARY ) { if ( le->pos.trType == TR_GRAVITY ) { RotateAroundDirection( re->axis, cg.time / 4 ); } else if ( le->pos.trType == TR_WATER_GRAVITY ) { RotateAroundDirection( re->axis, cg.time / 8 ); } else { RotateAroundDirection( re->axis, cg.time ); } } else { RotateAroundDirection( re->axis, 0 ); } // trace a line from previous position to new position CG_Trace( &trace, re->oldorigin, NULL, NULL, re->origin, le->owner, MASK_SHOT ); VectorCopy( re->origin, re->oldorigin ); // draw BIG grenades if ( weLi[le->ti.weapon].category == CT_EXPLOSIVE ) { AxisScale( re->axis, GRENADE_SCALE, re->axis ); } if ( trace.fraction != 1.0 ) { // hit the sky or something like that if ( trace.surfaceFlags & SURF_NOIMPACT ) { le->leFlags |= LEF_FINISHED; le->endTime = cg.time + 500; return; } // impact other = &cg_entities[trace.entityNum]; if ( le->bounceFactor > 0 && ( le->bounceFactor == BOUNCE_FACTOR_HALF || other->currentState.eType != ET_PLAYER ) ) { // reflect the velocity on the trace plane CG_ReflectVelocity( le, &trace ); if ( cg.predictedImpacts < MAX_PREDICTED_IMPACTS ) { cg.predictedImpacts++; cg.predictedImpactsDecTime = cg.time; } // do bounce sound if ( rand() & 1 ) { trap_S_StartSound( le->pos.trBase, 0, CHAN_AUTO, cgs.media.hgrenb1aSound ); } else { trap_S_StartSound( le->pos.trBase, 0, CHAN_AUTO, cgs.media.hgrenb2aSound ); } } else { // explode missile if ( cg.predictedImpacts < MAX_PREDICTED_IMPACTS ) { cg.predictedImpacts++; cg.predictedImpactsDecTime = cg.time; } if ( other->currentState.eType == ET_PLAYER ) { CG_MissileHitPlayer( le->ti.weapon, 0, trace.endpos, trace.plane.normal, trace.entityNum ); } else if ( !(trace.surfaceFlags & SURF_NOIMPACT) ) { CG_MissileHitWall( le->ti.weapon, 0, trace.endpos, trace.plane.normal, (trace.surfaceFlags & SURF_METALSTEPS) ? IMPACTSOUND_METAL : IMPACTSOUND_DEFAULT ); } // store the entity for deleting the server entity le->leFlags |= LEF_FINISHED; le->endTime = cg.time + 500; return; } } // check for medium change if ( trap_CM_PointContents( re->origin, 0 ) & CONTENTS_WATER ) inWater = qtrue; else inWater = qfalse; if ( ( !inWater && le->pos.trType == TR_WATER_GRAVITY ) || ( inWater && le->pos.trType == TR_GRAVITY ) ) { // setup new tr vec3_t newDelta; BG_EvaluateTrajectoryDelta( &le->pos, cg.time, newDelta ); VectorCopy( re->origin, le->pos.trBase ); VectorCopy( newDelta, le->pos.trDelta ); le->pos.trTime = cg.time; if ( inWater ) le->pos.trType = TR_WATER_GRAVITY; else le->pos.trType = TR_GRAVITY; } // add to refresh list trap_R_AddRefEntityToScene( re ); }
/* ==================== CG_MakeExplosion ==================== */ localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir, qhandle_t hModel, qhandle_t shader, int msec, float scale, qboolean isSprite ) { float ang; localEntity_t *ex; int offset; vec3_t tmpVec, newOrigin; if ( msec <= 0 ) { CG_Error( "CG_MakeExplosion: msec = %i", msec ); } // skew the time a bit so they aren't all in sync offset = rand() & 63; ex = CG_AllocLocalEntity(); if ( isSprite ) { ex->leType = LE_SPRITE_EXPLOSION; // randomly rotate sprite orientation ex->refEntity.data.sprite.rotation = rand() % 360; VectorScale( dir, 16, tmpVec ); VectorAdd( tmpVec, origin, newOrigin ); } else { ex->leType = LE_EXPLOSION; VectorCopy( origin, newOrigin ); // set axis with random rotate if ( !dir ) { AxisClear( ex->refEntity.axis ); } else { ang = rand() % 360; VectorCopy( dir, ex->refEntity.axis[0] ); RotateAroundDirection( ex->refEntity.axis, ang ); } } ex->startTime = cg.time - offset; ex->endTime = ex->startTime + msec; // bias the time so all shader effects start correctly ex->refEntity.shaderTime = ex->startTime * 0.001f; ex->refEntity.hModel = hModel; ex->refEntity.customShader = shader; // set origin VectorCopy( newOrigin, ex->refEntity.origin ); VectorCopy( newOrigin, ex->refEntity.oldorigin ); //Scale the explosion if (scale != 1) { ex->refEntity.nonNormalizedAxes = qtrue; VectorScale( ex->refEntity.axis[0], scale, ex->refEntity.axis[0] ); VectorScale( ex->refEntity.axis[1], scale, ex->refEntity.axis[1] ); VectorScale( ex->refEntity.axis[2], scale, ex->refEntity.axis[2] ); } ex->color[0] = ex->color[1] = ex->color[2] = 1.0; return ex; }