#include "csprogs.h"
#include "cl_video.h"
#include "dpsoftrast.h"
+#include "cl_collision.h"
#ifdef SUPPORTD3D
#include <d3d9.h>
cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1", "draw your weapon model"};
cvar_t r_drawexteriormodel = {0, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
cvar_t r_cullentities_trace = {0, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
+cvar_t r_cullentities_trace_entityocclusion = { 0, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull" };
cvar_t r_cullentities_trace_samples = {0, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"};
cvar_t r_cullentities_trace_tempentitysamples = {0, "r_cullentities_trace_tempentitysamples", "-1", "number of samples to test for entity culling of temp entities (including all CSQC entities), -1 disables trace culling on these entities to prevent flicker (pvs still applies)"};
cvar_t r_cullentities_trace_enlarge = {0, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
cvar_t r_cullentities_trace_delay = {0, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
+cvar_t r_cullentities_trace_eyejitter = {0, "r_cullentities_trace_eyejitter", "16", "randomly offset rays from the eye by this much to reduce the odds of flickering"};
cvar_t r_sortentities = {0, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
cvar_t r_speeds = {0, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
cvar_t r_fullbright = {0, "r_fullbright","0", "makes map very bright and renders faster"};
Cvar_RegisterVariable(&r_draw2d);
Cvar_RegisterVariable(&r_drawworld);
Cvar_RegisterVariable(&r_cullentities_trace);
+ Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
Cvar_RegisterVariable(&r_cullentities_trace_samples);
Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
}
}
-#define MAX_LINEOFSIGHTTRACES 64
-
-static qboolean R_CanSeeBox(int numsamples, vec_t enlarge, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
+qboolean R_CanSeeBox(int numsamples, vec_t eyejitter, vec_t entboxenlarge, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
{
int i;
+ vec3_t eyemins, eyemaxs;
vec3_t boxmins, boxmaxs;
vec3_t start;
vec3_t end;
dp_model_t *model = r_refdef.scene.worldmodel;
+ static vec3_t positions[] = {
+ { 0.5f, 0.5f, 0.5f },
+ { 0.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 1.0f },
+ { 0.0f, 1.0f, 0.0f },
+ { 0.0f, 1.0f, 1.0f },
+ { 1.0f, 0.0f, 0.0f },
+ { 1.0f, 0.0f, 1.0f },
+ { 1.0f, 1.0f, 0.0f },
+ { 1.0f, 1.0f, 1.0f },
+ };
+
+ // sample count can be set to -1 to skip this logic, for flicker-prone objects
+ if (numsamples < 0)
+ return true;
+
+ // view origin is not used for culling in portal/reflection/refraction renders or isometric views
+ if (r_refdef.view.useclipplane || !r_refdef.view.useperspective || r_trippy.integer)
+ return true;
- if (!model || !model->brush.TraceLineOfSight)
+ if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
return true;
+ // expand the eye box a little
+ eyemins[0] = eye[0] - eyejitter;
+ eyemaxs[0] = eye[0] + eyejitter;
+ eyemins[1] = eye[1] - eyejitter;
+ eyemaxs[1] = eye[1] + eyejitter;
+ eyemins[2] = eye[2] - eyejitter;
+ eyemaxs[2] = eye[2] + eyejitter;
// expand the box a little
- boxmins[0] = (enlarge+1) * entboxmins[0] - enlarge * entboxmaxs[0];
- boxmaxs[0] = (enlarge+1) * entboxmaxs[0] - enlarge * entboxmins[0];
- boxmins[1] = (enlarge+1) * entboxmins[1] - enlarge * entboxmaxs[1];
- boxmaxs[1] = (enlarge+1) * entboxmaxs[1] - enlarge * entboxmins[1];
- boxmins[2] = (enlarge+1) * entboxmins[2] - enlarge * entboxmaxs[2];
- boxmaxs[2] = (enlarge+1) * entboxmaxs[2] - enlarge * entboxmins[2];
-
- // return true if eye is inside enlarged box
- if (BoxesOverlap(boxmins, boxmaxs, eye, eye))
+ boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0];
+ boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0];
+ boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1];
+ boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1];
+ boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2];
+ boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2];
+
+ // return true if eye overlaps enlarged box
+ if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
return true;
- // try center
- VectorCopy(eye, start);
- VectorMAM(0.5f, boxmins, 0.5f, boxmaxs, end);
- if (model->brush.TraceLineOfSight(model, start, end))
+ // try specific positions in the box first - note that these can be cached
+ if (r_cullentities_trace_entityocclusion.integer)
+ {
+ for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
+ {
+ VectorCopy(eye, start);
+ end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
+ end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
+ end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
+ //trace_t trace = CL_TraceLine(start, end, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, 0.0f, true, false, NULL, true, true);
+ trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NOMONSTERS, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY);
+ // not picky - if the trace ended anywhere in the box we're good
+ if (BoxesOverlap(trace.endpos, trace.endpos, boxmins, boxmaxs))
+ return true;
+ }
+ }
+ else if (model->brush.TraceLineOfSight(model, start, end, boxmins, boxmaxs))
return true;
// try various random positions
- for (i = 0;i < numsamples;i++)
+ for (i = 0; i < numsamples; i++)
{
+ VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
- if (model->brush.TraceLineOfSight(model, start, end))
+ if (r_cullentities_trace_entityocclusion.integer)
+ {
+ trace_t trace = CL_TraceLine(start, end, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, 0.0f, true, false, NULL, true, true);
+ // not picky - if the trace ended anywhere in the box we're good
+ if (BoxesOverlap(trace.endpos, trace.endpos, boxmins, boxmaxs))
+ return true;
+ }
+ else if (model->brush.TraceLineOfSight(model, start, end, boxmins, boxmaxs))
return true;
}
r_refdef.viewcache.entityvisible[i] = true;
}
}
- if(r_cullentities_trace.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.TraceLineOfSight && !r_refdef.view.useclipplane && !r_trippy.integer)
- // sorry, this check doesn't work for portal/reflection/refraction renders as the view origin is not useful for culling
+ if (r_cullentities_trace.integer)
{
for (i = 0;i < r_refdef.scene.numentities;i++)
{
if (!r_refdef.viewcache.entityvisible[i])
continue;
ent = r_refdef.scene.entities[i];
- if(!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
+ if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
{
- samples = ent->entitynumber ? r_cullentities_trace_samples.integer : r_cullentities_trace_tempentitysamples.integer;
- if (samples < 0)
- continue; // temp entities do pvs only
- if(R_CanSeeBox(samples, r_cullentities_trace_enlarge.value, r_refdef.view.origin, ent->mins, ent->maxs))
+ samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
+ if (R_CanSeeBox(samples, r_cullentities_trace_eyejitter.value, r_cullentities_trace_enlarge.value, r_refdef.view.origin, ent->mins, ent->maxs))
ent->last_trace_visibility = realtime;
- if(ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
+ if (ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
r_refdef.viewcache.entityvisible[i] = 0;
}
}
static texture_t mod_q1bsp_texture_slime;
static texture_t mod_q1bsp_texture_water;
-static qboolean Mod_Q3BSP_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end);
+static qboolean Mod_Q3BSP_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end, const vec3_t acceptmins, const vec3_t acceptmaxs);
void Mod_BrushInit(void)
{
}
}
-static qboolean Mod_Q1BSP_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end)
+static qboolean Mod_Q1BSP_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end, const vec3_t acceptmins, const vec3_t acceptmaxs)
{
trace_t trace;
Mod_Q1BSP_TraceLine(model, NULL, NULL, &trace, start, end, SUPERCONTENTS_VISBLOCKERMASK, 0);
- return trace.fraction == 1;
+ return trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, acceptmins, acceptmaxs);
}
static int Mod_Q1BSP_LightPoint_RecursiveBSPNode(dp_model_t *model, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const mnode_t *node, float x, float y, float startz, float endz)
//Con_Printf("result: ambient %f %f %f diffuse %f %f %f diffusenormal %f %f %f\n", ambientcolor[0], ambientcolor[1], ambientcolor[2], diffusecolor[0], diffusecolor[1], diffusecolor[2], diffusenormal[0], diffusenormal[1], diffusenormal[2]);
}
-static int Mod_Q3BSP_TraceLineOfSight_RecursiveNodeCheck(mnode_t *node, double p1[3], double p2[3])
+static int Mod_Q3BSP_TraceLineOfSight_RecursiveNodeCheck(mnode_t *node, double p1[3], double p2[3], double endpos[3])
{
double t1, t2;
double midf, mid[3];
// or if start is solid and end is empty
// as these degenerate cases usually indicate the eye is in solid and
// should see the target point anyway
- ret = Mod_Q3BSP_TraceLineOfSight_RecursiveNodeCheck(node->children[side ], p1, mid);
+ ret = Mod_Q3BSP_TraceLineOfSight_RecursiveNodeCheck(node->children[side ], p1, mid, endpos);
if (ret != 0)
return ret;
- ret = Mod_Q3BSP_TraceLineOfSight_RecursiveNodeCheck(node->children[side ^ 1], mid, p2);
+ ret = Mod_Q3BSP_TraceLineOfSight_RecursiveNodeCheck(node->children[side ^ 1], mid, p2, endpos);
if (ret != 1)
return ret;
+ VectorCopy(mid, endpos);
return 2;
}
return ((mleaf_t *)node)->clusterindex < 0;
}
-static qboolean Mod_Q3BSP_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end)
+static qboolean Mod_Q3BSP_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end, const vec3_t acceptmins, const vec3_t acceptmaxs)
{
if (model->brush.submodel || mod_q3bsp_tracelineofsight_brushes.integer)
{
trace_t trace;
model->TraceLine(model, NULL, NULL, &trace, start, end, SUPERCONTENTS_VISBLOCKERMASK, 0);
- return trace.fraction == 1;
+ return trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, acceptmins, acceptmaxs);
}
else
{
- double tracestart[3], traceend[3];
+ double tracestart[3], traceend[3], traceendpos[3];
VectorCopy(start, tracestart);
VectorCopy(end, traceend);
- return !Mod_Q3BSP_TraceLineOfSight_RecursiveNodeCheck(model->brush.data_nodes, tracestart, traceend);
+ VectorCopy(end, traceendpos);
+ Mod_Q3BSP_TraceLineOfSight_RecursiveNodeCheck(model->brush.data_nodes, tracestart, traceend, traceendpos);
+ return BoxesOverlap(traceendpos, traceendpos, acceptmins, acceptmaxs);
}
}
return trace.startsupercontents;
}
-qboolean Mod_CollisionBIH_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end)
+qboolean Mod_CollisionBIH_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end, const vec3_t acceptmins, const vec3_t acceptmaxs)
{
trace_t trace;
Mod_CollisionBIH_TraceLine(model, NULL, NULL, &trace, start, end, SUPERCONTENTS_VISBLOCKERMASK, 0);
- return trace.fraction == 1;
+ return trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, acceptmins, acceptmaxs);
}
void Mod_CollisionBIH_TracePoint_Mesh(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, int hitsupercontentsmask, int skipsupercontentsmask)
void (*AmbientSoundLevelsForPoint)(struct model_s *model, const vec3_t p, unsigned char *out, int outsize);
void (*RoundUpToHullSize)(struct model_s *cmodel, const vec3_t inmins, const vec3_t inmaxs, vec3_t outmins, vec3_t outmaxs);
// trace a line of sight through this model (returns false if the line if sight is definitely blocked)
- qboolean (*TraceLineOfSight)(struct model_s *model, const vec3_t start, const vec3_t end);
+ qboolean (*TraceLineOfSight)(struct model_s *model, const vec3_t start, const vec3_t end, const vec3_t acceptmins, const vec3_t acceptmaxs);
char skybox[MAX_QPATH];
void Mod_CollisionBIH_TraceBox(dp_model_t *model, const struct frameblend_s *frameblend, const skeleton_t *skeleton, struct trace_s *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask);
void Mod_CollisionBIH_TraceBrush(dp_model_t *model, const struct frameblend_s *frameblend, const skeleton_t *skeleton, struct trace_s *trace, struct colbrushf_s *start, struct colbrushf_s *end, int hitsupercontentsmask, int skipsupercontentsmask);
void Mod_CollisionBIH_TracePoint_Mesh(dp_model_t *model, const struct frameblend_s *frameblend, const skeleton_t *skeleton, struct trace_s *trace, const vec3_t start, int hitsupercontentsmask, int skipsupercontentsmask);
-qboolean Mod_CollisionBIH_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end);
+qboolean Mod_CollisionBIH_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end, const vec3_t acceptmins, const vec3_t acceptmaxs);
int Mod_CollisionBIH_PointSuperContents(struct model_s *model, int frame, const vec3_t point);
int Mod_CollisionBIH_PointSuperContents_Mesh(struct model_s *model, int frame, const vec3_t point);
bih_t *Mod_MakeCollisionBIH(dp_model_t *model, qboolean userendersurfaces, bih_t *out);
int R_CullBox(const vec3_t mins, const vec3_t maxs);
int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes);
+qboolean R_CanSeeBox(int numsamples, vec_t eyejitter, vec_t entboxenlarge, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs);
#include "r_modules.h"
trace_t SV_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask);
int SV_EntitiesInBox(const vec3_t mins, const vec3_t maxs, int maxedicts, prvm_edict_t **resultedicts);
-qboolean SV_CanSeeBox(int numsamples, vec_t enlarge, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs);
+qboolean SV_CanSeeBox(int numsamples, vec_t eyejitter, vec_t enlarge, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs);
int SV_PointSuperContents(const vec3_t point);
if(snd_spatialization_occlusion.integer & 2)
if(!occluded)
- if(cl.worldmodel && cl.worldmodel->brush.TraceLineOfSight && !cl.worldmodel->brush.TraceLineOfSight(cl.worldmodel, listener_origin, ch->origin))
+ if(cl.worldmodel && cl.worldmodel->brush.TraceLineOfSight && !cl.worldmodel->brush.TraceLineOfSight(cl.worldmodel, listener_origin, ch->origin, ch->origin, ch->origin))
occluded = true;
}
if(occluded)
cvar_t sv_cullentities_trace_delay = {0, "sv_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
cvar_t sv_cullentities_trace_delay_players = {0, "sv_cullentities_trace_delay_players", "0.2", "number of seconds until the entity gets actually culled if it is a player entity"};
cvar_t sv_cullentities_trace_enlarge = {0, "sv_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
+cvar_t sv_cullentities_trace_eyejitter = {0, "sv_cullentities_trace_eyejitter", "16", "jitter the eye by this much for each trace"};
cvar_t sv_cullentities_trace_prediction = {0, "sv_cullentities_trace_prediction", "1", "also trace from the predicted player position"};
cvar_t sv_cullentities_trace_prediction_time = {0, "sv_cullentities_trace_prediction_time", "0.2", "how many seconds of prediction to use"};
cvar_t sv_cullentities_trace_entityocclusion = {0, "sv_cullentities_trace_entityocclusion", "0", "also check if doors and other bsp models are in the way"};
Cvar_RegisterVariable (&sv_cullentities_trace_delay);
Cvar_RegisterVariable (&sv_cullentities_trace_delay_players);
Cvar_RegisterVariable (&sv_cullentities_trace_enlarge);
+ Cvar_RegisterVariable (&sv_cullentities_trace_eyejitter);
Cvar_RegisterVariable (&sv_cullentities_trace_entityocclusion);
Cvar_RegisterVariable (&sv_cullentities_trace_prediction);
Cvar_RegisterVariable (&sv_cullentities_trace_prediction_time);
#define MAX_LINEOFSIGHTTRACES 64
-qboolean SV_CanSeeBox(int numtraces, vec_t enlarge, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
+qboolean SV_CanSeeBox(int numtraces, vec_t eyejitter, vec_t enlarge, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
{
prvm_prog_t *prog = SVVM_prog;
float pitchsign;
float alpha;
float starttransformed[3], endtransformed[3];
+ float boxminstransformed[3], boxmaxstransformed[3];
+ float localboxcenter[3], localboxextents[3], localboxmins[3], localboxmaxs[3];
int blocked = 0;
int traceindex;
int originalnumtouchedicts;
dp_model_t *model;
prvm_edict_t *touch;
static prvm_edict_t *touchedicts[MAX_EDICTS];
+ vec3_t eyemins, eyemaxs, start;
vec3_t boxmins, boxmaxs;
vec3_t clipboxmins, clipboxmaxs;
vec3_t endpoints[MAX_LINEOFSIGHTTRACES];
numtraces = min(numtraces, MAX_LINEOFSIGHTTRACES);
+ // jitter the eye location within this box
+ eyemins[0] = eye[0] - eyejitter;
+ eyemaxs[0] = eye[0] + eyejitter;
+ eyemins[1] = eye[1] - eyejitter;
+ eyemaxs[1] = eye[1] + eyejitter;
+ eyemins[2] = eye[2] - eyejitter;
+ eyemaxs[2] = eye[2] + eyejitter;
// expand the box a little
boxmins[0] = (enlarge+1) * entboxmins[0] - enlarge * entboxmaxs[0];
boxmaxs[0] = (enlarge+1) * entboxmaxs[0] - enlarge * entboxmins[0];
VectorSet(endpoints[traceindex], lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
// calculate sweep box for the entire swarm of traces
- VectorCopy(eye, clipboxmins);
- VectorCopy(eye, clipboxmaxs);
+ VectorCopy(eyemins, clipboxmins);
+ VectorCopy(eyemaxs, clipboxmaxs);
for (traceindex = 0;traceindex < numtraces;traceindex++)
{
clipboxmins[0] = min(clipboxmins[0], endpoints[traceindex][0]);
for (traceindex = 0;traceindex < numtraces;traceindex++)
{
+ VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
// check world occlusion
if (sv.worldmodel && sv.worldmodel->brush.TraceLineOfSight)
- if (!sv.worldmodel->brush.TraceLineOfSight(sv.worldmodel, eye, endpoints[traceindex]))
+ if (!sv.worldmodel->brush.TraceLineOfSight(sv.worldmodel, start, endpoints[traceindex], boxmins, boxmaxs))
continue;
for (touchindex = 0;touchindex < numtouchedicts;touchindex++)
{
Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2], pitchsign * PRVM_serveredictvector(touch, angles)[0], PRVM_serveredictvector(touch, angles)[1], PRVM_serveredictvector(touch, angles)[2], 1);
Matrix4x4_Invert_Simple(&imatrix, &matrix);
// see if the ray hits this entity
- Matrix4x4_Transform(&imatrix, eye, starttransformed);
+ Matrix4x4_Transform(&imatrix, start, starttransformed);
Matrix4x4_Transform(&imatrix, endpoints[traceindex], endtransformed);
- if (!model->brush.TraceLineOfSight(model, starttransformed, endtransformed))
+ Matrix4x4_Transform(&imatrix, boxmins, boxminstransformed);
+ Matrix4x4_Transform(&imatrix, boxmaxs, boxmaxstransformed);
+ // transform the AABB to local space
+ VectorMAM(0.5f, boxminstransformed, 0.5f, boxmaxstransformed, localboxcenter);
+ localboxextents[0] = fabs(boxmaxstransformed[0] - localboxcenter[0]);
+ localboxextents[1] = fabs(boxmaxstransformed[1] - localboxcenter[1]);
+ localboxextents[2] = fabs(boxmaxstransformed[2] - localboxcenter[2]);
+ localboxmins[0] = localboxcenter[0] - localboxextents[0];
+ localboxmins[1] = localboxcenter[1] - localboxextents[1];
+ localboxmins[2] = localboxcenter[2] - localboxextents[2];
+ localboxmaxs[0] = localboxcenter[0] + localboxextents[0];
+ localboxmaxs[1] = localboxcenter[1] + localboxextents[1];
+ localboxmaxs[2] = localboxcenter[2] + localboxextents[2];
+ if (!model->brush.TraceLineOfSight(model, starttransformed, endtransformed, localboxmins, localboxmaxs))
{
blocked++;
break;
{
int eyeindex;
for (eyeindex = 0;eyeindex < sv.writeentitiestoclient_numeyes;eyeindex++)
- if(SV_CanSeeBox(samples, enlarge, sv.writeentitiestoclient_eyes[eyeindex], ed->priv.server->cullmins, ed->priv.server->cullmaxs))
+ if(SV_CanSeeBox(samples, sv_cullentities_trace_eyejitter.value, enlarge, sv.writeentitiestoclient_eyes[eyeindex], ed->priv.server->cullmins, ed->priv.server->cullmaxs))
break;
if(eyeindex < sv.writeentitiestoclient_numeyes)
svs.clients[sv.writeentitiestoclient_clientnumber].visibletime[s->number] =
for(k = 0; k < sv.writeentitiestoclient_numeyes; ++k)
if(eye_levels[k] <= MAX_EYE_RECURSION)
{
- if(SV_CanSeeBox(sv_cullentities_trace_samples.integer, sv_cullentities_trace_enlarge.value, sv.writeentitiestoclient_eyes[k], mi, ma))
+ if(SV_CanSeeBox(sv_cullentities_trace_samples.integer, sv_cullentities_trace_eyejitter.value, sv_cullentities_trace_enlarge.value, sv.writeentitiestoclient_eyes[k], mi, ma))
{
eye_levels[sv.writeentitiestoclient_numeyes] = eye_levels[k] + 1;
VectorCopy(camera_origins[j], sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes]);
vec_t predtime = bound(0, host_client->ping, sv_cullentities_trace_prediction_time.value);
vec3_t predeye;
VectorMA(eye, predtime, PRVM_serveredictvector(camera, velocity), predeye);
- if (SV_CanSeeBox(1, 0, eye, predeye, predeye))
+ if (SV_CanSeeBox(1, 0, 0, eye, predeye, predeye))
{
VectorCopy(predeye, sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes]);
sv.writeentitiestoclient_numeyes++;