home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (c) 1992 The Geometry Center; University of Minnesota
- 1300 South Second Street; Minneapolis, MN 55454, USA;
-
- This file is part of geomview/OOGL. geomview/OOGL is free software;
- you can redistribute it and/or modify it only under the terms given in
- the file COPYING, which you should have received along with this file.
- This and other related software may be obtained via anonymous ftp from
- geom.umn.edu; email: software@geom.umn.edu. */
- static char *copyright = "Copyright (C) 1992 The Geometry Center";
-
- /* Authors: Charlie Gunn, Stuart Levy, Tamara Munzner, Mark Phillips */
-
- #include "appearance.h"
-
- #define MAXSHININESS 1024.0
-
- extern LmLighting * _LmSet(LmLighting *, int attr1, va_list *); /* Forward */
- Appearance *ApLoad(Appearance *into, char *fname);
- Material * _MtSet(Material *, int attr1, va_list *); /* Forward */
-
- Appearance *
- _ApSet(Appearance *ap, int attr1, register va_list *alist)
- {
- long mask;
- Color *co;
- int attr;
- char **ablock = NULL;
-
- #define NEXT(type) OOGL_VA_ARG(type,alist,ablock)
-
- if (ap == NULL) {
- /*
- * New Appearance created here.
- */
- ap = OOGLNewE(Appearance, "ApCreate Appearance");
- ApDefault(ap);
- }
-
- for ( attr = attr1; attr != AP_END; attr = NEXT(int)) {
- switch (attr) { /* parse argument list */
- case AP_ABLOCK:
- ablock = NEXT(char **);
- break;
- case AP_DO:
- mask = NEXT(int);
- ap->flag |= mask;
- ap->valid |= mask;
- break;
- case AP_DONT:
- mask = NEXT(int);
- ap->flag &= ~mask;
- ap->valid |= mask;
- break;
- case AP_INVALID:
- ap->valid &= ~NEXT(int);
- break;
- case AP_OVERRIDE:
- ap->override |= NEXT(int);
- break;
- case AP_NOOVERRIDE:
- ap->override &= ~NEXT(int);
- break;
- case AP_MAT:
- ap->mat = NEXT(Material*);
- break;
- case AP_MtSet:
- ap->mat = ablock ? MtSet(ap->mat, MT_ABLOCK, ablock)
- : _MtSet(ap->mat, va_arg(*alist, int), alist);
- break;
- case AP_LGT:
- ap->lighting = NEXT(LmLighting*);
- break;
- case AP_LmSet:
- if (!ap->lighting) ap->lighting = LmCreate(LM_END);
- ap->lighting = ablock ? LmSet(ap->lighting, LM_ABLOCK, ablock)
- : _LmSet(ap->lighting, va_arg(*alist, int), alist);
- break;
- case AP_NORMSCALE:
- ap->nscale = NEXT(double);
- ap->valid |= APF_NORMSCALE;
- break;
- case AP_LINEWIDTH:
- ap->linewidth = NEXT(int);
- ap->valid |= APF_LINEWIDTH;
- break;
- case AP_SHADING:
- /* should be APF_{CONSTANT,FLAT,SMOOTH} */
- ap->shading = NEXT(int);
- ap->valid |= APF_SHADING;
- break;
- default:
- OOGLError (0, "_ApSet: undefined option: %d\n", attr);
- return NULL;
- break;
- }
- }
- return ap;
-
- #undef NEXT
- }
-
-
- Appearance *
- ApCreate(int a1, ...)
- {
- va_list alist;
- Appearance *ap;
-
- va_start(alist,a1);
- ap = _ApSet(NULL, a1, &alist);
- va_end(alist);
- return ap;
- }
-
-
- Appearance *
- ApSet(Appearance *ap, int a1, ... )
- {
- va_list alist;
- va_start(alist,a1);
- ap = _ApSet(ap, a1, &alist);
- va_end(alist);
- return ap;
- }
-
- int
- ApGet(Appearance *ap, int attr, void *value)
- {
- if (!ap) return -1;
-
- switch (attr) {
- case AP_DO:
- case AP_DONT: *(int *) value = ap->flag; break;
- case AP_OVERRIDE:
- case AP_NOOVERRIDE: *(int *) value = ap->override; break;
- case AP_VALID:
- case AP_INVALID: *(int *) value = ap->valid; break;
- case AP_MAT: *(Material **) value = ap->mat; break;
- case AP_LGT: *(LmLighting **) value = ap->lighting; break;
- case AP_NORMSCALE: *(double *) value = ap->nscale; break;
- case AP_LINEWIDTH: *(int *) value = ap->linewidth; break;
- case AP_SHADING: *(int *)value = ap->shading; break;
- default:
- OOGLError (0, "ApGet: undefined option: %d\n", attr);
- return -1;
- break;
- }
- return attr;
- }
-
- void
- ApDelete(Appearance *ap)
- {
- if(ap == NULL || RefDecr((Ref *)ap) > 0)
- return;
- if (ap->mat) MtDelete(ap->mat);
- if (ap->lighting) LmDelete(ap->lighting);
- OOGLFree(ap);
- }
-
- /*
- * Copies just the Appearance part, not its Material and LmLighting children.
- * Pointers to the latter are retained BUT their reference counts are NOT
- * incremented. The caller MUST either RefIncr() or reassign mat and lighting.
- */
- Appearance *
- ApCopyShallow( Appearance *ap, register Appearance *into )
- {
- if(ap == NULL)
- return NULL;
- if(into == NULL) {
- into = OOGLNewE(Appearance, "ApCopy: Appearance");
- *into = *ap;
- into->mat = NULL;
- into->backmat = NULL;
- into->lighting = NULL;
- RefInit((Ref *)into, APMAGIC);
- } else {
- into->flag = ap->flag;
- into->valid = ap->valid;
- into->override = ap->override;
- into->nscale = ap->nscale;
- into->linewidth = ap->linewidth;
- into->shading = ap->shading;
- }
- return into;
- }
-
- Appearance *
- ApCopy( Appearance *ap, register Appearance *into )
- {
- if (ap == NULL) return into;
- into = ApCopyShallow( ap, into );
- if(ap->mat) into->mat = MtCopy(ap->mat, into->mat);
- if(ap->backmat) into->backmat = MtCopy(ap->backmat, into->backmat);
- if(ap->lighting) into->lighting = LmCopy(ap->lighting, into->lighting);
- return into;
- }
-
- /*
- * Merges appearance properties of src into dst.
- * If "inplace" is true, data are modified in place.
- * Otherwise if any modifications are needed to dst, a copy is made & returned.
- * If no modifications are necessary, the returned Appearance's reference
- * count is still incremented.
- * Thus, in all cases, the caller should ApDelete() the returned value
- * when finished with it.
- */
- Appearance *
- ApMerge( register Appearance *src, register Appearance *dst, int mergeflags )
- {
- int mask;
- Material *mt, *oldmt, *bmt, *oldbmt;
- LmLighting *lts, *oldlts;
-
-
- if(dst == NULL)
- return ApCopy(src, NULL);
-
- if(src == NULL) {
- RefIncr((Ref *)dst);
- return dst;
- }
- /* Mask of fields to copy to dst */
- mask = (mergeflags & APF_OVEROVERRIDE) ? src->valid :
- src->valid &~ ( dst->override &~ src->override);
-
- mt = MtMerge(src->mat, dst->mat, mergeflags);
- bmt = MtMerge(src->backmat, dst->backmat, mergeflags);
- lts = LmMerge(src->lighting, dst->lighting, mergeflags);
- if((mergeflags & APF_INPLACE)
- || (mask == 0 && mt == dst->mat &&
- lts == dst->lighting && bmt == dst->backmat)) {
- /*
- * No changes, or we're asked to merge in place. Bump ref count.
- */
- RefIncr((Ref *)dst);
- } else {
- /*
- * Another special case: Copy appearance, don't copy the items already
- * copied by {Mt,Lm}Merge. We're about to overwrite these values, so
- * toss the old ones. Pretty kludgy, but what can we do?
- */
- dst = ApCopyShallow(dst, NULL);
- }
- if(mt != dst->mat) MtDelete(dst->mat);
- if(bmt != dst->backmat) MtDelete(dst->backmat);
- if(lts != dst->lighting) LmDelete(dst->lighting);
-
- dst->mat = mt;
- dst->backmat = bmt;
- dst->lighting = lts;
- if(mask) {
- /* Merge together appearance-specific data */
- dst->flag = (src->flag & mask) | (dst->flag & ~mask);
- dst->valid = (src->valid & mask) | (dst->valid & ~mask);
- dst->override = (src->override & mask) | (dst->override & ~mask);
- if(mask & APF_NORMSCALE) dst->nscale = src->nscale;
- if(mask & APF_LINEWIDTH) dst->linewidth = src->linewidth;
- if(mask & APF_SHADING) dst->shading = src->shading;
- }
- return dst;
- }
-
- static struct {
- char *word;
- unsigned short amask;
- unsigned short aval;
- } ap_kw[] = {
- { "appearance", 0, 1 },
- { "face", APF_FACEDRAW, 0 },
- { "edge", APF_EDGEDRAW, 0 },
- { "vect", APF_VECTDRAW, 0 },
- { "transparent", APF_TRANSP, 0 },
- { "evert", APF_EVERT, 0 },
- { "shading", APF_SHADING, 2 },
- { "smooth", APF_SHADING, AP_SHADING + APF_SMOOTH },
- { "flat", APF_SHADING, AP_SHADING + APF_FLAT },
- { "constant", APF_SHADING, AP_SHADING + APF_CONSTANT },
- { "csmooth", APF_SHADING, AP_SHADING + APF_CSMOOTH },
- { "normal", APF_NORMALDRAW, 0 },
- { "normscale", APF_NORMSCALE, 3 },
- { "linewidth", APF_LINEWIDTH, 4 },
- { "material", 0, 5 },
- { "backmaterial", 0, 7 },
- { "light", 0, 6 },
- { "lighting", 0, 6 },
- };
-
- Appearance *
- ApFLoad( Appearance *into, FILE *stream, char *fname )
- {
- register Appearance *ap;
- char *w;
- int i;
- int any = 0;
- int brack = 0;
- int over, not, value;
- int mask, flagmask;
- int more;
- int mine = 1; /* Questionable -- we'll report all errors */
-
- ap = into;
-
- over = not = 0; value = ~0;
- more = 0;
- do {
- (void) fnextc(stream, 0);
-
- switch(i = fgetc(stream)) {
- case '<': ap = ApLoad(ap, fdelimtok("{}()", stream, 0)); break;
- case EOF: brack = 0; break;
- case '{': brack++; break;
- case '}': if(brack-- <= 0) { ungetc(i, stream); } break;
- case '+': value = ~0; break;
- case '-': value = 0; break;
- case '!': not = 1; break;
- case '*': over = 1; break;
-
- default:
- more = 0;
- ungetc(i, stream);
- w = fdelimtok("{}()", stream, 0);
- if(w == NULL)
- break;
- for(i = sizeof(ap_kw)/sizeof(ap_kw[0]); --i >= 0; )
- if(!strcmp(ap_kw[i].word, w))
- break;
-
- if(i < 0) {
- if(mine)
- OOGLError(1,
- "ApFLoad: file %s: unknown appearance keyword %s",
- fname, w);
- return NULL;
- }
- if(ap == NULL)
- ap = ApCreate(AP_END);
-
- mask = flagmask = ap_kw[i].amask;
- if(not) {
- switch(ap_kw[i].aval) {
- case 5: MtDelete(ap->mat); ap->mat = NULL; break;
- case 6: LmDelete(ap->lighting); ap->lighting = NULL; break;
- }
- ap->flag &= ~mask;
- if(!over) ap->valid &= ~mask;
- ap->override &= ~mask;
- } else {
- switch(ap_kw[i].aval) {
- case 0: break;
- case 1: mine = more = 1; break;
- case 2: fgetni(stream, 1, &ap->shading, 0); break;
- case 3:
- if(fgetnf(stream, 1, &ap->nscale, 0) <= 0)
- OOGLError(1,"ApFLoad: %s: \"normscale\": value expected",
- fname);
- break;
- case 4:
- if(fgetni(stream, 1, &ap->linewidth, 0) <= 0)
- OOGLSyntax(stream, "%s \"linewidth\": value expected",
- fname);
- break;
- case 5:
- if((ap->mat = MtFLoad(ap->mat, stream, fname)) == NULL)
- OOGLSyntax(stream,"Can't read material in %s",
- fname);
- break;
- case 7:
- if((ap->backmat = MtFLoad(ap->backmat, stream, fname)) == NULL)
- OOGLError(1,"Can't read backmaterial, file %s",
- fname);
- break;
- case 6:
- ap->lighting = LmFLoad(ap->lighting, stream, fname);
- if(ap->lighting == NULL)
- OOGLError(1,"Can't read lighting, file %s",
- fname);
- break;
- default:
- if(ap_kw[i].aval >= AP_SHADING)
- ap->shading = ap_kw[i].aval - AP_SHADING;
- }
- if(value) ap->flag |= flagmask;
- else ap->flag &= ~flagmask;
- ap->valid |= mask;
- if(over) ap->override |= mask;
- }
- /* Reset for next keyword */
- over = not = 0; value = ~0;
-
- }
- } while(brack > 0 || more);
- return ap;
- }
-
- Appearance *
- ApLoad(Appearance *into, char *fname)
- {
- FILE *f = fopen(fname, "r");
- Appearance *a;
-
- if(f == NULL) {
- OOGLError(0, "ApLoad: can't open %s: %s", fname, sperror());
- return NULL;
- }
- a = ApFLoad(into, f, fname);
- fclose(f);
- return a;
- }
-
-
- void ApFSave( Appearance *ap, Handle *aphandle, FILE *f, char *fname )
- {
- int valid;
- int mask;
- register int i;
-
- if(ap == NULL)
- return;
-
- valid = ap->valid;
- fprintf(f, "appearance {\n");
-
- for(i = 0; i < sizeof(ap_kw)/sizeof(ap_kw[0]); i++) {
- mask = ap_kw[i].amask;
- if((valid & mask) == 0)
- continue;
- Apsavepfx(valid, ap->override, mask, "", f);
- if(ap_kw[i].aval == 0) {
- if((mask & ap->flag) == 0)
- fputc('-', f);
- fputs(ap_kw[i].word, f);
- }
- valid &= ~mask;
- switch(mask) {
- case APF_SHADING:
- fputs(" shading ", f);
- switch(ap->shading) {
- case APF_SMOOTH: fputs("smooth", f); break;
- case APF_FLAT: fputs("flat", f); break;
- case APF_CONSTANT: fputs("constant", f); break;
- case APF_CSMOOTH: fputs("csmooth", f); break;
- default: fprintf(f, "%d", ap->shading); break;
- }
- break;
- case APF_NORMSCALE:
- fprintf(f, " normscale %g", ap->nscale);
- break;
- case APF_LINEWIDTH:
- fprintf(f, " linewidth %d ", ap->linewidth);
- break;
- }
- fputc('\n', f);
- }
-
- if(ap->mat) {
- fprintf(f, " material {\n");
- MtFSave(ap->mat, f);
- fprintf(f, " }\n");
- }
- if(ap->backmat) {
- fprintf(f, " backmaterial {\n");
- MtFSave(ap->backmat, f);
- fprintf(f, " }\n");
- }
- if(ap->lighting) {
- fprintf(f, " lighting {\n");
- LmFSave(ap->lighting, f, fname);
- fprintf(f, " }\n");
- }
- fprintf(f, "}\n");
- return;
- }
-
- ApSave(Appearance *ap, char *fname)
- {
- FILE *f = fname == NULL ? stdout : fopen(fname, "w");
-
- if(f) {
- ApFSave(ap, NULL, f, fname);
- if(fname != NULL)
- fclose(f);
- }
- }
-
- Material *
- _MtSet(Material *mat, int attr1, va_list *alist)
- {
- Color *co;
- long mask;
- int attr;
- char **ablock = NULL;
-
- #define NEXT(type) OOGL_VA_ARG(type,alist,ablock)
-
- if (mat == NULL) {
- /*
- * New Material created here.
- */
- mat = OOGLNewE(Material, "new Material");
- MtDefault(mat);
- }
-
- for(attr = attr1; attr != MT_END; attr = NEXT(int)) {
- switch (attr) { /* parse argument list */
- case MT_ABLOCK:
- ablock = NEXT(char**);
- break;
- case MT_AMBIENT:
- co = NEXT(Color *);
- CoCopy(co, &mat->ambient);
- mat->valid |= MTF_AMBIENT;
- break;
- case MT_DIFFUSE:
- co = NEXT(Color *);
- CoCopy(co, &mat->diffuse);
- mat->valid |= MTF_DIFFUSE;
- break;
- case MT_SPECULAR:
- co = NEXT(Color *);
- CoCopy(co, &mat->specular);
- mat->valid |= MTF_SPECULAR;
- break;
- case MT_EMISSION:
- co = NEXT(Color *);
- CoCopy(co, &mat->emission);
- mat->valid |= MTF_EMISSION;
- break;
- case MT_ALPHA:
- mat->alpha = NEXT(double);
- mat->valid |= MTF_ALPHA;
- break;
- case MT_Ka:
- mat->ka = NEXT(double);
- mat->valid |= MTF_Ka;
- break;
- case MT_Kd:
- mat->kd = NEXT(double);
- mat->valid |= MTF_Kd;
- break;
- case MT_Ks:
- mat->ks = NEXT(double);
- mat->valid |= MTF_Ks;
- break;
- case MT_SHININESS:
- mat->shininess = NEXT(double);
- mat->valid |= MTF_SHININESS;
- break;
- case MT_EDGECOLOR:
- CoCopy(NEXT(Color *), &mat->edgecolor);
- mat->valid |= MTF_EDGECOLOR;
- break;
- case MT_NORMALCOLOR:
- CoCopy(NEXT(Color *), &mat->normalcolor);
- mat->valid |= MTF_NORMALCOLOR;
- break;
- case MT_INVALID:
- mat->valid &= ~NEXT(int);
- break;
- case MT_OVERRIDE:
- mat->override |= NEXT(int);
- break;
- case MT_NOOVERRIDE:
- mat->override &= ~NEXT(int);
- break;
- default:
- OOGLError (0, "_MtSet: undefined option: %d\n", attr);
- return NULL;
- break;
- }
- }
-
- return mat;
-
- #undef NEXT
- }
-
- Material *
- MtCreate(int a1, ... )
- {
- va_list alist;
- Material *mat;
-
- va_start(alist,a1);
- mat = _MtSet(NULL, a1, &alist);
- va_end(alist);
- return mat;
- }
-
- Material *
- MtSet(Material *mat, int attr, ... )
- {
- va_list alist;
-
- va_start(alist,attr);
- mat = _MtSet(mat,attr,&alist);
- va_end(alist);
- return mat;
- }
-
- int
- MtGet(register Material *mat, int attr, void * value)
- {
- if (mat == NULL)
- return -1;
-
- switch (attr) {
- case MT_AMBIENT:
- *(Color *) value = mat->ambient;
- break;
- case MT_DIFFUSE:
- *(Color *) value = mat->diffuse;
- break;
- case MT_SPECULAR:
- *(Color *) value = mat->specular;
- break;
- case MT_EMISSION:
- *(Color *) value = mat->emission;
- break;
- case MT_ALPHA:
- *(double *) value = mat->alpha;
- break;
- case MT_Ka:
- *(double *) value = mat->ka;
- break;
- case MT_Kd:
- *(double *) value = mat->kd;
- break;
- case MT_Ks:
- *(double *) value = mat->ks;
- break;
- case MT_SHININESS:
- *(double *) value = mat->shininess;
- break;
- case MT_EDGECOLOR:
- *(Color *)value = mat->edgecolor;
- break;
- case MT_NORMALCOLOR:
- *(Color *)value = mat->normalcolor;
- break;
- case MT_OVERRIDE:
- case MT_NOOVERRIDE:
- *(int *) value = mat->override;
- break;
- case MT_VALID:
- case MT_INVALID:
- *(int *) value = mat->valid;
- break;
- default:
- OOGLError (0, "MtGet: undefined option: %d\n", attr);
- return -1;
- break;
- }
-
- return 1;
- }
-
- void
- MtDelete(Material *mat)
- {
- if(mat && RefDecr((Ref *)mat) <= 0) {
- mat->magic = -1;
- OOGLFree(mat);
- }
- }
-
- Material *
- MtDefault( Material *mat )
- {
- bzero(mat, sizeof(Material));
- RefInit((Ref *)mat, MATMAGIC);
- mat->valid = mat->override = 0;
- mat->alpha = 1.0;
- mat->Private = 0;
- mat->changed = 1;
- }
-
-
- Material *
- MtCopy( Material *src, Material *dst )
- {
- if (!src) return NULL;
- if(dst == NULL)
- dst = OOGLNewE(Material, "MtCopy: Material");
- *dst = *src;
- dst->Private = 0;
- RefInit((Ref *)dst, MATMAGIC);
- dst->changed = 1;
- return dst;
- }
-
- #define max(a,b) (a)>(b)?(a):(b)
-
- static
- norm( color, coeff )
- Color *color;
- float *coeff;
- {
- *coeff = max(color->r, color->g);
- *coeff = max(color->b, *coeff);
-
- if( *coeff != 0.0 ) {
- color->r /= *coeff;
- color->g /= *coeff;
- color->b /= *coeff;
- }
- }
-
- Material *
- MtLoad(mat, name)
- Material *mat;
- char *name;
- {
- FILE *f = fopen(name,"r");
-
- if(f == NULL) {
- OOGLError(0, "MtLoad: can't open %s: %s", name, sperror());
- return NULL;
- }
- mat = MtFLoad(mat, f, name);
- fclose(f);
- return mat;
- }
-
- /*
- * Load Material from file.
- * Syntax:
- * < "filename_containing_material" [or]
- * { keyword value keyword value ... }
- *
- * Each keyword may be prefixed by "*", indicating that its value should
- * override corresponding settings in child objects. [By default,
- * children's appearance values supercede those of their parents.]
- *
- * Note: don't overwrite ka, kd, ks if they're already set when we read in
- * the corresponding color.
- */
- static char *mt_kw[] = {
- "shininess", "ka", "kd", "ks", "alpha",
- "emission", "ambient", "diffuse", "specular",
- "edgecolor", "normalcolor", "material"
- };
- static unsigned short mt_flags[] = {
- MTF_SHININESS, MTF_Ka, MTF_Kd, MTF_Ks, MTF_ALPHA,
- MTF_EMISSION, MTF_AMBIENT, MTF_DIFFUSE, MTF_SPECULAR,
- MTF_EDGECOLOR, MTF_NORMALCOLOR, 0
- };
- static char mt_args[] = { 1,1,1,1,1, 3,3,3,3,3,3, 0 };
-
- Material *
- MtFLoad(mat, f, fname)
- Material *mat;
- FILE *f;
- char *fname; /* Used for error msgs, may be NULL */
- {
- char *w;
- register int i;
- float v[3];
- int brack = 0;
- int over, not;
- int got;
- Material m;
-
- MtDefault(&m);
-
- over = not = 0;
- for(;;) {
- switch(fnextc(f, 0)) {
- case '<':
- fgetc(f);
- if(MtLoad(&m, fdelimtok("{}()", f, 0)) == NULL) return NULL;
- if(!brack) goto done;
- break;
- case '{': brack++; fgetc(f); break;
- case '}': if(brack) { fgetc(f); } goto done;
- case '*': over = 1; fgetc(f); break; /* 'override' prefix */
- case '!': not = 1; fgetc(f); break;
- default:
- w = fdelimtok("{}()", f, 0);
- if(w == NULL)
- return MtCopy(&m, mat);
- /* break; */ /* done */
-
- for(i = sizeof(mt_kw)/sizeof(mt_kw[0]); --i >= 0; )
- if(!strcmp(w, mt_kw[i]))
- break;
-
- if( i < 0) {
- OOGLError(1, "MtFLoad: %s: unknown material keyword %s",fname,w);
- return NULL;
- } else if( !not && (got=fgetnf(f, mt_args[i], v, 0)) != mt_args[i] ) {
- OOGLError(1, "MtFLoad: %s: \"%s\" expects %d values, got %d",
- fname, w, mt_args[i], got);
- return NULL;
- }
-
- if(not) {
- if(!over) m.valid &= ~mt_flags[i];
- m.override &= ~mt_flags[i];
- } else {
- switch(i) {
- case 0: m.shininess = v[0]; break;
- case 1: m.ka = v[0]; break;
- case 2: m.kd = v[0]; break;
- case 3: m.ks = v[0]; break;
- case 4: m.alpha = v[0]; break;
- case 5: m.emission = *(Color *)v; break;
- case 6: m.ambient = *(Color *)v; break;
- case 7: m.diffuse = *(Color *)v; break;
- case 8: m.specular = *(Color *)v; break;
- case 9: m.edgecolor = *(Color *)v; break;
- case 10: m.normalcolor = *(Color *)v; break;
- }
- m.valid |= mt_flags[i];
- if(over) m.override |= mt_flags[i];
- }
- over = not = 0;
- }
- }
- done:
- return MtCopy(&m, mat);
- }
-
- /*
- * MtMerge(src, dst, mergeflags)
- * Merge Material values: src into dst, controlled by flag.
- * If "inplace" is true, changes are made in dst itself; otherwise,
- * the dst material is copied if any changes need be made to it.
- * The returned Material's reference count is incremented as appropriate;
- * thus the caller should MtDelete() the returned Material when done.
- */
- Material *
- MtMerge(Material *src, Material *dst, int mergeflags)
- {
- register int mask;
-
- if(dst == NULL)
- return MtCopy(src, NULL);
-
- /* Fields to merge in */
- mask = src ?
- (mergeflags & APF_OVEROVERRIDE) ?
- src->valid : src->valid & ~(dst->override &~ src->override)
- : 0;
-
- if(mergeflags & APF_INPLACE)
- RefIncr((Ref *)dst);
- else
- dst = MtCopy(dst, NULL);
-
- if(mask == 0) /* No changes to dst */
- return dst;
-
- dst->changed |= src->changed;
- dst->valid = (src->valid & mask) | (dst->valid & ~mask);
- dst->override = (src->override & mask) | (dst->override & ~mask);
- if(mask & MTF_EMISSION) dst->emission = src->emission;
- if(mask & MTF_AMBIENT) dst->ambient = src->ambient;
- if(mask & MTF_DIFFUSE) dst->diffuse = src->diffuse;
- if(mask & MTF_SPECULAR) dst->specular = src->specular;
- if(mask & MTF_Ka) dst->ka = src->ka;
- if(mask & MTF_Kd) dst->kd = src->kd;
- if(mask & MTF_Ks) dst->ks = src->ks;
- if(mask & MTF_ALPHA) dst->alpha = src->alpha;
- if(mask & MTF_SHININESS) dst->shininess = src->shininess;
- if(mask & MTF_EDGECOLOR) dst->edgecolor = src->edgecolor;
- if(mask & MTF_NORMALCOLOR) dst->normalcolor = src->normalcolor;
- return dst;
- }
-
- int
- MtSave(mat,name)
- Material *mat;
- char *name;
- {
- FILE *f;
- int ok;
-
- f = fopen(name,"w");
- if(!f) {
- perror(name);
- return -1;
- }
- ok = MtFSave(mat, f);
- fclose(f);
- return ok;
- }
-
- int
- Apsavepfx(valid, override, mask, keyword, f)
- int valid, override, mask;
- FILE *f;
- {
- if((valid & mask) == 0)
- return 0;
- fputc('\t', f);
- if(override & mask)
- fputc('*', f);
- fprintf(f, "%s ", keyword);
- return 1;
- }
-
-
- int
- MtFSave(mat,f)
- register Material *mat;
- FILE *f;
- {
- register int i;
- float v;
- Color *c;
-
- for(i = 0; i < sizeof(mt_kw)/sizeof(mt_kw[0]); i++) {
- if(Apsavepfx(mat->valid, mat->override, mt_flags[i], mt_kw[i], f)) {
- switch(mt_flags[i]) {
- case MTF_Ka: v = mat->ka; goto pfloat;
- case MTF_Kd: v = mat->kd; goto pfloat;
- case MTF_Ks: v = mat->ks; goto pfloat;
- case MTF_SHININESS: v = mat->shininess; goto pfloat;
- case MTF_ALPHA: v = mat->alpha; goto pfloat;
- pfloat:
- fprintf(f, "%f\n", v);
- break;
-
- case MTF_DIFFUSE: c = &mat->diffuse; goto pcolor;
- case MTF_AMBIENT: c = &mat->ambient; goto pcolor;
- case MTF_EMISSION: c = &mat->emission; goto pcolor;
- case MTF_SPECULAR: c = &mat->specular; goto pcolor;
- case MTF_EDGECOLOR: c = &mat->edgecolor; goto pcolor;
- case MTF_NORMALCOLOR: c = &mat->normalcolor; goto pcolor;
- pcolor:
- fprintf(f, "%f %f %f\n", c->r, c->g, c->b);
- break;
- }
- }
- }
- return ferror(f);
- }
-
- void
- MtPrint(mat)
- Material *mat;
- {
- MtFSave(mat,stdout);
- }
-
-
- Material *
- MtPlastic(
- float Ka, float Kd, float Ks, float roughness,
- Color *Ca, Color *Cd, Color *Cs )
- {
- Material *mat;
- static Color black = { 0.0, 0.0, 0.0 };
- mat = MtCreate( MT_END );
- mat->shininess = roughness < 1.0/MAXSHININESS ? 1.0/roughness : MAXSHININESS;
- mat->ka = Ka;
- mat->kd = Kd;
- mat->ks = Ks;
- mat->emission = black;
- if (Ca) mat->ambient = *Ca;
- if (Cd) mat->diffuse = *Cd;
- if (Cs) mat->specular = *Cs;
- return mat;
- }
-
- Appearance *
- ApDefault(Appearance *ap)
- {
- ap->valid = ap->override = 0;
- bzero(ap, sizeof(Appearance));
- RefInit((Ref *)ap, APMAGIC);
- ap->mat = NULL;
- ap->lighting = NULL;
- return ap;
- }
-
- void ApUseOverrides(Appearance *ap, int use_overrides)
- {
- Material *mat;
- if(ap == NULL) return;
- ap->override = ap->valid & use_overrides;
- if((mat = ap->mat) != NULL) {
- mat->override = mat->valid & use_overrides;
- mat->changed = 1;
- }
- if((mat = ap->backmat) != NULL) {
- mat->override = mat->valid & use_overrides;
- mat->changed = 1;
- }
- if(ap->lighting) {
- ap->lighting->override = ap->lighting->valid & use_overrides;
- ap->lighting->changed = 1;
- }
- }
-
- /*
- * We assume dst is a child of src in the inheritance tree.
- * Erase all settings in dst that are defined in src,
- * so that src's settings can propagate to (the children of) dst.
- */
- void ApLetPropagate(register Appearance *src, register Appearance *dst)
- {
- if(src == NULL || dst == NULL) return;
- dst->valid &= ~src->valid;
- dst->override &= ~src->valid;
- if(dst->mat && src->mat) {
- dst->mat->valid &= ~src->mat->valid;
- dst->mat->override &= ~src->mat->valid;
- dst->mat->changed = 1;
- }
- if(dst->backmat && src->backmat) {
- dst->backmat->valid &= ~src->backmat->valid;
- dst->backmat->override &= ~src->backmat->valid;
- dst->backmat->changed = 1;
- }
- if(dst->lighting && src->lighting) {
- dst->lighting->valid &= ~src->lighting->valid;
- dst->lighting->override &= ~src->lighting->valid;
- }
- }
-