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