more warnings done. Now q3map2 is warning free apart from libpng deprecation problems.
[divverent/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 {
28    if ( layer ) {
29       if ( layer->name ) _pico_free( layer->name );
30       lwFreePoints( &layer->point );
31       lwFreePolygons( &layer->polygon );
32       lwListFree( layer->vmap, (void *) lwFreeVMap );
33       _pico_free( layer );
34    }
35 }
36
37
38 /*
39 ======================================================================
40 lwFreeObject()
41
42 Free memory used by an lwObject.
43 ====================================================================== */
44
45 void lwFreeObject( lwObject *object )
46 {
47    if ( object ) {
48       lwListFree( object->layer, (void *) lwFreeLayer );
49       lwListFree( object->env, (void *) lwFreeEnvelope );
50       lwListFree( object->clip, (void *) lwFreeClip );
51       lwListFree( object->surf, (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 {
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 ) return NULL;
90
91    /* read the first 12 bytes */
92
93    set_flen( 0 );
94    id       = getU4( fp );
95    formsize = getU4( fp );
96    type     = getU4( fp );
97    if ( 12 != get_flen() ) {
98       return NULL;
99    }
100
101    /* is this a LW object? */
102
103    if ( id != ID_FORM ) {
104       if ( failpos ) *failpos = 12;
105       return NULL;
106    }
107
108    if ( type != ID_LWO2 ) {
109       if ( type == ID_LWOB )
110          return lwGetObject5( filename, fp, failID, failpos );
111       else {
112          if ( failpos ) *failpos = 12;
113          return NULL;
114       }
115    }
116
117    /* allocate an object and a default layer */
118
119    object = _pico_calloc( 1, sizeof( lwObject ));
120    if ( !object ) goto Fail;
121
122    layer = _pico_calloc( 1, sizeof( lwLayer ));
123    if ( !layer ) goto Fail;
124    object->layer = layer;
125
126    /* get the first chunk header */
127
128    id = getU4( fp );
129    cksize = getU4( fp );
130    if ( 0 > get_flen() ) goto Fail;
131
132    /* process chunks as they're encountered */
133
134    while ( 1 ) {
135       cksize += cksize & 1;
136
137       switch ( id )
138       {
139          case ID_LAYR:
140             if ( object->nlayers > 0 ) {
141                layer = _pico_calloc( 1, sizeof( lwLayer ));
142                if ( !layer ) goto Fail;
143                lwListAdd( (void **) &object->layer, layer );
144             }
145             object->nlayers++;
146
147             set_flen( 0 );
148             layer->index = getU2( fp );
149             layer->flags = getU2( fp );
150             layer->pivot[ 0 ] = getF4( fp );
151             layer->pivot[ 1 ] = getF4( fp );
152             layer->pivot[ 2 ] = getF4( fp );
153             layer->name = getS0( fp );
154
155             rlen = get_flen();
156             if ( rlen < 0 || rlen > cksize ) goto Fail;
157             if ( rlen <= cksize - 2 )
158                layer->parent = getU2( fp );
159             rlen = get_flen();
160             if ( rlen < cksize )
161                _pico_memstream_seek( fp, cksize - rlen, PICO_SEEK_CUR );
162             break;
163
164          case ID_PNTS:
165             if ( !lwGetPoints( fp, cksize, &layer->point ))
166                goto Fail;
167             break;
168
169          case ID_POLS:
170             if ( !lwGetPolygons( fp, cksize, &layer->polygon,
171                layer->point.offset ))
172                goto Fail;
173             break;
174
175          case ID_VMAP:
176          case ID_VMAD:
177             node = ( lwNode * ) lwGetVMap( fp, cksize, layer->point.offset,
178                layer->polygon.offset, id == ID_VMAD );
179             if ( !node ) goto Fail;
180             lwListAdd( (void **) &layer->vmap, node );
181             layer->nvmaps++;
182             break;
183
184          case ID_PTAG:
185             if ( !lwGetPolygonTags( fp, cksize, &object->taglist,
186                &layer->polygon ))
187                goto Fail;
188             break;
189
190          case ID_BBOX:
191             set_flen( 0 );
192             for ( i = 0; i < 6; i++ )
193                layer->bbox[ i ] = getF4( fp );
194             rlen = get_flen();
195             if ( rlen < 0 || rlen > cksize ) goto Fail;
196             if ( rlen < cksize )
197                _pico_memstream_seek( fp, cksize - rlen, PICO_SEEK_CUR );
198             break;
199
200          case ID_TAGS:
201             if ( !lwGetTags( fp, cksize, &object->taglist ))
202                goto Fail;
203             break;
204
205          case ID_ENVL:
206             node = ( lwNode * ) lwGetEnvelope( fp, cksize );
207             if ( !node ) goto Fail;
208             lwListAdd( (void **) &object->env, node );
209             object->nenvs++;
210             break;
211
212          case ID_CLIP:
213             node = ( lwNode * ) lwGetClip( fp, cksize );
214             if ( !node ) goto Fail;
215             lwListAdd( (void **) &object->clip, node );
216             object->nclips++;
217             break;
218
219          case ID_SURF:
220             node = ( lwNode * ) lwGetSurface( fp, cksize );
221             if ( !node ) goto Fail;
222             lwListAdd( (void **) &object->surf, node );
223             object->nsurfs++;
224             break;
225
226          case ID_DESC:
227          case ID_TEXT:
228          case ID_ICON:
229          default:
230             _pico_memstream_seek( fp, cksize, PICO_SEEK_CUR );
231             break;
232       }
233
234       /* end of the file? */
235
236       if ( formsize <= (unsigned int) (_pico_memstream_tell( fp ) - 8) ) break;
237
238       /* get the next chunk header */
239
240       set_flen( 0 );
241       id = getU4( fp );
242       cksize = getU4( fp );
243       if ( 8 != get_flen() ) goto Fail;
244    }
245
246    if ( object->nlayers == 0 )
247       object->nlayers = 1;
248
249    layer = object->layer;
250    while ( layer ) {
251       lwGetBoundingBox( &layer->point, layer->bbox );
252       lwGetPolyNormals( &layer->point, &layer->polygon );
253       if ( !lwGetPointPolygons( &layer->point, &layer->polygon )) goto Fail;
254       if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist,
255          &object->surf, &object->nsurfs )) goto Fail;
256       lwGetVertNormals( &layer->point, &layer->polygon );
257       if ( !lwGetPointVMaps( &layer->point, layer->vmap )) goto Fail;
258       if ( !lwGetPolyVMaps( &layer->polygon, layer->vmap )) goto Fail;
259       layer = layer->next;
260    }
261
262    return object;
263
264 Fail:
265   if ( failID ) *failID = id;
266    if ( fp ) {
267       if ( failpos ) *failpos = _pico_memstream_tell( fp );
268    }
269    lwFreeObject( object );
270    return NULL;
271 }
272
273 int lwValidateObject( const char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos )
274 {
275    unsigned int id, type;
276
277    /* open the file */
278
279    if ( !fp ) return PICO_PMV_ERROR_MEMORY;
280
281    /* read the first 12 bytes */
282
283    set_flen( 0 );
284    id       = getU4( fp );
285    /* formsize = */ getU4( fp );
286    type     = getU4( fp );
287    if ( 12 != get_flen() ) {
288       return PICO_PMV_ERROR_SIZE;
289    }
290
291    /* is this a LW object? */
292
293    if ( id != ID_FORM ) {
294       if ( failpos ) *failpos = 12;
295       return PICO_PMV_ERROR_SIZE;
296    }
297
298    if ( type != ID_LWO2 ) {
299       if ( type == ID_LWOB )
300          return lwValidateObject5( filename, fp, failID, failpos );
301       else {
302          if ( failpos ) *failpos = 12;
303          return PICO_PMV_ERROR_IDENT;
304       }
305    }
306
307    return PICO_PMV_OK;
308 }