int SV_PointContents(const CVec3 &p) { guard(SV_PointContents); // get base contents from world unsigned contents = CM_PointContents(p, 0); contents |= CM_PointModelContents(p); edict_t *list[MAX_EDICTS]; int num = SV_AreaEdicts(p, p, ARRAY_ARG(list), AREA_SOLID); for (int i = 0; i < num; i++) { edict_t *edict = list[i]; entityHull_t &ent = ents[NUM_FOR_EDICT(edict)]; if (ent.model) contents |= CM_TransformedPointContents(p, ent.model->headnode, edict->s.origin, ent.axis); else contents |= CM_TransformedPointContents(p, CM_HeadnodeForBox(ent.bounds), edict->s.origin, nullVec3); } return contents; unguard; }
/* ================ SV_HullForEntity Returns a headnode that can be used for testing or clipping an object of mins/maxs size. ================ */ static mnode_t *SV_HullForEntity(edict_t *ent) { if (ent->solid == SOLID_BSP) { int i = ent->s.modelindex - 1; // explicit hulls in the BSP model if (i <= 0 || i >= sv.cm.cache->nummodels) Com_Error(ERR_DROP, "%s: inline model %d out of range", __func__, i); return sv.cm.cache->models[i].headnode; } // create a temp hull from bounding box sizes return CM_HeadnodeForBox(ent->mins, ent->maxs); }
/* * ================ SV_HullForEntity * * Returns a headnode that can be used for testing or clipping an object of * mins/maxs size. Offset is filled in to contain the adjustment that must be * added to the testing object's origin to get a point to use with the * returned hull. ================ */ int SV_HullForEntity(edict_t * ent) { cmodel_t *model; /* decide which clipping hull to use, based on the size */ if (ent->solid == SOLID_BSP) { /* explicit hulls in the BSP model */ model = sv.models[ent->s.modelindex]; if (!model) Com_Error(ERR_FATAL, "MOVETYPE_PUSH with a non bsp model"); return model->headnode; } /* create a temp hull from bounding box sizes */ return CM_HeadnodeForBox(ent->mins, ent->maxs); }
/** * @brief Returns a headnode that can be used for testing or clipping an * object of mins/maxs size. * Offset is filled in to contain the adjustment that must be added to the * testing object's origin to get a point to use with the returned hull. * @param[in] le The local entity to get the bmodel from * @param[out] tile The maptile the bmodel belongs, too * @param[out] rmaShift the shift vector in case of an RMA (needed for doors) * @param[out] angles The rotation of the entity (in case of bmodels) * @return The headnode for the local entity * @sa SV_HullForEntity */ static int32_t CL_HullForEntity (const le_t* le, int* tile, vec3_t rmaShift, vec3_t angles) { /* special case for bmodels */ if (le->contents & CONTENTS_SOLID) { const cBspModel_t* model = LE_GetClipModel(le); /* special value for bmodel */ if (!model) Com_Error(ERR_DROP, "CL_HullForEntity: Error - le with nullptr bmodel (%i)\n", le->type); *tile = model->tile; VectorCopy(le->angles, angles); VectorCopy(model->shift, rmaShift); return model->headnode; } else { /* might intersect, so do an exact clip */ *tile = 0; VectorCopy(vec3_origin, angles); VectorCopy(vec3_origin, rmaShift); return CM_HeadnodeForBox(cl.mapTiles->mapTiles[*tile], le->aabb); } }
static void SV_ClipMoveToEntities(trace_t &trace, const CVec3 &start, const CVec3 &end, const CBox &bounds, edict_t *passedict, int contentmask) { guard(SV_ClipMoveToEntities); if (trace.allsolid) return; int i; CVec3 amins, amaxs; for (i = 0; i < 3; i++) { if (start[i] < end[i]) { amins[i] = bounds.mins[i] + start[i]; amaxs[i] = bounds.maxs[i] + end[i]; } else { amins[i] = bounds.mins[i] + end[i]; amaxs[i] = bounds.maxs[i] + start[i]; } } edict_t *list[MAX_EDICTS]; int num = SV_AreaEdicts(amins, amaxs, ARRAY_ARG(list), AREA_SOLID); if (!num) return; float b1 = dot(bounds.mins, bounds.mins); float b2 = dot(bounds.maxs, bounds.maxs); float t = max(b1, b2); float traceWidth = SQRTFAST(t); CVec3 traceDir; VectorSubtract(end, start, traceDir); float traceLen = traceDir.Normalize() + traceWidth; for (i = 0; i < num; i++) { edict_t *edict = list[i]; entityHull_t &ent = ents[NUM_FOR_EDICT(edict)]; // if (!ent->linked) continue; if (edict->solid == SOLID_NOT || edict == passedict) continue; if (passedict) { if (edict->owner == passedict) continue; // don't clip against own missiles if (passedict->owner == edict) continue; // don't clip against owner } if (!(contentmask & CONTENTS_DEADMONSTER) && (edict->svflags & SVF_DEADMONSTER)) continue; CVec3 eCenter; VectorSubtract(ent.center, start, eCenter); // check position of point projection on line float entPos = dot(eCenter, traceDir); if (entPos < -traceWidth - ent.radius || entPos > traceLen + ent.radius) continue; // too near / too far // check distance between point and line CVec3 tmp; VectorMA(eCenter, -entPos, traceDir, tmp); float dist2 = dot(tmp, tmp); float dist0 = ent.radius + traceWidth; if (dist2 >= dist0 * dist0) continue; trace_t tr; if (ent.model) CM_TransformedBoxTrace(tr, start, end, bounds, ent.model->headnode, contentmask, edict->s.origin, ent.axis); else CM_TransformedBoxTrace(tr, start, end, bounds, CM_HeadnodeForBox(ent.bounds), contentmask, edict->s.origin, nullVec3); if (CM_CombineTrace(trace, tr)) trace.ent = edict; if (trace.allsolid) return; } unguard; }