a big change with a little description...
[divverent/darkplaces.git] / gl_refrag.c
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 */
51 void R_RemoveEfrags (entity_t *ent)
52 {
53         efrag_t         *ef, *old, *walk, **prev;
54         
55         ef = ent->render.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->render.efrag = NULL; 
83 }
84
85 /*
86 ===================
87 R_SplitEntityOnNode
88 ===================
89 */
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 loc0:
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         // LordHavoc: optimized recursion
151 //      if (sides & 1) R_SplitEntityOnNode (node->children[0]);
152 //      if (sides & 2) R_SplitEntityOnNode (node->children[1]);
153         if (sides & 1)
154         {
155                 if (sides & 2) // 3
156                 {
157                         R_SplitEntityOnNode (node->children[0]);
158                         node = node->children[1];
159                         goto loc0;
160                 }
161                 else // 1
162                 {
163                         node = node->children[0];
164                         goto loc0;
165                 }
166         }
167         // 2
168         node = node->children[1];
169         goto loc0;
170 }
171
172
173
174 /*
175 ===========
176 R_AddEfrags
177 ===========
178 */
179 void R_AddEfrags (entity_t *ent)
180 {
181         model_t         *entmodel;
182         int                     i;
183                 
184         if (!ent->render.model)
185                 return;
186
187         r_addent = ent;
188                         
189         lastlink = &ent->render.efrag;
190         r_pefragtopnode = NULL;
191         
192         entmodel = ent->render.model;
193
194         for (i=0 ; i<3 ; i++)
195         {
196                 r_emins[i] = ent->render.origin[i] + entmodel->mins[i];
197                 r_emaxs[i] = ent->render.origin[i] + entmodel->maxs[i];
198         }
199
200         R_SplitEntityOnNode (cl.worldmodel->nodes);
201
202         ent->render.topnode = r_pefragtopnode;
203 }
204
205
206 /*
207 ================
208 R_StoreEfrags
209
210 // FIXME: a lot of this goes away with edge-based
211 ================
212 */
213 void R_StoreEfrags (efrag_t **ppefrag)
214 {
215         entity_t        *pent;
216         model_t         *clmodel;
217         efrag_t         *pefrag;
218
219
220         while ((pefrag = *ppefrag) != NULL)
221         {
222                 pent = pefrag->entity;
223                 clmodel = pent->render.model;
224
225                 switch (clmodel->type)
226                 {
227                 case mod_alias:
228                 case mod_brush:
229                 case mod_sprite:
230                         pent = pefrag->entity;
231
232                         if ((pent->render.visframe != r_framecount) && (cl_numvisedicts < MAX_VISEDICTS))
233                         {
234                                 cl_visedicts[cl_numvisedicts++] = pent;
235                                 pent->render.visframe = r_framecount; // render each entity only once per frame
236                         }
237
238                         ppefrag = &pefrag->leafnext;
239                         break;
240
241                 default:        
242                         Host_Error ("R_StoreEfrags: Bad entity type %d\n", clmodel->type);
243                 }
244         }
245 }
246
247