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