553 lines
13 KiB
C
553 lines
13 KiB
C
/*
|
|
* Copyright (c) 1993-1995 Argonaut Technologies Limited. All rights reserved.
|
|
*
|
|
* $Id: light24.c 1.5 1995/03/01 15:26:08 sam Exp $
|
|
* $Locker: $
|
|
*
|
|
* Bits of the lighting model for true colour pixels
|
|
*/
|
|
|
|
#include "fw.h"
|
|
#include "shortcut.h"
|
|
#include "brassert.h"
|
|
|
|
static char rscid[] = "$Id: light24.c 1.5 1995/03/01 15:26:08 sam Exp $";
|
|
|
|
/*
|
|
* Evaluate the vertex lighting function, and return a value
|
|
* for uniform face rendering
|
|
*/
|
|
br_uint_32 BR_SURFACE_CALL LightingFaceColour(br_vertex *v, br_face *fp, int reversed)
|
|
{
|
|
br_scalar comp[NUM_COMPONENTS];
|
|
br_fvector3 rev_normal;
|
|
|
|
if(!reversed) {
|
|
fw.surface_fn(v, &fp->n, comp);
|
|
|
|
} else {
|
|
|
|
BrFVector3Negate(&rev_normal,&fp->n);
|
|
fw.surface_fn(v, &rev_normal, comp);
|
|
}
|
|
|
|
return BR_COLOUR_RGB(BrScalarToInt(comp[C_R]),
|
|
BrScalarToInt(comp[C_G]),
|
|
BrScalarToInt(comp[C_B])) ;
|
|
}
|
|
|
|
/*
|
|
* Lighting function for unlit colour
|
|
*/
|
|
void BR_SURFACE_CALL LightingColourCopyMaterial(br_vertex *v, br_fvector3 *n, br_scalar *comp)
|
|
{
|
|
comp[C_R]=BrIntToScalar(BR_RED(fw.material->colour));
|
|
comp[C_G]=BrIntToScalar(BR_GRN(fw.material->colour));
|
|
comp[C_B]=BrIntToScalar(BR_BLU(fw.material->colour));
|
|
}
|
|
|
|
/*
|
|
* Lighting function for prelit colour
|
|
*/
|
|
void BR_SURFACE_CALL LightingColourCopyVertex(br_vertex *v, br_fvector3 *n, br_scalar *comp)
|
|
{
|
|
comp[C_R] = BrIntToScalar(v->red);
|
|
comp[C_G] = BrIntToScalar(v->grn);
|
|
comp[C_B] = BrIntToScalar(v->blu);
|
|
}
|
|
|
|
/*
|
|
* Work out 3 component lighting given:
|
|
* A point
|
|
* A normal
|
|
* A material
|
|
*
|
|
* Examines all active lights and accumulates lighting from each light
|
|
*
|
|
* Writes results into
|
|
* comp[C_R]
|
|
* comp[C_G]
|
|
* comp[C_B]
|
|
*/
|
|
void BR_SURFACE_CALL LightingColour(br_vertex *v, br_fvector3 *n, br_scalar *comp)
|
|
{
|
|
br_active_light *alp;
|
|
int i;
|
|
br_vector3 vp;
|
|
br_vector3 vn;
|
|
br_fvector3 fvn;
|
|
|
|
br_scalar lcomp[NUM_L_COMPONENTS];
|
|
br_scalar r,g,b;
|
|
|
|
r=g=b=BR_SCALAR(0.0);
|
|
|
|
fw.eye_l=fw.eye_m_normalised;
|
|
alp=fw.active_lights_model;
|
|
|
|
/*
|
|
* Ambient component
|
|
*/
|
|
r=BR_MUL(fw.material->ka,BrFixedToScalar(BR_RED(fw.material->colour) << 8));
|
|
g=BR_MUL(fw.material->ka,BrFixedToScalar(BR_GRN(fw.material->colour) << 8));
|
|
b=BR_MUL(fw.material->ka,BrFixedToScalar(BR_BLU(fw.material->colour) << 8));
|
|
|
|
/*
|
|
* Accumulate intensities for each active light in model space
|
|
*/
|
|
alp=fw.active_lights_model;
|
|
for(i=0;i<fw.nactive_lights_model;i++,alp++)
|
|
{
|
|
alp->light_sub_function(&v->p, n, alp, lcomp);
|
|
|
|
r+=lcomp[L_R];
|
|
g+=lcomp[L_G];
|
|
b+=lcomp[L_B];
|
|
}
|
|
|
|
/*
|
|
* See if any lights are to be calculated in view space
|
|
*/
|
|
if(fw.nactive_lights_view) {
|
|
BrMatrix34ApplyP(&vp, &v->p, &fw.model_to_view);
|
|
BrMatrix34TApplyFV(&vn, n, &fw.view_to_model);
|
|
BrFVector3Normalise(&fvn, &vn);
|
|
|
|
fw.eye_l.v[0] = BR_SCALAR(0);
|
|
fw.eye_l.v[1] = BR_SCALAR(0);
|
|
fw.eye_l.v[2] = BR_SCALAR(1);
|
|
|
|
/*
|
|
* ... and accumulate
|
|
*/
|
|
alp = fw.active_lights_view;
|
|
for(i=0; i < fw.nactive_lights_view; i++, alp++)
|
|
{
|
|
alp->light_sub_function(&vp, &fvn, alp, lcomp);
|
|
r+=lcomp[L_R];
|
|
g+=lcomp[L_G];
|
|
b+=lcomp[L_B];
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Scale and clamp to final range
|
|
*/
|
|
comp[C_R] = BR_MUL(r,BR_SCALAR(256));
|
|
comp[C_G] = BR_MUL(g,BR_SCALAR(256));
|
|
comp[C_B] = BR_MUL(b,BR_SCALAR(256));
|
|
|
|
#define RGB_MAX BR_SCALAR(254.0)
|
|
#define RGB_MIN BR_SCALAR(1.0)
|
|
|
|
if(comp[C_R] >= RGB_MAX)
|
|
comp[C_R] = RGB_MAX;
|
|
else if(comp[C_R] < RGB_MIN)
|
|
comp[C_R] = RGB_MIN;
|
|
|
|
if(comp[C_G] >= RGB_MAX)
|
|
comp[C_G] = RGB_MAX;
|
|
else if(comp[C_G] < RGB_MIN)
|
|
comp[C_G] = RGB_MIN;
|
|
|
|
if(comp[C_B] >= RGB_MAX)
|
|
comp[C_B] = RGB_MAX;
|
|
else if(comp[C_B] < RGB_MIN)
|
|
comp[C_B] = RGB_MIN;
|
|
}
|
|
|
|
/*
|
|
* Lighting function that returns 0.0
|
|
* True colour
|
|
*/
|
|
void LightingColour_Null(br_vector3 *p, br_fvector3 *n, br_active_light *alp,br_scalar *lcomp)
|
|
{
|
|
lcomp[L_R] = lcomp[L_G] = lcomp[L_B] = BR_SCALAR(1.0);
|
|
}
|
|
|
|
/*
|
|
* Lighting for directional light source in model space
|
|
* True colour
|
|
*/
|
|
void LightingColour_Dirn(br_vector3 *p, br_fvector3 *n, br_active_light *alp,br_scalar *lcomp)
|
|
{
|
|
br_scalar c,l,d;
|
|
|
|
/*
|
|
* Accumulate diffuse and specular components
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Diffuse (alp->direction already has alp->intensitt factored into it)
|
|
*/
|
|
c = BrFVector3Dot(n,&alp->direction);
|
|
|
|
if(c > BR_SCALAR(0.0)) {
|
|
|
|
c = BR_MUL(c,fw.material->kd);
|
|
|
|
lcomp[L_R] = BR_MUL(c,BrFixedToScalar(BR_RED(fw.material->colour) << 8));
|
|
lcomp[L_G] = BR_MUL(c,BrFixedToScalar(BR_GRN(fw.material->colour) << 8));
|
|
lcomp[L_B] = BR_MUL(c,BrFixedToScalar(BR_BLU(fw.material->colour) << 8));
|
|
|
|
if (fw.material->ks != BR_SCALAR(0.0)) {
|
|
|
|
c = BrFVector3Dot(n,&alp->half);
|
|
|
|
if(c > SPECULARPOW_CUTOFF) {
|
|
l = BR_MUL(fw.material->ks,alp->intensity);
|
|
d = BR_MULDIV(c,l,fw.material->power-BR_MUL(fw.material->power,c)+c);
|
|
|
|
lcomp[L_R] += d;
|
|
lcomp[L_G] += d;
|
|
lcomp[L_B] += d;
|
|
}
|
|
}
|
|
|
|
lcomp[L_R] = BR_MUL(lcomp[L_R],BrFixedToScalar(BR_RED(alp->light->colour) << 8));
|
|
lcomp[L_G] = BR_MUL(lcomp[L_G],BrFixedToScalar(BR_GRN(alp->light->colour) << 8));
|
|
lcomp[L_B] = BR_MUL(lcomp[L_B],BrFixedToScalar(BR_BLU(alp->light->colour) << 8));
|
|
|
|
} else
|
|
lcomp[L_R]=lcomp[L_G]=lcomp[L_B]=BR_SCALAR(0.0);
|
|
}
|
|
|
|
/*
|
|
* Lighting for point light source with attenuation
|
|
* True colour
|
|
*/
|
|
void LightingColour_Point(br_vector3 *p, br_fvector3 *n, br_active_light *alp, br_scalar *lcomp)
|
|
{
|
|
br_scalar c,rd,l,d;
|
|
br_vector3 dirn,dirn_norm,r,sn;
|
|
|
|
/*
|
|
* Work out vector between point and light source
|
|
*/
|
|
BrVector3Sub(&dirn,&alp->position,p);
|
|
BrVector3Normalise(&dirn_norm,&dirn);
|
|
|
|
/*
|
|
* Diffuse
|
|
*/
|
|
|
|
c = BrFVector3Dot(n,&dirn_norm);
|
|
|
|
if(c > BR_SCALAR(0.0)) {
|
|
|
|
c = BR_MUL(alp->intensity,BR_MUL(c,fw.material->kd));
|
|
|
|
lcomp[L_R] = BR_MUL(c,BrFixedToScalar(BR_RED(fw.material->colour) << 8));
|
|
lcomp[L_G] = BR_MUL(c,BrFixedToScalar(BR_GRN(fw.material->colour) << 8));
|
|
lcomp[L_B] = BR_MUL(c,BrFixedToScalar(BR_BLU(fw.material->colour) << 8));
|
|
|
|
if (fw.material->ks != BR_SCALAR(0.0)) {
|
|
/*
|
|
* Specular
|
|
*/
|
|
BrVector3CopyF(&sn,n);
|
|
rd = BR_CONST_MUL(BrVector3Dot(&dirn_norm,&sn),2);
|
|
BrVector3Scale(&r,&sn,rd);
|
|
BrVector3Sub(&r,&r,&dirn_norm);
|
|
|
|
c = BrVector3Dot(&fw.eye_l,&r);
|
|
|
|
/*
|
|
* Phong lighting approximation from Gems IV pg. 385
|
|
*/
|
|
if(c > SPECULARPOW_CUTOFF) {
|
|
l = BR_MUL(fw.material->ks,alp->intensity);
|
|
d = BR_MULDIV(c,l,fw.material->power-BR_MUL(fw.material->power,c)+c);
|
|
|
|
lcomp[L_R] += d;
|
|
lcomp[L_G] += d;
|
|
lcomp[L_B] += d;
|
|
}
|
|
}
|
|
|
|
lcomp[L_R] = BR_MUL(lcomp[L_R],BrFixedToScalar(BR_RED(alp->light->colour) << 8));
|
|
lcomp[L_G] = BR_MUL(lcomp[L_G],BrFixedToScalar(BR_GRN(alp->light->colour) << 8));
|
|
lcomp[L_B] = BR_MUL(lcomp[L_B],BrFixedToScalar(BR_BLU(alp->light->colour) << 8));
|
|
} else
|
|
lcomp[L_R] = lcomp[L_G] = lcomp[L_B] = BR_SCALAR(0.0);
|
|
}
|
|
|
|
/*
|
|
* Lighting for point light source with attenuation
|
|
* Colour
|
|
*/
|
|
void LightingColour_PointAttn(br_vector3 *p, br_fvector3 *n, br_active_light *alp, br_scalar *lcomp)
|
|
{
|
|
br_scalar c,d,d2,rd,i,power,l;
|
|
br_vector3 dirn,dirn_norm,r,sn;
|
|
|
|
/*
|
|
* Work out vector between point and light source
|
|
*/
|
|
BrVector3Sub(&dirn,&alp->position,p);
|
|
|
|
/*
|
|
* Work out attenuation with distance and distance^2
|
|
*/
|
|
d = BrVector3Length(&dirn);
|
|
|
|
if(d == BR_SCALAR(0.0))
|
|
{
|
|
lcomp[L_R]=lcomp[L_G]=lcomp[L_B]=BR_SCALAR(0.0);
|
|
return;
|
|
}
|
|
|
|
if(d >= BR_SCALAR(180.0))
|
|
d2 = BR_SCALAR(32767.0);
|
|
else
|
|
d2 = BR_MUL(d,d);
|
|
|
|
i = alp->light->attenuation_c
|
|
+ BR_MUL(d,alp->light->attenuation_l)
|
|
+ BR_MUL(d2,alp->light->attenuation_q);
|
|
|
|
d = BR_RCP(d);
|
|
|
|
BrVector3Scale(&dirn_norm,&dirn,d);
|
|
|
|
/*
|
|
* Diffuse
|
|
*/
|
|
|
|
c = BrFVector3Dot(n,&dirn_norm);
|
|
|
|
if(c > BR_SCALAR(0.0)) {
|
|
|
|
c = BR_MUL(alp->intensity,BR_MUL(c,fw.material->kd));
|
|
|
|
lcomp[L_R] = BR_MUL(c,BrFixedToScalar(BR_RED(fw.material->colour) << 8));
|
|
lcomp[L_G] = BR_MUL(c,BrFixedToScalar(BR_GRN(fw.material->colour) << 8));
|
|
lcomp[L_B] = BR_MUL(c,BrFixedToScalar(BR_BLU(fw.material->colour) << 8));
|
|
|
|
if (fw.material->ks != BR_SCALAR(0.0)) {
|
|
/*
|
|
* Specular
|
|
*/
|
|
BrVector3CopyF(&sn,n);
|
|
rd = BR_CONST_MUL(BrVector3Dot(&dirn_norm,&sn),2);
|
|
BrVector3Scale(&r,&sn,rd);
|
|
BrVector3Sub(&r,&r,&dirn_norm);
|
|
|
|
c = BrVector3Dot(&fw.eye_l,&r);
|
|
|
|
/*
|
|
* Phong lighting approximation from Gems IV pg. 385
|
|
*/
|
|
if(c > SPECULARPOW_CUTOFF) {
|
|
l = BR_MUL(fw.material->ks,alp->intensity);
|
|
d = BR_MULDIV(c,l,fw.material->power-BR_MUL(fw.material->power,c)+c);
|
|
|
|
lcomp[L_R] += d;
|
|
lcomp[L_G] += d;
|
|
lcomp[L_B] += d;
|
|
}
|
|
}
|
|
|
|
lcomp[L_R] = BR_MULDIV(lcomp[L_R],BrFixedToScalar(BR_RED(alp->light->colour) << 8),i);
|
|
lcomp[L_G] = BR_MULDIV(lcomp[L_G],BrFixedToScalar(BR_GRN(alp->light->colour) << 8),i);
|
|
lcomp[L_B] = BR_MULDIV(lcomp[L_B],BrFixedToScalar(BR_BLU(alp->light->colour) << 8),i);
|
|
} else
|
|
lcomp[L_R] = lcomp[L_G] = lcomp[L_B] = BR_SCALAR(0.0);
|
|
}
|
|
|
|
|
|
/*
|
|
* Lighting for spot light source
|
|
* True colour
|
|
*/
|
|
void LightingColour_Spot(br_vector3 *p, br_fvector3 *n, br_active_light *alp,br_scalar *lcomp)
|
|
{
|
|
br_scalar c,rd,i = alp->intensity,power,l,d;
|
|
br_vector3 dirn,dirn_norm,r,sn;
|
|
|
|
/*
|
|
* Work out vector between point and light source
|
|
*/
|
|
BrVector3Sub(&dirn,&alp->position,p);
|
|
BrVector3Normalise(&dirn_norm,&dirn);
|
|
|
|
/*
|
|
* Check cutoff
|
|
*/
|
|
c = BrVector3Dot(&dirn_norm,&alp->direction);
|
|
|
|
if(c < alp->spot_cosine_outer)
|
|
{
|
|
lcomp[L_R]=lcomp[L_G]=lcomp[L_B]=BR_SCALAR(0.0);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Falloff between inner and outer cones
|
|
*/
|
|
if(c < alp->spot_cosine_inner)
|
|
i = BR_MULDIV(i,alp->spot_cosine_outer - c,
|
|
alp->spot_cosine_outer - alp->spot_cosine_inner);
|
|
|
|
/*
|
|
* Diffuse
|
|
*/
|
|
|
|
c = BrFVector3Dot(n,&dirn_norm);
|
|
|
|
if(c > BR_SCALAR(0.0)) {
|
|
|
|
c = BR_MUL(alp->intensity,BR_MUL(c,fw.material->kd));
|
|
|
|
lcomp[L_R] = BR_MUL(c,BrFixedToScalar(BR_RED(fw.material->colour) << 8));
|
|
lcomp[L_G] = BR_MUL(c,BrFixedToScalar(BR_GRN(fw.material->colour) << 8));
|
|
lcomp[L_B] = BR_MUL(c,BrFixedToScalar(BR_BLU(fw.material->colour) << 8));
|
|
|
|
if (fw.material->ks != BR_SCALAR(0.0)) {
|
|
/*
|
|
* Specular
|
|
*/
|
|
BrVector3CopyF(&sn,n);
|
|
rd = BR_CONST_MUL(BrVector3Dot(&dirn_norm,&sn),2);
|
|
BrVector3Scale(&r,&sn,rd);
|
|
BrVector3Sub(&r,&r,&dirn_norm);
|
|
|
|
c = BrVector3Dot(&fw.eye_l,&r);
|
|
|
|
/*
|
|
* Phong lighting approximation from Gems IV pg. 385
|
|
*/
|
|
if(c > SPECULARPOW_CUTOFF) {
|
|
l = BR_MUL(fw.material->ks,alp->intensity);
|
|
d = BR_MULDIV(c,l,fw.material->power-BR_MUL(fw.material->power,c)+c);
|
|
|
|
lcomp[L_R] += d;
|
|
lcomp[L_G] += d;
|
|
lcomp[L_B] += d;
|
|
}
|
|
}
|
|
|
|
lcomp[L_R] = BR_MUL(lcomp[L_R],BrFixedToScalar(BR_RED(alp->light->colour) << 8));
|
|
lcomp[L_G] = BR_MUL(lcomp[L_G],BrFixedToScalar(BR_GRN(alp->light->colour) << 8));
|
|
lcomp[L_B] = BR_MUL(lcomp[L_B],BrFixedToScalar(BR_BLU(alp->light->colour) << 8));
|
|
|
|
lcomp[L_R] = BR_MUL(lcomp[L_R],i);
|
|
lcomp[L_G] = BR_MUL(lcomp[L_G],i);
|
|
lcomp[L_B] = BR_MUL(lcomp[L_B],i);
|
|
} else
|
|
lcomp[L_R] = lcomp[L_G] = lcomp[L_B] = BR_SCALAR(0.0);
|
|
}
|
|
|
|
/*
|
|
* Lighting for spot light source with attenuation
|
|
* True colour
|
|
*/
|
|
void LightingColour_SpotAttn(br_vector3 *p, br_fvector3 *n, br_active_light *alp,br_scalar *lcomp)
|
|
{
|
|
br_scalar c,d,d2,rd,i,power,l;
|
|
br_vector3 dirn,dirn_norm,r,sn;
|
|
|
|
/*
|
|
* Work out vector between point and light source
|
|
*/
|
|
BrVector3Sub(&dirn,&alp->position,p);
|
|
|
|
d = BrVector3Length(&dirn);
|
|
|
|
if(d == BR_SCALAR(0.0)) {
|
|
lcomp[L_R]=lcomp[L_G]=lcomp[L_B]=BR_SCALAR(0.0);
|
|
return;
|
|
}
|
|
|
|
d2 = BR_RCP(d);
|
|
BrVector3Scale(&dirn_norm,&dirn,d2);
|
|
|
|
/*
|
|
* Check cutoff
|
|
*/
|
|
c = BrVector3Dot(&dirn_norm,&alp->direction);
|
|
|
|
if(c < alp->spot_cosine_outer)
|
|
{
|
|
lcomp[L_R]=lcomp[L_G]=lcomp[L_B]=BR_SCALAR(0.0);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Work out attenuation with distance and distance^2
|
|
*/
|
|
|
|
if(d == BR_SCALAR(0.0))
|
|
{
|
|
lcomp[L_R]=lcomp[L_G]=lcomp[L_B]=BR_SCALAR(0.0);
|
|
return;
|
|
}
|
|
|
|
if(d >= BR_SCALAR(180.0))
|
|
d2 = BR_SCALAR(32767.0);
|
|
else
|
|
d2 = BR_MUL(d,d);
|
|
|
|
i = alp->light->attenuation_c
|
|
+ BR_MUL(d,alp->light->attenuation_l)
|
|
+ BR_MUL(d2,alp->light->attenuation_q);
|
|
|
|
i = BR_RCP(i);
|
|
|
|
/*
|
|
* Falloff between inner and outer cones
|
|
*/
|
|
if(c < alp->spot_cosine_inner)
|
|
i = BR_MULDIV(i,alp->spot_cosine_outer - c,
|
|
alp->spot_cosine_outer - alp->spot_cosine_inner);
|
|
|
|
/*
|
|
* Diffuse
|
|
*/
|
|
|
|
c = BrFVector3Dot(n,&dirn_norm);
|
|
|
|
if(c > BR_SCALAR(0.0)) {
|
|
|
|
c = BR_MUL(alp->intensity,BR_MUL(c,fw.material->kd));
|
|
|
|
lcomp[L_R] = BR_MUL(c,BrFixedToScalar(BR_RED(fw.material->colour) << 8));
|
|
lcomp[L_G] = BR_MUL(c,BrFixedToScalar(BR_GRN(fw.material->colour) << 8));
|
|
lcomp[L_B] = BR_MUL(c,BrFixedToScalar(BR_BLU(fw.material->colour) << 8));
|
|
|
|
if (fw.material->ks != BR_SCALAR(0.0)) {
|
|
/*
|
|
* Specular
|
|
*/
|
|
BrVector3CopyF(&sn,n);
|
|
rd = BR_CONST_MUL(BrVector3Dot(&dirn_norm,&sn),2);
|
|
BrVector3Scale(&r,&sn,rd);
|
|
BrVector3Sub(&r,&r,&dirn_norm);
|
|
|
|
c = BrVector3Dot(&fw.eye_l,&r);
|
|
|
|
/*
|
|
* Phong lighting approximation from Gems IV pg. 385
|
|
*/
|
|
if(c > SPECULARPOW_CUTOFF) {
|
|
l = BR_MUL(fw.material->ks,alp->intensity);
|
|
d = BR_MULDIV(c,l,fw.material->power-BR_MUL(fw.material->power,c)+c);
|
|
|
|
lcomp[L_R] += d;
|
|
lcomp[L_G] += d;
|
|
lcomp[L_B] += d;
|
|
}
|
|
}
|
|
|
|
lcomp[L_R] = BR_MUL(lcomp[L_R],BrFixedToScalar(BR_RED(alp->light->colour) << 8));
|
|
lcomp[L_G] = BR_MUL(lcomp[L_G],BrFixedToScalar(BR_GRN(alp->light->colour) << 8));
|
|
lcomp[L_B] = BR_MUL(lcomp[L_B],BrFixedToScalar(BR_BLU(alp->light->colour) << 8));
|
|
|
|
lcomp[L_R] = BR_MUL(lcomp[L_R],i);
|
|
lcomp[L_G] = BR_MUL(lcomp[L_G],i);
|
|
lcomp[L_B] = BR_MUL(lcomp[L_B],i);
|
|
|
|
} else
|
|
lcomp[L_R] = lcomp[L_G] = lcomp[L_B] = BR_SCALAR(0.0);
|
|
}
|