1 | /* $Id: shade.c,v 1.2 2000-05-23 20:40:53 jeroen Exp $ */
|
---|
2 |
|
---|
3 | /*
|
---|
4 | * Mesa 3-D graphics library
|
---|
5 | * Version: 3.3
|
---|
6 | *
|
---|
7 | * Copyright (C) 1999 Brian Paul All Rights Reserved.
|
---|
8 | *
|
---|
9 | * Permission is hereby granted, free of charge, to any person obtaining a
|
---|
10 | * copy of this software and associated documentation files (the "Software"),
|
---|
11 | * to deal in the Software without restriction, including without limitation
|
---|
12 | * the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
---|
13 | * and/or sell copies of the Software, and to permit persons to whom the
|
---|
14 | * Software is furnished to do so, subject to the following conditions:
|
---|
15 | *
|
---|
16 | * The above copyright notice and this permission notice shall be included
|
---|
17 | * in all copies or substantial portions of the Software.
|
---|
18 | *
|
---|
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
---|
20 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
---|
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
---|
22 | * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
---|
23 | * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
---|
24 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
---|
25 | */
|
---|
26 |
|
---|
27 |
|
---|
28 |
|
---|
29 |
|
---|
30 |
|
---|
31 | #ifdef PC_HEADER
|
---|
32 | #include "all.h"
|
---|
33 | #else
|
---|
34 | #include "glheader.h"
|
---|
35 | #include "light.h"
|
---|
36 | #include "macros.h"
|
---|
37 | #include "mmath.h"
|
---|
38 | #include "shade.h"
|
---|
39 | #include "pipeline.h"
|
---|
40 | #include "types.h"
|
---|
41 | #include "simple_list.h"
|
---|
42 | #endif
|
---|
43 |
|
---|
44 |
|
---|
45 |
|
---|
46 |
|
---|
47 |
|
---|
48 | #define GET_SHINE_TAB_ENTRY( tab, dp, result ) \
|
---|
49 | do { \
|
---|
50 | int k = (int) (dp * SHINE_TABLE_SIZE); \
|
---|
51 | result = tab->tab[k]; \
|
---|
52 | } while(0)
|
---|
53 |
|
---|
54 |
|
---|
55 | /* Combinatorics:
|
---|
56 | * rgba_spec/rgba/rgba_fast/ci
|
---|
57 | * one_side/two_side
|
---|
58 | * compacted_normals/ordinary_normals
|
---|
59 | * cull_mask/no_cull_mask
|
---|
60 | *
|
---|
61 | * We end up with an award-winning 32 seperate lighting functions.
|
---|
62 | */
|
---|
63 |
|
---|
64 |
|
---|
65 | /* Table of all the shading functions.
|
---|
66 | */
|
---|
67 | gl_shade_func gl_shade_func_tab[0x20];
|
---|
68 |
|
---|
69 |
|
---|
70 | /* The original case where the normal for vertex[j] is normal[j],
|
---|
71 | * both stride-aware, and every normal is present.
|
---|
72 | */
|
---|
73 | #define NEXT_NORMAL STRIDE_F(normal, nstride), mask++
|
---|
74 | #define NEXT_VERTEX_NORMAL STRIDE_F(normal, nstride), mask++
|
---|
75 | #define STATE_CHANGE(a,b) 1
|
---|
76 | #define COMPACTED 0
|
---|
77 |
|
---|
78 | #define TAG(x) x##_one_sided_masked
|
---|
79 | #define INVALID(x) 0
|
---|
80 | #define IDX CULL_MASK_ACTIVE
|
---|
81 | #define LIGHT_FRONT(x) 1
|
---|
82 | #define LIGHT_REAR(x) 0
|
---|
83 | #define LIGHT_SIDE(x,y) 1
|
---|
84 | #define CULL(x) !((x)&VERT_FACE_FLAGS)
|
---|
85 | #define NR_SIDES 1
|
---|
86 | #include "shade_tmp.h"
|
---|
87 |
|
---|
88 | #define TAG(x) x##_one_sided
|
---|
89 | #define INVALID(x) 0
|
---|
90 | #define IDX 0
|
---|
91 | #define LIGHT_FRONT(x) 1
|
---|
92 | #define LIGHT_REAR(x) 0
|
---|
93 | #define LIGHT_SIDE(x,y) 1
|
---|
94 | #define CULL(x) 0
|
---|
95 | #define NR_SIDES 1
|
---|
96 | #include "shade_tmp.h"
|
---|
97 |
|
---|
98 | #define TAG(x) x##_two_sided_masked
|
---|
99 | #define INVALID(x) ((x)&invalid)
|
---|
100 | #define IDX SHADE_TWOSIDE|CULL_MASK_ACTIVE
|
---|
101 | #define LIGHT_FRONT(f) ((f)&VERT_FACE_FRONT)
|
---|
102 | #define LIGHT_REAR(f) ((f)&VERT_FACE_REAR)
|
---|
103 | #define LIGHT_SIDE(x,y) ((x)&(y))
|
---|
104 | #define CULL(x) !((x)&VERT_FACE_FLAGS)
|
---|
105 | #define NR_SIDES 2
|
---|
106 | #include "shade_tmp.h"
|
---|
107 |
|
---|
108 | #define TAG(x) x##_two_sided
|
---|
109 | #define INVALID(x) 0
|
---|
110 | #define IDX SHADE_TWOSIDE
|
---|
111 | #define LIGHT_FRONT(f) 1
|
---|
112 | #define LIGHT_REAR(f) 1
|
---|
113 | #define LIGHT_SIDE(x,y) 1
|
---|
114 | #define CULL(x) 0
|
---|
115 | #define NR_SIDES 2
|
---|
116 | #include "shade_tmp.h"
|
---|
117 |
|
---|
118 | #undef NEXT_NORMAL
|
---|
119 | #undef NEXT_VERTEX_NORMAL
|
---|
120 | #undef STATE_CHANGE
|
---|
121 | #undef COMPACTED
|
---|
122 |
|
---|
123 | /* The 'compacted normal' case, where we have a sparse list of normals
|
---|
124 | * with flags indicating a new (valid) normal, as now built by the
|
---|
125 | * 'glVertex' API routines. We have a small bonus in that we know
|
---|
126 | * in advance that the normal stride must be 3 floats.
|
---|
127 | */
|
---|
128 | #define NEXT_NORMAL ((flags[j]&VERT_NORM) ? normal=first_normal[j],mask=&cullmask[j] : 0)
|
---|
129 | #define NEXT_VERTEX_NORMAL ((flags[j]&VERT_NORM) ? normal=first_normal[j],mask=&cullmask[j] : 0)
|
---|
130 | #define STATE_CHANGE(a,b) (a & b)
|
---|
131 | #define COMPACTED 1
|
---|
132 |
|
---|
133 |
|
---|
134 | #define TAG(x) x##_one_sided_masked_compacted
|
---|
135 | #define INVALID(x) 0
|
---|
136 | #define IDX COMPACTED_NORMALS|CULL_MASK_ACTIVE
|
---|
137 | #define LIGHT_FRONT(x) 1
|
---|
138 | #define LIGHT_REAR(x) 0
|
---|
139 | #define LIGHT_SIDE(x,y) 1
|
---|
140 | #define CULL(x) !((x)&VERT_FACE_FLAGS)
|
---|
141 | #define NR_SIDES 1
|
---|
142 | #include "shade_tmp.h"
|
---|
143 |
|
---|
144 | #define TAG(x) x##_one_sided_compacted
|
---|
145 | #define INVALID(x) 0
|
---|
146 | #define IDX COMPACTED_NORMALS
|
---|
147 | #define LIGHT_FRONT(x) 1
|
---|
148 | #define LIGHT_REAR(x) 0
|
---|
149 | #define LIGHT_SIDE(x,y) 1
|
---|
150 | #define CULL(x) 0
|
---|
151 | #define NR_SIDES 1
|
---|
152 | #include "shade_tmp.h"
|
---|
153 |
|
---|
154 | #define TAG(x) x##_two_sided_masked_compacted
|
---|
155 | #define INVALID(x) ((x)&invalid)
|
---|
156 | #define IDX COMPACTED_NORMALS|SHADE_TWOSIDE
|
---|
157 | #define LIGHT_FRONT(f) ((f)&VERT_FACE_FRONT)
|
---|
158 | #define LIGHT_REAR(f) ((f)&VERT_FACE_REAR)
|
---|
159 | #define LIGHT_SIDE(x,y) ((x)&(y))
|
---|
160 | #define CULL(x) !((x)&VERT_FACE_FLAGS)
|
---|
161 | #define NR_SIDES 2
|
---|
162 | #include "shade_tmp.h"
|
---|
163 |
|
---|
164 | #define TAG(x) x##_two_sided_compacted
|
---|
165 | #define INVALID(x) 0
|
---|
166 | #define IDX COMPACTED_NORMALS|CULL_MASK_ACTIVE|SHADE_TWOSIDE
|
---|
167 | #define LIGHT_FRONT(f) 1
|
---|
168 | #define LIGHT_REAR(f) 1
|
---|
169 | #define LIGHT_SIDE(x,y) 1
|
---|
170 | #define CULL(x) 0
|
---|
171 | #define NR_SIDES 2
|
---|
172 | #include "shade_tmp.h"
|
---|
173 |
|
---|
174 | #undef COMPACTED
|
---|
175 | #undef NEXT_NORMAL
|
---|
176 | #undef NEXT_VERTEX_NORMAL
|
---|
177 | #undef STATE_CHANGE
|
---|
178 |
|
---|
179 |
|
---|
180 |
|
---|
181 | void gl_init_shade( void )
|
---|
182 | {
|
---|
183 | init_shade_tab_one_sided();
|
---|
184 | init_shade_tab_one_sided_masked();
|
---|
185 | init_shade_tab_one_sided_compacted();
|
---|
186 | init_shade_tab_one_sided_masked_compacted();
|
---|
187 |
|
---|
188 | init_shade_tab_two_sided();
|
---|
189 | init_shade_tab_two_sided_masked();
|
---|
190 | init_shade_tab_two_sided_compacted();
|
---|
191 | init_shade_tab_two_sided_masked_compacted();
|
---|
192 | }
|
---|
193 |
|
---|
194 | void gl_update_lighting_function( GLcontext *ctx )
|
---|
195 | {
|
---|
196 | GLuint idx;
|
---|
197 |
|
---|
198 | if (ctx->Visual->RGBAflag) {
|
---|
199 | if (ctx->Light.NeedVertices) {
|
---|
200 | if (ctx->Texture.Enabled &&
|
---|
201 | ctx->Light.Model.ColorControl==GL_SEPARATE_SPECULAR_COLOR)
|
---|
202 | idx = SHADE_RGBA_SPEC;
|
---|
203 | else
|
---|
204 | idx = SHADE_RGBA_VERTICES;
|
---|
205 | }
|
---|
206 | else
|
---|
207 | idx = SHADE_RGBA_NORMALS;
|
---|
208 | }
|
---|
209 | else
|
---|
210 | idx = 0;
|
---|
211 |
|
---|
212 | if (ctx->TriangleCaps & DD_TRI_LIGHT_TWOSIDE) {
|
---|
213 | idx |= SHADE_TWOSIDE;
|
---|
214 | }
|
---|
215 |
|
---|
216 |
|
---|
217 | ctx->shade_func_flags = idx;
|
---|
218 | }
|
---|
219 |
|
---|
220 |
|
---|
221 |
|
---|
222 | /* This has been split off to allow the normal shade routines to
|
---|
223 | * get a little closer to the vertex buffer, and to use the
|
---|
224 | * GLvector objects directly.
|
---|
225 | */
|
---|
226 | void gl_shade_rastpos( GLcontext *ctx,
|
---|
227 | GLfloat vertex[4],
|
---|
228 | GLfloat normal[3],
|
---|
229 | GLfloat Rcolor[4],
|
---|
230 | GLuint *index )
|
---|
231 | {
|
---|
232 | GLfloat (*base)[3] = ctx->Light.BaseColor;
|
---|
233 | GLubyte *sumA = ctx->Light.BaseAlpha;
|
---|
234 | struct gl_light *light;
|
---|
235 | GLfloat color[4];
|
---|
236 | GLfloat diffuse = 0, specular = 0;
|
---|
237 |
|
---|
238 | COPY_3V(color, base[0]);
|
---|
239 | color[3] = UBYTE_COLOR_TO_FLOAT_COLOR( sumA[0] );
|
---|
240 |
|
---|
241 | foreach (light, &ctx->Light.EnabledList) {
|
---|
242 | GLfloat n_dot_h;
|
---|
243 | GLfloat attenuation = 1.0;
|
---|
244 | GLfloat VP[3];
|
---|
245 | GLfloat n_dot_VP;
|
---|
246 | GLfloat *h;
|
---|
247 | GLfloat contrib[3];
|
---|
248 | GLboolean normalized;
|
---|
249 |
|
---|
250 | if (!(light->Flags & LIGHT_POSITIONAL)) {
|
---|
251 | COPY_3V(VP, light->VP_inf_norm);
|
---|
252 | attenuation = light->VP_inf_spot_attenuation;
|
---|
253 | }
|
---|
254 | else {
|
---|
255 | GLfloat d;
|
---|
256 |
|
---|
257 | SUB_3V(VP, light->Position, vertex);
|
---|
258 | d = LEN_3FV( VP );
|
---|
259 |
|
---|
260 | if ( d > 1e-6) {
|
---|
261 | GLfloat invd = 1.0F / d;
|
---|
262 | SELF_SCALE_SCALAR_3V(VP, invd);
|
---|
263 | }
|
---|
264 | attenuation = 1.0F / (light->ConstantAttenuation + d *
|
---|
265 | (light->LinearAttenuation + d *
|
---|
266 | light->QuadraticAttenuation));
|
---|
267 |
|
---|
268 | if (light->Flags & LIGHT_SPOT)
|
---|
269 | {
|
---|
270 | GLfloat PV_dot_dir = - DOT3(VP, light->NormDirection);
|
---|
271 |
|
---|
272 | if (PV_dot_dir<light->CosCutoff) {
|
---|
273 | continue;
|
---|
274 | }
|
---|
275 | else
|
---|
276 | {
|
---|
277 | double x = PV_dot_dir * (EXP_TABLE_SIZE-1);
|
---|
278 | int k = (int) x;
|
---|
279 | GLfloat spot = (GLfloat) (light->SpotExpTable[k][0]
|
---|
280 | + (x-k)*light->SpotExpTable[k][1]);
|
---|
281 | attenuation *= spot;
|
---|
282 | }
|
---|
283 | }
|
---|
284 | }
|
---|
285 |
|
---|
286 | if (attenuation < 1e-3)
|
---|
287 | continue;
|
---|
288 |
|
---|
289 | n_dot_VP = DOT3( normal, VP );
|
---|
290 |
|
---|
291 | if (n_dot_VP < 0.0F) {
|
---|
292 | ACC_SCALE_SCALAR_3V(color, attenuation, light->MatAmbient[0]);
|
---|
293 | continue;
|
---|
294 | }
|
---|
295 |
|
---|
296 | COPY_3V(contrib, light->MatAmbient[0]);
|
---|
297 | ACC_SCALE_SCALAR_3V(contrib, n_dot_VP, light->MatDiffuse[0]);
|
---|
298 | diffuse += n_dot_VP * light->dli * attenuation;
|
---|
299 |
|
---|
300 | if (light->IsMatSpecular[0]) {
|
---|
301 | if (ctx->Light.Model.LocalViewer) {
|
---|
302 | GLfloat v[3];
|
---|
303 | COPY_3V(v, vertex);
|
---|
304 | NORMALIZE_3FV(v);
|
---|
305 | SUB_3V(VP, VP, v);
|
---|
306 | h = VP;
|
---|
307 | normalized = 0;
|
---|
308 | }
|
---|
309 | else if (light->Flags & LIGHT_POSITIONAL) {
|
---|
310 | h = VP;
|
---|
311 | ACC_3V(h, ctx->EyeZDir);
|
---|
312 | normalized = 0;
|
---|
313 | }
|
---|
314 | else {
|
---|
315 | h = light->h_inf_norm;
|
---|
316 | normalized = 1;
|
---|
317 | }
|
---|
318 |
|
---|
319 | n_dot_h = DOT3(normal, h);
|
---|
320 |
|
---|
321 | if (n_dot_h > 0.0F) {
|
---|
322 | struct gl_material *mat = &ctx->Light.Material[0];
|
---|
323 | GLfloat spec_coef;
|
---|
324 | GLfloat shininess = mat->Shininess;
|
---|
325 |
|
---|
326 | if (!normalized) {
|
---|
327 | n_dot_h *= n_dot_h;
|
---|
328 | n_dot_h /= LEN_SQUARED_3FV( h );
|
---|
329 | shininess *= .5;
|
---|
330 | }
|
---|
331 |
|
---|
332 | if (n_dot_h>1.0) {
|
---|
333 | spec_coef = (GLfloat) pow( n_dot_h, shininess );
|
---|
334 | }
|
---|
335 | else {
|
---|
336 | struct gl_shine_tab *tab = ctx->ShineTable[0];
|
---|
337 | GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec_coef );
|
---|
338 | }
|
---|
339 |
|
---|
340 | if (spec_coef > 1.0e-10) {
|
---|
341 | ACC_SCALE_SCALAR_3V( contrib, spec_coef,
|
---|
342 | light->MatSpecular[0]);
|
---|
343 | specular += spec_coef * light->sli * attenuation;
|
---|
344 | }
|
---|
345 | }
|
---|
346 | }
|
---|
347 |
|
---|
348 | ACC_SCALE_SCALAR_3V( color, attenuation, contrib );
|
---|
349 | }
|
---|
350 |
|
---|
351 | if (ctx->Visual->RGBAflag) {
|
---|
352 | Rcolor[0] = CLAMP(color[0], 0.0F, 1.0F);
|
---|
353 | Rcolor[1] = CLAMP(color[1], 0.0F, 1.0F);
|
---|
354 | Rcolor[2] = CLAMP(color[2], 0.0F, 1.0F);
|
---|
355 | Rcolor[3] = CLAMP(color[3], 0.0F, 1.0F);
|
---|
356 | }
|
---|
357 | else {
|
---|
358 | struct gl_material *mat = &ctx->Light.Material[0];
|
---|
359 | GLfloat d_a = mat->DiffuseIndex - mat->AmbientIndex;
|
---|
360 | GLfloat s_a = mat->SpecularIndex - mat->AmbientIndex;
|
---|
361 | GLfloat ind = mat->AmbientIndex
|
---|
362 | + diffuse * (1.0F-specular) * d_a
|
---|
363 | + specular * s_a;
|
---|
364 | if (ind > mat->SpecularIndex) {
|
---|
365 | ind = mat->SpecularIndex;
|
---|
366 | }
|
---|
367 | *index = (GLuint) (GLint) ind;
|
---|
368 | }
|
---|
369 |
|
---|
370 | }
|
---|
371 |
|
---|