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