1 /*
2    ======================================================================
3    pntspols.c
4 
5    Point and polygon functions for an LWO2 reader.
6 
7    Ernie Wright  17 Sep 00
8    ====================================================================== */
9 
10 #include "../picointernal.h"
11 #include "lwo2.h"
12 
13 
14 /*
15    ======================================================================
16    lwFreePoints()
17 
18    Free the memory used by an lwPointList.
19    ====================================================================== */
20 
lwFreePoints(lwPointList * point)21 void lwFreePoints( lwPointList *point ){
22 	int i;
23 
24 	if ( point ) {
25 		if ( point->pt ) {
26 			for ( i = 0; i < point->count; i++ ) {
27 				if ( point->pt[ i ].pol ) {
28 					_pico_free( point->pt[ i ].pol );
29 				}
30 				if ( point->pt[ i ].vm ) {
31 					_pico_free( point->pt[ i ].vm );
32 				}
33 			}
34 			_pico_free( point->pt );
35 		}
36 		memset( point, 0, sizeof( lwPointList ) );
37 	}
38 }
39 
40 
41 /*
42    ======================================================================
43    lwFreePolygons()
44 
45    Free the memory used by an lwPolygonList.
46    ====================================================================== */
47 
lwFreePolygons(lwPolygonList * plist)48 void lwFreePolygons( lwPolygonList *plist ){
49 	int i, j;
50 
51 	if ( plist ) {
52 		if ( plist->pol ) {
53 			for ( i = 0; i < plist->count; i++ ) {
54 				if ( plist->pol[ i ].v ) {
55 					for ( j = 0; j < plist->pol[ i ].nverts; j++ )
56 						if ( plist->pol[ i ].v[ j ].vm ) {
57 							_pico_free( plist->pol[ i ].v[ j ].vm );
58 						}
59 				}
60 			}
61 			if ( plist->pol[ 0 ].v ) {
62 				_pico_free( plist->pol[ 0 ].v );
63 			}
64 			_pico_free( plist->pol );
65 		}
66 		memset( plist, 0, sizeof( lwPolygonList ) );
67 	}
68 }
69 
70 
71 /*
72    ======================================================================
73    lwGetPoints()
74 
75    Read point records from a PNTS chunk in an LWO2 file.  The points are
76    added to the array in the lwPointList.
77    ====================================================================== */
78 
lwGetPoints(picoMemStream_t * fp,int cksize,lwPointList * point)79 int lwGetPoints( picoMemStream_t *fp, int cksize, lwPointList *point ){
80 	float *f;
81 	int np, i, j;
82 
83 	if ( cksize == 1 ) {
84 		return 1;
85 	}
86 
87 	/* extend the point array to hold the new points */
88 
89 	np = cksize / 12;
90 	point->offset = point->count;
91 	point->count += np;
92 	if ( !_pico_realloc( (void *) &point->pt, ( point->count - np ) * sizeof( lwPoint ), point->count * sizeof( lwPoint ) ) ) {
93 		return 0;
94 	}
95 	memset( &point->pt[ point->offset ], 0, np * sizeof( lwPoint ) );
96 
97 	/* read the whole chunk */
98 
99 	f = ( float * ) getbytes( fp, cksize );
100 	if ( !f ) {
101 		return 0;
102 	}
103 	revbytes( f, 4, np * 3 );
104 
105 	/* assign position values */
106 
107 	for ( i = 0, j = 0; i < np; i++, j += 3 ) {
108 		point->pt[ i ].pos[ 0 ] = f[ j ];
109 		point->pt[ i ].pos[ 1 ] = f[ j + 1 ];
110 		point->pt[ i ].pos[ 2 ] = f[ j + 2 ];
111 	}
112 
113 	_pico_free( f );
114 	return 1;
115 }
116 
117 
118 /*
119    ======================================================================
120    lwGetBoundingBox()
121 
122    Calculate the bounding box for a point list, but only if the bounding
123    box hasn't already been initialized.
124    ====================================================================== */
125 
lwGetBoundingBox(lwPointList * point,float bbox[])126 void lwGetBoundingBox( lwPointList *point, float bbox[] ){
127 	int i, j;
128 
129 	if ( point->count == 0 ) {
130 		return;
131 	}
132 
133 	for ( i = 0; i < 6; i++ )
134 		if ( bbox[ i ] != 0.0f ) {
135 			return;
136 		}
137 
138 	bbox[ 0 ] = bbox[ 1 ] = bbox[ 2 ] = 1e20f;
139 	bbox[ 3 ] = bbox[ 4 ] = bbox[ 5 ] = -1e20f;
140 	for ( i = 0; i < point->count; i++ ) {
141 		for ( j = 0; j < 3; j++ ) {
142 			if ( bbox[ j ] > point->pt[ i ].pos[ j ] ) {
143 				bbox[ j ] = point->pt[ i ].pos[ j ];
144 			}
145 			if ( bbox[ j + 3 ] < point->pt[ i ].pos[ j ] ) {
146 				bbox[ j + 3 ] = point->pt[ i ].pos[ j ];
147 			}
148 		}
149 	}
150 }
151 
152 
153 /*
154    ======================================================================
155    lwAllocPolygons()
156 
157    Allocate or extend the polygon arrays to hold new records.
158    ====================================================================== */
159 
lwAllocPolygons(lwPolygonList * plist,int npols,int nverts)160 int lwAllocPolygons( lwPolygonList *plist, int npols, int nverts ){
161 	int i;
162 
163 	plist->offset = plist->count;
164 	plist->count += npols;
165 	if ( !_pico_realloc( (void *) &plist->pol, ( plist->count - npols ) * sizeof( lwPolygon ), plist->count * sizeof( lwPolygon ) ) ) {
166 		return 0;
167 	}
168 	memset( plist->pol + plist->offset, 0, npols * sizeof( lwPolygon ) );
169 
170 	plist->voffset = plist->vcount;
171 	plist->vcount += nverts;
172 	if ( !_pico_realloc( (void *) &plist->pol[ 0 ].v, ( plist->vcount - nverts ) * sizeof( lwPolVert ), plist->vcount * sizeof( lwPolVert ) ) ) {
173 		return 0;
174 	}
175 	memset( plist->pol[ 0 ].v + plist->voffset, 0, nverts * sizeof( lwPolVert ) );
176 
177 	/* fix up the old vertex pointers */
178 
179 	for ( i = 1; i < plist->offset; i++ )
180 		plist->pol[ i ].v = plist->pol[ i - 1 ].v + plist->pol[ i - 1 ].nverts;
181 
182 	return 1;
183 }
184 
185 
186 /*
187    ======================================================================
188    lwGetPolygons()
189 
190    Read polygon records from a POLS chunk in an LWO2 file.  The polygons
191    are added to the array in the lwPolygonList.
192    ====================================================================== */
193 
lwGetPolygons(picoMemStream_t * fp,int cksize,lwPolygonList * plist,int ptoffset)194 int lwGetPolygons( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset ){
195 	lwPolygon *pp;
196 	lwPolVert *pv;
197 	unsigned char *buf, *bp;
198 	int i, j, flags, nv, nverts, npols;
199 	unsigned int type;
200 
201 
202 	if ( cksize == 0 ) {
203 		return 1;
204 	}
205 
206 	/* read the whole chunk */
207 
208 	set_flen( 0 );
209 	type = getU4( fp );
210 	buf = getbytes( fp, cksize - 4 );
211 	if ( cksize != get_flen() ) {
212 		goto Fail;
213 	}
214 
215 	/* count the polygons and vertices */
216 
217 	nverts = 0;
218 	npols = 0;
219 	bp = buf;
220 
221 	while ( bp < buf + cksize - 4 ) {
222 		nv = sgetU2( &bp );
223 		nv &= 0x03FF;
224 		nverts += nv;
225 		npols++;
226 		for ( i = 0; i < nv; i++ )
227 			j = sgetVX( &bp );
228 	}
229 
230 	if ( !lwAllocPolygons( plist, npols, nverts ) ) {
231 		goto Fail;
232 	}
233 
234 	/* fill in the new polygons */
235 
236 	bp = buf;
237 	pp = plist->pol + plist->offset;
238 	pv = plist->pol[ 0 ].v + plist->voffset;
239 
240 	for ( i = 0; i < npols; i++ ) {
241 		nv = sgetU2( &bp );
242 		flags = nv & 0xFC00;
243 		nv &= 0x03FF;
244 
245 		pp->nverts = nv;
246 		pp->flags = flags;
247 		pp->type = type;
248 		if ( !pp->v ) {
249 			pp->v = pv;
250 		}
251 		for ( j = 0; j < nv; j++ )
252 			pp->v[ j ].index = sgetVX( &bp ) + ptoffset;
253 
254 		pp++;
255 		pv += nv;
256 	}
257 
258 	_pico_free( buf );
259 	return 1;
260 
261 Fail:
262 	if ( buf ) {
263 		_pico_free( buf );
264 	}
265 	lwFreePolygons( plist );
266 	return 0;
267 }
268 
269 
270 /*
271    ======================================================================
272    lwGetPolyNormals()
273 
274    Calculate the polygon normals.  By convention, LW's polygon normals
275    are found as the cross product of the first and last edges.  It's
276    undefined for one- and two-point polygons.
277    ====================================================================== */
278 
lwGetPolyNormals(lwPointList * point,lwPolygonList * polygon)279 void lwGetPolyNormals( lwPointList *point, lwPolygonList *polygon ){
280 	int i, j;
281 	float p1[ 3 ], p2[ 3 ], pn[ 3 ], v1[ 3 ], v2[ 3 ];
282 
283 	for ( i = 0; i < polygon->count; i++ ) {
284 		if ( polygon->pol[ i ].nverts < 3 ) {
285 			continue;
286 		}
287 		for ( j = 0; j < 3; j++ ) {
288 			p1[ j ] = point->pt[ polygon->pol[ i ].v[ 0 ].index ].pos[ j ];
289 			p2[ j ] = point->pt[ polygon->pol[ i ].v[ 1 ].index ].pos[ j ];
290 			pn[ j ] = point->pt[ polygon->pol[ i ].v[
291 									 polygon->pol[ i ].nverts - 1 ].index ].pos[ j ];
292 		}
293 
294 		for ( j = 0; j < 3; j++ ) {
295 			v1[ j ] = p2[ j ] - p1[ j ];
296 			v2[ j ] = pn[ j ] - p1[ j ];
297 		}
298 
299 		cross( v1, v2, polygon->pol[ i ].norm );
300 		normalize( polygon->pol[ i ].norm );
301 	}
302 }
303 
304 
305 /*
306    ======================================================================
307    lwGetPointPolygons()
308 
309    For each point, fill in the indexes of the polygons that share the
310    point.  Returns 0 if any of the memory allocations fail, otherwise
311    returns 1.
312    ====================================================================== */
313 
lwGetPointPolygons(lwPointList * point,lwPolygonList * polygon)314 int lwGetPointPolygons( lwPointList *point, lwPolygonList *polygon ){
315 	int i, j, k;
316 
317 	/* count the number of polygons per point */
318 
319 	for ( i = 0; i < polygon->count; i++ )
320 		for ( j = 0; j < polygon->pol[ i ].nverts; j++ )
321 			++point->pt[ polygon->pol[ i ].v[ j ].index ].npols;
322 
323 	/* alloc per-point polygon arrays */
324 
325 	for ( i = 0; i < point->count; i++ ) {
326 		if ( point->pt[ i ].npols == 0 ) {
327 			continue;
328 		}
329 		point->pt[ i ].pol = _pico_calloc( point->pt[ i ].npols, sizeof( int ) );
330 		if ( !point->pt[ i ].pol ) {
331 			return 0;
332 		}
333 		point->pt[ i ].npols = 0;
334 	}
335 
336 	/* fill in polygon array for each point */
337 
338 	for ( i = 0; i < polygon->count; i++ ) {
339 		for ( j = 0; j < polygon->pol[ i ].nverts; j++ ) {
340 			k = polygon->pol[ i ].v[ j ].index;
341 			point->pt[ k ].pol[ point->pt[ k ].npols ] = i;
342 			++point->pt[ k ].npols;
343 		}
344 	}
345 
346 	return 1;
347 }
348 
349 
350 /*
351    ======================================================================
352    lwResolvePolySurfaces()
353 
354    Convert tag indexes into actual lwSurface pointers.  If any polygons
355    point to tags for which no corresponding surface can be found, a
356    default surface is created.
357    ====================================================================== */
358 
lwResolvePolySurfaces(lwPolygonList * polygon,lwTagList * tlist,lwSurface ** surf,int * nsurfs)359 int lwResolvePolySurfaces( lwPolygonList *polygon, lwTagList *tlist,
360 						   lwSurface **surf, int *nsurfs ){
361 	lwSurface **s, *st;
362 	int i, index;
363 
364 	if ( tlist->count == 0 ) {
365 		return 1;
366 	}
367 
368 	s = _pico_calloc( tlist->count, sizeof( lwSurface * ) );
369 	if ( !s ) {
370 		return 0;
371 	}
372 
373 	for ( i = 0; i < tlist->count; i++ ) {
374 		st = *surf;
375 		while ( st ) {
376 			if ( !strcmp( st->name, tlist->tag[ i ] ) ) {
377 				s[ i ] = st;
378 				break;
379 			}
380 			st = st->next;
381 		}
382 	}
383 
384 	for ( i = 0; i < polygon->count; i++ ) {
385 		index = ( size_t ) polygon->pol[ i ].surf;
386 		if ( index < 0 || index > tlist->count ) {
387 			return 0;
388 		}
389 		if ( !s[ index ] ) {
390 			s[ index ] = lwDefaultSurface();
391 			if ( !s[ index ] ) {
392 				return 0;
393 			}
394 			s[ index ]->name = _pico_alloc( strlen( tlist->tag[ index ] ) + 1 );
395 			if ( !s[ index ]->name ) {
396 				return 0;
397 			}
398 			strcpy( s[ index ]->name, tlist->tag[ index ] );
399 			lwListAdd( (void *) surf, s[ index ] );
400 			*nsurfs = *nsurfs + 1;
401 		}
402 		polygon->pol[ i ].surf = s[ index ];
403 	}
404 
405 	_pico_free( s );
406 	return 1;
407 }
408 
409 
410 /*
411    ======================================================================
412    lwGetVertNormals()
413 
414    Calculate the vertex normals.  For each polygon vertex, sum the
415    normals of the polygons that share the point.  If the normals of the
416    current and adjacent polygons form an angle greater than the max
417    smoothing angle for the current polygon's surface, the normal of the
418    adjacent polygon is excluded from the sum.  It's also excluded if the
419    polygons aren't in the same smoothing group.
420 
421    Assumes that lwGetPointPolygons(), lwGetPolyNormals() and
422    lwResolvePolySurfaces() have already been called.
423    ====================================================================== */
424 
lwGetVertNormals(lwPointList * point,lwPolygonList * polygon)425 void lwGetVertNormals( lwPointList *point, lwPolygonList *polygon ){
426 	int j, k, n, g, h, p;
427 	float a;
428 
429 	for ( j = 0; j < polygon->count; j++ ) {
430 		for ( n = 0; n < polygon->pol[ j ].nverts; n++ ) {
431 			for ( k = 0; k < 3; k++ )
432 				polygon->pol[ j ].v[ n ].norm[ k ] = polygon->pol[ j ].norm[ k ];
433 
434 			if ( polygon->pol[ j ].surf->smooth <= 0 ) {
435 				continue;
436 			}
437 
438 			p = polygon->pol[ j ].v[ n ].index;
439 
440 			for ( g = 0; g < point->pt[ p ].npols; g++ ) {
441 				h = point->pt[ p ].pol[ g ];
442 				if ( h == j ) {
443 					continue;
444 				}
445 
446 				if ( polygon->pol[ j ].smoothgrp != polygon->pol[ h ].smoothgrp ) {
447 					continue;
448 				}
449 				a = vecangle( polygon->pol[ j ].norm, polygon->pol[ h ].norm );
450 				if ( a > polygon->pol[ j ].surf->smooth ) {
451 					continue;
452 				}
453 
454 				for ( k = 0; k < 3; k++ )
455 					polygon->pol[ j ].v[ n ].norm[ k ] += polygon->pol[ h ].norm[ k ];
456 			}
457 
458 			normalize( polygon->pol[ j ].v[ n ].norm );
459 		}
460 	}
461 }
462 
463 
464 /*
465    ======================================================================
466    lwFreeTags()
467 
468    Free memory used by an lwTagList.
469    ====================================================================== */
470 
lwFreeTags(lwTagList * tlist)471 void lwFreeTags( lwTagList *tlist ){
472 	int i;
473 
474 	if ( tlist ) {
475 		if ( tlist->tag ) {
476 			for ( i = 0; i < tlist->count; i++ )
477 				if ( tlist->tag[ i ] ) {
478 					_pico_free( tlist->tag[ i ] );
479 				}
480 			_pico_free( tlist->tag );
481 		}
482 		memset( tlist, 0, sizeof( lwTagList ) );
483 	}
484 }
485 
486 
487 /*
488    ======================================================================
489    lwGetTags()
490 
491    Read tag strings from a TAGS chunk in an LWO2 file.  The tags are
492    added to the lwTagList array.
493    ====================================================================== */
494 
lwGetTags(picoMemStream_t * fp,int cksize,lwTagList * tlist)495 int lwGetTags( picoMemStream_t *fp, int cksize, lwTagList *tlist ){
496 	char *buf, *bp;
497 	int i, len, ntags;
498 
499 	if ( cksize == 0 ) {
500 		return 1;
501 	}
502 
503 	/* read the whole chunk */
504 
505 	set_flen( 0 );
506 	buf = getbytes( fp, cksize );
507 	if ( !buf ) {
508 		return 0;
509 	}
510 
511 	/* count the strings */
512 
513 	ntags = 0;
514 	bp = buf;
515 	while ( bp < buf + cksize ) {
516 		len = strlen( bp ) + 1;
517 		len += len & 1;
518 		bp += len;
519 		++ntags;
520 	}
521 
522 	/* expand the string array to hold the new tags */
523 
524 	tlist->offset = tlist->count;
525 	tlist->count += ntags;
526 	if ( !_pico_realloc( (void *) &tlist->tag, ( tlist->count - ntags ) * sizeof( char * ), tlist->count * sizeof( char * ) ) ) {
527 		goto Fail;
528 	}
529 	memset( &tlist->tag[ tlist->offset ], 0, ntags * sizeof( char * ) );
530 
531 	/* copy the new tags to the tag array */
532 
533 	bp = buf;
534 	for ( i = 0; i < ntags; i++ )
535 		tlist->tag[ i + tlist->offset ] = sgetS0( (unsigned char **) &bp );
536 
537 	_pico_free( buf );
538 	return 1;
539 
540 Fail:
541 	if ( buf ) {
542 		_pico_free( buf );
543 	}
544 	return 0;
545 }
546 
547 
548 /*
549    ======================================================================
550    lwGetPolygonTags()
551 
552    Read polygon tags from a PTAG chunk in an LWO2 file.
553    ====================================================================== */
554 
lwGetPolygonTags(picoMemStream_t * fp,int cksize,lwTagList * tlist,lwPolygonList * plist)555 int lwGetPolygonTags( picoMemStream_t *fp, int cksize, lwTagList *tlist,
556 					  lwPolygonList *plist ){
557 	unsigned int type;
558 	int rlen = 0, i, j;
559 
560 	set_flen( 0 );
561 	type = getU4( fp );
562 	rlen = get_flen();
563 	if ( rlen < 0 ) {
564 		return 0;
565 	}
566 
567 	if ( type != ID_SURF && type != ID_PART && type != ID_SMGP ) {
568 		_pico_memstream_seek( fp, cksize - 4, PICO_SEEK_CUR );
569 		return 1;
570 	}
571 
572 	while ( rlen < cksize ) {
573 		i = getVX( fp ) + plist->offset;
574 		j = getVX( fp ) + tlist->offset;
575 		rlen = get_flen();
576 		if ( rlen < 0 || rlen > cksize ) {
577 			return 0;
578 		}
579 
580 		switch ( type ) {
581 		case ID_SURF:  plist->pol[ i ].surf = ( lwSurface * ) (size_t) j;  break;
582 		case ID_PART:  plist->pol[ i ].part = j;  break;
583 		case ID_SMGP:  plist->pol[ i ].smoothgrp = j;  break;
584 		}
585 	}
586 
587 	return 1;
588 }
589