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