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"
13 #include "globaldefs.h"
15 /* disable warnings */
16 #if GDEF_COMPILER_MSVC
17 #pragma warning( disable:4018 ) /* signed/unsigned mismatch */
21 /* IDs specific to LWOB */
23 #define ID_SRFS LWID_( 'S','R','F','S' )
24 #define ID_FLAG LWID_( 'F','L','A','G' )
25 #define ID_VLUM LWID_( 'V','L','U','M' )
26 #define ID_VDIF LWID_( 'V','D','I','F' )
27 #define ID_VSPC LWID_( 'V','S','P','C' )
28 #define ID_RFLT LWID_( 'R','F','L','T' )
29 #define ID_BTEX LWID_( 'B','T','E','X' )
30 #define ID_CTEX LWID_( 'C','T','E','X' )
31 #define ID_DTEX LWID_( 'D','T','E','X' )
32 #define ID_LTEX LWID_( 'L','T','E','X' )
33 #define ID_RTEX LWID_( 'R','T','E','X' )
34 #define ID_STEX LWID_( 'S','T','E','X' )
35 #define ID_TTEX LWID_( 'T','T','E','X' )
36 #define ID_TFLG LWID_( 'T','F','L','G' )
37 #define ID_TSIZ LWID_( 'T','S','I','Z' )
38 #define ID_TCTR LWID_( 'T','C','T','R' )
39 #define ID_TFAL LWID_( 'T','F','A','L' )
40 #define ID_TVEL LWID_( 'T','V','E','L' )
41 #define ID_TCLR LWID_( 'T','C','L','R' )
42 #define ID_TVAL LWID_( 'T','V','A','L' )
43 #define ID_TAMP LWID_( 'T','A','M','P' )
44 #define ID_TIMG LWID_( 'T','I','M','G' )
45 #define ID_TAAS LWID_( 'T','A','A','S' )
46 #define ID_TREF LWID_( 'T','R','E','F' )
47 #define ID_TOPC LWID_( 'T','O','P','C' )
48 #define ID_SDAT LWID_( 'S','D','A','T' )
49 #define ID_TFP0 LWID_( 'T','F','P','0' )
50 #define ID_TFP1 LWID_( 'T','F','P','1' )
54 ======================================================================
57 Add a clip to the clip list. Used to store the contents of an RIMG or
58 TIMG surface subchunk.
59 ====================================================================== */
61 static int add_clip( char *s, lwClip **clist, int *nclips ){
65 clip = _pico_calloc( 1, sizeof( lwClip ) );
70 clip->contrast.val = 1.0f;
71 clip->brightness.val = 1.0f;
72 clip->saturation.val = 1.0f;
73 clip->gamma.val = 1.0f;
75 if ( ( p = strstr( s, "(sequence)" ) ) != NULL ) {
78 clip->source.seq.prefix = s;
79 clip->source.seq.digits = 3;
83 clip->source.still.name = s;
87 clip->index = *nclips;
89 lwListAdd( (void *) clist, clip );
96 ======================================================================
99 Add a triple of envelopes to simulate the old texture velocity
101 ====================================================================== */
103 static int add_tvel( float pos[], float vel[], lwEnvelope **elist, int *nenvs ){
108 for ( i = 0; i < 3; i++ ) {
109 env = _pico_calloc( 1, sizeof( lwEnvelope ) );
110 key0 = _pico_calloc( 1, sizeof( lwKey ) );
111 key1 = _pico_calloc( 1, sizeof( lwKey ) );
112 if ( !env || !key0 || !key1 ) {
117 key0->value = pos[ i ];
120 key1->value = pos[ i ] + vel[ i ] * 30.0f;
122 key0->shape = key1->shape = ID_LINE;
124 env->index = *nenvs + i + 1;
125 env->type = 0x0301 + i;
126 env->name = _pico_alloc( 11 );
128 strcpy( env->name, "Position.X" );
133 env->behavior[ 0 ] = BEH_LINEAR;
134 env->behavior[ 1 ] = BEH_LINEAR;
136 lwListAdd( (void *) elist, env );
140 return env->index - 2;
145 ======================================================================
148 Create a new texture for BTEX, CTEX, etc. subchunks.
149 ====================================================================== */
151 static lwTexture *get_texture( char *s ){
154 tex = _pico_calloc( 1, sizeof( lwTexture ) );
159 tex->tmap.size.val[ 0 ] =
160 tex->tmap.size.val[ 1 ] =
161 tex->tmap.size.val[ 2 ] = 1.0f;
162 tex->opacity.val = 1.0f;
165 if ( strstr( s, "Image Map" ) ) {
167 if ( strstr( s, "Planar" ) ) {
168 tex->param.imap.projection = 0;
170 else if ( strstr( s, "Cylindrical" ) ) {
171 tex->param.imap.projection = 1;
173 else if ( strstr( s, "Spherical" ) ) {
174 tex->param.imap.projection = 2;
176 else if ( strstr( s, "Cubic" ) ) {
177 tex->param.imap.projection = 3;
179 else if ( strstr( s, "Front" ) ) {
180 tex->param.imap.projection = 4;
182 tex->param.imap.aa_strength = 1.0f;
183 tex->param.imap.amplitude.val = 1.0f;
188 tex->param.proc.name = s;
196 ======================================================================
199 Read an lwSurface from an LWOB file.
200 ====================================================================== */
202 lwSurface *lwGetSurface5( picoMemStream_t *fp, int cksize, lwObject *obj ){
204 lwTexture *tex = NULL;
205 lwPlugin *shdr = NULL;
208 unsigned int id, flags;
213 /* allocate the Surface structure */
215 surf = _pico_calloc( 1, sizeof( lwSurface ) );
220 /* non-zero defaults */
222 surf->color.rgb[ 0 ] = 0.78431f;
223 surf->color.rgb[ 1 ] = 0.78431f;
224 surf->color.rgb[ 2 ] = 0.78431f;
225 surf->diffuse.val = 1.0f;
226 surf->glossiness.val = 0.4f;
227 surf->bump.val = 1.0f;
228 surf->eta.val = 1.0f;
231 /* remember where we started */
234 pos = _pico_memstream_tell( fp );
238 surf->name = getS0( fp );
240 /* first subchunk header */
244 if ( 0 > get_flen() ) {
248 /* process subchunks as they're encountered */
256 surf->color.rgb[ 0 ] = getU1( fp ) / 255.0f;
257 surf->color.rgb[ 1 ] = getU1( fp ) / 255.0f;
258 surf->color.rgb[ 2 ] = getU1( fp ) / 255.0f;
264 surf->smooth = 1.56207f;
267 surf->color_hilite.val = 1.0f;
270 surf->color_filter.val = 1.0f;
273 surf->dif_sharp.val = 0.5f;
279 surf->add_trans.val = 1.0f;
284 surf->luminosity.val = getI2( fp ) / 256.0f;
288 surf->luminosity.val = getF4( fp );
292 surf->diffuse.val = getI2( fp ) / 256.0f;
296 surf->diffuse.val = getF4( fp );
300 surf->specularity.val = getI2( fp ) / 256.0f;
304 surf->specularity.val = getF4( fp );
308 surf->glossiness.val = ( float ) log( getU2( fp ) ) / 20.7944f;
312 surf->smooth = getF4( fp );
316 surf->reflection.val.val = getI2( fp ) / 256.0f;
320 surf->reflection.options = getU2( fp );
325 surf->reflection.cindex = add_clip( s, &obj->clip, &obj->nclips );
326 surf->reflection.options = 3;
330 surf->reflection.seam_angle = getF4( fp );
334 surf->transparency.val.val = getI2( fp ) / 256.0f;
338 surf->eta.val = getF4( fp );
342 s = getbytes( fp, sz );
343 tex = get_texture( s );
344 lwListAdd( (void *) &surf->bump.tex, tex );
348 s = getbytes( fp, sz );
349 tex = get_texture( s );
350 lwListAdd( (void *) &surf->color.tex, tex );
354 s = getbytes( fp, sz );
355 tex = get_texture( s );
356 lwListAdd( (void *) &surf->diffuse.tex, tex );
360 s = getbytes( fp, sz );
361 tex = get_texture( s );
362 lwListAdd( (void *) &surf->luminosity.tex, tex );
366 s = getbytes( fp, sz );
367 tex = get_texture( s );
368 lwListAdd( (void *) &surf->reflection.val.tex, tex );
372 s = getbytes( fp, sz );
373 tex = get_texture( s );
374 lwListAdd( (void *) &surf->specularity.tex, tex );
378 s = getbytes( fp, sz );
379 tex = get_texture( s );
380 lwListAdd( (void *) &surf->transparency.val.tex, tex );
392 //only one of the three axis bits should be set
406 if ( tex->type == ID_IMAP ) {
407 tex->param.imap.axis = i;
410 tex->param.proc.axis = i;
414 tex->tmap.coord_sys = 1;
420 tex->param.imap.pblend = 1;
423 tex->param.imap.aa_strength = 1.0f;
424 tex->param.imap.aas_flags = 1;
432 for ( i = 0; i < 3; i++ )
433 tex->tmap.size.val[ i ] = getF4( fp );
440 for ( i = 0; i < 3; i++ )
441 tex->tmap.center.val[ i ] = getF4( fp );
448 for ( i = 0; i < 3; i++ )
449 tex->tmap.falloff.val[ i ] = getF4( fp );
456 for ( i = 0; i < 3; i++ )
457 v[ i ] = getF4( fp );
458 tex->tmap.center.eindex = add_tvel( tex->tmap.center.val, v,
459 &obj->env, &obj->nenvs );
466 if ( tex->type == ID_PROC ) {
467 for ( i = 0; i < 3; i++ )
468 tex->param.proc.value[ i ] = getU1( fp ) / 255.0f;
476 tex->param.proc.value[ 0 ] = getI2( fp ) / 256.0f;
483 if ( tex->type == ID_IMAP ) {
484 tex->param.imap.amplitude.val = getF4( fp );
493 tex->param.imap.cindex = add_clip( s, &obj->clip, &obj->nclips );
500 tex->param.imap.aa_strength = getF4( fp );
501 tex->param.imap.aas_flags = 1;
508 tex->tmap.ref_object = getbytes( fp, sz );
515 tex->opacity.val = getF4( fp );
522 if ( tex->type == ID_IMAP ) {
523 tex->param.imap.wrapw.val = getF4( fp );
531 if ( tex->type == ID_IMAP ) {
532 tex->param.imap.wraph.val = getF4( fp );
537 shdr = _pico_calloc( 1, sizeof( lwPlugin ) );
541 shdr->name = getbytes( fp, sz );
542 lwListAdd( (void *) &surf->shader, shdr );
550 shdr->data = getbytes( fp, sz );
557 /* error while reading current subchunk? */
560 if ( rlen < 0 || rlen > sz ) {
564 /* skip unread parts of the current subchunk */
567 _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
570 /* end of the SURF chunk? */
572 if ( cksize <= _pico_memstream_tell( fp ) - pos ) {
576 /* get the next subchunk header */
581 if ( 6 != get_flen() ) {
590 lwFreeSurface( surf );
597 ======================================================================
600 Read polygon records from a POLS chunk in an LWOB file. The polygons
601 are added to the array in the lwPolygonList.
602 ====================================================================== */
604 int lwGetPolygons5( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset ){
607 unsigned char *buf, *bp;
608 int i, j, nv, nverts, npols;
615 /* read the whole chunk */
618 buf = getbytes( fp, cksize );
623 /* count the polygons and vertices */
629 while ( bp < buf + cksize ) {
636 bp += 2; /* detail polygons */
640 if ( !lwAllocPolygons( plist, npols, nverts ) ) {
644 /* fill in the new polygons */
647 pp = plist->pol + plist->offset;
648 pv = plist->pol[ 0 ].v + plist->voffset;
650 for ( i = 0; i < npols; i++ ) {
658 for ( j = 0; j < nv; j++ )
659 pv[ j ].index = sgetU2( &bp ) + ptoffset;
666 pp->surf = ( lwSurface * ) (size_t) j;
679 lwFreePolygons( plist );
685 ======================================================================
688 Returns the contents of an LWOB, given its filename, or NULL if the
689 file couldn't be loaded. On failure, failID and failpos can be used
690 to diagnose the cause.
692 1. If the file isn't an LWOB, failpos will contain 12 and failID will
695 2. If an error occurs while reading an LWOB, failID will contain the
696 most recently read IFF chunk ID, and failpos will contain the
697 value returned by _pico_memstream_tell() at the time of the failure.
699 3. If the file couldn't be opened, or an error occurs while reading
700 the first 12 bytes, both failID and failpos will be unchanged.
702 If you don't need this information, failID and failpos can be NULL.
703 ====================================================================== */
705 lwObject *lwGetObject5( const char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ){
709 unsigned int id, formsize, type, cksize;
718 /* read the first 12 bytes */
722 formsize = getU4( fp );
724 if ( 12 != get_flen() ) {
730 if ( id != ID_FORM || type != ID_LWOB ) {
737 /* allocate an object and a default layer */
739 object = _pico_calloc( 1, sizeof( lwObject ) );
744 layer = _pico_calloc( 1, sizeof( lwLayer ) );
748 object->layer = layer;
751 /* get the first chunk header */
754 cksize = getU4( fp );
755 if ( 0 > get_flen() ) {
759 /* process chunks as they're encountered */
762 cksize += cksize & 1;
767 if ( !lwGetPoints( fp, cksize, &layer->point ) ) {
773 if ( !lwGetPolygons5( fp, cksize, &layer->polygon,
774 layer->point.offset ) ) {
780 if ( !lwGetTags( fp, cksize, &object->taglist ) ) {
786 node = ( lwNode * ) lwGetSurface5( fp, cksize, object );
790 lwListAdd( (void *) &object->surf, node );
795 _pico_memstream_seek( fp, cksize, PICO_SEEK_CUR );
799 /* end of the file? */
801 if ( formsize <= (unsigned int) ( _pico_memstream_tell( fp ) - 8 ) ) {
805 /* get the next chunk header */
809 cksize = getU4( fp );
810 if ( 8 != get_flen() ) {
815 lwGetBoundingBox( &layer->point, layer->bbox );
816 lwGetPolyNormals( &layer->point, &layer->polygon );
817 if ( !lwGetPointPolygons( &layer->point, &layer->polygon ) ) {
820 if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist,
821 &object->surf, &object->nsurfs ) ) {
824 lwGetVertNormals( &layer->point, &layer->polygon );
834 *failpos = _pico_memstream_tell( fp );
837 lwFreeObject( object );
841 int lwValidateObject5( const char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ){
842 unsigned int id, type;
848 return PICO_PMV_ERROR_MEMORY;
851 /* read the first 12 bytes */
855 /* formsize = */ getU4( fp );
857 if ( 12 != get_flen() ) {
858 return PICO_PMV_ERROR_SIZE;
863 if ( id != ID_FORM || type != ID_LWOB ) {
867 return PICO_PMV_ERROR_IDENT;