1 /* Copyright (C) 1992-1998 The Geometry Center
2 * Copyright (C) 1998-2000 Stuart Levy, Tamara Munzner, Mark Phillips
3 * Copyright (C) 2006-2007 Claus-Justus Heine
4 *
5 * This file is part of Geomview.
6 *
7 * Geomview is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * Geomview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Geomview; see the file COPYING. If not, write
19 * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
20 * USA, or visit http://www.gnu.org.
21 */
22
23 #if HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include "appearance.h"
28 #include "transobj.h"
29 #include "handleP.h"
30 #include <string.h>
31 #include <sys/stat.h>
32
33 extern int Apsavepfx(int valid, int override, int mask, char *keyword,
34 FILE *f, Pool *p);
35
36 Material *
_MtSet(Material * mat,int attr1,va_list * alist)37 _MtSet(Material *mat, int attr1, va_list *alist)
38 {
39 int attr;
40
41 #define NEXT(type) va_arg(*alist, type)
42
43 if (mat == NULL) {
44 /*
45 * New Material created here.
46 */
47 mat = OOGLNewE(Material, "new Material");
48 MtDefault(mat);
49 }
50
51 for (attr = attr1; attr != MT_END; attr = NEXT(int)) {
52 switch (attr) { /* parse argument list */
53 case MT_AMBIENT:
54 mat->ambient = *NEXT(Color *);
55 mat->valid |= MTF_AMBIENT;
56 break;
57 case MT_DIFFUSE:
58 {
59 Color tmp;
60 tmp = *NEXT(Color *);
61 mat->diffuse.r = tmp.r;
62 mat->diffuse.g = tmp.g;
63 mat->diffuse.b = tmp.b;
64 mat->valid |= MTF_DIFFUSE;
65 break;
66 }
67 case MT_SPECULAR:
68 mat->specular = *NEXT(Color *);
69 mat->valid |= MTF_SPECULAR;
70 break;
71 case MT_EMISSION:
72 mat->emission = *NEXT(Color *);
73 mat->valid |= MTF_EMISSION;
74 break;
75 case MT_ALPHA:
76 mat->diffuse.a = NEXT(double);
77 mat->valid |= MTF_ALPHA;
78 break;
79 case MT_Ka:
80 mat->ka = NEXT(double);
81 mat->valid |= MTF_Ka;
82 break;
83 case MT_Kd:
84 mat->kd = NEXT(double);
85 mat->valid |= MTF_Kd;
86 break;
87 case MT_Ks:
88 mat->ks = NEXT(double);
89 mat->valid |= MTF_Ks;
90 break;
91 case MT_SHININESS:
92 mat->shininess = NEXT(double);
93 mat->valid |= MTF_SHININESS;
94 break;
95 case MT_EDGECOLOR:
96 mat->edgecolor = *NEXT(Color *);
97 mat->valid |= MTF_EDGECOLOR;
98 break;
99 case MT_NORMALCOLOR:
100 mat->normalcolor = *NEXT(Color *);
101 mat->valid |= MTF_NORMALCOLOR;
102 break;
103 case MT_INVALID:
104 mat->valid &= ~NEXT(int);
105 break;
106 case MT_OVERRIDE:
107 mat->override |= NEXT(int);
108 break;
109 case MT_NOOVERRIDE:
110 mat->override &= ~NEXT(int);
111 break;
112 default:
113 OOGLError (0, "_MtSet: undefined option: %d\n", attr);
114 return NULL;
115 break;
116 }
117 }
118
119 return mat;
120
121 #undef NEXT
122 }
123
124 Material *
MtCreate(int a1,...)125 MtCreate(int a1, ... )
126 {
127 va_list alist;
128 Material *mat;
129
130 va_start(alist,a1);
131 mat = _MtSet(NULL, a1, &alist);
132 va_end(alist);
133 return mat;
134 }
135
136 Material *
MtSet(Material * mat,int attr,...)137 MtSet(Material *mat, int attr, ... )
138 {
139 va_list alist;
140
141 va_start(alist,attr);
142 mat = _MtSet(mat,attr,&alist);
143 va_end(alist);
144 return mat;
145 }
146
147 int
MtGet(Material * mat,int attr,void * value)148 MtGet(Material *mat, int attr, void * value)
149 {
150 if (mat == NULL)
151 return -1;
152
153 switch (attr) {
154 case MT_AMBIENT:
155 *(Color *)value = mat->ambient;
156 break;
157 case MT_DIFFUSE:
158 {
159 ((Color *)value)->r = mat->diffuse.r;
160 ((Color *)value)->g = mat->diffuse.g;
161 ((Color *)value)->b = mat->diffuse.b;
162 break;
163 }
164 case MT_SPECULAR:
165 *(Color *)value = mat->specular;
166 break;
167 case MT_EMISSION:
168 *(Color *) value = mat->emission;
169 break;
170 case MT_ALPHA:
171 *(double *) value = mat->diffuse.a;
172 break;
173 case MT_Ka:
174 *(double *) value = mat->ka;
175 break;
176 case MT_Kd:
177 *(double *) value = mat->kd;
178 break;
179 case MT_Ks:
180 *(double *) value = mat->ks;
181 break;
182 case MT_SHININESS:
183 *(double *) value = mat->shininess;
184 break;
185 case MT_EDGECOLOR:
186 *(Color *)value = mat->edgecolor;
187 break;
188 case MT_NORMALCOLOR:
189 *(Color *)value = mat->normalcolor;
190 break;
191 case MT_OVERRIDE:
192 case MT_NOOVERRIDE:
193 *(int *) value = mat->override;
194 break;
195 case MT_VALID:
196 case MT_INVALID:
197 *(int *) value = mat->valid;
198 break;
199 default:
200 OOGLError (0, "MtGet: undefined option: %d\n", attr);
201 return -1;
202 break;
203 }
204
205 return 1;
206 }
207
208 void
MtDelete(Material * mat)209 MtDelete(Material *mat)
210 {
211 if (mat && RefDecr((Ref *)mat) <= 0) {
212 if (mat->magic != MATMAGIC) {
213 OOGLError(1, "MtDelete(%x) of non-Material: magic %x != %x",
214 mat, mat->magic, MATMAGIC);
215 return;
216 }
217 mat->magic = MATMAGIC ^ 0x80000000;
218 OOGLFree(mat);
219 }
220 }
221
222 Material *
MtDefault(Material * mat)223 MtDefault( Material *mat )
224 {
225 memset(mat, 0, sizeof(Material));
226 RefInit((Ref *)mat, MATMAGIC);
227 mat->valid = mat->override = 0;
228 mat->diffuse.a = 1.0;
229 mat->Private = 0;
230 mat->changed = 1;
231 return mat;
232 }
233
234
235 Material *
MtCopy(Material * src,Material * dst)236 MtCopy( Material *src, Material *dst )
237 {
238 if (!src) return NULL;
239 if (dst == NULL)
240 dst = OOGLNewE(Material, "MtCopy: Material");
241 *dst = *src;
242 dst->Private = 0;
243 RefInit((Ref *)dst, MATMAGIC);
244 dst->changed = 1;
245 return dst;
246 }
247
248 #ifndef max
249 # define max(a,b) ((a) > (b) ? (a) : (b))
250 #endif
251
252 #if 0
253 static void
254 norm( color, coeff )
255 Color *color;
256 float *coeff;
257 {
258 *coeff = max(color->r, color->g);
259 *coeff = max(color->b, *coeff);
260
261 if ( *coeff != 0.0 ) {
262 color->r /= *coeff;
263 color->g /= *coeff;
264 color->b /= *coeff;
265 }
266 }
267 #endif
268
269 /*
270 * MtMerge(src, dst, mergeflags)
271 * Merge Material values: src into dst, controlled by flag.
272 * If "inplace" is true, changes are made in dst itself; otherwise,
273 * the dst material is copied if any changes need be made to it.
274 * The returned Material's reference count is incremented as appropriate;
275 * thus the caller should MtDelete() the returned Material when done.
276 */
277 Material *
MtMerge(Material * src,Material * dst,int mergeflags)278 MtMerge(Material *src, Material *dst, int mergeflags)
279 {
280 int mask;
281
282 if (dst == NULL)
283 return MtCopy(src, NULL);
284
285 /* Fields to merge in */
286 mask = src ?
287 (mergeflags & APF_OVEROVERRIDE) ?
288 src->valid : src->valid & ~(dst->override &~ src->override)
289 : 0;
290
291 if (mergeflags & APF_INPLACE)
292 RefIncr((Ref *)dst);
293 else
294 dst = MtCopy(dst, NULL);
295
296 if (mask == 0) /* No changes to dst */
297 return dst;
298
299 dst->changed |= src->changed;
300 dst->valid = (src->valid & mask) | (dst->valid & ~mask);
301 dst->override = (src->override & mask) | (dst->override & ~mask);
302 if (mask & MTF_EMISSION) dst->emission = src->emission;
303 if (mask & MTF_AMBIENT) dst->ambient = src->ambient;
304 if (mask & MTF_DIFFUSE) {
305 dst->diffuse.r = src->diffuse.r;
306 dst->diffuse.g = src->diffuse.g;
307 dst->diffuse.b = src->diffuse.b;
308 }
309 if (mask & MTF_SPECULAR) dst->specular = src->specular;
310 if (mask & MTF_Ka) dst->ka = src->ka;
311 if (mask & MTF_Kd) dst->kd = src->kd;
312 if (mask & MTF_Ks) dst->ks = src->ks;
313 if (mask & MTF_ALPHA) dst->diffuse.a = src->diffuse.a;
314 if (mask & MTF_SHININESS) dst->shininess = src->shininess;
315 if (mask & MTF_EDGECOLOR) dst->edgecolor = src->edgecolor;
316 if (mask & MTF_NORMALCOLOR) dst->normalcolor = src->normalcolor;
317 return dst;
318 }
319
MtSave(Material * mat,char * name)320 int MtSave(Material *mat, char *name)
321 {
322 FILE *f;
323 int ok;
324
325 f = fopen(name,"w");
326 if (!f) {
327 perror(name);
328 return -1;
329 }
330 ok = MtFSave(mat, f, NULL);
331 fclose(f);
332 return ok;
333 }
334
MtLoad(Material * mat,char * name)335 Material *MtLoad(Material *mat, char *name)
336 {
337 IOBFILE *f = iobfopen(name,"rb");
338
339 if (f == NULL) {
340 OOGLError(0, "MtLoad: can't open %s: %s", name, sperror());
341 return NULL;
342 }
343
344 mat = MtFLoad(mat, f, name);
345 iobfclose(f);
346 return mat;
347 }
348
349 /*
350 * Load Material from file.
351 * Syntax:
352 * < "filename_containing_material" [or]
353 * { keyword value keyword value ... }
354 *
355 * Each keyword may be prefixed by "*", indicating that its value should
356 * override corresponding settings in child objects. [By default,
357 * children's appearance values supercede those of their parents.]
358 *
359 * Note: don't overwrite ka, kd, ks if they're already set when we read in
360 * the corresponding color.
361 */
362 static char *mt_kw[] = {
363 "shininess", "ka", "kd", "ks", "alpha",
364 "backdiffuse", "emission", "ambient", "diffuse", "specular",
365 "edgecolor", "normalcolor", "material"
366 };
367 static unsigned short mt_flags[] = {
368 MTF_SHININESS, MTF_Ka, MTF_Kd, MTF_Ks, MTF_ALPHA,
369 MTF_EMISSION, MTF_EMISSION, MTF_AMBIENT, MTF_DIFFUSE, MTF_SPECULAR,
370 MTF_EDGECOLOR, MTF_NORMALCOLOR, 0
371 };
372 static char mt_args[] = { 1,1,1,1,1, 3,3,3,3,3,3,3, 0 };
373
374 /* fname used for error msgs, may be NULL */
375 Material *
MtFLoad(Material * mat,IOBFILE * f,char * fname)376 MtFLoad(Material *mat, IOBFILE *f, char *fname)
377 {
378 char *w;
379 int i;
380 float v[3];
381 int brack = 0;
382 int over, not;
383 int got;
384 Material m;
385
386 MtDefault(&m);
387
388 over = not = 0;
389 for (;;) {
390 switch(iobfnextc(f, 0)) {
391 case '<':
392 iobfgetc(f);
393 if (MtLoad(&m, iobfdelimtok("{}()", f, 0)) == NULL) return NULL;
394 if (!brack) goto done;
395 break;
396 case '{': brack++; iobfgetc(f); break;
397 case '}': if (brack) { iobfgetc(f); } goto done;
398 case '*': over = 1; iobfgetc(f); break; /* 'override' prefix */
399 case '!': not = 1; iobfgetc(f); break;
400 default:
401 w = iobfdelimtok("{}()", f, 0);
402 if (w == NULL)
403 return MtCopy(&m, mat);
404 /* break; */ /* done */
405
406 for (i = sizeof(mt_kw)/sizeof(mt_kw[0]); --i >= 0; )
407 if (!strcmp(w, mt_kw[i]))
408 break;
409
410 if ( i < 0) {
411 OOGLError(1, "MtFLoad: %s: unknown material keyword %s",fname,w);
412 return NULL;
413 } else if ( !not && (got=iobfgetnf(f, mt_args[i], v, 0)) != mt_args[i] ) {
414 OOGLError(1, "MtFLoad: %s: \"%s\" expects %d values, got %d",
415 fname, w, mt_args[i], got);
416 return NULL;
417 }
418
419 if (not) {
420 if (!over) m.valid &= ~mt_flags[i];
421 m.override &= ~mt_flags[i];
422 } else {
423 switch(i) {
424 case 0: m.shininess = v[0]; break;
425 case 1: m.ka = v[0]; break;
426 case 2: m.kd = v[0]; break;
427 case 3: m.ks = v[0]; break;
428 case 4: m.diffuse.a = v[0]; break;
429 case 5: case 6: memcpy(&m.emission, v, sizeof(Color)); break;
430 case 7: memcpy(&m.ambient, v, sizeof(Color)); break;
431 case 8: memcpy(&m.diffuse, v, sizeof(Color)); break;
432 case 9: memcpy(&m.specular, v, sizeof(Color)); break;
433 case 10: memcpy(&m.edgecolor, v, sizeof(Color)); break;
434 case 11: memcpy(&m.normalcolor, v, sizeof(Color)); break;
435 }
436 m.valid |= mt_flags[i];
437 if (over) m.override |= mt_flags[i];
438 }
439 over = not = 0;
440 }
441 }
442 done:
443 return MtCopy(&m, mat);
444 }
445
MtFSave(Material * mat,FILE * f,Pool * p)446 int MtFSave(Material *mat, FILE *f, Pool *p)
447 {
448 int i;
449 float v;
450 Color *c;
451
452 for (i = 0; i < (int)(sizeof(mt_kw)/sizeof(mt_kw[0])); i++) {
453 if (Apsavepfx(mat->valid, mat->override, mt_flags[i], mt_kw[i], f, p)) {
454 switch(mt_flags[i]) {
455 case MTF_Ka: v = mat->ka; goto pfloat;
456 case MTF_Kd: v = mat->kd; goto pfloat;
457 case MTF_Ks: v = mat->ks; goto pfloat;
458 case MTF_SHININESS: v = mat->shininess; goto pfloat;
459 case MTF_ALPHA: v = mat->diffuse.a; goto pfloat;
460 pfloat:
461 fprintf(f, "%f\n", v);
462 break;
463
464 case MTF_DIFFUSE: c = (Color *)(void *)&mat->diffuse; goto pcolor;
465 case MTF_AMBIENT: c = &mat->ambient; goto pcolor;
466 case MTF_EMISSION: c = &mat->emission; goto pcolor;
467 case MTF_SPECULAR: c = &mat->specular; goto pcolor;
468 case MTF_EDGECOLOR: c = &mat->edgecolor; goto pcolor;
469 case MTF_NORMALCOLOR: c = &mat->normalcolor; goto pcolor;
470 pcolor:
471 fprintf(f, "%f %f %f\n", c->r, c->g, c->b);
472 break;
473 }
474 }
475 }
476 return ferror(f);
477 }
478
479 /*
480 * Local Variables: ***
481 * mode: c ***
482 * c-basic-offset: 2 ***
483 * End: ***
484 */
485