/* =========== CG_FreeTrailJunc =========== */ void CG_FreeTrailJunc( trailJunc_t *junc ) { // kill any juncs after us, so they aren't left hanging if (junc->nextJunc) CG_KillTrail( junc ); // make it non-active junc->inuse = qfalse; junc->freed = qtrue; if (junc->nextGlobal) junc->nextGlobal->prevGlobal = junc->prevGlobal; if (junc->prevGlobal) junc->prevGlobal->nextGlobal = junc->nextGlobal; if (junc == activeTrails) activeTrails = junc->nextGlobal; // if it's a head, remove it if (junc == headTrails) headTrails = junc->nextHead; if (junc->nextHead) junc->nextHead->prevHead = junc->prevHead; if (junc->prevHead) junc->prevHead->nextHead = junc->nextHead; junc->nextHead = NULL; junc->prevHead = NULL; // stick it in the free list junc->prevGlobal = NULL; junc->nextGlobal = freeTrails; if (freeTrails) freeTrails->prevGlobal = junc; freeTrails = junc; numTrailsInuse--; }
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); } } }