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