]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/picomodel/lwo/lwo2.c
Remove -Wno-pedantic
[xonotic/netradiant.git] / libs / picomodel / lwo / lwo2.c
1 /*
2    ======================================================================
3    lwo2.c
4
5    The entry point for loading LightWave object files.
6
7    Ernie Wright  17 Sep 00
8    ====================================================================== */
9
10 #include "../picointernal.h"
11 #include "lwo2.h"
12
13 /* disable warnings */
14 #ifdef WIN32
15 #pragma warning( disable:4018 )         /* signed/unsigned mismatch */
16 #endif
17
18
19 /*
20    ======================================================================
21    lwFreeLayer()
22
23    Free memory used by an lwLayer.
24    ====================================================================== */
25
26 void lwFreeLayer( lwLayer *layer ){
27         if ( layer ) {
28                 if ( layer->name ) {
29                         _pico_free( layer->name );
30                 }
31                 lwFreePoints( &layer->point );
32                 lwFreePolygons( &layer->polygon );
33                 lwListFree(layer->vmap, (void (*)(void *)) lwFreeVMap);
34                 _pico_free( layer );
35         }
36 }
37
38
39 /*
40    ======================================================================
41    lwFreeObject()
42
43    Free memory used by an lwObject.
44    ====================================================================== */
45
46 void lwFreeObject( lwObject *object ){
47         if ( object ) {
48                 lwListFree(object->layer, (void (*)(void *)) lwFreeLayer);
49                 lwListFree(object->env, (void (*)(void *)) lwFreeEnvelope);
50                 lwListFree(object->clip, (void (*)(void *)) lwFreeClip);
51                 lwListFree(object->surf, (void (*)(void *)) lwFreeSurface);
52                 lwFreeTags( &object->taglist );
53                 _pico_free( object );
54         }
55 }
56
57
58 /*
59    ======================================================================
60    lwGetObject()
61
62    Returns the contents of a LightWave object, given its filename, or
63    NULL if the file couldn't be loaded.  On failure, failID and failpos
64    can be used to diagnose the cause.
65
66    1.  If the file isn't an LWO2 or an LWOB, failpos will contain 12 and
67     failID will be unchanged.
68
69    2.  If an error occurs while reading, failID will contain the most
70     recently read IFF chunk ID, and failpos will contain the value
71     returned by _pico_memstream_tell() at the time of the failure.
72
73    3.  If the file couldn't be opened, or an error occurs while reading
74     the first 12 bytes, both failID and failpos will be unchanged.
75
76    If you don't need this information, failID and failpos can be NULL.
77    ====================================================================== */
78
79 lwObject *lwGetObject( const char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ){
80         lwObject *object;
81         lwLayer *layer;
82         lwNode *node;
83         unsigned int id, formsize, type;
84         int i, rlen, cksize;
85
86         /* open the file */
87
88         if ( !fp ) {
89                 return NULL;
90         }
91
92         /* read the first 12 bytes */
93
94         set_flen( 0 );
95         id       = getU4( fp );
96         formsize = getU4( fp );
97         type     = getU4( fp );
98         if ( 12 != get_flen() ) {
99                 return NULL;
100         }
101
102         /* is this a LW object? */
103
104         if ( id != ID_FORM ) {
105                 if ( failpos ) {
106                         *failpos = 12;
107                 }
108                 return NULL;
109         }
110
111         if ( type != ID_LWO2 ) {
112                 if ( type == ID_LWOB ) {
113                         return lwGetObject5( filename, fp, failID, failpos );
114                 }
115                 else {
116                         if ( failpos ) {
117                                 *failpos = 12;
118                         }
119                         return NULL;
120                 }
121         }
122
123         /* allocate an object and a default layer */
124
125         object = _pico_calloc( 1, sizeof( lwObject ) );
126         if ( !object ) {
127                 goto Fail;
128         }
129
130         layer = _pico_calloc( 1, sizeof( lwLayer ) );
131         if ( !layer ) {
132                 goto Fail;
133         }
134         object->layer = layer;
135
136         /* get the first chunk header */
137
138         id = getU4( fp );
139         cksize = getU4( fp );
140         if ( 0 > get_flen() ) {
141                 goto Fail;
142         }
143
144         /* process chunks as they're encountered */
145
146         while ( 1 ) {
147                 cksize += cksize & 1;
148
149                 switch ( id )
150                 {
151                 case ID_LAYR:
152                         if ( object->nlayers > 0 ) {
153                                 layer = _pico_calloc( 1, sizeof( lwLayer ) );
154                                 if ( !layer ) {
155                                         goto Fail;
156                                 }
157                                 lwListAdd( (void **) &object->layer, layer );
158                         }
159                         object->nlayers++;
160
161                         set_flen( 0 );
162                         layer->index = getU2( fp );
163                         layer->flags = getU2( fp );
164                         layer->pivot[ 0 ] = getF4( fp );
165                         layer->pivot[ 1 ] = getF4( fp );
166                         layer->pivot[ 2 ] = getF4( fp );
167                         layer->name = getS0( fp );
168
169                         rlen = get_flen();
170                         if ( rlen < 0 || rlen > cksize ) {
171                                 goto Fail;
172                         }
173                         if ( rlen <= cksize - 2 ) {
174                                 layer->parent = getU2( fp );
175                         }
176                         rlen = get_flen();
177                         if ( rlen < cksize ) {
178                                 _pico_memstream_seek( fp, cksize - rlen, PICO_SEEK_CUR );
179                         }
180                         break;
181
182                 case ID_PNTS:
183                         if ( !lwGetPoints( fp, cksize, &layer->point ) ) {
184                                 goto Fail;
185                         }
186                         break;
187
188                 case ID_POLS:
189                         if ( !lwGetPolygons( fp, cksize, &layer->polygon,
190                                                                  layer->point.offset ) ) {
191                                 goto Fail;
192                         }
193                         break;
194
195                 case ID_VMAP:
196                 case ID_VMAD:
197                         node = ( lwNode * ) lwGetVMap( fp, cksize, layer->point.offset,
198                                                                                    layer->polygon.offset, id == ID_VMAD );
199                         if ( !node ) {
200                                 goto Fail;
201                         }
202                         lwListAdd( (void **) &layer->vmap, node );
203                         layer->nvmaps++;
204                         break;
205
206                 case ID_PTAG:
207                         if ( !lwGetPolygonTags( fp, cksize, &object->taglist,
208                                                                         &layer->polygon ) ) {
209                                 goto Fail;
210                         }
211                         break;
212
213                 case ID_BBOX:
214                         set_flen( 0 );
215                         for ( i = 0; i < 6; i++ )
216                                 layer->bbox[ i ] = getF4( fp );
217                         rlen = get_flen();
218                         if ( rlen < 0 || rlen > cksize ) {
219                                 goto Fail;
220                         }
221                         if ( rlen < cksize ) {
222                                 _pico_memstream_seek( fp, cksize - rlen, PICO_SEEK_CUR );
223                         }
224                         break;
225
226                 case ID_TAGS:
227                         if ( !lwGetTags( fp, cksize, &object->taglist ) ) {
228                                 goto Fail;
229                         }
230                         break;
231
232                 case ID_ENVL:
233                         node = ( lwNode * ) lwGetEnvelope( fp, cksize );
234                         if ( !node ) {
235                                 goto Fail;
236                         }
237                         lwListAdd( (void **) &object->env, node );
238                         object->nenvs++;
239                         break;
240
241                 case ID_CLIP:
242                         node = ( lwNode * ) lwGetClip( fp, cksize );
243                         if ( !node ) {
244                                 goto Fail;
245                         }
246                         lwListAdd( (void **) &object->clip, node );
247                         object->nclips++;
248                         break;
249
250                 case ID_SURF:
251                         node = ( lwNode * ) lwGetSurface( fp, cksize );
252                         if ( !node ) {
253                                 goto Fail;
254                         }
255                         lwListAdd( (void **) &object->surf, node );
256                         object->nsurfs++;
257                         break;
258
259                 case ID_DESC:
260                 case ID_TEXT:
261                 case ID_ICON:
262                 default:
263                         _pico_memstream_seek( fp, cksize, PICO_SEEK_CUR );
264                         break;
265                 }
266
267                 /* end of the file? */
268
269                 if ( formsize <= (unsigned int) ( _pico_memstream_tell( fp ) - 8 ) ) {
270                         break;
271                 }
272
273                 /* get the next chunk header */
274
275                 set_flen( 0 );
276                 id = getU4( fp );
277                 cksize = getU4( fp );
278                 if ( 8 != get_flen() ) {
279                         goto Fail;
280                 }
281         }
282
283         if ( object->nlayers == 0 ) {
284                 object->nlayers = 1;
285         }
286
287         layer = object->layer;
288         while ( layer ) {
289                 lwGetBoundingBox( &layer->point, layer->bbox );
290                 lwGetPolyNormals( &layer->point, &layer->polygon );
291                 if ( !lwGetPointPolygons( &layer->point, &layer->polygon ) ) {
292                         goto Fail;
293                 }
294                 if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist,
295                                                                          &object->surf, &object->nsurfs ) ) {
296                         goto Fail;
297                 }
298                 lwGetVertNormals( &layer->point, &layer->polygon );
299                 if ( !lwGetPointVMaps( &layer->point, layer->vmap ) ) {
300                         goto Fail;
301                 }
302                 if ( !lwGetPolyVMaps( &layer->polygon, layer->vmap ) ) {
303                         goto Fail;
304                 }
305                 layer = layer->next;
306         }
307
308         return object;
309
310 Fail:
311         if ( failID ) {
312                 *failID = id;
313         }
314         if ( fp ) {
315                 if ( failpos ) {
316                         *failpos = _pico_memstream_tell( fp );
317                 }
318         }
319         lwFreeObject( object );
320         return NULL;
321 }
322
323 int lwValidateObject( const char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ){
324         unsigned int id, type;
325
326         /* open the file */
327
328         if ( !fp ) {
329                 return PICO_PMV_ERROR_MEMORY;
330         }
331
332         /* read the first 12 bytes */
333
334         set_flen( 0 );
335         id       = getU4( fp );
336         /* formsize = */ getU4( fp );
337         type     = getU4( fp );
338         if ( 12 != get_flen() ) {
339                 return PICO_PMV_ERROR_SIZE;
340         }
341
342         /* is this a LW object? */
343
344         if ( id != ID_FORM ) {
345                 if ( failpos ) {
346                         *failpos = 12;
347                 }
348                 return PICO_PMV_ERROR_SIZE;
349         }
350
351         if ( type != ID_LWO2 ) {
352                 if ( type == ID_LWOB ) {
353                         return lwValidateObject5( filename, fp, failID, failpos );
354                 }
355                 else {
356                         if ( failpos ) {
357                                 *failpos = 12;
358                         }
359                         return PICO_PMV_ERROR_IDENT;
360                 }
361         }
362
363         return PICO_PMV_OK;
364 }