+#define MAX_LINEOFSIGHTTRACES 64
+
+qboolean SV_CanSeeBox(int numtraces, vec_t enlarge, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
+{
+ float pitchsign;
+ float alpha;
+ float starttransformed[3], endtransformed[3];
+ int blocked = 0;
+ int traceindex;
+ int originalnumtouchedicts;
+ int numtouchedicts = 0;
+ int touchindex;
+ matrix4x4_t matrix, imatrix;
+ dp_model_t *model;
+ prvm_edict_t *touch;
+ static prvm_edict_t *touchedicts[MAX_EDICTS];
+ vec3_t boxmins, boxmaxs;
+ vec3_t clipboxmins, clipboxmaxs;
+ vec3_t endpoints[MAX_LINEOFSIGHTTRACES];
+
+ numtraces = min(numtraces, MAX_LINEOFSIGHTTRACES);
+
+ // 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];
+
+ VectorMAM(0.5f, boxmins, 0.5f, boxmaxs, endpoints[0]);
+ for (traceindex = 1;traceindex < numtraces;traceindex++)
+ 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);
+ for (traceindex = 0;traceindex < numtraces;traceindex++)
+ {
+ clipboxmins[0] = min(clipboxmins[0], endpoints[traceindex][0]);
+ clipboxmins[1] = min(clipboxmins[1], endpoints[traceindex][1]);
+ clipboxmins[2] = min(clipboxmins[2], endpoints[traceindex][2]);
+ clipboxmaxs[0] = max(clipboxmaxs[0], endpoints[traceindex][0]);
+ clipboxmaxs[1] = max(clipboxmaxs[1], endpoints[traceindex][1]);
+ clipboxmaxs[2] = max(clipboxmaxs[2], endpoints[traceindex][2]);
+ }
+
+ // get the list of entities in the sweep box
+ if (sv_cullentities_trace_entityocclusion.integer)
+ numtouchedicts = World_EntitiesInBox(&sv.world, clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
+ if (numtouchedicts > MAX_EDICTS)
+ {
+ // this never happens
+ Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
+ numtouchedicts = MAX_EDICTS;
+ }
+ // iterate the entities found in the sweep box and filter them
+ originalnumtouchedicts = numtouchedicts;
+ numtouchedicts = 0;
+ for (touchindex = 0;touchindex < originalnumtouchedicts;touchindex++)
+ {
+ touch = touchedicts[touchindex];
+ if (touch->fields.server->solid != SOLID_BSP)
+ continue;
+ model = SV_GetModelFromEdict(touch);
+ if (!model || !model->brush.TraceLineOfSight)
+ continue;
+ // skip obviously transparent entities
+ alpha = PRVM_EDICTFIELDVALUE(touch, prog->fieldoffsets.alpha)->_float;
+ if (alpha && alpha < 1)
+ continue;
+ if ((int)touch->fields.server->effects & EF_ADDITIVE)
+ continue;
+ touchedicts[numtouchedicts++] = touch;
+ }
+
+ // now that we have a filtered list of "interesting" entities, fire each
+ // ray against all of them, this gives us an early-out case when something
+ // is visible (which it often is)
+
+ for (traceindex = 0;traceindex < numtraces;traceindex++)
+ {
+ // check world occlusion
+ if (sv.worldmodel && sv.worldmodel->brush.TraceLineOfSight)
+ if (!sv.worldmodel->brush.TraceLineOfSight(sv.worldmodel, eye, endpoints[traceindex]))
+ continue;
+ for (touchindex = 0;touchindex < numtouchedicts;touchindex++)
+ {
+ touch = touchedicts[touchindex];
+ model = SV_GetModelFromEdict(touch);
+ if(model && model->brush.TraceLineOfSight)
+ {
+ // get the entity matrix
+ pitchsign = SV_GetPitchSign(touch);
+ Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2], pitchsign * touch->fields.server->angles[0], touch->fields.server->angles[1], touch->fields.server->angles[2], 1);
+ Matrix4x4_Invert_Simple(&imatrix, &matrix);
+ // see if the ray hits this entity
+ Matrix4x4_Transform(&imatrix, eye, starttransformed);
+ Matrix4x4_Transform(&imatrix, endpoints[traceindex], endtransformed);
+ if (!model->brush.TraceLineOfSight(model, starttransformed, endtransformed))
+ {
+ blocked++;
+ break;
+ }
+ }
+ }
+ // check if the ray was blocked
+ if (touchindex < numtouchedicts)
+ continue;
+ // return if the ray was not blocked
+ return true;
+ }
+
+ // no rays survived
+ return false;
+}
+