void MOD_TraceLine (hull_t *hull, int num, const vec3_t start_point, const vec3_t end_point, trace_t *trace) { trace->fraction = 1; trace->allsolid = true; SV_RecursiveHullCheck (hull, num, 0, 1, start_point, end_point, trace); }
/* ============== TraceLine TODO: impact on bmodels, monsters ============== */ void TraceLine (vec3_t start, vec3_t end, vec3_t impact) { trace_t trace; memset (&trace, 0, sizeof(trace)); SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, start, end, &trace); VectorCopy (trace.endpos, impact); }
static float pfnTraceModel( physent_t *pe, float *start, float *end, trace_t *trace ) { int old_usehull; vec3_t start_l, end_l; vec3_t offset, temp; qboolean rotated; matrix4x4 matrix; hull_t *hull; old_usehull = clgame.pmove->usehull; clgame.pmove->usehull = 2; hull = PM_HullForBsp( pe, clgame.pmove, offset ); clgame.pmove->usehull = old_usehull; if( pe->solid == SOLID_BSP && !VectorIsNull( pe->angles )) rotated = true; else rotated = false; if( rotated ) { Matrix4x4_CreateFromEntity( matrix, pe->angles, offset, 1.0f ); Matrix4x4_VectorITransform( matrix, start, start_l ); Matrix4x4_VectorITransform( matrix, end, end_l ); } else { VectorSubtract( start, offset, start_l ); VectorSubtract( end, offset, end_l ); } SV_RecursiveHullCheck( hull, hull->firstclipnode, 0, 1, start_l, end_l, trace ); trace->ent = NULL; if( rotated ) { VectorCopy( trace->plane.normal, temp ); Matrix4x4_TransformPositivePlane( matrix, temp, trace->plane.dist, trace->plane.normal, &trace->plane.dist ); } VectorLerp( start, trace->fraction, end, trace->endpos ); return trace->fraction; }
/* ================= TraceLineN ================= */ qboolean TraceLineN (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal) { trace_t trace; memset (&trace, 0, sizeof(trace)); if (!SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, 0, 1, start, end, &trace)) { if (trace.fraction < 1) { VectorCopy (trace.endpos, impact); if (normal) VectorCopy (trace.plane.normal, normal); return true; } } return false; }
/* ================= CL_UpdateTEnts ================= */ void CL_UpdateTEnts (void) { int i; beam_t *b; vec3_t dist, org, beamstart; float d; entity_t *ent; float yaw, pitch; float forward; int j; vec3_t beamend; // qboolean sparks = false; num_temp_entities = 0; // update lightning for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) { if (!b->model || b->endtime < cl.time) continue; // if coming from the player, update the start position if (b->entity == cl.viewentity) { VectorCopy (cl_entities[cl.viewentity].origin, b->start); b->start[2] += cl.crouch + bound(-7, scr_ofsy.value, 4); b->start[2] += bound(0, cl_lightning_zadjust.value, 20);//progs.dat aims from 20 for traceline if (cl_truelightning.value) { vec3_t forward, v, org, ang; float f, delta; trace_t trace; f = fmax(0, fmin(1, cl_truelightning.value)); VectorSubtract (playerbeam_end, cl_entities[cl.viewentity].origin, v); //v[2] -= 22; // adjust for view height v[2] -= cl.crouch; // v[2] -= bound(0, cl_lightning_zadjust.value, 20); vectoangles (v, ang); // lerp pitch ang[0] = -ang[0]; if (ang[0] < -180) ang[0] += 360; ang[0] += (cl.viewangles[0] - ang[0]) * f; // lerp yaw delta = cl.viewangles[1] - ang[1]; if (delta > 180) delta -= 360; if (delta < -180) delta += 360; ang[1] += delta * f; ang[2] = 0; AngleVectors (ang, forward, NULLVEC, NULLVEC); VectorScale(forward, 600, forward); VectorCopy(cl_entities[cl.viewentity].origin, org); org[2] += bound(0, cl_lightning_zadjust.value, 20);//progs.dat aims from 20 for teaceline VectorAdd(org, forward, b->end); memset (&trace, 0, sizeof(trace_t)); if (!SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, 0, 1, org, b->end, &trace)) VectorCopy(trace.endpos, b->end); } } /* // if coming from the player, update the start position if (b->entity == cl.viewentity) { VectorCopy (cl_entities[cl.viewentity].origin, b->start); } */ // calculate pitch and yaw VectorSubtract (b->end, b->start, dist); if (dist[1] == 0 && dist[0] == 0) { yaw = 0; if (dist[2] > 0) pitch = 90; else pitch = 270; } else { yaw = (int) (atan2f(dist[1], dist[0]) * 180 / M_PI); if (yaw < 0) yaw += 360; forward = sqrtf (dist[0]*dist[0] + dist[1]*dist[1]); pitch = (int) (atan2f(dist[2], forward) * 180 / M_PI); if (pitch < 0) pitch += 360; } // add new entities for the lightning VectorCopy(b->start, org); VectorCopy(b->start, beamstart); d = VectorNormalize (dist); VectorScale (dist, 30, dist); if (key_dest == key_game) { for ( ; d > 0 ; d -= 30) { if ((qmb_initialized && r_part_lightning.value) && (!cl.paused)) { VectorAdd(org, dist, beamend); for (j=0 ; j<3 ; j++) beamend[j] += ((rand()%10)-5); QMB_LightningBeam (beamstart, beamend); //if ((r_glowlg.value) && (r_dynamic.value)) // CL_NewDlight (i, beamstart, 100, 0.1, lt_blue); VectorCopy(beamend, beamstart); } else { if (!(ent = CL_NewTempEntity())) return; VectorCopy(org, ent->origin); ent->model = b->model; ent->angles[0] = pitch; ent->angles[1] = yaw; ent->angles[2] = rand() % 360; } VectorAdd(org, dist, org); } } /* // add new entities for the lightning VectorCopy (b->start, org); d = VectorNormalize(dist); while (d > 0) { ent = CL_NewTempEntity (); if (!ent) return; VectorCopy (org, ent->origin); ent->model = b->model; ent->angles[0] = pitch; ent->angles[1] = yaw; ent->angles[2] = rand()%360; for (i=0 ; i<3 ; i++) org[i] += dist[i]*30; d -= 30; } */ } }
float TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal) { trace_t trace; extern cvar_t env_engine; int x; model_t *mod; float shortest; vec3_t newstart, newend; memset (&trace, 0, sizeof(trace)); VectorCopy (end, trace.endpos); trace.fraction = 1; trace.startsolid = true; // if (sv.active) // SV_RecursiveHullCheck (sv.worldmodel->hulls, 0, 0, 1, start, end, &trace); // else if (cl.worldmodel) SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, start, end, &trace); VectorCopy (trace.endpos, impact); VectorCopy (trace.plane.normal, normal); shortest = trace.fraction; VectorCopy (end, trace.endpos); trace.fraction = 1; trace.startsolid = true; for (x = 0; x < traceline_entities; x++) { mod = traceline_entity[x]->model; if (mod->type != mod_brush) continue; if (mod->name[0] != '*') continue; // set up start point // offset the start [0] and [1] points by entity origin to do func_train bmodels // this is positioned above the model to account for moving bmodels (note the "-" in [2]) newstart[0] = start[0] + cl_visedicts[x]->origin[0]; newstart[1] = start[1] + cl_visedicts[x]->origin[1]; newstart[2] = start[2] + cl_visedicts[x]->origin[2]; // set up end point newend[0] = end[0] + cl_visedicts[x]->origin[0]; newend[1] = end[1] + cl_visedicts[x]->origin[1]; newend[2] = end[2] + cl_visedicts[x]->origin[2]; // reset trace memset (&trace, 0, sizeof(trace)); VectorCopy (end, trace.endpos); trace.fraction = 1; trace.startsolid = true; // r = RecursiveLightPoint (mod->nodes + mod->hulls[0].firstclipnode, start, end); SV_RecursiveHullCheck (mod->hulls, mod->hulls[0].firstclipnode, 0, 1, newstart, newend, &trace); // check for shortest path if (trace.fraction < shortest) { shortest = trace.fraction; VectorCopy (trace.endpos, impact); VectorSubtract(trace.endpos, cl_visedicts[x]->origin, trace.endpos); VectorCopy (trace.plane.normal, normal); } VectorCopy (end, trace.endpos); trace.fraction = 1; trace.startsolid = true; } return shortest; }
/* DESCRIPTION: SV_ClipMoveToEntity/SV_SingleClipMoveToEntity // LOCATION: world.c // PATH: Mostly in this file. // // SV_ClipMoveToEntity is a proxy (and only access point) for the next one. // // The function seems to be related to collision detection. */ void SV_SingleClipMoveToEntity(edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, trace_t * Outgoing_Trace) { vec3_t var_c; vec3_t var_18; vec3_t var_24; hull_t * var_28; // int var_2c; int var_30; int var_34; int var_38; vec3_t forward; vec3_t right; vec3_t up; vec3_t var_68; int var_6c; trace_t var_a4; vec3_t var_bc; vec3_t var_c8; vec3_t var_d4; Q_memset(Outgoing_Trace, 0, sizeof(trace_t)); Outgoing_Trace->fraction = 1.0; Outgoing_Trace->allsolid = 1; Outgoing_Trace->endpos[0] = end[0]; Outgoing_Trace->endpos[1] = end[1]; Outgoing_Trace->endpos[2] = end[2]; if(global_sv.models[ent->v.modelindex]->modeltype == 3) { //taken: 1616, -528, 127.97 endpos var_28 = SV_HullForStudioModel(ent, mins, maxs, var_c, &var_30); } else { var_28 = SV_HullForEntity(ent, mins, maxs, var_c); var_30 = 1; //if model? } VectorSubtract(start, var_c, var_18); VectorSubtract(end, var_c, var_24); if((ent->v.solid != SOLID_BSP) || (ent->v.angles[0] == 0 && ent->v.angles[1] == 0 && ent->v.angles[2] == 0)) { //taken var_38 = 0; //rotated prob } else { var_38 = 1; } if(var_38) { //This is another function in QW. AngleVectors(ent->v.angles, forward, right, up); //v.angles is def +58. VectorCopy(var_18, var_68); var_18[0] = DotProduct(var_68, forward); var_18[1] = -DotProduct(var_68, right); var_18[2] = DotProduct(var_68, up); VectorCopy(var_24, var_68); var_24[0] = DotProduct(var_68, forward); var_24[1] = -DotProduct(var_68, right); var_24[2] = DotProduct(var_68, up); } //Curiously enough, I'm taking linear algebra right now. I hate it. //= 20 if(var_30 == 1) { SV_RecursiveHullCheck(var_28, var_28->firstclipnode, 0, 1.0, var_18, var_24, Outgoing_Trace); } else { for(var_6c = 0, var_34 = 0; var_34 < var_30; var_34++) { Q_memset(&var_a4, 0, sizeof(trace_t)); var_a4.fraction = 1.0; var_a4.allsolid = 1; VectorCopy(end, var_a4.endpos); SV_RecursiveHullCheck(&(var_28[var_34]), var_28[var_34].firstclipnode, 0, 1.0, var_18, var_24, &var_a4); if(var_34 != 0 && var_a4.startsolid == 0 && var_a4.allsolid == 0 && var_a4.fraction > Outgoing_Trace->fraction) { continue; } if(Outgoing_Trace->startsolid == 0) { Q_memcpy(Outgoing_Trace, &var_a4, sizeof(trace_t)); } else { Q_memcpy(Outgoing_Trace, &var_a4, sizeof(trace_t)); //Probably could be a bit more efficient here. Outgoing_Trace->startsolid = 1; } var_6c = var_34; } Outgoing_Trace->hitgroup = SV_HitgroupForStudioHull(var_6c); } if(Outgoing_Trace->fraction != 1.0) { if(var_38 != 0) { AngleVectorsTranspose(ent->v.angles, var_68, var_bc, var_c8); VectorCopy(Outgoing_Trace->plane.normal, var_d4); Outgoing_Trace->plane.normal[0] = DotProduct(var_d4, var_68); Outgoing_Trace->plane.normal[1] = -DotProduct(var_d4, var_bc); Outgoing_Trace->plane.normal[2] = DotProduct(var_d4, var_c8); } //Scaling, clearly. Outgoing_Trace->endpos[0] = start[0] + (Outgoing_Trace->fraction * (end[0] - start[0])); Outgoing_Trace->endpos[1] = start[1] + (Outgoing_Trace->fraction * (end[1] - start[1])); Outgoing_Trace->endpos[2] = start[2] + (Outgoing_Trace->fraction * (end[2] - start[2])); } if(Outgoing_Trace->fraction < 1.0 || Outgoing_Trace->startsolid != 0) { Outgoing_Trace->pHit = ent; } }
static qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, const vec3_t p1, const vec3_t p2, trace_t *trace) { mclipnode_t *node; mplane_t *plane; float t1, t2; float frac; int i; vec3_t mid; int side; float midf; // check for empty if (num < 0) { if (num != CONTENTS_SOLID) { trace->allsolid = false; if (num == CONTENTS_EMPTY) trace->inopen = true; else trace->inwater = true; } else trace->startsolid = true; return true; // empty } if (num < hull->firstclipnode || num > hull->lastclipnode) Sys_Error ("SV_RecursiveHullCheck: bad node number"); // // find the point distances // node = hull->clipnodes + num; plane = hull->planes + node->planenum; if (plane->type < 3) { t1 = p1[plane->type] - plane->dist; t2 = p2[plane->type] - plane->dist; } else { t1 = DotProduct (plane->normal, p1) - plane->dist; t2 = DotProduct (plane->normal, p2) - plane->dist; } if (t1 >= 0 && t2 >= 0) return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace); if (t1 < 0 && t2 < 0) return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace); // put the crosspoint DIST_EPSILON pixels on the near side if (t1 < 0) frac = (t1 + DIST_EPSILON)/(t1-t2); else frac = (t1 - DIST_EPSILON)/(t1-t2); if (frac < 0) frac = 0; if (frac > 1) frac = 1; midf = p1f + (p2f - p1f)*frac; for (i=0 ; i<3 ; i++) mid[i] = p1[i] + frac*(p2[i] - p1[i]); side = (t1 < 0); // move up to the node if (!SV_RecursiveHullCheck (hull, node->children[side], p1f, midf, p1, mid, trace) ) return false; if (HullPointContents (hull, node->children[side^1], mid) != CONTENTS_SOLID) // go past the node return SV_RecursiveHullCheck (hull, node->children[side^1], midf, p2f, mid, p2, trace); if (trace->allsolid) return false; // never got out of the solid area //================== // the other side of the node is solid, this is the impact point //================== if (!side) { VectorCopy (plane->normal, trace->plane.normal); trace->plane.dist = plane->dist; } else { VectorSubtract (vec3_origin, plane->normal, trace->plane.normal); trace->plane.dist = -plane->dist; } #if 0 while (HullPointContents (hull, hull->firstclipnode, mid) == CONTENTS_SOLID) { // shouldn't really happen, but does occasionally frac -= 0.1; if (frac < 0) { trace->fraction = midf; VectorCopy (mid, trace->endpos); //Con_DPrintf ("backup past 0\n"); return false; } midf = p1f + (p2f - p1f)*frac; for (i=0 ; i<3 ; i++) mid[i] = p1[i] + frac*(p2[i] - p1[i]); } #endif trace->fraction = midf; VectorCopy (mid, trace->endpos); return false; }
/* ================= CL_UpdateLightning ================= */ void CL_UpdateLightning (void) { int i, j; beam_t *b; vec3_t dist, org, beamstart, beamend; float d, yaw, pitch, forward; entity_t *ent; // qboolean sparks = false; num_temp_entities = 0; // update lightning for (i = 0, b = cl_beams ; i < MAX_BEAMS ; i++, b++) { if (!b->model || BEAM_INACTIVE(b)) continue; // if coming from the player, update the start position if (b->entity == cl.viewentity) { VectorCopy (cl_entities[cl.viewentity].origin, b->start); // joe: using koval's [sons]Quake code b->start[2] += cl.crouch; if (!cls.demorecording && cl_truelightning.value) { vec3_t forward, v, org, ang; float f, delta; trace_t trace; f = bound(0, cl_truelightning.value, 1); VectorSubtract (playerbeam_end, cl_entities[cl.viewentity].origin, v); // v[2] -= 22; // adjust for view height v[2] -= cl.viewheight; // adjust for view height vectoangles (v, ang); // lerp pitch ang[0] = -ang[0]; if (ang[0] < -180) ang[0] += 360; ang[0] += (cl.viewangles[0] - ang[0]) * f; // lerp yaw delta = cl.viewangles[1] - ang[1]; if (delta > 180) delta -= 360; if (delta < -180) delta += 360; ang[1] += delta * f; ang[2] = 0; AngleVectors (ang, forward, NULL, NULL); VectorScale (forward, 600, forward); VectorCopy (cl_entities[cl.viewentity].origin, org); org[2] += 16; VectorAdd(org, forward, b->end); memset (&trace, 0, sizeof(trace_t)); if (!SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, 0, 1, org, b->end, &trace)) VectorCopy (trace.endpos, b->end); } } // calculate pitch and yaw VectorSubtract (b->end, b->start, dist); if (!dist[1] && !dist[0]) { yaw = 0; pitch = (dist[2] > 0) ? 90 : 270; } else { yaw = atan2 (dist[1], dist[0]) * 180 / M_PI; if (yaw < 0) yaw += 360; forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]); pitch = atan2 (dist[2], forward) * 180 / M_PI; if (pitch < 0) pitch += 360; } // add new entities for the lightning VectorCopy (b->start, org); VectorCopy (b->start, beamstart); d = VectorNormalize (dist); VectorScale (dist, 30, dist); for ( ; d > 0 ; d -= 30) { if (qmb_initialized && gl_part_lightning.value) { VectorAdd(org, dist, beamend); for (j=0 ; j<3 ; j++) beamend[j] += (b->entity != cl.viewentity) ? (rand() % 40) - 20 : (rand() % 16) - 8; QMB_LightningBeam (beamstart, beamend); // JT040905 - glowing lightning. CL_NewDlight (i, beamend, 200 + (rand() & 31), 0.1, lt_blue); CL_NewDlight (i, beamstart, 200 + (rand() & 31), 0.1, lt_blue); // end VectorCopy (beamend, beamstart); } else { if (!(ent = CL_NewTempEntity())) return; VectorCopy (org, ent->origin); ent->model = b->model; ent->angles[0] = pitch; ent->angles[1] = yaw; ent->angles[2] = rand() % 360; } #if 0 if (qmb_initialized && gl_part_lightning.value && !sparks) { trace_t trace; memset (&trace, 0, sizeof(trace_t)); if (!SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, 0, 1, org, beamend, &trace)) { byte col[3] = {240, 150, 0}; // change color here 60, 100, 240 QMB_GenSparks (trace.endpos, col, 3, 300, 0.25); // // JT 041105 - add second spark color /* byte col[3] = {255, 204, 0}; // change color here QMB_GenSparks (trace.endpos, col, 2, 300, 0.25); */ // end QMB_Lightning_Splash (trace.endpos); sparks = true; } } #endif VectorAdd(org, dist, org); } } }
void R_DrawParticles (void) { particle_t *p, *kill; float grav; int i; float time2, time3; float time1; float dvel, blend, blend1; float frametime; vec3_t up, right, neworg; float scale, sscale; ParticleEmitter_t *ekill, *emt; if (gl_wireframe.value) return; glFogfv(GL_FOG_COLOR, color_black); //Done in actual function now (stops "triangle effect") - Eradicator glEnable (GL_BLEND); glBlendFunc (GL_ONE, GL_ONE); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER,0.01); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glDepthMask(0); VectorScale (vup, 1, up); VectorScale (vright, 1, right); glMatrixMode(GL_TEXTURE); frametime = cl.time - cl.oldtime; time3 = frametime * 15; time2 = frametime * 10; // 15; time1 = frametime * 5; grav = frametime * sv_gravity.value * 0.05; dvel = 4*frametime; //remove expired emitters for ( ;; ) { ekill = active_emitters; if (ekill && ekill->die < cl.time) { active_emitters = ekill->next; ekill->next = free_emitters; free_emitters = ekill; continue; } break; } //Do the particle logic/drawing for (emt=active_emitters ; emt ; emt=emt->next) { for ( ;; ) { ekill = emt->next; //XYZ if (ekill && (ekill->die < cl.time)) { emt->next = ekill->next; ekill->next = free_emitters; free_emitters = ekill; continue; } break; } if (emt->nexttick < cl.time) { vec3_t length; VectorSubtract(emt->origin, r_refdef.vieworg, length); //dont emit if we are to far away to see it if (Length(length) < 600.0f) { for (i=0; i<emt->count; i++) { InitParticleFromEffect(emt->effect,emt->origin); } } emt->nexttick = cl.time + emt->tick; } } //remove expired particles for ( ;; ) { kill = active_particles; if (kill && kill->die < cl.time) { active_particles = kill->next; kill->next = free_particles; free_particles = kill; continue; } break; } //Do the particle logic/drawing for (p=active_particles ; p ; p=p->next) { for ( ;; ) { kill = p->next; //XYZ if (kill && ((kill->die < cl.time) || (kill->numbounces <= 0))) { p->next = kill->next; kill->next = free_particles; free_particles = kill; continue; } break; } scale = p->size; p->size += p->growspeed*frametime; //calculate color based on life ... blend = (p->die-cl.time)/p->lifetime; blend1 = 1-blend; for (i=0; i<3; i++) { p->color[i] = p->startcolor[i] * blend + p->endcolor[i] * blend1; } if ((p->die - cl.time) < 0.5) { float fade = 2*(p->die - cl.time); glColor4f(p->color[0]*fade, p->color[1]*fade, p->color[2]*fade, fade); } else { glColor3fv(&p->color[0]); } GL_Bind(p->texture); glBlendFunc (p->srcblend, p->dstblend); //Align with velocity if (p->velaligned){ float lscale; VectorCopy (p->vel, up); VectorNormalize(up); CrossProduct(vpn,up,right); VectorNormalize(right); lscale = (Length(p->vel)*p->velscale); VectorScale(up,lscale,up); } else { VectorCopy (vup, up); VectorCopy (vright, right); } glLoadIdentity(); glTranslatef(0.5,0.5,0); glRotatef(p->rot,0,0,1); glTranslatef(-0.5,-0.5,0); sscale = -scale/4; VectorMA(p->org,sscale,up,neworg); VectorMA(neworg,sscale,right,neworg); // draw the particle as two triangles scale /= 2; glBegin(GL_TRIANGLE_FAN); glTexCoord2f (0,0); glVertex3fv (neworg); glTexCoord2f (0,1); glVertex3f (neworg[0] + up[0]*scale, neworg[1] + up[1]*scale, neworg[2] + up[2]*scale); glTexCoord2f (1,1); glVertex3f (neworg[0] + up[0]*scale + right[0]*scale, neworg[1] + up[1]*scale + right[1]*scale, neworg[2] + up[2]*scale + right[2]*scale); glTexCoord2f (1,0); glVertex3f (neworg[0] + right[0]*scale, neworg[1] + right[1]*scale, neworg[2] + right[2]*scale); glEnd(); scale *= 2; //calculate new position/rotation neworg[0] = p->org[0]+p->vel[0]*frametime; neworg[1] = p->org[1]+p->vel[1]*frametime; neworg[2] = p->org[2]+p->vel[2]*frametime; p->rot = p->rot+p->rspeed*frametime; //do collision detection { trace_t trace; float d; memset (&trace, 0, sizeof(trace)); trace.fraction = 1; SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, p->org, neworg, &trace); if (trace.fraction < 1) { vec3_t tangent; //calc reflection vector d = DotProduct (p->vel, trace.plane.normal); VectorMA (p->vel, -2*d, trace.plane.normal, p->vel); VectorScale(p->vel,0.33,p->vel); VectorCopy(trace.endpos,p->org); //XYZ p->numbounces--; if (p->spawn) { CrossProduct(trace.plane.normal,p->vel,tangent); if (p->spawn->align == align_surf) { R_SpawnDecal(p->org, trace.plane.normal, tangent, p->spawn); } else { InitParticleFromEffect(p->spawn, p->org); } } } else { VectorCopy(neworg,p->org); } } for (i=0; i<3; i++) { p->vel[i] += p->gravity[i]*frametime; } for (i=0; i<3; i++) { p->vel[i] *= p->drag[i]; } } glDepthMask(1); glDisable (GL_BLEND); glDisable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER,0.666); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //XYZ glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glFogfv(GL_FOG_COLOR, fog_color); //Done in actual function now (stops "triangle effect") - Eradicator }