2 ======================================================================
5 Functions for an LWOB reader. LWOB is the LightWave object format
6 for versions of LW prior to 6.0.
9 ====================================================================== */
11 #include "../picointernal.h"
14 /* disable warnings */
16 #pragma warning( disable:4018 ) /* signed/unsigned mismatch */
20 /* IDs specific to LWOB */
22 #define ID_SRFS LWID_('S','R','F','S')
23 #define ID_FLAG LWID_('F','L','A','G')
24 #define ID_VLUM LWID_('V','L','U','M')
25 #define ID_VDIF LWID_('V','D','I','F')
26 #define ID_VSPC LWID_('V','S','P','C')
27 #define ID_RFLT LWID_('R','F','L','T')
28 #define ID_BTEX LWID_('B','T','E','X')
29 #define ID_CTEX LWID_('C','T','E','X')
30 #define ID_DTEX LWID_('D','T','E','X')
31 #define ID_LTEX LWID_('L','T','E','X')
32 #define ID_RTEX LWID_('R','T','E','X')
33 #define ID_STEX LWID_('S','T','E','X')
34 #define ID_TTEX LWID_('T','T','E','X')
35 #define ID_TFLG LWID_('T','F','L','G')
36 #define ID_TSIZ LWID_('T','S','I','Z')
37 #define ID_TCTR LWID_('T','C','T','R')
38 #define ID_TFAL LWID_('T','F','A','L')
39 #define ID_TVEL LWID_('T','V','E','L')
40 #define ID_TCLR LWID_('T','C','L','R')
41 #define ID_TVAL LWID_('T','V','A','L')
42 #define ID_TAMP LWID_('T','A','M','P')
43 #define ID_TIMG LWID_('T','I','M','G')
44 #define ID_TAAS LWID_('T','A','A','S')
45 #define ID_TREF LWID_('T','R','E','F')
46 #define ID_TOPC LWID_('T','O','P','C')
47 #define ID_SDAT LWID_('S','D','A','T')
48 #define ID_TFP0 LWID_('T','F','P','0')
49 #define ID_TFP1 LWID_('T','F','P','1')
53 ======================================================================
56 Add a clip to the clip list. Used to store the contents of an RIMG or
57 TIMG surface subchunk.
58 ====================================================================== */
60 static int add_clip( char *s, lwClip **clist, int *nclips )
65 clip = _pico_calloc( 1, sizeof( lwClip ));
66 if ( !clip ) return 0;
68 clip->contrast.val = 1.0f;
69 clip->brightness.val = 1.0f;
70 clip->saturation.val = 1.0f;
71 clip->gamma.val = 1.0f;
73 if ((p = strstr( s, "(sequence)" ))) {
76 clip->source.seq.prefix = s;
77 clip->source.seq.digits = 3;
81 clip->source.still.name = s;
85 clip->index = *nclips;
87 lwListAdd( (void *) clist, clip );
94 ======================================================================
97 Add a triple of envelopes to simulate the old texture velocity
99 ====================================================================== */
101 static int add_tvel( float pos[], float vel[], lwEnvelope **elist, int *nenvs )
107 for ( i = 0; i < 3; i++ ) {
108 env = _pico_calloc( 1, sizeof( lwEnvelope ));
109 key0 = _pico_calloc( 1, sizeof( lwKey ));
110 key1 = _pico_calloc( 1, sizeof( lwKey ));
111 if ( !env || !key0 || !key1 ) return 0;
114 key0->value = pos[ i ];
117 key1->value = pos[ i ] + vel[ i ] * 30.0f;
119 key0->shape = key1->shape = ID_LINE;
121 env->index = *nenvs + i + 1;
122 env->type = 0x0301 + i;
123 env->name = _pico_alloc( 11 );
125 strcpy( env->name, "Position.X" );
130 env->behavior[ 0 ] = BEH_LINEAR;
131 env->behavior[ 1 ] = BEH_LINEAR;
133 lwListAdd( (void *) elist, env );
137 return env->index - 2;
142 ======================================================================
145 Create a new texture for BTEX, CTEX, etc. subchunks.
146 ====================================================================== */
148 static lwTexture *get_texture( char *s )
152 tex = _pico_calloc( 1, sizeof( lwTexture ));
153 if ( !tex ) return NULL;
155 tex->tmap.size.val[ 0 ] =
156 tex->tmap.size.val[ 1 ] =
157 tex->tmap.size.val[ 2 ] = 1.0f;
158 tex->opacity.val = 1.0f;
161 if ( strstr( s, "Image Map" )) {
163 if ( strstr( s, "Planar" )) tex->param.imap.projection = 0;
164 else if ( strstr( s, "Cylindrical" )) tex->param.imap.projection = 1;
165 else if ( strstr( s, "Spherical" )) tex->param.imap.projection = 2;
166 else if ( strstr( s, "Cubic" )) tex->param.imap.projection = 3;
167 else if ( strstr( s, "Front" )) tex->param.imap.projection = 4;
168 tex->param.imap.aa_strength = 1.0f;
169 tex->param.imap.amplitude.val = 1.0f;
174 tex->param.proc.name = s;
182 ======================================================================
185 Read an lwSurface from an LWOB file.
186 ====================================================================== */
188 lwSurface *lwGetSurface5( picoMemStream_t *fp, int cksize, lwObject *obj )
191 lwTexture *tex = NULL;
192 lwPlugin *shdr = NULL;
195 unsigned int id, flags;
200 /* allocate the Surface structure */
202 surf = _pico_calloc( 1, sizeof( lwSurface ));
203 if ( !surf ) goto Fail;
205 /* non-zero defaults */
207 surf->color.rgb[ 0 ] = 0.78431f;
208 surf->color.rgb[ 1 ] = 0.78431f;
209 surf->color.rgb[ 2 ] = 0.78431f;
210 surf->diffuse.val = 1.0f;
211 surf->glossiness.val = 0.4f;
212 surf->bump.val = 1.0f;
213 surf->eta.val = 1.0f;
216 /* remember where we started */
219 pos = _pico_memstream_tell( fp );
223 surf->name = getS0( fp );
225 /* first subchunk header */
229 if ( 0 > get_flen() ) goto Fail;
231 /* process subchunks as they're encountered */
239 surf->color.rgb[ 0 ] = getU1( fp ) / 255.0f;
240 surf->color.rgb[ 1 ] = getU1( fp ) / 255.0f;
241 surf->color.rgb[ 2 ] = getU1( fp ) / 255.0f;
246 if ( flags & 4 ) surf->smooth = 1.56207f;
247 if ( flags & 8 ) surf->color_hilite.val = 1.0f;
248 if ( flags & 16 ) surf->color_filter.val = 1.0f;
249 if ( flags & 128 ) surf->dif_sharp.val = 0.5f;
250 if ( flags & 256 ) surf->sideflags = 3;
251 if ( flags & 512 ) surf->add_trans.val = 1.0f;
255 surf->luminosity.val = getI2( fp ) / 256.0f;
259 surf->luminosity.val = getF4( fp );
263 surf->diffuse.val = getI2( fp ) / 256.0f;
267 surf->diffuse.val = getF4( fp );
271 surf->specularity.val = getI2( fp ) / 256.0f;
275 surf->specularity.val = getF4( fp );
279 surf->glossiness.val = ( float ) log( getU2( fp )) / 20.7944f;
283 surf->smooth = getF4( fp );
287 surf->reflection.val.val = getI2( fp ) / 256.0f;
291 surf->reflection.options = getU2( fp );
296 surf->reflection.cindex = add_clip( s, &obj->clip, &obj->nclips );
297 surf->reflection.options = 3;
301 surf->reflection.seam_angle = getF4( fp );
305 surf->transparency.val.val = getI2( fp ) / 256.0f;
309 surf->eta.val = getF4( fp );
313 s = getbytes( fp, sz );
314 tex = get_texture( s );
315 lwListAdd( (void *) &surf->bump.tex, tex );
319 s = getbytes( fp, sz );
320 tex = get_texture( s );
321 lwListAdd( (void *) &surf->color.tex, tex );
325 s = getbytes( fp, sz );
326 tex = get_texture( s );
327 lwListAdd( (void *) &surf->diffuse.tex, tex );
331 s = getbytes( fp, sz );
332 tex = get_texture( s );
333 lwListAdd( (void *) &surf->luminosity.tex, tex );
337 s = getbytes( fp, sz );
338 tex = get_texture( s );
339 lwListAdd( (void *) &surf->reflection.val.tex, tex );
343 s = getbytes( fp, sz );
344 tex = get_texture( s );
345 lwListAdd( (void *) &surf->specularity.tex, tex );
349 s = getbytes( fp, sz );
350 tex = get_texture( s );
351 lwListAdd( (void *) &surf->transparency.val.tex, tex );
359 if ( flags & 1 ) i = 0;
360 if ( flags & 2 ) i = 1;
361 if ( flags & 4 ) i = 2;
364 if ( tex->type == ID_IMAP )
365 tex->param.imap.axis = i;
367 tex->param.proc.axis = i;
369 if ( flags & 8 ) tex->tmap.coord_sys = 1;
370 if ( flags & 16 ) tex->negative = 1;
371 if ( flags & 32 ) tex->param.imap.pblend = 1;
373 tex->param.imap.aa_strength = 1.0f;
374 tex->param.imap.aas_flags = 1;
380 for ( i = 0; i < 3; i++ )
381 tex->tmap.size.val[ i ] = getF4( fp );
386 for ( i = 0; i < 3; i++ )
387 tex->tmap.center.val[ i ] = getF4( fp );
392 for ( i = 0; i < 3; i++ )
393 tex->tmap.falloff.val[ i ] = getF4( fp );
398 for ( i = 0; i < 3; i++ )
399 v[ i ] = getF4( fp );
400 tex->tmap.center.eindex = add_tvel( tex->tmap.center.val, v,
401 &obj->env, &obj->nenvs );
406 if ( tex->type == ID_PROC )
407 for ( i = 0; i < 3; i++ )
408 tex->param.proc.value[ i ] = getU1( fp ) / 255.0f;
413 tex->param.proc.value[ 0 ] = getI2( fp ) / 256.0f;
418 if ( tex->type == ID_IMAP )
419 tex->param.imap.amplitude.val = getF4( fp );
425 tex->param.imap.cindex = add_clip( s, &obj->clip, &obj->nclips );
430 tex->param.imap.aa_strength = getF4( fp );
431 tex->param.imap.aas_flags = 1;
436 tex->tmap.ref_object = getbytes( fp, sz );
441 tex->opacity.val = getF4( fp );
446 if ( tex->type == ID_IMAP )
447 tex->param.imap.wrapw.val = getF4( fp );
452 if ( tex->type == ID_IMAP )
453 tex->param.imap.wraph.val = getF4( fp );
457 shdr = _pico_calloc( 1, sizeof( lwPlugin ));
458 if ( !shdr ) goto Fail;
459 shdr->name = getbytes( fp, sz );
460 lwListAdd( (void *) &surf->shader, shdr );
466 shdr->data = getbytes( fp, sz );
473 /* error while reading current subchunk? */
476 if ( rlen < 0 || rlen > sz ) goto Fail;
478 /* skip unread parts of the current subchunk */
481 _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
483 /* end of the SURF chunk? */
485 if ( cksize <= _pico_memstream_tell( fp ) - pos )
488 /* get the next subchunk header */
493 if ( 6 != get_flen() ) goto Fail;
499 if ( surf ) lwFreeSurface( surf );
505 ======================================================================
508 Read polygon records from a POLS chunk in an LWOB file. The polygons
509 are added to the array in the lwPolygonList.
510 ====================================================================== */
512 int lwGetPolygons5( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset )
516 unsigned char *buf, *bp;
517 int i, j, nv, nverts, npols;
520 if ( cksize == 0 ) return 1;
522 /* read the whole chunk */
525 buf = getbytes( fp, cksize );
526 if ( !buf ) goto Fail;
528 /* count the polygons and vertices */
534 while ( bp < buf + cksize ) {
540 if ( i < 0 ) bp += 2; /* detail polygons */
543 if ( !lwAllocPolygons( plist, npols, nverts ))
546 /* fill in the new polygons */
549 pp = plist->pol + plist->offset;
550 pv = plist->pol[ 0 ].v + plist->voffset;
552 for ( i = 0; i < npols; i++ ) {
557 if ( !pp->v ) pp->v = pv;
558 for ( j = 0; j < nv; j++ )
559 pv[ j ].index = sgetU2( &bp ) + ptoffset;
566 pp->surf = ( lwSurface * ) (size_t) j;
576 if ( buf ) _pico_free( buf );
577 lwFreePolygons( plist );
583 ======================================================================
586 Returns the contents of an LWOB, given its filename, or NULL if the
587 file couldn't be loaded. On failure, failID and failpos can be used
588 to diagnose the cause.
590 1. If the file isn't an LWOB, failpos will contain 12 and failID will
593 2. If an error occurs while reading an LWOB, failID will contain the
594 most recently read IFF chunk ID, and failpos will contain the
595 value returned by _pico_memstream_tell() at the time of the failure.
597 3. If the file couldn't be opened, or an error occurs while reading
598 the first 12 bytes, both failID and failpos will be unchanged.
600 If you don't need this information, failID and failpos can be NULL.
601 ====================================================================== */
603 lwObject *lwGetObject5( const char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos )
608 unsigned int id, formsize, type, cksize;
613 if ( !fp ) return NULL;
615 /* read the first 12 bytes */
619 formsize = getU4( fp );
621 if ( 12 != get_flen() ) {
627 if ( id != ID_FORM || type != ID_LWOB ) {
628 if ( failpos ) *failpos = 12;
632 /* allocate an object and a default layer */
634 object = _pico_calloc( 1, sizeof( lwObject ));
635 if ( !object ) goto Fail;
637 layer = _pico_calloc( 1, sizeof( lwLayer ));
638 if ( !layer ) goto Fail;
639 object->layer = layer;
642 /* get the first chunk header */
645 cksize = getU4( fp );
646 if ( 0 > get_flen() ) goto Fail;
648 /* process chunks as they're encountered */
651 cksize += cksize & 1;
656 if ( !lwGetPoints( fp, cksize, &layer->point ))
661 if ( !lwGetPolygons5( fp, cksize, &layer->polygon,
662 layer->point.offset ))
667 if ( !lwGetTags( fp, cksize, &object->taglist ))
672 node = ( lwNode * ) lwGetSurface5( fp, cksize, object );
673 if ( !node ) goto Fail;
674 lwListAdd( (void *) &object->surf, node );
679 _pico_memstream_seek( fp, cksize, PICO_SEEK_CUR );
683 /* end of the file? */
685 if ( formsize <= (unsigned int) (_pico_memstream_tell( fp ) - 8) ) break;
687 /* get the next chunk header */
691 cksize = getU4( fp );
692 if ( 8 != get_flen() ) goto Fail;
695 lwGetBoundingBox( &layer->point, layer->bbox );
696 lwGetPolyNormals( &layer->point, &layer->polygon );
697 if ( !lwGetPointPolygons( &layer->point, &layer->polygon )) goto Fail;
698 if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist,
699 &object->surf, &object->nsurfs )) goto Fail;
700 lwGetVertNormals( &layer->point, &layer->polygon );
705 if ( failID ) *failID = id;
707 if ( failpos ) *failpos = _pico_memstream_tell( fp );
709 lwFreeObject( object );
713 int lwValidateObject5( const char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos )
715 unsigned int id, type;
720 if ( !fp ) return PICO_PMV_ERROR_MEMORY;
722 /* read the first 12 bytes */
726 /* formsize = */ getU4( fp );
728 if ( 12 != get_flen() ) {
729 return PICO_PMV_ERROR_SIZE;
734 if ( id != ID_FORM || type != ID_LWOB ) {
735 if ( failpos ) *failpos = 12;
736 return PICO_PMV_ERROR_IDENT;