/* | |
Copyright (C) 1996-1997 Id Software, Inc. | |
This program is free software; you can redistribute it and/or | |
modify it under the terms of the GNU General Public License | |
as published by the Free Software Foundation; either version 2 | |
of the License, or (at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
See the GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program; if not, write to the Free Software | |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
*/ | |
// r_efrag.c | |
#include "quakedef.h" | |
#include "r_local.h" | |
mnode_t *r_pefragtopnode; | |
//=========================================================================== | |
/* | |
=============================================================================== | |
ENTITY FRAGMENT FUNCTIONS | |
=============================================================================== | |
*/ | |
efrag_t **lastlink; | |
vec3_t r_emins, r_emaxs; | |
entity_t *r_addent; | |
/* | |
================ | |
R_RemoveEfrags | |
Call when removing an object from the world or moving it to another position | |
================ | |
*/ | |
void R_RemoveEfrags (entity_t *ent) | |
{ | |
efrag_t *ef, *old, *walk, **prev; | |
ef = ent->efrag; | |
while (ef) | |
{ | |
prev = &ef->leaf->efrags; | |
while (1) | |
{ | |
walk = *prev; | |
if (!walk) | |
break; | |
if (walk == ef) | |
{ // remove this fragment | |
*prev = ef->leafnext; | |
break; | |
} | |
else | |
prev = &walk->leafnext; | |
} | |
old = ef; | |
ef = ef->entnext; | |
// put it on the free list | |
old->entnext = cl.free_efrags; | |
cl.free_efrags = old; | |
} | |
ent->efrag = NULL; | |
} | |
/* | |
=================== | |
R_SplitEntityOnNode | |
=================== | |
*/ | |
void R_SplitEntityOnNode (mnode_t *node) | |
{ | |
efrag_t *ef; | |
mplane_t *splitplane; | |
mleaf_t *leaf; | |
int sides; | |
if (node->contents == CONTENTS_SOLID) | |
{ | |
return; | |
} | |
// add an efrag if the node is a leaf | |
if ( node->contents < 0) | |
{ | |
if (!r_pefragtopnode) | |
r_pefragtopnode = node; | |
leaf = (mleaf_t *)node; | |
// grab an efrag off the free list | |
ef = cl.free_efrags; | |
if (!ef) | |
{ | |
Con_Printf ("Too many efrags!\n"); | |
return; // no free fragments... | |
} | |
cl.free_efrags = cl.free_efrags->entnext; | |
ef->entity = r_addent; | |
// add the entity link | |
*lastlink = ef; | |
lastlink = &ef->entnext; | |
ef->entnext = NULL; | |
// set the leaf links | |
ef->leaf = leaf; | |
ef->leafnext = leaf->efrags; | |
leaf->efrags = ef; | |
return; | |
} | |
// NODE_MIXED | |
splitplane = node->plane; | |
sides = BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane); | |
if (sides == 3) | |
{ | |
// split on this plane | |
// if this is the first splitter of this bmodel, remember it | |
if (!r_pefragtopnode) | |
r_pefragtopnode = node; | |
} | |
// recurse down the contacted sides | |
if (sides & 1) | |
R_SplitEntityOnNode (node->children[0]); | |
if (sides & 2) | |
R_SplitEntityOnNode (node->children[1]); | |
} | |
/* | |
=================== | |
R_SplitEntityOnNode2 | |
=================== | |
*/ | |
void R_SplitEntityOnNode2 (mnode_t *node) | |
{ | |
mplane_t *splitplane; | |
int sides; | |
if (node->visframe != r_visframecount) | |
return; | |
if (node->contents < 0) | |
{ | |
if (node->contents != CONTENTS_SOLID) | |
r_pefragtopnode = node; // we've reached a non-solid leaf, so it's | |
// visible and not BSP clipped | |
return; | |
} | |
splitplane = node->plane; | |
sides = BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane); | |
if (sides == 3) | |
{ | |
// remember first splitter | |
r_pefragtopnode = node; | |
return; | |
} | |
// not split yet; recurse down the contacted side | |
if (sides & 1) | |
R_SplitEntityOnNode2 (node->children[0]); | |
else | |
R_SplitEntityOnNode2 (node->children[1]); | |
} | |
/* | |
=========== | |
R_AddEfrags | |
=========== | |
*/ | |
void R_AddEfrags (entity_t *ent) | |
{ | |
model_t *entmodel; | |
int i; | |
if (!ent->model) | |
return; | |
if (ent == cl_entities) | |
return; // never add the world | |
r_addent = ent; | |
lastlink = &ent->efrag; | |
r_pefragtopnode = NULL; | |
entmodel = ent->model; | |
for (i=0 ; i<3 ; i++) | |
{ | |
r_emins[i] = ent->origin[i] + entmodel->mins[i]; | |
r_emaxs[i] = ent->origin[i] + entmodel->maxs[i]; | |
} | |
R_SplitEntityOnNode (cl.worldmodel->nodes); | |
ent->topnode = r_pefragtopnode; | |
} | |
/* | |
================ | |
R_StoreEfrags | |
// FIXME: a lot of this goes away with edge-based | |
================ | |
*/ | |
void R_StoreEfrags (efrag_t **ppefrag) | |
{ | |
entity_t *pent; | |
model_t *clmodel; | |
efrag_t *pefrag; | |
while ((pefrag = *ppefrag) != NULL) | |
{ | |
pent = pefrag->entity; | |
clmodel = pent->model; | |
switch (clmodel->type) | |
{ | |
case mod_alias: | |
case mod_brush: | |
case mod_sprite: | |
pent = pefrag->entity; | |
if ((pent->visframe != r_framecount) && | |
(cl_numvisedicts < MAX_VISEDICTS)) | |
{ | |
cl_visedicts[cl_numvisedicts++] = pent; | |
// mark that we've recorded this entity for this frame | |
pent->visframe = r_framecount; | |
} | |
ppefrag = &pefrag->leafnext; | |
break; | |
default: | |
Sys_Error ("R_StoreEfrags: Bad entity type %d\n", clmodel->type); | |
} | |
} | |
} | |