/* ================ PM_TestPlayerPosition Returns false if the given player position is not valid (in solid) ================ */ qbool PM_TestPlayerPosition (playermove_t *pm, vec3_t pos) { int i; physent_t *pe; vec3_t mins, maxs, offset, test; hull_t *hull; for (i=0 ; i< pm->numphysent ; i++) { pe = &pm->physents[i]; // get the clipping hull if (pe->model) { hull = &pm->physents[i].model->hulls[1]; VectorSubtract (hull->clip_mins, player_mins, offset); VectorAdd (offset, pe->origin, offset); } else { VectorSubtract (pe->mins, player_maxs, mins); VectorSubtract (pe->maxs, player_mins, maxs); hull = CM_HullForBox (mins, maxs); VectorCopy (pe->origin, offset); } VectorSubtract (pos, offset, test); if (CM_HullPointContents (hull, hull->firstclipnode, test) == CONTENTS_SOLID) return false; } return true; }
/* ================ PM_TraceLine ================ */ trace_t PM_TraceLine (playermove_t *pm, vec3_t start, vec3_t end) { trace_t trace, total; vec3_t offset; vec3_t start_l, end_l; hull_t *hull; int i; physent_t *pe; // fill in a default trace memset (&total, 0, sizeof(trace_t)); total.fraction = 1; total.e.entnum = -1; VectorCopy (end, total.endpos); for (i=0 ; i< pm->numphysent ; i++) { pe = &pm->physents[i]; // get the clipping hull if (pe->model) hull = &pm->physents[i].model->hulls[0]; else hull = CM_HullForBox (pe->mins, pe->maxs); // PM_HullForEntity (ent, mins, maxs, offset); VectorCopy (pe->origin, offset); VectorSubtract (start, offset, start_l); VectorSubtract (end, offset, end_l); // trace a line through the apropriate clipping hull trace = CM_HullTrace (hull, start_l, end_l); // fix trace up by the offset VectorAdd (trace.endpos, offset, trace.endpos); if (trace.allsolid) trace.startsolid = true; if (trace.startsolid) trace.fraction = 0; // did we clip the move? if (trace.fraction < total.fraction) { total = trace; total.e.entnum = i; } } return total; }
/* ================ SV_HullForEntity Returns a hull 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. ================ */ hull_t *SV_HullForEntity (edict_t *ent, vec3_t mins, vec3_t maxs, vec3_t offset) { cmodel_t *model; vec3_t size; vec3_t hullmins, hullmaxs; hull_t *hull; // decide which clipping hull to use, based on the size if (ent->v.solid == SOLID_BSP) { // explicit hulls in the BSP model if (ent->v.movetype != MOVETYPE_PUSH) Host_Error ("SOLID_BSP without MOVETYPE_PUSH"); if ((unsigned)ent->v.modelindex >= MAX_MODELS) Host_Error ("SV_HullForEntity: ent.modelindex >= MAX_MODELS"); model = sv.models[(int)ent->v.modelindex]; if (!model) Host_Error ("SOLID_BSP with a non-bsp model"); VectorSubtract (maxs, mins, size); if (size[0] < 3) hull = &model->hulls[0]; else if (size[0] <= 32) hull = &model->hulls[1]; else hull = &model->hulls[2]; // calculate an offset value to center the origin VectorSubtract (hull->clip_mins, mins, offset); VectorAdd (offset, ent->v.origin, offset); } else { // create a temp hull from bounding box sizes VectorSubtract (ent->v.mins, maxs, hullmins); VectorSubtract (ent->v.maxs, mins, hullmaxs); hull = CM_HullForBox (hullmins, hullmaxs); VectorCopy (ent->v.origin, offset); } return hull; }
/* ================ PM_PlayerTrace ================ */ trace_t PM_PlayerTrace (playermove_t *pm, vec3_t start, vec3_t end) { trace_t trace, total; vec3_t offset; vec3_t start_l, end_l; hull_t *hull; int i; physent_t *pe; vec3_t mins, maxs, tracemins, tracemaxs; // fill in a default trace memset (&total, 0, sizeof(trace_t)); total.fraction = 1; total.e.entnum = -1; VectorCopy (end, total.endpos); PM_TraceBounds(start, end, tracemins, tracemaxs); for (i=0 ; i< pm->numphysent ; i++) { pe = &pm->physents[i]; // get the clipping hull if (pe->model) { hull = &pm->physents[i].model->hulls[1]; if (i > 0 && PM_CullTraceBox(tracemins, tracemaxs, pe->origin, pe->model->mins, pe->model->maxs, hull->clip_mins, hull->clip_maxs)) continue; VectorSubtract (hull->clip_mins, player_mins, offset); VectorAdd (offset, pe->origin, offset); } else { VectorSubtract (pe->mins, player_maxs, mins); VectorSubtract (pe->maxs, player_mins, maxs); if (PM_CullTraceBox(tracemins, tracemaxs, pe->origin, mins, maxs, vec3_origin, vec3_origin)) continue; hull = CM_HullForBox (mins, maxs); VectorCopy (pe->origin, offset); } VectorSubtract (start, offset, start_l); VectorSubtract (end, offset, end_l); // rotate start and end into the models frame of reference if (pe->solid == 4 /*SOLID_BSP*/ && (pe->angles[0] || pe->angles[1] || pe->angles[2])) { vec3_t forward, right, up; vec3_t temp; AngleVectors (pe->angles, forward, right, up); VectorCopy (start_l, temp); start_l[0] = DotProduct (temp, forward); start_l[1] = -DotProduct (temp, right); start_l[2] = DotProduct (temp, up); VectorCopy (end_l, temp); end_l[0] = DotProduct (temp, forward); end_l[1] = -DotProduct (temp, right); end_l[2] = DotProduct (temp, up); } // trace a line through the apropriate clipping hull trace = CM_HullTrace (hull, start_l, end_l); // rotate endpos back to world frame of reference if (pe->solid == 4 /*SOLID_BSP*/ && (pe->angles[0] || pe->angles[1] || pe->angles[2])) { vec3_t a; vec3_t forward, right, up; vec3_t temp; if (trace.fraction != 1) { VectorSubtract (vec3_origin, pe->angles, a); AngleVectors (a, forward, right, up); VectorCopy (trace.endpos, temp); trace.endpos[0] = DotProduct (temp, forward); trace.endpos[1] = -DotProduct (temp, right); trace.endpos[2] = DotProduct (temp, up); VectorCopy (trace.plane.normal, temp); trace.plane.normal[0] = DotProduct (temp, forward); trace.plane.normal[1] = -DotProduct (temp, right); trace.plane.normal[2] = DotProduct (temp, up); } } // fix trace up by the offset VectorAdd (trace.endpos, offset, trace.endpos); if (trace.allsolid) trace.startsolid = true; if (trace.startsolid) trace.fraction = 0; // did we clip the move? if (trace.fraction < total.fraction) { total = trace; total.e.entnum = i; } } return total; }