void CG_AddMarks() { int j; markPoly_t *mp, *next; int t; int fade; if ( !cg_addMarks.integer ) { return; } mp = cg_activeMarkPolys.nextMark; for ( ; mp != &cg_activeMarkPolys; mp = next ) { // grab next now, so if the local entity is freed we // still have it next = mp->nextMark; // see if it is time to completely remove it if ( cg.time > mp->time + MARK_TOTAL_TIME ) { CG_FreeMarkPoly( mp ); continue; } // fade all marks out with time t = mp->time + MARK_TOTAL_TIME - cg.time; if ( t < MARK_FADE_TIME ) { fade = 255 * t / MARK_FADE_TIME; if ( mp->alphaFade ) { for ( j = 0; j < mp->poly.numVerts; j++ ) { mp->verts[ j ].modulate[ 3 ] = fade; } } else { for ( j = 0; j < mp->poly.numVerts; j++ ) { mp->verts[ j ].modulate[ 0 ] = mp->color[ 0 ] * fade; mp->verts[ j ].modulate[ 1 ] = mp->color[ 1 ] * fade; mp->verts[ j ].modulate[ 2 ] = mp->color[ 2 ] * fade; } } } trap_R_AddPolyToScene( mp->markShader, mp->poly.numVerts, mp->verts ); } }
/* ======================================================================================================================================= CG_EmitPolyVerts ======================================================================================================================================= */ static void CG_EmitPolyVerts(const refEntity_t *re) { polyVert_t verts[4]; float sinR, cosR; float angle; vec3_t left, up; int i; if (re->rotation) { angle = M_PI * re->rotation / 180.0; sinR = sin(angle); cosR = cos(angle); VectorScale(cg.refdef.viewaxis[1], cosR * re->radius, left); VectorMA(left, -sinR * re->radius, cg.refdef.viewaxis[2], left); VectorScale(cg.refdef.viewaxis[2], cosR * re->radius, up); VectorMA(up, sinR * re->radius, cg.refdef.viewaxis[1], up); } else { VectorScale(cg.refdef.viewaxis[1], re->radius, left); VectorScale(cg.refdef.viewaxis[2], re->radius, up); } verts[0].xyz[0] = re->origin[0] + left[0] + up[0]; verts[0].xyz[1] = re->origin[1] + left[1] + up[1]; verts[0].xyz[2] = re->origin[2] + left[2] + up[2]; verts[0].st[0] = 0.0; verts[0].st[1] = 0.0; verts[1].xyz[0] = re->origin[0] - left[0] + up[0]; verts[1].xyz[1] = re->origin[1] - left[1] + up[1]; verts[1].xyz[2] = re->origin[2] - left[2] + up[2]; verts[1].st[0] = 1.0; verts[1].st[1] = 0.0; verts[2].xyz[0] = re->origin[0] - left[0] - up[0]; verts[2].xyz[1] = re->origin[1] - left[1] - up[1]; verts[2].xyz[2] = re->origin[2] - left[2] - up[2]; verts[2].st[0] = 1.0; verts[2].st[1] = 1.0; verts[3].xyz[0] = re->origin[0] + left[0] - up[0]; verts[3].xyz[1] = re->origin[1] + left[1] - up[1]; verts[3].xyz[2] = re->origin[2] + left[2] - up[2]; verts[3].st[0] = 0.0; verts[3].st[1] = 1.0; for (i = 0; i < 4; i++) { verts[i].modulate[0] = re->shaderRGBA[0]; verts[i].modulate[1] = re->shaderRGBA[1]; verts[i].modulate[2] = re->shaderRGBA[2]; verts[i].modulate[3] = re->shaderRGBA[3]; } trap_R_AddPolyToScene(re->customShader, 4, verts, 0, 0); }
/* =============== CG_AddMarks =============== */ void CG_AddMarks(void) { int j; markPoly_t *mp, *next; int t; int fade; if (!cg_markTime.integer) { return; } mp = cg_activeMarkPolys.nextMark; for ( ; mp != &cg_activeMarkPolys ; mp = next) { // grab next now, so if the local entity is freed we // still have it next = mp->nextMark; // see if it is time to completely remove it if (cg.time > mp->time + mp->duration) { CG_FreeMarkPoly(mp); continue; } // fade all marks out with time t = mp->time + mp->duration - cg.time; if (t < (float)mp->duration / 2.0) { fade = (int)(255.0 * (float)t / ((float)mp->duration / 2.0)); if (mp->alphaFade) { for (j = 0 ; j < mp->poly.numVerts ; j++) { mp->verts[j].modulate[3] = fade; } } else { for (j = 0 ; j < mp->poly.numVerts ; j++) { mp->verts[j].modulate[0] = mp->color[0] * fade; mp->verts[j].modulate[1] = mp->color[1] * fade; mp->verts[j].modulate[2] = mp->color[2] * fade; } } } trap_R_AddPolyToScene(mp->markShader, mp->poly.numVerts, mp->verts); } }
void CG_EffectMark(qhandle_t markShader, const vec3_t origin, const vec3_t dir, float alpha, float radius) { // 'quick' version of the CG_ImpactMark function vec3_t axis[3], originalPoints[4]; float texCoordScale; byte colors[4]; int i; polyVert_t *v, verts[4]; if (!cg_addMarks.integer) { return; } if (radius <= 0) { CG_Error("CG_EffectMark called with <= 0 radius"); } // create the texture axis VectorNormalize2(dir, axis[0]); PerpendicularVector(axis[1], axis[0]); VectorSet(axis[2], 1, 0, 0); // This is _wrong_, but the function is for water anyway (i.e. usually flat) CrossProduct(axis[0], axis[2], axis[1]); texCoordScale = 0.5 * 1.0 / radius; // create the full polygon for (i = 0; i < 3; i++) { originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i]; originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i]; originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i]; originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i]; } colors[0] = 127; colors[1] = 127; colors[2] = 127; colors[3] = alpha * 255; for (i = 0, v = verts; i < 4; i++, v++) { vec3_t delta; VectorCopy(originalPoints[i], v->xyz); VectorSubtract(v->xyz, origin, delta); v->st[0] = 0.5 + DotProduct(delta, axis[1]) * texCoordScale; v->st[1] = 0.5 + DotProduct(delta, axis[2]) * texCoordScale; *(int *) v->modulate = *(int *) colors; } trap_R_AddPolyToScene(markShader, 4, verts); }
/* * CG_AddDecals */ void CG_AddDecals( void ) { int i; float fade; cdecal_t *dl, *next, *hnode; poly_t *poly; byte_vec4_t color; // add decals in first-spawed - first-drawn order hnode = &cg_decals_headnode; for( dl = hnode->prev; dl != hnode; dl = next ) { next = dl->prev; // it's time to DIE if( dl->die <= cg.time ) { CG_FreeDecal( dl ); continue; } poly = dl->poly; // fade out if( dl->fadetime < cg.time ) { fade = ( dl->die - cg.time ) * dl->fadefreq; if( dl->fadealpha ) { color[0] = ( qbyte )( dl->color[0] ); color[1] = ( qbyte )( dl->color[1] ); color[2] = ( qbyte )( dl->color[2] ); color[3] = ( qbyte )( dl->color[3] * fade ); } else { color[0] = ( qbyte )( dl->color[0] * fade ); color[1] = ( qbyte )( dl->color[1] * fade ); color[2] = ( qbyte )( dl->color[2] * fade ); color[3] = ( qbyte )( dl->color[3] ); } for( i = 0; i < poly->numverts; i++ ) *( int * )poly->colors[i] = *( int * )color; } trap_R_AddPolyToScene( poly ); } }
/* * CG_Addpolys */ void CG_AddPolys( void ) { int i; float fade; cpoly_t *cgpoly, *next, *hnode; poly_t *poly; static vec3_t angles; // add polys in first-spawned - first-drawn order hnode = &cg_polys_headnode; for( cgpoly = hnode->prev; cgpoly != hnode; cgpoly = next ) { next = cgpoly->prev; // it's time to die if( cgpoly->die <= cg.time ) { CG_FreePoly( cgpoly ); continue; } poly = cgpoly->poly; for( i = 0; i < poly->numverts; i++ ) VectorCopy( cgpoly->verts[i], poly->verts[i] ); for( i = 0; i < 3; i++ ) angles[i] = anglemod( cgpoly->angles[i] ); CG_OrientPolygon( cgpoly->origin, angles, poly ); // fade out if( cgpoly->fadetime < cg.time ) { fade = ( cgpoly->die - cg.time ) * cgpoly->fadefreq; for( i = 0; i < poly->numverts; i++ ) { poly->colors[i][0] = ( uint8_t )( cgpoly->color[0] * fade * 255 ); poly->colors[i][1] = ( uint8_t )( cgpoly->color[1] * fade * 255 ); poly->colors[i][2] = ( uint8_t )( cgpoly->color[2] * fade * 255 ); poly->colors[i][3] = ( uint8_t )( cgpoly->color[3] * fade * 255 ); } } trap_R_AddPolyToScene( poly ); } }
/* =============== CG_DrawPlane Draw a quad in 3 space - basically CG_DrawPic in 3 space =============== */ void CG_DrawPlane( vec3_t origin, vec3_t down, vec3_t right, qhandle_t shader ) { polyVert_t verts[ 4 ]; vec3_t temp; VectorCopy( origin, verts[ 0 ].xyz ); verts[ 0 ].st[ 0 ] = 0; verts[ 0 ].st[ 1 ] = 0; verts[ 0 ].modulate[ 0 ] = 255; verts[ 0 ].modulate[ 1 ] = 255; verts[ 0 ].modulate[ 2 ] = 255; verts[ 0 ].modulate[ 3 ] = 255; VectorAdd( origin, right, temp ); VectorCopy( temp, verts[ 1 ].xyz ); verts[ 1 ].st[ 0 ] = 1; verts[ 1 ].st[ 1 ] = 0; verts[ 1 ].modulate[ 0 ] = 255; verts[ 1 ].modulate[ 1 ] = 255; verts[ 1 ].modulate[ 2 ] = 255; verts[ 1 ].modulate[ 3 ] = 255; VectorAdd( origin, right, temp ); VectorAdd( temp, down, temp ); VectorCopy( temp, verts[ 2 ].xyz ); verts[ 2 ].st[ 0 ] = 1; verts[ 2 ].st[ 1 ] = 1; verts[ 2 ].modulate[ 0 ] = 255; verts[ 2 ].modulate[ 1 ] = 255; verts[ 2 ].modulate[ 2 ] = 255; verts[ 2 ].modulate[ 3 ] = 255; VectorAdd( origin, down, temp ); VectorCopy( temp, verts[ 3 ].xyz ); verts[ 3 ].st[ 0 ] = 0; verts[ 3 ].st[ 1 ] = 1; verts[ 3 ].modulate[ 0 ] = 255; verts[ 3 ].modulate[ 1 ] = 255; verts[ 3 ].modulate[ 2 ] = 255; verts[ 3 ].modulate[ 3 ] = 255; trap_R_AddPolyToScene( shader, 4, verts ); }
/* =============== CG_DrawSurfNormal Draws a vector against the surface player is looking at =============== */ static void CG_DrawSurfNormal( void ) { trace_t tr; vec3_t end, temp; polyVert_t normal[ 4 ]; vec4_t color = { 0.0f, 255.0f, 0.0f, 128.0f }; VectorMA( cg.refdef.vieworg, 8192, cg.refdef.viewaxis[ 0 ], end ); CG_Trace( &tr, cg.refdef.vieworg, NULL, NULL, end, cg.predictedPlayerState.clientNum, MASK_SOLID, 0 ); VectorCopy( tr.endpos, normal[ 0 ].xyz ); normal[ 0 ].st[ 0 ] = 0; normal[ 0 ].st[ 1 ] = 0; Vector4Copy( color, normal[ 0 ].modulate ); VectorMA( tr.endpos, NORMAL_WIDTH, cg.refdef.viewaxis[ 1 ], temp ); VectorCopy( temp, normal[ 1 ].xyz ); normal[ 1 ].st[ 0 ] = 0; normal[ 1 ].st[ 1 ] = 1; Vector4Copy( color, normal[ 1 ].modulate ); VectorMA( tr.endpos, NORMAL_HEIGHT, tr.plane.normal, temp ); VectorMA( temp, NORMAL_WIDTH, cg.refdef.viewaxis[ 1 ], temp ); VectorCopy( temp, normal[ 2 ].xyz ); normal[ 2 ].st[ 0 ] = 1; normal[ 2 ].st[ 1 ] = 1; Vector4Copy( color, normal[ 2 ].modulate ); VectorMA( tr.endpos, NORMAL_HEIGHT, tr.plane.normal, temp ); VectorCopy( temp, normal[ 3 ].xyz ); normal[ 3 ].st[ 0 ] = 1; normal[ 3 ].st[ 1 ] = 0; Vector4Copy( color, normal[ 3 ].modulate ); trap_R_AddPolyToScene( cgs.media.outlineShader, 4, normal ); }
/* =================== CG_Aura_DrawSpike =================== Draws the polygons for one aura spike */ static void CG_Aura_DrawSpike (vec3_t start, vec3_t end, float width, qhandle_t shader, vec4_t RGBModulate){ vec3_t line, offset, viewLine; polyVert_t verts[4]; float len; int i, j; VectorSubtract (end, start, line); VectorSubtract (start, cg.refdef.vieworg, viewLine); CrossProduct (viewLine, line, offset); len = VectorNormalize (offset); if (!len){ return; } VectorMA (end, -width, offset, verts[0].xyz); verts[0].st[0] = 1; verts[0].st[1] = 0; VectorMA (end, width, offset, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 0; VectorMA (start, width, offset, verts[2].xyz); verts[2].st[0] = 0; verts[2].st[1] = 1; VectorMA (start, -width, offset, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 1; for (i = 0;i < 4;i++){ for (j = 0;j < 4;j++){ verts[i].modulate[j] = 255 * RGBModulate[j]; } } trap_R_AddPolyToScene( shader, 4, verts); }
/* * CG_AddFragmentedDecal */ void CG_AddFragmentedDecal( vec3_t origin, vec3_t dir, float orient, float radius, float r, float g, float b, float a, struct shader_s *shader ) { int i, j, c; vec3_t axis[3]; byte_vec4_t color; fragment_t *fr, fragments[MAX_TEMPDECAL_FRAGMENTS]; int numfragments; poly_t poly; vec4_t verts[MAX_BLOBSHADOW_VERTS]; static vec4_t t_verts[MAX_TEMPDECAL_VERTS * MAX_TEMPDECALS]; static vec4_t t_norms[MAX_TEMPDECAL_VERTS * MAX_TEMPDECALS]; static vec2_t t_stcoords[MAX_TEMPDECAL_VERTS * MAX_TEMPDECALS]; static byte_vec4_t t_colors[MAX_TEMPDECAL_VERTS * MAX_TEMPDECALS]; if( radius <= 0 || VectorCompare( dir, vec3_origin ) ) { return; // invalid } // calculate orientation matrix VectorNormalize2( dir, axis[0] ); PerpendicularVector( axis[1], axis[0] ); RotatePointAroundVector( axis[2], axis[0], axis[1], orient ); CrossProduct( axis[0], axis[2], axis[1] ); numfragments = trap_R_GetClippedFragments( origin, radius, axis, // clip it MAX_BLOBSHADOW_VERTS, verts, MAX_TEMPDECAL_FRAGMENTS, fragments ); // no valid fragments if( !numfragments ) { return; } // clamp and scale colors if( r < 0 ) { r = 0; } else if( r > 1 ) { r = 255; } else { r *= 255; } if( g < 0 ) { g = 0; } else if( g > 1 ) { g = 255; } else { g *= 255; } if( b < 0 ) { b = 0; } else if( b > 1 ) { b = 255; } else { b *= 255; } if( a < 0 ) { a = 0; } else if( a > 1 ) { a = 255; } else { a *= 255; } color[0] = ( uint8_t )( r ); color[1] = ( uint8_t )( g ); color[2] = ( uint8_t )( b ); color[3] = ( uint8_t )( a ); c = *( int * )color; radius = 0.5f / radius; VectorScale( axis[1], radius, axis[1] ); VectorScale( axis[2], radius, axis[2] ); memset( &poly, 0, sizeof( poly ) ); for( i = 0, fr = fragments; i < numfragments; i++, fr++ ) { if( fr->numverts <= 0 ) { continue; } if( cg_numDecalVerts + (unsigned)fr->numverts > sizeof( t_verts ) / sizeof( t_verts[0] ) ) { return; } poly.shader = shader; poly.verts = &t_verts[cg_numDecalVerts]; poly.normals = &t_norms[cg_numDecalVerts]; poly.stcoords = &t_stcoords[cg_numDecalVerts]; poly.colors = &t_colors[cg_numDecalVerts]; poly.numverts = fr->numverts; poly.fognum = fr->fognum; cg_numDecalVerts += (unsigned)fr->numverts; for( j = 0; j < fr->numverts; j++ ) { vec3_t v; Vector4Copy( verts[fr->firstvert + j], poly.verts[j] ); VectorCopy( axis[0], poly.normals[j] ); poly.normals[j][3] = 0; VectorSubtract( poly.verts[j], origin, v ); poly.stcoords[j][0] = DotProduct( v, axis[1] ) + 0.5f; poly.stcoords[j][1] = DotProduct( v, axis[2] ) + 0.5f; *( int * )poly.colors[j] = c; } trap_R_AddPolyToScene( &poly ); } }
/* * CG_AddParticles */ void CG_AddParticles( void ) { int i, j, k; float alpha; float time, time2; vec3_t org; vec3_t corner; byte_vec4_t color; int maxparticle, activeparticles; float alphaValues[MAX_PARTICLES]; cparticle_t *p, *free_particles[MAX_PARTICLES]; if( !cg_numparticles ) { return; } j = 0; maxparticle = -1; activeparticles = 0; for( i = 0, p = particles; i < cg_numparticles; i++, p++ ) { time = ( cg.time - p->time ) * 0.001f; alpha = alphaValues[i] = p->alpha + time * p->alphavel; if( alpha <= 0 ) { // faded out free_particles[j++] = p; continue; } maxparticle = i; activeparticles++; time2 = time * time * 0.5f; org[0] = p->org[0] + p->vel[0] * time + p->accel[0] * time2; org[1] = p->org[1] + p->vel[1] * time + p->accel[1] * time2; org[2] = p->org[2] + p->vel[2] * time + p->accel[2] * time2; color[0] = (uint8_t)( bound( 0, p->color[0], 1.0f ) * 255 ); color[1] = (uint8_t)( bound( 0, p->color[1], 1.0f ) * 255 ); color[2] = (uint8_t)( bound( 0, p->color[2], 1.0f ) * 255 ); color[3] = (uint8_t)( bound( 0, alpha, 1.0f ) * 255 ); corner[0] = org[0]; corner[1] = org[1] - 0.5f * p->scale; corner[2] = org[2] - 0.5f * p->scale; Vector4Set( p->pVerts[0], corner[0], corner[1] + p->scale, corner[2] + p->scale, 1 ); Vector4Set( p->pVerts[1], corner[0], corner[1], corner[2] + p->scale, 1 ); Vector4Set( p->pVerts[2], corner[0], corner[1], corner[2], 1 ); Vector4Set( p->pVerts[3], corner[0], corner[1] + p->scale, corner[2], 1 ); for( k = 0; k < 4; k++ ) { Vector4Copy( color, p->pColor[k] ); } p->poly.numverts = 4; p->poly.verts = p->pVerts; p->poly.stcoords = p->pStcoords; p->poly.colors = p->pColor; p->poly.fognum = p->fog ? 0 : -1; p->poly.shader = ( p->shader == NULL ) ? CG_MediaShader( cgs.media.shaderParticle ) : p->shader; trap_R_AddPolyToScene( &p->poly ); } i = 0; while( maxparticle >= activeparticles ) { *free_particles[i++] = particles[maxparticle--]; while( maxparticle >= activeparticles ) { if( alphaValues[maxparticle] <= 0 ) { maxparticle--; } else { break; } } } cg_numparticles = activeparticles; }
/* =============== CG_Tracer =============== */ void CG_Tracer( vec3_t source, vec3_t dest ) { vec3_t forward, right; polyVert_t verts[ 4 ]; vec3_t line; float len, begin, end; vec3_t start, finish; vec3_t midpoint; // tracer VectorSubtract( dest, source, forward ); len = VectorNormalize( forward ); // start at least a little ways from the muzzle if( len < 100 ) return; begin = 50 + random( ) * ( len - 60 ); end = begin + cg_tracerLength.value; if( end > len ) end = len; VectorMA( source, begin, forward, start ); VectorMA( source, end, forward, finish ); line[ 0 ] = DotProduct( forward, cg.refdef.viewaxis[ 1 ] ); line[ 1 ] = DotProduct( forward, cg.refdef.viewaxis[ 2 ] ); VectorScale( cg.refdef.viewaxis[ 1 ], line[ 1 ], right ); VectorMA( right, -line[ 0 ], cg.refdef.viewaxis[ 2 ], right ); VectorNormalize( right ); VectorMA( finish, cg_tracerWidth.value, right, verts[ 0 ].xyz ); verts[ 0 ].st[ 0 ] = 0; verts[ 0 ].st[ 1 ] = 1; verts[ 0 ].modulate[ 0 ] = 255; verts[ 0 ].modulate[ 1 ] = 255; verts[ 0 ].modulate[ 2 ] = 255; verts[ 0 ].modulate[ 3 ] = 255; VectorMA( finish, -cg_tracerWidth.value, right, verts[ 1 ].xyz ); verts[ 1 ].st[ 0 ] = 1; verts[ 1 ].st[ 1 ] = 0; verts[ 1 ].modulate[ 0 ] = 255; verts[ 1 ].modulate[ 1 ] = 255; verts[ 1 ].modulate[ 2 ] = 255; verts[ 1 ].modulate[ 3 ] = 255; VectorMA( start, -cg_tracerWidth.value, right, verts[ 2 ].xyz ); verts[ 2 ].st[ 0 ] = 1; verts[ 2 ].st[ 1 ] = 1; verts[ 2 ].modulate[ 0 ] = 255; verts[ 2 ].modulate[ 1 ] = 255; verts[ 2 ].modulate[ 2 ] = 255; verts[ 2 ].modulate[ 3 ] = 255; VectorMA( start, cg_tracerWidth.value, right, verts[ 3 ].xyz ); verts[ 3 ].st[ 0 ] = 0; verts[ 3 ].st[ 1 ] = 0; verts[ 3 ].modulate[ 0 ] = 255; verts[ 3 ].modulate[ 1 ] = 255; verts[ 3 ].modulate[ 2 ] = 255; verts[ 3 ].modulate[ 3 ] = 255; trap_R_AddPolyToScene( cgs.media.tracerShader, 4, verts ); midpoint[ 0 ] = ( start[ 0 ] + finish[ 0 ] ) * 0.5; midpoint[ 1 ] = ( start[ 1 ] + finish[ 1 ] ) * 0.5; midpoint[ 2 ] = ( start[ 2 ] + finish[ 2 ] ) * 0.5; // add the tracer sound trap_S_StartSound( midpoint, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.tracerSound ); }
void CG_VolumetricFog( vec3_t source, vec3_t dest ) { vec3_t forward, right; polyVert_t verts[4]; vec3_t line; float len, begin, end; vec3_t start, finish; float width = 2.0; vec4_t rgba; if ( fogshader < 0 ) { fogshader = trap_R_RegisterShader( "nsq3_sfx/volumetricfog" ); } rgba[0] = 1.0; rgba[1] = 1.0; rgba[2] = 1.0; rgba[3] = 1.0; VectorSubtract( dest, source, forward ); len = VectorNormalize( forward ); begin = 1; end = len; VectorMA( source, begin, forward, start ); VectorMA( source, end, forward, finish ); line[0] = DotProduct( forward, cg.refdef.viewaxis[1] ); line[1] = DotProduct( forward, cg.refdef.viewaxis[2] ); VectorScale( cg.refdef.viewaxis[1], line[1], right ); VectorMA( right, -line[0], cg.refdef.viewaxis[2], right ); VectorNormalize( right ); VectorMA( finish, width, right, verts[0].xyz ); verts[0].st[0] = 0; verts[0].st[1] = 1; verts[0].modulate[0] = 255 * rgba[0]; verts[0].modulate[1] = 255 * rgba[1]; verts[0].modulate[2] = 255 * rgba[2]; verts[0].modulate[3] = 255 * rgba[3]; VectorMA( finish, -width, right, verts[1].xyz ); verts[1].st[0] = 1; verts[1].st[1] = 1; verts[1].modulate[0] = 255 * rgba[0]; verts[1].modulate[1] = 255 * rgba[1]; verts[1].modulate[2] = 255 * rgba[2]; verts[1].modulate[3] = 255 * rgba[3]; VectorMA( start, -width, right, verts[2].xyz ); verts[2].st[0] = 1; verts[2].st[1] = 0; verts[2].modulate[0] = 255 * rgba[0]; verts[2].modulate[1] = 255 * rgba[1]; verts[2].modulate[2] = 255 * rgba[2]; verts[2].modulate[3] = 255 * rgba[3]; VectorMA( start, width, right, verts[3].xyz ); verts[3].st[0] = 0; verts[3].st[1] = 0; verts[3].modulate[0] = 255 * rgba[0]; verts[3].modulate[1] = 255 * rgba[1]; verts[3].modulate[2] = 255 * rgba[2]; verts[3].modulate[3] = 255 * rgba[3]; trap_R_AddPolyToScene( fogshader, 4, verts ); }
void CG_AddParticleToScene(cparticle_t *p, vec3_t org) { vec3_t point; polyVert_t verts[4]; float width; float height; float time, time2; float ratio; float invratio; vec3_t color; polyVert_t TRIverts[3]; vec3_t rright2, rup2; if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY || p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT) { // create a front facing polygon if (p->type != P_WEATHER_FLURRY) { if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT) { if (org[2] > p->end) { p->time = cg.time; VectorCopy(org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground p->org[2] = (p->start + crandom() * 4); if (p->type == P_BUBBLE_TURBULENT) { p->vel[0] = crandom() * 4; p->vel[1] = crandom() * 4; } } } else { if (org[2] < p->end) { p->time = cg.time; VectorCopy(org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground while (p->org[2] < p->end) { p->org[2] += (p->start - p->end); } if (p->type == P_WEATHER_TURBULENT) { p->vel[0] = crandom() * 16; p->vel[1] = crandom() * 16; } } } // Rafael snow pvs check if (!p->link) { return; } p->alpha = 1; } // Ridah, had to do this or MAX_POLYS is being exceeded in village1.bsp if (VectorDistanceSquared(cg.snap->ps.origin, org) > SQR(1024)) { return; } // done. if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT) { VectorMA(org, -p->height, vup, point); VectorMA(point, -p->width, vright, point); VectorCopy(point, verts[0].xyz); verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255; verts[0].modulate[1] = 255; verts[0].modulate[2] = 255; verts[0].modulate[3] = 255 * p->alpha; VectorMA(org, -p->height, vup, point); VectorMA(point, p->width, vright, point); VectorCopy(point, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255; verts[1].modulate[1] = 255; verts[1].modulate[2] = 255; verts[1].modulate[3] = 255 * p->alpha; VectorMA(org, p->height, vup, point); VectorMA(point, p->width, vright, point); VectorCopy(point, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255; verts[2].modulate[1] = 255; verts[2].modulate[2] = 255; verts[2].modulate[3] = 255 * p->alpha; VectorMA(org, p->height, vup, point); VectorMA(point, -p->width, vright, point); VectorCopy(point, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255; verts[3].modulate[1] = 255; verts[3].modulate[2] = 255; verts[3].modulate[3] = 255 * p->alpha; } else { VectorMA(org, -p->height, vup, point); VectorMA(point, -p->width, vright, point); VectorCopy(point, TRIverts[0].xyz); TRIverts[0].st[0] = 1; TRIverts[0].st[1] = 0; TRIverts[0].modulate[0] = 255; TRIverts[0].modulate[1] = 255; TRIverts[0].modulate[2] = 255; TRIverts[0].modulate[3] = 255 * p->alpha; VectorMA(org, p->height, vup, point); VectorMA(point, -p->width, vright, point); VectorCopy(point, TRIverts[1].xyz); TRIverts[1].st[0] = 0; TRIverts[1].st[1] = 0; TRIverts[1].modulate[0] = 255; TRIverts[1].modulate[1] = 255; TRIverts[1].modulate[2] = 255; TRIverts[1].modulate[3] = 255 * p->alpha; VectorMA(org, p->height, vup, point); VectorMA(point, p->width, vright, point); VectorCopy(point, TRIverts[2].xyz); TRIverts[2].st[0] = 0; TRIverts[2].st[1] = 1; TRIverts[2].modulate[0] = 255; TRIverts[2].modulate[1] = 255; TRIverts[2].modulate[2] = 255; TRIverts[2].modulate[3] = 255 * p->alpha; } } else if (p->type == P_SPRITE) { vec3_t rr, ru; vec3_t rotate_ang; VectorSet(color, 1.0, 1.0, 1.0); time = cg.time - p->time; time2 = p->endtime - p->time; ratio = time / time2; width = p->width + (ratio * (p->endwidth - p->width)); height = p->height + (ratio * (p->endheight - p->height)); if (p->roll) { vectoangles(cg.refdef_current->viewaxis[0], rotate_ang); rotate_ang[ROLL] += p->roll; AngleVectors(rotate_ang, NULL, rr, ru); } if (p->roll) { VectorMA(org, -height, ru, point); VectorMA(point, -width, rr, point); } else { VectorMA(org, -height, vup, point); VectorMA(point, -width, vright, point); } VectorCopy(point, verts[0].xyz); verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255; verts[0].modulate[1] = 255; verts[0].modulate[2] = 255; verts[0].modulate[3] = 255; if (p->roll) { VectorMA(point, 2 * height, ru, point); } else { VectorMA(point, 2 * height, vup, point); } VectorCopy(point, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255; verts[1].modulate[1] = 255; verts[1].modulate[2] = 255; verts[1].modulate[3] = 255; if (p->roll) { VectorMA(point, 2 * width, rr, point); } else { VectorMA(point, 2 * width, vright, point); } VectorCopy(point, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255; verts[2].modulate[1] = 255; verts[2].modulate[2] = 255; verts[2].modulate[3] = 255; if (p->roll) { VectorMA(point, -2 * height, ru, point); } else { VectorMA(point, -2 * height, vup, point); } VectorCopy(point, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255; verts[3].modulate[1] = 255; verts[3].modulate[2] = 255; verts[3].modulate[3] = 255; } else if (p->type == P_SMOKE || p->type == P_SMOKE_IMPACT) { // create a front rotating facing polygon if (p->type == P_SMOKE_IMPACT && VectorDistanceSquared(cg.snap->ps.origin, org) > SQR(1024)) { return; } if (p->color == MUSTARD) { VectorSet(color, 0.42, 0.33, 0.19); } else if (p->color == BLOODRED) { VectorSet(color, 0.22, 0, 0); } else if (p->color == ZOMBIE) { VectorSet(color, 0.4, 0.28, 0.23); } else if (p->color == GREY75) { float len; float greyit; float val; len = Distance(cg.snap->ps.origin, org); if (!len) { len = 1; } val = 4096 / len; greyit = 0.25 * val; if (greyit > 0.5) { greyit = 0.5; } VectorSet(color, greyit, greyit, greyit); } else { VectorSet(color, 1.0, 1.0, 1.0); } time = cg.time - p->time; time2 = p->endtime - p->time; ratio = time / time2; if (cg.time > p->startfade) { invratio = 1 - ((cg.time - p->startfade) / (p->endtime - p->startfade)); if (p->color == EMISIVEFADE) { float fval; fval = (invratio * invratio); if (fval < 0) { fval = 0; } VectorSet(color, fval, fval, fval); } invratio *= p->alpha; } else { invratio = 1 * p->alpha; } if (cgs.glconfig.hardwareType == GLHW_RAGEPRO) { invratio = 1; } if (invratio > 1) { invratio = 1; } width = p->width + (ratio * (p->endwidth - p->width)); height = p->height + (ratio * (p->endheight - p->height)); { vec3_t temp; vectoangles(rforward, temp); p->accumroll += p->roll; temp[ROLL] += p->accumroll * 0.1; AngleVectors(temp, NULL, rright2, rup2); } if (p->rotate) { VectorMA(org, -height, rup2, point); VectorMA(point, -width, rright2, point); } else { VectorMA(org, -p->height, vup, point); VectorMA(point, -p->width, vright, point); } VectorCopy(point, verts[0].xyz); verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255 * color[0]; verts[0].modulate[1] = 255 * color[1]; verts[0].modulate[2] = 255 * color[2]; verts[0].modulate[3] = 255 * invratio; if (p->rotate) { VectorMA(org, -height, rup2, point); VectorMA(point, width, rright2, point); } else { VectorMA(org, -p->height, vup, point); VectorMA(point, p->width, vright, point); } VectorCopy(point, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255 * color[0]; verts[1].modulate[1] = 255 * color[1]; verts[1].modulate[2] = 255 * color[2]; verts[1].modulate[3] = 255 * invratio; if (p->rotate) { VectorMA(org, height, rup2, point); VectorMA(point, width, rright2, point); } else { VectorMA(org, p->height, vup, point); VectorMA(point, p->width, vright, point); } VectorCopy(point, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255 * color[0]; verts[2].modulate[1] = 255 * color[1]; verts[2].modulate[2] = 255 * color[2]; verts[2].modulate[3] = 255 * invratio; if (p->rotate) { VectorMA(org, height, rup2, point); VectorMA(point, -width, rright2, point); } else { VectorMA(org, p->height, vup, point); VectorMA(point, -p->width, vright, point); } VectorCopy(point, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255 * color[0]; verts[3].modulate[1] = 255 * color[1]; verts[3].modulate[2] = 255 * color[2]; verts[3].modulate[3] = 255 * invratio; } else if (p->type == P_FLAT_SCALEUP) { float width, height; float sinR, cosR; if (p->color == BLOODRED) { VectorSet(color, 1, 1, 1); } else { VectorSet(color, 0.5, 0.5, 0.5); } time = cg.time - p->time; time2 = p->endtime - p->time; ratio = time / time2; width = p->width + (ratio * (p->endwidth - p->width)); height = p->height + (ratio * (p->endheight - p->height)); if (width > p->endwidth) { width = p->endwidth; } if (height > p->endheight) { height = p->endheight; } sinR = height * sin(DEG2RAD(p->roll)) * ROOT_2; cosR = width * cos(DEG2RAD(p->roll)) * ROOT_2; VectorCopy(org, verts[0].xyz); verts[0].xyz[0] -= sinR; verts[0].xyz[1] -= cosR; verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255 * color[0]; verts[0].modulate[1] = 255 * color[1]; verts[0].modulate[2] = 255 * color[2]; verts[0].modulate[3] = 255; VectorCopy(org, verts[1].xyz); verts[1].xyz[0] -= cosR; verts[1].xyz[1] += sinR; verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = verts[0].modulate[0]; verts[1].modulate[1] = verts[0].modulate[1]; verts[1].modulate[2] = verts[0].modulate[2]; verts[1].modulate[3] = verts[0].modulate[3]; VectorCopy(org, verts[2].xyz); verts[2].xyz[0] += sinR; verts[2].xyz[1] += cosR; verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = verts[0].modulate[0]; verts[2].modulate[1] = verts[0].modulate[1]; verts[2].modulate[2] = verts[0].modulate[2]; verts[2].modulate[3] = verts[0].modulate[3]; VectorCopy(org, verts[3].xyz); verts[3].xyz[0] += cosR; verts[3].xyz[1] -= sinR; verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = verts[0].modulate[0]; verts[3].modulate[1] = verts[0].modulate[1]; verts[3].modulate[2] = verts[0].modulate[2]; verts[3].modulate[3] = verts[0].modulate[3]; } else if (p->type == P_FLAT) { VectorCopy(org, verts[0].xyz); verts[0].xyz[0] -= p->height; verts[0].xyz[1] -= p->width; verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255; verts[0].modulate[1] = 255; verts[0].modulate[2] = 255; verts[0].modulate[3] = 255; VectorCopy(org, verts[1].xyz); verts[1].xyz[0] -= p->height; verts[1].xyz[1] += p->width; verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255; verts[1].modulate[1] = 255; verts[1].modulate[2] = 255; verts[1].modulate[3] = 255; VectorCopy(org, verts[2].xyz); verts[2].xyz[0] += p->height; verts[2].xyz[1] += p->width; verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255; verts[2].modulate[1] = 255; verts[2].modulate[2] = 255; verts[2].modulate[3] = 255; VectorCopy(org, verts[3].xyz); verts[3].xyz[0] += p->height; verts[3].xyz[1] -= p->width; verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255; verts[3].modulate[1] = 255; verts[3].modulate[2] = 255; verts[3].modulate[3] = 255; } // Ridah else if (p->type == P_ANIM || p->type == P_DLIGHT_ANIM) { // ydnar vec3_t rr, ru; vec3_t rotate_ang; int i, j; time = cg.time - p->time; time2 = p->endtime - p->time; ratio = time / time2; if (ratio >= 1.0) { ratio = 0.9999; } else if (ratio < 0.0) { // rain - make sure that ratio isn't negative or // we'll walk out of bounds when j is calculated below ratio = 0.0001; } width = p->width + (ratio * (p->endwidth - p->width)); height = p->height + (ratio * (p->endheight - p->height)); // ydnar: add dlight if necessary if (p->type == P_DLIGHT_ANIM) { // fixme: support arbitrary color trap_R_AddLightToScene(org, 320, //% 1.5 * (width > height ? width : height), 1.25 * (1.0 - ratio), 1.0, 0.95, 0.85, 0, 0); } // if we are "inside" this sprite, don't draw if (VectorDistanceSquared(cg.snap->ps.origin, org) < SQR(width / 1.5f)) { return; } i = p->shaderAnim; j = (int)floor(ratio * shaderAnimCounts[p->shaderAnim]); p->pshader = shaderAnims[i][j]; // JPW NERVE more particle testing if (cg_fxflags & 1) { p->roll = 0; p->pshader = getTestShader(); rotate_ang[ROLL] = 90; } // jpw if (p->roll) { vectoangles(cg.refdef_current->viewaxis[0], rotate_ang); rotate_ang[ROLL] += p->roll; AngleVectors(rotate_ang, NULL, rr, ru); } if (p->roll) { VectorMA(org, -height, ru, point); VectorMA(point, -width, rr, point); } else { VectorMA(org, -height, vup, point); VectorMA(point, -width, vright, point); } VectorCopy(point, verts[0].xyz); verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255; verts[0].modulate[1] = 255; verts[0].modulate[2] = 255; verts[0].modulate[3] = 255; if (p->roll) { VectorMA(point, 2 * height, ru, point); } else { VectorMA(point, 2 * height, vup, point); } VectorCopy(point, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255; verts[1].modulate[1] = 255; verts[1].modulate[2] = 255; verts[1].modulate[3] = 255; if (p->roll) { VectorMA(point, 2 * width, rr, point); } else { VectorMA(point, 2 * width, vright, point); } VectorCopy(point, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255; verts[2].modulate[1] = 255; verts[2].modulate[2] = 255; verts[2].modulate[3] = 255; if (p->roll) { VectorMA(point, -2 * height, ru, point); } else { VectorMA(point, -2 * height, vup, point); } VectorCopy(point, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255; verts[3].modulate[1] = 255; verts[3].modulate[2] = 255; verts[3].modulate[3] = 255; } // done. if (!cg_wolfparticles.integer) { return; } if (!p->pshader) { return; } if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY) { trap_R_AddPolyToScene(p->pshader, 3, TRIverts); } else { trap_R_AddPolyToScene(p->pshader, 4, verts); } }
void CGSyscall_R_AddPolysToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int num ) { trap_R_AddPolyToScene( hShader, numVerts, verts ); }
void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir, float orientation, float red, float green, float blue, float alpha, qboolean alphaFade, float radius, qboolean temporary ) #endif { vec3_t axis[3]; float texCoordScale; vec3_t originalPoints[4]; byte colors[4]; int i, j; int numFragments; markFragment_t markFragments[MAX_MARK_FRAGMENTS], *mf; vec3_t markPoints[MAX_MARK_POINTS]; vec3_t projection; #ifdef TA_WEAPSYS qboolean addedMark = qfalse; #endif if ( !cg_addMarks.integer ) { #ifdef TA_WEAPSYS return qfalse; #else return; #endif } if ( radius <= 0 ) { CG_Error( "CG_ImpactMark called with <= 0 radius" ); } #ifndef IOQ3ZTM //if ( markTotal >= MAX_MARK_POLYS ) { // return; //} #endif // create the texture axis VectorNormalize2( dir, axis[0] ); PerpendicularVector( axis[1], axis[0] ); RotatePointAroundVector( axis[2], axis[0], axis[1], orientation ); CrossProduct( axis[0], axis[2], axis[1] ); texCoordScale = 0.5 * 1.0 / radius; // create the full polygon for ( i = 0 ; i < 3 ; i++ ) { originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i]; originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i]; originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i]; originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i]; } // get the fragments VectorScale( dir, -20, projection ); numFragments = trap_CM_MarkFragments( 4, (void *)originalPoints, projection, MAX_MARK_POINTS, markPoints[0], MAX_MARK_FRAGMENTS, markFragments ); colors[0] = red * 255; colors[1] = green * 255; colors[2] = blue * 255; colors[3] = alpha * 255; for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) { polyVert_t *v; polyVert_t verts[MAX_VERTS_ON_POLY]; markPoly_t *mark; vec3_t delta; vec3_t localOrigin; // create the texture axis VectorNormalize2( mf->projectionDir, axis[0] ); VectorScale( axis[0], -1, axis[0] ); // ZTM: the dir was scaled to -20 before giving to renderer, turn it back around. :S PerpendicularVector( axis[1], axis[0] ); RotatePointAroundVector( axis[2], axis[0], axis[1], orientation ); CrossProduct( axis[0], axis[2], axis[1] ); if ( mf->bmodelNum ) { // ZTM: TODO?: compensate for scale in the axes if necessary? see R_RotateForEntity // ZTM: FIXME: cgame should be able to get origin and axis from entity ! VectorSubtract( origin, mf->bmodelOrigin, delta ); localOrigin[0] = DotProduct( delta, mf->bmodelAxis[0] ); localOrigin[1] = DotProduct( delta, mf->bmodelAxis[1] ); localOrigin[2] = DotProduct( delta, mf->bmodelAxis[2] ); } else { VectorCopy( origin, localOrigin ); } // we have an upper limit on the complexity of polygons // that we store persistantly if ( mf->numPoints > MAX_VERTS_ON_POLY ) { mf->numPoints = MAX_VERTS_ON_POLY; } for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) { VectorCopy( markPoints[mf->firstPoint + j], v->xyz ); VectorSubtract( v->xyz, localOrigin, delta ); v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale; v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale; *(int *)v->modulate = *(int *)colors; } // if it is a temporary (shadow) mark, add it immediately and forget about it if ( temporary ) { trap_R_AddPolyToScene( markShader, mf->numPoints, verts, mf->bmodelNum, 0 ); continue; } // otherwise save it persistantly mark = CG_AllocMark(); mark->bmodelNum = mf->bmodelNum; mark->time = cg.time; mark->alphaFade = alphaFade; mark->markShader = markShader; mark->numVerts = mf->numPoints; mark->color[0] = red; mark->color[1] = green; mark->color[2] = blue; mark->color[3] = alpha; memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) ); #ifndef IOQ3ZTM markTotal++; #endif #ifdef TA_WEAPSYS addedMark = qtrue; #endif } #ifdef TA_WEAPSYS return addedMark; #endif }
static void CG_RainParticleRender(cg_atmosphericParticle_t * particle) { // Draw a raindrop vec3_t forward, right; polyVert_t verts[4]; vec2_t line; float len, frac; vec3_t start, finish; if (!particle->active) return; VectorCopy(particle->pos, start); len = particle->height; if (start[2] <= particle->minz) { // Stop rain going through surfaces. len = particle->height - particle->minz + start[2]; frac = start[2]; VectorMA(start, len - particle->height, particle->deltaNormalized, start); if (!cg_lowEffects.integer) { frac = (ATMOSPHERIC_CUTHEIGHT - particle->minz + frac) / (float) ATMOSPHERIC_CUTHEIGHT; // Splash effects on different surfaces if (particle->contents & (CONTENTS_WATER | CONTENTS_SLIME)) { // Water splash if (cg_atmFx.effectwatershader && frac > 0 && frac < 1) CG_EffectMark(cg_atmFx.effectwatershader, start, particle->surfacenormal, frac * 0.5, 8 - frac * 8); } else if (!(particle->contents & CONTENTS_LAVA) && !(particle-> surface & (SURF_NODAMAGE | SURF_NOIMPACT | SURF_NOMARKS | SURF_SKY))) { // Solid splash if (cg_atmFx.effectlandshader && frac > 0 && frac < 1) CG_ImpactMark(cg_atmFx.effectlandshader, start, particle->surfacenormal, 0, 1, 1, 1, frac * 0.5, qfalse, 3 - frac * 2, qtrue); } } } if (len <= 0) return; VectorCopy(particle->deltaNormalized, forward); VectorMA(start, -len, forward, finish); line[0] = DotProduct(forward, cg.refdef.viewaxis[1]); line[1] = DotProduct(forward, cg.refdef.viewaxis[2]); VectorScale(cg.refdef.viewaxis[1], line[1], right); VectorMA(right, -line[0], cg.refdef.viewaxis[2], right); VectorNormalize(right); VectorMA(finish, particle->weight, right, verts[0].xyz); verts[0].st[0] = 1; verts[0].st[1] = 0; verts[0].modulate[0] = 255; verts[0].modulate[1] = 255; verts[0].modulate[2] = 255; verts[0].modulate[3] = 0; VectorMA(finish, -particle->weight, right, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 0; verts[1].modulate[0] = 255; verts[1].modulate[1] = 255; verts[1].modulate[2] = 255; verts[1].modulate[3] = 0; VectorMA(start, -particle->weight, right, verts[2].xyz); verts[2].st[0] = 0; verts[2].st[1] = 1; verts[2].modulate[0] = 255; verts[2].modulate[1] = 255; verts[2].modulate[2] = 255; verts[2].modulate[3] = 127; VectorMA(start, particle->weight, right, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 1; verts[3].modulate[0] = 255; verts[3].modulate[1] = 255; verts[3].modulate[2] = 255; verts[3].modulate[3] = 127; trap_R_AddPolyToScene(*particle->effectshader, 4, verts); }
/* * CG_AddBlobShadow * * Ok, to not use decals space we need these arrays to store the * polygons info. We do not need the linked list nor registration */ static void CG_AddBlobShadow( vec3_t origin, vec3_t dir, float orient, float radius, float r, float g, float b, float a, cgshadebox_t *shadeBox ) { int i, j, c, nverts; vec3_t axis[3]; byte_vec4_t color; fragment_t *fr, fragments[MAX_BLOBSHADOW_FRAGMENTS]; int numfragments; poly_t poly; vec4_t verts[MAX_BLOBSHADOW_VERTS]; if( radius <= 0 || VectorCompare( dir, vec3_origin ) ) return; // invalid // calculate orientation matrix VectorNormalize2( dir, axis[0] ); PerpendicularVector( axis[1], axis[0] ); RotatePointAroundVector( axis[2], axis[0], axis[1], orient ); CrossProduct( axis[0], axis[2], axis[1] ); numfragments = trap_R_GetClippedFragments( origin, radius, axis, // clip it MAX_BLOBSHADOW_VERTS, verts, MAX_BLOBSHADOW_FRAGMENTS, fragments ); // no valid fragments if( !numfragments ) return; // clamp and scale colors if( r < 0 ) r = 0;else if( r > 1 ) r = 255;else r *= 255; if( g < 0 ) g = 0;else if( g > 1 ) g = 255;else g *= 255; if( b < 0 ) b = 0;else if( b > 1 ) b = 255;else b *= 255; if( a < 0 ) a = 0;else if( a > 1 ) a = 255;else a *= 255; color[0] = ( qbyte )( r ); color[1] = ( qbyte )( g ); color[2] = ( qbyte )( b ); color[3] = ( qbyte )( a ); c = *( int * )color; radius = 0.5f / radius; VectorScale( axis[1], radius, axis[1] ); VectorScale( axis[2], radius, axis[2] ); memset( &poly, 0, sizeof( poly ) ); for( i = 0, nverts = 0, fr = fragments; i < numfragments; i++, fr++ ) { if( nverts+fr->numverts > MAX_BLOBSHADOW_VERTS ) return; if( fr->numverts <= 0 ) continue; poly.shader = shadeBox->shader; poly.verts = &shadeBox->verts[nverts]; poly.normals = &shadeBox->norms[nverts]; poly.stcoords = &shadeBox->stcoords[nverts]; poly.colors = &shadeBox->colors[nverts]; poly.numverts = fr->numverts; poly.fognum = fr->fognum; nverts += fr->numverts; for( j = 0; j < fr->numverts; j++ ) { vec3_t v; Vector4Copy( verts[fr->firstvert+j], poly.verts[j] ); VectorCopy( axis[0], poly.normals[j] ); poly.normals[j][3] = 0; VectorSubtract( poly.verts[j], origin, v ); poly.stcoords[j][0] = DotProduct( v, axis[1] ) + 0.5f; poly.stcoords[j][1] = DotProduct( v, axis[2] ) + 0.5f; *( int * )poly.colors[j] = c; } trap_R_AddPolyToScene( &poly ); } }
void CG_AddMarks( void ) { int j; markPoly_t *mp, *next; int t; int fade; if ( !cg_addMarks.integer ) { return; } mp = cg_activeMarkPolys.nextMark; for ( ; mp != &cg_activeMarkPolys ; mp = next ) { // grab next now, so if the local entity is freed we // still have it next = mp->nextMark; if(mp->markShader == cgs.media.SchaumShader) { if(cg.time> mp->time + 10000 ) { CG_FreeMarkPoly( mp ); continue; } if((fade=cg.time-mp->time-8000)>=0) { fade=1.0f-(fade/2000.0f); if ( mp->verts[0].modulate[0] != 0 ) { for ( j = 0 ; j < mp->poly.numVerts ; j++ ) { mp->verts[j].modulate[0] = mp->color[0] * fade; mp->verts[j].modulate[1] = mp->color[1] * fade; mp->verts[j].modulate[2] = mp->color[2] * fade; } } } trap_R_AddPolyToScene( mp->markShader, mp->poly.numVerts, mp->verts ); continue; } // see if it is time to completely remove it if ( cg.time > mp->time + MARK_TOTAL_TIME ) { CG_FreeMarkPoly( mp ); continue; } // fade out the energy bursts if ( mp->markShader == cgs.media.energyMarkShader ) { fade = 450 - 450 * ( (cg.time - mp->time ) / 3000.0 ); if ( fade < 255 ) { if ( fade < 0 ) { fade = 0; } if ( mp->verts[0].modulate[0] != 0 ) { for ( j = 0 ; j < mp->poly.numVerts ; j++ ) { mp->verts[j].modulate[0] = mp->color[0] * fade; mp->verts[j].modulate[1] = mp->color[1] * fade; mp->verts[j].modulate[2] = mp->color[2] * fade; } } } } // fade all marks out with time t = mp->time + MARK_TOTAL_TIME - cg.time; if ( t < MARK_FADE_TIME ) { fade = 255 * t / MARK_FADE_TIME; if ( mp->alphaFade ) { for ( j = 0 ; j < mp->poly.numVerts ; j++ ) { mp->verts[j].modulate[3] = fade; } } else { for ( j = 0 ; j < mp->poly.numVerts ; j++ ) { mp->verts[j].modulate[0] = mp->color[0] * fade; mp->verts[j].modulate[1] = mp->color[1] * fade; mp->verts[j].modulate[2] = mp->color[2] * fade; } } } trap_R_AddPolyToScene( mp->markShader, mp->poly.numVerts, mp->verts ); } }
void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir, float orientation, float red, float green, float blue, float alpha, qboolean alphaFade, float radius, qboolean temporary ) { vec3_t axis[3]; float texCoordScale; vec3_t originalPoints[4]; byte colors[4]; int i, j; int numFragments; markFragment_t markFragments[MAX_MARK_FRAGMENTS], *mf; vec3_t markPoints[MAX_MARK_POINTS]; vec3_t projection; markPoly_t *mp, *next; vec3_t delta; if ( !cg_addMarks.integer ) { return; } if ( radius <= 0 ) { CG_Error( "CG_ImpactMark called with <= 0 radius" ); } //if ( markTotal >= MAX_MARK_POLYS ) { // return; //} // HERBY: Bubble G overdraw fix mp = cg_activeMarkPolys.nextMark; for ( ; mp != &cg_activeMarkPolys; mp = next ) { next = mp->nextMark; if(temporary) break; // keep all marks if the new one is just the shadow if(mp->markShader == cgs.media.SchaumShader) continue;//die slick-ents einfach übergehen VectorSubtract( mp->origin, origin, delta ); if ( radius <= mp->radius + 4 && VectorLength( delta ) < ( radius + mp->radius ) * MIN_MARK_DISTANCE ) { CG_FreeMarkPoly( mp ); } } // create the texture axis VectorNormalize2( dir, axis[0] ); PerpendicularVector( axis[1], axis[0] ); RotatePointAroundVector( axis[2], axis[0], axis[1], orientation ); CrossProduct( axis[0], axis[2], axis[1] ); texCoordScale = 0.5 * 1.0 / radius; // create the full polygon for ( i = 0 ; i < 3 ; ++i ) { originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i]; originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i]; originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i]; originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i]; } // get the fragments VectorScale( dir, -20, projection ); numFragments = trap_CM_MarkFragments( 4, (void *)originalPoints, projection, MAX_MARK_POINTS, markPoints[0], MAX_MARK_FRAGMENTS, markFragments ); if(!numFragments && markShader == cgs.media.SchaumShader) { numFragments = 1; markFragments->firstPoint = 0; markFragments->numPoints = 4; for(i=0;i<4;++i) VectorCopy(originalPoints[i],markPoints[i]); } colors[0] = red * 255; colors[1] = green * 255; colors[2] = blue * 255; colors[3] = alpha * 255; for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) { polyVert_t *v; polyVert_t verts[MAX_VERTS_ON_POLY]; markPoly_t *mark; // we have an upper limit on the complexity of polygons // that we store persistantly if ( mf->numPoints > MAX_VERTS_ON_POLY ) { mf->numPoints = MAX_VERTS_ON_POLY; } for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) { vec3_t delta; VectorCopy( markPoints[mf->firstPoint + j], v->xyz ); VectorSubtract( v->xyz, origin, delta ); v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale; v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale; *(int *)v->modulate = *(int *)colors; } // if it is a temporary (shadow) mark, add it immediately and forget about it if ( temporary ) { trap_R_AddPolyToScene( markShader, mf->numPoints, verts ); continue; } // otherwise save it persistantly mark = CG_AllocMark(); mark->time = cg.time; mark->alphaFade = alphaFade; mark->markShader = markShader; mark->poly.numVerts = mf->numPoints; mark->color[0] = red; mark->color[1] = green; mark->color[2] = blue; mark->color[3] = alpha; mark->radius = radius; VectorCopy( origin, mark->origin ); memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) ); markTotal++; } }
void CG_AddMarks( void ) { int j; markPoly_t *mp, *next; int t; int fade; if ( !cg_addMarks.integer ) { return; } mp = cg_activeMarkPolys.nextMark; for ( ; mp != &cg_activeMarkPolys ; mp = next ) { // grab next now, so if the local entity is freed we // still have it next = mp->nextMark; // see if it is time to completely remove it if ( cg.time > mp->time + MARK_TOTAL_TIME ) { CG_FreeMarkPoly( mp ); continue; } // fade out the energy bursts #ifdef IOQ3ZTM // IOQ3BUGFIX: Use alphaFade instead of shader num (As only energyMark used alphaFade) if ( mp->alphaFade ) #else if ( mp->markShader == cgs.media.energyMarkShader ) #endif { fade = 450 - 450 * ( (cg.time - mp->time ) / 3000.0 ); if ( fade < 255 ) { if ( fade < 0 ) { fade = 0; } if ( mp->verts[0].modulate[0] != 0 ) { for ( j = 0 ; j < mp->numVerts ; j++ ) { mp->verts[j].modulate[0] = mp->color[0] * fade; mp->verts[j].modulate[1] = mp->color[1] * fade; mp->verts[j].modulate[2] = mp->color[2] * fade; } } } } // fade all marks out with time t = mp->time + MARK_TOTAL_TIME - cg.time; if ( t < MARK_FADE_TIME ) { fade = 255 * t / MARK_FADE_TIME; if ( mp->alphaFade ) { for ( j = 0 ; j < mp->numVerts ; j++ ) { mp->verts[j].modulate[3] = fade; } } else { for ( j = 0 ; j < mp->numVerts ; j++ ) { mp->verts[j].modulate[0] = mp->color[0] * fade; mp->verts[j].modulate[1] = mp->color[1] * fade; mp->verts[j].modulate[2] = mp->color[2] * fade; } } } trap_R_AddPolyToScene( mp->markShader, mp->numVerts, mp->verts, mp->bmodelNum, 0 ); } }
void CG_AddMarks( void ) { int j, k; markPoly_t *mp, *next; int t; int fade; if ( !cg_addMarks.integer ) { return; } mp = cg_activeMarkPolys.nextMark; for ( ; mp != &cg_activeMarkPolys ; mp = next ) { // grab next now, so if the local entity is freed we // still have it next = mp->nextMark; // see if it is time to completely remove it if ( cg.time > mp->time + MARK_TOTAL_TIME ) { CG_FreeMarkPoly( mp ); continue; } // fade out the energy bursts -- eh... don't /* if ( mp->markShader == cgs.media.energyMarkShader ) { fade = 450 - 450 * ( (cg.time - mp->time ) / 3000.0 ); if ( fade < 255 ) { if ( fade < 0 ) { fade = 0; } if ( mp->verts[0].modulate[0] != 0 ) { for ( j = 0 ; j < mp->poly.numVerts ; j++ ) { mp->verts[j].modulate[0] = mp->color[0] * fade; mp->verts[j].modulate[1] = mp->color[1] * fade; mp->verts[j].modulate[2] = mp->color[2] * fade; } } } } */ // trippy marks :) if ( mp->markShader == cgs.media.energyMarkShader && cgs.valkyrMode ) { k = ( mp->time / 4 + cg.time / 4 ) % 256; for ( j = 0 ; j < mp->poly.numVerts ; j++ ) { mp->verts[j].modulate[0] = trippyColors[k].red; mp->verts[j].modulate[1] = trippyColors[k].green; mp->verts[j].modulate[2] = trippyColors[k].blue; } } // fade all marks out with time t = mp->time + MARK_TOTAL_TIME - cg.time; if ( t < MARK_FADE_TIME ) { fade = 255 * t / MARK_FADE_TIME; if ( mp->alphaFade ) { for ( j = 0 ; j < mp->poly.numVerts ; j++ ) { mp->verts[j].modulate[3] = fade; } } else { for ( j = 0 ; j < mp->poly.numVerts ; j++ ) { mp->verts[j].modulate[0] = mp->color[0] * fade; mp->verts[j].modulate[1] = mp->color[1] * fade; mp->verts[j].modulate[2] = mp->color[2] * fade; } } } trap_R_AddPolyToScene( mp->markShader, mp->poly.numVerts, mp->verts ); } }
void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir, float orientation, float red, float green, float blue, float alpha, qboolean alphaFade, float radius, qboolean temporary, int duration ) { vec3_t axis[3]; float texCoordScale; vec3_t originalPoints[4]; byte colors[4]; int i, j; int numFragments; markFragment_t markFragments[MAX_MARK_FRAGMENTS], *mf; vec5_t markPoints[MAX_MARK_POINTS]; // Ridah, made it vec5_t so it includes S/T vec3_t projection; int multMaxFragments=1; if ( !cg_markTime.integer ) { return; } if ( radius <= 0 ) { CG_Error( "CG_ImpactMark called with <= 0 radius" ); } // Ridah, if no duration, use the default if (duration < 0) { if (duration == -2) { multMaxFragments = -1; // use original mapping } // duration = MARK_TOTAL_TIME; duration = cg_markTime.integer; } // create the texture axis VectorNormalize2( dir, axis[0] ); PerpendicularVector( axis[1], axis[0] ); RotatePointAroundVector( axis[2], axis[0], axis[1], orientation ); CrossProduct( axis[0], axis[2], axis[1] ); texCoordScale = 0.5 * 1.0 / radius; // create the full polygon for ( i = 0 ; i < 3 ; i++ ) { originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i]; originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i]; originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i]; originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i]; } // get the fragments //VectorScale( dir, -20, projection ); VectorScale( dir, radius*2, projection ); numFragments = trap_CM_MarkFragments( (int)orientation, (void *)originalPoints, projection, MAX_MARK_POINTS, (float *)&markPoints[0], MAX_MARK_FRAGMENTS*multMaxFragments, markFragments ); colors[0] = red * 255; colors[1] = green * 255; colors[2] = blue * 255; colors[3] = alpha * 255; for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) { polyVert_t *v; polyVert_t verts[MAX_VERTS_ON_POLY]; markPoly_t *mark; qboolean hasST; // we have an upper limit on the complexity of polygons // that we store persistantly if ( mf->numPoints > MAX_VERTS_ON_POLY ) { mf->numPoints = MAX_VERTS_ON_POLY; } if (mf->numPoints < 0) { hasST = qtrue; mf->numPoints *= -1; } else { hasST = qfalse; } for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) { vec3_t delta; VectorCopy( markPoints[mf->firstPoint + j], v->xyz ); if (!hasST) { VectorSubtract( v->xyz, origin, delta ); v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale; v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale; } else { v->st[0] = markPoints[mf->firstPoint + j][3]; v->st[1] = markPoints[mf->firstPoint + j][4]; } *(int *)v->modulate = *(int *)colors; } // if it is a temporary (shadow) mark, add it immediately and forget about it if ( temporary ) { trap_R_AddPolyToScene( markShader, mf->numPoints, verts ); continue; } // otherwise save it persistantly mark = CG_AllocMark(cg.time + duration); mark->time = cg.time; mark->alphaFade = alphaFade; mark->markShader = markShader; mark->poly.numVerts = mf->numPoints; mark->color[0] = red; mark->color[1] = green; mark->color[2] = blue; mark->color[3] = alpha; mark->duration = duration; memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) ); } }
static void CG_SnowParticleRender(cg_atmosphericParticle_t * particle) { // Draw a snowflake vec3_t forward, right; polyVert_t verts[4]; vec2_t line; float len, sinTumbling, cosTumbling, particleWidth; vec3_t start, finish; if (!particle->active) return; VectorCopy(particle->pos, start); sinTumbling = sin(particle->pos[2] * 0.03125f); cosTumbling = cos((particle->pos[2] + particle->pos[1]) * 0.03125f); start[0] += 24 * (1 - particle->deltaNormalized[2]) * sinTumbling; start[1] += 24 * (1 - particle->deltaNormalized[2]) * cosTumbling; len = particle->height; if (start[2] <= particle->minz) { // Stop snow going through surfaces. len = particle->height - particle->minz + start[2]; // frac = start[2]; VectorMA(start, len - particle->height, particle->deltaNormalized, start); } if (len <= 0) return; VectorCopy(particle->deltaNormalized, forward); VectorMA(start, -(len * sinTumbling), forward, finish); line[0] = DotProduct(forward, cg.refdef.viewaxis[1]); line[1] = DotProduct(forward, cg.refdef.viewaxis[2]); VectorScale(cg.refdef.viewaxis[1], line[1], right); VectorMA(right, -line[0], cg.refdef.viewaxis[2], right); VectorNormalize(right); particleWidth = cosTumbling * particle->weight; VectorMA(finish, particleWidth, right, verts[0].xyz); verts[0].st[0] = 1; verts[0].st[1] = 0; verts[0].modulate[0] = 255; verts[0].modulate[1] = 255; verts[0].modulate[2] = 255; verts[0].modulate[3] = 255; VectorMA(finish, -particleWidth, right, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 0; verts[1].modulate[0] = 255; verts[1].modulate[1] = 255; verts[1].modulate[2] = 255; verts[1].modulate[3] = 255; VectorMA(start, -particleWidth, right, verts[2].xyz); verts[2].st[0] = 0; verts[2].st[1] = 1; verts[2].modulate[0] = 255; verts[2].modulate[1] = 255; verts[2].modulate[2] = 255; verts[2].modulate[3] = 255; VectorMA(start, particleWidth, right, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 1; verts[3].modulate[0] = 255; verts[3].modulate[1] = 255; verts[3].modulate[2] = 255; verts[3].modulate[3] = 255; trap_R_AddPolyToScene(*particle->effectshader, 4, verts); }
void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir, float orientation, float red, float green, float blue, float alpha, bool alphaFade, float radius, bool temporary ) { vec3_t axis[ 3 ]; float texCoordScale; vec3_t originalPoints[ 4 ]; byte colors[ 4 ]; int i, j; int numFragments; markFragment_t markFragments[ MAX_MARK_FRAGMENTS ], *mf; vec3_t markPoints[ MAX_MARK_POINTS ]; vec3_t projection; if ( !cg_addMarks.integer ) { return; } if( temporary ) { if( CG_CullPointAndRadius( origin, M_SQRT2 * radius ) ) { return; } } if ( radius <= 0 ) { Com_Error(errorParm_t::ERR_DROP, "CG_ImpactMark called with <= 0 radius" ); } //if ( markTotal >= MAX_MARK_POLYS ) { // return; //} // create the texture axis VectorNormalize2( dir, axis[ 0 ] ); PerpendicularVector( axis[ 1 ], axis[ 0 ] ); RotatePointAroundVector( axis[ 2 ], axis[ 0 ], axis[ 1 ], orientation ); CrossProduct( axis[ 0 ], axis[ 2 ], axis[ 1 ] ); texCoordScale = 0.5 * 1.0 / radius; // create the full polygon for ( i = 0; i < 3; i++ ) { originalPoints[ 0 ][ i ] = origin[ i ] - radius * axis[ 1 ][ i ] - radius * axis[ 2 ][ i ]; originalPoints[ 1 ][ i ] = origin[ i ] + radius * axis[ 1 ][ i ] - radius * axis[ 2 ][ i ]; originalPoints[ 2 ][ i ] = origin[ i ] + radius * axis[ 1 ][ i ] + radius * axis[ 2 ][ i ]; originalPoints[ 3 ][ i ] = origin[ i ] - radius * axis[ 1 ][ i ] + radius * axis[ 2 ][ i ]; } // get the fragments VectorScale( dir, -20, projection ); numFragments = trap_CM_MarkFragments( 4, ( const vec3_t * ) originalPoints, projection, MAX_MARK_POINTS, markPoints[ 0 ], MAX_MARK_FRAGMENTS, markFragments ); colors[ 0 ] = red * 255; colors[ 1 ] = green * 255; colors[ 2 ] = blue * 255; colors[ 3 ] = alpha * 255; for ( i = 0, mf = markFragments; i < numFragments; i++, mf++ ) { polyVert_t *v; polyVert_t verts[ MAX_VERTS_ON_POLY ]; markPoly_t *mark; // we have an upper limit on the complexity of polygons // that we store persistently if ( mf->numPoints > MAX_VERTS_ON_POLY ) { mf->numPoints = MAX_VERTS_ON_POLY; } for ( j = 0, v = verts; j < mf->numPoints; j++, v++ ) { vec3_t delta; VectorCopy( markPoints[ mf->firstPoint + j ], v->xyz ); VectorSubtract( v->xyz, origin, delta ); v->st[ 0 ] = 0.5 + DotProduct( delta, axis[ 1 ] ) * texCoordScale; v->st[ 1 ] = 0.5 + DotProduct( delta, axis[ 2 ] ) * texCoordScale; * ( int * ) v->modulate = * ( int * ) colors; } // if it is a temporary (shadow) mark, add it immediately and forget about it if ( temporary ) { trap_R_AddPolyToScene( markShader, mf->numPoints, verts ); continue; } // otherwise save it persistently mark = CG_AllocMark(); mark->time = cg.time; mark->alphaFade = alphaFade; mark->markShader = markShader; mark->poly.numVerts = mf->numPoints; mark->color[ 0 ] = red; mark->color[ 1 ] = green; mark->color[ 2 ] = blue; mark->color[ 3 ] = alpha; memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[ 0 ] ) ); markTotal++; } }
/* ===================== CG_AddParticleToScene ===================== */ void CG_AddParticleToScene (cparticle_t *p, vec3_t org, float alpha) { vec3_t point; polyVert_t verts[4]; float width; float height; float time, time2; float ratio; float invratio; vec3_t color; polyVert_t TRIverts[3]; vec3_t rright2, rup2; if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY || p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT) {// create a front facing polygon if (p->type != P_WEATHER_FLURRY) { if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT) { if (org[2] > p->end) { p->time = cg.time; VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground p->org[2] = ( p->start + crandom () * 4 ); if (p->type == P_BUBBLE_TURBULENT) { p->vel[0] = crandom() * 4; p->vel[1] = crandom() * 4; } } } else { if (org[2] < p->end) { p->time = cg.time; VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground while (p->org[2] < p->end) { p->org[2] += (p->start - p->end); } if (p->type == P_WEATHER_TURBULENT) { p->vel[0] = crandom() * 16; p->vel[1] = crandom() * 16; } } } // Rafael snow pvs check if (!p->link) return; p->alpha = 1; } // Ridah, had to do this or MAX_POLYS is being exceeded in village1.bsp if (Distance( cg.snap->ps.origin, org ) > 1024) { return; } // done. if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT) { VectorMA (org, -p->height, pvup, point); VectorMA (point, -p->width, pvright, point); VectorCopy (point, verts[0].xyz); verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255; verts[0].modulate[1] = 255; verts[0].modulate[2] = 255; verts[0].modulate[3] = 255 * p->alpha; VectorMA (org, -p->height, pvup, point); VectorMA (point, p->width, pvright, point); VectorCopy (point, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255; verts[1].modulate[1] = 255; verts[1].modulate[2] = 255; verts[1].modulate[3] = 255 * p->alpha; VectorMA (org, p->height, pvup, point); VectorMA (point, p->width, pvright, point); VectorCopy (point, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255; verts[2].modulate[1] = 255; verts[2].modulate[2] = 255; verts[2].modulate[3] = 255 * p->alpha; VectorMA (org, p->height, pvup, point); VectorMA (point, -p->width, pvright, point); VectorCopy (point, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255; verts[3].modulate[1] = 255; verts[3].modulate[2] = 255; verts[3].modulate[3] = 255 * p->alpha; } else { VectorMA (org, -p->height, pvup, point); VectorMA (point, -p->width, pvright, point); VectorCopy( point, TRIverts[0].xyz ); TRIverts[0].st[0] = 1; TRIverts[0].st[1] = 0; TRIverts[0].modulate[0] = 255; TRIverts[0].modulate[1] = 255; TRIverts[0].modulate[2] = 255; TRIverts[0].modulate[3] = 255 * p->alpha; VectorMA (org, p->height, pvup, point); VectorMA (point, -p->width, pvright, point); VectorCopy (point, TRIverts[1].xyz); TRIverts[1].st[0] = 0; TRIverts[1].st[1] = 0; TRIverts[1].modulate[0] = 255; TRIverts[1].modulate[1] = 255; TRIverts[1].modulate[2] = 255; TRIverts[1].modulate[3] = 255 * p->alpha; VectorMA (org, p->height, pvup, point); VectorMA (point, p->width, pvright, point); VectorCopy (point, TRIverts[2].xyz); TRIverts[2].st[0] = 0; TRIverts[2].st[1] = 1; TRIverts[2].modulate[0] = 255; TRIverts[2].modulate[1] = 255; TRIverts[2].modulate[2] = 255; TRIverts[2].modulate[3] = 255 * p->alpha; } } else if (p->type == P_SPRITE) { vec3_t rr, ru; vec3_t rotate_ang; VectorSet (color, 1.0, 1.0, 0.5); time = cg.time - p->time; time2 = p->endtime - p->time; ratio = time / time2; width = p->width + ( ratio * ( p->endwidth - p->width) ); height = p->height + ( ratio * ( p->endheight - p->height) ); if (p->roll) { vectoangles( cg.refdef.viewaxis[0], rotate_ang ); rotate_ang[ROLL] += p->roll; AngleVectors ( rotate_ang, NULL, rr, ru); } if (p->roll) { VectorMA (org, -height, ru, point); VectorMA (point, -width, rr, point); } else { VectorMA (org, -height, pvup, point); VectorMA (point, -width, pvright, point); } VectorCopy (point, verts[0].xyz); verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255; verts[0].modulate[1] = 255; verts[0].modulate[2] = 255; verts[0].modulate[3] = 255; if (p->roll) { VectorMA (point, 2*height, ru, point); } else { VectorMA (point, 2*height, pvup, point); } VectorCopy (point, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255; verts[1].modulate[1] = 255; verts[1].modulate[2] = 255; verts[1].modulate[3] = 255; if (p->roll) { VectorMA (point, 2*width, rr, point); } else { VectorMA (point, 2*width, pvright, point); } VectorCopy (point, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255; verts[2].modulate[1] = 255; verts[2].modulate[2] = 255; verts[2].modulate[3] = 255; if (p->roll) { VectorMA (point, -2*height, ru, point); } else { VectorMA (point, -2*height, pvup, point); } VectorCopy (point, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255; verts[3].modulate[1] = 255; verts[3].modulate[2] = 255; verts[3].modulate[3] = 255; } else if (p->type == P_SMOKE || p->type == P_SMOKE_IMPACT) {// create a front rotating facing polygon if ( p->type == P_SMOKE_IMPACT && Distance( cg.snap->ps.origin, org ) > 1024) { return; } if (p->color == BLOODRED) VectorSet (color, 0.22f, 0.0f, 0.0f); else if (p->color == GREY75) { float len; float greyit; float val; len = Distance (cg.snap->ps.origin, org); if (!len) len = 1; val = 4096/len; greyit = 0.25 * val; if (greyit > 0.5) greyit = 0.5; VectorSet (color, greyit, greyit, greyit); } else VectorSet (color, 1.0, 1.0, 1.0); time = cg.time - p->time; time2 = p->endtime - p->time; ratio = time / time2; if (cg.time > p->startfade) { invratio = 1 - ( (cg.time - p->startfade) / (p->endtime - p->startfade) ); if (p->color == EMISIVEFADE) { float fval; fval = (invratio * invratio); if (fval < 0) fval = 0; VectorSet (color, fval , fval , fval ); } invratio *= p->alpha; } else invratio = 1 * p->alpha; if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) invratio = 1; if (invratio > 1) invratio = 1; width = p->width + ( ratio * ( p->endwidth - p->width) ); height = p->height + ( ratio * ( p->endheight - p->height) ); if (p->type != P_SMOKE_IMPACT) { vec3_t temp; vectoangles (rforward, temp); p->accumroll += p->roll; temp[ROLL] += p->accumroll * 0.1; AngleVectors ( temp, NULL, rright2, rup2); } else { VectorCopy (rright, rright2); VectorCopy (rup, rup2); } if (p->rotate) { VectorMA (org, -height, rup2, point); VectorMA (point, -width, rright2, point); } else { VectorMA (org, -p->height, pvup, point); VectorMA (point, -p->width, pvright, point); } VectorCopy (point, verts[0].xyz); verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255 * color[0]; verts[0].modulate[1] = 255 * color[1]; verts[0].modulate[2] = 255 * color[2]; verts[0].modulate[3] = 255 * invratio; if (p->rotate) { VectorMA (org, -height, rup2, point); VectorMA (point, width, rright2, point); } else { VectorMA (org, -p->height, pvup, point); VectorMA (point, p->width, pvright, point); } VectorCopy (point, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255 * color[0]; verts[1].modulate[1] = 255 * color[1]; verts[1].modulate[2] = 255 * color[2]; verts[1].modulate[3] = 255 * invratio; if (p->rotate) { VectorMA (org, height, rup2, point); VectorMA (point, width, rright2, point); } else { VectorMA (org, p->height, pvup, point); VectorMA (point, p->width, pvright, point); } VectorCopy (point, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255 * color[0]; verts[2].modulate[1] = 255 * color[1]; verts[2].modulate[2] = 255 * color[2]; verts[2].modulate[3] = 255 * invratio; if (p->rotate) { VectorMA (org, height, rup2, point); VectorMA (point, -width, rright2, point); } else { VectorMA (org, p->height, pvup, point); VectorMA (point, -p->width, pvright, point); } VectorCopy (point, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255 * color[0]; verts[3].modulate[1] = 255 * color[1]; verts[3].modulate[2] = 255 * color[2]; verts[3].modulate[3] = 255 * invratio; } else if (p->type == P_BLEED) { vec3_t rr, ru; vec3_t rotate_ang; float alpha; alpha = p->alpha; if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) alpha = 1; if (p->roll) { vectoangles( cg.refdef.viewaxis[0], rotate_ang ); rotate_ang[ROLL] += p->roll; AngleVectors ( rotate_ang, NULL, rr, ru); } else { VectorCopy (pvup, ru); VectorCopy (pvright, rr); } VectorMA (org, -p->height, ru, point); VectorMA (point, -p->width, rr, point); VectorCopy (point, verts[0].xyz); verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 111; verts[0].modulate[1] = 19; verts[0].modulate[2] = 9; verts[0].modulate[3] = 255 * alpha; VectorMA (org, -p->height, ru, point); VectorMA (point, p->width, rr, point); VectorCopy (point, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 111; verts[1].modulate[1] = 19; verts[1].modulate[2] = 9; verts[1].modulate[3] = 255 * alpha; VectorMA (org, p->height, ru, point); VectorMA (point, p->width, rr, point); VectorCopy (point, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 111; verts[2].modulate[1] = 19; verts[2].modulate[2] = 9; verts[2].modulate[3] = 255 * alpha; VectorMA (org, p->height, ru, point); VectorMA (point, -p->width, rr, point); VectorCopy (point, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 111; verts[3].modulate[1] = 19; verts[3].modulate[2] = 9; verts[3].modulate[3] = 255 * alpha; } else if (p->type == P_FLAT_SCALEUP) { float width, height; float sinR, cosR; if (p->color == BLOODRED) VectorSet (color, 1, 1, 1); else VectorSet (color, 0.5, 0.5, 0.5); time = cg.time - p->time; time2 = p->endtime - p->time; ratio = time / time2; width = p->width + ( ratio * ( p->endwidth - p->width) ); height = p->height + ( ratio * ( p->endheight - p->height) ); if (width > p->endwidth) width = p->endwidth; if (height > p->endheight) height = p->endheight; sinR = height * sin(DEG2RAD(p->roll)) * sqrt(2); cosR = width * cos(DEG2RAD(p->roll)) * sqrt(2); VectorCopy (org, verts[0].xyz); verts[0].xyz[0] -= sinR; verts[0].xyz[1] -= cosR; verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255 * color[0]; verts[0].modulate[1] = 255 * color[1]; verts[0].modulate[2] = 255 * color[2]; verts[0].modulate[3] = 255; VectorCopy (org, verts[1].xyz); verts[1].xyz[0] -= cosR; verts[1].xyz[1] += sinR; verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255 * color[0]; verts[1].modulate[1] = 255 * color[1]; verts[1].modulate[2] = 255 * color[2]; verts[1].modulate[3] = 255; VectorCopy (org, verts[2].xyz); verts[2].xyz[0] += sinR; verts[2].xyz[1] += cosR; verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255 * color[0]; verts[2].modulate[1] = 255 * color[1]; verts[2].modulate[2] = 255 * color[2]; verts[2].modulate[3] = 255; VectorCopy (org, verts[3].xyz); verts[3].xyz[0] += cosR; verts[3].xyz[1] -= sinR; verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255 * color[0]; verts[3].modulate[1] = 255 * color[1]; verts[3].modulate[2] = 255 * color[2]; verts[3].modulate[3] = 255; } else if (p->type == P_FLAT) { VectorCopy (org, verts[0].xyz); verts[0].xyz[0] -= p->height; verts[0].xyz[1] -= p->width; verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255; verts[0].modulate[1] = 255; verts[0].modulate[2] = 255; verts[0].modulate[3] = 255; VectorCopy (org, verts[1].xyz); verts[1].xyz[0] -= p->height; verts[1].xyz[1] += p->width; verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255; verts[1].modulate[1] = 255; verts[1].modulate[2] = 255; verts[1].modulate[3] = 255; VectorCopy (org, verts[2].xyz); verts[2].xyz[0] += p->height; verts[2].xyz[1] += p->width; verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255; verts[2].modulate[1] = 255; verts[2].modulate[2] = 255; verts[2].modulate[3] = 255; VectorCopy (org, verts[3].xyz); verts[3].xyz[0] += p->height; verts[3].xyz[1] -= p->width; verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255; verts[3].modulate[1] = 255; verts[3].modulate[2] = 255; verts[3].modulate[3] = 255; } // Ridah else if (p->type == P_ANIM) { vec3_t rr, ru; vec3_t rotate_ang; int i, j; time = cg.time - p->time; time2 = p->endtime - p->time; ratio = time / time2; if (ratio >= 1.0f) { ratio = 0.9999f; } width = p->width + ( ratio * ( p->endwidth - p->width) ); height = p->height + ( ratio * ( p->endheight - p->height) ); // if we are "inside" this sprite, don't draw if (Distance( cg.snap->ps.origin, org ) < width/1.5) { return; } i = p->shaderAnim; j = (int)floor(ratio * shaderAnimCounts[p->shaderAnim]); p->pshader = shaderAnims[i][j]; if (p->roll) { vectoangles( cg.refdef.viewaxis[0], rotate_ang ); rotate_ang[ROLL] += p->roll; AngleVectors ( rotate_ang, NULL, rr, ru); } if (p->roll) { VectorMA (org, -height, ru, point); VectorMA (point, -width, rr, point); } else { VectorMA (org, -height, pvup, point); VectorMA (point, -width, pvright, point); } VectorCopy (point, verts[0].xyz); verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255; verts[0].modulate[1] = 255; verts[0].modulate[2] = 255; verts[0].modulate[3] = 255; if (p->roll) { VectorMA (point, 2*height, ru, point); } else { VectorMA (point, 2*height, pvup, point); } VectorCopy (point, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255; verts[1].modulate[1] = 255; verts[1].modulate[2] = 255; verts[1].modulate[3] = 255; if (p->roll) { VectorMA (point, 2*width, rr, point); } else { VectorMA (point, 2*width, pvright, point); } VectorCopy (point, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255; verts[2].modulate[1] = 255; verts[2].modulate[2] = 255; verts[2].modulate[3] = 255; if (p->roll) { VectorMA (point, -2*height, ru, point); } else { VectorMA (point, -2*height, pvup, point); } VectorCopy (point, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255; verts[3].modulate[1] = 255; verts[3].modulate[2] = 255; verts[3].modulate[3] = 255; } // done. if (!p->pshader) { // (SA) temp commented out for DM // CG_Printf ("CG_AddParticleToScene type %d p->pshader == ZERO\n", p->type); return; } if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY) trap_R_AddPolyToScene( p->pshader, 3, TRIverts ); else trap_R_AddPolyToScene( p->pshader, 4, verts ); }
/* ================ CG_DrawBinaryShadersFinalPhases ================ */ static void CG_DrawBinaryShadersFinalPhases() { float ss; char str[ 20 ]; float f, l, u; polyVert_t verts[ 4 ] = { { { 0, 0, 0 }, { 0, 0 }, { 255, 255, 255, 255 } }, { { 0, 0, 0 }, { 1, 0 }, { 255, 255, 255, 255 } }, { { 0, 0, 0 }, { 1, 1 }, { 255, 255, 255, 255 } }, { { 0, 0, 0 }, { 0, 1 }, { 255, 255, 255, 255 } } }; if ( !cg.numBinaryShadersUsed ) { return; } ss = cg_binaryShaderScreenScale.value; if ( ss <= 0.0f ) { cg.numBinaryShadersUsed = 0; return; } else if ( ss > 1.0f ) { ss = 1.0f; } ss = sqrt( ss ); trap_Cvar_VariableStringBuffer( "r_znear", str, sizeof( str ) ); f = atof( str ) + 0.01; l = f * tan( DEG2RAD( cg.refdef.fov_x / 2 ) ) * ss; u = f * tan( DEG2RAD( cg.refdef.fov_y / 2 ) ) * ss; VectorMA( cg.refdef.vieworg, f, cg.refdef.viewaxis[ 0 ], verts[ 0 ].xyz ); VectorMA( verts[ 0 ].xyz, l, cg.refdef.viewaxis[ 1 ], verts[ 0 ].xyz ); VectorMA( verts[ 0 ].xyz, u, cg.refdef.viewaxis[ 2 ], verts[ 0 ].xyz ); VectorMA( verts[ 0 ].xyz, -2 * l, cg.refdef.viewaxis[ 1 ], verts[ 1 ].xyz ); VectorMA( verts[ 1 ].xyz, -2 * u, cg.refdef.viewaxis[ 2 ], verts[ 2 ].xyz ); VectorMA( verts[ 0 ].xyz, -2 * u, cg.refdef.viewaxis[ 2 ], verts[ 3 ].xyz ); trap_R_AddPolyToScene( cgs.media.binaryAlpha1Shader, 4, verts ); for ( int i = 0; i < cg.numBinaryShadersUsed; ++i ) { for ( int j = 0; j < 4; ++j ) { auto alpha = verts[ j ].modulate[ 3 ]; cg.binaryShaderSettings[ i ].color.ToArray( verts[ j ].modulate ); verts[ j ].modulate[ 3 ] = alpha; } if ( cg.binaryShaderSettings[ i ].drawFrontline ) { trap_R_AddPolyToScene( cgs.media.binaryShaders[ i ].f3, 4, verts ); } if ( cg.binaryShaderSettings[ i ].drawIntersection ) { trap_R_AddPolyToScene( cgs.media.binaryShaders[ i ].b3, 4, verts ); } } cg.numBinaryShadersUsed = 0; }
/** * @brief CG_AddParticleToScene * @param[in,out] p * @param[in] org * @param alpha - unused */ void CG_AddParticleToScene(cparticle_t *p, vec3_t org, float alpha) { polyVert_t verts[4]; polyVert_t TRIverts[3]; switch (p->type) { case P_WEATHER: case P_WEATHER_TURBULENT: case P_WEATHER_FLURRY: case P_BUBBLE: case P_BUBBLE_TURBULENT: // create a front facing polygon { if (p->type != P_WEATHER_FLURRY) { if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT) { if (org[2] > p->end) { p->time = cg.time; VectorCopy(org, p->org); // fixes rare snow flakes that flicker on the ground p->org[2] = (p->start + crandom() * 4); if (p->type == P_BUBBLE_TURBULENT) { p->vel[0] = crandom() * 4; p->vel[1] = crandom() * 4; } } } else { if (org[2] < p->end) { p->time = cg.time; VectorCopy(org, p->org); // fixes rare snow flakes that flicker on the ground while (p->org[2] < p->end) { p->org[2] += (p->start - p->end); } if (p->type == P_WEATHER_TURBULENT) { p->vel[0] = crandom() * 16; p->vel[1] = crandom() * 16; } } } // snow pvs check if (!p->link) { return; } p->alpha = 1; } // had to do this or MAX_POLYS is being exceeded in village1.bsp if (VectorDistanceSquared(cg.snap->ps.origin, org) > Square(1024)) { return; } if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT) { vec3_t point; VectorMA(org, -p->height, vup, point); VectorMA(point, -p->width, vright, point); VectorCopy(point, verts[0].xyz); verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255; verts[0].modulate[1] = 255; verts[0].modulate[2] = 255; verts[0].modulate[3] = (byte)(255 * p->alpha); VectorMA(org, -p->height, vup, point); VectorMA(point, p->width, vright, point); VectorCopy(point, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255; verts[1].modulate[1] = 255; verts[1].modulate[2] = 255; verts[1].modulate[3] = (byte)(255 * p->alpha); VectorMA(org, p->height, vup, point); VectorMA(point, p->width, vright, point); VectorCopy(point, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255; verts[2].modulate[1] = 255; verts[2].modulate[2] = 255; verts[2].modulate[3] = (byte)(255 * p->alpha); VectorMA(org, p->height, vup, point); VectorMA(point, -p->width, vright, point); VectorCopy(point, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255; verts[3].modulate[1] = 255; verts[3].modulate[2] = 255; verts[3].modulate[3] = (byte)(255 * p->alpha); } else { vec3_t point; VectorMA(org, -p->height, vup, point); VectorMA(point, -p->width, vright, point); VectorCopy(point, TRIverts[0].xyz); TRIverts[0].st[0] = 1; TRIverts[0].st[1] = 0; TRIverts[0].modulate[0] = 255; TRIverts[0].modulate[1] = 255; TRIverts[0].modulate[2] = 255; TRIverts[0].modulate[3] = (byte)(255 * p->alpha); VectorMA(org, p->height, vup, point); VectorMA(point, -p->width, vright, point); VectorCopy(point, TRIverts[1].xyz); TRIverts[1].st[0] = 0; TRIverts[1].st[1] = 0; TRIverts[1].modulate[0] = 255; TRIverts[1].modulate[1] = 255; TRIverts[1].modulate[2] = 255; TRIverts[1].modulate[3] = (byte)(255 * p->alpha); VectorMA(org, p->height, vup, point); VectorMA(point, p->width, vright, point); VectorCopy(point, TRIverts[2].xyz); TRIverts[2].st[0] = 0; TRIverts[2].st[1] = 1; TRIverts[2].modulate[0] = 255; TRIverts[2].modulate[1] = 255; TRIverts[2].modulate[2] = 255; TRIverts[2].modulate[3] = (byte)(255 * p->alpha); } } break; case P_SPRITE: { vec3_t point, rr, ru, rotate_ang; float time = cg.time - p->time; float time2 = p->endtime - p->time; float ratio = time / time2; float width = p->width + (ratio * (p->endwidth - p->width)); float height = p->height + (ratio * (p->endheight - p->height)); if (p->roll) { vectoangles(cg.refdef_current->viewaxis[0], rotate_ang); rotate_ang[ROLL] += p->roll; AngleVectors(rotate_ang, NULL, rr, ru); } if (p->roll) { VectorMA(org, -height, ru, point); VectorMA(point, -width, rr, point); } else { VectorMA(org, -height, vup, point); VectorMA(point, -width, vright, point); } VectorCopy(point, verts[0].xyz); verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255; verts[0].modulate[1] = 255; verts[0].modulate[2] = 255; verts[0].modulate[3] = 255; if (p->roll) { VectorMA(point, 2 * height, ru, point); } else { VectorMA(point, 2 * height, vup, point); } VectorCopy(point, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255; verts[1].modulate[1] = 255; verts[1].modulate[2] = 255; verts[1].modulate[3] = 255; if (p->roll) { VectorMA(point, 2 * width, rr, point); } else { VectorMA(point, 2 * width, vright, point); } VectorCopy(point, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255; verts[2].modulate[1] = 255; verts[2].modulate[2] = 255; verts[2].modulate[3] = 255; if (p->roll) { VectorMA(point, -2 * height, ru, point); } else { VectorMA(point, -2 * height, vup, point); } VectorCopy(point, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255; verts[3].modulate[1] = 255; verts[3].modulate[2] = 255; verts[3].modulate[3] = 255; } break; case P_SMOKE: case P_SMOKE_IMPACT: // create a front rotating facing polygon { vec3_t point, rup2, rright2, color; float invratio, time, time2, ratio, width, height; if (p->type == P_SMOKE_IMPACT && VectorDistanceSquared(cg.snap->ps.origin, org) > Square(1024)) { return; } if (p->color == MUSTARD) { VectorSet(color, 0.42f, 0.33f, 0.19f); } else if (p->color == BLOODRED) { VectorSet(color, 0.22f, 0, 0); } else if (p->color == ZOMBIE) { VectorSet(color, 0.4f, 0.28f, 0.23f); } else if (p->color == GREY75) { float len, greyit; len = Distance(cg.snap->ps.origin, org); if (len == 0.f) { len = 1; } //val = 4096 / len; greyit = 0.25f * (4096 / len); if (greyit > 0.5f) { greyit = 0.5f; } VectorSet(color, greyit, greyit, greyit); } else { VectorSet(color, 1.0f, 1.0f, 1.0f); } time = cg.time - p->time; time2 = p->endtime - p->time; ratio = time / time2; if (cg.time > p->startfade) { invratio = 1 - ((cg.time - p->startfade) / (p->endtime - p->startfade)); if (p->color == EMISIVEFADE) { float fval = invratio * invratio; if (fval < 0) { fval = 0; } VectorSet(color, fval, fval, fval); } invratio *= p->alpha; } else { invratio = 1 * p->alpha; } if (invratio > 1) { invratio = 1; } width = p->width + (ratio * (p->endwidth - p->width)); height = p->height + (ratio * (p->endheight - p->height)); //if (p->type != P_SMOKE_IMPACT) { vec3_t temp; vectoangles(rforward, temp); p->accumroll += p->roll; temp[ROLL] += p->accumroll * 0.1; //temp[ROLL] += p->roll * 0.1; AngleVectors(temp, NULL, rright2, rup2); } //else //{ //VectorCopy (rright, rright2); //VectorCopy (rup, rup2); //} if (p->rotate) { VectorMA(org, -height, rup2, point); VectorMA(point, -width, rright2, point); } else { VectorMA(org, -p->height, vup, point); VectorMA(point, -p->width, vright, point); } VectorCopy(point, verts[0].xyz); verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = (byte)(255 * color[0]); verts[0].modulate[1] = (byte)(255 * color[1]); verts[0].modulate[2] = (byte)(255 * color[2]); verts[0].modulate[3] = (byte)(255 * invratio); if (p->rotate) { VectorMA(org, -height, rup2, point); VectorMA(point, width, rright2, point); } else { VectorMA(org, -p->height, vup, point); VectorMA(point, p->width, vright, point); } VectorCopy(point, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = (byte)(255 * color[0]); verts[1].modulate[1] = (byte)(255 * color[1]); verts[1].modulate[2] = (byte)(255 * color[2]); verts[1].modulate[3] = (byte)(255 * invratio); if (p->rotate) { VectorMA(org, height, rup2, point); VectorMA(point, width, rright2, point); } else { VectorMA(org, p->height, vup, point); VectorMA(point, p->width, vright, point); } VectorCopy(point, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = (byte)(255 * color[0]); verts[2].modulate[1] = (byte)(255 * color[1]); verts[2].modulate[2] = (byte)(255 * color[2]); verts[2].modulate[3] = (byte)(255 * invratio); if (p->rotate) { VectorMA(org, height, rup2, point); VectorMA(point, -width, rright2, point); } else { VectorMA(org, p->height, vup, point); VectorMA(point, -p->width, vright, point); } VectorCopy(point, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = (byte)(255 * color[0]); verts[3].modulate[1] = (byte)(255 * color[1]); verts[3].modulate[2] = (byte)(255 * color[2]); verts[3].modulate[3] = (byte)(255 * invratio); } break; case P_BLEED: { vec3_t point, rr, ru, rotate_ang; float alpha = p->alpha; if (p->roll) { vectoangles(cg.refdef_current->viewaxis[0], rotate_ang); rotate_ang[ROLL] += p->roll; AngleVectors(rotate_ang, NULL, rr, ru); } else { VectorCopy(vup, ru); VectorCopy(vright, rr); } VectorMA(org, -p->height, ru, point); VectorMA(point, -p->width, rr, point); VectorCopy(point, verts[0].xyz); verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 111; verts[0].modulate[1] = 19; verts[0].modulate[2] = 9; verts[0].modulate[3] = (byte)(255 * alpha); VectorMA(org, -p->height, ru, point); VectorMA(point, p->width, rr, point); VectorCopy(point, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 111; verts[1].modulate[1] = 19; verts[1].modulate[2] = 9; verts[1].modulate[3] = (byte)(255 * alpha); VectorMA(org, p->height, ru, point); VectorMA(point, p->width, rr, point); VectorCopy(point, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 111; verts[2].modulate[1] = 19; verts[2].modulate[2] = 9; verts[2].modulate[3] = (byte)(255 * alpha); VectorMA(org, p->height, ru, point); VectorMA(point, -p->width, rr, point); VectorCopy(point, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 111; verts[3].modulate[1] = 19; verts[3].modulate[2] = 9; verts[3].modulate[3] = (byte)(255 * alpha); } break; case P_FLAT_SCALEUP: { vec3_t color; float width, height; float sinR, cosR; float time = cg.time - p->time; float time2 = p->endtime - p->time; float ratio = time / time2; if (p->color == BLOODRED) { VectorSet(color, 1, 1, 1); } else { VectorSet(color, 0.5f, 0.5f, 0.5f); } width = p->width + (ratio * (p->endwidth - p->width)); height = p->height + (ratio * (p->endheight - p->height)); if (width > p->endwidth) { width = p->endwidth; } if (height > p->endheight) { height = p->endheight; } sinR = height * (float)(sin(DEG2RAD(p->roll)) * M_SQRT2); cosR = width * (float)(cos(DEG2RAD(p->roll)) * M_SQRT2); VectorCopy(org, verts[0].xyz); verts[0].xyz[0] -= sinR; verts[0].xyz[1] -= cosR; verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = (byte)(255 * color[0]); verts[0].modulate[1] = (byte)(255 * color[1]); verts[0].modulate[2] = (byte)(255 * color[2]); verts[0].modulate[3] = 255; VectorCopy(org, verts[1].xyz); verts[1].xyz[0] -= cosR; verts[1].xyz[1] += sinR; verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = verts[0].modulate[0]; verts[1].modulate[1] = verts[0].modulate[1]; verts[1].modulate[2] = verts[0].modulate[2]; verts[1].modulate[3] = verts[0].modulate[3]; VectorCopy(org, verts[2].xyz); verts[2].xyz[0] += sinR; verts[2].xyz[1] += cosR; verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = verts[0].modulate[0]; verts[2].modulate[1] = verts[0].modulate[1]; verts[2].modulate[2] = verts[0].modulate[2]; verts[2].modulate[3] = verts[0].modulate[3]; VectorCopy(org, verts[3].xyz); verts[3].xyz[0] += cosR; verts[3].xyz[1] -= sinR; verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = verts[0].modulate[0]; verts[3].modulate[1] = verts[0].modulate[1]; verts[3].modulate[2] = verts[0].modulate[2]; verts[3].modulate[3] = verts[0].modulate[3]; } break; case P_FLAT: { VectorCopy(org, verts[0].xyz); verts[0].xyz[0] -= p->height; verts[0].xyz[1] -= p->width; verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255; verts[0].modulate[1] = 255; verts[0].modulate[2] = 255; verts[0].modulate[3] = 255; VectorCopy(org, verts[1].xyz); verts[1].xyz[0] -= p->height; verts[1].xyz[1] += p->width; verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255; verts[1].modulate[1] = 255; verts[1].modulate[2] = 255; verts[1].modulate[3] = 255; VectorCopy(org, verts[2].xyz); verts[2].xyz[0] += p->height; verts[2].xyz[1] += p->width; verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255; verts[2].modulate[1] = 255; verts[2].modulate[2] = 255; verts[2].modulate[3] = 255; VectorCopy(org, verts[3].xyz); verts[3].xyz[0] += p->height; verts[3].xyz[1] -= p->width; verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255; verts[3].modulate[1] = 255; verts[3].modulate[2] = 255; verts[3].modulate[3] = 255; } break; case P_ANIM: case P_DLIGHT_ANIM: { vec3_t point, rr, ru, rotate_ang; float width, height; float time = cg.time - p->time; float time2 = p->endtime - p->time; float ratio = time / time2; int i, j; if (ratio >= 1) { ratio = 0.9999f; } else if (ratio < 0) { // make sure that ratio isn't negative or // we'll walk out of bounds when j is calculated below ratio = 0.0001f; } width = p->width + (ratio * (p->endwidth - p->width)); height = p->height + (ratio * (p->endheight - p->height)); // add dlight if necessary if (p->type == P_DLIGHT_ANIM) { // fixme: support arbitrary color trap_R_AddLightToScene(org, 320, //% 1.5 * (width > height ? width : height), 1.25f * (1.0f - ratio), 1.0f, 0.95f, 0.85f, 0, 0); } // if we are "inside" this sprite, don't draw if (VectorDistanceSquared(cg.snap->ps.origin, org) < Square(width / 1.5f)) { return; } i = p->shaderAnim; j = (int)floor((double)ratio * shaderAnimCounts[p->shaderAnim]); p->pshader = shaderAnims[i][j]; if (p->roll) { vectoangles(cg.refdef_current->viewaxis[0], rotate_ang); rotate_ang[ROLL] += p->roll; AngleVectors(rotate_ang, NULL, rr, ru); } if (p->roll) { VectorMA(org, -height, ru, point); VectorMA(point, -width, rr, point); } else { VectorMA(org, -height, vup, point); VectorMA(point, -width, vright, point); } VectorCopy(point, verts[0].xyz); verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255; verts[0].modulate[1] = 255; verts[0].modulate[2] = 255; verts[0].modulate[3] = 255; if (p->roll) { VectorMA(point, 2 * height, ru, point); } else { VectorMA(point, 2 * height, vup, point); } VectorCopy(point, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255; verts[1].modulate[1] = 255; verts[1].modulate[2] = 255; verts[1].modulate[3] = 255; if (p->roll) { VectorMA(point, 2 * width, rr, point); } else { VectorMA(point, 2 * width, vright, point); } VectorCopy(point, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255; verts[2].modulate[1] = 255; verts[2].modulate[2] = 255; verts[2].modulate[3] = 255; if (p->roll) { VectorMA(point, -2 * height, ru, point); } else { VectorMA(point, -2 * height, vup, point); } VectorCopy(point, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255; verts[3].modulate[1] = 255; verts[3].modulate[2] = 255; verts[3].modulate[3] = 255; } break; default: break; } if (!cg_wolfparticles.integer) { return; } if (!p->pshader) { CG_Printf("CG_AddParticleToScene type %d p->pshader == ZERO\n", p->type); return; } if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY) { trap_R_AddPolyToScene(p->pshader, 3, TRIverts); } else { trap_R_AddPolyToScene(p->pshader, 4, verts); } }
void CG_AddTrailToScene(trailJunc_t *trail, int iteration, int numJuncs) { #define MAX_TRAIL_VERTS 2048 polyVert_t verts[MAX_TRAIL_VERTS]; polyVert_t outVerts[MAX_TRAIL_VERTS * 3]; int k, i, n, l, numOutVerts; polyVert_t mid; float mod[4]; float sInc = 0.0f, s = 0.0f; // TTimo: init trailJunc_t *j, *jNext; vec3_t fwd, up, p, v; (void)fwd; // Ignore compiler warning -- Justasic // clipping vars #define TRAIL_FADE_CLOSE_DIST 64.0 #define TRAIL_FADE_FAR_SCALE 4.0 vec3_t viewProj; float viewDist, fadeAlpha; // add spark shader at head position if(trail->flags & TJFL_SPARKHEADFLARE) { j = trail; VectorCopy(j->pos, p); VectorMA(p, -j->width * 2, vup, p); VectorMA(p, -j->width * 2, vright, p); VectorCopy(p, verts[0].xyz); verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255; verts[0].modulate[1] = 255; verts[0].modulate[2] = 255; verts[0].modulate[3] = (unsigned char)(j->alpha * 255.0); VectorCopy(j->pos, p); VectorMA(p, -j->width * 2, vup, p); VectorMA(p, j->width * 2, vright, p); VectorCopy(p, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255; verts[1].modulate[1] = 255; verts[1].modulate[2] = 255; verts[1].modulate[3] = (unsigned char)(j->alpha * 255.0); VectorCopy(j->pos, p); VectorMA(p, j->width * 2, vup, p); VectorMA(p, j->width * 2, vright, p); VectorCopy(p, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255; verts[2].modulate[1] = 255; verts[2].modulate[2] = 255; verts[2].modulate[3] = (unsigned char)(j->alpha * 255.0); VectorCopy(j->pos, p); VectorMA(p, j->width * 2, vup, p); VectorMA(p, -j->width * 2, vright, p); VectorCopy(p, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255; verts[3].modulate[1] = 255; verts[3].modulate[2] = 255; verts[3].modulate[3] = (unsigned char)(j->alpha * 255.0); trap_R_AddPolyToScene(cgs.media.sparkFlareShader, 4, verts); } // if (trail->flags & TJFL_CROSSOVER && iteration < 1) { // iteration = 1; // } if(!numJuncs) { // first count the number of juncs in the trail j = trail; numJuncs = 0; sInc = 0; while(j) { numJuncs++; // check for a dead next junc if(!j->inuse && j->nextJunc && !j->nextJunc->inuse) { CG_KillTrail(j); } else if(j->nextJunc && j->nextJunc->freed) { // not sure how this can happen, but it does, and causes infinite loops j->nextJunc = NULL; } if(j->nextJunc) { sInc += VectorDistance(j->nextJunc->pos, j->pos); } j = j->nextJunc; } } if(numJuncs < 2) { return; } if(trail->sType == STYPE_STRETCH) { //sInc = ((1.0 - 0.1) / (float)(numJuncs)); // hack, the end of funnel shows a bit of the start (looping) s = 0.05; //s = 0.05; } else if(trail->sType == STYPE_REPEAT) { s = trail->sTex; } // now traverse the list j = trail; jNext = j->nextJunc; i = 0; while(jNext) { // first get the directional vectors to the next junc VectorSubtract(jNext->pos, j->pos, fwd); GetPerpendicularViewVector(cg.refdef.vieworg, j->pos, jNext->pos, up); // if it's a crossover, draw it twice if(j->flags & TJFL_CROSSOVER) { if(iteration > 0) { ProjectPointOntoVector(cg.refdef.vieworg, j->pos, jNext->pos, viewProj); VectorSubtract(cg.refdef.vieworg, viewProj, v); VectorNormalize(v); if(iteration == 1) { VectorMA(up, 0.3, v, up); } else { VectorMA(up, -0.3, v, up); } VectorNormalize(up); } } // do fading when moving towards the projection point onto the trail segment vector else if(!(j->flags & TJFL_NOCULL) && (j->widthEnd > 4 || jNext->widthEnd > 4)) { ProjectPointOntoVector(cg.refdef.vieworg, j->pos, jNext->pos, viewProj); viewDist = Distance(viewProj, cg.refdef.vieworg); if(viewDist < (TRAIL_FADE_CLOSE_DIST * TRAIL_FADE_FAR_SCALE)) { if(viewDist < TRAIL_FADE_CLOSE_DIST) { fadeAlpha = 0.0; } else { fadeAlpha = (viewDist - TRAIL_FADE_CLOSE_DIST) / (TRAIL_FADE_CLOSE_DIST * TRAIL_FADE_FAR_SCALE); } if(fadeAlpha < j->alpha) { j->alpha = fadeAlpha; } if(fadeAlpha < jNext->alpha) { jNext->alpha = fadeAlpha; } } } // now output the QUAD for this segment // 1 ---- VectorMA(j->pos, 0.5 * j->width, up, p); VectorCopy(p, verts[i].xyz); verts[i].st[0] = s; verts[i].st[1] = 1.0; for(k = 0; k < 3; k++) verts[i].modulate[k] = (unsigned char)(j->color[k] * 255.0); verts[i].modulate[3] = (unsigned char)(j->alpha * 255.0); // blend this with the previous junc if(j != trail) { VectorAdd(verts[i].xyz, verts[i - 1].xyz, verts[i].xyz); VectorScale(verts[i].xyz, 0.5, verts[i].xyz); VectorCopy(verts[i].xyz, verts[i - 1].xyz); } else if(j->flags & TJFL_FADEIN) { verts[i].modulate[3] = 0; // fade in } i++; // 2 ---- VectorMA(p, -1 * j->width, up, p); VectorCopy(p, verts[i].xyz); verts[i].st[0] = s; verts[i].st[1] = 0.0; for(k = 0; k < 3; k++) verts[i].modulate[k] = (unsigned char)(j->color[k] * 255.0); verts[i].modulate[3] = (unsigned char)(j->alpha * 255.0); // blend this with the previous junc if(j != trail) { VectorAdd(verts[i].xyz, verts[i - 3].xyz, verts[i].xyz); VectorScale(verts[i].xyz, 0.5, verts[i].xyz); VectorCopy(verts[i].xyz, verts[i - 3].xyz); } else if(j->flags & TJFL_FADEIN) { verts[i].modulate[3] = 0; // fade in } i++; if(trail->sType == STYPE_REPEAT) { s = jNext->sTex; } else { //s += sInc; s += VectorDistance(j->pos, jNext->pos) / sInc; if(s > 1.0) { s = 1.0; } } // 3 ---- VectorMA(jNext->pos, -0.5 * jNext->width, up, p); VectorCopy(p, verts[i].xyz); verts[i].st[0] = s; verts[i].st[1] = 0.0; for(k = 0; k < 3; k++) verts[i].modulate[k] = (unsigned char)(jNext->color[k] * 255.0); verts[i].modulate[3] = (unsigned char)(jNext->alpha * 255.0); i++; // 4 ---- VectorMA(p, jNext->width, up, p); VectorCopy(p, verts[i].xyz); verts[i].st[0] = s; verts[i].st[1] = 1.0; for(k = 0; k < 3; k++) verts[i].modulate[k] = (unsigned char)(jNext->color[k] * 255.0); verts[i].modulate[3] = (unsigned char)(jNext->alpha * 255.0); i++; if(i + 4 > MAX_TRAIL_VERTS) { break; } j = jNext; jNext = j->nextJunc; } if(trail->flags & TJFL_FIXDISTORT) { // build the list of outVerts, by dividing up the QUAD's into 4 Tri's each, so as to allow // any shaped (convex) Quad without bilinear distortion for(k = 0, numOutVerts = 0; k < i; k += 4) { VectorCopy(verts[k].xyz, mid.xyz); mid.st[0] = verts[k].st[0]; mid.st[1] = verts[k].st[1]; for(l = 0; l < 4; l++) { mod[l] = (float)verts[k].modulate[l]; } for(n = 1; n < 4; n++) { VectorAdd(verts[k + n].xyz, mid.xyz, mid.xyz); mid.st[0] += verts[k + n].st[0]; mid.st[1] += verts[k + n].st[1]; for(l = 0; l < 4; l++) { mod[l] += (float)verts[k + n].modulate[l]; } } VectorScale(mid.xyz, 0.25, mid.xyz); mid.st[0] *= 0.25; mid.st[1] *= 0.25; for(l = 0; l < 4; l++) { mid.modulate[l] = (unsigned char)(mod[l] / 4.0); } // now output the tri's for(n = 0; n < 4; n++) { outVerts[numOutVerts++] = verts[k + n]; outVerts[numOutVerts++] = mid; if(n < 3) { outVerts[numOutVerts++] = verts[k + n + 1]; } else { outVerts[numOutVerts++] = verts[k]; } } } if(!(trail->flags & TJFL_NOPOLYMERGE)) { trap_R_AddPolysToScene(trail->shader, 3, &outVerts[0], numOutVerts / 3); } else { int k; for(k = 0; k < numOutVerts / 3; k++) { trap_R_AddPolyToScene(trail->shader, 3, &outVerts[k * 3]); } } } else { // send the polygons // FIXME: is it possible to send a GL_STRIP here? We are actually sending 2x the verts we really need to if(!(trail->flags & TJFL_NOPOLYMERGE)) { trap_R_AddPolysToScene(trail->shader, 4, &verts[0], i / 4); } else { int k; for(k = 0; k < i / 4; k++) { trap_R_AddPolyToScene(trail->shader, 4, &verts[k * 4]); } } } // do we need to make another pass? if(trail->flags & TJFL_CROSSOVER) { if(iteration < 2) { CG_AddTrailToScene(trail, iteration + 1, numJuncs); } } }
void CG_Spotlight( centity_t *cent, float *color, vec3_t realstart, vec3_t lightDir, int segs, float range, int startWidth, float coneAngle, int flags ) { int i, j; vec3_t start, traceEnd, proj; vec3_t right, up; vec3_t v1, v2; vec3_t startvec, endvec; // the vectors to rotate around lightDir to create the circles vec3_t conevec; vec3_t start_points[MAX_SPOT_SEGS], end_points[MAX_SPOT_SEGS]; vec3_t coreright; polyVert_t verts[MAX_SPOT_SEGS * 4]; // x4 for 4 verts per poly polyVert_t plugVerts[MAX_SPOT_SEGS]; vec3_t endCenter; polyVert_t coreverts[4]; trace_t tr; float alpha; float radius = 0.0; // TTimo might be used uninitialized float coreEndRadius; qboolean capStart = qtrue; float hitDist; // the actual distance of the trace impact (0 is no hit) float beamLen; // actual distance of the drawn beam float endAlpha = 0.0; vec4_t colorNorm; // normalized color vector refEntity_t ent; vec3_t angles; VectorCopy( realstart, start ); // normalize color colorNorm[3] = 0; // store normalize multiplier in alpha index for ( i = 0; i < 3; i++ ) { if ( color[i] > colorNorm[3] ) { colorNorm[3] = color[i]; // find largest color value in RGB } } if ( colorNorm[3] != 1 ) { // it needs to be boosted VectorMA( color, 1.0 / colorNorm[3], color, colorNorm ); // FIXME: div by 0 } else { VectorCopy( color, colorNorm ); } colorNorm[3] = color[3]; if ( flags & SL_NOSTARTCAP ) { capStart = qfalse; } if ( startWidth == 0 ) { // cone, not cylinder capStart = qfalse; } if ( flags & SL_LOCKTRACETORANGE ) { VectorMA( start, range, lightDir, traceEnd ); // trace out to 'range' } else { VectorMA( start, MAX_SPOT_RANGE, lightDir, traceEnd ); // trace all the way out to max dist } // first trace to see if anything is hit if ( flags & SL_NOTRACE ) { tr.fraction = 1.0; // force no hit } else { if ( flags & SL_TRACEWORLDONLY ) { CG_Trace( &tr, start, NULL, NULL, traceEnd, -1, CONTENTS_SOLID ); } else { CG_Trace( &tr, start, NULL, NULL, traceEnd, -1, MASK_SHOT ); } // CG_Trace( &tr, start, NULL, NULL, traceEnd, -1, MASK_ALL &~(CONTENTS_MONSTERCLIP|CONTENTS_AREAPORTAL|CONTENTS_CLUSTERPORTAL)); } if ( tr.fraction < 1.0 ) { hitDist = beamLen = MAX_SPOT_RANGE * tr.fraction; if ( beamLen > range ) { beamLen = range; } } else { hitDist = 0; beamLen = range; } if ( flags & SL_LOCKUV ) { if ( beamLen < range ) { endAlpha = 255.0f * ( color[3] - ( color[3] * beamLen / range ) ); } } if ( segs >= MAX_SPOT_SEGS ) { segs = MAX_SPOT_SEGS - 1; } // TODO: adjust segs based on r_lodbias // TODO: move much of this to renderer // model at base if ( cent->currentState.modelindex ) { memset( &ent, 0, sizeof( ent ) ); ent.frame = 0; ent.oldframe = 0; ent.backlerp = 0; VectorCopy( cent->lerpOrigin, ent.origin ); VectorCopy( cent->lerpOrigin, ent.oldorigin ); ent.hModel = cgs.gameModels[cent->currentState.modelindex]; // AnglesToAxis( cent->lerpAngles, ent.axis ); vectoangles( lightDir, angles ); AnglesToAxis( angles, ent.axis ); trap_R_AddRefEntityToScene( &ent ); memcpy( ¢->refEnt, &ent, sizeof( refEntity_t ) ); // push start out a bit so the beam fits to the front of the base model VectorMA( start, 14, lightDir, start ); } //// BEAM PerpendicularVector( up, lightDir ); CrossProduct( lightDir, up, right ); // find first vert of the start VectorScale( right, startWidth, startvec ); // find the first vert of the end RotatePointAroundVector( conevec, up, lightDir, -coneAngle ); VectorMA( startvec, beamLen, conevec, endvec ); // this applies the offset of the start diameter before finding the end points VectorScale( lightDir, beamLen, endCenter ); VectorSubtract( endCenter, endvec, coreverts[3].xyz ); // get a vector of the radius out at the end for the core to use coreEndRadius = VectorLength( coreverts[3].xyz ); #define CORESCALE 0.6f // // generate the flat beam 'core' // if ( !( flags & SL_NOCORE ) ) { VectorSubtract( start, cg.refdef.vieworg, v1 ); VectorNormalize( v1 ); VectorSubtract( traceEnd, cg.refdef.vieworg, v2 ); VectorNormalize( v2 ); CrossProduct( v1, v2, coreright ); VectorNormalize( coreright ); memset( &coreverts[0], 0, 4 * sizeof( polyVert_t ) ); VectorMA( start, startWidth * 0.5f, coreright, coreverts[0].xyz ); VectorMA( start, -startWidth * 0.5f, coreright, coreverts[1].xyz ); VectorMA( endCenter, -coreEndRadius * CORESCALE, coreright, coreverts[2].xyz ); VectorAdd( start, coreverts[2].xyz, coreverts[2].xyz ); VectorMA( endCenter, coreEndRadius * CORESCALE, coreright, coreverts[3].xyz ); VectorAdd( start, coreverts[3].xyz, coreverts[3].xyz ); for ( i = 0; i < 4; i++ ) { coreverts[i].modulate[0] = color[0] * 200.0f; coreverts[i].modulate[1] = color[1] * 200.0f; coreverts[i].modulate[2] = color[2] * 200.0f; coreverts[i].modulate[3] = color[3] * 200.0f; if ( i > 1 ) { coreverts[i].modulate[3] = 0; } } trap_R_AddPolyToScene( cgs.media.spotLightBeamShader, 4, &coreverts[0] ); } // // generate the beam cylinder // for ( i = 0; i <= segs; i++ ) { RotatePointAroundVector( start_points[i], lightDir, startvec, ( 360.0f / (float)segs ) * i ); VectorAdd( start_points[i], start, start_points[i] ); RotatePointAroundVector( end_points[i], lightDir, endvec, ( 360.0f / (float)segs ) * i ); VectorAdd( end_points[i], start, end_points[i] ); } for ( i = 0; i < segs; i++ ) { j = ( i * 4 ); VectorCopy( start_points[i], verts[( i * 4 )].xyz ); verts[j].st[0] = 0; verts[j].st[1] = 1; verts[j].modulate[0] = color[0] * 255.0f; verts[j].modulate[1] = color[1] * 255.0f; verts[j].modulate[2] = color[2] * 255.0f; verts[j].modulate[3] = color[3] * 255.0f; j++; VectorCopy( end_points[i], verts[j].xyz ); verts[j].st[0] = 0; verts[j].st[1] = 0; verts[j].modulate[0] = color[0] * 255.0f; verts[j].modulate[1] = color[1] * 255.0f; verts[j].modulate[2] = color[2] * 255.0f; verts[j].modulate[3] = endAlpha; j++; VectorCopy( end_points[i + 1], verts[j].xyz ); verts[j].st[0] = 1; verts[j].st[1] = 0; verts[j].modulate[0] = color[0] * 255.0f; verts[j].modulate[1] = color[1] * 255.0f; verts[j].modulate[2] = color[2] * 255.0f; verts[j].modulate[3] = endAlpha; j++; VectorCopy( start_points[i + 1], verts[j].xyz ); verts[j].st[0] = 1; verts[j].st[1] = 1; verts[j].modulate[0] = color[0] * 255.0f; verts[j].modulate[1] = color[1] * 255.0f; verts[j].modulate[2] = color[2] * 255.0f; verts[j].modulate[3] = color[3] * 255.0f; if ( capStart ) { VectorCopy( start_points[i], plugVerts[i].xyz ); plugVerts[i].st[0] = 0; plugVerts[i].st[1] = 0; plugVerts[i].modulate[0] = color[0] * 255.0f; plugVerts[i].modulate[1] = color[1] * 255.0f; plugVerts[i].modulate[2] = color[2] * 255.0f; plugVerts[i].modulate[3] = color[3] * 255.0f; } } trap_R_AddPolysToScene( cgs.media.spotLightBeamShader, 4, &verts[0], segs ); // plug up the start circle if ( capStart ) { trap_R_AddPolyToScene( cgs.media.spotLightBeamShader, segs, &plugVerts[0] ); } // show the endpoint if ( !( flags & SL_NOIMPACT ) ) { if ( hitDist ) { VectorMA( startvec, hitDist, conevec, endvec ); alpha = 0.3f; radius = coreEndRadius * ( hitDist / beamLen ); VectorNegate( lightDir, proj ); CG_ImpactMark( cgs.media.spotLightShader, tr.endpos, proj, 0, colorNorm[0], colorNorm[1], colorNorm[2], alpha, qfalse, radius, qtrue, -1 ); } } // add d light at end if ( !( flags & SL_NODLIGHT ) ) { vec3_t dlightLoc; // VectorMA(tr.endpos, -60, lightDir, dlightLoc); // back away from the hit // trap_R_AddLightToScene(dlightLoc, 200, colorNorm[0], colorNorm[1], colorNorm[2], 0); // ,REF_JUNIOR_DLIGHT); VectorMA( tr.endpos, 0, lightDir, dlightLoc ); // back away from the hit // trap_R_AddLightToScene(dlightLoc, radius*2, colorNorm[0], colorNorm[1], colorNorm[2], 0); // ,REF_JUNIOR_DLIGHT); trap_R_AddLightToScene( dlightLoc, radius * 2, 0.3, 0.3, 0.3, 0 ); // ,REF_JUNIOR_DLIGHT); } // draw flare at source if ( !( flags & SL_NOFLARE ) ) { qboolean lightInEyes = qfalse; vec3_t camloc, dirtolight; float dot, deg, dist; float flarescale = 0.0; // TTimo: might be used uninitialized // get camera position and direction to lightsource VectorCopy( cg.snap->ps.origin, camloc ); camloc[2] += cg.snap->ps.viewheight; VectorSubtract( start, camloc, dirtolight ); dist = VectorNormalize( dirtolight ); // first use dot to determine if it's facing the camera dot = DotProduct( lightDir, dirtolight ); // it's facing the camera, find out how closely and trace to see if the source can be seen deg = RAD2DEG( M_PI - acos( dot ) ); if ( deg <= 35 ) { // start flare a bit before the camera gets inside the cylinder lightInEyes = qtrue; flarescale = 1 - ( deg / 35 ); } if ( lightInEyes ) { // the dot check succeeded, now do a trace CG_Trace( &tr, start, NULL, NULL, camloc, -1, MASK_ALL & ~( CONTENTS_MONSTERCLIP | CONTENTS_AREAPORTAL | CONTENTS_CLUSTERPORTAL ) ); if ( tr.fraction != 1 ) { lightInEyes = qfalse; } } if ( lightInEyes ) { float coronasize = flarescale; if ( dist < 512 ) { // make even bigger if you're close enough coronasize *= ( 512.0f / dist ); } trap_R_AddCoronaToScene( start, colorNorm[0], colorNorm[1], colorNorm[2], coronasize, cent->currentState.number, qtrue ); } else { // even though it's off, still need to add it, but turned off so it can fade in/out properly trap_R_AddCoronaToScene( start, colorNorm[0], colorNorm[1], colorNorm[2], 0, cent->currentState.number, qfalse ); } } }