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 /* Authors: Charlie Gunn, Stuart Levy, Tamara Munzner, Mark Phillips */
32 
33 #include "appearance.h"
34 #include "transobj.h"
35 #include "handleP.h"
36 #include <string.h>
37 #include <sys/stat.h>
38 
39 #define MAXSHININESS 1024.0
40 
41 extern LmLighting * _LmSet(LmLighting *, int attr1, va_list *);
42 extern Material * _MtSet(Material *, int attr1, va_list *);
43 
44 Appearance *
_ApSet(Appearance * ap,int attr1,va_list * alist)45 _ApSet(Appearance *ap, int attr1, va_list *alist)
46 {
47   int mask;
48   int attr;
49 
50 #define NEXT(type) va_arg(*alist, type)
51 
52   if (ap == NULL) {
53     /*
54      * New Appearance created here.
55      */
56     ap = OOGLNewE(Appearance, "ApCreate Appearance");
57     ApDefault(ap);
58   }
59 
60   for ( attr = attr1; attr != AP_END; attr = NEXT(int)) {
61     switch (attr) { /* parse argument list */
62     case AP_DO:
63       mask = NEXT(int);
64       ap->flag |= mask;
65       ap->valid |= mask;
66       break;
67     case AP_DONT:
68       mask = NEXT(int);
69       ap->flag &= ~mask;
70       ap->valid |= mask;
71       break;
72     case AP_INVALID:
73       ap->valid &= ~NEXT(int);
74       break;
75     case AP_OVERRIDE:
76       ap->override |= NEXT(int);
77       break;
78     case AP_NOOVERRIDE:
79       ap->override &= ~NEXT(int);
80       break;
81     case AP_MAT:
82       ap->mat = NEXT(Material*);
83       break;
84     case AP_MtSet:
85       ap->mat = _MtSet(ap->mat, va_arg(*alist, int), alist);
86       break;
87     case AP_LGT:
88       ap->lighting = NEXT(LmLighting*);
89       break;
90     case AP_LmSet:
91       if (!ap->lighting) ap->lighting = LmCreate(LM_END);
92       ap->lighting = _LmSet(ap->lighting, va_arg(*alist, int), alist);
93       break;
94     case AP_NORMSCALE:
95       ap->nscale = NEXT(double);
96       ap->valid |= APF_NORMSCALE;
97       break;
98     case AP_LINEWIDTH:
99       ap->linewidth = NEXT(int);
100       ap->valid |= APF_LINEWIDTH;
101       break;
102     case AP_SHADING:
103       /* should be APF_{CONSTANT,FLAT,SMOOTH} */
104       ap->shading = NEXT(int);
105       ap->valid |= APF_SHADING;
106       break;
107     case AP_TRANSLUCENCY:
108       /* should be APF_ALPHA_BLENDING or APF_SCREEN_DOOR */
109       ap->translucency = NEXT(int);
110       ap->valid |= APF_TRANSP;
111       break;
112     case AP_DICE:
113       ap->dice[0] = NEXT(int);
114       ap->dice[1] = NEXT(int);
115       ap->valid |= APF_DICE;
116       break;
117     default:
118       OOGLError (0, "_ApSet: undefined option: %d\n", attr);
119       return NULL;
120       break;
121     }
122   }
123   return ap;
124 
125 #undef NEXT
126 }
127 
128 Appearance *
ApCreate(int a1,...)129 ApCreate(int a1, ...)
130 {
131   va_list alist;
132   Appearance *ap;
133 
134   va_start(alist,a1);
135   ap = _ApSet(NULL, a1, &alist);
136   va_end(alist);
137   return ap;
138 }
139 
140 Appearance *
ApSet(Appearance * ap,int a1,...)141 ApSet(Appearance *ap, int a1, ... )
142 {
143   va_list alist;
144   va_start(alist,a1);
145   ap = _ApSet(ap, a1, &alist);
146   va_end(alist);
147   return ap;
148 }
149 
150 int
ApGet(Appearance * ap,int attr,void * value)151 ApGet(Appearance *ap, int attr, void *value)
152 {
153   if (!ap) return -1;
154 
155   switch (attr) {
156   case AP_DO:
157   case AP_DONT:         *(int *) value =  ap->flag; break;
158   case AP_OVERRIDE:
159   case AP_NOOVERRIDE:   *(int *) value = ap->override; break;
160   case AP_VALID:
161   case AP_INVALID:      *(int *) value = ap->valid; break;
162   case AP_MAT:          *(Material **) value = ap->mat; break;
163   case AP_LGT:          *(LmLighting **) value = ap->lighting; break;
164   case AP_NORMSCALE:    *(double *) value = ap->nscale; break;
165   case AP_LINEWIDTH:    *(int *) value = ap->linewidth; break;
166   case AP_SHADING:      *(int *)value = ap->shading; break;
167   case AP_TRANSLUCENCY: *(int *)value = ap->translucency; break;
168   case AP_DICE: ((int *)value)[0] = ap->dice[0];
169     ((int *)value)[1] = ap->dice[1];
170     break;
171   default:
172     OOGLError (0, "ApGet: undefined option: %d\n", attr);
173     return -1;
174     break;
175   }
176   return attr;
177 }
178 
179 void
ApDelete(Appearance * ap)180 ApDelete(Appearance *ap)
181 {
182   if (ap == NULL || RefDecr((Ref *)ap) > 0)
183     return;
184   if (ap->magic != APMAGIC) {
185     OOGLError(1, "ApDelete(%x) of non-Appearance: magic %x != %x",
186               ap, ap->magic, APMAGIC);
187     return;
188   }
189   if (ap->mat) MtDelete(ap->mat);
190   if (ap->lighting) LmDelete(ap->lighting);
191   if (ap->tex) TxDelete(ap->tex);
192 
193   OOGLFree(ap);
194 }
195 
196 /*
197  * Copies just the Appearance part, not its Material and LmLighting children.
198  * Pointers to the latter are retained BUT their reference counts are NOT
199  * incremented.  The caller MUST either RefIncr() or reassign mat and lighting.
200  */
201 Appearance *
ApCopyShallow(const Appearance * ap,Appearance * into)202 ApCopyShallow(const Appearance *ap, Appearance *into )
203 {
204   if (ap == NULL)
205     return NULL;
206   if (into == NULL) {
207     into = OOGLNewE(Appearance, "ApCopy: Appearance");
208     *into = *ap;
209     into->mat = NULL;
210     into->backmat = NULL;
211     into->lighting = NULL;
212     into->tex = NULL;
213     RefInit((Ref *)into, APMAGIC);
214   } else {
215     into->flag = ap->flag;
216     into->valid = ap->valid;
217     into->override = ap->override;
218     into->nscale = ap->nscale;
219     into->linewidth = ap->linewidth;
220     into->shading = ap->shading;
221     into->translucency = ap->translucency;
222     into->dice[0] = ap->dice[0];
223     into->dice[1] = ap->dice[1];
224   }
225   return into;
226 }
227 
228 Appearance *
ApCopy(const Appearance * ap,Appearance * into)229 ApCopy(const Appearance *ap, Appearance *into )
230 {
231   if (ap == NULL) return into;
232   into = ApCopyShallow( ap, into );
233   if (ap->mat) into->mat = MtCopy(ap->mat, into->mat);
234   if (ap->backmat) into->backmat = MtCopy(ap->backmat, into->backmat);
235   if (ap->lighting) into->lighting = LmCopy(ap->lighting, into->lighting);
236   if (ap->tex) into->tex = TxCopy(ap->tex, into->tex);
237   return into;
238 }
239 
240 Appearance *
ApCopyShared(const Appearance * ap,Appearance * into)241 ApCopyShared(const Appearance *ap, Appearance *into )
242 {
243   if (ap == NULL) return into;
244   into = ApCopyShallow( ap, into );
245   if (ap->mat) {
246     if (into->mat) MtCopy(ap->mat, into->mat);
247     else RefIncr((Ref *)(into->mat = ap->mat));
248   }
249   if (ap->backmat) {
250     if (into->backmat) MtCopy(ap->backmat, into->backmat);
251     else RefIncr((Ref *)(into->backmat = ap->backmat));
252   }
253   if (ap->lighting) {
254     if (into->lighting) LmCopy(ap->lighting, into->lighting);
255     else RefIncr((Ref *)(into->lighting = ap->lighting));
256   }
257   if (ap->tex) {
258     if (into->tex) TxCopy(ap->tex, into->tex);
259     else RefIncr((Ref *)(into->tex = ap->tex));
260   }
261   return into;
262 }
263 
264 /*
265  * Merges appearance properties of src into dst.
266  * If "inplace" is true, data are modified in place.
267  * Otherwise if any modifications are needed to dst, a copy is made & returned.
268  * If no modifications are necessary, the returned Appearance's reference
269  * count is still incremented.
270  * Thus, in all cases, the caller should ApDelete() the returned value
271  * when finished with it.
272  */
273 Appearance *
ApMerge(const Appearance * src,Appearance * dst,int mergeflags)274 ApMerge(const Appearance *src, Appearance *dst, int mergeflags )
275 {
276   int mask;
277   Material *mt, *bmt;
278   LmLighting *lts;
279   Texture *tex;
280 
281   if (dst == NULL)
282     return ApCopy(src, NULL);
283 
284   if (src == NULL) {
285     RefIncr((Ref *)dst);
286     return dst;
287   }
288   /* Mask of fields to copy to dst */
289   mask = (mergeflags & APF_OVEROVERRIDE) ? src->valid :
290     src->valid &~ ( dst->override &~ src->override);
291 
292   mt = MtMerge(src->mat, dst->mat, mergeflags);
293   bmt = MtMerge(src->backmat, dst->backmat, mergeflags);
294   lts = LmMerge(src->lighting, dst->lighting, mergeflags);
295   tex = TxMerge(src->tex, dst->tex, mergeflags);
296   if ((mergeflags & APF_INPLACE)
297       || (mask == 0 && mt == dst->mat &&
298           lts == dst->lighting && bmt == dst->backmat
299           && tex == dst->tex)) {
300     /*
301      * No changes, or we're asked to merge in place.  Bump ref count.
302      */
303     RefIncr((Ref *)dst);
304   } else {
305     /*
306      * Another special case: Copy appearance, don't copy the items already
307      * copied by {Mt,Lm}Merge.  We're about to overwrite these values, so
308      * toss the old ones.  Pretty kludgy, but what can we do?
309      */
310     dst = ApCopyShallow(dst, NULL);
311   }
312 #if 0
313   if (mt != dst->mat) MtDelete(dst->mat);
314   if (bmt != dst->backmat) MtDelete(dst->backmat);
315   if (lts != dst->lighting) LmDelete(dst->lighting);
316   if (tex != dst->tex && dst->tex) TxDelete(dst->tex);
317 #else
318   MtDelete(dst->mat);
319   MtDelete(dst->backmat);
320   LmDelete(dst->lighting);
321   TxDelete(dst->tex);
322 #endif
323 
324   dst->mat = mt;
325   dst->backmat = bmt;
326   dst->lighting = lts;
327   dst->tex = tex;
328   if (mask) {
329     /* Merge together appearance-specific data */
330     dst->flag = (src->flag & mask) | (dst->flag & ~mask);
331     dst->valid = (src->valid & mask) | (dst->valid & ~mask);
332     dst->override = (src->override & mask) | (dst->override & ~mask);
333     if (mask & APF_NORMSCALE) dst->nscale = src->nscale;
334     if (mask & APF_LINEWIDTH) dst->linewidth = src->linewidth;
335     if (mask & APF_SHADING) dst->shading = src->shading;
336     if (mask & APF_TRANSP) dst->translucency = src->translucency;
337     if (mask & APF_DICE) {
338       dst->dice[0] = src->dice[0];
339       dst->dice[1] = src->dice[1];
340     }
341   }
342   return dst;
343 }
344 
345 Appearance *
ApDefault(Appearance * ap)346 ApDefault(Appearance *ap)
347 {
348   ap->valid = ap->override = 0;
349   memset(ap, 0, sizeof(Appearance));
350   RefInit((Ref *)ap, APMAGIC);
351   ap->mat = NULL;
352   ap->lighting = NULL;
353   return ap;
354 }
355 
ApUseOverrides(Appearance * ap,int use_overrides)356 void ApUseOverrides(Appearance *ap, int use_overrides)
357 {
358   Material *mat;
359   if (ap == NULL) return;
360   ap->override = ap->valid & use_overrides;
361   if ((mat = ap->mat) != NULL) {
362     mat->override = mat->valid & use_overrides;
363     mat->changed = 1;
364   }
365   if ((mat = ap->backmat) != NULL) {
366     mat->override = mat->valid & use_overrides;
367     mat->changed = 1;
368   }
369   if (ap->lighting) {
370     ap->lighting->override = ap->lighting->valid & use_overrides;
371     ap->lighting->changed = 1;
372   }
373 }
374 
375 /*
376  * We assume dst is a child of src in the inheritance tree.
377  * Erase all settings in dst that are defined in src,
378  * so that src's settings can propagate to (the children of) dst.
379  */
ApLetPropagate(Appearance * src,Appearance * dst)380 void ApLetPropagate(Appearance *src, Appearance *dst)
381 {
382   if (src == NULL || dst == NULL) return;
383   dst->valid &= ~src->valid;
384   dst->override &= ~src->valid;
385   if (dst->mat && src->mat) {
386     dst->mat->valid &= ~src->mat->valid;
387     dst->mat->override &= ~src->mat->valid;
388     dst->mat->changed = 1;
389   }
390   if (dst->backmat && src->backmat) {
391     dst->backmat->valid &= ~src->backmat->valid;
392     dst->backmat->override &= ~src->backmat->valid;
393     dst->backmat->changed = 1;
394   }
395   if (dst->lighting && src->lighting) {
396     dst->lighting->valid &= ~src->lighting->valid;
397     dst->lighting->override &= ~src->lighting->valid;
398   }
399 }
400 
401 
402 /*
403  * Local Variables: ***
404  * mode: c ***
405  * c-basic-offset: 2 ***
406  * End: ***
407  */
408