This is mgshade.c in view mode; [Download] [Up]
/* * Software shaders. * These operate in the mg environment. */ #include "mgP.h" #define DOT(a,b) ((a).x*(b).x + (a).y*(b).y + (a).z*(b).z) #define CCMUL(A,B,C) ((C).r=(A).r*(B).r, (C).g=(A).g*(B).g, (C).b=(A).b*(B).b) #define CCADD(A,B,C) ((C).r=(A).r+(B).r, (C).g=(A).g+(B).g, (C).b=(A).b+(B).b, (C).a = (A).a + (B).a) #define CSCALE(s, A, B) ( (B).r = (A).r * s, (B).g = (A).g * s, (B).b = (A).b * s, (B).a = (A).b * s) #define CCSADD(A,B,s,C) \ ((C).r += (s)*(A).r*(B).r, \ (C).g += (s)*(A).g*(B).g, \ (C).b += (s)*(A).b*(B).b) /* * Transform a vector covariantly */ static void cotransform(register Transform Tinv, register Point3 *in, Point3 *out) { out->x = Tinv[0][0]*in->x + Tinv[0][1]*in->y + Tinv[0][2]*in->z; out->y = Tinv[1][0]*in->x + Tinv[1][1]*in->y + Tinv[1][2]*in->z; out->z = Tinv[2][0]*in->x + Tinv[2][1]*in->y + Tinv[2][2]*in->z; } static float euck1 = 1.0; /* inverse power falloff */ static float euck2 = 0.0; /* safety zone around light */ static float fog = 0.0; /* fog control */ static float hypk1 = .5; /* controls exponential falloff */ static float hypk2 = .0; /* controls exponential falloff */ static float sphk1 = .5; /* controls exponential falloff */ static float sphk2 = 0.0; /* safety zone around light */ /* * Euclidean shader * * We depend on the following mg features: * _mgc->xstk->hasinv (cleared whenever transform changes) * _mgc->W2C, C2W (initialized from camera at mgworldbegin()) */ int mg_eucshade(int nv, HPoint3 *v, Point3 *n, ColorA *c, ColorA *cs) { struct mgxstk *mx = _mgc->xstk; struct mgastk *ma = _mgc->astk; struct LtLight *l; int i; HPoint3 V; Point3 N, I; float s; Color Ca; euck1 = ma->lighting.attenmult; euck2 = ma->lighting.attenmult2; fog = ma->lighting.attenconst; #define EYE ((HPoint3 *) (_mgc->C2W[3])) /* Eye (camera) position as an HPoint3 */ if(!mx->hasinv) { TmInvert(mx->T, mx->Tinv); mx->hasinv = 1; } /* "ambient" color */ Ca.r = Ca.g = Ca.b = 0; CCSADD(ma->mat.ambient, ma->lighting.ambient, ma->mat.ka, Ca); for(i = 0; i < nv; i++, v++, n++, c++, cs++) { ColorA *thiscolor = c; /* Transform point by T */ HPt3Transform(mx->T, v, &V); /* V = v in world coords */ HPt3SubPt3(EYE, &V, &I); /* I = EYE - V (point-to-eye vector) */ /* Transform normal by T'^-1 */ cotransform(mx->Tinv, n, &N); s = 1/sqrt(DOT(N,N)); if(DOT(N,I) < 0) { s = -s; /* Flip normal to face the viewer */ /* Hack: use otherwise-useless emission color, if defined, * as the back-side material color. */ if(ma->mat.valid & MTF_EMISSION) thiscolor = (ColorA*)&ma->mat.emission; } N.x *= s; N.y *= s; N.z *= s; /* Ambient term */ *(Color *)cs = Ca; for(l = ma->lighting.lights; l != NULL; l = l->next) { register Point3 *L; Point3 Lt; float bright, ls, ll, ln, power; /* Diffuse term */ bright = l->intensity; if(l->globalposition.w == 0) { L = (Point3 *)&l->globalposition; ll = DOT(*L,*L); } else { HPt3SubPt3(&l->globalposition, &V, &Lt); L = ≪ ll = DOT(Lt,Lt); /* ll = (ll > euck2) ? ll : euck2; */ power = pow(ll, -euck1/2.0); /* Inverse square falloff */ bright *= power; } ln = DOT(*L,N); if(ln <= 0) /* Ignore lights shining from behind */ continue; ls = sqrt(ll); s = ma->mat.kd * bright * (ln/ls); /* cosine law: L.N diffuse shading */ CCSADD(l->color, *thiscolor, s, *cs); if(ma->mat.ks > 0) { /* Specular term */ Point3 H; /* H: halfway between L and I */ H.x = L->x/ls + I.x, H.y = L->y/ls + I.y, H.z = L->z/ls + I.z; s = DOT(H,N) / sqrt(DOT(H,H)); /* cos angle(H,N) */ /* Note we need s>=0 for specular term to make sense. * This should be true since we checked * that both L.N and I.N are positive above. */ /* shininess = specular exponent */ s = ma->mat.ks * bright * pow(s, ma->mat.shininess); CCSADD(l->color, ma->mat.specular, s, *cs); } } /* insert fog code */ if (fog) { float k1, k2; float d = HPt3Distance(&V, EYE); ColorA surfcolor, fogcolor; d = d - euck2; /* fog-free sphere of radius euck2 */ if (d < 0) d = 0; k1 = exp( -fog * d); k2 = 1.0 - k1; CSCALE(k1, *cs, surfcolor); CSCALE(k2, _mgc->background, fogcolor); CCADD(surfcolor, fogcolor, *cs); } if(cs->r < 0) cs->r = 0; else if(cs->r > 1) cs->r = 1; if(cs->g < 0) cs->g = 0; else if(cs->g > 1) cs->g = 1; if(cs->b < 0) cs->b = 0; else if(cs->b > 1) cs->b = 1; cs->a = c->a; } return 0; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.