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