Home | History | Annotate | Download | only in WinQuake
      1 /*
      2 Copyright (C) 1996-1997 Id Software, Inc.
      3 
      4 This program is free software; you can redistribute it and/or
      5 modify it under the terms of the GNU General Public License
      6 as published by the Free Software Foundation; either version 2
      7 of the License, or (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     12 
     13 See the GNU General Public License for more details.
     14 
     15 You should have received a copy of the GNU General Public License
     16 along with this program; if not, write to the Free Software
     17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     18 
     19 */
     20 // r_efrag.c
     21 
     22 #include "quakedef.h"
     23 #include "r_local.h"
     24 
     25 mnode_t	*r_pefragtopnode;
     26 
     27 
     28 //===========================================================================
     29 
     30 /*
     31 ===============================================================================
     32 
     33 					ENTITY FRAGMENT FUNCTIONS
     34 
     35 ===============================================================================
     36 */
     37 
     38 efrag_t		**lastlink;
     39 
     40 vec3_t		r_emins, r_emaxs;
     41 
     42 entity_t	*r_addent;
     43 
     44 
     45 /*
     46 ================
     47 R_RemoveEfrags
     48 
     49 Call when removing an object from the world or moving it to another position
     50 ================
     51 */
     52 void R_RemoveEfrags (entity_t *ent)
     53 {
     54 	efrag_t		*ef, *old, *walk, **prev;
     55 
     56 	ef = ent->efrag;
     57 
     58 	while (ef)
     59 	{
     60 		prev = &ef->leaf->efrags;
     61 		while (1)
     62 		{
     63 			walk = *prev;
     64 			if (!walk)
     65 				break;
     66 			if (walk == ef)
     67 			{	// remove this fragment
     68 				*prev = ef->leafnext;
     69 				break;
     70 			}
     71 			else
     72 				prev = &walk->leafnext;
     73 		}
     74 
     75 		old = ef;
     76 		ef = ef->entnext;
     77 
     78 	// put it on the free list
     79 		old->entnext = cl.free_efrags;
     80 		cl.free_efrags = old;
     81 	}
     82 
     83 	ent->efrag = NULL;
     84 }
     85 
     86 /*
     87 ===================
     88 R_SplitEntityOnNode
     89 ===================
     90 */
     91 void R_SplitEntityOnNode (mnode_t *node)
     92 {
     93 	efrag_t		*ef;
     94 	mplane_t	*splitplane;
     95 	mleaf_t		*leaf;
     96 	int			sides;
     97 
     98 	if (node->contents == CONTENTS_SOLID)
     99 	{
    100 		return;
    101 	}
    102 
    103 // add an efrag if the node is a leaf
    104 
    105 	if ( node->contents < 0)
    106 	{
    107 		if (!r_pefragtopnode)
    108 			r_pefragtopnode = node;
    109 
    110 		leaf = (mleaf_t *)node;
    111 
    112 // grab an efrag off the free list
    113 		ef = cl.free_efrags;
    114 		if (!ef)
    115 		{
    116 			Con_Printf ("Too many efrags!\n");
    117 			return;		// no free fragments...
    118 		}
    119 		cl.free_efrags = cl.free_efrags->entnext;
    120 
    121 		ef->entity = r_addent;
    122 
    123 // add the entity link
    124 		*lastlink = ef;
    125 		lastlink = &ef->entnext;
    126 		ef->entnext = NULL;
    127 
    128 // set the leaf links
    129 		ef->leaf = leaf;
    130 		ef->leafnext = leaf->efrags;
    131 		leaf->efrags = ef;
    132 
    133 		return;
    134 	}
    135 
    136 // NODE_MIXED
    137 
    138 	splitplane = node->plane;
    139 	sides = BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane);
    140 
    141 	if (sides == 3)
    142 	{
    143 	// split on this plane
    144 	// if this is the first splitter of this bmodel, remember it
    145 		if (!r_pefragtopnode)
    146 			r_pefragtopnode = node;
    147 	}
    148 
    149 // recurse down the contacted sides
    150 	if (sides & 1)
    151 		R_SplitEntityOnNode (node->children[0]);
    152 
    153 	if (sides & 2)
    154 		R_SplitEntityOnNode (node->children[1]);
    155 }
    156 
    157 
    158 /*
    159 ===================
    160 R_SplitEntityOnNode2
    161 ===================
    162 */
    163 void R_SplitEntityOnNode2 (mnode_t *node)
    164 {
    165 	mplane_t	*splitplane;
    166 	int			sides;
    167 
    168 	if (node->visframe != r_visframecount)
    169 		return;
    170 
    171 	if (node->contents < 0)
    172 	{
    173 		if (node->contents != CONTENTS_SOLID)
    174 			r_pefragtopnode = node; // we've reached a non-solid leaf, so it's
    175 									//  visible and not BSP clipped
    176 		return;
    177 	}
    178 
    179 	splitplane = node->plane;
    180 	sides = BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane);
    181 
    182 	if (sides == 3)
    183 	{
    184 	// remember first splitter
    185 		r_pefragtopnode = node;
    186 		return;
    187 	}
    188 
    189 // not split yet; recurse down the contacted side
    190 	if (sides & 1)
    191 		R_SplitEntityOnNode2 (node->children[0]);
    192 	else
    193 		R_SplitEntityOnNode2 (node->children[1]);
    194 }
    195 
    196 
    197 /*
    198 ===========
    199 R_AddEfrags
    200 ===========
    201 */
    202 void R_AddEfrags (entity_t *ent)
    203 {
    204 	model_t		*entmodel;
    205 	int			i;
    206 
    207 	if (!ent->model)
    208 		return;
    209 
    210 	if (ent == cl_entities)
    211 		return;		// never add the world
    212 
    213 	r_addent = ent;
    214 
    215 	lastlink = &ent->efrag;
    216 	r_pefragtopnode = NULL;
    217 
    218 	entmodel = ent->model;
    219 
    220 	for (i=0 ; i<3 ; i++)
    221 	{
    222 		r_emins[i] = ent->origin[i] + entmodel->mins[i];
    223 		r_emaxs[i] = ent->origin[i] + entmodel->maxs[i];
    224 	}
    225 
    226 	R_SplitEntityOnNode (cl.worldmodel->nodes);
    227 
    228 	ent->topnode = r_pefragtopnode;
    229 }
    230 
    231 
    232 /*
    233 ================
    234 R_StoreEfrags
    235 
    236 // FIXME: a lot of this goes away with edge-based
    237 ================
    238 */
    239 void R_StoreEfrags (efrag_t **ppefrag)
    240 {
    241 	entity_t	*pent;
    242 	model_t		*clmodel;
    243 	efrag_t		*pefrag;
    244 
    245 
    246 	while ((pefrag = *ppefrag) != NULL)
    247 	{
    248 		pent = pefrag->entity;
    249 		clmodel = pent->model;
    250 
    251 		switch (clmodel->type)
    252 		{
    253 		case mod_alias:
    254 		case mod_brush:
    255 		case mod_sprite:
    256 			pent = pefrag->entity;
    257 
    258 			if ((pent->visframe != r_framecount) &&
    259 				(cl_numvisedicts < MAX_VISEDICTS))
    260 			{
    261 				cl_visedicts[cl_numvisedicts++] = pent;
    262 
    263 			// mark that we've recorded this entity for this frame
    264 				pent->visframe = r_framecount;
    265 			}
    266 
    267 			ppefrag = &pefrag->leafnext;
    268 			break;
    269 
    270 		default:
    271 			Sys_Error ("R_StoreEfrags: Bad entity type %d\n", clmodel->type);
    272 		}
    273 	}
    274 }
    275 
    276 
    277