]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/picomodel/lwo/surface.c
Remove -Wno-pedantic
[xonotic/netradiant.git] / libs / picomodel / lwo / surface.c
1 /*
2    ======================================================================
3    surface.c
4
5    Surface functions for an LWO2 reader.
6
7    Ernie Wright  17 Sep 00
8    ====================================================================== */
9
10 #include "../picointernal.h"
11 #include "lwo2.h"
12
13
14 /*
15    ======================================================================
16    lwFreePlugin()
17
18    Free the memory used by an lwPlugin.
19    ====================================================================== */
20
21 void lwFreePlugin( lwPlugin *p ){
22         if ( p ) {
23                 if ( p->ord ) {
24                         _pico_free( p->ord );
25                 }
26                 if ( p->name ) {
27                         _pico_free( p->name );
28                 }
29                 if ( p->data ) {
30                         _pico_free( p->data );
31                 }
32                 _pico_free( p );
33         }
34 }
35
36
37 /*
38    ======================================================================
39    lwFreeTexture()
40
41    Free the memory used by an lwTexture.
42    ====================================================================== */
43
44 void lwFreeTexture( lwTexture *t ){
45         if ( t ) {
46                 if ( t->ord ) {
47                         _pico_free( t->ord );
48                 }
49                 switch ( t->type ) {
50                 case ID_IMAP:
51                         if ( t->param.imap.vmap_name ) {
52                                 _pico_free( t->param.imap.vmap_name );
53                         }
54                         if ( t->tmap.ref_object ) {
55                                 _pico_free( t->tmap.ref_object );
56                         }
57                         break;
58                 case ID_PROC:
59                         if ( t->param.proc.name ) {
60                                 _pico_free( t->param.proc.name );
61                         }
62                         if ( t->param.proc.data ) {
63                                 _pico_free( t->param.proc.data );
64                         }
65                         break;
66                 case ID_GRAD:
67                         if ( t->param.grad.key ) {
68                                 _pico_free( t->param.grad.key );
69                         }
70                         if ( t->param.grad.ikey ) {
71                                 _pico_free( t->param.grad.ikey );
72                         }
73                         break;
74                 }
75                 _pico_free( t );
76         }
77 }
78
79
80 /*
81    ======================================================================
82    lwFreeSurface()
83
84    Free the memory used by an lwSurface.
85    ====================================================================== */
86
87 void lwFreeSurface( lwSurface *surf ){
88         if ( surf ) {
89                 if ( surf->name ) {
90                         _pico_free( surf->name );
91                 }
92                 if ( surf->srcname ) {
93                         _pico_free( surf->srcname );
94                 }
95
96                 lwListFree(surf->shader, (void (*)(void *)) lwFreePlugin);
97
98                 void (*freeTexture)(void *) = (void (*)(void *)) lwFreeTexture;
99                 lwListFree(surf->color.tex, freeTexture);
100                 lwListFree(surf->luminosity.tex, freeTexture);
101                 lwListFree(surf->diffuse.tex, freeTexture);
102                 lwListFree(surf->specularity.tex, freeTexture);
103                 lwListFree(surf->glossiness.tex, freeTexture);
104                 lwListFree(surf->reflection.val.tex, freeTexture);
105                 lwListFree(surf->transparency.val.tex, freeTexture);
106                 lwListFree(surf->eta.tex, freeTexture);
107                 lwListFree(surf->translucency.tex, freeTexture);
108                 lwListFree(surf->bump.tex, freeTexture);
109
110                 _pico_free( surf );
111         }
112 }
113
114
115 /*
116    ======================================================================
117    lwGetTHeader()
118
119    Read a texture map header from a SURF.BLOK in an LWO2 file.  This is
120    the first subchunk in a BLOK, and its contents are common to all three
121    texture types.
122    ====================================================================== */
123
124 int lwGetTHeader( picoMemStream_t *fp, int hsz, lwTexture *tex ){
125         unsigned int id;
126         unsigned short sz;
127         int pos, rlen;
128
129
130         /* remember where we started */
131
132         set_flen( 0 );
133         pos = _pico_memstream_tell( fp );
134
135         /* ordinal string */
136
137         tex->ord = getS0( fp );
138
139         /* first subchunk header */
140
141         id = getU4( fp );
142         sz = getU2( fp );
143         if ( 0 > get_flen() ) {
144                 return 0;
145         }
146
147         /* process subchunks as they're encountered */
148
149         while ( 1 ) {
150                 sz += sz & 1;
151                 set_flen( 0 );
152
153                 switch ( id ) {
154                 case ID_CHAN:
155                         tex->chan = getU4( fp );
156                         break;
157
158                 case ID_OPAC:
159                         tex->opac_type = getU2( fp );
160                         tex->opacity.val = getF4( fp );
161                         tex->opacity.eindex = getVX( fp );
162                         break;
163
164                 case ID_ENAB:
165                         tex->enabled = getU2( fp );
166                         break;
167
168                 case ID_NEGA:
169                         tex->negative = getU2( fp );
170                         break;
171
172                 case ID_AXIS:
173                         tex->axis = getU2( fp );
174                         break;
175
176                 default:
177                         break;
178                 }
179
180                 /* error while reading current subchunk? */
181
182                 rlen = get_flen();
183                 if ( rlen < 0 || rlen > sz ) {
184                         return 0;
185                 }
186
187                 /* skip unread parts of the current subchunk */
188
189                 if ( rlen < sz ) {
190                         _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
191                 }
192
193                 /* end of the texture header subchunk? */
194
195                 if ( hsz <= _pico_memstream_tell( fp ) - pos ) {
196                         break;
197                 }
198
199                 /* get the next subchunk header */
200
201                 set_flen( 0 );
202                 id = getU4( fp );
203                 sz = getU2( fp );
204                 if ( 6 != get_flen() ) {
205                         return 0;
206                 }
207         }
208
209         set_flen( _pico_memstream_tell( fp ) - pos );
210         return 1;
211 }
212
213
214 /*
215    ======================================================================
216    lwGetTMap()
217
218    Read a texture map from a SURF.BLOK in an LWO2 file.  The TMAP
219    defines the mapping from texture to world or object coordinates.
220    ====================================================================== */
221
222 int lwGetTMap( picoMemStream_t *fp, int tmapsz, lwTMap *tmap ){
223         unsigned int id;
224         unsigned short sz;
225         int rlen, pos, i;
226
227         pos = _pico_memstream_tell( fp );
228         id = getU4( fp );
229         sz = getU2( fp );
230         if ( 0 > get_flen() ) {
231                 return 0;
232         }
233
234         while ( 1 ) {
235                 sz += sz & 1;
236                 set_flen( 0 );
237
238                 switch ( id ) {
239                 case ID_SIZE:
240                         for ( i = 0; i < 3; i++ )
241                                 tmap->size.val[ i ] = getF4( fp );
242                         tmap->size.eindex = getVX( fp );
243                         break;
244
245                 case ID_CNTR:
246                         for ( i = 0; i < 3; i++ )
247                                 tmap->center.val[ i ] = getF4( fp );
248                         tmap->center.eindex = getVX( fp );
249                         break;
250
251                 case ID_ROTA:
252                         for ( i = 0; i < 3; i++ )
253                                 tmap->rotate.val[ i ] = getF4( fp );
254                         tmap->rotate.eindex = getVX( fp );
255                         break;
256
257                 case ID_FALL:
258                         tmap->fall_type = getU2( fp );
259                         for ( i = 0; i < 3; i++ )
260                                 tmap->falloff.val[ i ] = getF4( fp );
261                         tmap->falloff.eindex = getVX( fp );
262                         break;
263
264                 case ID_OREF:
265                         tmap->ref_object = getS0( fp );
266                         break;
267
268                 case ID_CSYS:
269                         tmap->coord_sys = getU2( fp );
270                         break;
271
272                 default:
273                         break;
274                 }
275
276                 /* error while reading the current subchunk? */
277
278                 rlen = get_flen();
279                 if ( rlen < 0 || rlen > sz ) {
280                         return 0;
281                 }
282
283                 /* skip unread parts of the current subchunk */
284
285                 if ( rlen < sz ) {
286                         _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
287                 }
288
289                 /* end of the TMAP subchunk? */
290
291                 if ( tmapsz <= _pico_memstream_tell( fp ) - pos ) {
292                         break;
293                 }
294
295                 /* get the next subchunk header */
296
297                 set_flen( 0 );
298                 id = getU4( fp );
299                 sz = getU2( fp );
300                 if ( 6 != get_flen() ) {
301                         return 0;
302                 }
303         }
304
305         set_flen( _pico_memstream_tell( fp ) - pos );
306         return 1;
307 }
308
309
310 /*
311    ======================================================================
312    lwGetImageMap()
313
314    Read an lwImageMap from a SURF.BLOK in an LWO2 file.
315    ====================================================================== */
316
317 int lwGetImageMap( picoMemStream_t *fp, int rsz, lwTexture *tex ){
318         unsigned int id;
319         unsigned short sz;
320         int rlen, pos;
321
322         pos = _pico_memstream_tell( fp );
323         id = getU4( fp );
324         sz = getU2( fp );
325         if ( 0 > get_flen() ) {
326                 return 0;
327         }
328
329         while ( 1 ) {
330                 sz += sz & 1;
331                 set_flen( 0 );
332
333                 switch ( id ) {
334                 case ID_TMAP:
335                         if ( !lwGetTMap( fp, sz, &tex->tmap ) ) {
336                                 return 0;
337                         }
338                         break;
339
340                 case ID_PROJ:
341                         tex->param.imap.projection = getU2( fp );
342                         break;
343
344                 case ID_VMAP:
345                         tex->param.imap.vmap_name = getS0( fp );
346                         break;
347
348                 case ID_AXIS:
349                         tex->param.imap.axis = getU2( fp );
350                         break;
351
352                 case ID_IMAG:
353                         tex->param.imap.cindex = getVX( fp );
354                         break;
355
356                 case ID_WRAP:
357                         tex->param.imap.wrapw_type = getU2( fp );
358                         tex->param.imap.wraph_type = getU2( fp );
359                         break;
360
361                 case ID_WRPW:
362                         tex->param.imap.wrapw.val = getF4( fp );
363                         tex->param.imap.wrapw.eindex = getVX( fp );
364                         break;
365
366                 case ID_WRPH:
367                         tex->param.imap.wraph.val = getF4( fp );
368                         tex->param.imap.wraph.eindex = getVX( fp );
369                         break;
370
371                 case ID_AAST:
372                         tex->param.imap.aas_flags = getU2( fp );
373                         tex->param.imap.aa_strength = getF4( fp );
374                         break;
375
376                 case ID_PIXB:
377                         tex->param.imap.pblend = getU2( fp );
378                         break;
379
380                 case ID_STCK:
381                         tex->param.imap.stck.val = getF4( fp );
382                         tex->param.imap.stck.eindex = getVX( fp );
383                         break;
384
385                 case ID_TAMP:
386                         tex->param.imap.amplitude.val = getF4( fp );
387                         tex->param.imap.amplitude.eindex = getVX( fp );
388                         break;
389
390                 default:
391                         break;
392                 }
393
394                 /* error while reading the current subchunk? */
395
396                 rlen = get_flen();
397                 if ( rlen < 0 || rlen > sz ) {
398                         return 0;
399                 }
400
401                 /* skip unread parts of the current subchunk */
402
403                 if ( rlen < sz ) {
404                         _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
405                 }
406
407                 /* end of the image map? */
408
409                 if ( rsz <= _pico_memstream_tell( fp ) - pos ) {
410                         break;
411                 }
412
413                 /* get the next subchunk header */
414
415                 set_flen( 0 );
416                 id = getU4( fp );
417                 sz = getU2( fp );
418                 if ( 6 != get_flen() ) {
419                         return 0;
420                 }
421         }
422
423         set_flen( _pico_memstream_tell( fp ) - pos );
424         return 1;
425 }
426
427
428 /*
429    ======================================================================
430    lwGetProcedural()
431
432    Read an lwProcedural from a SURF.BLOK in an LWO2 file.
433    ====================================================================== */
434
435 int lwGetProcedural( picoMemStream_t *fp, int rsz, lwTexture *tex ){
436         unsigned int id;
437         unsigned short sz;
438         int rlen, pos;
439
440         pos = _pico_memstream_tell( fp );
441         id = getU4( fp );
442         sz = getU2( fp );
443         if ( 0 > get_flen() ) {
444                 return 0;
445         }
446
447         while ( 1 ) {
448                 sz += sz & 1;
449                 set_flen( 0 );
450
451                 switch ( id ) {
452                 case ID_TMAP:
453                         if ( !lwGetTMap( fp, sz, &tex->tmap ) ) {
454                                 return 0;
455                         }
456                         break;
457
458                 case ID_AXIS:
459                         tex->param.proc.axis = getU2( fp );
460                         break;
461
462                 case ID_VALU:
463                         tex->param.proc.value[ 0 ] = getF4( fp );
464                         if ( sz >= 8 ) {
465                                 tex->param.proc.value[ 1 ] = getF4( fp );
466                         }
467                         if ( sz >= 12 ) {
468                                 tex->param.proc.value[ 2 ] = getF4( fp );
469                         }
470                         break;
471
472                 case ID_FUNC:
473                         tex->param.proc.name = getS0( fp );
474                         rlen = get_flen();
475                         tex->param.proc.data = getbytes( fp, sz - rlen );
476                         break;
477
478                 default:
479                         break;
480                 }
481
482                 /* error while reading the current subchunk? */
483
484                 rlen = get_flen();
485                 if ( rlen < 0 || rlen > sz ) {
486                         return 0;
487                 }
488
489                 /* skip unread parts of the current subchunk */
490
491                 if ( rlen < sz ) {
492                         _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
493                 }
494
495                 /* end of the procedural block? */
496
497                 if ( rsz <= _pico_memstream_tell( fp ) - pos ) {
498                         break;
499                 }
500
501                 /* get the next subchunk header */
502
503                 set_flen( 0 );
504                 id = getU4( fp );
505                 sz = getU2( fp );
506                 if ( 6 != get_flen() ) {
507                         return 0;
508                 }
509         }
510
511         set_flen( _pico_memstream_tell( fp ) - pos );
512         return 1;
513 }
514
515
516 /*
517    ======================================================================
518    lwGetGradient()
519
520    Read an lwGradient from a SURF.BLOK in an LWO2 file.
521    ====================================================================== */
522
523 int lwGetGradient( picoMemStream_t *fp, int rsz, lwTexture *tex ){
524         unsigned int id;
525         unsigned short sz;
526         int rlen, pos, i, j, nkeys;
527
528         pos = _pico_memstream_tell( fp );
529         id = getU4( fp );
530         sz = getU2( fp );
531         if ( 0 > get_flen() ) {
532                 return 0;
533         }
534
535         while ( 1 ) {
536                 sz += sz & 1;
537                 set_flen( 0 );
538
539                 switch ( id ) {
540                 case ID_TMAP:
541                         if ( !lwGetTMap( fp, sz, &tex->tmap ) ) {
542                                 return 0;
543                         }
544                         break;
545
546                 case ID_PNAM:
547                         tex->param.grad.paramname = getS0( fp );
548                         break;
549
550                 case ID_INAM:
551                         tex->param.grad.itemname = getS0( fp );
552                         break;
553
554                 case ID_GRST:
555                         tex->param.grad.start = getF4( fp );
556                         break;
557
558                 case ID_GREN:
559                         tex->param.grad.end = getF4( fp );
560                         break;
561
562                 case ID_GRPT:
563                         tex->param.grad.repeat = getU2( fp );
564                         break;
565
566                 case ID_FKEY:
567                         nkeys = sz / sizeof( lwGradKey );
568                         tex->param.grad.key = _pico_calloc( nkeys, sizeof( lwGradKey ) );
569                         if ( !tex->param.grad.key ) {
570                                 return 0;
571                         }
572                         for ( i = 0; i < nkeys; i++ ) {
573                                 tex->param.grad.key[ i ].value = getF4( fp );
574                                 for ( j = 0; j < 4; j++ )
575                                         tex->param.grad.key[ i ].rgba[ j ] = getF4( fp );
576                         }
577                         break;
578
579                 case ID_IKEY:
580                         nkeys = sz / 2;
581                         tex->param.grad.ikey = _pico_calloc( nkeys, sizeof( short ) );
582                         if ( !tex->param.grad.ikey ) {
583                                 return 0;
584                         }
585                         for ( i = 0; i < nkeys; i++ )
586                                 tex->param.grad.ikey[ i ] = getU2( fp );
587                         break;
588
589                 default:
590                         break;
591                 }
592
593                 /* error while reading the current subchunk? */
594
595                 rlen = get_flen();
596                 if ( rlen < 0 || rlen > sz ) {
597                         return 0;
598                 }
599
600                 /* skip unread parts of the current subchunk */
601
602                 if ( rlen < sz ) {
603                         _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
604                 }
605
606                 /* end of the gradient? */
607
608                 if ( rsz <= _pico_memstream_tell( fp ) - pos ) {
609                         break;
610                 }
611
612                 /* get the next subchunk header */
613
614                 set_flen( 0 );
615                 id = getU4( fp );
616                 sz = getU2( fp );
617                 if ( 6 != get_flen() ) {
618                         return 0;
619                 }
620         }
621
622         set_flen( _pico_memstream_tell( fp ) - pos );
623         return 1;
624 }
625
626
627 /*
628    ======================================================================
629    lwGetTexture()
630
631    Read an lwTexture from a SURF.BLOK in an LWO2 file.
632    ====================================================================== */
633
634 lwTexture *lwGetTexture( picoMemStream_t *fp, int bloksz, unsigned int type ){
635         lwTexture *tex;
636         unsigned short sz;
637         int ok;
638
639         tex = _pico_calloc( 1, sizeof( lwTexture ) );
640         if ( !tex ) {
641                 return NULL;
642         }
643
644         tex->type = type;
645         tex->tmap.size.val[ 0 ] =
646                 tex->tmap.size.val[ 1 ] =
647                         tex->tmap.size.val[ 2 ] = 1.0f;
648         tex->opacity.val = 1.0f;
649         tex->enabled = 1;
650
651         sz = getU2( fp );
652         if ( !lwGetTHeader( fp, sz, tex ) ) {
653                 _pico_free( tex );
654                 return NULL;
655         }
656
657         sz = bloksz - sz - 6;
658         switch ( type ) {
659         case ID_IMAP:  ok = lwGetImageMap( fp, sz, tex );  break;
660         case ID_PROC:  ok = lwGetProcedural( fp, sz, tex );  break;
661         case ID_GRAD:  ok = lwGetGradient( fp, sz, tex );  break;
662         default:
663                 ok = !_pico_memstream_seek( fp, sz, PICO_SEEK_CUR );
664         }
665
666         if ( !ok ) {
667                 lwFreeTexture( tex );
668                 return NULL;
669         }
670
671         set_flen( bloksz );
672         return tex;
673 }
674
675
676 /*
677    ======================================================================
678    lwGetShader()
679
680    Read a shader record from a SURF.BLOK in an LWO2 file.
681    ====================================================================== */
682
683 lwPlugin *lwGetShader( picoMemStream_t *fp, int bloksz ){
684         lwPlugin *shdr;
685         unsigned int id;
686         unsigned short sz;
687         int hsz, rlen, pos;
688
689         shdr = _pico_calloc( 1, sizeof( lwPlugin ) );
690         if ( !shdr ) {
691                 return NULL;
692         }
693
694         pos = _pico_memstream_tell( fp );
695         set_flen( 0 );
696         hsz = getU2( fp );
697         shdr->ord = getS0( fp );
698         id = getU4( fp );
699         sz = getU2( fp );
700         if ( 0 > get_flen() ) {
701                 goto Fail;
702         }
703
704         while ( hsz > 0 ) {
705                 sz += sz & 1;
706                 hsz -= sz;
707                 if ( id == ID_ENAB ) {
708                         shdr->flags = getU2( fp );
709                         break;
710                 }
711                 else {
712                         _pico_memstream_seek( fp, sz, PICO_SEEK_CUR );
713                         id = getU4( fp );
714                         sz = getU2( fp );
715                 }
716         }
717
718         id = getU4( fp );
719         sz = getU2( fp );
720         if ( 0 > get_flen() ) {
721                 goto Fail;
722         }
723
724         while ( 1 ) {
725                 sz += sz & 1;
726                 set_flen( 0 );
727
728                 switch ( id ) {
729                 case ID_FUNC:
730                         shdr->name = getS0( fp );
731                         rlen = get_flen();
732                         shdr->data = getbytes( fp, sz - rlen );
733                         break;
734
735                 default:
736                         break;
737                 }
738
739                 /* error while reading the current subchunk? */
740
741                 rlen = get_flen();
742                 if ( rlen < 0 || rlen > sz ) {
743                         goto Fail;
744                 }
745
746                 /* skip unread parts of the current subchunk */
747
748                 if ( rlen < sz ) {
749                         _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
750                 }
751
752                 /* end of the shader block? */
753
754                 if ( bloksz <= _pico_memstream_tell( fp ) - pos ) {
755                         break;
756                 }
757
758                 /* get the next subchunk header */
759
760                 set_flen( 0 );
761                 id = getU4( fp );
762                 sz = getU2( fp );
763                 if ( 6 != get_flen() ) {
764                         goto Fail;
765                 }
766         }
767
768         set_flen( _pico_memstream_tell( fp ) - pos );
769         return shdr;
770
771 Fail:
772         lwFreePlugin( shdr );
773         return NULL;
774 }
775
776
777 /*
778    ======================================================================
779    compare_textures()
780    compare_shaders()
781
782    Callbacks for the lwListInsert() function, which is called to add
783    textures to surface channels and shaders to surfaces.
784    ====================================================================== */
785
786 static int compare_textures( lwTexture *a, lwTexture *b ){
787         return strcmp( a->ord, b->ord );
788 }
789
790
791 static int compare_shaders( lwPlugin *a, lwPlugin *b ){
792         return strcmp( a->ord, b->ord );
793 }
794
795
796 /*
797    ======================================================================
798    add_texture()
799
800    Finds the surface channel (lwTParam or lwCParam) to which a texture is
801    applied, then calls lwListInsert().
802    ====================================================================== */
803
804 static int add_texture( lwSurface *surf, lwTexture *tex ){
805         lwTexture **list;
806
807         switch ( tex->chan ) {
808         case ID_COLR:  list = &surf->color.tex;             break;
809         case ID_LUMI:  list = &surf->luminosity.tex;        break;
810         case ID_DIFF:  list = &surf->diffuse.tex;           break;
811         case ID_SPEC:  list = &surf->specularity.tex;       break;
812         case ID_GLOS:  list = &surf->glossiness.tex;        break;
813         case ID_REFL:  list = &surf->reflection.val.tex;    break;
814         case ID_TRAN:  list = &surf->transparency.val.tex;  break;
815         case ID_RIND:  list = &surf->eta.tex;               break;
816         case ID_TRNL:  list = &surf->translucency.tex;      break;
817         case ID_BUMP:  list = &surf->bump.tex;              break;
818         default:  return 0;
819         }
820
821         lwListInsert((void **) list, tex, (int (*)(void *, void *)) compare_textures);
822         return 1;
823 }
824
825
826 /*
827    ======================================================================
828    lwDefaultSurface()
829
830    Allocate and initialize a surface.
831    ====================================================================== */
832
833 lwSurface *lwDefaultSurface( void ){
834         lwSurface *surf;
835
836         surf = _pico_calloc( 1, sizeof( lwSurface ) );
837         if ( !surf ) {
838                 return NULL;
839         }
840
841         surf->color.rgb[ 0 ] = 0.78431f;
842         surf->color.rgb[ 1 ] = 0.78431f;
843         surf->color.rgb[ 2 ] = 0.78431f;
844         surf->diffuse.val    = 1.0f;
845         surf->glossiness.val = 0.4f;
846         surf->bump.val       = 1.0f;
847         surf->eta.val        = 1.0f;
848         surf->sideflags      = 1;
849
850         return surf;
851 }
852
853
854 /*
855    ======================================================================
856    lwGetSurface()
857
858    Read an lwSurface from an LWO2 file.
859    ====================================================================== */
860
861 lwSurface *lwGetSurface( picoMemStream_t *fp, int cksize ){
862         lwSurface *surf;
863         lwTexture *tex;
864         lwPlugin *shdr;
865         unsigned int id, type;
866         unsigned short sz;
867         int pos, rlen;
868
869
870         /* allocate the Surface structure */
871
872         surf = _pico_calloc( 1, sizeof( lwSurface ) );
873         if ( !surf ) {
874                 goto Fail;
875         }
876
877         /* non-zero defaults */
878
879         surf->color.rgb[ 0 ] = 0.78431f;
880         surf->color.rgb[ 1 ] = 0.78431f;
881         surf->color.rgb[ 2 ] = 0.78431f;
882         surf->diffuse.val    = 1.0f;
883         surf->glossiness.val = 0.4f;
884         surf->bump.val       = 1.0f;
885         surf->eta.val        = 1.0f;
886         surf->sideflags      = 1;
887
888         /* remember where we started */
889
890         set_flen( 0 );
891         pos = _pico_memstream_tell( fp );
892
893         /* names */
894
895         surf->name = getS0( fp );
896         surf->srcname = getS0( fp );
897
898         /* first subchunk header */
899
900         id = getU4( fp );
901         sz = getU2( fp );
902         if ( 0 > get_flen() ) {
903                 goto Fail;
904         }
905
906         /* process subchunks as they're encountered */
907
908         while ( 1 ) {
909                 sz += sz & 1;
910                 set_flen( 0 );
911
912                 switch ( id ) {
913                 case ID_COLR:
914                         surf->color.rgb[ 0 ] = getF4( fp );
915                         surf->color.rgb[ 1 ] = getF4( fp );
916                         surf->color.rgb[ 2 ] = getF4( fp );
917                         surf->color.eindex = getVX( fp );
918                         break;
919
920                 case ID_LUMI:
921                         surf->luminosity.val = getF4( fp );
922                         surf->luminosity.eindex = getVX( fp );
923                         break;
924
925                 case ID_DIFF:
926                         surf->diffuse.val = getF4( fp );
927                         surf->diffuse.eindex = getVX( fp );
928                         break;
929
930                 case ID_SPEC:
931                         surf->specularity.val = getF4( fp );
932                         surf->specularity.eindex = getVX( fp );
933                         break;
934
935                 case ID_GLOS:
936                         surf->glossiness.val = getF4( fp );
937                         surf->glossiness.eindex = getVX( fp );
938                         break;
939
940                 case ID_REFL:
941                         surf->reflection.val.val = getF4( fp );
942                         surf->reflection.val.eindex = getVX( fp );
943                         break;
944
945                 case ID_RFOP:
946                         surf->reflection.options = getU2( fp );
947                         break;
948
949                 case ID_RIMG:
950                         surf->reflection.cindex = getVX( fp );
951                         break;
952
953                 case ID_RSAN:
954                         surf->reflection.seam_angle = getF4( fp );
955                         break;
956
957                 case ID_TRAN:
958                         surf->transparency.val.val = getF4( fp );
959                         surf->transparency.val.eindex = getVX( fp );
960                         break;
961
962                 case ID_TROP:
963                         surf->transparency.options = getU2( fp );
964                         break;
965
966                 case ID_TIMG:
967                         surf->transparency.cindex = getVX( fp );
968                         break;
969
970                 case ID_RIND:
971                         surf->eta.val = getF4( fp );
972                         surf->eta.eindex = getVX( fp );
973                         break;
974
975                 case ID_TRNL:
976                         surf->translucency.val = getF4( fp );
977                         surf->translucency.eindex = getVX( fp );
978                         break;
979
980                 case ID_BUMP:
981                         surf->bump.val = getF4( fp );
982                         surf->bump.eindex = getVX( fp );
983                         break;
984
985                 case ID_SMAN:
986                         surf->smooth = getF4( fp );
987                         break;
988
989                 case ID_SIDE:
990                         surf->sideflags = getU2( fp );
991                         break;
992
993                 case ID_CLRH:
994                         surf->color_hilite.val = getF4( fp );
995                         surf->color_hilite.eindex = getVX( fp );
996                         break;
997
998                 case ID_CLRF:
999                         surf->color_filter.val = getF4( fp );
1000                         surf->color_filter.eindex = getVX( fp );
1001                         break;
1002
1003                 case ID_ADTR:
1004                         surf->add_trans.val = getF4( fp );
1005                         surf->add_trans.eindex = getVX( fp );
1006                         break;
1007
1008                 case ID_SHRP:
1009                         surf->dif_sharp.val = getF4( fp );
1010                         surf->dif_sharp.eindex = getVX( fp );
1011                         break;
1012
1013                 case ID_GVAL:
1014                         surf->glow.val = getF4( fp );
1015                         surf->glow.eindex = getVX( fp );
1016                         break;
1017
1018                 case ID_LINE:
1019                         surf->line.enabled = 1;
1020                         if ( sz >= 2 ) {
1021                                 surf->line.flags = getU2( fp );
1022                         }
1023                         if ( sz >= 6 ) {
1024                                 surf->line.size.val = getF4( fp );
1025                         }
1026                         if ( sz >= 8 ) {
1027                                 surf->line.size.eindex = getVX( fp );
1028                         }
1029                         break;
1030
1031                 case ID_ALPH:
1032                         surf->alpha_mode = getU2( fp );
1033                         surf->alpha = getF4( fp );
1034                         break;
1035
1036                 case ID_AVAL:
1037                         surf->alpha = getF4( fp );
1038                         break;
1039
1040                 case ID_BLOK:
1041                         type = getU4( fp );
1042
1043                         switch ( type ) {
1044                         case ID_IMAP:
1045                         case ID_PROC:
1046                         case ID_GRAD:
1047                                 tex = lwGetTexture( fp, sz - 4, type );
1048                                 if ( !tex ) {
1049                                         goto Fail;
1050                                 }
1051                                 if ( !add_texture( surf, tex ) ) {
1052                                         lwFreeTexture( tex );
1053                                 }
1054                                 set_flen( 4 + get_flen() );
1055                                 break;
1056                         case ID_SHDR:
1057                                 shdr = lwGetShader( fp, sz - 4 );
1058                                 if ( !shdr ) {
1059                                         goto Fail;
1060                                 }
1061                                 lwListInsert((void **) &surf->shader, shdr, (int (*)(void *, void *)) compare_shaders);
1062                                 ++surf->nshaders;
1063                                 set_flen( 4 + get_flen() );
1064                                 break;
1065                         }
1066                         break;
1067
1068                 default:
1069                         break;
1070                 }
1071
1072                 /* error while reading current subchunk? */
1073
1074                 rlen = get_flen();
1075                 if ( rlen < 0 || rlen > sz ) {
1076                         goto Fail;
1077                 }
1078
1079                 /* skip unread parts of the current subchunk */
1080
1081                 if ( rlen < sz ) {
1082                         _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
1083                 }
1084
1085                 /* end of the SURF chunk? */
1086
1087                 if ( cksize <= _pico_memstream_tell( fp ) - pos ) {
1088                         break;
1089                 }
1090
1091                 /* get the next subchunk header */
1092
1093                 set_flen( 0 );
1094                 id = getU4( fp );
1095                 sz = getU2( fp );
1096                 if ( 6 != get_flen() ) {
1097                         goto Fail;
1098                 }
1099         }
1100
1101         return surf;
1102
1103 Fail:
1104         if ( surf ) {
1105                 lwFreeSurface( surf );
1106         }
1107         return NULL;
1108 }