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