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