1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "sys/platform.h"
30 
31 #include "tools/compilers/dmap/dmap.h"
32 
33 /*
34 
35   All triangle list functions should behave reasonably with NULL lists.
36 
37 */
38 
39 /*
40 ===============
41 AllocTri
42 ===============
43 */
AllocTri(void)44 mapTri_t	*AllocTri( void ) {
45 	mapTri_t	*tri;
46 
47 	tri = (mapTri_t *)Mem_Alloc( sizeof( *tri ) );
48 	memset( tri, 0, sizeof( *tri ) );
49 	return tri;
50 }
51 
52 /*
53 ===============
54 FreeTri
55 ===============
56 */
FreeTri(mapTri_t * tri)57 void		FreeTri( mapTri_t *tri ) {
58 	Mem_Free( tri );
59 }
60 
61 
62 /*
63 ===============
64 MergeTriLists
65 
66 This does not copy any tris, it just relinks them
67 ===============
68 */
MergeTriLists(mapTri_t * a,mapTri_t * b)69 mapTri_t	*MergeTriLists( mapTri_t *a, mapTri_t *b ) {
70 	mapTri_t	**prev;
71 
72 	prev = &a;
73 	while ( *prev ) {
74 		prev = &(*prev)->next;
75 	}
76 
77 	*prev = b;
78 
79 	return a;
80 }
81 
82 
83 /*
84 ===============
85 FreeTriList
86 ===============
87 */
FreeTriList(mapTri_t * a)88 void FreeTriList( mapTri_t *a ) {
89 	mapTri_t	*next;
90 
91 	for ( ; a ; a = next ) {
92 		next = a->next;
93 		Mem_Free( a );
94 	}
95 }
96 
97 /*
98 ===============
99 CopyTriList
100 ===============
101 */
CopyTriList(const mapTri_t * a)102 mapTri_t	*CopyTriList( const mapTri_t *a ) {
103 	mapTri_t	*testList;
104 	const mapTri_t	*tri;
105 
106 	testList = NULL;
107 	for ( tri = a ; tri ; tri = tri->next ) {
108 		mapTri_t	*copy;
109 
110 		copy = CopyMapTri( tri );
111 		copy ->next = testList;
112 		testList = copy;
113 	}
114 
115 	return testList;
116 }
117 
118 
119 /*
120 =============
121 CountTriList
122 =============
123 */
CountTriList(const mapTri_t * tri)124 int	CountTriList( const mapTri_t *tri ) {
125 	int		c;
126 
127 	c = 0;
128 	while ( tri ) {
129 		c++;
130 		tri = tri->next;
131 	}
132 
133 	return c;
134 }
135 
136 
137 /*
138 ===============
139 CopyMapTri
140 ===============
141 */
CopyMapTri(const mapTri_t * tri)142 mapTri_t	*CopyMapTri( const mapTri_t *tri ) {
143 	mapTri_t		*t;
144 
145 	t = (mapTri_t *)Mem_Alloc( sizeof( *t ) );
146 	*t = *tri;
147 
148 	return t;
149 }
150 
151 /*
152 ===============
153 MapTriArea
154 ===============
155 */
MapTriArea(const mapTri_t * tri)156 float MapTriArea( const mapTri_t *tri ) {
157 	return idWinding::TriangleArea( tri->v[0].xyz, tri->v[1].xyz, tri->v[2].xyz );
158 }
159 
160 /*
161 ===============
162 RemoveBadTris
163 
164 Return a new list with any zero or negative area triangles removed
165 ===============
166 */
RemoveBadTris(const mapTri_t * list)167 mapTri_t	*RemoveBadTris( const mapTri_t *list ) {
168 	mapTri_t	*newList;
169 	mapTri_t	*copy;
170 	const mapTri_t	*tri;
171 
172 	newList = NULL;
173 
174 	for ( tri = list ; tri ; tri = tri->next ) {
175 		if ( MapTriArea( tri ) > 0 ) {
176 			copy = CopyMapTri( tri );
177 			copy->next = newList;
178 			newList = copy;
179 		}
180 	}
181 
182 	return newList;
183 }
184 
185 /*
186 ================
187 BoundTriList
188 ================
189 */
BoundTriList(const mapTri_t * list,idBounds & b)190 void BoundTriList( const mapTri_t *list, idBounds &b ) {
191 	b.Clear();
192 	for ( ; list ; list = list->next ) {
193 		b.AddPoint( list->v[0].xyz );
194 		b.AddPoint( list->v[1].xyz );
195 		b.AddPoint( list->v[2].xyz );
196 	}
197 }
198 
199 /*
200 ================
201 DrawTri
202 ================
203 */
DrawTri(const mapTri_t * tri)204 void DrawTri( const mapTri_t *tri ) {
205 	idWinding w;
206 
207 	w.SetNumPoints( 3 );
208 	VectorCopy( tri->v[0].xyz, w[0] );
209 	VectorCopy( tri->v[1].xyz, w[1] );
210 	VectorCopy( tri->v[2].xyz, w[2] );
211 	DrawWinding( &w );
212 }
213 
214 
215 /*
216 ================
217 FlipTriList
218 
219 Swaps the vertex order
220 ================
221 */
FlipTriList(mapTri_t * tris)222 void	FlipTriList( mapTri_t *tris ) {
223 	mapTri_t	*tri;
224 
225 	for ( tri = tris ; tri ; tri = tri->next ) {
226 		idDrawVert	v;
227 		const struct hashVert_s *hv;
228 		struct optVertex_s	*ov;
229 
230 		v = tri->v[0];
231 		tri->v[0] = tri->v[2];
232 		tri->v[2] = v;
233 
234 		hv = tri->hashVert[0];
235 		tri->hashVert[0] = tri->hashVert[2];
236 		tri->hashVert[2] = hv;
237 
238 		ov = tri->optVert[0];
239 		tri->optVert[0] = tri->optVert[2];
240 		tri->optVert[2] = ov;
241 	}
242 }
243 
244 /*
245 ================
246 WindingForTri
247 ================
248 */
WindingForTri(const mapTri_t * tri)249 idWinding *WindingForTri( const mapTri_t *tri ) {
250 	idWinding	*w;
251 
252 	w = new idWinding( 3 );
253 	w->SetNumPoints( 3 );
254 	VectorCopy( tri->v[0].xyz, (*w)[0] );
255 	VectorCopy( tri->v[1].xyz, (*w)[1] );
256 	VectorCopy( tri->v[2].xyz, (*w)[2] );
257 
258 	return w;
259 }
260 
261 /*
262 ================
263 TriVertsFromOriginal
264 
265 Regenerate the texcoords and colors on a fragmented tri from the plane equations
266 ================
267 */
TriVertsFromOriginal(mapTri_t * tri,const mapTri_t * original)268 void		TriVertsFromOriginal( mapTri_t *tri, const mapTri_t *original ) {
269 	int		i, j;
270 	float	denom;
271 
272 	denom = idWinding::TriangleArea( original->v[0].xyz, original->v[1].xyz, original->v[2].xyz );
273 	if ( denom == 0 ) {
274 		return;		// original was degenerate, so it doesn't matter
275 	}
276 
277 	for ( i = 0 ; i < 3 ; i++ ) {
278 		float	a, b, c;
279 
280 		// find the barycentric coordinates
281 		a = idWinding::TriangleArea( tri->v[i].xyz, original->v[1].xyz, original->v[2].xyz ) / denom;
282 		b = idWinding::TriangleArea( tri->v[i].xyz, original->v[2].xyz, original->v[0].xyz ) / denom;
283 		c = idWinding::TriangleArea( tri->v[i].xyz, original->v[0].xyz, original->v[1].xyz ) / denom;
284 
285 		// regenerate the interpolated values
286 		tri->v[i].st[0] = a * original->v[0].st[0]
287 			 + b * original->v[1].st[0] + c * original->v[2].st[0];
288 		tri->v[i].st[1] = a * original->v[0].st[1]
289 			 + b * original->v[1].st[1] + c * original->v[2].st[1];
290 
291 		for ( j = 0 ; j < 3 ; j++ ) {
292 			tri->v[i].normal[j] = a * original->v[0].normal[j]
293 				 + b * original->v[1].normal[j] + c * original->v[2].normal[j];
294 		}
295 		tri->v[i].normal.Normalize();
296 	}
297 }
298 
299 /*
300 ================
301 WindingToTriList
302 
303 Generates a new list of triangles with proper texcoords from a winding
304 created by clipping the originalTri
305 
306 OriginalTri can be NULL if you don't care about texCoords
307 ================
308 */
WindingToTriList(const idWinding * w,const mapTri_t * originalTri)309 mapTri_t *WindingToTriList( const idWinding *w, const mapTri_t *originalTri ) {
310 	mapTri_t	*tri;
311 	mapTri_t	*triList;
312 	int			i, j;
313 	const idVec3	*vec;
314 
315 	if ( !w ) {
316 		return NULL;
317 	}
318 
319 	triList = NULL;
320 	for ( i = 2 ; i < w->GetNumPoints() ; i++ ) {
321 		tri = AllocTri();
322 		if ( !originalTri ) {
323 			memset( tri, 0, sizeof( *tri ) );
324 		} else {
325 			*tri = *originalTri;
326 		}
327 		tri->next = triList;
328 		triList = tri;
329 
330 		for ( j = 0 ; j < 3 ; j++ ) {
331 			if ( j == 0 ) {
332 				vec = &((*w)[0]).ToVec3();
333 			} else if ( j == 1 ) {
334 				vec = &((*w)[i-1]).ToVec3();
335 			} else {
336 				vec = &((*w)[i]).ToVec3();
337 			}
338 
339 			VectorCopy( *vec, tri->v[j].xyz );
340 		}
341 		if ( originalTri ) {
342 			TriVertsFromOriginal( tri, originalTri );
343 		}
344 	}
345 
346 	return triList;
347 }
348 
349 
350 /*
351 ==================
352 ClipTriList
353 ==================
354 */
ClipTriList(const mapTri_t * list,const idPlane & plane,float epsilon,mapTri_t ** front,mapTri_t ** back)355 void	ClipTriList( const mapTri_t *list, const idPlane &plane, float epsilon,
356 						mapTri_t **front, mapTri_t **back ) {
357 	const mapTri_t *tri;
358 	mapTri_t		*newList;
359 	idWinding		*w, *frontW, *backW;
360 
361 	*front = NULL;
362 	*back = NULL;
363 
364 	for ( tri = list ; tri ; tri = tri->next ) {
365 		w = WindingForTri( tri );
366 		w->Split( plane, epsilon, &frontW, &backW );
367 
368 		newList = WindingToTriList( frontW, tri );
369 		*front = MergeTriLists( *front, newList );
370 
371 		newList = WindingToTriList( backW, tri );
372 		*back = MergeTriLists( *back, newList );
373 
374 		delete w;
375 	}
376 
377 }
378 
379 /*
380 ==================
381 PlaneForTri
382 ==================
383 */
PlaneForTri(const mapTri_t * tri,idPlane & plane)384 void	PlaneForTri( const mapTri_t *tri, idPlane &plane ) {
385 	plane.FromPoints( tri->v[0].xyz, tri->v[1].xyz, tri->v[2].xyz );
386 }
387