1/* 2Copyright (C) 1996-1997 Id Software, Inc. 3 4This program is free software; you can redistribute it and/or 5modify it under the terms of the GNU General Public License 6as published by the Free Software Foundation; either version 2 7of the License, or (at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13See the GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with this program; if not, write to the Free Software 17Foundation, 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 25mnode_t *r_pefragtopnode; 26 27 28//=========================================================================== 29 30/* 31=============================================================================== 32 33 ENTITY FRAGMENT FUNCTIONS 34 35=============================================================================== 36*/ 37 38efrag_t **lastlink; 39 40vec3_t r_emins, r_emaxs; 41 42entity_t *r_addent; 43 44 45/* 46================ 47R_RemoveEfrags 48 49Call when removing an object from the world or moving it to another position 50================ 51*/ 52void 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=================== 88R_SplitEntityOnNode 89=================== 90*/ 91void 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=================== 160R_SplitEntityOnNode2 161=================== 162*/ 163void 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=========== 199R_AddEfrags 200=========== 201*/ 202void R_AddEfrags (entity_t *ent) 203{ 204 model_t *entmodel; 205 int i; 206 207 if (!ent->model) 208 return; 209 210 if (ent == &r_worldentity) 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================ 234R_StoreEfrags 235 236// FIXME: a lot of this goes away with edge-based 237================ 238*/ 239void 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