home *** CD-ROM | disk | FTP | other *** search
- /* $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;
- }
-
- }
-
-