brender-1997/softrend/light8.c

611 lines
14 KiB
C
Raw Permalink Normal View History

2022-05-03 16:30:35 -05:00
/*
* Copyright (c) 1993-1995 Argonaut Technologies Limited. All rights reserved.
*
* $Id: light8.c 2.5 1996/11/11 16:07:54 sam Exp $
* $Locker: $
*
* Bits of the lighting model for indexed pixels
*/
#include "drv.h"
#include "shortcut.h"
#include "brassert.h"
#include "math_ip.h"
#include "lightmac.h"
br_scalar globalAmbient;
BR_RCS_ID("$Id: light8.c 2.5 1996/11/11 16:07:54 sam Exp $");
/*
* Lighting function for unlit indexed
*/
void SURFACE_CALL SurfaceIndexZero(br_renderer *self, br_vector3 *p, br_vector2 *map, br_vector3 *n, br_colour colour, br_scalar *comp)
{
comp[C_I] = self->state.cache.comp_offsets[C_I];
}
/*
* Lighting function for prelit indexed
*/
void SURFACE_CALL SurfaceIndexUnlit(br_renderer *self, br_vector3 *p, br_vector2 *map, br_vector3 *n, br_colour colour, br_scalar *comp)
{
comp[C_I] = BR_MUL(self->state.cache.comp_scales[C_I],
BR_CONST_DIV(BrIntToScalar(BR_ALPHA(colour)),256)) +
self->state.cache.comp_offsets[C_I];
}
/*
* Accumulate lighting for multiple active lights by calling the
* appropriate sub-function for each light
*
* Write the results into comp[C_I]
*/
void SURFACE_CALL SurfaceIndexLit(br_renderer *self, br_vector3 *p, br_vector2 *map, br_vector3 *n, br_colour colour, br_scalar *comp)
{
int i;
struct active_light *alp = scache.lights;
br_vector3 vp;
br_vector3 vn;
br_vector3 fvn;
/*
* Handle special case lighting of 1 model-space directional light
*/
if(scache.light_1md) {
br_scalar l,dot;
dot = BrVector3Dot(n,&alp->direction);
if(dot <= BR_SCALAR(0.0)) {
comp[C_I] = self->state.surface.ka;
CLAMP_SCALE(C_I);
return;
}
l = BR_MUL(dot, self->state.surface.kd);
if (self->state.surface.ks != BR_SCALAR(0.0)) {
/*
* Specular
*/
dot = BrVector3Dot(n,&alp->half);
/*
* Phong lighting approximation from Gems IV pg. 385
*/
if(dot > SPECULARPOW_CUTOFF)
l += SPECULAR_POWER(BR_MUL(self->state.surface.ks,alp->intensity));
}
comp[C_I] = l + self->state.surface.ka;
/*
* Scale final intensity to range of indices
*/
CLAMP_SCALE(C_I);
return;
}
/*
* Ambient component
*/
comp[C_I] = self->state.surface.ka;
/*
* Accumulate intensities for each active light in model space
*/
rend.eye_l = scache.eye_m_normalised;
for(i=0; i < scache.nlights_model; i++, alp++)
alp->accumulate_index(self, p, n, alp, comp);
/*
* See if any lights are to be calculated in view space
*/
if(scache.nlights_view) {
/*
* Transform point and normal into view space ...
*/
BrMatrix34ApplyP(&vp, p, &self->state.matrix.model_to_view);
BrMatrix34TApplyV(&vn, n, &scache.view_to_model);
BrVector3Normalise(&fvn, &vn);
rend.eye_l.v[0] = BR_SCALAR(0);
rend.eye_l.v[1] = BR_SCALAR(0);
rend.eye_l.v[2] = BR_SCALAR(1);
/*
* ... and accumulate
*/
for(i=0; i < scache.nlights_view; i++, alp++)
alp->accumulate_index(self, &vp, &fvn, alp, comp);
}
/*
* Scale final intensity to range of indices
*/
CLAMP_SCALE(C_I);
}
void GEOMETRY_CALL GeometryIndexLit(struct br_geometry *self, struct br_renderer *renderer)
{
// initialise vertices to ambient values
int i, v;
struct active_light *alp;
brp_vertex *tvp;
br_scalar s,attn,dist,l,dot,r,g,b,materialRed,materialGreen,materialBlue;
br_vector3 dirn,dirn_norm;
for(v=0,tvp = rend.temp_vertices; v < rend.nvertices; v++, tvp++) {
if(rend.vertex_counts[v] == 0)
continue;
tvp->comp[C_I] = globalAmbient;
}
alp = scache.lights;
// accumulate active lights
for(i=0; i < scache.nlights_model; i++, alp++){
switch(alp->type){
case BRT_DIRECT:
for(v=0,tvp = rend.temp_vertices; v < rend.nvertices; v++, tvp++) {
if(rend.vertex_counts[v] == 0)
continue;
dot = BrVector3Dot(&rend.vertices[v].n,&alp->direction);
// if(dot <= BR_SCALAR(0.0))
if(FP_TO_UINT(dot)&FP_NEG)
continue;
// l=BR_MUL(dot, renderer->state.surface.kd);
tvp->comp[C_I] += dot;
}
break;
case BRT_POINT:
if(useLight[i]){
for(v=0,tvp = rend.temp_vertices; v < rend.nvertices; v++, tvp++) {
if(rend.vertex_counts[v] == 0)
continue;
BrVector3Sub(&dirn,&alp->position,&rend.vertices[v].p);
// CALCULATE_DIRN_NORM_GEOM();
dist = BrVector3Length(&dirn);
// if(dist <= 2 * BR_SCALAR_EPSILON)
if(FP_TO_UINT(dist) <= FP_TO_UINT(epsilonX2))
continue;
s = BR_RCP(dist);
BrVector3Scale(&dirn_norm,&dirn,s);
// CALCULATE_ATTENUATION_GEOM();
if(FP_TO_UINT(dist)>FP_TO_UINT(alp->s->attenuation_q)){
continue;
}else{
if(FP_TO_UINT(dist)>FP_TO_UINT(alp->s->attenuation_c)){
attn=BR_MUL((dist-alp->s->attenuation_c),alp->s->attenuation_l);
}else{
attn=BR_SCALAR(0);
}
}
attn=BR_SCALAR(1)-attn;
// DIFFUSE_DOT_GEOM();
dot = BrVector3Dot(&rend.vertices[v].n,&dirn_norm);
// if(dot <= BR_SCALAR(0.0))
if(FP_TO_UINT(dot)&FP_NEG)
continue;
l = BR_MUL(dot, attn);
tvp->comp[C_I] += l;
}
}
break;
}
}
// clamp and scale
for(v=0,tvp = rend.temp_vertices; v < rend.nvertices; v++, tvp++) {
if(rend.vertex_counts[v] == 0)
continue;
CLAMP_SCALE_GEOM(C_I);
}
}
void SURFACE_CALL VertexIndexLit(br_renderer *self, br_vector3 *p, br_vector2 *map, br_vector3 *n, br_colour colour, br_scalar *comp)
{
int i;
struct active_light *alp;
br_scalar s,attn,dist,l,dot,r,g,b,materialRed,materialGreen,materialBlue;
br_vector3 dirn,dirn_norm;
comp[C_I] = globalAmbient;
alp = scache.lights;
// accumulate active lights
for(i=0; i < scache.nlights_model; i++, alp++){
switch(alp->type){
case BRT_DIRECT:
dot = BrVector3Dot(n,&alp->direction);
// if(dot <= BR_SCALAR(0.0))
if(FP_TO_UINT(dot)&FP_NEG)
continue;
// l=BR_MUL(dot, renderer->state.surface.kd);
comp[C_I] += dot;
break;
case BRT_POINT:
if(useLight[i]){
BrVector3Sub(&dirn,&alp->position,p);
// CALCULATE_DIRN_NORM_GEOM();
dist = BrVector3Length(&dirn);
// if(dist <= 2 * BR_SCALAR_EPSILON)
if(FP_TO_UINT(dist) <= FP_TO_UINT(epsilonX2))
continue;
s = BR_RCP(dist);
BrVector3Scale(&dirn_norm,&dirn,s);
// CALCULATE_ATTENUATION_GEOM();
if(FP_TO_UINT(dist)>FP_TO_UINT(alp->s->attenuation_q)){
continue;
}else{
if(FP_TO_UINT(dist)>FP_TO_UINT(alp->s->attenuation_c)){
attn=BR_MUL((dist-alp->s->attenuation_c),alp->s->attenuation_l);
}else{
attn=BR_SCALAR(0);
}
}
attn=BR_SCALAR(1)-attn;
// DIFFUSE_DOT_GEOM();
dot = BrVector3Dot(n,&dirn_norm);
// if(dot <= BR_SCALAR(0.0))
if(FP_TO_UINT(dot)&FP_NEG)
continue;
l = BR_MUL(dot, attn);
comp[C_I] += l;
}
break;
}
}
// clamp and scale
CLAMP_SCALE(C_I);
}
void BR_ASM_CALL FaceIndexLit(struct brp_block *block, brp_vertex *v0, brp_vertex *v1, brp_vertex *v2,
struct v11face *fp, struct temp_face *tfp)
{
struct fmt_vertex *vp;
int i;
struct active_light *alp;
brp_vertex *tvp = v0;
br_scalar s,attn,dist,l,dot,r,g,b,materialRed,materialGreen,materialBlue;
br_vector3 dirn,dirn_norm;
br_renderer *renderer = rend.renderer;
vp = rend.vertices + fp->vertices[0];
tvp->comp[C_I] = globalAmbient;
alp = scache.lights;
// accumulate active lights
for(i=0; i < scache.nlights_model; i++, alp++){
switch(alp->type){
case BRT_DIRECT:
dot = BrVector3Dot((br_vector3 *)&fp->eqn,&alp->direction);
// if(dot <= BR_SCALAR(0.0))
if(FP_TO_UINT(dot)&FP_NEG)
continue;
// l=BR_MUL(dot, renderer->state.surface.kd);
tvp->comp[C_I] += dot;
break;
case BRT_POINT:
if(useLight[i]){
BrVector3Sub(&dirn,&alp->position,&vp->p);
// CALCULATE_DIRN_NORM_GEOM();
dist = BrVector3Length(&dirn);
// if(dist <= 2 * BR_SCALAR_EPSILON)
if(FP_TO_UINT(dist) <= FP_TO_UINT(epsilonX2))
continue;
s = BR_RCP(dist);
BrVector3Scale(&dirn_norm,&dirn,s);
// CALCULATE_ATTENUATION_GEOM();
if(FP_TO_UINT(dist)>FP_TO_UINT(alp->s->attenuation_q)){
continue;
}else{
if(FP_TO_UINT(dist)>FP_TO_UINT(alp->s->attenuation_c)){
attn=BR_MUL((dist-alp->s->attenuation_c),alp->s->attenuation_l);
}else{
attn=BR_SCALAR(0);
}
}
attn=BR_SCALAR(1)-attn;
// DIFFUSE_DOT_GEOM();
dot = BrVector3Dot((br_vector3 *)&fp->eqn,&dirn_norm);
// if(dot <= BR_SCALAR(0.0))
if(FP_TO_UINT(dot)&FP_NEG)
continue;
l = BR_MUL(dot, attn);
tvp->comp[C_I] += l;
}
break;
}
}
// clamp and scale
CLAMP_SCALE_GEOM(C_I);
block->chain->render(block->chain, v0, v1, v2, fp, tfp);
}
/*
* Lighting function that does nothing
*/
static void lightingIndexNull(br_renderer *self, br_vector3 *p, br_vector3 *n, struct active_light *alp,br_scalar *comp)
{
}
/*
* Lighting for directional light source in model space
*/
static void lightingIndexDirect(br_renderer *self, br_vector3 *p, br_vector3 *n, struct active_light *alp,br_scalar *comp)
{
br_scalar l,dot;
dot = BrVector3Dot(n,&alp->direction);
if(dot <= BR_SCALAR(0.0))
return;
l = BR_MUL(dot, self->state.surface.kd);
if (self->state.surface.ks != BR_SCALAR(0.0)) {
/*
* Specular
*/
dot = BrVector3Dot(n,&alp->half);
/*
* Phong lighting approximation from Gems IV pg. 385
*/
if(dot > SPECULARPOW_CUTOFF)
l += SPECULAR_POWER(BR_MUL(self->state.surface.ks,alp->intensity));
}
comp[C_I] += l;
}
/*
* Lighting for point light source with attenuation
* Index
*/
static void lightingIndexPoint(br_renderer *self, br_vector3 *p, br_vector3 *n, struct active_light *alp, br_scalar *comp)
{
br_scalar l,dot;
br_vector3 dirn,dirn_norm;
/*
* Work out vector between point and light source
*/
BrVector3Sub(&dirn,&alp->position,p);
BrVector3Normalise(&dirn_norm,&dirn);
DIFFUSE_DOT();
l = BR_MUL(dot,self->state.surface.kd);
if (self->state.surface.ks != BR_SCALAR(0.0)) {
/*
* Specular
*/
SPECULAR_DOT();
/*
* Phong lighting approximation from Gems IV pg. 385
*/
if(dot > SPECULARPOW_CUTOFF)
l += SPECULAR_POWER(self->state.surface.ks);
}
comp[C_I] += BR_MUL(l, alp->intensity);
}
/*
* Lighting for point light source with attenuation
* Index
*/
static void lightingIndexPointAttn(br_renderer *self, br_vector3 *p, br_vector3 *n, struct active_light *alp, br_scalar *comp)
{
br_scalar attn,dot,l,dist;
br_vector3 dirn,dirn_norm;
BrVector3Sub(&dirn,&alp->position, p);
CALCULATE_DIRN_NORM();
CALCULATE_ATTENUATION();
DIFFUSE_DOT();
l = BR_MUL(dot, self->state.surface.kd);
if (self->state.surface.ks != BR_SCALAR(0.0)) {
/*
* Specular
*/
SPECULAR_DOT();
/*
* Phong lighting approximation from Gems IV pg. 385
*/
if(dot > SPECULARPOW_CUTOFF)
l += SPECULAR_POWER(self->state.surface.ks);
}
comp[C_I] += BR_MUL(l,attn);
}
/*
* Lighting for spot light source
* Index
*/
static void lightingIndexSpot(br_renderer *self, br_vector3 *p, br_vector3 *n, struct active_light *alp, br_scalar *comp)
{
br_scalar dot_spot, dot, l, attn;
br_vector3 dirn,dirn_norm;
BrVector3Sub(&dirn,&alp->position,p);
BrVector3Normalise(&dirn_norm,&dirn);
SPOT_DOT();
DIFFUSE_DOT();
attn = SPOT_FALLOFF(alp->intensity);
l = BR_MUL(dot, self->state.surface.kd);
if (self->state.surface.ks != BR_SCALAR(0.0)) {
/*
* Specular
*/
SPECULAR_DOT();
/*
* Phong lighting approximation from Gems IV pg. 385
*/
if(dot > SPECULARPOW_CUTOFF)
l += SPECULAR_POWER(self->state.surface.ks);
}
comp[C_I] += BR_MUL(l, attn);
}
/*
* Lighting for spot light source with attenuation
* Index
*/
static void lightingIndexSpotAttn(br_renderer *self, br_vector3 *p, br_vector3 *n, struct active_light *alp,br_scalar *comp)
{
br_scalar dot,dot_spot,dist,attn,l;
br_vector3 dirn,dirn_norm;
BrVector3Sub(&dirn,&alp->position,p);
CALCULATE_DIRN_NORM();
SPOT_DOT();
DIFFUSE_DOT();
CALCULATE_ATTENUATION();
attn = SPOT_FALLOFF(attn);
l = BR_MUL(dot, self->state.surface.kd);
if (self->state.surface.ks != BR_SCALAR(0.0)) {
/*
* Specular
*/
SPECULAR_DOT();
/*
* Phong lighting approximation from Gems IV pg. 385
*/
if(dot > SPECULARPOW_CUTOFF)
l += SPECULAR_POWER(self->state.surface.ks);
}
comp[C_I] += BR_MUL(l, attn);
}
/*
* Select a per-light component accumulation function
*/
void ActiveLightAccumulateIndexSet(struct active_light *alp)
{
switch(alp->type) {
case BRT_DIRECT:
alp->accumulate_index = lightingIndexDirect;
break;
case BRT_POINT:
if(alp->s->attenuation_l == BR_SCALAR(0.0) &&
alp->s->attenuation_q == BR_SCALAR(0.0))
alp->accumulate_index = lightingIndexPoint;
else
alp->accumulate_index = lightingIndexPointAttn;
break;
case BRT_SPOT:
if(alp->s->attenuation_l == BR_SCALAR(0.0) &&
alp->s->attenuation_q == BR_SCALAR(0.0))
alp->accumulate_index = lightingIndexSpot;
else
alp->accumulate_index = lightingIndexSpotAttn;
break;
default:
alp->accumulate_index = lightingIndexNull;
}
}
#if 0
/*
* Special case for 1 directional light in model space
*
* Write the results into comp[C_I]
*/
void SURFACE_CALL SurfaceIndexLit1MD(br_renderer *self, br_vector3 *p, br_vector2 *map, br_vector3 *n, br_colour colour, br_scalar *comp)
{
struct active_light *alp = scache.lights;
br_scalar l,dot;
dot = BrVector3Dot(n,&alp->direction);
if(dot <= BR_SCALAR(0.0))
return;
l = BR_MUL(dot, self->state.surface.kd);
if (self->state.surface.ks != BR_SCALAR(0.0)) {
/*
* Specular
*/
dot = BrVector3Dot(n,&alp->half);
/*
* Phong lighting approximation from Gems IV pg. 385
*/
if(dot > SPECULARPOW_CUTOFF)
l += SPECULAR_POWER(BR_MUL(self->state.surface.ks,alp->intensity));
}
comp[C_I] = l + self->state.surface.ka;
/*
* Scale final intensity to range of indices
*/
CLAMP_SCALE(C_I);
}
#endif