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
24 mnode_t *r_pefragtopnode;
25
26
27 //===========================================================================
28
29 /*
30 ===============================================================================
31
32 ENTITY FRAGMENT FUNCTIONS
33
34 ===============================================================================
35 */
36
37 efrag_t **lastlink;
38
39 vec3_t r_emins, r_emaxs;
40
41 entity_t *r_addent;
42
43
44 /*
45 ================
46 R_RemoveEfrags
47
48 Call when removing an object from the world or moving it to another position
49 ================
50 */
R_RemoveEfrags(entity_t * ent)51 void R_RemoveEfrags (entity_t *ent)
52 {
53 efrag_t *ef, *old, *walk, **prev;
54
55 ef = ent->efrag;
56
57 while (ef)
58 {
59 prev = &ef->leaf->efrags;
60 while (1)
61 {
62 walk = *prev;
63 if (!walk)
64 break;
65 if (walk == ef)
66 { // remove this fragment
67 *prev = ef->leafnext;
68 break;
69 }
70 else
71 prev = &walk->leafnext;
72 }
73
74 old = ef;
75 ef = ef->entnext;
76
77 // put it on the free list
78 old->entnext = cl.free_efrags;
79 cl.free_efrags = old;
80 }
81
82 ent->efrag = NULL;
83 }
84
85 /*
86 ===================
87 R_SplitEntityOnNode
88 ===================
89 */
R_SplitEntityOnNode(mnode_t * node)90 void R_SplitEntityOnNode (mnode_t *node)
91 {
92 efrag_t *ef;
93 mplane_t *splitplane;
94 mleaf_t *leaf;
95 int sides;
96
97 if (node->contents == CONTENTS_SOLID)
98 {
99 return;
100 }
101
102 // add an efrag if the node is a leaf
103
104 if ( node->contents < 0)
105 {
106 if (!r_pefragtopnode)
107 r_pefragtopnode = node;
108
109 leaf = (mleaf_t *)node;
110
111 // grab an efrag off the free list
112 ef = cl.free_efrags;
113 if (!ef)
114 {
115 Con_Printf ("Too many efrags!\n");
116 return; // no free fragments...
117 }
118 cl.free_efrags = cl.free_efrags->entnext;
119
120 ef->entity = r_addent;
121
122 // add the entity link
123 *lastlink = ef;
124 lastlink = &ef->entnext;
125 ef->entnext = NULL;
126
127 // set the leaf links
128 ef->leaf = leaf;
129 ef->leafnext = leaf->efrags;
130 leaf->efrags = ef;
131
132 return;
133 }
134
135 // NODE_MIXED
136
137 splitplane = node->plane;
138 sides = BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane);
139
140 if (sides == 3)
141 {
142 // split on this plane
143 // if this is the first splitter of this bmodel, remember it
144 if (!r_pefragtopnode)
145 r_pefragtopnode = node;
146 }
147
148 // recurse down the contacted sides
149 if (sides & 1)
150 R_SplitEntityOnNode (node->children[0]);
151
152 if (sides & 2)
153 R_SplitEntityOnNode (node->children[1]);
154 }
155
156
157
158 /*
159 ===========
160 R_AddEfrags
161 ===========
162 */
R_AddEfrags(entity_t * ent)163 void R_AddEfrags (entity_t *ent)
164 {
165 model_t *entmodel;
166 int i;
167
168 if (!ent->model) {
169 Sys_Error("Ent with NULL model\n");
170
171 } else {
172 //Con_Printf("Kept ent. %s\n",ent->model->name);
173 }
174
175 r_addent = ent;
176
177 lastlink = &ent->efrag;
178 r_pefragtopnode = NULL;
179
180 entmodel = ent->model;
181
182 for (i=0 ; i<3 ; i++)
183 {
184 r_emins[i] = ent->origin[i] + entmodel->mins[i];
185 r_emaxs[i] = ent->origin[i] + entmodel->maxs[i];
186 }
187
188 R_SplitEntityOnNode (cl.worldmodel->nodes);
189
190 ent->topnode = r_pefragtopnode;
191 }
192
193
194 /*
195 ================
196 R_StoreEfrags
197
198 // FIXME: a lot of this goes away with edge-based
199
200 Wat dit ook doet het voegt in ieder geval de statische ents aan
201 de visibility lijst voor dit frame toe.
202 Maar enkel de statische ents voor een leaf I suppose.
203 ================
204 */
R_StoreEfrags(efrag_t ** ppefrag)205 void R_StoreEfrags (efrag_t **ppefrag)
206 {
207 entity_t *pent;
208 model_t *clmodel;
209 efrag_t *pefrag;
210
211
212 while ((pefrag = *ppefrag) != NULL)
213 {
214 pent = pefrag->entity;
215 clmodel = pent->model;
216
217 //PENTA: null model? skip it!
218 if (!clmodel) {
219 ppefrag = &pefrag->leafnext;
220 }
221
222 switch (clmodel->type)
223 {
224 case mod_alias:
225 case mod_brush:
226 case mod_sprite:
227 pent = pefrag->entity;
228
229 //prob kunnen ents in meerdere leafs tegelijk zitten (overlappen van bbox)
230 //maar we willen ze dus maar 1x tekenen
231 if ((pent->visframe != r_framecount) &&
232 (cl_numvisedicts < MAX_VISEDICTS))
233 {
234 cl_visedicts[cl_numvisedicts++] = pent;
235
236 // mark that we've recorded this entity for this frame
237 pent->visframe = r_framecount;
238 }
239
240 ppefrag = &pefrag->leafnext;
241 break;
242
243 default:
244 Sys_Error ("R_StoreEfrags: Bad entity type %d\n", clmodel->type);
245 }
246 }
247 }
248 /*
249 void R_SplitEntityOnNodePenta (mnode_t *node)
250 {
251 efrag_t *ef;
252 mplane_t *splitplane;
253 mleaf_t *leaf;
254 int sides;
255
256 if (node->contents == CONTENTS_SOLID)
257 {
258 return;
259 }
260
261 // add an efrag if the node is a leaf
262
263 if ( node->contents < 0)
264 {
265 leaf = (mleaf_t *)node;
266
267 //Store leaf index for vis lookup
268 if (r_addent->numleafs < MAX_CLIENT_ENT_LEAFS) {
269 r_addent->leafnums[r_addent->numleafs] = leaf->index;
270 r_addent->numleafs++;
271 } else {
272 Con_Printf("Entity is in more than MAX_CLIENT_ENT_LEAFS leafs\n");
273 }
274
275 return;
276 }
277
278 // NODE_MIXED
279
280 splitplane = node->plane;
281 sides = BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane);
282
283 if (sides == 3)
284 {
285 // split on this plane
286 // if this is the first splitter of this bmodel, remember it
287 if (!r_pefragtopnode)
288 r_pefragtopnode = node;
289 }
290
291 // recurse down the contacted sides
292 if (sides & 1)
293 R_SplitEntityOnNodePenta (node->children[0]);
294
295 if (sides & 2)
296 R_SplitEntityOnNodePenta (node->children[1]);
297 }
298
299 */
R_SplitEntityOnNodePenta(entity_t * ent,mnode_t * node)300 void R_SplitEntityOnNodePenta (entity_t *ent, mnode_t *node)
301 {
302 mplane_t *splitplane;
303 mleaf_t *leaf;
304 int sides;
305 int leafnum;
306
307 if (node->contents == CONTENTS_SOLID)
308 return;
309
310 // add an efrag if the node is a leaf
311
312 if ( node->contents < 0)
313 {
314 if (ent->numleafs == MAX_CLIENT_ENT_LEAFS) {
315 //Con_Printf("Max ent leafs reached\n");
316 return;
317 }
318
319 leaf = (mleaf_t *)node;
320 leafnum = leaf - cl.worldmodel->leafs - 1;
321
322 ent->leafnums[ent->numleafs] = leafnum;
323 ent->numleafs++;
324 return;
325 }
326
327 // NODE_MIXED
328
329 splitplane = node->plane;
330 sides = BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane);
331
332 // recurse down the contacted sides
333 if (sides & 1)
334 R_SplitEntityOnNodePenta (ent, node->children[0]);
335
336 if (sides & 2)
337 R_SplitEntityOnNodePenta (ent, node->children[1]);
338 }
339
340
341 /*
342 ===================
343 R_FillEntityLeafs
344 ===================
345 */
R_FillEntityLeafs(entity_t * ent)346 void R_FillEntityLeafs (entity_t *ent)
347 {
348 model_t *entmodel;
349 int i;
350
351 if (!ent->model)
352 return;
353
354 if (ent == cl_entities)
355 return; // never add the world
356
357 r_addent = ent;
358
359 entmodel = ent->model;
360
361 for (i=0 ; i<3 ; i++)
362 {
363 r_emins[i] = ent->origin[i] + entmodel->mins[i];
364 r_emaxs[i] = ent->origin[i] + entmodel->maxs[i];
365 }
366
367 //fiddle a bit with precision
368 r_emins[0] -= 5;
369 r_emins[1] -= 5;
370 r_emins[2] -= 5;
371 r_emaxs[0] += 5;
372 r_emaxs[1] += 5;
373 r_emaxs[2] += 5;
374
375 ent->numleafs = 0;
376 R_SplitEntityOnNodePenta (ent, cl.worldmodel->nodes);
377
378 ent->topnode = r_pefragtopnode;
379 }
380
381
382