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