1 /* Copyright (C) 1992-1998 The Geometry Center
2 * Copyright (C) 1998-2000 Stuart Levy, Tamara Munzner, Mark Phillips
3 *
4 * This file is part of Geomview.
5 *
6 * Geomview is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published
8 * by the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * Geomview is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with Geomview; see the file COPYING. If not, write
18 * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
19 * USA, or visit http://www.gnu.org.
20 */
21
22 #if HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25
26 #if 0
27 static char copyright[] = "Copyright (C) 1992-1998 The Geometry Center\n\
28 Copyright (C) 1998-2000 Stuart Levy, Tamara Munzner, Mark Phillips";
29 #endif
30
31
32 /* Authors: Charlie Gunn, Stuart Levy, Tamara Munzner, Mark Phillips */
33
34 #include "appearance.h"
35 #include "handleP.h"
36
37 HandleOps AppearanceOps = {
38 "ap",
39 (int ((*)(Pool *p, Handle **hp, Ref **rp)))ApStreamIn,
40 (int ((*)(Pool *p, Handle *h, Ref *r)))ApStreamOut,
41 (void ((*)(Ref *rp)))ApDelete,
42 NULL,
43 NULL,
44 };
45
46 static struct {
47 char *word;
48 int amask;
49 enum {
50 _flag = 0,
51 _appearance,
52 _shading,
53 _normscale,
54 _linewidth,
55 _material,
56 _backmaterial,
57 _patchdice,
58 _light,
59 _texture,
60 _translucency,
61 _ap_alpha_blending = AP_TRANSLUCENCY + APF_ALPHA_BLENDING,
62 _ap_screen_door = AP_TRANSLUCENCY + APF_SCREEN_DOOR,
63 _ap_naive_blending = AP_TRANSLUCENCY + APF_NAIVE_BLENDING,
64 _ap_smooth = AP_SHADING + APF_SMOOTH,
65 _ap_flat = AP_SHADING + APF_FLAT,
66 _ap_constant = AP_SHADING + APF_CONSTANT,
67 _ap_csmooth = AP_SHADING + APF_CSMOOTH,
68 _ap_vcflat = AP_SHADING + APF_VCFLAT,
69 } aval;
70 } ap_kw[] = {
71 { "appearance", 0, _appearance },
72 { "face", APF_FACEDRAW, _flag },
73 { "edge", APF_EDGEDRAW, _flag },
74 { "vect", APF_VECTDRAW, _flag },
75 { "transparent", APF_TRANSP, _translucency },
76 { "screendoor", APF_TRANSP, _ap_screen_door },
77 { "blending", APF_TRANSP, _ap_alpha_blending },
78 { "naive", APF_TRANSP, _ap_naive_blending },
79 { "evert", APF_EVERT, _flag },
80 { "keepcolor", APF_KEEPCOLOR, _flag },
81 { "texturing", APF_TEXTURE, _flag },
82 { "backcull", APF_BACKCULL, _flag },
83 { "shadelines", APF_SHADELINES, _flag },
84 { "concave", APF_CONCAVE, _flag },
85 { "shading", APF_SHADING, _shading },
86 { "smooth", APF_SHADING, _ap_smooth },
87 { "flat", APF_SHADING, _ap_flat },
88 { "constant", APF_SHADING, _ap_constant },
89 { "csmooth", APF_SHADING, _ap_csmooth },
90 { "vcflat", APF_VCFLAT, _ap_vcflat },
91 { "mipmap", APF_TXMIPMAP, _flag },
92 { "mipinterp", APF_TXMIPINTERP, _flag },
93 { "linear", APF_TXLINEAR, _flag },
94 { "normal", APF_NORMALDRAW, _flag },
95 { "normscale", APF_NORMSCALE, _normscale },
96 { "linewidth", APF_LINEWIDTH, _linewidth },
97 { "material", 0, _material },
98 { "backmaterial", 0, _backmaterial },
99 { "patchdice", APF_DICE, _patchdice },
100 { "light", 0, _light },
101 { "lighting", 0, _light },
102 { "texture", 0, _texture },
103 };
104
ApStreamIn(Pool * p,Handle ** hp,Appearance ** app)105 int ApStreamIn(Pool *p, Handle **hp, Appearance **app)
106 {
107 Handle *h = NULL;
108 Handle *hname = NULL;
109 Appearance *ap = NULL;
110 IOBFILE *inf;
111 char *fname;
112 char *w, *raww;
113 int c, i;
114 int brack = 0;
115 bool over, not, more, empty, braces;
116 int value;
117 int mask, flagmask;
118 bool mine = true; /* Questionable -- we'll report all errors */
119
120 if (p == NULL || (inf = PoolInputFile(p)) == NULL) {
121 return 0;
122 }
123 fname = PoolName(p);
124
125 over = not = false;
126 value = ~0;
127 more = false;
128 empty = true;
129 braces = false;
130 do {
131 switch(c = iobfnextc(inf, 0)) {
132 case '{': brack++; braces = true; iobfgetc(inf); break;
133 case '}': if (brack--) iobfgetc(inf); break;
134 case '+': value = ~0; iobfgetc(inf); break;
135 case '-': value = 0; iobfgetc(inf); break;
136 case '!': not = 1; iobfgetc(inf); break;
137 case '*': over = 1; iobfgetc(inf); break;
138 case '<':
139 case ':':
140 case '@':
141 iobfgetc(inf);
142 w = iobfdelimtok("{}()", inf, 0);
143 if (c == '<' &&
144 (h = HandleByName(w, &ImageOps)) == NULL && w[0] != '/') {
145 w = findfile(PoolName(p), raww = w);
146 if (w == NULL) {
147 OOGLSyntax(inf,
148 "Reading image from \"%s\": "
149 "can't find file \"%s\"",
150 PoolName(p), raww);
151 return false;
152 }
153 } else if (h) {
154 /* HandleByName() increases the ref. count s.t. the
155 * caller of HandleByName() owns the returned handle.
156 */
157 HandleDelete(h);
158 }
159 h = HandleReferringTo(c, w, &AppearanceOps, NULL);
160 if (h) {
161 ap = (Appearance *)HandleObject(h);
162 /* Increment the ref. count. This way we can call
163 * HandleDelete() and ImgDelete() independently.
164 */
165 REFGET(Appearance, ap);
166 }
167 break;
168
169 default:
170 more = 0;
171 w = iobfdelimtok("{}()", inf, 0);
172 if (w == NULL) {
173 break;
174 }
175 if (strcmp(w, "define") == 0) {
176 hname = HandleCreateGlobal(iobftoken(inf, 0), &AppearanceOps);
177 break;
178 }
179 for (i = sizeof(ap_kw)/sizeof(ap_kw[0]); --i >= 0; ) {
180 if (!strcmp(ap_kw[i].word, w)) {
181 break;
182 }
183 }
184
185 if (i < 0) {
186 if (mine) {
187 OOGLError(1,
188 "ApStreamIn: file %s: unknown appearance keyword %s",
189 fname, w);
190 ApDelete(ap);
191 return false;
192 }
193 }
194 if (ap == NULL) {
195 ap = ApCreate(AP_END);
196 }
197
198 empty = false;
199 mask = flagmask = ap_kw[i].amask;
200 if (not) {
201 switch(ap_kw[i].aval) {
202 case _material: MtDelete(ap->mat); ap->mat = NULL; break;
203 case _backmaterial: MtDelete(ap->backmat); ap->mat = NULL; break;
204 case _light: LmDelete(ap->lighting); ap->lighting = NULL; break;
205 case _texture: TxDelete(ap->tex); ap->tex = NULL; break;
206 default: break;
207 }
208 ap->flag &= ~mask;
209 if (!over) ap->valid &= ~mask;
210 ap->override &= ~mask;
211 } else {
212 switch(ap_kw[i].aval) {
213 case _flag:
214 break;
215 case _appearance:
216 mine = more = 1;
217 break;
218 case _translucency:
219 ap->translucency = APF_ALPHA_BLENDING;
220 iobfgetni(inf, 1, (int *)&ap->translucency, 0);
221 break;
222 case _ap_alpha_blending:
223 case _ap_screen_door:
224 case _ap_naive_blending:
225 ap->translucency = ap_kw[i].aval - AP_TRANSLUCENCY;
226 break;
227 case _shading:
228 iobfgetni(inf, 1, (int *)&ap->shading, 0);
229 break;
230 case _ap_smooth:
231 case _ap_flat:
232 case _ap_constant:
233 case _ap_csmooth:
234 case _ap_vcflat:
235 ap->shading = ap_kw[i].aval - AP_SHADING;
236 break;
237 case _normscale:
238 if (iobfgetnf(inf, 1, &ap->nscale, 0) <= 0) {
239 OOGLError(1,"ApFLoad: %s: \"normscale\": value expected", fname);
240 }
241 break;
242 case _linewidth:
243 if (iobfgetni(inf, 1, &ap->linewidth, 0) <= 0) {
244 OOGLSyntax(inf, "%s \"linewidth\": value expected", fname);
245 }
246 break;
247 case _material:
248 if ((ap->mat = MtFLoad(ap->mat, inf, fname)) == NULL) {
249 OOGLSyntax(inf,"Can't read material in %s", fname);
250 }
251 break;
252 case _backmaterial:
253 if ((ap->backmat = MtFLoad(ap->backmat, inf, fname)) == NULL) {
254 OOGLError(1,"Can't read backmaterial, file %s", fname);
255 }
256 break;
257 case _light:
258 ap->lighting = LmFLoad(ap->lighting, inf, fname);
259 if (ap->lighting == NULL) {
260 OOGLError(1,"Can't read lighting, file %s", fname);
261 }
262 break;
263 case _texture:
264 if (!TxStreamIn(p, NULL, &ap->tex)) {
265 OOGLError(1, "%s: Can't read texture", fname);
266 }
267 break;
268 case _patchdice:
269 if (iobfgetni(inf, 2, ap->dice, 0) < 2) {
270 OOGLSyntax(inf,
271 "%s \"patchdice\": "
272 "expected integer u- and v- dicing values", fname);
273 }
274 break;
275 default:
276 OOGLSyntax(inf,
277 "%s unknown appearance keyword", fname);
278 }
279 if (value) {
280 ap->flag |= flagmask;
281 } else {
282 ap->flag &= ~flagmask;
283 }
284 ap->valid |= mask;
285 if (over) {
286 ap->override |= mask;
287 }
288 }
289 /* Reset for next keyword */
290 over = not = 0; value = ~0;
291
292 }
293 } while(brack > 0 || more);
294
295 if (hname != NULL) {
296 if (ap) {
297 HandleSetObject(hname, (Ref *)ap);
298 }
299 if (h) {
300 /* HandleReferringTo() has passed the ownership to use, so
301 * delete h because we do not need it anymore.
302 */
303 HandleDelete(h);
304 }
305 h = hname;
306 }
307
308 /* Pass the ownership of h and ap to the caller if requested */
309
310 if (hp != NULL) {
311 /* pass on ownership of the handle h to the caller of this function */
312 if (*hp != NULL) {
313 if (*hp != h) {
314 HandlePDelete(hp);
315 } else {
316 HandleDelete(*hp);
317 }
318 }
319 *hp = h;
320 } else if (h) {
321 /* Otherwise delete h because we are its owner. Note that
322 * HandleReferringTo() has passed the ownership of h to us;
323 * explicitly defined handles (hdefine and define constructs)
324 * will not be deleted by this call.
325 */
326 HandleDelete(h);
327 }
328
329 /* same logic as for hp */
330 if (app != NULL) {
331 if (*app != NULL) {
332 ApDelete(*app);
333 }
334 *app = ap;
335 } else if(ap) {
336 ApDelete(ap);
337 }
338
339 return (h != NULL || ap != NULL || (empty && braces));
340 }
341
342 int
Apsavepfx(int valid,int override,int mask,char * keyword,FILE * f,Pool * p)343 Apsavepfx(int valid, int override, int mask, char *keyword, FILE *f, Pool *p)
344 {
345 if ((valid & mask) == 0) {
346 return 0;
347 }
348 PoolFPrint(p, f, "");
349 if (override & mask) {
350 fputc('*', f);
351 }
352 if (keyword && *keyword) {
353 fprintf(f, "%s ", keyword);
354 }
355 return 1;
356 }
357
ApStreamOut(Pool * p,Handle * h,Appearance * ap)358 int ApStreamOut(Pool *p, Handle *h, Appearance *ap)
359 {
360 FILE *f = PoolOutputFile(p);
361 int valid;
362 int mask;
363 int i;
364
365 if (f == NULL ||
366 (ap == NULL &&
367 (h == NULL || (ap = (Appearance *)HandleObject(h)) == NULL))) {
368 return false;
369 }
370
371 valid = ap->valid;
372 fprintf(f, "appearance {\n");
373 PoolIncLevel(p, 1);
374 if (PoolStreamOutHandle(p, h, ap != NULL)) {
375 for (i = 0; i < (int)(sizeof(ap_kw)/sizeof(ap_kw[0])); i++) {
376 mask = ap_kw[i].amask;
377 if ((valid & mask) == 0) {
378 continue;
379 }
380 Apsavepfx(valid, ap->override, mask, "", f, p);
381 if (ap_kw[i].aval == 0 || ap_kw[i].aval == _translucency) {
382 if ((mask & ap->flag) == 0) {
383 fputc('-', f);
384 }
385 fputs(ap_kw[i].word, f);
386 }
387 valid &= ~mask;
388 switch (mask) {
389 case APF_TRANSP:
390 if ((mask & ap->flag) != 0) {
391 switch (ap->translucency) {
392 case APF_SCREEN_DOOR:
393 fputs(" screendoor", f);
394 break;
395 case APF_NAIVE_BLENDING:
396 fputs(" naive", f);
397 break;
398 case APF_ALPHA_BLENDING:
399 fputs(" blending", f);
400 break;
401 default:
402 fprintf(f, "%d", ap->translucency); break;
403 break;
404 }
405 }
406 break;
407 case APF_SHADING:
408 fputs("shading ", f);
409 switch(ap->shading) {
410 case APF_SMOOTH: fputs("smooth", f); break;
411 case APF_FLAT: fputs("flat", f); break;
412 case APF_CONSTANT: fputs("constant", f); break;
413 case APF_CSMOOTH: fputs("csmooth", f); break;
414 case APF_VCFLAT: fputs("vcflat", f); break;
415 default: fprintf(f, "%d", ap->shading); break;
416 }
417 break;
418 case APF_NORMSCALE:
419 fprintf(f, "normscale %.8g", ap->nscale);
420 break;
421 case APF_LINEWIDTH:
422 fprintf(f, "linewidth %d ", ap->linewidth);
423 break;
424 case APF_DICE:
425 fprintf(f, "patchdice %d %d", ap->dice[0], ap->dice[1]);
426 break;
427 }
428 fputc('\n', f);
429 }
430
431 if (ap->mat) {
432 PoolFPrint(p, f, "material {\n");
433 PoolIncLevel(p, 1);
434 MtFSave(ap->mat, f, p);
435 PoolIncLevel(p, -1);
436 PoolFPrint(p, f, "}\n");
437 }
438 if (ap->backmat) {
439 PoolFPrint(p, f, "backmaterial {\n");
440 PoolIncLevel(p, 1);
441 MtFSave(ap->backmat, f, p);
442 PoolIncLevel(p, -1);
443 PoolFPrint(p, f, "}\n");
444 }
445 if (ap->lighting) {
446 PoolFPrint(p, f, "lighting {\n");
447 PoolIncLevel(p, 1);
448 LmFSave(ap->lighting, f, p->poolname, p);
449 PoolIncLevel(p, -1);
450 PoolFPrint(p, f, "}\n");
451 }
452 if (ap->tex) {
453 TxStreamOut(p, NULL, ap->tex);
454 }
455 }
456 PoolIncLevel(p, -1);
457 PoolFPrint(p, f, "}\n");
458
459 return !ferror(f);
460 }
461
462 Appearance *
ApFLoad(IOBFILE * inf,char * fname)463 ApFLoad(IOBFILE *inf, char *fname)
464 {
465 Pool *p;
466 Appearance *ap = NULL;
467 p = PoolStreamTemp(fname, inf, NULL, 0, &AppearanceOps);
468 ApStreamIn(p, NULL, &ap);
469 PoolDelete(p);
470 return ap;
471 }
472
473 Appearance *
ApFSave(Appearance * ap,FILE * outf,char * fname)474 ApFSave(Appearance *ap, FILE *outf, char *fname)
475 {
476 Pool *p;
477 int ok;
478
479 p = PoolStreamTemp(fname, NULL, outf, 1, NULL);
480 PoolSetOType(p, PO_DATA);
481 PoolIncLevel(p, 1);
482 ok = ApStreamOut(p, NULL, ap);
483 PoolDelete(p);
484 return ok ? ap : NULL;
485 }
486
487 /*
488 * Local Variables: ***
489 * mode: c ***
490 * c-basic-offset: 2 ***
491 * End: ***
492 */
493