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