2 ======================================================================
\r
5 Surface functions for an LWO2 reader.
\r
7 Ernie Wright 17 Sep 00
\r
8 ====================================================================== */
\r
10 #include "../picointernal.h"
\r
15 ======================================================================
\r
18 Free the memory used by an lwPlugin.
\r
19 ====================================================================== */
\r
21 void lwFreePlugin( lwPlugin *p )
\r
24 if ( p->ord ) _pico_free( p->ord );
\r
25 if ( p->name ) _pico_free( p->name );
\r
26 if ( p->data ) _pico_free( p->data );
\r
33 ======================================================================
\r
36 Free the memory used by an lwTexture.
\r
37 ====================================================================== */
\r
39 void lwFreeTexture( lwTexture *t )
\r
42 if ( t->ord ) _pico_free( t->ord );
\r
43 switch ( t->type ) {
\r
45 if ( t->param.imap.vmap_name ) _pico_free( t->param.imap.vmap_name );
\r
48 if ( t->param.proc.name ) _pico_free( t->param.proc.name );
\r
49 if ( t->param.proc.data ) _pico_free( t->param.proc.data );
\r
52 if ( t->param.grad.key ) _pico_free( t->param.grad.key );
\r
53 if ( t->param.grad.ikey ) _pico_free( t->param.grad.ikey );
\r
62 ======================================================================
\r
65 Free the memory used by an lwSurface.
\r
66 ====================================================================== */
\r
68 void lwFreeSurface( lwSurface *surf )
\r
71 if ( surf->name ) _pico_free( surf->name );
\r
72 if ( surf->srcname ) _pico_free( surf->srcname );
\r
74 lwListFree( surf->shader, lwFreePlugin );
\r
76 lwListFree( surf->color.tex, lwFreeTexture );
\r
77 lwListFree( surf->luminosity.tex, lwFreeTexture );
\r
78 lwListFree( surf->diffuse.tex, lwFreeTexture );
\r
79 lwListFree( surf->specularity.tex, lwFreeTexture );
\r
80 lwListFree( surf->glossiness.tex, lwFreeTexture );
\r
81 lwListFree( surf->reflection.val.tex, lwFreeTexture );
\r
82 lwListFree( surf->transparency.val.tex, lwFreeTexture );
\r
83 lwListFree( surf->eta.tex, lwFreeTexture );
\r
84 lwListFree( surf->translucency.tex, lwFreeTexture );
\r
85 lwListFree( surf->bump.tex, lwFreeTexture );
\r
93 ======================================================================
\r
96 Read a texture map header from a SURF.BLOK in an LWO2 file. This is
\r
97 the first subchunk in a BLOK, and its contents are common to all three
\r
99 ====================================================================== */
\r
101 int lwGetTHeader( picoMemStream_t *fp, int hsz, lwTexture *tex )
\r
108 /* remember where we started */
\r
111 pos = _pico_memstream_tell( fp );
\r
113 /* ordinal string */
\r
115 tex->ord = getS0( fp );
\r
117 /* first subchunk header */
\r
121 if ( 0 > get_flen() ) return 0;
\r
123 /* process subchunks as they're encountered */
\r
131 tex->chan = getU4( fp );
\r
135 tex->opac_type = getU2( fp );
\r
136 tex->opacity.val = getF4( fp );
\r
137 tex->opacity.eindex = getVX( fp );
\r
141 tex->enabled = getU2( fp );
\r
145 tex->negative = getU2( fp );
\r
149 tex->axis = getU2( fp );
\r
156 /* error while reading current subchunk? */
\r
159 if ( rlen < 0 || rlen > sz ) return 0;
\r
161 /* skip unread parts of the current subchunk */
\r
164 _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
\r
166 /* end of the texture header subchunk? */
\r
168 if ( hsz <= _pico_memstream_tell( fp ) - pos )
\r
171 /* get the next subchunk header */
\r
176 if ( 6 != get_flen() ) return 0;
\r
179 set_flen( _pico_memstream_tell( fp ) - pos );
\r
185 ======================================================================
\r
188 Read a texture map from a SURF.BLOK in an LWO2 file. The TMAP
\r
189 defines the mapping from texture to world or object coordinates.
\r
190 ====================================================================== */
\r
192 int lwGetTMap( picoMemStream_t *fp, int tmapsz, lwTMap *tmap )
\r
198 pos = _pico_memstream_tell( fp );
\r
201 if ( 0 > get_flen() ) return 0;
\r
209 for ( i = 0; i < 3; i++ )
\r
210 tmap->size.val[ i ] = getF4( fp );
\r
211 tmap->size.eindex = getVX( fp );
\r
215 for ( i = 0; i < 3; i++ )
\r
216 tmap->center.val[ i ] = getF4( fp );
\r
217 tmap->center.eindex = getVX( fp );
\r
221 for ( i = 0; i < 3; i++ )
\r
222 tmap->rotate.val[ i ] = getF4( fp );
\r
223 tmap->rotate.eindex = getVX( fp );
\r
227 tmap->fall_type = getU2( fp );
\r
228 for ( i = 0; i < 3; i++ )
\r
229 tmap->falloff.val[ i ] = getF4( fp );
\r
230 tmap->falloff.eindex = getVX( fp );
\r
234 tmap->ref_object = getS0( fp );
\r
238 tmap->coord_sys = getU2( fp );
\r
245 /* error while reading the current subchunk? */
\r
248 if ( rlen < 0 || rlen > sz ) return 0;
\r
250 /* skip unread parts of the current subchunk */
\r
253 _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
\r
255 /* end of the TMAP subchunk? */
\r
257 if ( tmapsz <= _pico_memstream_tell( fp ) - pos )
\r
260 /* get the next subchunk header */
\r
265 if ( 6 != get_flen() ) return 0;
\r
268 set_flen( _pico_memstream_tell( fp ) - pos );
\r
274 ======================================================================
\r
277 Read an lwImageMap from a SURF.BLOK in an LWO2 file.
\r
278 ====================================================================== */
\r
280 int lwGetImageMap( picoMemStream_t *fp, int rsz, lwTexture *tex )
\r
286 pos = _pico_memstream_tell( fp );
\r
289 if ( 0 > get_flen() ) return 0;
\r
297 if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0;
\r
301 tex->param.imap.projection = getU2( fp );
\r
305 tex->param.imap.vmap_name = getS0( fp );
\r
309 tex->param.imap.axis = getU2( fp );
\r
313 tex->param.imap.cindex = getVX( fp );
\r
317 tex->param.imap.wrapw_type = getU2( fp );
\r
318 tex->param.imap.wraph_type = getU2( fp );
\r
322 tex->param.imap.wrapw.val = getF4( fp );
\r
323 tex->param.imap.wrapw.eindex = getVX( fp );
\r
327 tex->param.imap.wraph.val = getF4( fp );
\r
328 tex->param.imap.wraph.eindex = getVX( fp );
\r
332 tex->param.imap.aas_flags = getU2( fp );
\r
333 tex->param.imap.aa_strength = getF4( fp );
\r
337 tex->param.imap.pblend = getU2( fp );
\r
341 tex->param.imap.stck.val = getF4( fp );
\r
342 tex->param.imap.stck.eindex = getVX( fp );
\r
346 tex->param.imap.amplitude.val = getF4( fp );
\r
347 tex->param.imap.amplitude.eindex = getVX( fp );
\r
354 /* error while reading the current subchunk? */
\r
357 if ( rlen < 0 || rlen > sz ) return 0;
\r
359 /* skip unread parts of the current subchunk */
\r
362 _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
\r
364 /* end of the image map? */
\r
366 if ( rsz <= _pico_memstream_tell( fp ) - pos )
\r
369 /* get the next subchunk header */
\r
374 if ( 6 != get_flen() ) return 0;
\r
377 set_flen( _pico_memstream_tell( fp ) - pos );
\r
383 ======================================================================
\r
386 Read an lwProcedural from a SURF.BLOK in an LWO2 file.
\r
387 ====================================================================== */
\r
389 int lwGetProcedural( picoMemStream_t *fp, int rsz, lwTexture *tex )
\r
395 pos = _pico_memstream_tell( fp );
\r
398 if ( 0 > get_flen() ) return 0;
\r
406 if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0;
\r
410 tex->param.proc.axis = getU2( fp );
\r
414 tex->param.proc.value[ 0 ] = getF4( fp );
\r
415 if ( sz >= 8 ) tex->param.proc.value[ 1 ] = getF4( fp );
\r
416 if ( sz >= 12 ) tex->param.proc.value[ 2 ] = getF4( fp );
\r
420 tex->param.proc.name = getS0( fp );
\r
422 tex->param.proc.data = getbytes( fp, sz - rlen );
\r
429 /* error while reading the current subchunk? */
\r
432 if ( rlen < 0 || rlen > sz ) return 0;
\r
434 /* skip unread parts of the current subchunk */
\r
437 _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
\r
439 /* end of the procedural block? */
\r
441 if ( rsz <= _pico_memstream_tell( fp ) - pos )
\r
444 /* get the next subchunk header */
\r
449 if ( 6 != get_flen() ) return 0;
\r
452 set_flen( _pico_memstream_tell( fp ) - pos );
\r
458 ======================================================================
\r
461 Read an lwGradient from a SURF.BLOK in an LWO2 file.
\r
462 ====================================================================== */
\r
464 int lwGetGradient( picoMemStream_t *fp, int rsz, lwTexture *tex )
\r
468 int rlen, pos, i, j, nkeys;
\r
470 pos = _pico_memstream_tell( fp );
\r
473 if ( 0 > get_flen() ) return 0;
\r
481 if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0;
\r
485 tex->param.grad.paramname = getS0( fp );
\r
489 tex->param.grad.itemname = getS0( fp );
\r
493 tex->param.grad.start = getF4( fp );
\r
497 tex->param.grad.end = getF4( fp );
\r
501 tex->param.grad.repeat = getU2( fp );
\r
505 nkeys = sz / sizeof( lwGradKey );
\r
506 tex->param.grad.key = _pico_calloc( nkeys, sizeof( lwGradKey ));
\r
507 if ( !tex->param.grad.key ) return 0;
\r
508 for ( i = 0; i < nkeys; i++ ) {
\r
509 tex->param.grad.key[ i ].value = getF4( fp );
\r
510 for ( j = 0; j < 4; j++ )
\r
511 tex->param.grad.key[ i ].rgba[ j ] = getF4( fp );
\r
517 tex->param.grad.ikey = _pico_calloc( nkeys, sizeof( short ));
\r
518 if ( !tex->param.grad.ikey ) return 0;
\r
519 for ( i = 0; i < nkeys; i++ )
\r
520 tex->param.grad.ikey[ i ] = getU2( fp );
\r
527 /* error while reading the current subchunk? */
\r
530 if ( rlen < 0 || rlen > sz ) return 0;
\r
532 /* skip unread parts of the current subchunk */
\r
535 _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
\r
537 /* end of the gradient? */
\r
539 if ( rsz <= _pico_memstream_tell( fp ) - pos )
\r
542 /* get the next subchunk header */
\r
547 if ( 6 != get_flen() ) return 0;
\r
550 set_flen( _pico_memstream_tell( fp ) - pos );
\r
556 ======================================================================
\r
559 Read an lwTexture from a SURF.BLOK in an LWO2 file.
\r
560 ====================================================================== */
\r
562 lwTexture *lwGetTexture( picoMemStream_t *fp, int bloksz, unsigned int type )
\r
568 tex = _pico_calloc( 1, sizeof( lwTexture ));
\r
569 if ( !tex ) return NULL;
\r
572 tex->tmap.size.val[ 0 ] =
\r
573 tex->tmap.size.val[ 1 ] =
\r
574 tex->tmap.size.val[ 2 ] = 1.0f;
\r
575 tex->opacity.val = 1.0f;
\r
579 if ( !lwGetTHeader( fp, sz, tex )) {
\r
584 sz = bloksz - sz - 6;
\r
586 case ID_IMAP: ok = lwGetImageMap( fp, sz, tex ); break;
\r
587 case ID_PROC: ok = lwGetProcedural( fp, sz, tex ); break;
\r
588 case ID_GRAD: ok = lwGetGradient( fp, sz, tex ); break;
\r
590 ok = !_pico_memstream_seek( fp, sz, PICO_SEEK_CUR );
\r
594 lwFreeTexture( tex );
\r
598 set_flen( bloksz );
\r
604 ======================================================================
\r
607 Read a shader record from a SURF.BLOK in an LWO2 file.
\r
608 ====================================================================== */
\r
610 lwPlugin *lwGetShader( picoMemStream_t *fp, int bloksz )
\r
615 int hsz, rlen, pos;
\r
617 shdr = _pico_calloc( 1, sizeof( lwPlugin ));
\r
618 if ( !shdr ) return NULL;
\r
620 pos = _pico_memstream_tell( fp );
\r
623 shdr->ord = getS0( fp );
\r
626 if ( 0 > get_flen() ) goto Fail;
\r
628 while ( hsz > 0 ) {
\r
631 if ( id == ID_ENAB ) {
\r
632 shdr->flags = getU2( fp );
\r
636 _pico_memstream_seek( fp, sz, PICO_SEEK_CUR );
\r
644 if ( 0 > get_flen() ) goto Fail;
\r
652 shdr->name = getS0( fp );
\r
654 shdr->data = getbytes( fp, sz - rlen );
\r
661 /* error while reading the current subchunk? */
\r
664 if ( rlen < 0 || rlen > sz ) goto Fail;
\r
666 /* skip unread parts of the current subchunk */
\r
669 _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
\r
671 /* end of the shader block? */
\r
673 if ( bloksz <= _pico_memstream_tell( fp ) - pos )
\r
676 /* get the next subchunk header */
\r
681 if ( 6 != get_flen() ) goto Fail;
\r
684 set_flen( _pico_memstream_tell( fp ) - pos );
\r
688 lwFreePlugin( shdr );
\r
694 ======================================================================
\r
698 Callbacks for the lwListInsert() function, which is called to add
\r
699 textures to surface channels and shaders to surfaces.
\r
700 ====================================================================== */
\r
702 static int compare_textures( lwTexture *a, lwTexture *b )
\r
704 return strcmp( a->ord, b->ord );
\r
708 static int compare_shaders( lwPlugin *a, lwPlugin *b )
\r
710 return strcmp( a->ord, b->ord );
\r
715 ======================================================================
\r
718 Finds the surface channel (lwTParam or lwCParam) to which a texture is
\r
719 applied, then calls lwListInsert().
\r
720 ====================================================================== */
\r
722 static int add_texture( lwSurface *surf, lwTexture *tex )
\r
726 switch ( tex->chan ) {
\r
727 case ID_COLR: list = &surf->color.tex; break;
\r
728 case ID_LUMI: list = &surf->luminosity.tex; break;
\r
729 case ID_DIFF: list = &surf->diffuse.tex; break;
\r
730 case ID_SPEC: list = &surf->specularity.tex; break;
\r
731 case ID_GLOS: list = &surf->glossiness.tex; break;
\r
732 case ID_REFL: list = &surf->reflection.val.tex; break;
\r
733 case ID_TRAN: list = &surf->transparency.val.tex; break;
\r
734 case ID_RIND: list = &surf->eta.tex; break;
\r
735 case ID_TRNL: list = &surf->translucency.tex; break;
\r
736 case ID_BUMP: list = &surf->bump.tex; break;
\r
740 lwListInsert( list, tex, compare_textures );
\r
746 ======================================================================
\r
749 Allocate and initialize a surface.
\r
750 ====================================================================== */
\r
752 lwSurface *lwDefaultSurface( void )
\r
756 surf = _pico_calloc( 1, sizeof( lwSurface ));
\r
757 if ( !surf ) return NULL;
\r
759 surf->color.rgb[ 0 ] = 0.78431f;
\r
760 surf->color.rgb[ 1 ] = 0.78431f;
\r
761 surf->color.rgb[ 2 ] = 0.78431f;
\r
762 surf->diffuse.val = 1.0f;
\r
763 surf->glossiness.val = 0.4f;
\r
764 surf->bump.val = 1.0f;
\r
765 surf->eta.val = 1.0f;
\r
766 surf->sideflags = 1;
\r
773 ======================================================================
\r
776 Read an lwSurface from an LWO2 file.
\r
777 ====================================================================== */
\r
779 lwSurface *lwGetSurface( picoMemStream_t *fp, int cksize )
\r
784 unsigned int id, type;
\r
789 /* allocate the Surface structure */
\r
791 surf = _pico_calloc( 1, sizeof( lwSurface ));
\r
792 if ( !surf ) goto Fail;
\r
794 /* non-zero defaults */
\r
796 surf->color.rgb[ 0 ] = 0.78431f;
\r
797 surf->color.rgb[ 1 ] = 0.78431f;
\r
798 surf->color.rgb[ 2 ] = 0.78431f;
\r
799 surf->diffuse.val = 1.0f;
\r
800 surf->glossiness.val = 0.4f;
\r
801 surf->bump.val = 1.0f;
\r
802 surf->eta.val = 1.0f;
\r
803 surf->sideflags = 1;
\r
805 /* remember where we started */
\r
808 pos = _pico_memstream_tell( fp );
\r
812 surf->name = getS0( fp );
\r
813 surf->srcname = getS0( fp );
\r
815 /* first subchunk header */
\r
819 if ( 0 > get_flen() ) goto Fail;
\r
821 /* process subchunks as they're encountered */
\r
829 surf->color.rgb[ 0 ] = getF4( fp );
\r
830 surf->color.rgb[ 1 ] = getF4( fp );
\r
831 surf->color.rgb[ 2 ] = getF4( fp );
\r
832 surf->color.eindex = getVX( fp );
\r
836 surf->luminosity.val = getF4( fp );
\r
837 surf->luminosity.eindex = getVX( fp );
\r
841 surf->diffuse.val = getF4( fp );
\r
842 surf->diffuse.eindex = getVX( fp );
\r
846 surf->specularity.val = getF4( fp );
\r
847 surf->specularity.eindex = getVX( fp );
\r
851 surf->glossiness.val = getF4( fp );
\r
852 surf->glossiness.eindex = getVX( fp );
\r
856 surf->reflection.val.val = getF4( fp );
\r
857 surf->reflection.val.eindex = getVX( fp );
\r
861 surf->reflection.options = getU2( fp );
\r
865 surf->reflection.cindex = getVX( fp );
\r
869 surf->reflection.seam_angle = getF4( fp );
\r
873 surf->transparency.val.val = getF4( fp );
\r
874 surf->transparency.val.eindex = getVX( fp );
\r
878 surf->transparency.options = getU2( fp );
\r
882 surf->transparency.cindex = getVX( fp );
\r
886 surf->eta.val = getF4( fp );
\r
887 surf->eta.eindex = getVX( fp );
\r
891 surf->translucency.val = getF4( fp );
\r
892 surf->translucency.eindex = getVX( fp );
\r
896 surf->bump.val = getF4( fp );
\r
897 surf->bump.eindex = getVX( fp );
\r
901 surf->smooth = getF4( fp );
\r
905 surf->sideflags = getU2( fp );
\r
909 surf->color_hilite.val = getF4( fp );
\r
910 surf->color_hilite.eindex = getVX( fp );
\r
914 surf->color_filter.val = getF4( fp );
\r
915 surf->color_filter.eindex = getVX( fp );
\r
919 surf->add_trans.val = getF4( fp );
\r
920 surf->add_trans.eindex = getVX( fp );
\r
924 surf->dif_sharp.val = getF4( fp );
\r
925 surf->dif_sharp.eindex = getVX( fp );
\r
929 surf->glow.val = getF4( fp );
\r
930 surf->glow.eindex = getVX( fp );
\r
934 surf->line.enabled = 1;
\r
935 if ( sz >= 2 ) surf->line.flags = getU2( fp );
\r
936 if ( sz >= 6 ) surf->line.size.val = getF4( fp );
\r
937 if ( sz >= 8 ) surf->line.size.eindex = getVX( fp );
\r
941 surf->alpha_mode = getU2( fp );
\r
942 surf->alpha = getF4( fp );
\r
946 surf->alpha = getF4( fp );
\r
950 type = getU4( fp );
\r
956 tex = lwGetTexture( fp, sz - 4, type );
\r
957 if ( !tex ) goto Fail;
\r
958 if ( !add_texture( surf, tex ))
\r
959 lwFreeTexture( tex );
\r
960 set_flen( 4 + get_flen() );
\r
963 shdr = lwGetShader( fp, sz - 4 );
\r
964 if ( !shdr ) goto Fail;
\r
965 lwListInsert( &surf->shader, shdr, compare_shaders );
\r
967 set_flen( 4 + get_flen() );
\r
976 /* error while reading current subchunk? */
\r
979 if ( rlen < 0 || rlen > sz ) goto Fail;
\r
981 /* skip unread parts of the current subchunk */
\r
984 _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
\r
986 /* end of the SURF chunk? */
\r
988 if ( cksize <= _pico_memstream_tell( fp ) - pos )
\r
991 /* get the next subchunk header */
\r
996 if ( 6 != get_flen() ) goto Fail;
\r
1002 if ( surf ) lwFreeSurface( surf );
\r