]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/picomodel/lwo/pntspols.c
ported over the 1.5 branch version of q3map2 which is newer
[xonotic/netradiant.git] / libs / picomodel / lwo / pntspols.c
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
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
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
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
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
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
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
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
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
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 ) ((size_t)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( 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
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
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
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( &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
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 * ) ((size_t)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 }