1 /* $Id: light.c,v 1.14 1997/07/24 01:24:11 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 2.4
6 * Copyright (C) 1995-1997 Brian Paul
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23
24 /*
25 * $Log: light.c,v $
26 * Revision 1.14 1997/07/24 01:24:11 brianp
27 * changed precompiled header symbol from PCH to PC_HEADER
28 *
29 * Revision 1.13 1997/06/20 04:15:43 brianp
30 * optimized changing of SHININESS (Henk Kok)
31 *
32 * Revision 1.12 1997/05/28 03:25:26 brianp
33 * added precompiled header (PCH) support
34 *
35 * Revision 1.11 1997/05/01 01:38:57 brianp
36 * now use NORMALIZE_3FV() macro from mmath.h
37 *
38 * Revision 1.10 1997/04/20 20:28:49 brianp
39 * replaced abort() with gl_problem()
40 *
41 * Revision 1.9 1997/04/07 02:59:17 brianp
42 * small optimization to setting of shininess and spot exponent
43 *
44 * Revision 1.8 1997/04/01 04:09:31 brianp
45 * misc code clean-ups. moved shading code to shade.c
46 *
47 * Revision 1.7 1997/03/11 00:37:39 brianp
48 * spotlight factor now effects ambient lighting
49 *
50 * Revision 1.6 1996/12/18 20:02:07 brianp
51 * glColorMaterial() and glMaterial() should finally work right!
52 *
53 * Revision 1.5 1996/12/07 10:22:41 brianp
54 * gl_Materialfv() now calls gl_set_material() if GL_COLOR_MATERIAL disabled
55 * implemented gl_GetLightiv()
56 *
57 * Revision 1.4 1996/11/08 04:39:23 brianp
58 * new gl_compute_spot_exp_table() contributed by Randy Frank
59 *
60 * Revision 1.3 1996/09/27 01:27:55 brianp
61 * removed unused variables
62 *
63 * Revision 1.2 1996/09/15 14:18:10 brianp
64 * now use GLframebuffer and GLvisual
65 *
66 * Revision 1.1 1996/09/13 01:38:16 brianp
67 * Initial revision
68 *
69 */
70
71
72 #ifdef PC_HEADER
73 #include "all.h"
74 #else
75 #include <assert.h>
76 #include <float.h>
77 #include <math.h>
78 #include <stdlib.h>
79 #include "context.h"
80 #include "light.h"
81 #include "dlist.h"
82 #include "macros.h"
83 #include "matrix.h"
84 #include "mmath.h"
85 #include "types.h"
86 #include "vb.h"
87 #include "xform.h"
88 #endif
89
90
91
gl_ShadeModel(GLcontext * ctx,GLenum mode)92 void gl_ShadeModel( GLcontext *ctx, GLenum mode )
93 {
94 if (INSIDE_BEGIN_END(ctx)) {
95 gl_error( ctx, GL_INVALID_OPERATION, "glShadeModel" );
96 return;
97 }
98
99 switch (mode) {
100 case GL_FLAT:
101 case GL_SMOOTH:
102 if (ctx->Light.ShadeModel!=mode) {
103 ctx->Light.ShadeModel = mode;
104 ctx->NewState |= NEW_RASTER_OPS;
105 }
106 break;
107 default:
108 gl_error( ctx, GL_INVALID_ENUM, "glShadeModel" );
109 }
110 }
111
112
113
gl_Lightfv(GLcontext * ctx,GLenum light,GLenum pname,const GLfloat * params,GLint nparams)114 void gl_Lightfv( GLcontext *ctx,
115 GLenum light, GLenum pname, const GLfloat *params,
116 GLint nparams )
117 {
118 GLint l;
119
120 if (INSIDE_BEGIN_END(ctx)) {
121 gl_error( ctx, GL_INVALID_OPERATION, "glShadeModel" );
122 return;
123 }
124
125 l = (GLint) (light - GL_LIGHT0);
126
127 if (l<0 || l>=MAX_LIGHTS) {
128 gl_error( ctx, GL_INVALID_ENUM, "glLight" );
129 return;
130 }
131
132 switch (pname) {
133 case GL_AMBIENT:
134 COPY_4V( ctx->Light.Light[l].Ambient, params );
135 break;
136 case GL_DIFFUSE:
137 COPY_4V( ctx->Light.Light[l].Diffuse, params );
138 break;
139 case GL_SPECULAR:
140 COPY_4V( ctx->Light.Light[l].Specular, params );
141 break;
142 case GL_POSITION:
143 /* transform position by ModelView matrix */
144 TRANSFORM_POINT( ctx->Light.Light[l].Position, ctx->ModelViewMatrix,
145 params );
146 break;
147 case GL_SPOT_DIRECTION:
148 /* transform direction by inverse modelview */
149 {
150 GLfloat direction[4];
151 direction[0] = params[0];
152 direction[1] = params[1];
153 direction[2] = params[2];
154 direction[3] = 0.0;
155 if (ctx->NewModelViewMatrix) {
156 gl_analyze_modelview_matrix( ctx );
157 }
158 gl_transform_vector( ctx->Light.Light[l].Direction,
159 direction, ctx->ModelViewInv);
160 }
161 break;
162 case GL_SPOT_EXPONENT:
163 if (params[0]<0.0 || params[0]>128.0) {
164 gl_error( ctx, GL_INVALID_VALUE, "glLight" );
165 return;
166 }
167 if (ctx->Light.Light[l].SpotExponent != params[0]) {
168 ctx->Light.Light[l].SpotExponent = params[0];
169 gl_compute_spot_exp_table( &ctx->Light.Light[l] );
170 }
171 break;
172 case GL_SPOT_CUTOFF:
173 if ((params[0]<0.0 || params[0]>90.0) && params[0]!=180.0) {
174 gl_error( ctx, GL_INVALID_VALUE, "glLight" );
175 return;
176 }
177 ctx->Light.Light[l].SpotCutoff = params[0];
178 ctx->Light.Light[l].CosCutoff = cos(params[0]*DEG2RAD);
179 break;
180 case GL_CONSTANT_ATTENUATION:
181 if (params[0]<0.0) {
182 gl_error( ctx, GL_INVALID_VALUE, "glLight" );
183 return;
184 }
185 ctx->Light.Light[l].ConstantAttenuation = params[0];
186 break;
187 case GL_LINEAR_ATTENUATION:
188 if (params[0]<0.0) {
189 gl_error( ctx, GL_INVALID_VALUE, "glLight" );
190 return;
191 }
192 ctx->Light.Light[l].LinearAttenuation = params[0];
193 break;
194 case GL_QUADRATIC_ATTENUATION:
195 if (params[0]<0.0) {
196 gl_error( ctx, GL_INVALID_VALUE, "glLight" );
197 return;
198 }
199 ctx->Light.Light[l].QuadraticAttenuation = params[0];
200 break;
201 default:
202 gl_error( ctx, GL_INVALID_ENUM, "glLight" );
203 break;
204 }
205
206 ctx->NewState |= NEW_LIGHTING;
207 }
208
209
210
gl_GetLightfv(GLcontext * ctx,GLenum light,GLenum pname,GLfloat * params)211 void gl_GetLightfv( GLcontext *ctx,
212 GLenum light, GLenum pname, GLfloat *params )
213 {
214 GLint l = (GLint) (light - GL_LIGHT0);
215
216 if (l<0 || l>=MAX_LIGHTS) {
217 gl_error( ctx, GL_INVALID_ENUM, "glGetLightfv" );
218 return;
219 }
220
221 switch (pname) {
222 case GL_AMBIENT:
223 COPY_4V( params, ctx->Light.Light[l].Ambient );
224 break;
225 case GL_DIFFUSE:
226 COPY_4V( params, ctx->Light.Light[l].Diffuse );
227 break;
228 case GL_SPECULAR:
229 COPY_4V( params, ctx->Light.Light[l].Specular );
230 break;
231 case GL_POSITION:
232 COPY_4V( params, ctx->Light.Light[l].Position );
233 break;
234 case GL_SPOT_DIRECTION:
235 COPY_3V( params, ctx->Light.Light[l].Direction );
236 break;
237 case GL_SPOT_EXPONENT:
238 params[0] = ctx->Light.Light[l].SpotExponent;
239 break;
240 case GL_SPOT_CUTOFF:
241 params[0] = ctx->Light.Light[l].SpotCutoff;
242 break;
243 case GL_CONSTANT_ATTENUATION:
244 params[0] = ctx->Light.Light[l].ConstantAttenuation;
245 break;
246 case GL_LINEAR_ATTENUATION:
247 params[0] = ctx->Light.Light[l].LinearAttenuation;
248 break;
249 case GL_QUADRATIC_ATTENUATION:
250 params[0] = ctx->Light.Light[l].QuadraticAttenuation;
251 break;
252 default:
253 gl_error( ctx, GL_INVALID_ENUM, "glGetLightfv" );
254 break;
255 }
256 }
257
258
259
gl_GetLightiv(GLcontext * ctx,GLenum light,GLenum pname,GLint * params)260 void gl_GetLightiv( GLcontext *ctx, GLenum light, GLenum pname, GLint *params )
261 {
262 GLint l = (GLint) (light - GL_LIGHT0);
263
264 if (l<0 || l>=MAX_LIGHTS) {
265 gl_error( ctx, GL_INVALID_ENUM, "glGetLightiv" );
266 return;
267 }
268
269 switch (pname) {
270 case GL_AMBIENT:
271 params[0] = FLOAT_TO_INT(ctx->Light.Light[l].Ambient[0]);
272 params[1] = FLOAT_TO_INT(ctx->Light.Light[l].Ambient[1]);
273 params[2] = FLOAT_TO_INT(ctx->Light.Light[l].Ambient[2]);
274 params[3] = FLOAT_TO_INT(ctx->Light.Light[l].Ambient[3]);
275 break;
276 case GL_DIFFUSE:
277 params[0] = FLOAT_TO_INT(ctx->Light.Light[l].Diffuse[0]);
278 params[1] = FLOAT_TO_INT(ctx->Light.Light[l].Diffuse[1]);
279 params[2] = FLOAT_TO_INT(ctx->Light.Light[l].Diffuse[2]);
280 params[3] = FLOAT_TO_INT(ctx->Light.Light[l].Diffuse[3]);
281 break;
282 case GL_SPECULAR:
283 params[0] = FLOAT_TO_INT(ctx->Light.Light[l].Specular[0]);
284 params[1] = FLOAT_TO_INT(ctx->Light.Light[l].Specular[1]);
285 params[2] = FLOAT_TO_INT(ctx->Light.Light[l].Specular[2]);
286 params[3] = FLOAT_TO_INT(ctx->Light.Light[l].Specular[3]);
287 break;
288 case GL_POSITION:
289 params[0] = ctx->Light.Light[l].Position[0];
290 params[1] = ctx->Light.Light[l].Position[1];
291 params[2] = ctx->Light.Light[l].Position[2];
292 params[3] = ctx->Light.Light[l].Position[3];
293 break;
294 case GL_SPOT_DIRECTION:
295 params[0] = ctx->Light.Light[l].Direction[0];
296 params[1] = ctx->Light.Light[l].Direction[1];
297 params[2] = ctx->Light.Light[l].Direction[2];
298 break;
299 case GL_SPOT_EXPONENT:
300 params[0] = ctx->Light.Light[l].SpotExponent;
301 break;
302 case GL_SPOT_CUTOFF:
303 params[0] = ctx->Light.Light[l].SpotCutoff;
304 break;
305 case GL_CONSTANT_ATTENUATION:
306 params[0] = ctx->Light.Light[l].ConstantAttenuation;
307 break;
308 case GL_LINEAR_ATTENUATION:
309 params[0] = ctx->Light.Light[l].LinearAttenuation;
310 break;
311 case GL_QUADRATIC_ATTENUATION:
312 params[0] = ctx->Light.Light[l].QuadraticAttenuation;
313 break;
314 default:
315 gl_error( ctx, GL_INVALID_ENUM, "glGetLightiv" );
316 break;
317 }
318 }
319
320
321
322 /**********************************************************************/
323 /*** Light Model ***/
324 /**********************************************************************/
325
326
gl_LightModelfv(GLcontext * ctx,GLenum pname,const GLfloat * params)327 void gl_LightModelfv( GLcontext *ctx, GLenum pname, const GLfloat *params )
328 {
329 switch (pname) {
330 case GL_LIGHT_MODEL_AMBIENT:
331 COPY_4V( ctx->Light.Model.Ambient, params );
332 break;
333 case GL_LIGHT_MODEL_LOCAL_VIEWER:
334 if (params[0]==0.0)
335 ctx->Light.Model.LocalViewer = GL_FALSE;
336 else
337 ctx->Light.Model.LocalViewer = GL_TRUE;
338 break;
339 case GL_LIGHT_MODEL_TWO_SIDE:
340 if (params[0]==0.0)
341 ctx->Light.Model.TwoSide = GL_FALSE;
342 else
343 ctx->Light.Model.TwoSide = GL_TRUE;
344 break;
345 default:
346 gl_error( ctx, GL_INVALID_ENUM, "glLightModel" );
347 break;
348 }
349 ctx->NewState |= NEW_LIGHTING;
350 }
351
352
353
354
355 /********** MATERIAL **********/
356
357
358 /*
359 * Given a face and pname value (ala glColorMaterial), compute a bitmask
360 * of the targeted material values.
361 */
gl_material_bitmask(GLenum face,GLenum pname)362 GLuint gl_material_bitmask( GLenum face, GLenum pname )
363 {
364 GLuint bitmask = 0;
365
366 /* Make a bitmask indicating what material attribute(s) we're updating */
367 switch (pname) {
368 case GL_EMISSION:
369 bitmask |= FRONT_EMISSION_BIT | BACK_EMISSION_BIT;
370 break;
371 case GL_AMBIENT:
372 bitmask |= FRONT_AMBIENT_BIT | BACK_AMBIENT_BIT;
373 break;
374 case GL_DIFFUSE:
375 bitmask |= FRONT_DIFFUSE_BIT | BACK_DIFFUSE_BIT;
376 break;
377 case GL_SPECULAR:
378 bitmask |= FRONT_SPECULAR_BIT | BACK_SPECULAR_BIT;
379 break;
380 case GL_SHININESS:
381 bitmask |= FRONT_SHININESS_BIT | BACK_SHININESS_BIT;
382 break;
383 case GL_AMBIENT_AND_DIFFUSE:
384 bitmask |= FRONT_AMBIENT_BIT | BACK_AMBIENT_BIT;
385 bitmask |= FRONT_DIFFUSE_BIT | BACK_DIFFUSE_BIT;
386 break;
387 case GL_COLOR_INDEXES:
388 bitmask |= FRONT_INDEXES_BIT | BACK_INDEXES_BIT;
389 break;
390 default:
391 gl_problem(NULL, "Bad param in gl_material_bitmask");
392 return 0;
393 }
394
395 ASSERT( face==GL_FRONT || face==GL_BACK || face==GL_FRONT_AND_BACK );
396
397 if (face==GL_FRONT) {
398 bitmask &= FRONT_MATERIAL_BITS;
399 }
400 else if (face==GL_BACK) {
401 bitmask &= BACK_MATERIAL_BITS;
402 }
403
404 return bitmask;
405 }
406
407
408
409 /*
410 * This is called by glColor() when GL_COLOR_MATERIAL is enabled and
411 * called by glMaterial() when GL_COLOR_MATERIAL is disabled.
412 */
gl_set_material(GLcontext * ctx,GLuint bitmask,const GLfloat * params)413 void gl_set_material( GLcontext *ctx, GLuint bitmask, const GLfloat *params )
414 {
415 struct gl_material *mat;
416
417 if (INSIDE_BEGIN_END(ctx)) {
418 struct vertex_buffer *VB = ctx->VB;
419 /* Save per-vertex material changes in the Vertex Buffer.
420 * The update_material function will eventually update the global
421 * ctx->Light.Material values.
422 */
423 mat = VB->Material[VB->Count];
424 VB->MaterialMask[VB->Count] |= bitmask;
425 VB->MonoMaterial = GL_FALSE;
426 }
427 else {
428 /* just update the global material property */
429 mat = ctx->Light.Material;
430 ctx->NewState |= NEW_LIGHTING;
431 }
432
433 if (bitmask & FRONT_AMBIENT_BIT) {
434 COPY_4V( mat[0].Ambient, params );
435 }
436 if (bitmask & BACK_AMBIENT_BIT) {
437 COPY_4V( mat[1].Ambient, params );
438 }
439 if (bitmask & FRONT_DIFFUSE_BIT) {
440 COPY_4V( mat[0].Diffuse, params );
441 }
442 if (bitmask & BACK_DIFFUSE_BIT) {
443 COPY_4V( mat[1].Diffuse, params );
444 }
445 if (bitmask & FRONT_SPECULAR_BIT) {
446 COPY_4V( mat[0].Specular, params );
447 }
448 if (bitmask & BACK_SPECULAR_BIT) {
449 COPY_4V( mat[1].Specular, params );
450 }
451 if (bitmask & FRONT_EMISSION_BIT) {
452 COPY_4V( mat[0].Emission, params );
453 }
454 if (bitmask & BACK_EMISSION_BIT) {
455 COPY_4V( mat[1].Emission, params );
456 }
457 if (bitmask & FRONT_SHININESS_BIT) {
458 GLfloat shininess = CLAMP( params[0], 0.0F, 128.0F );
459 if (mat[0].Shininess != shininess) {
460 mat[0].Shininess = shininess;
461 gl_compute_material_shine_table( &mat[0] );
462 }
463 }
464 if (bitmask & BACK_SHININESS_BIT) {
465 GLfloat shininess = CLAMP( params[0], 0.0F, 128.0F );
466 if (mat[1].Shininess != shininess) {
467 mat[1].Shininess = shininess;
468 gl_compute_material_shine_table( &mat[1] );
469 }
470 }
471 if (bitmask & FRONT_INDEXES_BIT) {
472 mat[0].AmbientIndex = params[0];
473 mat[0].DiffuseIndex = params[1];
474 mat[0].SpecularIndex = params[2];
475 }
476 if (bitmask & BACK_INDEXES_BIT) {
477 mat[1].AmbientIndex = params[0];
478 mat[1].DiffuseIndex = params[1];
479 mat[1].SpecularIndex = params[2];
480 }
481 }
482
483
484
gl_ColorMaterial(GLcontext * ctx,GLenum face,GLenum mode)485 void gl_ColorMaterial( GLcontext *ctx, GLenum face, GLenum mode )
486 {
487 if (INSIDE_BEGIN_END(ctx)) {
488 gl_error( ctx, GL_INVALID_OPERATION, "glColorMaterial" );
489 return;
490 }
491 switch (face) {
492 case GL_FRONT:
493 case GL_BACK:
494 case GL_FRONT_AND_BACK:
495 ctx->Light.ColorMaterialFace = face;
496 break;
497 default:
498 gl_error( ctx, GL_INVALID_ENUM, "glColorMaterial(face)" );
499 return;
500 }
501 switch (mode) {
502 case GL_EMISSION:
503 case GL_AMBIENT:
504 case GL_DIFFUSE:
505 case GL_SPECULAR:
506 case GL_AMBIENT_AND_DIFFUSE:
507 ctx->Light.ColorMaterialMode = mode;
508 break;
509 default:
510 gl_error( ctx, GL_INVALID_ENUM, "glColorMaterial(mode)" );
511 return;
512 }
513
514 ctx->Light.ColorMaterialBitmask = gl_material_bitmask( face, mode );
515 }
516
517
518
519 /*
520 * This is only called via the api_function_table struct or by the
521 * display list executor.
522 */
gl_Materialfv(GLcontext * ctx,GLenum face,GLenum pname,const GLfloat * params)523 void gl_Materialfv( GLcontext *ctx,
524 GLenum face, GLenum pname, const GLfloat *params )
525 {
526 GLuint bitmask;
527
528 /* error checking */
529 if (face!=GL_FRONT && face!=GL_BACK && face!=GL_FRONT_AND_BACK) {
530 gl_error( ctx, GL_INVALID_ENUM, "glMaterial(face)" );
531 return;
532 }
533 switch (pname) {
534 case GL_EMISSION:
535 case GL_AMBIENT:
536 case GL_DIFFUSE:
537 case GL_SPECULAR:
538 case GL_SHININESS:
539 case GL_AMBIENT_AND_DIFFUSE:
540 case GL_COLOR_INDEXES:
541 /* OK */
542 break;
543 default:
544 gl_error( ctx, GL_INVALID_ENUM, "glMaterial(pname)" );
545 return;
546 }
547
548 /* convert face and pname to a bitmask */
549 bitmask = gl_material_bitmask( face, pname );
550
551 if (ctx->Light.ColorMaterialEnabled) {
552 /* The material values specified by glColorMaterial() can't be */
553 /* updated by glMaterial() while GL_COLOR_MATERIAL is enabled! */
554 bitmask &= ~ctx->Light.ColorMaterialBitmask;
555 }
556
557 gl_set_material( ctx, bitmask, params );
558 }
559
560
561
562
gl_GetMaterialfv(GLcontext * ctx,GLenum face,GLenum pname,GLfloat * params)563 void gl_GetMaterialfv( GLcontext *ctx,
564 GLenum face, GLenum pname, GLfloat *params )
565 {
566 GLuint f;
567
568 if (INSIDE_BEGIN_END(ctx)) {
569 gl_error( ctx, GL_INVALID_OPERATION, "glGetMaterialfv" );
570 return;
571 }
572 if (face==GL_FRONT) {
573 f = 0;
574 }
575 else if (face==GL_BACK) {
576 f = 1;
577 }
578 else {
579 gl_error( ctx, GL_INVALID_ENUM, "glGetMaterialfv(face)" );
580 return;
581 }
582 switch (pname) {
583 case GL_AMBIENT:
584 COPY_4V( params, ctx->Light.Material[f].Ambient );
585 break;
586 case GL_DIFFUSE:
587 COPY_4V( params, ctx->Light.Material[f].Diffuse );
588 break;
589 case GL_SPECULAR:
590 COPY_4V( params, ctx->Light.Material[f].Specular );
591 break;
592 case GL_EMISSION:
593 COPY_4V( params, ctx->Light.Material[f].Emission );
594 break;
595 case GL_SHININESS:
596 *params = ctx->Light.Material[f].Shininess;
597 break;
598 case GL_COLOR_INDEXES:
599 params[0] = ctx->Light.Material[f].AmbientIndex;
600 params[1] = ctx->Light.Material[f].DiffuseIndex;
601 params[2] = ctx->Light.Material[f].SpecularIndex;
602 break;
603 default:
604 gl_error( ctx, GL_INVALID_ENUM, "glGetMaterialfv(pname)" );
605 }
606 }
607
608
609
gl_GetMaterialiv(GLcontext * ctx,GLenum face,GLenum pname,GLint * params)610 void gl_GetMaterialiv( GLcontext *ctx,
611 GLenum face, GLenum pname, GLint *params )
612 {
613 GLuint f;
614
615 if (INSIDE_BEGIN_END(ctx)) {
616 gl_error( ctx, GL_INVALID_OPERATION, "glGetMaterialiv" );
617 return;
618 }
619 if (face==GL_FRONT) {
620 f = 0;
621 }
622 else if (face==GL_BACK) {
623 f = 1;
624 }
625 else {
626 gl_error( ctx, GL_INVALID_ENUM, "glGetMaterialiv(face)" );
627 return;
628 }
629 switch (pname) {
630 case GL_AMBIENT:
631 params[0] = FLOAT_TO_INT( ctx->Light.Material[f].Ambient[0] );
632 params[1] = FLOAT_TO_INT( ctx->Light.Material[f].Ambient[1] );
633 params[2] = FLOAT_TO_INT( ctx->Light.Material[f].Ambient[2] );
634 params[3] = FLOAT_TO_INT( ctx->Light.Material[f].Ambient[3] );
635 break;
636 case GL_DIFFUSE:
637 params[0] = FLOAT_TO_INT( ctx->Light.Material[f].Diffuse[0] );
638 params[1] = FLOAT_TO_INT( ctx->Light.Material[f].Diffuse[1] );
639 params[2] = FLOAT_TO_INT( ctx->Light.Material[f].Diffuse[2] );
640 params[3] = FLOAT_TO_INT( ctx->Light.Material[f].Diffuse[3] );
641 break;
642 case GL_SPECULAR:
643 params[0] = FLOAT_TO_INT( ctx->Light.Material[f].Specular[0] );
644 params[1] = FLOAT_TO_INT( ctx->Light.Material[f].Specular[1] );
645 params[2] = FLOAT_TO_INT( ctx->Light.Material[f].Specular[2] );
646 params[3] = FLOAT_TO_INT( ctx->Light.Material[f].Specular[3] );
647 break;
648 case GL_EMISSION:
649 params[0] = FLOAT_TO_INT( ctx->Light.Material[f].Emission[0] );
650 params[1] = FLOAT_TO_INT( ctx->Light.Material[f].Emission[1] );
651 params[2] = FLOAT_TO_INT( ctx->Light.Material[f].Emission[2] );
652 params[3] = FLOAT_TO_INT( ctx->Light.Material[f].Emission[3] );
653 break;
654 case GL_SHININESS:
655 *params = ROUNDF( ctx->Light.Material[f].Shininess );
656 break;
657 case GL_COLOR_INDEXES:
658 params[0] = ROUNDF( ctx->Light.Material[f].AmbientIndex );
659 params[1] = ROUNDF( ctx->Light.Material[f].DiffuseIndex );
660 params[2] = ROUNDF( ctx->Light.Material[f].SpecularIndex );
661 break;
662 default:
663 gl_error( ctx, GL_INVALID_ENUM, "glGetMaterialfv(pname)" );
664 }
665 }
666
667
668
669
670 /**********************************************************************/
671 /***** Lighting computation *****/
672 /**********************************************************************/
673
674
675 /*
676 * Notes:
677 * When two-sided lighting is enabled we compute the color (or index)
678 * for both the front and back side of the primitive. Then, when the
679 * orientation of the facet is later learned, we can determine which
680 * color (or index) to use for rendering.
681 *
682 * Variables:
683 * n = normal vector
684 * V = vertex position
685 * P = light source position
686 * Pe = (0,0,0,1)
687 *
688 * Precomputed:
689 * IF P[3]==0 THEN
690 * // light at infinity
691 * IF local_viewer THEN
692 * VP_inf_norm = unit vector from V to P // Precompute
693 * ELSE
694 * // eye at infinity
695 * h_inf_norm = Normalize( VP + <0,0,1> ) // Precompute
696 * ENDIF
697 * ENDIF
698 *
699 * Functions:
700 * Normalize( v ) = normalized vector v
701 * Magnitude( v ) = length of vector v
702 */
703
704
705
706 /*
707 * Whenever the spotlight exponent for a light changes we must call
708 * this function to recompute the exponent lookup table.
709 */
gl_compute_spot_exp_table(struct gl_light * l)710 void gl_compute_spot_exp_table( struct gl_light *l )
711 {
712 int i;
713 double exponent = l->SpotExponent;
714 double tmp;
715 int clamp = 0;
716
717 l->SpotExpTable[0][0] = 0.0;
718
719 for (i=EXP_TABLE_SIZE-1;i>0;i--) {
720 if (clamp == 0) {
721 tmp = pow(i/(double)(EXP_TABLE_SIZE-1), exponent);
722 if (tmp < FLT_MIN*100.0) {
723 tmp = 0.0;
724 clamp = 1;
725 }
726 }
727 l->SpotExpTable[i][0] = tmp;
728 }
729 for (i=0;i<EXP_TABLE_SIZE-1;i++) {
730 l->SpotExpTable[i][1] = l->SpotExpTable[i+1][0] - l->SpotExpTable[i][0];
731 }
732 l->SpotExpTable[EXP_TABLE_SIZE-1][1] = 0.0;
733 }
734
735
736
737 /*
738 * Whenever the shininess of a material changes we must call this
739 * function to recompute the exponential lookup table.
740 */
gl_compute_material_shine_table(struct gl_material * m)741 void gl_compute_material_shine_table( struct gl_material *m )
742 {
743 int i;
744
745 m->ShineTable[0] = 0.0F;
746 for (i=1;i<SHINE_TABLE_SIZE;i++) {
747 #if 0
748 double x = pow( i/(double)(SHINE_TABLE_SIZE-1), exponent );
749 if (x<1.0e-10) {
750 m->ShineTable[i] = 0.0F;
751 }
752 else {
753 m->ShineTable[i] = x;
754 }
755 #else
756 /* just invalidate the table */
757 m->ShineTable[i] = -1.0;
758 #endif
759 }
760 }
761
762
763
764 /*
765 * Examine current lighting parameters to determine if the optimized lighting
766 * function can be used.
767 * Also, precompute some lighting values such as the products of light
768 * source and material ambient, diffuse and specular coefficients.
769 */
gl_update_lighting(GLcontext * ctx)770 void gl_update_lighting( GLcontext *ctx )
771 {
772 GLint i, side;
773 struct gl_light *prev_enabled, *light;
774
775 if (!ctx->Light.Enabled) {
776 /* If lighting is not enabled, we can skip all this. */
777 return;
778 }
779
780 /* Setup linked list of enabled light sources */
781 prev_enabled = NULL;
782 ctx->Light.FirstEnabled = NULL;
783 for (i=0;i<MAX_LIGHTS;i++) {
784 ctx->Light.Light[i].NextEnabled = NULL;
785 if (ctx->Light.Light[i].Enabled) {
786 if (prev_enabled) {
787 prev_enabled->NextEnabled = &ctx->Light.Light[i];
788 }
789 else {
790 ctx->Light.FirstEnabled = &ctx->Light.Light[i];
791 }
792 prev_enabled = &ctx->Light.Light[i];
793 }
794 }
795
796 /* base color = material_emission + global_ambient * material_ambient */
797 for (side=0; side<2; side++) {
798 ctx->Light.BaseColor[side][0] = ctx->Light.Material[side].Emission[0]
799 + ctx->Light.Model.Ambient[0] * ctx->Light.Material[side].Ambient[0];
800 ctx->Light.BaseColor[side][1] = ctx->Light.Material[side].Emission[1]
801 + ctx->Light.Model.Ambient[1] * ctx->Light.Material[side].Ambient[1];
802 ctx->Light.BaseColor[side][2] = ctx->Light.Material[side].Emission[2]
803 + ctx->Light.Model.Ambient[2] * ctx->Light.Material[side].Ambient[2];
804 ctx->Light.BaseColor[side][3]
805 = MIN2( ctx->Light.Material[side].Diffuse[3], 1.0F );
806 }
807
808
809 /* Precompute some lighting stuff */
810 for (light = ctx->Light.FirstEnabled; light; light = light->NextEnabled) {
811 for (side=0; side<2; side++) {
812 struct gl_material *mat = &ctx->Light.Material[side];
813 /* Add each light's ambient component to base color */
814 ctx->Light.BaseColor[side][0] += light->Ambient[0] * mat->Ambient[0];
815 ctx->Light.BaseColor[side][1] += light->Ambient[1] * mat->Ambient[1];
816 ctx->Light.BaseColor[side][2] += light->Ambient[2] * mat->Ambient[2];
817 /* compute product of light's ambient with front material ambient */
818 light->MatAmbient[side][0] = light->Ambient[0] * mat->Ambient[0];
819 light->MatAmbient[side][1] = light->Ambient[1] * mat->Ambient[1];
820 light->MatAmbient[side][2] = light->Ambient[2] * mat->Ambient[2];
821 /* compute product of light's diffuse with front material diffuse */
822 light->MatDiffuse[side][0] = light->Diffuse[0] * mat->Diffuse[0];
823 light->MatDiffuse[side][1] = light->Diffuse[1] * mat->Diffuse[1];
824 light->MatDiffuse[side][2] = light->Diffuse[2] * mat->Diffuse[2];
825 /* compute product of light's specular with front material specular */
826 light->MatSpecular[side][0] = light->Specular[0] * mat->Specular[0];
827 light->MatSpecular[side][1] = light->Specular[1] * mat->Specular[1];
828 light->MatSpecular[side][2] = light->Specular[2] * mat->Specular[2];
829
830 /* VP (VP) = Normalize( Position ) */
831 COPY_3V( light->VP_inf_norm, light->Position );
832 NORMALIZE_3FV( light->VP_inf_norm );
833
834 /* h_inf_norm = Normalize( V_to_P + <0,0,1> ) */
835 COPY_3V( light->h_inf_norm, light->VP_inf_norm );
836 light->h_inf_norm[2] += 1.0F;
837 NORMALIZE_3FV( light->h_inf_norm );
838
839 COPY_3V( light->NormDirection, light->Direction );
840 NORMALIZE_3FV( light->NormDirection );
841
842 /* Compute color index diffuse and specular light intensities */
843 light->dli = 0.30F * light->Diffuse[0]
844 + 0.59F * light->Diffuse[1]
845 + 0.11F * light->Diffuse[2];
846 light->sli = 0.30F * light->Specular[0]
847 + 0.59F * light->Specular[1]
848 + 0.11F * light->Specular[2];
849
850 } /* loop over materials */
851 } /* loop over lights */
852
853 /* Determine if the fast lighting function can be used */
854 ctx->Light.Fast = GL_TRUE;
855 if ( ctx->Light.BaseColor[0][0]<0.0F
856 || ctx->Light.BaseColor[0][1]<0.0F
857 || ctx->Light.BaseColor[0][2]<0.0F
858 || ctx->Light.BaseColor[0][3]<0.0F
859 || ctx->Light.BaseColor[1][0]<0.0F
860 || ctx->Light.BaseColor[1][1]<0.0F
861 || ctx->Light.BaseColor[1][2]<0.0F
862 || ctx->Light.BaseColor[1][3]<0.0F
863 || ctx->Light.Model.LocalViewer
864 || ctx->Light.ColorMaterialEnabled) {
865 ctx->Light.Fast = GL_FALSE;
866 }
867 else {
868 for (light=ctx->Light.FirstEnabled; light; light=light->NextEnabled) {
869 if ( light->Position[3]!=0.0F
870 || light->SpotCutoff!=180.0F
871 || light->MatDiffuse[0][0]<0.0F
872 || light->MatDiffuse[0][1]<0.0F
873 || light->MatDiffuse[0][2]<0.0F
874 || light->MatSpecular[0][0]<0.0F
875 || light->MatSpecular[0][1]<0.0F
876 || light->MatSpecular[0][2]<0.0F
877 || light->MatDiffuse[1][0]<0.0F
878 || light->MatDiffuse[1][1]<0.0F
879 || light->MatDiffuse[1][2]<0.0F
880 || light->MatSpecular[1][0]<0.0F
881 || light->MatSpecular[1][1]<0.0F
882 || light->MatSpecular[1][2]<0.0F) {
883 ctx->Light.Fast = GL_FALSE;
884 break;
885 }
886 }
887 }
888 }
889