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