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)" ) ) ) {
77 clip->source.seq.prefix = s;
78 clip->source.seq.digits = 3;
82 clip->source.still.name = s;
86 clip->index = *nclips;
88 lwListAdd( (void *) 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( (void *) 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 ){
203 lwTexture *tex = NULL;
204 lwPlugin *shdr = NULL;
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( (void *) &surf->bump.tex, tex );
347 s = getbytes( fp, sz );
348 tex = get_texture( s );
349 lwListAdd( (void *) &surf->color.tex, tex );
353 s = getbytes( fp, sz );
354 tex = get_texture( s );
355 lwListAdd( (void *) &surf->diffuse.tex, tex );
359 s = getbytes( fp, sz );
360 tex = get_texture( s );
361 lwListAdd( (void *) &surf->luminosity.tex, tex );
365 s = getbytes( fp, sz );
366 tex = get_texture( s );
367 lwListAdd( (void *) &surf->reflection.val.tex, tex );
371 s = getbytes( fp, sz );
372 tex = get_texture( s );
373 lwListAdd( (void *) &surf->specularity.tex, tex );
377 s = getbytes( fp, sz );
378 tex = get_texture( s );
379 lwListAdd( (void *) &surf->transparency.val.tex, tex );
402 if ( tex->type == ID_IMAP ) {
403 tex->param.imap.axis = i;
406 tex->param.proc.axis = i;
410 tex->tmap.coord_sys = 1;
416 tex->param.imap.pblend = 1;
419 tex->param.imap.aa_strength = 1.0f;
420 tex->param.imap.aas_flags = 1;
428 for ( i = 0; i < 3; i++ )
429 tex->tmap.size.val[ i ] = getF4( fp );
436 for ( i = 0; i < 3; i++ )
437 tex->tmap.center.val[ i ] = getF4( fp );
444 for ( i = 0; i < 3; i++ )
445 tex->tmap.falloff.val[ i ] = getF4( fp );
452 for ( i = 0; i < 3; i++ )
453 v[ i ] = getF4( fp );
454 tex->tmap.center.eindex = add_tvel( tex->tmap.center.val, v,
455 &obj->env, &obj->nenvs );
462 if ( tex->type == ID_PROC ) {
463 for ( i = 0; i < 3; i++ )
464 tex->param.proc.value[ i ] = getU1( fp ) / 255.0f;
472 tex->param.proc.value[ 0 ] = getI2( fp ) / 256.0f;
479 if ( tex->type == ID_IMAP ) {
480 tex->param.imap.amplitude.val = getF4( fp );
489 tex->param.imap.cindex = add_clip( s, &obj->clip, &obj->nclips );
496 tex->param.imap.aa_strength = getF4( fp );
497 tex->param.imap.aas_flags = 1;
504 tex->tmap.ref_object = getbytes( fp, sz );
511 tex->opacity.val = getF4( fp );
518 if ( tex->type == ID_IMAP ) {
519 tex->param.imap.wrapw.val = getF4( fp );
527 if ( tex->type == ID_IMAP ) {
528 tex->param.imap.wraph.val = getF4( fp );
533 shdr = _pico_calloc( 1, sizeof( lwPlugin ) );
537 shdr->name = getbytes( fp, sz );
538 lwListAdd( (void *) &surf->shader, shdr );
546 shdr->data = getbytes( fp, sz );
553 /* error while reading current subchunk? */
556 if ( rlen < 0 || rlen > sz ) {
560 /* skip unread parts of the current subchunk */
563 _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
566 /* end of the SURF chunk? */
568 if ( cksize <= _pico_memstream_tell( fp ) - pos ) {
572 /* get the next subchunk header */
577 if ( 6 != get_flen() ) {
586 lwFreeSurface( surf );
593 ======================================================================
596 Read polygon records from a POLS chunk in an LWOB file. The polygons
597 are added to the array in the lwPolygonList.
598 ====================================================================== */
600 int lwGetPolygons5( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset ){
603 unsigned char *buf, *bp;
604 int i, j, nv, nverts, npols;
611 /* read the whole chunk */
614 buf = getbytes( fp, cksize );
619 /* count the polygons and vertices */
625 while ( bp < buf + cksize ) {
632 bp += 2; /* detail polygons */
636 if ( !lwAllocPolygons( plist, npols, nverts ) ) {
640 /* fill in the new polygons */
643 pp = plist->pol + plist->offset;
644 pv = plist->pol[ 0 ].v + plist->voffset;
646 for ( i = 0; i < npols; i++ ) {
654 for ( j = 0; j < nv; j++ )
655 pv[ j ].index = sgetU2( &bp ) + ptoffset;
662 pp->surf = ( lwSurface * ) (size_t) j;
675 lwFreePolygons( plist );
681 ======================================================================
684 Returns the contents of an LWOB, given its filename, or NULL if the
685 file couldn't be loaded. On failure, failID and failpos can be used
686 to diagnose the cause.
688 1. If the file isn't an LWOB, failpos will contain 12 and failID will
691 2. If an error occurs while reading an LWOB, failID will contain the
692 most recently read IFF chunk ID, and failpos will contain the
693 value returned by _pico_memstream_tell() at the time of the failure.
695 3. If the file couldn't be opened, or an error occurs while reading
696 the first 12 bytes, both failID and failpos will be unchanged.
698 If you don't need this information, failID and failpos can be NULL.
699 ====================================================================== */
701 lwObject *lwGetObject5( const char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ){
705 unsigned int id, formsize, type, cksize;
714 /* read the first 12 bytes */
718 formsize = getU4( fp );
720 if ( 12 != get_flen() ) {
726 if ( id != ID_FORM || type != ID_LWOB ) {
733 /* allocate an object and a default layer */
735 object = _pico_calloc( 1, sizeof( lwObject ) );
740 layer = _pico_calloc( 1, sizeof( lwLayer ) );
744 object->layer = layer;
747 /* get the first chunk header */
750 cksize = getU4( fp );
751 if ( 0 > get_flen() ) {
755 /* process chunks as they're encountered */
758 cksize += cksize & 1;
763 if ( !lwGetPoints( fp, cksize, &layer->point ) ) {
769 if ( !lwGetPolygons5( fp, cksize, &layer->polygon,
770 layer->point.offset ) ) {
776 if ( !lwGetTags( fp, cksize, &object->taglist ) ) {
782 node = ( lwNode * ) lwGetSurface5( fp, cksize, object );
786 lwListAdd( (void *) &object->surf, node );
791 _pico_memstream_seek( fp, cksize, PICO_SEEK_CUR );
795 /* end of the file? */
797 if ( formsize <= (unsigned int) ( _pico_memstream_tell( fp ) - 8 ) ) {
801 /* get the next chunk header */
805 cksize = getU4( fp );
806 if ( 8 != get_flen() ) {
811 lwGetBoundingBox( &layer->point, layer->bbox );
812 lwGetPolyNormals( &layer->point, &layer->polygon );
813 if ( !lwGetPointPolygons( &layer->point, &layer->polygon ) ) {
816 if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist,
817 &object->surf, &object->nsurfs ) ) {
820 lwGetVertNormals( &layer->point, &layer->polygon );
830 *failpos = _pico_memstream_tell( fp );
833 lwFreeObject( object );
837 int lwValidateObject5( const char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ){
838 unsigned int id, type;
844 return PICO_PMV_ERROR_MEMORY;
847 /* read the first 12 bytes */
851 /* formsize = */ getU4( fp );
853 if ( 12 != get_flen() ) {
854 return PICO_PMV_ERROR_SIZE;
859 if ( id != ID_FORM || type != ID_LWOB ) {
863 return PICO_PMV_ERROR_IDENT;