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