mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 10:35:28 +00:00
608 lines
20 KiB
C
608 lines
20 KiB
C
|
/* $Id: shade.c,v 1.10 1997/12/18 02:54:48 brianp Exp $ */
|
||
|
|
||
|
/*
|
||
|
* Mesa 3-D graphics library
|
||
|
* Version: 2.6
|
||
|
* Copyright (C) 1995-1997 Brian Paul
|
||
|
*
|
||
|
* This library is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU Library General Public
|
||
|
* License as published by the Free Software Foundation; either
|
||
|
* version 2 of the License, or (at your option) any later version.
|
||
|
*
|
||
|
* This library is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* Library General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Library General Public
|
||
|
* License along with this library; if not, write to the Free
|
||
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
|
*/
|
||
|
|
||
|
|
||
|
/*
|
||
|
* $Log: shade.c,v $
|
||
|
* Revision 1.10 1997/12/18 02:54:48 brianp
|
||
|
* now using FloatToInt() macro for better performance on x86
|
||
|
*
|
||
|
* Revision 1.9 1997/07/24 01:21:56 brianp
|
||
|
* changed precompiled header symbol from PCH to PC_HEADER
|
||
|
*
|
||
|
* Revision 1.8 1997/07/09 03:04:44 brianp
|
||
|
* fixed bug in gl_color_shade_vertices() with GL_COLOR_MATERIAL
|
||
|
*
|
||
|
* Revision 1.7 1997/07/05 16:24:26 brianp
|
||
|
* fixed FP underflow problem in pow(). Renamed h[xyz] to h_[xyz].
|
||
|
*
|
||
|
* Revision 1.6 1997/06/20 04:15:43 brianp
|
||
|
* optimized changing of SHININESS (Henk Kok)
|
||
|
*
|
||
|
* Revision 1.5 1997/06/20 02:28:40 brianp
|
||
|
* changed color components from GLfixed to GLubyte
|
||
|
*
|
||
|
* Revision 1.4 1997/05/28 03:26:29 brianp
|
||
|
* added precompiled header (PCH) support
|
||
|
*
|
||
|
* Revision 1.3 1997/05/23 03:01:18 brianp
|
||
|
* commented out a few const keywords because IRIX cc chokes on them
|
||
|
*
|
||
|
* Revision 1.2 1997/05/09 02:41:08 brianp
|
||
|
* call GL_SQRT() instead of sqrt()
|
||
|
*
|
||
|
* Revision 1.1 1997/04/01 04:11:04 brianp
|
||
|
* Initial revision
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
|
||
|
#ifdef PC_HEADER
|
||
|
#include "all.h"
|
||
|
#else
|
||
|
#include <math.h>
|
||
|
#include "macros.h"
|
||
|
#include "mmath.h"
|
||
|
#include "shade.h"
|
||
|
#include "types.h"
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Return x^y.
|
||
|
*/
|
||
|
static GLfloat gl_pow( GLfloat x, GLfloat y )
|
||
|
{
|
||
|
GLdouble z = pow(x, y);
|
||
|
if (z<1.0e-10)
|
||
|
return 0.0F;
|
||
|
else
|
||
|
return (GLfloat) z;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Use current lighting/material settings to compute the RGBA colors of
|
||
|
* an array of vertexes.
|
||
|
* Input: side - 0=use front material, 1=use back material
|
||
|
* n - number of vertexes to process
|
||
|
* vertex - array of vertex positions in eye coordinates
|
||
|
* normal - array of surface normal vectors
|
||
|
* Output: color - array of resulting colors
|
||
|
*/
|
||
|
void gl_color_shade_vertices( GLcontext *ctx,
|
||
|
GLuint side,
|
||
|
GLuint n,
|
||
|
/*const*/ GLfloat vertex[][4],
|
||
|
/*const*/ GLfloat normal[][3],
|
||
|
GLubyte color[][4] )
|
||
|
{
|
||
|
GLint j;
|
||
|
GLfloat rscale, gscale, bscale, ascale;
|
||
|
GLfloat baseR, baseG, baseB, baseA;
|
||
|
GLint sumA;
|
||
|
struct gl_light *light;
|
||
|
struct gl_material *mat;
|
||
|
|
||
|
/* Compute scale factor to go from floats in [0,1] to integers or fixed
|
||
|
* point values:
|
||
|
*/
|
||
|
rscale = ctx->Visual->RedScale;
|
||
|
gscale = ctx->Visual->GreenScale;
|
||
|
bscale = ctx->Visual->BlueScale;
|
||
|
ascale = ctx->Visual->AlphaScale;
|
||
|
|
||
|
mat = &ctx->Light.Material[side];
|
||
|
|
||
|
/*** Compute color contribution from global lighting ***/
|
||
|
baseR = mat->Emission[0] + ctx->Light.Model.Ambient[0] * mat->Ambient[0];
|
||
|
baseG = mat->Emission[1] + ctx->Light.Model.Ambient[1] * mat->Ambient[1];
|
||
|
baseB = mat->Emission[2] + ctx->Light.Model.Ambient[2] * mat->Ambient[2];
|
||
|
baseA = mat->Diffuse[3]; /* Alpha is simple, same for all vertices */
|
||
|
|
||
|
sumA = (GLint) (CLAMP( baseA, 0.0F, 1.0F ) * ascale);
|
||
|
|
||
|
for (j=0;j<n;j++) {
|
||
|
GLfloat sumR, sumG, sumB;
|
||
|
GLfloat nx, ny, nz;
|
||
|
|
||
|
if (side==0) {
|
||
|
/* shade frontside */
|
||
|
nx = normal[j][0];
|
||
|
ny = normal[j][1];
|
||
|
nz = normal[j][2];
|
||
|
}
|
||
|
else {
|
||
|
/* shade backside */
|
||
|
nx = -normal[j][0];
|
||
|
ny = -normal[j][1];
|
||
|
nz = -normal[j][2];
|
||
|
}
|
||
|
|
||
|
sumR = baseR;
|
||
|
sumG = baseG;
|
||
|
sumB = baseB;
|
||
|
|
||
|
/* Add contribution from each enabled light source */
|
||
|
for (light=ctx->Light.FirstEnabled; light; light=light->NextEnabled) {
|
||
|
GLfloat ambientR, ambientG, ambientB;
|
||
|
GLfloat attenuation, spot;
|
||
|
GLfloat VPx, VPy, VPz; /* unit vector from vertex to light */
|
||
|
GLfloat n_dot_VP; /* n dot VP */
|
||
|
|
||
|
/* compute VP and attenuation */
|
||
|
if (light->Position[3]==0.0) {
|
||
|
/* directional light */
|
||
|
VPx = light->VP_inf_norm[0];
|
||
|
VPy = light->VP_inf_norm[1];
|
||
|
VPz = light->VP_inf_norm[2];
|
||
|
attenuation = 1.0F;
|
||
|
}
|
||
|
else {
|
||
|
/* positional light */
|
||
|
GLfloat d; /* distance from vertex to light */
|
||
|
VPx = light->Position[0] - vertex[j][0];
|
||
|
VPy = light->Position[1] - vertex[j][1];
|
||
|
VPz = light->Position[2] - vertex[j][2];
|
||
|
d = (GLfloat) GL_SQRT( VPx*VPx + VPy*VPy + VPz*VPz );
|
||
|
if (d>0.001F) {
|
||
|
GLfloat invd = 1.0F / d;
|
||
|
VPx *= invd;
|
||
|
VPy *= invd;
|
||
|
VPz *= invd;
|
||
|
}
|
||
|
attenuation = 1.0F / (light->ConstantAttenuation
|
||
|
+ d * (light->LinearAttenuation
|
||
|
+ d * light->QuadraticAttenuation));
|
||
|
}
|
||
|
|
||
|
/* spotlight factor */
|
||
|
if (light->SpotCutoff==180.0F) {
|
||
|
/* not a spot light */
|
||
|
spot = 1.0F;
|
||
|
}
|
||
|
else {
|
||
|
GLfloat PVx, PVy, PVz, PV_dot_dir;
|
||
|
PVx = -VPx;
|
||
|
PVy = -VPy;
|
||
|
PVz = -VPz;
|
||
|
PV_dot_dir = PVx*light->NormDirection[0]
|
||
|
+ PVy*light->NormDirection[1]
|
||
|
+ PVz*light->NormDirection[2];
|
||
|
if (PV_dot_dir<=0.0F || PV_dot_dir<light->CosCutoff) {
|
||
|
/* outside of cone */
|
||
|
spot = 0.0F;
|
||
|
}
|
||
|
else {
|
||
|
double x = PV_dot_dir * (EXP_TABLE_SIZE-1);
|
||
|
int k = (int) x;
|
||
|
spot = light->SpotExpTable[k][0]
|
||
|
+ (x-k)*light->SpotExpTable[k][1];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ambientR = mat->Ambient[0] * light->Ambient[0];
|
||
|
ambientG = mat->Ambient[1] * light->Ambient[1];
|
||
|
ambientB = mat->Ambient[2] * light->Ambient[2];
|
||
|
|
||
|
/* Compute dot product or normal and vector from V to light pos */
|
||
|
n_dot_VP = nx * VPx + ny * VPy + nz * VPz;
|
||
|
|
||
|
/* diffuse and specular terms */
|
||
|
if (n_dot_VP<=0.0F) {
|
||
|
/* surface face away from light, no diffuse or specular */
|
||
|
GLfloat t = attenuation * spot;
|
||
|
sumR += t * ambientR;
|
||
|
sumG += t * ambientG;
|
||
|
sumB += t * ambientB;
|
||
|
/* done with this light */
|
||
|
}
|
||
|
else {
|
||
|
GLfloat diffuseR, diffuseG, diffuseB;
|
||
|
GLfloat specularR, specularG, specularB;
|
||
|
GLfloat h_x, h_y, h_z, n_dot_h, t;
|
||
|
|
||
|
/* diffuse term */
|
||
|
diffuseR = n_dot_VP * mat->Diffuse[0] * light->Diffuse[0];
|
||
|
diffuseG = n_dot_VP * mat->Diffuse[1] * light->Diffuse[1];
|
||
|
diffuseB = n_dot_VP * mat->Diffuse[2] * light->Diffuse[2];
|
||
|
|
||
|
/* specular term */
|
||
|
if (ctx->Light.Model.LocalViewer) {
|
||
|
GLfloat vx, vy, vz, vlen;
|
||
|
vx = vertex[j][0];
|
||
|
vy = vertex[j][1];
|
||
|
vz = vertex[j][2];
|
||
|
vlen = GL_SQRT( vx*vx + vy*vy + vz*vz );
|
||
|
if (vlen>0.0001F) {
|
||
|
GLfloat invlen = 1.0F / vlen;
|
||
|
vx *= invlen;
|
||
|
vy *= invlen;
|
||
|
vz *= invlen;
|
||
|
}
|
||
|
/* h = VP + VPe */
|
||
|
h_x = VPx - vx;
|
||
|
h_y = VPy - vy;
|
||
|
h_z = VPz - vz;
|
||
|
}
|
||
|
else {
|
||
|
/* h = VP + <0,0,1> */
|
||
|
h_x = VPx;
|
||
|
h_y = VPy;
|
||
|
h_z = VPz + 1.0F;
|
||
|
}
|
||
|
|
||
|
/* attention: h is not normalized, done later if needed */
|
||
|
n_dot_h = nx*h_x + ny*h_y + nz*h_z;
|
||
|
|
||
|
if (n_dot_h<=0.0F) {
|
||
|
specularR = 0.0F;
|
||
|
specularG = 0.0F;
|
||
|
specularB = 0.0F;
|
||
|
}
|
||
|
else {
|
||
|
GLfloat spec_coef;
|
||
|
/* now `correct' the dot product */
|
||
|
n_dot_h = n_dot_h / GL_SQRT( h_x*h_x + h_y*h_y + h_z*h_z );
|
||
|
if (n_dot_h>1.0F) {
|
||
|
/* only happens if normal vector length > 1.0 */
|
||
|
spec_coef = pow( n_dot_h, mat->Shininess );
|
||
|
}
|
||
|
else {
|
||
|
/* use table lookup approximation */
|
||
|
int k = (int) (n_dot_h * (GLfloat) (SHINE_TABLE_SIZE-1));
|
||
|
if (mat->ShineTable[k] < 0.0F)
|
||
|
mat->ShineTable[k] = gl_pow( n_dot_h, mat->Shininess );
|
||
|
spec_coef = mat->ShineTable[k];
|
||
|
}
|
||
|
if (spec_coef<1.0e-10) {
|
||
|
specularR = 0.0F;
|
||
|
specularG = 0.0F;
|
||
|
specularB = 0.0F;
|
||
|
}
|
||
|
else {
|
||
|
specularR = spec_coef * mat->Specular[0]*light->Specular[0];
|
||
|
specularG = spec_coef * mat->Specular[1]*light->Specular[1];
|
||
|
specularB = spec_coef * mat->Specular[2]*light->Specular[2];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
t = attenuation * spot;
|
||
|
sumR += t * (ambientR + diffuseR + specularR);
|
||
|
sumG += t * (ambientG + diffuseG + specularG);
|
||
|
sumB += t * (ambientB + diffuseB + specularB);
|
||
|
}
|
||
|
|
||
|
} /*loop over lights*/
|
||
|
|
||
|
/* clamp and convert to integer or fixed point */
|
||
|
color[j][0] = FloatToInt(CLAMP( sumR, 0.0F, 1.0F ) * rscale);
|
||
|
color[j][1] = FloatToInt(CLAMP( sumG, 0.0F, 1.0F ) * gscale);
|
||
|
color[j][2] = FloatToInt(CLAMP( sumB, 0.0F, 1.0F ) * bscale);
|
||
|
color[j][3] = sumA;
|
||
|
|
||
|
} /*loop over vertices*/
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* This is an optimized version of the above function.
|
||
|
*/
|
||
|
void gl_color_shade_vertices_fast( GLcontext *ctx,
|
||
|
GLuint side,
|
||
|
GLuint n,
|
||
|
/*const*/ GLfloat normal[][3],
|
||
|
GLubyte color[][4] )
|
||
|
{
|
||
|
GLint j;
|
||
|
GLfloat rscale, gscale, bscale, ascale;
|
||
|
GLint sumA;
|
||
|
GLfloat *baseColor = ctx->Light.BaseColor[side];
|
||
|
|
||
|
/* Compute scale factor to go from floats in [0,1] to integers or fixed
|
||
|
* point values:
|
||
|
*/
|
||
|
rscale = ctx->Visual->RedScale;
|
||
|
gscale = ctx->Visual->GreenScale;
|
||
|
bscale = ctx->Visual->BlueScale;
|
||
|
ascale = ctx->Visual->AlphaScale;
|
||
|
|
||
|
/* Alpha is easy to compute, same for all vertices */
|
||
|
sumA = (GLint) (baseColor[3] * ascale);
|
||
|
|
||
|
/* Loop over vertices */
|
||
|
for (j=0;j<n;j++) {
|
||
|
GLfloat sumR, sumG, sumB;
|
||
|
GLfloat nx, ny, nz;
|
||
|
struct gl_light *light;
|
||
|
|
||
|
/* the normal vector */
|
||
|
if (side==0) {
|
||
|
nx = normal[j][0];
|
||
|
ny = normal[j][1];
|
||
|
nz = normal[j][2];
|
||
|
}
|
||
|
else {
|
||
|
nx = -normal[j][0];
|
||
|
ny = -normal[j][1];
|
||
|
nz = -normal[j][2];
|
||
|
}
|
||
|
|
||
|
#ifdef SPEED_HACK
|
||
|
if (nz<0.0F) {
|
||
|
color[j][0] = 0.0F;
|
||
|
color[j][1] = 0.0F;
|
||
|
color[j][2] = 0.0F;
|
||
|
color[j][3] = A;
|
||
|
continue;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/* base color from global illumination and enabled light's ambient */
|
||
|
sumR = baseColor[0];
|
||
|
sumG = baseColor[1];
|
||
|
sumB = baseColor[2];
|
||
|
|
||
|
/* Add contribution from each light source */
|
||
|
for (light=ctx->Light.FirstEnabled; light; light=light->NextEnabled) {
|
||
|
GLfloat n_dot_VP; /* n dot VP */
|
||
|
|
||
|
n_dot_VP = nx * light->VP_inf_norm[0]
|
||
|
+ ny * light->VP_inf_norm[1]
|
||
|
+ nz * light->VP_inf_norm[2];
|
||
|
|
||
|
/* diffuse and specular terms */
|
||
|
if (n_dot_VP>0.0F) {
|
||
|
GLfloat n_dot_h;
|
||
|
GLfloat *lightMatDiffuse = light->MatDiffuse[side];
|
||
|
|
||
|
/** add diffuse term **/
|
||
|
sumR += n_dot_VP * lightMatDiffuse[0];
|
||
|
sumG += n_dot_VP * lightMatDiffuse[1];
|
||
|
sumB += n_dot_VP * lightMatDiffuse[2];
|
||
|
|
||
|
/** specular term **/
|
||
|
/* dot product of n and h_inf_norm */
|
||
|
n_dot_h = nx * light->h_inf_norm[0]
|
||
|
+ ny * light->h_inf_norm[1]
|
||
|
+ nz * light->h_inf_norm[2];
|
||
|
if (n_dot_h>0.0F) {
|
||
|
if (n_dot_h>1.0F) {
|
||
|
/* only happens if Magnitude(n) > 1.0 */
|
||
|
GLfloat spec_coef = pow( n_dot_h,
|
||
|
ctx->Light.Material[side].Shininess );
|
||
|
if (spec_coef>1.0e-10F) {
|
||
|
sumR += spec_coef * light->MatSpecular[side][0];
|
||
|
sumG += spec_coef * light->MatSpecular[side][1];
|
||
|
sumB += spec_coef * light->MatSpecular[side][2];
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
/* use table lookup approximation */
|
||
|
int k = (int) (n_dot_h * (GLfloat) (SHINE_TABLE_SIZE-1));
|
||
|
struct gl_material *m = &ctx->Light.Material[side];
|
||
|
GLfloat spec_coef;
|
||
|
if (m->ShineTable[k] < 0.0F)
|
||
|
m->ShineTable[k] = gl_pow( n_dot_h, m->Shininess );
|
||
|
spec_coef = m->ShineTable[k];
|
||
|
sumR += spec_coef * light->MatSpecular[side][0];
|
||
|
sumG += spec_coef * light->MatSpecular[side][1];
|
||
|
sumB += spec_coef * light->MatSpecular[side][2];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} /*loop over lights*/
|
||
|
|
||
|
/* clamp and convert to integer or fixed point */
|
||
|
color[j][0] = FloatToInt(MIN2( sumR, 1.0F ) * rscale);
|
||
|
color[j][1] = FloatToInt(MIN2( sumG, 1.0F ) * gscale);
|
||
|
color[j][2] = FloatToInt(MIN2( sumB, 1.0F ) * bscale);
|
||
|
color[j][3] = sumA;
|
||
|
|
||
|
} /*loop over vertices*/
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Use current lighting/material settings to compute the color indexes
|
||
|
* for an array of vertices.
|
||
|
* Input: n - number of vertices to shade
|
||
|
* side - 0=use front material, 1=use back material
|
||
|
* vertex - array of [n] vertex position in eye coordinates
|
||
|
* normal - array of [n] surface normal vector
|
||
|
* Output: indexResult - resulting array of [n] color indexes
|
||
|
*/
|
||
|
void gl_index_shade_vertices( GLcontext *ctx,
|
||
|
GLuint side,
|
||
|
GLuint n,
|
||
|
GLfloat vertex[][4],
|
||
|
GLfloat normal[][3],
|
||
|
GLuint indexResult[] )
|
||
|
{
|
||
|
struct gl_material *mat = &ctx->Light.Material[side];
|
||
|
GLint j;
|
||
|
|
||
|
/* loop over vertices */
|
||
|
for (j=0;j<n;j++) {
|
||
|
GLfloat index;
|
||
|
GLfloat diffuse, specular; /* accumulated diffuse and specular */
|
||
|
GLfloat nx, ny, nz; /* normal vector */
|
||
|
struct gl_light *light;
|
||
|
|
||
|
if (side==0) {
|
||
|
/* shade frontside */
|
||
|
nx = normal[j][0];
|
||
|
ny = normal[j][1];
|
||
|
nz = normal[j][2];
|
||
|
}
|
||
|
else {
|
||
|
/* shade backside */
|
||
|
nx = -normal[j][0];
|
||
|
ny = -normal[j][1];
|
||
|
nz = -normal[j][2];
|
||
|
}
|
||
|
|
||
|
diffuse = specular = 0.0F;
|
||
|
|
||
|
/* Accumulate diffuse and specular from each light source */
|
||
|
for (light=ctx->Light.FirstEnabled; light; light=light->NextEnabled) {
|
||
|
GLfloat attenuation;
|
||
|
GLfloat lx, ly, lz; /* unit vector from vertex to light */
|
||
|
GLfloat l_dot_norm; /* dot product of l and n */
|
||
|
|
||
|
/* compute l and attenuation */
|
||
|
if (light->Position[3]==0.0) {
|
||
|
/* directional light */
|
||
|
/* Effectively, l is a vector from the origin to the light. */
|
||
|
lx = light->VP_inf_norm[0];
|
||
|
ly = light->VP_inf_norm[1];
|
||
|
lz = light->VP_inf_norm[2];
|
||
|
attenuation = 1.0F;
|
||
|
}
|
||
|
else {
|
||
|
/* positional light */
|
||
|
GLfloat d; /* distance from vertex to light */
|
||
|
lx = light->Position[0] - vertex[j][0];
|
||
|
ly = light->Position[1] - vertex[j][1];
|
||
|
lz = light->Position[2] - vertex[j][2];
|
||
|
d = (GLfloat) GL_SQRT( lx*lx + ly*ly + lz*lz );
|
||
|
if (d>0.001F) {
|
||
|
GLfloat invd = 1.0F / d;
|
||
|
lx *= invd;
|
||
|
ly *= invd;
|
||
|
lz *= invd;
|
||
|
}
|
||
|
attenuation = 1.0F / (light->ConstantAttenuation
|
||
|
+ d * (light->LinearAttenuation
|
||
|
+ d * light->QuadraticAttenuation));
|
||
|
}
|
||
|
|
||
|
l_dot_norm = lx*nx + ly*ny + lz*nz;
|
||
|
|
||
|
if (l_dot_norm>0.0F) {
|
||
|
GLfloat spot_times_atten;
|
||
|
|
||
|
/* spotlight factor */
|
||
|
if (light->SpotCutoff==180.0F) {
|
||
|
/* not a spot light */
|
||
|
spot_times_atten = attenuation;
|
||
|
}
|
||
|
else {
|
||
|
GLfloat v[3], dot;
|
||
|
v[0] = -lx; /* v points from light to vertex */
|
||
|
v[1] = -ly;
|
||
|
v[2] = -lz;
|
||
|
dot = DOT3( v, light->NormDirection );
|
||
|
if (dot<=0.0F || dot<light->CosCutoff) {
|
||
|
/* outside of cone */
|
||
|
spot_times_atten = 0.0F;
|
||
|
}
|
||
|
else {
|
||
|
double x = dot * (EXP_TABLE_SIZE-1);
|
||
|
int k = (int) x;
|
||
|
GLfloat spot = light->SpotExpTable[k][0]
|
||
|
+ (x-k)*light->SpotExpTable[k][1];
|
||
|
spot_times_atten = spot * attenuation;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* accumulate diffuse term */
|
||
|
diffuse += l_dot_norm * light->dli * spot_times_atten;
|
||
|
|
||
|
/* accumulate specular term */
|
||
|
{
|
||
|
GLfloat h_x, h_y, h_z, n_dot_h, spec_coef;
|
||
|
|
||
|
/* specular term */
|
||
|
if (ctx->Light.Model.LocalViewer) {
|
||
|
GLfloat vx, vy, vz, vlen;
|
||
|
vx = vertex[j][0];
|
||
|
vy = vertex[j][1];
|
||
|
vz = vertex[j][2];
|
||
|
vlen = GL_SQRT( vx*vx + vy*vy + vz*vz );
|
||
|
if (vlen>0.0001F) {
|
||
|
GLfloat invlen = 1.0F / vlen;
|
||
|
vx *= invlen;
|
||
|
vy *= invlen;
|
||
|
vz *= invlen;
|
||
|
}
|
||
|
h_x = lx - vx;
|
||
|
h_y = ly - vy;
|
||
|
h_z = lz - vz;
|
||
|
}
|
||
|
else {
|
||
|
h_x = lx;
|
||
|
h_y = ly;
|
||
|
h_z = lz + 1.0F;
|
||
|
}
|
||
|
/* attention: s is not normalized, done later if necessary */
|
||
|
n_dot_h = h_x*nx + h_y*ny + h_z*nz;
|
||
|
|
||
|
if (n_dot_h <= 0.0F) {
|
||
|
spec_coef = 0.0F;
|
||
|
}
|
||
|
else {
|
||
|
/* now `correct' the dot product */
|
||
|
n_dot_h = n_dot_h / GL_SQRT(h_x*h_x + h_y*h_y + h_z*h_z);
|
||
|
if (n_dot_h>1.0F) {
|
||
|
spec_coef = pow( n_dot_h, mat->Shininess );
|
||
|
}
|
||
|
else {
|
||
|
int k = (int) (n_dot_h * (GLfloat)(SHINE_TABLE_SIZE-1));
|
||
|
if (mat->ShineTable[k] < 0.0F)
|
||
|
mat->ShineTable[k] = gl_pow( n_dot_h, mat->Shininess );
|
||
|
spec_coef = mat->ShineTable[k];
|
||
|
}
|
||
|
}
|
||
|
specular += spec_coef * light->sli * spot_times_atten;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} /*loop over lights*/
|
||
|
|
||
|
/* Now compute final color index */
|
||
|
if (specular>1.0F) {
|
||
|
index = mat->SpecularIndex;
|
||
|
}
|
||
|
else {
|
||
|
GLfloat d_a, s_a;
|
||
|
d_a = mat->DiffuseIndex - mat->AmbientIndex;
|
||
|
s_a = mat->SpecularIndex - mat->AmbientIndex;
|
||
|
|
||
|
index = mat->AmbientIndex
|
||
|
+ diffuse * (1.0F-specular) * d_a
|
||
|
+ specular * s_a;
|
||
|
if (index>mat->SpecularIndex) {
|
||
|
index = mat->SpecularIndex;
|
||
|
}
|
||
|
}
|
||
|
indexResult[j] = (GLuint) (GLint) index;
|
||
|
|
||
|
} /*for vertex*/
|
||
|
}
|
||
|
|