]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/picomodel/lwo/pntspols.c
Merge remote-tracking branch 'ttimo/master'
[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         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
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
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
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
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
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
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
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
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
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
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
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
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 }