845 lines · 18.2 KB · C
RawDownload
// world.c -- world query functions #include "quakedef.h" /* entities never clip against themselves, or their owner line of sight checks trace->crosscontent, but bullets don't */ typedef struct{	vec3_t boxmins, boxmaxs;// enclose the test object along entire move	float *mins, *maxs; // size of the moving object	vec3_t mins2, maxs2; // size when clipping against mosnters	float *start, *end;	trace_t trace;	int type;	edict_t *passedict;} moveclip_t; int SV_HullPointContents (hull_t *hull, int num, vec3_t p); /*=============================================================================== HULL BOXES ===============================================================================*/ static hull_t box_hull;static dclipnode_t box_clipnodes[6];static mplane_t box_planes[6]; /*===================SV_InitBoxHull Set up the planes and clipnodes so that the six floats of a bounding boxcan just be stored out and get a proper hull_t structure.===================*/void SV_InitBoxHull (void){	int i;	int side; 	box_hull.clipnodes = box_clipnodes;	box_hull.planes = box_planes;	box_hull.firstclipnode = 0;	box_hull.lastclipnode = 5; 	for (i=0 ; i<6 ; i++)	{		box_clipnodes[i].planenum = i; 		side = i&1; 		box_clipnodes[i].children[side] = CONTENTS_EMPTY;		if (i != 5)			box_clipnodes[i].children[side^1] = i + 1;		else			box_clipnodes[i].children[side^1] = CONTENTS_SOLID; 		box_planes[i].type = i>>1;		box_planes[i].normal[i>>1] = 1;	} } /*===================SV_HullForBox To keep everything totally uniform, bounding boxes are turned into smallBSP trees instead of being compared directly.===================*/hull_t *SV_HullForBox (vec3_t mins, vec3_t maxs){	box_planes[0].dist = maxs[0];	box_planes[1].dist = mins[0];	box_planes[2].dist = maxs[1];	box_planes[3].dist = mins[1];	box_planes[4].dist = maxs[2];	box_planes[5].dist = mins[2]; 	return &box_hull;} /*================SV_HullForEntity Returns a hull that can be used for testing or clipping an object of mins/maxssize.Offset is filled in to contain the adjustment that must be added to thetesting 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){	model_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)			Sys_Error ("SOLID_BSP without MOVETYPE_PUSH"); 		model = sv.models[ (int)ent->v.modelindex ]; 		if (!model || model->type != mod_brush)			Sys_Error ("MOVETYPE_PUSH 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 = SV_HullForBox (hullmins, hullmaxs); 		VectorCopy (ent->v.origin, offset);	} 	return hull;} /*=============================================================================== ENTITY AREA CHECKING ===============================================================================*/ typedef struct areanode_s{	int axis; // -1 = leaf node	float dist;	struct areanode_s *children[2];	link_t trigger_edicts;	link_t solid_edicts;} areanode_t; #define AREA_DEPTH 4#define AREA_NODES 32 static areanode_t sv_areanodes[AREA_NODES];static int sv_numareanodes; /*===============SV_CreateAreaNode ===============*/areanode_t *SV_CreateAreaNode (int depth, vec3_t mins, vec3_t maxs){	areanode_t *anode;	vec3_t size;	vec3_t mins1, maxs1, mins2, maxs2; 	anode = &sv_areanodes[sv_numareanodes];	sv_numareanodes++; 	ClearLink (&anode->trigger_edicts);	ClearLink (&anode->solid_edicts); 	if (depth == AREA_DEPTH)	{		anode->axis = -1;		anode->children[0] = anode->children[1] = NULL;		return anode;	} 	VectorSubtract (maxs, mins, size);	if (size[0] > size[1])		anode->axis = 0;	else		anode->axis = 1; 	anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);	VectorCopy (mins, mins1);	VectorCopy (mins, mins2);	VectorCopy (maxs, maxs1);	VectorCopy (maxs, maxs2); 	maxs1[anode->axis] = mins2[anode->axis] = anode->dist; 	anode->children[0] = SV_CreateAreaNode (depth+1, mins2, maxs2);	anode->children[1] = SV_CreateAreaNode (depth+1, mins1, maxs1); 	return anode;} /*===============SV_ClearWorld ===============*/void SV_ClearWorld (void){	SV_InitBoxHull (); 	memset (sv_areanodes, 0, sizeof(sv_areanodes));	sv_numareanodes = 0;	SV_CreateAreaNode (0, sv.worldmodel->mins, sv.worldmodel->maxs);} /*===============SV_UnlinkEdict ===============*/void SV_UnlinkEdict (edict_t *ent){	if (!ent->area.prev)		return; // not linked in anywhere	RemoveLink (&ent->area);	ent->area.prev = ent->area.next = NULL;} /*====================SV_TouchLinks====================*/void SV_TouchLinks ( edict_t *ent, areanode_t *node ){	link_t *l, *next;	edict_t *touch;	int old_self, old_other; // touch linked edicts	for (l = node->trigger_edicts.next ; l != &node->trigger_edicts ; l = next)	{		next = l->next;		touch = EDICT_FROM_AREA(l);		if (touch == ent)			continue;		if (!touch->v.touch || touch->v.solid != SOLID_TRIGGER)			continue;		if (ent->v.absmin[0] > touch->v.absmax[0]		|| ent->v.absmin[1] > touch->v.absmax[1]		|| ent->v.absmin[2] > touch->v.absmax[2]		|| ent->v.absmax[0] < touch->v.absmin[0]		|| ent->v.absmax[1] < touch->v.absmin[1]		|| ent->v.absmax[2] < touch->v.absmin[2] )			continue;		old_self = pr_global_struct->self;		old_other = pr_global_struct->other; 		pr_global_struct->self = EDICT_TO_PROG(touch);		pr_global_struct->other = EDICT_TO_PROG(ent);		pr_global_struct->time = sv.time;		PR_ExecuteProgram (touch->v.touch); 		pr_global_struct->self = old_self;		pr_global_struct->other = old_other;	} // recurse down both sides	if (node->axis == -1)		return; 	if ( ent->v.absmax[node->axis] > node->dist )		SV_TouchLinks ( ent, node->children[0] );	if ( ent->v.absmin[node->axis] < node->dist )		SV_TouchLinks ( ent, node->children[1] );} /*===============SV_FindTouchedLeafs ===============*/void SV_FindTouchedLeafs (edict_t *ent, mnode_t *node){	mplane_t *splitplane;	mleaf_t *leaf;	int sides;	int leafnum; 	if (node->contents == CONTENTS_SOLID)		return; // add an efrag if the node is a leaf 	if ( node->contents < 0)	{		if (ent->num_leafs == MAX_ENT_LEAFS)			return; 		leaf = (mleaf_t *)node;		leafnum = leaf - sv.worldmodel->leafs - 1; 		ent->leafnums[ent->num_leafs] = leafnum;		ent->num_leafs++;		return;	} // NODE_MIXED 	splitplane = node->plane;	sides = BOX_ON_PLANE_SIDE(ent->v.absmin, ent->v.absmax, splitplane); // recurse down the contacted sides	if (sides & 1)		SV_FindTouchedLeafs (ent, node->children[0]); 	if (sides & 2)		SV_FindTouchedLeafs (ent, node->children[1]);} /*===============SV_LinkEdict ===============*/void SV_LinkEdict (edict_t *ent, bool touch_triggers){	areanode_t *node; 	if (ent->area.prev)		SV_UnlinkEdict (ent); // unlink from old position 	if (ent == sv.edicts)		return; // don't add the world 	if (ent->free)		return; // set the abs box	VectorAdd (ent->v.origin, ent->v.mins, ent->v.absmin);	VectorAdd (ent->v.origin, ent->v.maxs, ent->v.absmax); //// to make items easier to pick up and allow them to be grabbed off// of shelves, the abs sizes are expanded//	if ((int)ent->v.flags & FL_ITEM)	{		ent->v.absmin[0] -= 15;		ent->v.absmin[1] -= 15;		ent->v.absmax[0] += 15;		ent->v.absmax[1] += 15;	}	else	{ // because movement is clipped an epsilon away from an actual edge,		// we must fully check even when bounding boxes don't quite touch		ent->v.absmin[0] -= 1;		ent->v.absmin[1] -= 1;		ent->v.absmin[2] -= 1;		ent->v.absmax[0] += 1;		ent->v.absmax[1] += 1;		ent->v.absmax[2] += 1;	} // link to PVS leafs	ent->num_leafs = 0;	if (ent->v.modelindex)		SV_FindTouchedLeafs (ent, sv.worldmodel->nodes); 	if (ent->v.solid == SOLID_NOT)		return; // find the first node that the ent's box crosses	node = sv_areanodes;	while (1)	{		if (node->axis == -1)			break;		if (ent->v.absmin[node->axis] > node->dist)			node = node->children[0];		else if (ent->v.absmax[node->axis] < node->dist)			node = node->children[1];		else			break; // crosses the node	} // link it in 	if (ent->v.solid == SOLID_TRIGGER)		InsertLinkBefore (&ent->area, &node->trigger_edicts);	else		InsertLinkBefore (&ent->area, &node->solid_edicts); // if touch_triggers, touch all entities at this node and decend for more	if (touch_triggers)		SV_TouchLinks ( ent, sv_areanodes );} /*=============================================================================== POINT TESTING IN HULLS ===============================================================================*/ /*==================SV_HullPointContents ==================*/int SV_HullPointContents (hull_t *hull, int num, vec3_t p){	float d;	dclipnode_t *node;	mplane_t *plane; 	while (num >= 0)	{		if (num < hull->firstclipnode || num > hull->lastclipnode)			Sys_Error ("SV_HullPointContents: bad node number"); 		node = hull->clipnodes + num;		plane = hull->planes + node->planenum; 		if (plane->type < 3)			d = p[plane->type] - plane->dist;		else			d = DotProduct (plane->normal, p) - plane->dist;		if (d < 0)			num = node->children[1];		else			num = node->children[0];	} 	return num;} /*==================SV_PointContents ==================*/int SV_PointContents (vec3_t p){	int cont; 	cont = SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p);	if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN)		cont = CONTENTS_WATER;	return cont;} int SV_TruePointContents (vec3_t p){	return SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p);} //=========================================================================== /*============SV_TestEntityPosition This could be a lot more efficient...============*/edict_t *SV_TestEntityPosition (edict_t *ent){	trace_t trace; 	trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, 0, ent); 	if (trace.startsolid)		return sv.edicts; 	return NULL;} /*===============================================================================

Lines 1–500 of 845.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t