From ab9e8a37699390a5dc199e4def9cdbaaa59d82cf Mon Sep 17 00:00:00 2001 From: havoc Date: Mon, 17 Oct 2011 17:00:10 +0000 Subject: [PATCH] reworked collision cache to only be used by bouncegrid and only in dynamic mode (static mode no longer causes several heart attacks in the collision cache as it executes many times the regular amount of traces) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@11436 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_collision.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++ cl_collision.h | 1 + collision.c | 112 +++++++++++---------------------------------- collision.h | 3 ++ r_shadow.c | 12 +++-- 5 files changed, 160 insertions(+), 88 deletions(-) diff --git a/cl_collision.c b/cl_collision.c index 8c954066..68298630 100644 --- a/cl_collision.c +++ b/cl_collision.c @@ -938,3 +938,123 @@ finished: #endif return cliptrace; } + +/* +================== +CL_Cache_TraceLine +================== +*/ +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND +trace_t CL_Cache_TraceLineSurfaces(const vec3_t start, const vec3_t pEnd, int type, int hitsupercontentsmask) +#else +trace_t CL_Cache_TraceLineSurfaces(const vec3_t start, const vec3_t end, int type, int hitsupercontentsmask) +#endif +{ + int i; + prvm_edict_t *touch; + trace_t trace; + // bounding box of entire move area + vec3_t clipboxmins, clipboxmaxs; + // start and end origin of move + vec3_t clipstart, clipend; + // trace results + trace_t cliptrace; + // matrices to transform into/out of other entity's space + matrix4x4_t matrix, imatrix; + // model of other entity + dp_model_t *model; + // list of entities to test for collisions + int numtouchedicts; + static prvm_edict_t *touchedicts[MAX_EDICTS]; +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND + vec3_t end; + vec_t len = 0; + + if(collision_endposnudge.value > 0 && !VectorCompare(start, pEnd)) + { + // TRICK: make the trace 1 qu longer! + VectorSubtract(pEnd, start, end); + len = VectorNormalizeLength(end); + VectorMA(pEnd, collision_endposnudge.value, end, end); + } + else + VectorCopy(pEnd, end); +#endif + + VectorCopy(start, clipstart); + VectorCopy(end, clipend); +#if COLLISIONPARANOID >= 3 + Con_Printf("move(%f %f %f,%f %f %f)", clipstart[0], clipstart[1], clipstart[2], clipend[0], clipend[1], clipend[2]); +#endif + + // clip to world + Collision_Cache_ClipLineToWorldSurfaces(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask); + cliptrace.bmodelstartsolid = cliptrace.startsolid; + if (cliptrace.startsolid || cliptrace.fraction < 1) + cliptrace.ent = prog ? prog->edicts : NULL; + if (type == MOVE_WORLDONLY) + goto finished; + + // create the bounding box of the entire move + for (i = 0;i < 3;i++) + { + clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) - 1; + clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + 1; + } + + // if the passedict is world, make it NULL (to avoid two checks each time) + // this checks prog because this function is often called without a CSQC + // VM context + + // collide against network entities + for (i = 0;i < cl.num_brushmodel_entities;i++) + { + entity_render_t *ent = &cl.entities[cl.brushmodel_entities[i]].render; + if (!BoxesOverlap(clipboxmins, clipboxmaxs, ent->mins, ent->maxs)) + continue; + Collision_Cache_ClipLineToGenericEntitySurfaces(&trace, ent->model, &ent->matrix, &ent->inversematrix, start, end, hitsupercontentsmask); + Collision_CombineTraces(&cliptrace, &trace, NULL, true); + } + + // clip to entities + // because this uses World_EntitiestoBox, we know all entity boxes overlap + // the clip region, so we can skip culling checks in the loop below + // note: if prog is NULL then there won't be any linked entities + numtouchedicts = 0; + if (prog != NULL) + { + numtouchedicts = World_EntitiesInBox(&cl.world, clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts); + if (numtouchedicts > MAX_EDICTS) + { + // this never happens + Con_Printf("CL_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS); + numtouchedicts = MAX_EDICTS; + } + } + for (i = 0;i < numtouchedicts;i++) + { + touch = touchedicts[i]; + // might interact, so do an exact clip + // only hit entity models, not collision shapes + model = CL_GetModelFromEdict(touch); + if (!model) + continue; + // animated models are too slow to collide against and can't be cached + if (touch->priv.server->frameblend || touch->priv.server->skeleton.relativetransforms) + continue; + if (type == MOVE_NOMONSTERS && PRVM_clientedictfloat(touch, solid) != SOLID_BSP) + continue; + Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_clientedictvector(touch, origin)[0], PRVM_clientedictvector(touch, origin)[1], PRVM_clientedictvector(touch, origin)[2], PRVM_clientedictvector(touch, angles)[0], PRVM_clientedictvector(touch, angles)[1], PRVM_clientedictvector(touch, angles)[2], 1); + Matrix4x4_Invert_Simple(&imatrix, &matrix); + Collision_Cache_ClipLineToGenericEntitySurfaces(&trace, model, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask); + Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_clientedictfloat(touch, solid) == SOLID_BSP); + } + +finished: +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND + if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0) + Collision_ShortenTrace(&cliptrace, len / (len + collision_endposnudge.value), pEnd); +#endif + return cliptrace; +} + diff --git a/cl_collision.h b/cl_collision.h index 27ce51be..851502cf 100644 --- a/cl_collision.h +++ b/cl_collision.h @@ -13,6 +13,7 @@ int CL_GenericHitSuperContentsMask(const prvm_edict_t *edict); trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities); trace_t CL_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities, qboolean hitsurfaces); trace_t CL_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int hitsupercontentsmask, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities); +trace_t CL_Cache_TraceLineSurfaces(const vec3_t start, const vec3_t end, int type, int hitsupercontentsmask); #define CL_PointSuperContents(point) (CL_TracePoint((point), sv_gameplayfix_swiminbmodels.integer ? MOVE_NOMONSTERS : MOVE_WORLDONLY, NULL, 0, true, false, NULL, false).startsupercontents) #endif diff --git a/collision.c b/collision.c index cf0d527f..e0cc37dd 100644 --- a/collision.c +++ b/collision.c @@ -1671,17 +1671,8 @@ typedef struct collision_cachedtrace_parameters_s dp_model_t *model; vec3_t end; vec3_t start; - vec3_t mins; - vec3_t maxs; -// const frameblend_t *frameblend; -// const skeleton_t *skeleton; -// matrix4x4_t inversematrix; int hitsupercontentsmask; - int type; // which type of query produced this cache entry matrix4x4_t matrix; - vec3_t bodymins; - vec3_t bodymaxs; - int bodysupercontents; } collision_cachedtrace_parameters_t; @@ -1810,7 +1801,7 @@ static unsigned int Collision_Cache_HashIndexForArray(unsigned int *array, unsig return hashindex; } -static collision_cachedtrace_t *Collision_Cache_Lookup(int type, dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontentsmask) +static collision_cachedtrace_t *Collision_Cache_Lookup(dp_model_t *model, const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, const vec3_t start, const vec3_t end, int hitsupercontentsmask) { int hashindex = 0; unsigned int fullhashindex; @@ -1823,28 +1814,18 @@ static collision_cachedtrace_t *Collision_Cache_Lookup(int type, dp_model_t *mod collision_cachedtrace_t *cached = collision_cachedtrace_array + index; collision_cachedtrace_parameters_t params; // all non-cached traces use the same index - if ((frameblend && frameblend[0].lerp != 1) || (skeleton && skeleton->relativetransforms)) - r_refdef.stats.collisioncache_animated++; - else if (!collision_cache.integer) + if (!collision_cache.integer) r_refdef.stats.collisioncache_traced++; else { // cached trace lookup memset(¶ms, 0, sizeof(params)); - params.type = type; params.model = model; - VectorCopy(bodymins, params.bodymins); - VectorCopy(bodymaxs, params.bodymaxs); - params.bodysupercontents = bodysupercontents; VectorCopy(start, params.start); - VectorCopy(mins, params.mins); - VectorCopy(maxs, params.maxs); VectorCopy(end, params.end); params.hitsupercontentsmask = hitsupercontentsmask; params.matrix = *matrix; - //params.inversematrix = *inversematrix; fullhashindex = Collision_Cache_HashIndexForArray((unsigned int *)¶ms, sizeof(params) / sizeof(unsigned int)); - //fullhashindex = Collision_Cache_HashIndexForArray((unsigned int *)¶ms, 10); hashindex = (int)(fullhashindex % (unsigned int)collision_cachedtrace_hashsize); for (index = hash[hashindex];index;index = arraynext[index]) { @@ -1859,20 +1840,6 @@ static collision_cachedtrace_t *Collision_Cache_Lookup(int type, dp_model_t *mod || cached->p.start[0] != params.start[0] || cached->p.start[1] != params.start[1] || cached->p.start[2] != params.start[2] - || cached->p.mins[0] != params.mins[0] - || cached->p.mins[1] != params.mins[1] - || cached->p.mins[2] != params.mins[2] - || cached->p.maxs[0] != params.maxs[0] - || cached->p.maxs[1] != params.maxs[1] - || cached->p.maxs[2] != params.maxs[2] - || cached->p.type != params.type - || cached->p.bodysupercontents != params.bodysupercontents - || cached->p.bodymins[0] != params.bodymins[0] - || cached->p.bodymins[1] != params.bodymins[1] - || cached->p.bodymins[2] != params.bodymins[2] - || cached->p.bodymaxs[0] != params.bodymaxs[0] - || cached->p.bodymaxs[1] != params.bodymaxs[1] - || cached->p.bodymaxs[2] != params.bodymaxs[2] || cached->p.hitsupercontentsmask != params.hitsupercontentsmask || cached->p.matrix.m[0][0] != params.matrix.m[0][0] || cached->p.matrix.m[0][1] != params.matrix.m[0][1] @@ -1938,16 +1905,38 @@ static collision_cachedtrace_t *Collision_Cache_Lookup(int type, dp_model_t *mod return cached; } -void Collision_ClipToGenericEntity(trace_t *trace, dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontentsmask) +void Collision_Cache_ClipLineToGenericEntitySurfaces(trace_t *trace, dp_model_t *model, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t end, int hitsupercontentsmask) { - float starttransformed[3], endtransformed[3]; - collision_cachedtrace_t *cached = Collision_Cache_Lookup(3, model, frameblend, skeleton, bodymins, bodymaxs, bodysupercontents, matrix, inversematrix, start, mins, maxs, end, hitsupercontentsmask); + collision_cachedtrace_t *cached = Collision_Cache_Lookup(model, matrix, inversematrix, start, end, hitsupercontentsmask); + if (cached->valid) + { + *trace = cached->result; + return; + } + + Collision_ClipLineToGenericEntity(trace, model, NULL, NULL, vec3_origin, vec3_origin, 0, matrix, inversematrix, start, end, hitsupercontentsmask, true); + + cached->result = *trace; +} + +void Collision_Cache_ClipLineToWorldSurfaces(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t end, int hitsupercontents) +{ + collision_cachedtrace_t *cached = Collision_Cache_Lookup(model, &identitymatrix, &identitymatrix, start, end, hitsupercontents); if (cached->valid) { *trace = cached->result; return; } + Collision_ClipLineToWorld(trace, model, start, end, hitsupercontents, true); + + cached->result = *trace; +} + +void Collision_ClipToGenericEntity(trace_t *trace, dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontentsmask) +{ + float starttransformed[3], endtransformed[3]; + memset(trace, 0, sizeof(*trace)); trace->fraction = trace->realfraction = 1; @@ -1987,19 +1976,10 @@ void Collision_ClipToGenericEntity(trace_t *trace, dp_model_t *model, const fram // transform plane // NOTE: this relies on plane.dist being directly after plane.normal Matrix4x4_TransformPositivePlane(matrix, trace->plane.normal[0], trace->plane.normal[1], trace->plane.normal[2], trace->plane.dist, trace->plane.normal); - - cached->result = *trace; } void Collision_ClipToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontents) { - collision_cachedtrace_t *cached = Collision_Cache_Lookup(3, model, NULL, NULL, vec3_origin, vec3_origin, 0, &identitymatrix, &identitymatrix, start, mins, maxs, end, hitsupercontents); - if (cached->valid) - { - *trace = cached->result; - return; - } - memset(trace, 0, sizeof(*trace)); trace->fraction = trace->realfraction = 1; // ->TraceBox: TraceBrush not needed here, as worldmodel is never rotated @@ -2008,20 +1988,11 @@ void Collision_ClipToWorld(trace_t *trace, dp_model_t *model, const vec3_t start trace->fraction = bound(0, trace->fraction, 1); trace->realfraction = bound(0, trace->realfraction, 1); VectorLerp(start, trace->fraction, end, trace->endpos); - - cached->result = *trace; } void Collision_ClipLineToGenericEntity(trace_t *trace, dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t end, int hitsupercontentsmask, qboolean hitsurfaces) { float starttransformed[3], endtransformed[3]; - collision_cachedtrace_t *cached = Collision_Cache_Lookup(2, model, frameblend, skeleton, bodymins, bodymaxs, bodysupercontents, matrix, inversematrix, start, vec3_origin, vec3_origin, end, hitsupercontentsmask); - if (cached->valid) - { - *trace = cached->result; - return; - } - memset(trace, 0, sizeof(*trace)); trace->fraction = trace->realfraction = 1; @@ -2044,19 +2015,10 @@ void Collision_ClipLineToGenericEntity(trace_t *trace, dp_model_t *model, const // transform plane // NOTE: this relies on plane.dist being directly after plane.normal Matrix4x4_TransformPositivePlane(matrix, trace->plane.normal[0], trace->plane.normal[1], trace->plane.normal[2], trace->plane.dist, trace->plane.normal); - - cached->result = *trace; } void Collision_ClipLineToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t end, int hitsupercontents, qboolean hitsurfaces) { - collision_cachedtrace_t *cached = Collision_Cache_Lookup(2, model, NULL, NULL, vec3_origin, vec3_origin, 0, &identitymatrix, &identitymatrix, start, vec3_origin, vec3_origin, end, hitsupercontents); - if (cached->valid) - { - *trace = cached->result; - return; - } - memset(trace, 0, sizeof(*trace)); trace->fraction = trace->realfraction = 1; if (model && model->TraceLineAgainstSurfaces && hitsurfaces) @@ -2066,20 +2028,11 @@ void Collision_ClipLineToWorld(trace_t *trace, dp_model_t *model, const vec3_t s trace->fraction = bound(0, trace->fraction, 1); trace->realfraction = bound(0, trace->realfraction, 1); VectorLerp(start, trace->fraction, end, trace->endpos); - - cached->result = *trace; } void Collision_ClipPointToGenericEntity(trace_t *trace, dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, int hitsupercontentsmask) { float starttransformed[3]; - collision_cachedtrace_t *cached = Collision_Cache_Lookup(1, model, frameblend, skeleton, bodymins, bodymaxs, bodysupercontents, matrix, inversematrix, start, vec3_origin, vec3_origin, start, hitsupercontentsmask); - if (cached->valid) - { - *trace = cached->result; - return; - } - memset(trace, 0, sizeof(*trace)); trace->fraction = trace->realfraction = 1; @@ -2097,26 +2050,15 @@ void Collision_ClipPointToGenericEntity(trace_t *trace, dp_model_t *model, const // transform plane // NOTE: this relies on plane.dist being directly after plane.normal Matrix4x4_TransformPositivePlane(matrix, trace->plane.normal[0], trace->plane.normal[1], trace->plane.normal[2], trace->plane.dist, trace->plane.normal); - - cached->result = *trace; } void Collision_ClipPointToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, int hitsupercontents) { - collision_cachedtrace_t *cached = Collision_Cache_Lookup(1, model, NULL, NULL, vec3_origin, vec3_origin, 0, &identitymatrix, &identitymatrix, start, vec3_origin, vec3_origin, start, hitsupercontents); - if (cached->valid) - { - *trace = cached->result; - return; - } - memset(trace, 0, sizeof(*trace)); trace->fraction = trace->realfraction = 1; if (model && model->TracePoint) model->TracePoint(model, NULL, NULL, trace, start, hitsupercontents); VectorCopy(start, trace->endpos); - - cached->result = *trace; } void Collision_CombineTraces(trace_t *cliptrace, const trace_t *trace, void *touch, qboolean isbmodel) diff --git a/collision.h b/collision.h index 919e9dcd..5e0a4ba0 100644 --- a/collision.h +++ b/collision.h @@ -160,6 +160,9 @@ void Collision_ClipPointToGenericEntity(trace_t *trace, dp_model_t *model, const void Collision_ClipToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontents); void Collision_ClipLineToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t end, int hitsupercontents, qboolean hitsurfaces); void Collision_ClipPointToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, int hitsupercontents); +// caching surface trace for renderer (NOT THREAD SAFE) +void Collision_Cache_ClipLineToGenericEntitySurfaces(trace_t *trace, dp_model_t *model, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t end, int hitsupercontentsmask); +void Collision_Cache_ClipLineToWorldSurfaces(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t end, int hitsupercontents); // combines data from two traces: // merges contents flags, startsolid, allsolid, inwater // updates fraction, endpos, plane and surface info if new fraction is shorter diff --git a/r_shadow.c b/r_shadow.c index 020a35b4..f48621e5 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -2702,10 +2702,16 @@ void R_Shadow_UpdateBounceGridTexture(void) r_refdef.stats.bouncegrid_traces++; //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask); //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask); - //if (settings.staticmode) - // Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask, true); - //else + if (settings.staticmode) + { + // static mode fires a LOT of rays but none of them are identical, so they are not cached cliptrace = CL_TraceLine(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, true, false, NULL, true, true); + } + else + { + // dynamic mode fires many rays and most will match the cache from the previous frame + cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask); + } if (bouncecount > 0 || settings.includedirectlighting) { // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ) -- 2.39.2