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
24mnode_t	*r_pefragtopnode;
25
26
27//===========================================================================
28
29/*
30===============================================================================
31
32					ENTITY FRAGMENT FUNCTIONS
33
34===============================================================================
35*/
36
37efrag_t		**lastlink;
38
39vec3_t		r_emins, r_emaxs;
40
41entity_t	*r_addent;
42
43
44/*
45================
46R_RemoveEfrags
47
48Call when removing an object from the world or moving it to another position
49================
50*/
51void R_RemoveEfrags (entity_t *ent)
52{
53	efrag_t		*ef, *old, *walk, **prev;
54
55	ef = ent->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->efrag = NULL;
83}
84
85/*
86===================
87R_SplitEntityOnNode
88===================
89*/
90void R_SplitEntityOnNode (mnode_t *node)
91{
92	efrag_t		*ef;
93	mplane_t	*splitplane;
94	mleaf_t		*leaf;
95	int			sides;
96
97	if (node->contents == CONTENTS_SOLID)
98	{
99		return;
100	}
101
102// add an efrag if the node is a leaf
103
104	if ( node->contents < 0)
105	{
106		if (!r_pefragtopnode)
107			r_pefragtopnode = node;
108
109		leaf = (mleaf_t *)node;
110
111// grab an efrag off the free list
112		ef = cl.free_efrags;
113		if (!ef)
114		{
115			Con_Printf ("Too many efrags!\n");
116			return;		// no free fragments...
117		}
118		cl.free_efrags = cl.free_efrags->entnext;
119
120		ef->entity = r_addent;
121
122// add the entity link
123		*lastlink = ef;
124		lastlink = &ef->entnext;
125		ef->entnext = NULL;
126
127// set the leaf links
128		ef->leaf = leaf;
129		ef->leafnext = leaf->efrags;
130		leaf->efrags = ef;
131
132		return;
133	}
134
135// NODE_MIXED
136
137	splitplane = node->plane;
138	sides = BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane);
139
140	if (sides == 3)
141	{
142	// split on this plane
143	// if this is the first splitter of this bmodel, remember it
144		if (!r_pefragtopnode)
145			r_pefragtopnode = node;
146	}
147
148// recurse down the contacted sides
149	if (sides & 1)
150		R_SplitEntityOnNode (node->children[0]);
151
152	if (sides & 2)
153		R_SplitEntityOnNode (node->children[1]);
154}
155
156
157
158/*
159===========
160R_AddEfrags
161===========
162*/
163void R_AddEfrags (entity_t *ent)
164{
165	model_t		*entmodel;
166	int			i;
167
168	if (!ent->model)
169		return;
170
171	r_addent = ent;
172
173	lastlink = &ent->efrag;
174	r_pefragtopnode = NULL;
175
176	entmodel = ent->model;
177
178	for (i=0 ; i<3 ; i++)
179	{
180		r_emins[i] = ent->origin[i] + entmodel->mins[i];
181		r_emaxs[i] = ent->origin[i] + entmodel->maxs[i];
182	}
183
184	R_SplitEntityOnNode (cl.worldmodel->nodes);
185
186	ent->topnode = r_pefragtopnode;
187}
188
189
190/*
191================
192R_StoreEfrags
193
194// FIXME: a lot of this goes away with edge-based
195================
196*/
197void R_StoreEfrags (efrag_t **ppefrag)
198{
199	entity_t	*pent;
200	model_t		*clmodel;
201	efrag_t		*pefrag;
202
203
204	while ((pefrag = *ppefrag) != NULL)
205	{
206		pent = pefrag->entity;
207		clmodel = pent->model;
208
209		switch (clmodel->type)
210		{
211		case mod_alias:
212		case mod_brush:
213		case mod_sprite:
214			pent = pefrag->entity;
215
216			if ((pent->visframe != r_framecount) &&
217				(cl_numvisedicts < MAX_VISEDICTS))
218			{
219				cl_visedicts[cl_numvisedicts++] = *pent;
220
221			// mark that we've recorded this entity for this frame
222				pent->visframe = r_framecount;
223			}
224
225			ppefrag = &pefrag->leafnext;
226			break;
227
228		default:
229			Sys_Error ("R_StoreEfrags: Bad entity type %d\n", clmodel->type);
230		}
231	}
232}
233
234
235