2 ======================================================================
5 Surface functions for an LWO2 reader.
8 ====================================================================== */
10 #include "../picointernal.h"
15 ======================================================================
18 Free the memory used by an lwPlugin.
19 ====================================================================== */
21 void lwFreePlugin( lwPlugin *p )
24 if ( p->ord ) _pico_free( p->ord );
25 if ( p->name ) _pico_free( p->name );
26 if ( p->data ) _pico_free( p->data );
33 ======================================================================
36 Free the memory used by an lwTexture.
37 ====================================================================== */
39 void lwFreeTexture( lwTexture *t )
42 if ( t->ord ) _pico_free( t->ord );
45 if ( t->param.imap.vmap_name ) _pico_free( t->param.imap.vmap_name );
46 if ( t->tmap.ref_object ) _pico_free( t->tmap.ref_object );
49 if ( t->param.proc.name ) _pico_free( t->param.proc.name );
50 if ( t->param.proc.data ) _pico_free( t->param.proc.data );
53 if ( t->param.grad.key ) _pico_free( t->param.grad.key );
54 if ( t->param.grad.ikey ) _pico_free( t->param.grad.ikey );
63 ======================================================================
66 Free the memory used by an lwSurface.
67 ====================================================================== */
69 void lwFreeSurface( lwSurface *surf )
72 if ( surf->name ) _pico_free( surf->name );
73 if ( surf->srcname ) _pico_free( surf->srcname );
75 lwListFree( surf->shader, (void *) lwFreePlugin );
77 lwListFree( surf->color.tex, (void *) lwFreeTexture );
78 lwListFree( surf->luminosity.tex, (void *) lwFreeTexture );
79 lwListFree( surf->diffuse.tex, (void *) lwFreeTexture );
80 lwListFree( surf->specularity.tex, (void *) lwFreeTexture );
81 lwListFree( surf->glossiness.tex, (void *) lwFreeTexture );
82 lwListFree( surf->reflection.val.tex, (void *) lwFreeTexture );
83 lwListFree( surf->transparency.val.tex, (void *) lwFreeTexture );
84 lwListFree( surf->eta.tex, (void *) lwFreeTexture );
85 lwListFree( surf->translucency.tex, (void *) lwFreeTexture );
86 lwListFree( surf->bump.tex, (void *) lwFreeTexture );
94 ======================================================================
97 Read a texture map header from a SURF.BLOK in an LWO2 file. This is
98 the first subchunk in a BLOK, and its contents are common to all three
100 ====================================================================== */
102 int lwGetTHeader( picoMemStream_t *fp, int hsz, lwTexture *tex )
109 /* remember where we started */
112 pos = _pico_memstream_tell( fp );
116 tex->ord = getS0( fp );
118 /* first subchunk header */
122 if ( 0 > get_flen() ) return 0;
124 /* process subchunks as they're encountered */
132 tex->chan = getU4( fp );
136 tex->opac_type = getU2( fp );
137 tex->opacity.val = getF4( fp );
138 tex->opacity.eindex = getVX( fp );
142 tex->enabled = getU2( fp );
146 tex->negative = getU2( fp );
150 tex->axis = getU2( fp );
157 /* error while reading current subchunk? */
160 if ( rlen < 0 || rlen > sz ) return 0;
162 /* skip unread parts of the current subchunk */
165 _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
167 /* end of the texture header subchunk? */
169 if ( hsz <= _pico_memstream_tell( fp ) - pos )
172 /* get the next subchunk header */
177 if ( 6 != get_flen() ) return 0;
180 set_flen( _pico_memstream_tell( fp ) - pos );
186 ======================================================================
189 Read a texture map from a SURF.BLOK in an LWO2 file. The TMAP
190 defines the mapping from texture to world or object coordinates.
191 ====================================================================== */
193 int lwGetTMap( picoMemStream_t *fp, int tmapsz, lwTMap *tmap )
199 pos = _pico_memstream_tell( fp );
202 if ( 0 > get_flen() ) return 0;
210 for ( i = 0; i < 3; i++ )
211 tmap->size.val[ i ] = getF4( fp );
212 tmap->size.eindex = getVX( fp );
216 for ( i = 0; i < 3; i++ )
217 tmap->center.val[ i ] = getF4( fp );
218 tmap->center.eindex = getVX( fp );
222 for ( i = 0; i < 3; i++ )
223 tmap->rotate.val[ i ] = getF4( fp );
224 tmap->rotate.eindex = getVX( fp );
228 tmap->fall_type = getU2( fp );
229 for ( i = 0; i < 3; i++ )
230 tmap->falloff.val[ i ] = getF4( fp );
231 tmap->falloff.eindex = getVX( fp );
235 tmap->ref_object = getS0( fp );
239 tmap->coord_sys = getU2( fp );
246 /* error while reading the current subchunk? */
249 if ( rlen < 0 || rlen > sz ) return 0;
251 /* skip unread parts of the current subchunk */
254 _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
256 /* end of the TMAP subchunk? */
258 if ( tmapsz <= _pico_memstream_tell( fp ) - pos )
261 /* get the next subchunk header */
266 if ( 6 != get_flen() ) return 0;
269 set_flen( _pico_memstream_tell( fp ) - pos );
275 ======================================================================
278 Read an lwImageMap from a SURF.BLOK in an LWO2 file.
279 ====================================================================== */
281 int lwGetImageMap( picoMemStream_t *fp, int rsz, lwTexture *tex )
287 pos = _pico_memstream_tell( fp );
290 if ( 0 > get_flen() ) return 0;
298 if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0;
302 tex->param.imap.projection = getU2( fp );
306 tex->param.imap.vmap_name = getS0( fp );
310 tex->param.imap.axis = getU2( fp );
314 tex->param.imap.cindex = getVX( fp );
318 tex->param.imap.wrapw_type = getU2( fp );
319 tex->param.imap.wraph_type = getU2( fp );
323 tex->param.imap.wrapw.val = getF4( fp );
324 tex->param.imap.wrapw.eindex = getVX( fp );
328 tex->param.imap.wraph.val = getF4( fp );
329 tex->param.imap.wraph.eindex = getVX( fp );
333 tex->param.imap.aas_flags = getU2( fp );
334 tex->param.imap.aa_strength = getF4( fp );
338 tex->param.imap.pblend = getU2( fp );
342 tex->param.imap.stck.val = getF4( fp );
343 tex->param.imap.stck.eindex = getVX( fp );
347 tex->param.imap.amplitude.val = getF4( fp );
348 tex->param.imap.amplitude.eindex = getVX( fp );
355 /* error while reading the current subchunk? */
358 if ( rlen < 0 || rlen > sz ) return 0;
360 /* skip unread parts of the current subchunk */
363 _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
365 /* end of the image map? */
367 if ( rsz <= _pico_memstream_tell( fp ) - pos )
370 /* get the next subchunk header */
375 if ( 6 != get_flen() ) return 0;
378 set_flen( _pico_memstream_tell( fp ) - pos );
384 ======================================================================
387 Read an lwProcedural from a SURF.BLOK in an LWO2 file.
388 ====================================================================== */
390 int lwGetProcedural( picoMemStream_t *fp, int rsz, lwTexture *tex )
396 pos = _pico_memstream_tell( fp );
399 if ( 0 > get_flen() ) return 0;
407 if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0;
411 tex->param.proc.axis = getU2( fp );
415 tex->param.proc.value[ 0 ] = getF4( fp );
416 if ( sz >= 8 ) tex->param.proc.value[ 1 ] = getF4( fp );
417 if ( sz >= 12 ) tex->param.proc.value[ 2 ] = getF4( fp );
421 tex->param.proc.name = getS0( fp );
423 tex->param.proc.data = getbytes( fp, sz - rlen );
430 /* error while reading the current subchunk? */
433 if ( rlen < 0 || rlen > sz ) return 0;
435 /* skip unread parts of the current subchunk */
438 _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
440 /* end of the procedural block? */
442 if ( rsz <= _pico_memstream_tell( fp ) - pos )
445 /* get the next subchunk header */
450 if ( 6 != get_flen() ) return 0;
453 set_flen( _pico_memstream_tell( fp ) - pos );
459 ======================================================================
462 Read an lwGradient from a SURF.BLOK in an LWO2 file.
463 ====================================================================== */
465 int lwGetGradient( picoMemStream_t *fp, int rsz, lwTexture *tex )
469 int rlen, pos, i, j, nkeys;
471 pos = _pico_memstream_tell( fp );
474 if ( 0 > get_flen() ) return 0;
482 if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0;
486 tex->param.grad.paramname = getS0( fp );
490 tex->param.grad.itemname = getS0( fp );
494 tex->param.grad.start = getF4( fp );
498 tex->param.grad.end = getF4( fp );
502 tex->param.grad.repeat = getU2( fp );
506 nkeys = sz / sizeof( lwGradKey );
507 tex->param.grad.key = _pico_calloc( nkeys, sizeof( lwGradKey ));
508 if ( !tex->param.grad.key ) return 0;
509 for ( i = 0; i < nkeys; i++ ) {
510 tex->param.grad.key[ i ].value = getF4( fp );
511 for ( j = 0; j < 4; j++ )
512 tex->param.grad.key[ i ].rgba[ j ] = getF4( fp );
518 tex->param.grad.ikey = _pico_calloc( nkeys, sizeof( short ));
519 if ( !tex->param.grad.ikey ) return 0;
520 for ( i = 0; i < nkeys; i++ )
521 tex->param.grad.ikey[ i ] = getU2( fp );
528 /* error while reading the current subchunk? */
531 if ( rlen < 0 || rlen > sz ) return 0;
533 /* skip unread parts of the current subchunk */
536 _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
538 /* end of the gradient? */
540 if ( rsz <= _pico_memstream_tell( fp ) - pos )
543 /* get the next subchunk header */
548 if ( 6 != get_flen() ) return 0;
551 set_flen( _pico_memstream_tell( fp ) - pos );
557 ======================================================================
560 Read an lwTexture from a SURF.BLOK in an LWO2 file.
561 ====================================================================== */
563 lwTexture *lwGetTexture( picoMemStream_t *fp, int bloksz, unsigned int type )
569 tex = _pico_calloc( 1, sizeof( lwTexture ));
570 if ( !tex ) return NULL;
573 tex->tmap.size.val[ 0 ] =
574 tex->tmap.size.val[ 1 ] =
575 tex->tmap.size.val[ 2 ] = 1.0f;
576 tex->opacity.val = 1.0f;
580 if ( !lwGetTHeader( fp, sz, tex )) {
585 sz = bloksz - sz - 6;
587 case ID_IMAP: ok = lwGetImageMap( fp, sz, tex ); break;
588 case ID_PROC: ok = lwGetProcedural( fp, sz, tex ); break;
589 case ID_GRAD: ok = lwGetGradient( fp, sz, tex ); break;
591 ok = !_pico_memstream_seek( fp, sz, PICO_SEEK_CUR );
595 lwFreeTexture( tex );
605 ======================================================================
608 Read a shader record from a SURF.BLOK in an LWO2 file.
609 ====================================================================== */
611 lwPlugin *lwGetShader( picoMemStream_t *fp, int bloksz )
618 shdr = _pico_calloc( 1, sizeof( lwPlugin ));
619 if ( !shdr ) return NULL;
621 pos = _pico_memstream_tell( fp );
624 shdr->ord = getS0( fp );
627 if ( 0 > get_flen() ) goto Fail;
632 if ( id == ID_ENAB ) {
633 shdr->flags = getU2( fp );
637 _pico_memstream_seek( fp, sz, PICO_SEEK_CUR );
645 if ( 0 > get_flen() ) goto Fail;
653 shdr->name = getS0( fp );
655 shdr->data = getbytes( fp, sz - rlen );
662 /* error while reading the current subchunk? */
665 if ( rlen < 0 || rlen > sz ) goto Fail;
667 /* skip unread parts of the current subchunk */
670 _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
672 /* end of the shader block? */
674 if ( bloksz <= _pico_memstream_tell( fp ) - pos )
677 /* get the next subchunk header */
682 if ( 6 != get_flen() ) goto Fail;
685 set_flen( _pico_memstream_tell( fp ) - pos );
689 lwFreePlugin( shdr );
695 ======================================================================
699 Callbacks for the lwListInsert() function, which is called to add
700 textures to surface channels and shaders to surfaces.
701 ====================================================================== */
703 static int compare_textures( lwTexture *a, lwTexture *b )
705 return strcmp( a->ord, b->ord );
709 static int compare_shaders( lwPlugin *a, lwPlugin *b )
711 return strcmp( a->ord, b->ord );
716 ======================================================================
719 Finds the surface channel (lwTParam or lwCParam) to which a texture is
720 applied, then calls lwListInsert().
721 ====================================================================== */
723 static int add_texture( lwSurface *surf, lwTexture *tex )
727 switch ( tex->chan ) {
728 case ID_COLR: list = &surf->color.tex; break;
729 case ID_LUMI: list = &surf->luminosity.tex; break;
730 case ID_DIFF: list = &surf->diffuse.tex; break;
731 case ID_SPEC: list = &surf->specularity.tex; break;
732 case ID_GLOS: list = &surf->glossiness.tex; break;
733 case ID_REFL: list = &surf->reflection.val.tex; break;
734 case ID_TRAN: list = &surf->transparency.val.tex; break;
735 case ID_RIND: list = &surf->eta.tex; break;
736 case ID_TRNL: list = &surf->translucency.tex; break;
737 case ID_BUMP: list = &surf->bump.tex; break;
741 lwListInsert( (void **) list, tex, ( void *) compare_textures );
747 ======================================================================
750 Allocate and initialize a surface.
751 ====================================================================== */
753 lwSurface *lwDefaultSurface( void )
757 surf = _pico_calloc( 1, sizeof( lwSurface ));
758 if ( !surf ) return NULL;
760 surf->color.rgb[ 0 ] = 0.78431f;
761 surf->color.rgb[ 1 ] = 0.78431f;
762 surf->color.rgb[ 2 ] = 0.78431f;
763 surf->diffuse.val = 1.0f;
764 surf->glossiness.val = 0.4f;
765 surf->bump.val = 1.0f;
766 surf->eta.val = 1.0f;
774 ======================================================================
777 Read an lwSurface from an LWO2 file.
778 ====================================================================== */
780 lwSurface *lwGetSurface( picoMemStream_t *fp, int cksize )
785 unsigned int id, type;
790 /* allocate the Surface structure */
792 surf = _pico_calloc( 1, sizeof( lwSurface ));
793 if ( !surf ) goto Fail;
795 /* non-zero defaults */
797 surf->color.rgb[ 0 ] = 0.78431f;
798 surf->color.rgb[ 1 ] = 0.78431f;
799 surf->color.rgb[ 2 ] = 0.78431f;
800 surf->diffuse.val = 1.0f;
801 surf->glossiness.val = 0.4f;
802 surf->bump.val = 1.0f;
803 surf->eta.val = 1.0f;
806 /* remember where we started */
809 pos = _pico_memstream_tell( fp );
813 surf->name = getS0( fp );
814 surf->srcname = getS0( fp );
816 /* first subchunk header */
820 if ( 0 > get_flen() ) goto Fail;
822 /* process subchunks as they're encountered */
830 surf->color.rgb[ 0 ] = getF4( fp );
831 surf->color.rgb[ 1 ] = getF4( fp );
832 surf->color.rgb[ 2 ] = getF4( fp );
833 surf->color.eindex = getVX( fp );
837 surf->luminosity.val = getF4( fp );
838 surf->luminosity.eindex = getVX( fp );
842 surf->diffuse.val = getF4( fp );
843 surf->diffuse.eindex = getVX( fp );
847 surf->specularity.val = getF4( fp );
848 surf->specularity.eindex = getVX( fp );
852 surf->glossiness.val = getF4( fp );
853 surf->glossiness.eindex = getVX( fp );
857 surf->reflection.val.val = getF4( fp );
858 surf->reflection.val.eindex = getVX( fp );
862 surf->reflection.options = getU2( fp );
866 surf->reflection.cindex = getVX( fp );
870 surf->reflection.seam_angle = getF4( fp );
874 surf->transparency.val.val = getF4( fp );
875 surf->transparency.val.eindex = getVX( fp );
879 surf->transparency.options = getU2( fp );
883 surf->transparency.cindex = getVX( fp );
887 surf->eta.val = getF4( fp );
888 surf->eta.eindex = getVX( fp );
892 surf->translucency.val = getF4( fp );
893 surf->translucency.eindex = getVX( fp );
897 surf->bump.val = getF4( fp );
898 surf->bump.eindex = getVX( fp );
902 surf->smooth = getF4( fp );
906 surf->sideflags = getU2( fp );
910 surf->color_hilite.val = getF4( fp );
911 surf->color_hilite.eindex = getVX( fp );
915 surf->color_filter.val = getF4( fp );
916 surf->color_filter.eindex = getVX( fp );
920 surf->add_trans.val = getF4( fp );
921 surf->add_trans.eindex = getVX( fp );
925 surf->dif_sharp.val = getF4( fp );
926 surf->dif_sharp.eindex = getVX( fp );
930 surf->glow.val = getF4( fp );
931 surf->glow.eindex = getVX( fp );
935 surf->line.enabled = 1;
936 if ( sz >= 2 ) surf->line.flags = getU2( fp );
937 if ( sz >= 6 ) surf->line.size.val = getF4( fp );
938 if ( sz >= 8 ) surf->line.size.eindex = getVX( fp );
942 surf->alpha_mode = getU2( fp );
943 surf->alpha = getF4( fp );
947 surf->alpha = getF4( fp );
957 tex = lwGetTexture( fp, sz - 4, type );
958 if ( !tex ) goto Fail;
959 if ( !add_texture( surf, tex ))
960 lwFreeTexture( tex );
961 set_flen( 4 + get_flen() );
964 shdr = lwGetShader( fp, sz - 4 );
965 if ( !shdr ) goto Fail;
966 lwListInsert( (void **) &surf->shader, shdr, (void *) compare_shaders );
968 set_flen( 4 + get_flen() );
977 /* error while reading current subchunk? */
980 if ( rlen < 0 || rlen > sz ) goto Fail;
982 /* skip unread parts of the current subchunk */
985 _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
987 /* end of the SURF chunk? */
989 if ( cksize <= _pico_memstream_tell( fp ) - pos )
992 /* get the next subchunk header */
997 if ( 6 != get_flen() ) goto Fail;
1003 if ( surf ) lwFreeSurface( surf );