7f93c7571f30fd14c9395d4e28e715d4f3bc1c4d
[summerhack] / src / 3dengfx / libs / lib3ds / material.c
1 /*
2  * The 3D Studio File Format Library
3  * Copyright (C) 1996-2001 by J.E. Hoffmann <je-h@gmx.net>
4  * All rights reserved.
5  *
6  * This program is  free  software;  you can redistribute it and/or modify it
7  * under the terms of the  GNU Lesser General Public License  as published by 
8  * the  Free Software Foundation;  either version 2.1 of the License,  or (at 
9  * your option) any later version.
10  *
11  * This  program  is  distributed in  the  hope that it will  be useful,  but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or  FITNESS FOR A  PARTICULAR PURPOSE.  See the  GNU Lesser General Public  
14  * License for more details.
15  *
16  * You should  have received  a copy of the GNU Lesser General Public License
17  * along with  this program;  if not, write to the  Free Software Foundation,
18  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  * $Id: material.c,v 1.18 2004/11/20 08:31:31 efalk Exp $
21  */
22 #define LIB3DS_EXPORT
23 #include <lib3ds/material.h>
24 #include <lib3ds/chunk.h>
25 #include <lib3ds/io.h>
26 #include <stdlib.h>
27 #include <math.h>
28 #include <string.h>
29 #ifdef WITH_DMALLOC
30 #include <dmalloc.h>
31 #endif
32
33
34 /*!
35  * \defgroup material Materials
36  *
37  * \author J.E. Hoffmann <je-h@gmx.net>
38  */
39
40
41 static void
42 initialize_texture_map(Lib3dsTextureMap *map)
43 {
44   map->flags = 0x10;
45   map->percent = 1.0f;
46   map->scale[0] = 1.0f;
47   map->scale[1] = 1.0f;
48 }
49
50
51 /*!
52  * Creates and returns a new, empty Lib3dsMaterial object.
53  *
54  * Initial value of the material is a shiny grey.
55  *
56  * \return      A pointer to the Lib3dsMaterial structure.
57  *              If the structure cannot be allocated, NULL is returned.
58  *
59  * \ingroup material
60  */
61 Lib3dsMaterial*
62 lib3ds_material_new()
63 {
64   Lib3dsMaterial *mat;
65
66   mat = (Lib3dsMaterial*)calloc(sizeof(Lib3dsMaterial), 1);
67   if (!mat) {
68     return(0);
69   }
70
71   mat->ambient[0] = mat->ambient[1] = mat->ambient[2] = 0.588235f;
72   mat->diffuse[0] = mat->diffuse[1] = mat->diffuse[2] = 0.588235f;
73   mat->specular[0] = mat->specular[1] = mat->specular[2] = 0.898039f;
74   mat->shininess = 0.1f;
75   mat->wire_size = 1.0f;
76   mat->shading = 3;
77
78   initialize_texture_map(&mat->texture1_map);
79   initialize_texture_map(&mat->texture1_mask);
80   initialize_texture_map(&mat->texture2_map);
81   initialize_texture_map(&mat->texture2_mask);
82   initialize_texture_map(&mat->opacity_map);
83   initialize_texture_map(&mat->opacity_mask);
84   initialize_texture_map(&mat->bump_map);
85   initialize_texture_map(&mat->bump_mask);
86   initialize_texture_map(&mat->specular_map);
87   initialize_texture_map(&mat->specular_mask);
88   initialize_texture_map(&mat->shininess_map);
89   initialize_texture_map(&mat->shininess_mask);
90   initialize_texture_map(&mat->self_illum_map);
91   initialize_texture_map(&mat->self_illum_mask);
92   initialize_texture_map(&mat->reflection_map);
93   initialize_texture_map(&mat->reflection_mask);
94   
95   return(mat);
96 }
97
98
99 /*!
100  * \ingroup material
101  */
102 void
103 lib3ds_material_free(Lib3dsMaterial *material)
104 {
105   memset(material, 0, sizeof(Lib3dsMaterial));
106   free(material);
107 }
108
109
110 static Lib3dsBool
111 color_read(Lib3dsRgba rgb, Lib3dsIo *io)
112 {
113   Lib3dsChunk c;
114   Lib3dsWord chunk;
115   Lib3dsBool have_lin=LIB3DS_FALSE;
116
117   if (!lib3ds_chunk_read_start(&c, 0, io)) {
118     return(LIB3DS_FALSE);
119   }
120
121   while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
122     switch (chunk) {
123       case LIB3DS_LIN_COLOR_24:
124         {
125           int i;
126           for (i=0; i<3; ++i) {
127             rgb[i]=1.0f*lib3ds_io_read_byte(io)/255.0f;
128           }
129           rgb[3]=1.0f;
130         }
131         have_lin=LIB3DS_TRUE;
132         break;
133       case LIB3DS_COLOR_24:
134         /* gamma corrected color chunk
135            replaced in 3ds R3 by LIN_COLOR_24 */
136         if (!have_lin) {
137           int i;
138           for (i=0; i<3; ++i) {
139             rgb[i]=1.0f*lib3ds_io_read_byte(io)/255.0f;
140           }
141           rgb[3]=1.0f;
142         }
143         break;
144       default:
145         lib3ds_chunk_unknown(chunk);
146     }
147   }
148   
149   lib3ds_chunk_read_end(&c, io);
150   return(LIB3DS_TRUE);
151 }
152
153
154 static Lib3dsBool
155 int_percentage_read(Lib3dsFloat *p, Lib3dsIo *io)
156 {
157   Lib3dsChunk c;
158   Lib3dsWord chunk;
159
160   if (!lib3ds_chunk_read_start(&c, 0, io)) {
161     return(LIB3DS_FALSE);
162   }
163
164   while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
165     switch (chunk) {
166       case LIB3DS_INT_PERCENTAGE:
167         {
168           Lib3dsIntw i=lib3ds_io_read_intw(io);
169           *p=(Lib3dsFloat)(1.0*i/100.0);
170         }
171         break;
172       default:
173         lib3ds_chunk_unknown(chunk);
174     }
175   }
176   
177   lib3ds_chunk_read_end(&c, io);
178   return(LIB3DS_TRUE);
179 }
180
181
182 static Lib3dsBool
183 texture_map_read(Lib3dsTextureMap *map, Lib3dsIo *io)
184 {
185   Lib3dsChunk c;
186   Lib3dsWord chunk;
187
188   if (!lib3ds_chunk_read_start(&c, 0, io)) {
189     return(LIB3DS_FALSE);
190   }
191
192   while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
193     switch (chunk) {
194       case LIB3DS_INT_PERCENTAGE:
195         {
196           map->percent=1.0f*lib3ds_io_read_intw(io)/100.0f;
197         }
198         break;
199       case LIB3DS_MAT_MAPNAME:
200         {
201           if (!lib3ds_io_read_string(io, map->name, 64)) {
202             return(LIB3DS_FALSE);
203           }
204           lib3ds_chunk_dump_info("  NAME=%s", map->name);
205         }
206         break;
207       case LIB3DS_MAT_MAP_TILING:
208         {
209           map->flags=lib3ds_io_read_word(io);
210         }
211         break;
212       case LIB3DS_MAT_MAP_TEXBLUR:
213         {
214           map->blur=lib3ds_io_read_float(io);
215         }
216         break;
217       case LIB3DS_MAT_MAP_USCALE:
218         {
219           map->scale[0]=lib3ds_io_read_float(io);
220         }
221         break;
222       case LIB3DS_MAT_MAP_VSCALE:
223         {
224           map->scale[1]=lib3ds_io_read_float(io);
225         }
226         break;
227       case LIB3DS_MAT_MAP_UOFFSET:
228         {
229           map->offset[0]=lib3ds_io_read_float(io);
230         }
231         break;
232       case LIB3DS_MAT_MAP_VOFFSET:
233         {
234           map->offset[1]=lib3ds_io_read_float(io);
235         }
236         break;
237       case LIB3DS_MAT_MAP_ANG:
238         {
239           map->rotation=lib3ds_io_read_float(io);
240         }
241         break;
242       case LIB3DS_MAT_MAP_COL1:
243         {
244           map->tint_1[0]=1.0f*lib3ds_io_read_byte(io)/255.0f;
245           map->tint_1[1]=1.0f*lib3ds_io_read_byte(io)/255.0f;
246           map->tint_1[2]=1.0f*lib3ds_io_read_byte(io)/255.0f;
247         }
248         break;
249       case LIB3DS_MAT_MAP_COL2:
250         {
251           map->tint_2[0]=1.0f*lib3ds_io_read_byte(io)/255.0f;
252           map->tint_2[1]=1.0f*lib3ds_io_read_byte(io)/255.0f;
253           map->tint_2[2]=1.0f*lib3ds_io_read_byte(io)/255.0f;
254         }
255         break;
256       case LIB3DS_MAT_MAP_RCOL:
257         {
258           map->tint_r[0]=1.0f*lib3ds_io_read_byte(io)/255.0f;
259           map->tint_r[1]=1.0f*lib3ds_io_read_byte(io)/255.0f;
260           map->tint_r[2]=1.0f*lib3ds_io_read_byte(io)/255.0f;
261         }
262         break;
263       case LIB3DS_MAT_MAP_GCOL:
264         {
265           map->tint_g[0]=1.0f*lib3ds_io_read_byte(io)/255.0f;
266           map->tint_g[1]=1.0f*lib3ds_io_read_byte(io)/255.0f;
267           map->tint_g[2]=1.0f*lib3ds_io_read_byte(io)/255.0f;
268         }
269         break;
270       case LIB3DS_MAT_MAP_BCOL:
271         {
272           map->tint_b[0]=1.0f*lib3ds_io_read_byte(io)/255.0f;
273           map->tint_b[1]=1.0f*lib3ds_io_read_byte(io)/255.0f;
274           map->tint_b[2]=1.0f*lib3ds_io_read_byte(io)/255.0f;
275         }
276         break;
277       default:
278         lib3ds_chunk_unknown(chunk);
279     }
280   }
281   
282   lib3ds_chunk_read_end(&c, io);
283   return(LIB3DS_TRUE);
284 }
285
286
287 /*!
288  * \ingroup material
289  */
290 static void
291 texture_dump(const char *maptype, Lib3dsTextureMap *texture)
292 {
293   ASSERT(texture);
294   if (strlen(texture->name)==0) {
295     return;
296   }
297   printf("  %s:\n", maptype);
298   printf("    name:        %s\n", texture->name);
299   printf("    flags:       %X\n", (unsigned)texture->flags);
300   printf("    percent:     %f\n", texture->percent);
301   printf("    blur:        %f\n", texture->blur);
302   printf("    scale:       (%f, %f)\n", texture->scale[0], texture->scale[1]);
303   printf("    offset:      (%f, %f)\n", texture->offset[0], texture->offset[1]);
304   printf("    rotation:    %f\n", texture->rotation);
305   printf("    tint_1:      (%f, %f, %f)\n",
306     texture->tint_1[0], texture->tint_1[1], texture->tint_1[2]);
307   printf("    tint_2:      (%f, %f, %f)\n",
308     texture->tint_2[0], texture->tint_2[1], texture->tint_2[2]);
309   printf("    tint_r:      (%f, %f, %f)\n",
310     texture->tint_r[0], texture->tint_r[1], texture->tint_r[2]);
311   printf("    tint_g:      (%f, %f, %f)\n",
312     texture->tint_g[0], texture->tint_g[1], texture->tint_g[2]);
313   printf("    tint_b:      (%f, %f, %f)\n",
314     texture->tint_b[0], texture->tint_b[1], texture->tint_b[2]);
315 }
316
317
318 /*!
319  * \ingroup material
320  */
321 void
322 lib3ds_material_dump(Lib3dsMaterial *material)
323 {
324   ASSERT(material);
325   printf("  name:          %s\n", material->name);
326   printf("  ambient:       (%f, %f, %f)\n",
327     material->ambient[0], material->ambient[1], material->ambient[2]);
328   printf("  diffuse:       (%f, %f, %f)\n",
329     material->diffuse[0], material->diffuse[1], material->diffuse[2]);
330   printf("  specular:      (%f, %f, %f)\n",
331     material->specular[0], material->specular[1], material->specular[2]);
332   printf("  shininess:     %f\n", material->shininess);
333   printf("  shin_strength: %f\n", material->shin_strength);
334   printf("  use_blur:      %s\n", material->use_blur ? "yes" : "no");
335   printf("  blur:          %f\n", material->blur);
336   printf("  falloff:       %f\n", material->falloff);
337   printf("  additive:      %s\n", material->additive ? "yes" : "no");
338   printf("  use_falloff:   %s\n", material->use_falloff ? "yes" : "no");
339   printf("  self_illum:    %s\n", material->self_illum ? "yes" : "no");
340   printf("  self_ilpct:    %f\n", material->self_ilpct);
341   printf("  shading:       %d\n", material->shading);
342   printf("  soften:        %s\n", material->soften ? "yes" : "no");
343   printf("  face_map:      %s\n", material->face_map ? "yes" : "no");
344   printf("  two_sided:     %s\n", material->two_sided ? "yes" : "no");
345   printf("  map_decal:     %s\n", material->map_decal ? "yes" : "no");
346   printf("  use_wire:      %s\n", material->use_wire ? "yes" : "no");
347   printf("  use_wire_abs:  %s\n", material->use_wire_abs ? "yes" : "no");
348   printf("  wire_size:     %f\n", material->wire_size);
349   texture_dump("texture1_map", &material->texture1_map);
350   texture_dump("texture1_mask", &material->texture1_mask);
351   texture_dump("texture2_map", &material->texture2_map);
352   texture_dump("texture2_mask", &material->texture2_mask);
353   texture_dump("opacity_map", &material->opacity_map);
354   texture_dump("opacity_mask", &material->opacity_mask);
355   texture_dump("bump_map", &material->bump_map);
356   texture_dump("bump_mask", &material->bump_mask);
357   texture_dump("specular_map", &material->specular_map);
358   texture_dump("specular_mask", &material->specular_mask);
359   texture_dump("shininess_map", &material->shininess_map);
360   texture_dump("shininess_mask", &material->shininess_mask);
361   texture_dump("self_illum_map", &material->self_illum_map);
362   texture_dump("self_illum_mask", &material->self_illum_mask);
363   texture_dump("reflection_map", &material->reflection_map);
364   texture_dump("reflection_mask", &material->reflection_mask);
365   printf("  autorefl_map:\n");
366   printf("    flags        %X\n", (unsigned)material->autorefl_map.flags);
367   printf("    level        %d\n", (int)material->autorefl_map.level);
368   printf("    size         %d\n", (int)material->autorefl_map.size);
369   printf("    frame_step   %d\n", (int)material->autorefl_map.frame_step);
370   printf("\n");
371 }
372
373
374 /*!
375  * \ingroup material
376  */
377 Lib3dsBool
378 lib3ds_material_read(Lib3dsMaterial *material, Lib3dsIo *io)
379 {
380   Lib3dsChunk c;
381   Lib3dsWord chunk;
382
383   ASSERT(material);
384   if (!lib3ds_chunk_read_start(&c, LIB3DS_MAT_ENTRY, io)) {
385     return(LIB3DS_FALSE);
386   }
387
388   while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
389     switch (chunk) {
390       case LIB3DS_MAT_NAME:
391         {
392           if (!lib3ds_io_read_string(io, material->name, 64)) {
393             return(LIB3DS_FALSE);
394           }
395           lib3ds_chunk_dump_info("  NAME=%s", material->name);
396         }
397         break;
398       case LIB3DS_MAT_AMBIENT:
399         {
400           lib3ds_chunk_read_reset(&c, io);
401           if (!color_read(material->ambient, io)) {
402             return(LIB3DS_FALSE);
403           }
404         }
405         break;
406       case LIB3DS_MAT_DIFFUSE:
407         {
408           lib3ds_chunk_read_reset(&c, io);
409           if (!color_read(material->diffuse, io)) {
410             return(LIB3DS_FALSE);
411           }
412         }
413         break;
414       case LIB3DS_MAT_SPECULAR:
415         {
416           lib3ds_chunk_read_reset(&c, io);
417           if (!color_read(material->specular, io)) {
418             return(LIB3DS_FALSE);
419           }
420         }
421         break;
422       case LIB3DS_MAT_SHININESS:
423         {
424           lib3ds_chunk_read_reset(&c, io);
425           if (!int_percentage_read(&material->shininess, io)) {
426             return(LIB3DS_FALSE);
427           }
428         }
429         break;
430       case LIB3DS_MAT_SHIN2PCT:
431         {
432           lib3ds_chunk_read_reset(&c, io);
433           if (!int_percentage_read(&material->shin_strength, io)) {
434             return(LIB3DS_FALSE);
435           }
436         }
437         break;
438       case LIB3DS_MAT_TRANSPARENCY:
439         {
440           lib3ds_chunk_read_reset(&c, io);
441           if (!int_percentage_read(&material->transparency, io)) {
442             return(LIB3DS_FALSE);
443           }
444         }
445         break;
446       case LIB3DS_MAT_XPFALL:
447         {
448           lib3ds_chunk_read_reset(&c, io);
449           if (!int_percentage_read(&material->falloff, io)) {
450             return(LIB3DS_FALSE);
451           }
452         }
453         break;
454       case LIB3DS_MAT_SELF_ILPCT:
455         {
456           lib3ds_chunk_read_reset(&c, io);
457           if (!int_percentage_read(&material->self_ilpct, io)) {
458             return(LIB3DS_FALSE);
459           }
460         }
461         break;
462       case LIB3DS_MAT_USE_XPFALL:
463         {
464           material->use_falloff=LIB3DS_TRUE;
465         }
466         break;
467       case LIB3DS_MAT_REFBLUR:
468         {
469           lib3ds_chunk_read_reset(&c, io);
470           if (!int_percentage_read(&material->blur, io)) {
471             return(LIB3DS_FALSE);
472           }
473         }
474         break;
475       case LIB3DS_MAT_USE_REFBLUR:
476         {
477           material->use_blur=LIB3DS_TRUE;
478         }
479         break;
480       case LIB3DS_MAT_SHADING:
481         {
482           material->shading=lib3ds_io_read_intw(io);
483         }
484         break;
485       case LIB3DS_MAT_SELF_ILLUM:
486         {
487           material->self_illum=LIB3DS_TRUE;
488         }
489         break;
490       case LIB3DS_MAT_TWO_SIDE:
491         {
492           material->two_sided=LIB3DS_TRUE;
493         }
494         break;
495       case LIB3DS_MAT_DECAL:
496         {
497           material->map_decal=LIB3DS_TRUE;
498         }
499         break;
500       case LIB3DS_MAT_ADDITIVE:
501         {
502           material->additive=LIB3DS_TRUE;
503         }
504         break;
505       case LIB3DS_MAT_FACEMAP:
506         {
507           material->face_map=LIB3DS_TRUE;
508         }
509         break;
510       case LIB3DS_MAT_PHONGSOFT:
511         {
512           material->soften=LIB3DS_TRUE;
513         }
514         break;
515       case LIB3DS_MAT_WIRE:
516         {
517           material->use_wire=LIB3DS_TRUE;
518         }
519         break;
520       case LIB3DS_MAT_WIREABS:
521         {
522           material->use_wire_abs=LIB3DS_TRUE;
523         }
524         break;
525       case LIB3DS_MAT_WIRE_SIZE:
526         {
527           material->wire_size=lib3ds_io_read_float(io);
528         }
529         break;
530       case LIB3DS_MAT_TEXMAP:
531         {
532           lib3ds_chunk_read_reset(&c, io);
533           if (!texture_map_read(&material->texture1_map, io)) {
534             return(LIB3DS_FALSE);
535           }
536         }
537         break;
538       case LIB3DS_MAT_TEXMASK:
539         {
540           lib3ds_chunk_read_reset(&c, io);
541           if (!texture_map_read(&material->texture1_mask, io)) {
542             return(LIB3DS_FALSE);
543           }
544         }
545         break;
546       case LIB3DS_MAT_TEX2MAP:
547         {
548           lib3ds_chunk_read_reset(&c, io);
549           if (!texture_map_read(&material->texture2_map, io)) {
550             return(LIB3DS_FALSE);
551           }
552         }
553         break;
554       case LIB3DS_MAT_TEX2MASK:
555         {
556           lib3ds_chunk_read_reset(&c, io);
557           if (!texture_map_read(&material->texture2_mask, io)) {
558             return(LIB3DS_FALSE);
559           }
560         }
561         break;
562       case LIB3DS_MAT_OPACMAP:
563         {
564           lib3ds_chunk_read_reset(&c, io);
565           if (!texture_map_read(&material->opacity_map, io)) {
566             return(LIB3DS_FALSE);
567           }
568         }
569         break;
570       case LIB3DS_MAT_OPACMASK:
571         {
572           lib3ds_chunk_read_reset(&c, io);
573           if (!texture_map_read(&material->opacity_mask, io)) {
574             return(LIB3DS_FALSE);
575           }
576         }
577         break;
578       case LIB3DS_MAT_BUMPMAP:
579         {
580           lib3ds_chunk_read_reset(&c, io);
581           if (!texture_map_read(&material->bump_map, io)) {
582             return(LIB3DS_FALSE);
583           }
584         }
585         break;
586       case LIB3DS_MAT_BUMPMASK:
587         {
588           lib3ds_chunk_read_reset(&c, io);
589           if (!texture_map_read(&material->bump_mask, io)) {
590             return(LIB3DS_FALSE);
591           }
592         }
593         break;
594       case LIB3DS_MAT_SPECMAP:
595         {
596           lib3ds_chunk_read_reset(&c, io);
597           if (!texture_map_read(&material->specular_map, io)) {
598             return(LIB3DS_FALSE);
599           }
600         }
601         break;
602       case LIB3DS_MAT_SPECMASK:
603         {
604           lib3ds_chunk_read_reset(&c, io);
605           if (!texture_map_read(&material->specular_mask, io)) {
606             return(LIB3DS_FALSE);
607           }
608         }
609         break;
610       case LIB3DS_MAT_SHINMAP:
611         {
612           lib3ds_chunk_read_reset(&c, io);
613           if (!texture_map_read(&material->shininess_map, io)) {
614             return(LIB3DS_FALSE);
615           }
616         }
617         break;
618       case LIB3DS_MAT_SHINMASK:
619         {
620           lib3ds_chunk_read_reset(&c, io);
621           if (!texture_map_read(&material->shininess_mask, io)) {
622             return(LIB3DS_FALSE);
623           }
624         }
625         break;
626       case LIB3DS_MAT_SELFIMAP:
627         {
628           lib3ds_chunk_read_reset(&c, io);
629           if (!texture_map_read(&material->self_illum_map, io)) {
630             return(LIB3DS_FALSE);
631           }
632         }
633         break;
634       case LIB3DS_MAT_SELFIMASK:
635         {
636           lib3ds_chunk_read_reset(&c, io);
637           if (!texture_map_read(&material->self_illum_mask, io)) {
638             return(LIB3DS_FALSE);
639           }
640         }
641         break;
642       case LIB3DS_MAT_REFLMAP:
643         {
644           lib3ds_chunk_read_reset(&c, io);
645           if (!texture_map_read(&material->reflection_map, io)) {
646             return(LIB3DS_FALSE);
647           }
648         }
649         break;
650       case LIB3DS_MAT_REFLMASK:
651         {
652           lib3ds_chunk_read_reset(&c, io);
653           if (!texture_map_read(&material->reflection_mask, io)) {
654             return(LIB3DS_FALSE);
655           }
656         }
657         break;
658       case LIB3DS_MAT_ACUBIC:
659         {
660           lib3ds_io_read_intb(io);
661           material->autorefl_map.level=lib3ds_io_read_intb(io);
662           material->autorefl_map.flags=lib3ds_io_read_intw(io);
663           material->autorefl_map.size=lib3ds_io_read_intd(io);
664           material->autorefl_map.frame_step=lib3ds_io_read_intd(io);
665         }
666         break;
667       default:
668         lib3ds_chunk_unknown(chunk);
669     }
670   }
671
672   lib3ds_chunk_read_end(&c, io);
673   return(LIB3DS_TRUE);
674 }
675
676
677 static Lib3dsBool
678 color_write(Lib3dsRgba rgb, Lib3dsIo *io)
679 {
680   Lib3dsChunk c;
681
682   c.chunk=LIB3DS_COLOR_24;
683   c.size=9;
684   lib3ds_chunk_write(&c,io);
685   lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*rgb[0]+0.5));
686   lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*rgb[1]+0.5));
687   lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*rgb[2]+0.5));
688
689   c.chunk=LIB3DS_LIN_COLOR_24;
690   c.size=9;
691   lib3ds_chunk_write(&c,io);
692   lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*rgb[0]+0.5));
693   lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*rgb[1]+0.5));
694   lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*rgb[2]+0.5));
695
696   return(LIB3DS_TRUE);
697 }
698
699
700 static Lib3dsBool
701 int_percentage_write(Lib3dsFloat p, Lib3dsIo *io)
702 {
703   Lib3dsChunk c;
704
705   c.chunk=LIB3DS_INT_PERCENTAGE;
706   c.size=8;
707   lib3ds_chunk_write(&c,io);
708   lib3ds_io_write_intw(io, (Lib3dsByte)floor(100.0*p+0.5));
709
710   return(LIB3DS_TRUE);
711 }
712
713
714 static Lib3dsBool
715 texture_map_write(Lib3dsWord chunk, Lib3dsTextureMap *map, Lib3dsIo *io)
716 {
717   Lib3dsChunk c;
718
719   if (strlen(map->name)==0) {
720     return(LIB3DS_TRUE);
721   }
722   c.chunk=chunk;
723   if (!lib3ds_chunk_write_start(&c,io)) {
724     return(LIB3DS_FALSE);
725   }
726   
727   int_percentage_write(map->percent,io);
728
729   { /*---- LIB3DS_MAT_MAPNAME ----*/
730     Lib3dsChunk c;
731     c.chunk=LIB3DS_MAT_MAPNAME;
732     c.size=6+strlen(map->name)+1;
733     lib3ds_chunk_write(&c,io);
734     lib3ds_io_write_string(io, map->name);
735   }
736
737   { /*---- LIB3DS_MAT_MAP_TILING ----*/
738     Lib3dsChunk c;
739     c.chunk=LIB3DS_MAT_MAP_TILING;
740     c.size=8;
741     lib3ds_chunk_write(&c,io);
742     lib3ds_io_write_word(io, (Lib3dsWord)map->flags);
743   }
744   
745   { /*---- LIB3DS_MAT_MAP_TEXBLUR ----*/
746     Lib3dsChunk c;
747     c.chunk=LIB3DS_MAT_MAP_TEXBLUR;
748     c.size=10;
749     lib3ds_chunk_write(&c,io);
750     lib3ds_io_write_float(io, map->blur);
751   }
752
753   { /*---- LIB3DS_MAT_MAP_USCALE ----*/
754     Lib3dsChunk c;
755     c.chunk=LIB3DS_MAT_MAP_USCALE;
756     c.size=10;
757     lib3ds_chunk_write(&c,io);
758     lib3ds_io_write_float(io, map->scale[0]);
759   }
760
761   { /*---- LIB3DS_MAT_MAP_VSCALE ----*/
762     Lib3dsChunk c;
763     c.chunk=LIB3DS_MAT_MAP_VSCALE;
764     c.size=10;
765     lib3ds_chunk_write(&c,io);
766     lib3ds_io_write_float(io, map->scale[1]);
767   }
768
769   { /*---- LIB3DS_MAT_MAP_UOFFSET ----*/
770     Lib3dsChunk c;
771     c.chunk=LIB3DS_MAT_MAP_UOFFSET;
772     c.size=10;
773     lib3ds_chunk_write(&c,io);
774     lib3ds_io_write_float(io, map->offset[0]);
775   }
776
777   { /*---- LIB3DS_MAT_MAP_VOFFSET ----*/
778     Lib3dsChunk c;
779     c.chunk=LIB3DS_MAT_MAP_VOFFSET;
780     c.size=10;
781     lib3ds_chunk_write(&c,io);
782     lib3ds_io_write_float(io, map->offset[1]);
783   }
784
785   { /*---- LIB3DS_MAT_MAP_ANG ----*/
786     Lib3dsChunk c;
787     c.chunk=LIB3DS_MAT_MAP_ANG;
788     c.size=10;
789     lib3ds_chunk_write(&c,io);
790     lib3ds_io_write_float(io, map->rotation);
791   }
792
793   { /*---- LIB3DS_MAT_MAP_COL1 ----*/
794     Lib3dsChunk c;
795     c.chunk=LIB3DS_MAT_MAP_COL1;
796     c.size=9;
797     lib3ds_chunk_write(&c,io);
798     lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_1[0]+0.5));
799     lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_1[1]+0.5));
800     lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_1[2]+0.5));
801   }
802
803   { /*---- LIB3DS_MAT_MAP_COL2 ----*/
804     Lib3dsChunk c;
805     c.chunk=LIB3DS_MAT_MAP_COL2;
806     c.size=9;
807     lib3ds_chunk_write(&c,io);
808     lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_2[0]+0.5));
809     lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_2[1]+0.5));
810     lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_2[2]+0.5));
811   }
812   
813   { /*---- LIB3DS_MAT_MAP_RCOL ----*/
814     Lib3dsChunk c;
815     c.chunk=LIB3DS_MAT_MAP_RCOL;
816     c.size=9;
817     lib3ds_chunk_write(&c,io);
818     lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_r[0]+0.5));
819     lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_r[1]+0.5));
820     lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_r[2]+0.5));
821   }
822
823   { /*---- LIB3DS_MAT_MAP_GCOL ----*/
824     Lib3dsChunk c;
825     c.chunk=LIB3DS_MAT_MAP_GCOL;
826     c.size=9;
827     lib3ds_chunk_write(&c,io);
828     lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_g[0]+0.5));
829     lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_g[1]+0.5));
830     lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_g[2]+0.5));
831   }
832   
833   { /*---- LIB3DS_MAT_MAP_BCOL ----*/
834     Lib3dsChunk c;
835     c.chunk=LIB3DS_MAT_MAP_BCOL;
836     c.size=9;
837     lib3ds_chunk_write(&c,io);
838     lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_b[0]+0.5));
839     lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_b[1]+0.5));
840     lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_b[2]+0.5));
841   }
842
843   if (!lib3ds_chunk_write_end(&c,io)) {
844     return(LIB3DS_FALSE);
845   }
846   return(LIB3DS_TRUE);
847 }
848
849
850 /*!
851  * \ingroup material
852  */
853 Lib3dsBool
854 lib3ds_material_write(Lib3dsMaterial *material, Lib3dsIo *io)
855 {
856   Lib3dsChunk c;
857
858   c.chunk=LIB3DS_MAT_ENTRY;
859   if (!lib3ds_chunk_write_start(&c,io)) {
860     return(LIB3DS_FALSE);
861   }
862
863   { /*---- LIB3DS_MAT_NAME ----*/
864     Lib3dsChunk c;
865     c.chunk=LIB3DS_MAT_NAME;
866     c.size=6+strlen(material->name)+1;
867     lib3ds_chunk_write(&c,io);
868     lib3ds_io_write_string(io, material->name);
869   }
870
871   { /*---- LIB3DS_MAT_AMBIENT ----*/
872     Lib3dsChunk c;
873     c.chunk=LIB3DS_MAT_AMBIENT;
874     c.size=24;
875     lib3ds_chunk_write(&c,io);
876     color_write(material->ambient,io);
877   }
878
879   { /*---- LIB3DS_MAT_DIFFUSE ----*/
880     Lib3dsChunk c;
881     c.chunk=LIB3DS_MAT_DIFFUSE;
882     c.size=24;
883     lib3ds_chunk_write(&c,io);
884     color_write(material->diffuse,io);
885   }
886
887   { /*---- LIB3DS_MAT_SPECULAR ----*/
888     Lib3dsChunk c;
889     c.chunk=LIB3DS_MAT_SPECULAR;
890     c.size=24;
891     lib3ds_chunk_write(&c,io);
892     color_write(material->specular,io);
893   }
894
895   { /*---- LIB3DS_MAT_SHININESS ----*/
896     Lib3dsChunk c;
897     c.chunk=LIB3DS_MAT_SHININESS;
898     c.size=14;
899     lib3ds_chunk_write(&c,io);
900     int_percentage_write(material->shininess,io);
901   }
902
903   { /*---- LIB3DS_MAT_SHIN2PCT ----*/
904     Lib3dsChunk c;
905     c.chunk=LIB3DS_MAT_SHIN2PCT;
906     c.size=14;
907     lib3ds_chunk_write(&c,io);
908     int_percentage_write(material->shin_strength,io);
909   }
910
911   { /*---- LIB3DS_MAT_TRANSPARENCY ----*/
912     Lib3dsChunk c;
913     c.chunk=LIB3DS_MAT_TRANSPARENCY;
914     c.size=14;
915     lib3ds_chunk_write(&c,io);
916     int_percentage_write(material->transparency,io);
917   }
918
919   { /*---- LIB3DS_MAT_XPFALL ----*/
920     Lib3dsChunk c;
921     c.chunk=LIB3DS_MAT_XPFALL;
922     c.size=14;
923     lib3ds_chunk_write(&c,io);
924     int_percentage_write(material->falloff,io);
925   }
926
927   if (material->use_falloff) { /*---- LIB3DS_MAT_USE_XPFALL ----*/
928     Lib3dsChunk c;
929     c.chunk=LIB3DS_MAT_USE_XPFALL;
930     c.size=6;
931     lib3ds_chunk_write(&c,io);
932   }
933
934   { /*---- LIB3DS_MAT_SHADING ----*/
935     Lib3dsChunk c;
936     c.chunk=LIB3DS_MAT_SHADING;
937     c.size=8;
938     lib3ds_chunk_write(&c,io);
939     lib3ds_io_write_intw(io, material->shading);
940   }
941
942   { /*---- LIB3DS_MAT_REFBLUR ----*/
943     Lib3dsChunk c;
944     c.chunk=LIB3DS_MAT_REFBLUR;
945     c.size=14;
946     lib3ds_chunk_write(&c,io);
947     int_percentage_write(material->blur,io);
948   }
949
950   if (material->use_blur) { /*---- LIB3DS_MAT_USE_REFBLUR ----*/
951     Lib3dsChunk c;
952     c.chunk=LIB3DS_MAT_USE_REFBLUR;
953     c.size=6;
954     lib3ds_chunk_write(&c,io);
955   }
956
957   if (material->self_illum) { /*---- LIB3DS_MAT_SELF_ILLUM ----*/
958     Lib3dsChunk c;
959     c.chunk=LIB3DS_MAT_SELF_ILLUM;
960     c.size=6;
961     lib3ds_chunk_write(&c,io);
962   }
963
964   if (material->two_sided) { /*---- LIB3DS_MAT_TWO_SIDE ----*/
965     Lib3dsChunk c;
966     c.chunk=LIB3DS_MAT_TWO_SIDE;
967     c.size=6;
968     lib3ds_chunk_write(&c,io);
969   }
970   
971   if (material->map_decal) { /*---- LIB3DS_MAT_DECAL ----*/
972     Lib3dsChunk c;
973     c.chunk=LIB3DS_MAT_DECAL;
974     c.size=6;
975     lib3ds_chunk_write(&c,io);
976   }
977
978   if (material->additive) { /*---- LIB3DS_MAT_ADDITIVE ----*/
979     Lib3dsChunk c;
980     c.chunk=LIB3DS_MAT_ADDITIVE;
981     c.size=6;
982     lib3ds_chunk_write(&c,io);
983   }
984
985   if (material->use_wire) { /*---- LIB3DS_MAT_WIRE ----*/
986     Lib3dsChunk c;
987     c.chunk=LIB3DS_MAT_WIRE;
988     c.size=6;
989     lib3ds_chunk_write(&c,io);
990   }
991
992   if (material->use_wire_abs) { /*---- LIB3DS_MAT_WIREABS ----*/
993     Lib3dsChunk c;
994     c.chunk=LIB3DS_MAT_WIREABS;
995     c.size=6;
996     lib3ds_chunk_write(&c,io);
997   }
998
999   { /*---- LIB3DS_MAT_WIRE_SIZE ----*/
1000     Lib3dsChunk c;
1001     c.chunk=LIB3DS_MAT_WIRE_SIZE;
1002     c.size=10;
1003     lib3ds_chunk_write(&c,io);
1004     lib3ds_io_write_float(io, material->wire_size);
1005   }
1006
1007   if (material->face_map) { /*---- LIB3DS_MAT_FACEMAP ----*/
1008     Lib3dsChunk c;
1009     c.chunk=LIB3DS_MAT_FACEMAP;
1010     c.size=6;
1011     lib3ds_chunk_write(&c,io);
1012   }
1013
1014   if (material->soften) { /*---- LIB3DS_MAT_PHONGSOFT ----*/
1015     Lib3dsChunk c;
1016     c.chunk=LIB3DS_MAT_PHONGSOFT;
1017     c.size=6;
1018     lib3ds_chunk_write(&c,io);
1019   }
1020
1021   if (!texture_map_write(LIB3DS_MAT_TEXMAP, &material->texture1_map, io)) {
1022     return(LIB3DS_FALSE);
1023   }
1024   if (!texture_map_write(LIB3DS_MAT_TEXMASK, &material->texture1_mask, io)) {
1025     return(LIB3DS_FALSE);
1026   }
1027   if (!texture_map_write(LIB3DS_MAT_TEX2MAP, &material->texture2_map, io)) {
1028     return(LIB3DS_FALSE);
1029   }
1030   if (!texture_map_write(LIB3DS_MAT_TEX2MASK, &material->texture2_mask, io)) {
1031     return(LIB3DS_FALSE);
1032   }
1033   if (!texture_map_write(LIB3DS_MAT_OPACMAP, &material->opacity_map, io)) {
1034     return(LIB3DS_FALSE);
1035   }
1036   if (!texture_map_write(LIB3DS_MAT_OPACMASK, &material->opacity_mask, io)) {
1037     return(LIB3DS_FALSE);
1038   }
1039   if (!texture_map_write(LIB3DS_MAT_BUMPMAP, &material->bump_map, io)) {
1040     return(LIB3DS_FALSE);
1041   }
1042   if (!texture_map_write(LIB3DS_MAT_BUMPMASK, &material->bump_mask, io)) {
1043     return(LIB3DS_FALSE);
1044   }
1045   if (!texture_map_write(LIB3DS_MAT_SPECMAP, &material->specular_map, io)) {
1046     return(LIB3DS_FALSE);
1047   }
1048   if (!texture_map_write(LIB3DS_MAT_SPECMASK, &material->specular_mask, io)) {
1049     return(LIB3DS_FALSE);
1050   }
1051   if (!texture_map_write(LIB3DS_MAT_SHINMAP, &material->shininess_map, io)) {
1052     return(LIB3DS_FALSE);
1053   }
1054   if (!texture_map_write(LIB3DS_MAT_SHINMASK, &material->shininess_mask, io)) {
1055     return(LIB3DS_FALSE);
1056   }
1057   if (!texture_map_write(LIB3DS_MAT_SELFIMAP, &material->self_illum_map, io)) {
1058     return(LIB3DS_FALSE);
1059   }
1060   if (!texture_map_write(LIB3DS_MAT_SELFIMASK, &material->self_illum_mask, io)) {
1061     return(LIB3DS_FALSE);
1062   }
1063   if (!texture_map_write(LIB3DS_MAT_REFLMAP,  &material->reflection_map, io)) {
1064     return(LIB3DS_FALSE);
1065   }
1066   if (!texture_map_write(LIB3DS_MAT_REFLMASK,  &material->reflection_mask, io)) {
1067     return(LIB3DS_FALSE);
1068   }
1069
1070   if (!lib3ds_chunk_write_end(&c,io)) {
1071     return(LIB3DS_FALSE);
1072   }
1073   return(LIB3DS_TRUE);
1074 }
1075
1076
1077 /*!
1078
1079 \typedef Lib3dsMaterial
1080   \ingroup material
1081   \sa _Lib3dsMaterial
1082
1083 */
1084