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.