home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 6
/
AACD06.ISO
/
AACD
/
System
/
Mesa-3.1
/
src
/
shade.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-01-07
|
10KB
|
377 lines
/* $Id: shade.c,v 1.3.2.1 1999/11/29 13:41:15 brianp Exp $ */
/*
* Mesa 3-D graphics library
* Version: 3.1
*
* Copyright (C) 1999 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifdef PC_HEADER
#include "all.h"
#else
#ifndef XFree86Server
#include <math.h>
#include <stdio.h>
#else
#include "GL/xf86glx.h"
#endif
#include "light.h"
#include "macros.h"
#include "mmath.h"
#include "shade.h"
#include "pipeline.h"
#include "types.h"
#include "simple_list.h"
#endif
#define GET_SHINE_TAB_ENTRY( tab, dp, result ) \
do { \
int k = (int) (dp * SHINE_TABLE_SIZE); \
result = tab->tab[k]; \
} while(0)
/* Combinatorics:
* rgba_spec/rgba/rgba_fast/ci
* one_side/two_side
* compacted_normals/ordinary_normals
* cull_mask/no_cull_mask
*
* We end up with an award-winning 32 seperate lighting functions.
*/
/* Table of all the shading functions.
*/
gl_shade_func gl_shade_func_tab[0x20];
/* The original case where the normal for vertex[j] is normal[j],
* both stride-aware, and every normal is present.
*/
#define NEXT_NORMAL STRIDE_F(normal, nstride), mask++
#define NEXT_VERTEX_NORMAL STRIDE_F(normal, nstride), mask++
#define STATE_CHANGE(a,b) 1
#define COMPACTED 0
#define TAG(x) x##_one_sided_masked
#define INVALID(x) 0
#define IDX CULL_MASK_ACTIVE
#define LIGHT_FRONT(x) 1
#define LIGHT_REAR(x) 0
#define LIGHT_SIDE(x,y) 1
#define CULL(x) !((x)&VERT_FACE_FLAGS)
#define NR_SIDES 1
#include "shade_tmp.h"
#define TAG(x) x##_one_sided
#define INVALID(x) 0
#define IDX 0
#define LIGHT_FRONT(x) 1
#define LIGHT_REAR(x) 0
#define LIGHT_SIDE(x,y) 1
#define CULL(x) 0
#define NR_SIDES 1
#include "shade_tmp.h"
#define TAG(x) x##_two_sided_masked
#define INVALID(x) ((x)&invalid)
#define IDX SHADE_TWOSIDE|CULL_MASK_ACTIVE
#define LIGHT_FRONT(f) ((f)&VERT_FACE_FRONT)
#define LIGHT_REAR(f) ((f)&VERT_FACE_REAR)
#define LIGHT_SIDE(x,y) ((x)&(y))
#define CULL(x) !((x)&VERT_FACE_FLAGS)
#define NR_SIDES 2
#include "shade_tmp.h"
#define TAG(x) x##_two_sided
#define INVALID(x) 0
#define IDX SHADE_TWOSIDE
#define LIGHT_FRONT(f) 1
#define LIGHT_REAR(f) 1
#define LIGHT_SIDE(x,y) 1
#define CULL(x) 0
#define NR_SIDES 2
#include "shade_tmp.h"
#undef NEXT_NORMAL
#undef NEXT_VERTEX_NORMAL
#undef STATE_CHANGE
#undef COMPACTED
/* The 'compacted normal' case, where we have a sparse list of normals
* with flags indicating a new (valid) normal, as now built by the
* 'glVertex' API routines. We have a small bonus in that we know
* in advance that the normal stride must be 3 floats.
*/
#define NEXT_NORMAL ((flags[j]&VERT_NORM) ? normal=first_normal[j],mask=&cullmask[j] : 0)
#define NEXT_VERTEX_NORMAL ((flags[j]&VERT_NORM) ? normal=first_normal[j],mask=&cullmask[j] : 0)
#define STATE_CHANGE(a,b) (a & b)
#define COMPACTED 1
#define TAG(x) x##_one_sided_masked_compacted
#define INVALID(x) 0
#define IDX COMPACTED_NORMALS|CULL_MASK_ACTIVE
#define LIGHT_FRONT(x) 1
#define LIGHT_REAR(x) 0
#define LIGHT_SIDE(x,y) 1
#define CULL(x) !((x)&VERT_FACE_FLAGS)
#define NR_SIDES 1
#include "shade_tmp.h"
#define TAG(x) x##_one_sided_compacted
#define INVALID(x) 0
#define IDX COMPACTED_NORMALS
#define LIGHT_FRONT(x) 1
#define LIGHT_REAR(x) 0
#define LIGHT_SIDE(x,y) 1
#define CULL(x) 0
#define NR_SIDES 1
#include "shade_tmp.h"
#define TAG(x) x##_two_sided_masked_compacted
#define INVALID(x) ((x)&invalid)
#define IDX COMPACTED_NORMALS|SHADE_TWOSIDE
#define LIGHT_FRONT(f) ((f)&VERT_FACE_FRONT)
#define LIGHT_REAR(f) ((f)&VERT_FACE_REAR)
#define LIGHT_SIDE(x,y) ((x)&(y))
#define CULL(x) !((x)&VERT_FACE_FLAGS)
#define NR_SIDES 2
#include "shade_tmp.h"
#define TAG(x) x##_two_sided_compacted
#define INVALID(x) 0
#define IDX COMPACTED_NORMALS|CULL_MASK_ACTIVE|SHADE_TWOSIDE
#define LIGHT_FRONT(f) 1
#define LIGHT_REAR(f) 1
#define LIGHT_SIDE(x,y) 1
#define CULL(x) 0
#define NR_SIDES 2
#include "shade_tmp.h"
#undef COMPACTED
#undef NEXT_NORMAL
#undef NEXT_VERTEX_NORMAL
#undef STATE_CHANGE
void gl_init_shade( void )
{
init_shade_tab_one_sided();
init_shade_tab_one_sided_masked();
init_shade_tab_one_sided_compacted();
init_shade_tab_one_sided_masked_compacted();
init_shade_tab_two_sided();
init_shade_tab_two_sided_masked();
init_shade_tab_two_sided_compacted();
init_shade_tab_two_sided_masked_compacted();
}
void gl_update_lighting_function( GLcontext *ctx )
{
GLuint idx;
if (ctx->Visual->RGBAflag) {
if (ctx->Light.NeedVertices) {
if (ctx->Texture.Enabled &&
ctx->Light.Model.ColorControl==GL_SEPARATE_SPECULAR_COLOR)
idx = SHADE_RGBA_SPEC;
else
idx = SHADE_RGBA_VERTICES;
}
else
idx = SHADE_RGBA_NORMALS;
}
else
idx = 0;
if (ctx->TriangleCaps & DD_TRI_LIGHT_TWOSIDE) {
idx |= SHADE_TWOSIDE;
}
ctx->shade_func_flags = idx;
}
/* This has been split off to allow the normal shade routines to
* get a little closer to the vertex buffer, and to use the
* GLvector objects directly.
*/
void gl_shade_rastpos( GLcontext *ctx,
GLfloat vertex[4],
GLfloat normal[3],
GLfloat Rcolor[4],
GLuint *index )
{
GLfloat (*base)[3] = ctx->Light.BaseColor;
GLubyte *sumA = ctx->Light.BaseAlpha;
struct gl_light *light;
GLfloat color[4];
GLfloat diffuse = 0, specular = 0;
COPY_3V(color, base[0]);
color[3] = UBYTE_COLOR_TO_FLOAT_COLOR( sumA[0] );
foreach (light, &ctx->Light.EnabledList) {
GLfloat n_dot_h;
GLfloat attenuation = 1.0;
GLfloat VP[3];
GLfloat n_dot_VP;
GLfloat *h;
GLfloat contrib[3];
GLboolean normalized;
if (!(light->Flags & LIGHT_POSITIONAL)) {
COPY_3V(VP, light->VP_inf_norm);
attenuation = light->VP_inf_spot_attenuation;
}
else {
GLfloat d;
SUB_3V(VP, light->Position, vertex);
d = LEN_3FV( VP );
if ( d > 1e-6) {
GLfloat invd = 1.0F / d;
SELF_SCALE_SCALAR_3V(VP, invd);
}
attenuation = 1.0F / (light->ConstantAttenuation + d *
(light->LinearAttenuation + d *
light->QuadraticAttenuation));
if (light->Flags & LIGHT_SPOT)
{
GLfloat PV_dot_dir = - DOT3(VP, light->NormDirection);
if (PV_dot_dir<light->CosCutoff) {
continue;
}
else
{
double x = PV_dot_dir * (EXP_TABLE_SIZE-1);
int k = (int) x;
GLfloat spot = (GLfloat) (light->SpotExpTable[k][0]
+ (x-k)*light->SpotExpTable[k][1]);
attenuation *= spot;
}
}
}
if (attenuation < 1e-3)
continue;
n_dot_VP = DOT3( normal, VP );
if (n_dot_VP < 0.0F) {
ACC_SCALE_SCALAR_3V(color, attenuation, light->MatAmbient[0]);
continue;
}
COPY_3V(contrib, light->MatAmbient[0]);
ACC_SCALE_SCALAR_3V(contrib, n_dot_VP, light->MatDiffuse[0]);
diffuse += n_dot_VP * light->dli * attenuation;
if (light->IsMatSpecular[0]) {
if (ctx->Light.Model.LocalViewer) {
GLfloat v[3];
COPY_3V(v, vertex);
NORMALIZE_3FV(v);
SUB_3V(VP, VP, v);
h = VP;
normalized = 0;
}
else if (light->Flags & LIGHT_POSITIONAL) {
h = VP;
ACC_3V(h, ctx->EyeZDir);
normalized = 0;
}
else {
h = light->h_inf_norm;
normalized = 1;
}
n_dot_h = DOT3(normal, h);
if (n_dot_h > 0.0F) {
struct gl_material *mat = &ctx->Light.Material[0];
GLfloat spec_coef;
GLfloat shininess = mat->Shininess;
if (!normalized) {
n_dot_h *= n_dot_h;
n_dot_h /= LEN_SQUARED_3FV( h );
shininess *= .5;
}
if (n_dot_h>1.0) {
spec_coef = (GLfloat) pow( n_dot_h, shininess );
}
else {
struct gl_shine_tab *tab = ctx->ShineTable[0];
GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec_coef );
}
if (spec_coef > 1.0e-10) {
ACC_SCALE_SCALAR_3V( contrib, spec_coef,
light->MatSpecular[0]);
specular += spec_coef * light->sli * attenuation;
}
}
}
ACC_SCALE_SCALAR_3V( color, attenuation, contrib );
}
if (ctx->Visual->RGBAflag) {
Rcolor[0] = CLAMP(color[0], 0.0F, 1.0F);
Rcolor[1] = CLAMP(color[1], 0.0F, 1.0F);
Rcolor[2] = CLAMP(color[2], 0.0F, 1.0F);
Rcolor[3] = CLAMP(color[3], 0.0F, 1.0F);
}
else {
struct gl_material *mat = &ctx->Light.Material[0];
GLfloat d_a = mat->DiffuseIndex - mat->AmbientIndex;
GLfloat s_a = mat->SpecularIndex - mat->AmbientIndex;
GLfloat ind = mat->AmbientIndex
+ diffuse * (1.0F-specular) * d_a
+ specular * s_a;
if (ind > mat->SpecularIndex) {
ind = mat->SpecularIndex;
}
*index = (GLuint) (GLint) ind;
}
}