#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;
+}
+
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;
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;
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])
{
|| 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]
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;
// 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
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;
// 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)
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;
// 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)