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 )
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 );
357 if ( flags & 1 ) i = 0;
358 if ( flags & 2 ) i = 1;
359 if ( flags & 4 ) i = 2;
361 if ( tex->type == ID_IMAP )
362 tex->param.imap.axis = i;
364 tex->param.proc.axis = i;
366 if ( flags & 8 ) tex->tmap.coord_sys = 1;
367 if ( flags & 16 ) tex->negative = 1;
368 if ( flags & 32 ) tex->param.imap.pblend = 1;
370 tex->param.imap.aa_strength = 1.0f;
371 tex->param.imap.aas_flags = 1;
376 for ( i = 0; i < 3; i++ )
377 tex->tmap.size.val[ i ] = getF4( fp );
381 for ( i = 0; i < 3; i++ )
382 tex->tmap.center.val[ i ] = getF4( fp );
386 for ( i = 0; i < 3; i++ )
387 tex->tmap.falloff.val[ i ] = getF4( fp );
391 for ( i = 0; i < 3; i++ )
392 v[ i ] = getF4( fp );
393 tex->tmap.center.eindex = add_tvel( tex->tmap.center.val, v,
394 &obj->env, &obj->nenvs );
398 if ( tex->type == ID_PROC )
399 for ( i = 0; i < 3; i++ )
400 tex->param.proc.value[ i ] = getU1( fp ) / 255.0f;
404 tex->param.proc.value[ 0 ] = getI2( fp ) / 256.0f;
408 if ( tex->type == ID_IMAP )
409 tex->param.imap.amplitude.val = getF4( fp );
414 tex->param.imap.cindex = add_clip( s, &obj->clip, &obj->nclips );
418 tex->param.imap.aa_strength = getF4( fp );
419 tex->param.imap.aas_flags = 1;
423 tex->tmap.ref_object = getbytes( fp, sz );
427 tex->opacity.val = getF4( fp );
431 if ( tex->type == ID_IMAP )
432 tex->param.imap.wrapw.val = getF4( fp );
436 if ( tex->type == ID_IMAP )
437 tex->param.imap.wraph.val = getF4( fp );
441 shdr = _pico_calloc( 1, sizeof( lwPlugin ));
442 if ( !shdr ) goto Fail;
443 shdr->name = getbytes( fp, sz );
444 lwListAdd( (void *) &surf->shader, shdr );
449 shdr->data = getbytes( fp, sz );
456 /* error while reading current subchunk? */
459 if ( rlen < 0 || rlen > sz ) goto Fail;
461 /* skip unread parts of the current subchunk */
464 _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
466 /* end of the SURF chunk? */
468 if ( cksize <= _pico_memstream_tell( fp ) - pos )
471 /* get the next subchunk header */
476 if ( 6 != get_flen() ) goto Fail;
482 if ( surf ) lwFreeSurface( surf );
488 ======================================================================
491 Read polygon records from a POLS chunk in an LWOB file. The polygons
492 are added to the array in the lwPolygonList.
493 ====================================================================== */
495 int lwGetPolygons5( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset )
499 unsigned char *buf, *bp;
500 int i, j, nv, nverts, npols;
503 if ( cksize == 0 ) return 1;
505 /* read the whole chunk */
508 buf = getbytes( fp, cksize );
509 if ( !buf ) goto Fail;
511 /* count the polygons and vertices */
517 while ( bp < buf + cksize ) {
523 if ( i < 0 ) bp += 2; /* detail polygons */
526 if ( !lwAllocPolygons( plist, npols, nverts ))
529 /* fill in the new polygons */
532 pp = plist->pol + plist->offset;
533 pv = plist->pol[ 0 ].v + plist->voffset;
535 for ( i = 0; i < npols; i++ ) {
540 if ( !pp->v ) pp->v = pv;
541 for ( j = 0; j < nv; j++ )
542 pv[ j ].index = sgetU2( &bp ) + ptoffset;
549 pp->surf = ( lwSurface * ) j;
559 if ( buf ) _pico_free( buf );
560 lwFreePolygons( plist );
566 ======================================================================
569 Returns the contents of an LWOB, given its filename, or NULL if the
570 file couldn't be loaded. On failure, failID and failpos can be used
571 to diagnose the cause.
573 1. If the file isn't an LWOB, failpos will contain 12 and failID will
576 2. If an error occurs while reading an LWOB, failID will contain the
577 most recently read IFF chunk ID, and failpos will contain the
578 value returned by _pico_memstream_tell() at the time of the failure.
580 3. If the file couldn't be opened, or an error occurs while reading
581 the first 12 bytes, both failID and failpos will be unchanged.
583 If you don't need this information, failID and failpos can be NULL.
584 ====================================================================== */
586 lwObject *lwGetObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos )
591 unsigned int id, formsize, type, cksize;
596 if ( !fp ) return NULL;
598 /* read the first 12 bytes */
602 formsize = getU4( fp );
604 if ( 12 != get_flen() ) {
610 if ( id != ID_FORM || type != ID_LWOB ) {
611 if ( failpos ) *failpos = 12;
615 /* allocate an object and a default layer */
617 object = _pico_calloc( 1, sizeof( lwObject ));
618 if ( !object ) goto Fail;
620 layer = _pico_calloc( 1, sizeof( lwLayer ));
621 if ( !layer ) goto Fail;
622 object->layer = layer;
625 /* get the first chunk header */
628 cksize = getU4( fp );
629 if ( 0 > get_flen() ) goto Fail;
631 /* process chunks as they're encountered */
634 cksize += cksize & 1;
639 if ( !lwGetPoints( fp, cksize, &layer->point ))
644 if ( !lwGetPolygons5( fp, cksize, &layer->polygon,
645 layer->point.offset ))
650 if ( !lwGetTags( fp, cksize, &object->taglist ))
655 node = ( lwNode * ) lwGetSurface5( fp, cksize, object );
656 if ( !node ) goto Fail;
657 lwListAdd( (void *) &object->surf, node );
662 _pico_memstream_seek( fp, cksize, PICO_SEEK_CUR );
666 /* end of the file? */
668 if ( formsize <= _pico_memstream_tell( fp ) - 8 ) break;
670 /* get the next chunk header */
674 cksize = getU4( fp );
675 if ( 8 != get_flen() ) goto Fail;
678 lwGetBoundingBox( &layer->point, layer->bbox );
679 lwGetPolyNormals( &layer->point, &layer->polygon );
680 if ( !lwGetPointPolygons( &layer->point, &layer->polygon )) goto Fail;
681 if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist,
682 &object->surf, &object->nsurfs )) goto Fail;
683 lwGetVertNormals( &layer->point, &layer->polygon );
688 if ( failID ) *failID = id;
690 if ( failpos ) *failpos = _pico_memstream_tell( fp );
692 lwFreeObject( object );
696 int lwValidateObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos )
698 unsigned int id, formsize, type;
703 if ( !fp ) return PICO_PMV_ERROR_MEMORY;
705 /* read the first 12 bytes */
709 formsize = getU4( fp );
711 if ( 12 != get_flen() ) {
712 return PICO_PMV_ERROR_SIZE;
717 if ( id != ID_FORM || type != ID_LWOB ) {
718 if ( failpos ) *failpos = 12;
719 return PICO_PMV_ERROR_IDENT;