xref: /reactos/dll/opengl/mesa/light.c (revision 1734f297)
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 
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 
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 
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 
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 
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  */
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  */
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 
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  */
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 
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 
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  */
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  */
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  */
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