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 ){
64 clip = _pico_calloc( 1, sizeof( lwClip ) );
69 clip->contrast.val = 1.0f;
70 clip->brightness.val = 1.0f;
71 clip->saturation.val = 1.0f;
72 clip->gamma.val = 1.0f;
74 if ( ( p = strstr( s, "(sequence)" ) ) != NULL ) {
77 clip->source.seq.prefix = s;
78 clip->source.seq.digits = 3;
82 clip->source.still.name = s;
86 clip->index = *nclips;
88 lwListAdd( clist, clip );
95 ======================================================================
98 Add a triple of envelopes to simulate the old texture velocity
100 ====================================================================== */
102 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 ) {
116 key0->value = pos[ i ];
119 key1->value = pos[ i ] + vel[ i ] * 30.0f;
121 key0->shape = key1->shape = ID_LINE;
123 env->index = *nenvs + i + 1;
124 env->type = 0x0301 + i;
125 env->name = _pico_alloc( 11 );
127 strcpy( env->name, "Position.X" );
132 env->behavior[ 0 ] = BEH_LINEAR;
133 env->behavior[ 1 ] = BEH_LINEAR;
135 lwListAdd( elist, env );
139 return env->index - 2;
144 ======================================================================
147 Create a new texture for BTEX, CTEX, etc. subchunks.
148 ====================================================================== */
150 static lwTexture *get_texture( char *s ){
153 tex = _pico_calloc( 1, sizeof( lwTexture ) );
158 tex->tmap.size.val[ 0 ] =
159 tex->tmap.size.val[ 1 ] =
160 tex->tmap.size.val[ 2 ] = 1.0f;
161 tex->opacity.val = 1.0f;
164 if ( strstr( s, "Image Map" ) ) {
166 if ( strstr( s, "Planar" ) ) {
167 tex->param.imap.projection = 0;
169 else if ( strstr( s, "Cylindrical" ) ) {
170 tex->param.imap.projection = 1;
172 else if ( strstr( s, "Spherical" ) ) {
173 tex->param.imap.projection = 2;
175 else if ( strstr( s, "Cubic" ) ) {
176 tex->param.imap.projection = 3;
178 else if ( strstr( s, "Front" ) ) {
179 tex->param.imap.projection = 4;
181 tex->param.imap.aa_strength = 1.0f;
182 tex->param.imap.amplitude.val = 1.0f;
187 tex->param.proc.name = s;
195 ======================================================================
198 Read an lwSurface from an LWOB file.
199 ====================================================================== */
201 lwSurface *lwGetSurface5( picoMemStream_t *fp, int cksize, lwObject *obj ){
207 unsigned int id, flags;
212 /* allocate the Surface structure */
214 surf = _pico_calloc( 1, sizeof( lwSurface ) );
219 /* non-zero defaults */
221 surf->color.rgb[ 0 ] = 0.78431f;
222 surf->color.rgb[ 1 ] = 0.78431f;
223 surf->color.rgb[ 2 ] = 0.78431f;
224 surf->diffuse.val = 1.0f;
225 surf->glossiness.val = 0.4f;
226 surf->bump.val = 1.0f;
227 surf->eta.val = 1.0f;
230 /* remember where we started */
233 pos = _pico_memstream_tell( fp );
237 surf->name = getS0( fp );
239 /* first subchunk header */
243 if ( 0 > get_flen() ) {
247 /* process subchunks as they're encountered */
255 surf->color.rgb[ 0 ] = getU1( fp ) / 255.0f;
256 surf->color.rgb[ 1 ] = getU1( fp ) / 255.0f;
257 surf->color.rgb[ 2 ] = getU1( fp ) / 255.0f;
263 surf->smooth = 1.56207f;
266 surf->color_hilite.val = 1.0f;
269 surf->color_filter.val = 1.0f;
272 surf->dif_sharp.val = 0.5f;
278 surf->add_trans.val = 1.0f;
283 surf->luminosity.val = getI2( fp ) / 256.0f;
287 surf->luminosity.val = getF4( fp );
291 surf->diffuse.val = getI2( fp ) / 256.0f;
295 surf->diffuse.val = getF4( fp );
299 surf->specularity.val = getI2( fp ) / 256.0f;
303 surf->specularity.val = getF4( fp );
307 surf->glossiness.val = ( float ) log( getU2( fp ) ) / 20.7944f;
311 surf->smooth = getF4( fp );
315 surf->reflection.val.val = getI2( fp ) / 256.0f;
319 surf->reflection.options = getU2( fp );
324 surf->reflection.cindex = add_clip( s, &obj->clip, &obj->nclips );
325 surf->reflection.options = 3;
329 surf->reflection.seam_angle = getF4( fp );
333 surf->transparency.val.val = getI2( fp ) / 256.0f;
337 surf->eta.val = getF4( fp );
341 s = getbytes( fp, sz );
342 tex = get_texture( s );
343 lwListAdd( &surf->bump.tex, tex );
347 s = getbytes( fp, sz );
348 tex = get_texture( s );
349 lwListAdd( &surf->color.tex, tex );
353 s = getbytes( fp, sz );
354 tex = get_texture( s );
355 lwListAdd( &surf->diffuse.tex, tex );
359 s = getbytes( fp, sz );
360 tex = get_texture( s );
361 lwListAdd( &surf->luminosity.tex, tex );
365 s = getbytes( fp, sz );
366 tex = get_texture( s );
367 lwListAdd( &surf->reflection.val.tex, tex );
371 s = getbytes( fp, sz );
372 tex = get_texture( s );
373 lwListAdd( &surf->specularity.tex, tex );
377 s = getbytes( fp, sz );
378 tex = get_texture( s );
379 lwListAdd( &surf->transparency.val.tex, tex );
395 if ( tex->type == ID_IMAP ) {
396 tex->param.imap.axis = i;
399 tex->param.proc.axis = i;
403 tex->tmap.coord_sys = 1;
409 tex->param.imap.pblend = 1;
412 tex->param.imap.aa_strength = 1.0f;
413 tex->param.imap.aas_flags = 1;
418 for ( i = 0; i < 3; i++ )
419 tex->tmap.size.val[ i ] = getF4( fp );
423 for ( i = 0; i < 3; i++ )
424 tex->tmap.center.val[ i ] = getF4( fp );
428 for ( i = 0; i < 3; i++ )
429 tex->tmap.falloff.val[ i ] = getF4( fp );
433 for ( i = 0; i < 3; i++ )
434 v[ i ] = getF4( fp );
435 tex->tmap.center.eindex = add_tvel( tex->tmap.center.val, v,
436 &obj->env, &obj->nenvs );
440 if ( tex->type == ID_PROC ) {
441 for ( i = 0; i < 3; i++ )
442 tex->param.proc.value[ i ] = getU1( fp ) / 255.0f;
447 tex->param.proc.value[ 0 ] = getI2( fp ) / 256.0f;
451 if ( tex->type == ID_IMAP ) {
452 tex->param.imap.amplitude.val = getF4( fp );
458 tex->param.imap.cindex = add_clip( s, &obj->clip, &obj->nclips );
462 tex->param.imap.aa_strength = getF4( fp );
463 tex->param.imap.aas_flags = 1;
467 tex->tmap.ref_object = getbytes( fp, sz );
471 tex->opacity.val = getF4( fp );
475 if ( tex->type == ID_IMAP ) {
476 tex->param.imap.wrapw.val = getF4( fp );
481 if ( tex->type == ID_IMAP ) {
482 tex->param.imap.wraph.val = getF4( fp );
487 shdr = _pico_calloc( 1, sizeof( lwPlugin ) );
491 shdr->name = getbytes( fp, sz );
492 lwListAdd( &surf->shader, shdr );
497 shdr->data = getbytes( fp, sz );
504 /* error while reading current subchunk? */
507 if ( rlen < 0 || rlen > sz ) {
511 /* skip unread parts of the current subchunk */
514 _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
517 /* end of the SURF chunk? */
519 if ( cksize <= _pico_memstream_tell( fp ) - pos ) {
523 /* get the next subchunk header */
528 if ( 6 != get_flen() ) {
537 lwFreeSurface( surf );
544 ======================================================================
547 Read polygon records from a POLS chunk in an LWOB file. The polygons
548 are added to the array in the lwPolygonList.
549 ====================================================================== */
551 int lwGetPolygons5( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset ){
554 unsigned char *buf, *bp;
555 int i, j, nv, nverts, npols;
562 /* read the whole chunk */
565 buf = getbytes( fp, cksize );
570 /* count the polygons and vertices */
576 while ( bp < buf + cksize ) {
583 bp += 2; /* detail polygons */
587 if ( !lwAllocPolygons( plist, npols, nverts ) ) {
591 /* fill in the new polygons */
594 pp = plist->pol + plist->offset;
595 pv = plist->pol[ 0 ].v + plist->voffset;
597 for ( i = 0; i < npols; i++ ) {
605 for ( j = 0; j < nv; j++ )
606 pv[ j ].index = sgetU2( &bp ) + ptoffset;
613 pp->surf = ( lwSurface * ) ( (size_t)j );
626 lwFreePolygons( plist );
632 ======================================================================
635 Returns the contents of an LWOB, given its filename, or NULL if the
636 file couldn't be loaded. On failure, failID and failpos can be used
637 to diagnose the cause.
639 1. If the file isn't an LWOB, failpos will contain 12 and failID will
642 2. If an error occurs while reading an LWOB, failID will contain the
643 most recently read IFF chunk ID, and failpos will contain the
644 value returned by _pico_memstream_tell() at the time of the failure.
646 3. If the file couldn't be opened, or an error occurs while reading
647 the first 12 bytes, both failID and failpos will be unchanged.
649 If you don't need this information, failID and failpos can be NULL.
650 ====================================================================== */
652 lwObject *lwGetObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ){
656 unsigned int id, formsize, type, cksize;
665 /* read the first 12 bytes */
669 formsize = getU4( fp );
671 if ( 12 != get_flen() ) {
677 if ( id != ID_FORM || type != ID_LWOB ) {
684 /* allocate an object and a default layer */
686 object = _pico_calloc( 1, sizeof( lwObject ) );
691 layer = _pico_calloc( 1, sizeof( lwLayer ) );
695 object->layer = layer;
698 /* get the first chunk header */
701 cksize = getU4( fp );
702 if ( 0 > get_flen() ) {
706 /* process chunks as they're encountered */
709 cksize += cksize & 1;
714 if ( !lwGetPoints( fp, cksize, &layer->point ) ) {
720 if ( !lwGetPolygons5( fp, cksize, &layer->polygon,
721 layer->point.offset ) ) {
727 if ( !lwGetTags( fp, cksize, &object->taglist ) ) {
733 node = ( lwNode * ) lwGetSurface5( fp, cksize, object );
737 lwListAdd( &object->surf, node );
742 _pico_memstream_seek( fp, cksize, PICO_SEEK_CUR );
746 /* end of the file? */
748 if ( formsize <= _pico_memstream_tell( fp ) - 8 ) {
752 /* get the next chunk header */
756 cksize = getU4( fp );
757 if ( 8 != get_flen() ) {
762 lwGetBoundingBox( &layer->point, layer->bbox );
763 lwGetPolyNormals( &layer->point, &layer->polygon );
764 if ( !lwGetPointPolygons( &layer->point, &layer->polygon ) ) {
767 if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist,
768 &object->surf, &object->nsurfs ) ) {
771 lwGetVertNormals( &layer->point, &layer->polygon );
781 *failpos = _pico_memstream_tell( fp );
784 lwFreeObject( object );
788 int lwValidateObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ){
789 unsigned int id, formsize, type;
795 return PICO_PMV_ERROR_MEMORY;
798 /* read the first 12 bytes */
802 formsize = getU4( fp );
804 if ( 12 != get_flen() ) {
805 return PICO_PMV_ERROR_SIZE;
810 if ( id != ID_FORM || type != ID_LWOB ) {
814 return PICO_PMV_ERROR_IDENT;