ftp.nice.ch/pub/next/graphics/3d/geomview.1.4.1.s.tar.gz#/Geomview/src/lib/mg/common/mgshade.c

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 = &Lt;
		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.