Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / main / light.c
1 /*
2  * Mesa 3-D graphics library
3  * Version:  7.5
4  *
5  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
6  * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included
16  * in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25
26
27 #include "glheader.h"
28 #include "imports.h"
29 #include "context.h"
30 #include "enums.h"
31 #include "light.h"
32 #include "macros.h"
33 #include "simple_list.h"
34 #include "mtypes.h"
35 #include "math/m_matrix.h"
36
37
38 void GLAPIENTRY
39 _mesa_ShadeModel( GLenum mode )
40 {
41    GET_CURRENT_CONTEXT(ctx);
42    ASSERT_OUTSIDE_BEGIN_END(ctx);
43
44    if (MESA_VERBOSE & VERBOSE_API)
45       _mesa_debug(ctx, "glShadeModel %s\n", _mesa_lookup_enum_by_nr(mode));
46
47    if (mode != GL_FLAT && mode != GL_SMOOTH) {
48       _mesa_error(ctx, GL_INVALID_ENUM, "glShadeModel");
49       return;
50    }
51
52    if (ctx->Light.ShadeModel == mode)
53       return;
54
55    FLUSH_VERTICES(ctx, _NEW_LIGHT);
56    ctx->Light.ShadeModel = mode;
57    if (mode == GL_FLAT)
58       ctx->_TriangleCaps |= DD_FLATSHADE;
59    else
60       ctx->_TriangleCaps &= ~DD_FLATSHADE;
61
62    if (ctx->Driver.ShadeModel)
63       ctx->Driver.ShadeModel( ctx, mode );
64 }
65
66
67 /**
68  * Set the provoking vertex (the vertex which specifies the prim's
69  * color when flat shading) to either the first or last vertex of the
70  * triangle or line.
71  */
72 void GLAPIENTRY
73 _mesa_ProvokingVertexEXT(GLenum mode)
74 {
75    GET_CURRENT_CONTEXT(ctx);
76    ASSERT_OUTSIDE_BEGIN_END(ctx);
77
78    if (MESA_VERBOSE&VERBOSE_API)
79       _mesa_debug(ctx, "glProvokingVertexEXT 0x%x\n", mode);
80
81    switch (mode) {
82    case GL_FIRST_VERTEX_CONVENTION_EXT:
83    case GL_LAST_VERTEX_CONVENTION_EXT:
84       break;
85    default:
86       _mesa_error(ctx, GL_INVALID_ENUM, "glProvokingVertexEXT(0x%x)", mode);
87       return;
88    }
89
90    if (ctx->Light.ProvokingVertex == mode)
91       return;
92
93    FLUSH_VERTICES(ctx, _NEW_LIGHT);
94    ctx->Light.ProvokingVertex = mode;
95 }
96
97
98 /**
99  * Helper function called by _mesa_Lightfv and _mesa_PopAttrib to set
100  * per-light state.
101  * For GL_POSITION and GL_SPOT_DIRECTION the params position/direction
102  * will have already been transformed by the modelview matrix!
103  * Also, all error checking should have already been done.
104  */
105 void
106 _mesa_light(struct gl_context *ctx, GLuint lnum, GLenum pname, const GLfloat *params)
107 {
108    struct gl_light *light;
109
110    ASSERT(lnum < MAX_LIGHTS);
111    light = &ctx->Light.Light[lnum];
112
113    switch (pname) {
114    case GL_AMBIENT:
115       if (TEST_EQ_4V(light->Ambient, params))
116          return;
117       FLUSH_VERTICES(ctx, _NEW_LIGHT);
118       COPY_4V( light->Ambient, params );
119       break;
120    case GL_DIFFUSE:
121       if (TEST_EQ_4V(light->Diffuse, params))
122          return;
123       FLUSH_VERTICES(ctx, _NEW_LIGHT);
124       COPY_4V( light->Diffuse, params );
125       break;
126    case GL_SPECULAR:
127       if (TEST_EQ_4V(light->Specular, params))
128          return;
129       FLUSH_VERTICES(ctx, _NEW_LIGHT);
130       COPY_4V( light->Specular, params );
131       break;
132    case GL_POSITION:
133       /* NOTE: position has already been transformed by ModelView! */
134       if (TEST_EQ_4V(light->EyePosition, params))
135          return;
136       FLUSH_VERTICES(ctx, _NEW_LIGHT);
137       COPY_4V(light->EyePosition, params);
138       if (light->EyePosition[3] != 0.0F)
139          light->_Flags |= LIGHT_POSITIONAL;
140       else
141          light->_Flags &= ~LIGHT_POSITIONAL;
142       break;
143    case GL_SPOT_DIRECTION:
144       /* NOTE: Direction already transformed by inverse ModelView! */
145       if (TEST_EQ_3V(light->SpotDirection, params))
146          return;
147       FLUSH_VERTICES(ctx, _NEW_LIGHT);
148       COPY_3V(light->SpotDirection, params);
149       break;
150    case GL_SPOT_EXPONENT:
151       ASSERT(params[0] >= 0.0);
152       ASSERT(params[0] <= ctx->Const.MaxSpotExponent);
153       if (light->SpotExponent == params[0])
154          return;
155       FLUSH_VERTICES(ctx, _NEW_LIGHT);
156       light->SpotExponent = params[0];
157       _mesa_invalidate_spot_exp_table(light);
158       break;
159    case GL_SPOT_CUTOFF:
160       ASSERT(params[0] == 180.0 || (params[0] >= 0.0 && params[0] <= 90.0));
161       if (light->SpotCutoff == params[0])
162          return;
163       FLUSH_VERTICES(ctx, _NEW_LIGHT);
164       light->SpotCutoff = params[0];
165       light->_CosCutoffNeg = (GLfloat) (cos(light->SpotCutoff * DEG2RAD));
166       if (light->_CosCutoffNeg < 0)
167          light->_CosCutoff = 0;
168       else
169          light->_CosCutoff = light->_CosCutoffNeg;
170       if (light->SpotCutoff != 180.0F)
171          light->_Flags |= LIGHT_SPOT;
172       else
173          light->_Flags &= ~LIGHT_SPOT;
174       break;
175    case GL_CONSTANT_ATTENUATION:
176       ASSERT(params[0] >= 0.0);
177       if (light->ConstantAttenuation == params[0])
178          return;
179       FLUSH_VERTICES(ctx, _NEW_LIGHT);
180       light->ConstantAttenuation = params[0];
181       break;
182    case GL_LINEAR_ATTENUATION:
183       ASSERT(params[0] >= 0.0);
184       if (light->LinearAttenuation == params[0])
185          return;
186       FLUSH_VERTICES(ctx, _NEW_LIGHT);
187       light->LinearAttenuation = params[0];
188       break;
189    case GL_QUADRATIC_ATTENUATION:
190       ASSERT(params[0] >= 0.0);
191       if (light->QuadraticAttenuation == params[0])
192          return;
193       FLUSH_VERTICES(ctx, _NEW_LIGHT);
194       light->QuadraticAttenuation = params[0];
195       break;
196    default:
197       _mesa_problem(ctx, "Unexpected pname in _mesa_light()");
198       return;
199    }
200
201    if (ctx->Driver.Lightfv)
202       ctx->Driver.Lightfv( ctx, GL_LIGHT0 + lnum, pname, params );
203 }
204
205
206 void GLAPIENTRY
207 _mesa_Lightf( GLenum light, GLenum pname, GLfloat param )
208 {
209    GLfloat fparam[4];
210    fparam[0] = param;
211    fparam[1] = fparam[2] = fparam[3] = 0.0F;
212    _mesa_Lightfv( light, pname, fparam );
213 }
214
215
216 void GLAPIENTRY
217 _mesa_Lightfv( GLenum light, GLenum pname, const GLfloat *params )
218 {
219    GET_CURRENT_CONTEXT(ctx);
220    GLint i = (GLint) (light - GL_LIGHT0);
221    GLfloat temp[4];
222    ASSERT_OUTSIDE_BEGIN_END(ctx);
223
224    if (i < 0 || i >= (GLint) ctx->Const.MaxLights) {
225       _mesa_error( ctx, GL_INVALID_ENUM, "glLight(light=0x%x)", light );
226       return;
227    }
228
229    /* do particular error checks, transformations */
230    switch (pname) {
231    case GL_AMBIENT:
232    case GL_DIFFUSE:
233    case GL_SPECULAR:
234       /* nothing */
235       break;
236    case GL_POSITION:
237       /* transform position by ModelView matrix */
238       TRANSFORM_POINT(temp, ctx->ModelviewMatrixStack.Top->m, params);
239       params = temp;
240       break;
241    case GL_SPOT_DIRECTION:
242       /* transform direction by inverse modelview */
243       if (_math_matrix_is_dirty(ctx->ModelviewMatrixStack.Top)) {
244          _math_matrix_analyse(ctx->ModelviewMatrixStack.Top);
245       }
246       TRANSFORM_DIRECTION(temp, params, ctx->ModelviewMatrixStack.Top->m);
247       params = temp;
248       break;
249    case GL_SPOT_EXPONENT:
250       if (params[0] < 0.0 || params[0] > ctx->Const.MaxSpotExponent) {
251          _mesa_error(ctx, GL_INVALID_VALUE, "glLight");
252          return;
253       }
254       break;
255    case GL_SPOT_CUTOFF:
256       if ((params[0] < 0.0 || params[0] > 90.0) && params[0] != 180.0) {
257          _mesa_error(ctx, GL_INVALID_VALUE, "glLight");
258          return;
259       }
260       break;
261    case GL_CONSTANT_ATTENUATION:
262       if (params[0] < 0.0) {
263          _mesa_error(ctx, GL_INVALID_VALUE, "glLight");
264          return;
265       }
266       break;
267    case GL_LINEAR_ATTENUATION:
268       if (params[0] < 0.0) {
269          _mesa_error(ctx, GL_INVALID_VALUE, "glLight");
270          return;
271       }
272       break;
273    case GL_QUADRATIC_ATTENUATION:
274       if (params[0] < 0.0) {
275          _mesa_error(ctx, GL_INVALID_VALUE, "glLight");
276          return;
277       }
278       break;
279    default:
280       _mesa_error(ctx, GL_INVALID_ENUM, "glLight(pname=0x%x)", pname);
281       return;
282    }
283
284    _mesa_light(ctx, i, pname, params);
285 }
286
287
288 void GLAPIENTRY
289 _mesa_Lighti( GLenum light, GLenum pname, GLint param )
290 {
291    GLint iparam[4];
292    iparam[0] = param;
293    iparam[1] = iparam[2] = iparam[3] = 0;
294    _mesa_Lightiv( light, pname, iparam );
295 }
296
297
298 void GLAPIENTRY
299 _mesa_Lightiv( GLenum light, GLenum pname, const GLint *params )
300 {
301    GLfloat fparam[4];
302
303    switch (pname) {
304       case GL_AMBIENT:
305       case GL_DIFFUSE:
306       case GL_SPECULAR:
307          fparam[0] = INT_TO_FLOAT( params[0] );
308          fparam[1] = INT_TO_FLOAT( params[1] );
309          fparam[2] = INT_TO_FLOAT( params[2] );
310          fparam[3] = INT_TO_FLOAT( params[3] );
311          break;
312       case GL_POSITION:
313          fparam[0] = (GLfloat) params[0];
314          fparam[1] = (GLfloat) params[1];
315          fparam[2] = (GLfloat) params[2];
316          fparam[3] = (GLfloat) params[3];
317          break;
318       case GL_SPOT_DIRECTION:
319          fparam[0] = (GLfloat) params[0];
320          fparam[1] = (GLfloat) params[1];
321          fparam[2] = (GLfloat) params[2];
322          break;
323       case GL_SPOT_EXPONENT:
324       case GL_SPOT_CUTOFF:
325       case GL_CONSTANT_ATTENUATION:
326       case GL_LINEAR_ATTENUATION:
327       case GL_QUADRATIC_ATTENUATION:
328          fparam[0] = (GLfloat) params[0];
329          break;
330       default:
331          /* error will be caught later in gl_Lightfv */
332          ;
333    }
334
335    _mesa_Lightfv( light, pname, fparam );
336 }
337
338
339
340 void GLAPIENTRY
341 _mesa_GetLightfv( GLenum light, GLenum pname, GLfloat *params )
342 {
343    GET_CURRENT_CONTEXT(ctx);
344    GLint l = (GLint) (light - GL_LIGHT0);
345    ASSERT_OUTSIDE_BEGIN_END(ctx);
346
347    if (l < 0 || l >= (GLint) ctx->Const.MaxLights) {
348       _mesa_error( ctx, GL_INVALID_ENUM, "glGetLightfv" );
349       return;
350    }
351
352    switch (pname) {
353       case GL_AMBIENT:
354          COPY_4V( params, ctx->Light.Light[l].Ambient );
355          break;
356       case GL_DIFFUSE:
357          COPY_4V( params, ctx->Light.Light[l].Diffuse );
358          break;
359       case GL_SPECULAR:
360          COPY_4V( params, ctx->Light.Light[l].Specular );
361          break;
362       case GL_POSITION:
363          COPY_4V( params, ctx->Light.Light[l].EyePosition );
364          break;
365       case GL_SPOT_DIRECTION:
366          COPY_3V( params, ctx->Light.Light[l].SpotDirection );
367          break;
368       case GL_SPOT_EXPONENT:
369          params[0] = ctx->Light.Light[l].SpotExponent;
370          break;
371       case GL_SPOT_CUTOFF:
372          params[0] = ctx->Light.Light[l].SpotCutoff;
373          break;
374       case GL_CONSTANT_ATTENUATION:
375          params[0] = ctx->Light.Light[l].ConstantAttenuation;
376          break;
377       case GL_LINEAR_ATTENUATION:
378          params[0] = ctx->Light.Light[l].LinearAttenuation;
379          break;
380       case GL_QUADRATIC_ATTENUATION:
381          params[0] = ctx->Light.Light[l].QuadraticAttenuation;
382          break;
383       default:
384          _mesa_error( ctx, GL_INVALID_ENUM, "glGetLightfv" );
385          break;
386    }
387 }
388
389
390 void GLAPIENTRY
391 _mesa_GetLightiv( GLenum light, GLenum pname, GLint *params )
392 {
393    GET_CURRENT_CONTEXT(ctx);
394    GLint l = (GLint) (light - GL_LIGHT0);
395    ASSERT_OUTSIDE_BEGIN_END(ctx);
396
397    if (l < 0 || l >= (GLint) ctx->Const.MaxLights) {
398       _mesa_error( ctx, GL_INVALID_ENUM, "glGetLightiv" );
399       return;
400    }
401
402    switch (pname) {
403       case GL_AMBIENT:
404          params[0] = FLOAT_TO_INT(ctx->Light.Light[l].Ambient[0]);
405          params[1] = FLOAT_TO_INT(ctx->Light.Light[l].Ambient[1]);
406          params[2] = FLOAT_TO_INT(ctx->Light.Light[l].Ambient[2]);
407          params[3] = FLOAT_TO_INT(ctx->Light.Light[l].Ambient[3]);
408          break;
409       case GL_DIFFUSE:
410          params[0] = FLOAT_TO_INT(ctx->Light.Light[l].Diffuse[0]);
411          params[1] = FLOAT_TO_INT(ctx->Light.Light[l].Diffuse[1]);
412          params[2] = FLOAT_TO_INT(ctx->Light.Light[l].Diffuse[2]);
413          params[3] = FLOAT_TO_INT(ctx->Light.Light[l].Diffuse[3]);
414          break;
415       case GL_SPECULAR:
416          params[0] = FLOAT_TO_INT(ctx->Light.Light[l].Specular[0]);
417          params[1] = FLOAT_TO_INT(ctx->Light.Light[l].Specular[1]);
418          params[2] = FLOAT_TO_INT(ctx->Light.Light[l].Specular[2]);
419          params[3] = FLOAT_TO_INT(ctx->Light.Light[l].Specular[3]);
420          break;
421       case GL_POSITION:
422          params[0] = (GLint) ctx->Light.Light[l].EyePosition[0];
423          params[1] = (GLint) ctx->Light.Light[l].EyePosition[1];
424          params[2] = (GLint) ctx->Light.Light[l].EyePosition[2];
425          params[3] = (GLint) ctx->Light.Light[l].EyePosition[3];
426          break;
427       case GL_SPOT_DIRECTION:
428          params[0] = (GLint) ctx->Light.Light[l].SpotDirection[0];
429          params[1] = (GLint) ctx->Light.Light[l].SpotDirection[1];
430          params[2] = (GLint) ctx->Light.Light[l].SpotDirection[2];
431          break;
432       case GL_SPOT_EXPONENT:
433          params[0] = (GLint) ctx->Light.Light[l].SpotExponent;
434          break;
435       case GL_SPOT_CUTOFF:
436          params[0] = (GLint) ctx->Light.Light[l].SpotCutoff;
437          break;
438       case GL_CONSTANT_ATTENUATION:
439          params[0] = (GLint) ctx->Light.Light[l].ConstantAttenuation;
440          break;
441       case GL_LINEAR_ATTENUATION:
442          params[0] = (GLint) ctx->Light.Light[l].LinearAttenuation;
443          break;
444       case GL_QUADRATIC_ATTENUATION:
445          params[0] = (GLint) ctx->Light.Light[l].QuadraticAttenuation;
446          break;
447       default:
448          _mesa_error( ctx, GL_INVALID_ENUM, "glGetLightiv" );
449          break;
450    }
451 }
452
453
454
455 /**********************************************************************/
456 /***                        Light Model                             ***/
457 /**********************************************************************/
458
459
460 void GLAPIENTRY
461 _mesa_LightModelfv( GLenum pname, const GLfloat *params )
462 {
463    GLenum newenum;
464    GLboolean newbool;
465    GET_CURRENT_CONTEXT(ctx);
466    ASSERT_OUTSIDE_BEGIN_END(ctx);
467
468    switch (pname) {
469       case GL_LIGHT_MODEL_AMBIENT:
470          if (TEST_EQ_4V( ctx->Light.Model.Ambient, params ))
471             return;
472          FLUSH_VERTICES(ctx, _NEW_LIGHT);
473          COPY_4V( ctx->Light.Model.Ambient, params );
474          break;
475       case GL_LIGHT_MODEL_LOCAL_VIEWER:
476          newbool = (params[0]!=0.0);
477          if (ctx->Light.Model.LocalViewer == newbool)
478             return;
479          FLUSH_VERTICES(ctx, _NEW_LIGHT);
480          ctx->Light.Model.LocalViewer = newbool;
481          break;
482       case GL_LIGHT_MODEL_TWO_SIDE:
483          newbool = (params[0]!=0.0);
484          if (ctx->Light.Model.TwoSide == newbool)
485             return;
486          FLUSH_VERTICES(ctx, _NEW_LIGHT);
487          ctx->Light.Model.TwoSide = newbool;
488          if (ctx->Light.Enabled && ctx->Light.Model.TwoSide)
489             ctx->_TriangleCaps |= DD_TRI_LIGHT_TWOSIDE;
490          else
491             ctx->_TriangleCaps &= ~DD_TRI_LIGHT_TWOSIDE;
492          break;
493       case GL_LIGHT_MODEL_COLOR_CONTROL:
494          if (params[0] == (GLfloat) GL_SINGLE_COLOR)
495             newenum = GL_SINGLE_COLOR;
496          else if (params[0] == (GLfloat) GL_SEPARATE_SPECULAR_COLOR)
497             newenum = GL_SEPARATE_SPECULAR_COLOR;
498          else {
499             _mesa_error( ctx, GL_INVALID_ENUM, "glLightModel(param=0x0%x)",
500                          (GLint) params[0] );
501             return;
502          }
503          if (ctx->Light.Model.ColorControl == newenum)
504             return;
505          FLUSH_VERTICES(ctx, _NEW_LIGHT);
506          ctx->Light.Model.ColorControl = newenum;
507          break;
508       default:
509          _mesa_error( ctx, GL_INVALID_ENUM, "glLightModel(pname=0x%x)", pname );
510          break;
511    }
512
513    if (ctx->Driver.LightModelfv)
514       ctx->Driver.LightModelfv( ctx, pname, params );
515 }
516
517
518 void GLAPIENTRY
519 _mesa_LightModeliv( GLenum pname, const GLint *params )
520 {
521    GLfloat fparam[4];
522
523    switch (pname) {
524       case GL_LIGHT_MODEL_AMBIENT:
525          fparam[0] = INT_TO_FLOAT( params[0] );
526          fparam[1] = INT_TO_FLOAT( params[1] );
527          fparam[2] = INT_TO_FLOAT( params[2] );
528          fparam[3] = INT_TO_FLOAT( params[3] );
529          break;
530       case GL_LIGHT_MODEL_LOCAL_VIEWER:
531       case GL_LIGHT_MODEL_TWO_SIDE:
532       case GL_LIGHT_MODEL_COLOR_CONTROL:
533          fparam[0] = (GLfloat) params[0];
534          break;
535       default:
536          /* Error will be caught later in gl_LightModelfv */
537          ASSIGN_4V(fparam, 0.0F, 0.0F, 0.0F, 0.0F);
538    }
539    _mesa_LightModelfv( pname, fparam );
540 }
541
542
543 void GLAPIENTRY
544 _mesa_LightModeli( GLenum pname, GLint param )
545 {
546    GLint iparam[4];
547    iparam[0] = param;
548    iparam[1] = iparam[2] = iparam[3] = 0;
549    _mesa_LightModeliv( pname, iparam );
550 }
551
552
553 void GLAPIENTRY
554 _mesa_LightModelf( GLenum pname, GLfloat param )
555 {
556    GLfloat fparam[4];
557    fparam[0] = param;
558    fparam[1] = fparam[2] = fparam[3] = 0.0F;
559    _mesa_LightModelfv( pname, fparam );
560 }
561
562
563
564 /********** MATERIAL **********/
565
566
567 /*
568  * Given a face and pname value (ala glColorMaterial), compute a bitmask
569  * of the targeted material values.
570  */
571 GLuint
572 _mesa_material_bitmask( struct gl_context *ctx, GLenum face, GLenum pname,
573                         GLuint legal, const char *where )
574 {
575    GLuint bitmask = 0;
576
577    /* Make a bitmask indicating what material attribute(s) we're updating */
578    switch (pname) {
579       case GL_EMISSION:
580          bitmask |= MAT_BIT_FRONT_EMISSION | MAT_BIT_BACK_EMISSION;
581          break;
582       case GL_AMBIENT:
583          bitmask |= MAT_BIT_FRONT_AMBIENT | MAT_BIT_BACK_AMBIENT;
584          break;
585       case GL_DIFFUSE:
586          bitmask |= MAT_BIT_FRONT_DIFFUSE | MAT_BIT_BACK_DIFFUSE;
587          break;
588       case GL_SPECULAR:
589          bitmask |= MAT_BIT_FRONT_SPECULAR | MAT_BIT_BACK_SPECULAR;
590          break;
591       case GL_SHININESS:
592          bitmask |= MAT_BIT_FRONT_SHININESS | MAT_BIT_BACK_SHININESS;
593          break;
594       case GL_AMBIENT_AND_DIFFUSE:
595          bitmask |= MAT_BIT_FRONT_AMBIENT | MAT_BIT_BACK_AMBIENT;
596          bitmask |= MAT_BIT_FRONT_DIFFUSE | MAT_BIT_BACK_DIFFUSE;
597          break;
598       case GL_COLOR_INDEXES:
599          bitmask |= MAT_BIT_FRONT_INDEXES  | MAT_BIT_BACK_INDEXES;
600          break;
601       default:
602          _mesa_error( ctx, GL_INVALID_ENUM, "%s", where );
603          return 0;
604    }
605
606    if (face==GL_FRONT) {
607       bitmask &= FRONT_MATERIAL_BITS;
608    }
609    else if (face==GL_BACK) {
610       bitmask &= BACK_MATERIAL_BITS;
611    }
612    else if (face != GL_FRONT_AND_BACK) {
613       _mesa_error( ctx, GL_INVALID_ENUM, "%s", where );
614       return 0;
615    }
616
617    if (bitmask & ~legal) {
618       _mesa_error( ctx, GL_INVALID_ENUM, "%s", where );
619       return 0;
620    }
621
622    return bitmask;
623 }
624
625
626
627 /* Perform a straight copy between materials.
628  */
629 void
630 _mesa_copy_materials( struct gl_material *dst,
631                       const struct gl_material *src,
632                       GLuint bitmask )
633 {
634    int i;
635
636    for (i = 0 ; i < MAT_ATTRIB_MAX ; i++) 
637       if (bitmask & (1<<i))
638          COPY_4FV( dst->Attrib[i], src->Attrib[i] );
639 }
640
641
642
643 /* Update derived values following a change in ctx->Light.Material
644  */
645 void
646 _mesa_update_material( struct gl_context *ctx, GLuint bitmask )
647 {
648    struct gl_light *light, *list = &ctx->Light.EnabledList;
649    GLfloat (*mat)[4] = ctx->Light.Material.Attrib;
650
651    if (MESA_VERBOSE & VERBOSE_MATERIAL) 
652       _mesa_debug(ctx, "_mesa_update_material, mask 0x%x\n", bitmask);
653
654    if (!bitmask)
655       return;
656
657    /* update material ambience */
658    if (bitmask & MAT_BIT_FRONT_AMBIENT) {
659       foreach (light, list) {
660          SCALE_3V( light->_MatAmbient[0], light->Ambient, 
661                    mat[MAT_ATTRIB_FRONT_AMBIENT]);
662       }
663    }
664
665    if (bitmask & MAT_BIT_BACK_AMBIENT) {
666       foreach (light, list) {
667          SCALE_3V( light->_MatAmbient[1], light->Ambient, 
668                    mat[MAT_ATTRIB_BACK_AMBIENT]);
669       }
670    }
671
672    /* update BaseColor = emission + scene's ambience * material's ambience */
673    if (bitmask & (MAT_BIT_FRONT_EMISSION | MAT_BIT_FRONT_AMBIENT)) {
674       COPY_3V( ctx->Light._BaseColor[0], mat[MAT_ATTRIB_FRONT_EMISSION] );
675       ACC_SCALE_3V( ctx->Light._BaseColor[0], mat[MAT_ATTRIB_FRONT_AMBIENT],
676                     ctx->Light.Model.Ambient );
677    }
678
679    if (bitmask & (MAT_BIT_BACK_EMISSION | MAT_BIT_BACK_AMBIENT)) {
680       COPY_3V( ctx->Light._BaseColor[1], mat[MAT_ATTRIB_BACK_EMISSION] );
681       ACC_SCALE_3V( ctx->Light._BaseColor[1], mat[MAT_ATTRIB_BACK_AMBIENT],
682                     ctx->Light.Model.Ambient );
683    }
684
685    /* update material diffuse values */
686    if (bitmask & MAT_BIT_FRONT_DIFFUSE) {
687       foreach (light, list) {
688          SCALE_3V( light->_MatDiffuse[0], light->Diffuse, 
689                    mat[MAT_ATTRIB_FRONT_DIFFUSE] );
690       }
691    }
692
693    if (bitmask & MAT_BIT_BACK_DIFFUSE) {
694       foreach (light, list) {
695          SCALE_3V( light->_MatDiffuse[1], light->Diffuse, 
696                    mat[MAT_ATTRIB_BACK_DIFFUSE] );
697       }
698    }
699
700    /* update material specular values */
701    if (bitmask & MAT_BIT_FRONT_SPECULAR) {
702       foreach (light, list) {
703          SCALE_3V( light->_MatSpecular[0], light->Specular, 
704                    mat[MAT_ATTRIB_FRONT_SPECULAR]);
705       }
706    }
707
708    if (bitmask & MAT_BIT_BACK_SPECULAR) {
709       foreach (light, list) {
710          SCALE_3V( light->_MatSpecular[1], light->Specular,
711                    mat[MAT_ATTRIB_BACK_SPECULAR]);
712       }
713    }
714
715    if (bitmask & MAT_BIT_FRONT_SHININESS) {
716       _mesa_invalidate_shine_table( ctx, 0 );
717    }
718
719    if (bitmask & MAT_BIT_BACK_SHININESS) {
720       _mesa_invalidate_shine_table( ctx, 1 );
721    }
722 }
723
724
725 /*
726  * Update the current materials from the given rgba color
727  * according to the bitmask in ColorMaterialBitmask, which is
728  * set by glColorMaterial().
729  */
730 void
731 _mesa_update_color_material( struct gl_context *ctx, const GLfloat color[4] )
732 {
733    GLuint bitmask = ctx->Light.ColorMaterialBitmask;
734    struct gl_material *mat = &ctx->Light.Material;
735    int i;
736
737    for (i = 0 ; i < MAT_ATTRIB_MAX ; i++) 
738       if (bitmask & (1<<i))
739          COPY_4FV( mat->Attrib[i], color );
740
741    _mesa_update_material( ctx, bitmask );
742 }
743
744
745 void GLAPIENTRY
746 _mesa_ColorMaterial( GLenum face, GLenum mode )
747 {
748    GET_CURRENT_CONTEXT(ctx);
749    GLuint bitmask;
750    GLuint legal = (MAT_BIT_FRONT_EMISSION | MAT_BIT_BACK_EMISSION |
751                    MAT_BIT_FRONT_SPECULAR | MAT_BIT_BACK_SPECULAR |
752                    MAT_BIT_FRONT_DIFFUSE  | MAT_BIT_BACK_DIFFUSE  |
753                    MAT_BIT_FRONT_AMBIENT  | MAT_BIT_BACK_AMBIENT);
754    ASSERT_OUTSIDE_BEGIN_END(ctx);
755
756    if (MESA_VERBOSE&VERBOSE_API)
757       _mesa_debug(ctx, "glColorMaterial %s %s\n",
758                   _mesa_lookup_enum_by_nr(face),
759                   _mesa_lookup_enum_by_nr(mode));
760
761    bitmask = _mesa_material_bitmask(ctx, face, mode, legal, "glColorMaterial");
762
763    if (ctx->Light.ColorMaterialBitmask == bitmask &&
764        ctx->Light.ColorMaterialFace == face &&
765        ctx->Light.ColorMaterialMode == mode)
766       return;
767
768    FLUSH_VERTICES(ctx, _NEW_LIGHT);
769    ctx->Light.ColorMaterialBitmask = bitmask;
770    ctx->Light.ColorMaterialFace = face;
771    ctx->Light.ColorMaterialMode = mode;
772
773    if (ctx->Light.ColorMaterialEnabled) {
774       FLUSH_CURRENT( ctx, 0 );
775       _mesa_update_color_material(ctx,ctx->Current.Attrib[VERT_ATTRIB_COLOR0]);
776    }
777
778    if (ctx->Driver.ColorMaterial)
779       ctx->Driver.ColorMaterial( ctx, face, mode );
780 }
781
782
783 void GLAPIENTRY
784 _mesa_GetMaterialfv( GLenum face, GLenum pname, GLfloat *params )
785 {
786    GET_CURRENT_CONTEXT(ctx);
787    GLuint f;
788    GLfloat (*mat)[4] = ctx->Light.Material.Attrib;
789    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* update materials */
790
791    FLUSH_CURRENT(ctx, 0); /* update ctx->Light.Material from vertex buffer */
792
793    if (face==GL_FRONT) {
794       f = 0;
795    }
796    else if (face==GL_BACK) {
797       f = 1;
798    }
799    else {
800       _mesa_error( ctx, GL_INVALID_ENUM, "glGetMaterialfv(face)" );
801       return;
802    }
803
804    switch (pname) {
805       case GL_AMBIENT:
806          COPY_4FV( params, mat[MAT_ATTRIB_AMBIENT(f)] );
807          break;
808       case GL_DIFFUSE:
809          COPY_4FV( params, mat[MAT_ATTRIB_DIFFUSE(f)] );
810          break;
811       case GL_SPECULAR:
812          COPY_4FV( params, mat[MAT_ATTRIB_SPECULAR(f)] );
813          break;
814       case GL_EMISSION:
815          COPY_4FV( params, mat[MAT_ATTRIB_EMISSION(f)] );
816          break;
817       case GL_SHININESS:
818          *params = mat[MAT_ATTRIB_SHININESS(f)][0];
819          break;
820       case GL_COLOR_INDEXES:
821          params[0] = mat[MAT_ATTRIB_INDEXES(f)][0];
822          params[1] = mat[MAT_ATTRIB_INDEXES(f)][1];
823          params[2] = mat[MAT_ATTRIB_INDEXES(f)][2];
824          break;
825       default:
826          _mesa_error( ctx, GL_INVALID_ENUM, "glGetMaterialfv(pname)" );
827    }
828 }
829
830
831 void GLAPIENTRY
832 _mesa_GetMaterialiv( GLenum face, GLenum pname, GLint *params )
833 {
834    GET_CURRENT_CONTEXT(ctx);
835    GLuint f;
836    GLfloat (*mat)[4] = ctx->Light.Material.Attrib;
837    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* update materials */
838
839    FLUSH_CURRENT(ctx, 0); /* update ctx->Light.Material from vertex buffer */
840
841    if (face==GL_FRONT) {
842       f = 0;
843    }
844    else if (face==GL_BACK) {
845       f = 1;
846    }
847    else {
848       _mesa_error( ctx, GL_INVALID_ENUM, "glGetMaterialiv(face)" );
849       return;
850    }
851    switch (pname) {
852       case GL_AMBIENT:
853          params[0] = FLOAT_TO_INT( mat[MAT_ATTRIB_AMBIENT(f)][0] );
854          params[1] = FLOAT_TO_INT( mat[MAT_ATTRIB_AMBIENT(f)][1] );
855          params[2] = FLOAT_TO_INT( mat[MAT_ATTRIB_AMBIENT(f)][2] );
856          params[3] = FLOAT_TO_INT( mat[MAT_ATTRIB_AMBIENT(f)][3] );
857          break;
858       case GL_DIFFUSE:
859          params[0] = FLOAT_TO_INT( mat[MAT_ATTRIB_DIFFUSE(f)][0] );
860          params[1] = FLOAT_TO_INT( mat[MAT_ATTRIB_DIFFUSE(f)][1] );
861          params[2] = FLOAT_TO_INT( mat[MAT_ATTRIB_DIFFUSE(f)][2] );
862          params[3] = FLOAT_TO_INT( mat[MAT_ATTRIB_DIFFUSE(f)][3] );
863          break;
864       case GL_SPECULAR:
865          params[0] = FLOAT_TO_INT( mat[MAT_ATTRIB_SPECULAR(f)][0] );
866          params[1] = FLOAT_TO_INT( mat[MAT_ATTRIB_SPECULAR(f)][1] );
867          params[2] = FLOAT_TO_INT( mat[MAT_ATTRIB_SPECULAR(f)][2] );
868          params[3] = FLOAT_TO_INT( mat[MAT_ATTRIB_SPECULAR(f)][3] );
869          break;
870       case GL_EMISSION:
871          params[0] = FLOAT_TO_INT( mat[MAT_ATTRIB_EMISSION(f)][0] );
872          params[1] = FLOAT_TO_INT( mat[MAT_ATTRIB_EMISSION(f)][1] );
873          params[2] = FLOAT_TO_INT( mat[MAT_ATTRIB_EMISSION(f)][2] );
874          params[3] = FLOAT_TO_INT( mat[MAT_ATTRIB_EMISSION(f)][3] );
875          break;
876       case GL_SHININESS:
877          *params = IROUND( mat[MAT_ATTRIB_SHININESS(f)][0] );
878          break;
879       case GL_COLOR_INDEXES:
880          params[0] = IROUND( mat[MAT_ATTRIB_INDEXES(f)][0] );
881          params[1] = IROUND( mat[MAT_ATTRIB_INDEXES(f)][1] );
882          params[2] = IROUND( mat[MAT_ATTRIB_INDEXES(f)][2] );
883          break;
884       default:
885          _mesa_error( ctx, GL_INVALID_ENUM, "glGetMaterialfv(pname)" );
886    }
887 }
888
889
890
891 /**********************************************************************/
892 /*****                  Lighting computation                      *****/
893 /**********************************************************************/
894
895
896 /*
897  * Notes:
898  *   When two-sided lighting is enabled we compute the color (or index)
899  *   for both the front and back side of the primitive.  Then, when the
900  *   orientation of the facet is later learned, we can determine which
901  *   color (or index) to use for rendering.
902  *
903  *   KW: We now know orientation in advance and only shade for
904  *       the side or sides which are actually required.
905  *
906  * Variables:
907  *   n = normal vector
908  *   V = vertex position
909  *   P = light source position
910  *   Pe = (0,0,0,1)
911  *
912  * Precomputed:
913  *   IF P[3]==0 THEN
914  *       // light at infinity
915  *       IF local_viewer THEN
916  *           _VP_inf_norm = unit vector from V to P      // Precompute
917  *       ELSE
918  *           // eye at infinity
919  *           _h_inf_norm = Normalize( VP + <0,0,1> )     // Precompute
920  *       ENDIF
921  *   ENDIF
922  *
923  * Functions:
924  *   Normalize( v ) = normalized vector v
925  *   Magnitude( v ) = length of vector v
926  */
927
928
929
930 /*
931  * Whenever the spotlight exponent for a light changes we must call
932  * this function to recompute the exponent lookup table.
933  */
934 void
935 _mesa_invalidate_spot_exp_table( struct gl_light *l )
936 {
937    l->_SpotExpTable[0][0] = -1;
938 }
939
940
941 static void
942 validate_spot_exp_table( struct gl_light *l )
943 {
944    GLint i;
945    GLdouble exponent = l->SpotExponent;
946    GLdouble tmp = 0;
947    GLint clamp = 0;
948
949    l->_SpotExpTable[0][0] = 0.0;
950
951    for (i = EXP_TABLE_SIZE - 1; i > 0 ;i--) {
952       if (clamp == 0) {
953          tmp = pow(i / (GLdouble) (EXP_TABLE_SIZE - 1), exponent);
954          if (tmp < FLT_MIN * 100.0) {
955             tmp = 0.0;
956             clamp = 1;
957          }
958       }
959       l->_SpotExpTable[i][0] = (GLfloat) tmp;
960    }
961    for (i = 0; i < EXP_TABLE_SIZE - 1; i++) {
962       l->_SpotExpTable[i][1] = (l->_SpotExpTable[i+1][0] -
963                                 l->_SpotExpTable[i][0]);
964    }
965    l->_SpotExpTable[EXP_TABLE_SIZE-1][1] = 0.0;
966 }
967
968
969
970 /* Calculate a new shine table.  Doing this here saves a branch in
971  * lighting, and the cost of doing it early may be partially offset
972  * by keeping a MRU cache of shine tables for various shine values.
973  */
974 void
975 _mesa_invalidate_shine_table( struct gl_context *ctx, GLuint side )
976 {
977    ASSERT(side < 2);
978    if (ctx->_ShineTable[side])
979       ctx->_ShineTable[side]->refcount--;
980    ctx->_ShineTable[side] = NULL;
981 }
982
983
984 static void
985 validate_shine_table( struct gl_context *ctx, GLuint side, GLfloat shininess )
986 {
987    struct gl_shine_tab *list = ctx->_ShineTabList;
988    struct gl_shine_tab *s;
989
990    ASSERT(side < 2);
991
992    foreach(s, list)
993       if ( s->shininess == shininess )
994          break;
995
996    if (s == list) {
997       GLint j;
998       GLfloat *m;
999
1000       foreach(s, list)
1001          if (s->refcount == 0)
1002             break;
1003
1004       m = s->tab;
1005       m[0] = 0.0;
1006       if (shininess == 0.0) {
1007          for (j = 1 ; j <= SHINE_TABLE_SIZE ; j++)
1008             m[j] = 1.0;
1009       }
1010       else {
1011          for (j = 1 ; j < SHINE_TABLE_SIZE ; j++) {
1012             GLdouble t, x = j / (GLfloat) (SHINE_TABLE_SIZE - 1);
1013             if (x < 0.005) /* underflow check */
1014                x = 0.005;
1015             t = pow(x, shininess);
1016             if (t > 1e-20)
1017                m[j] = (GLfloat) t;
1018             else
1019                m[j] = 0.0;
1020          }
1021          m[SHINE_TABLE_SIZE] = 1.0;
1022       }
1023
1024       s->shininess = shininess;
1025    }
1026
1027    if (ctx->_ShineTable[side])
1028       ctx->_ShineTable[side]->refcount--;
1029
1030    ctx->_ShineTable[side] = s;
1031    move_to_tail( list, s );
1032    s->refcount++;
1033 }
1034
1035
1036 void
1037 _mesa_validate_all_lighting_tables( struct gl_context *ctx )
1038 {
1039    GLuint i;
1040    GLfloat shininess;
1041    
1042    shininess = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SHININESS][0];
1043    if (!ctx->_ShineTable[0] || ctx->_ShineTable[0]->shininess != shininess)
1044       validate_shine_table( ctx, 0, shininess );
1045
1046    shininess = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SHININESS][0];
1047    if (!ctx->_ShineTable[1] || ctx->_ShineTable[1]->shininess != shininess)
1048       validate_shine_table( ctx, 1, shininess );
1049
1050    for (i = 0; i < ctx->Const.MaxLights; i++)
1051       if (ctx->Light.Light[i]._SpotExpTable[0][0] == -1)
1052          validate_spot_exp_table( &ctx->Light.Light[i] );
1053 }
1054
1055
1056 /**
1057  * Examine current lighting parameters to determine if the optimized lighting
1058  * function can be used.
1059  * Also, precompute some lighting values such as the products of light
1060  * source and material ambient, diffuse and specular coefficients.
1061  */
1062 void
1063 _mesa_update_lighting( struct gl_context *ctx )
1064 {
1065    struct gl_light *light;
1066    ctx->Light._NeedEyeCoords = GL_FALSE;
1067    ctx->Light._Flags = 0;
1068
1069    if (!ctx->Light.Enabled)
1070       return;
1071
1072    foreach(light, &ctx->Light.EnabledList) {
1073       ctx->Light._Flags |= light->_Flags;
1074    }
1075
1076    ctx->Light._NeedVertices =
1077       ((ctx->Light._Flags & (LIGHT_POSITIONAL|LIGHT_SPOT)) ||
1078        ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR ||
1079        ctx->Light.Model.LocalViewer);
1080
1081    ctx->Light._NeedEyeCoords = ((ctx->Light._Flags & LIGHT_POSITIONAL) ||
1082                                 ctx->Light.Model.LocalViewer);
1083
1084    /* XXX: This test is overkill & needs to be fixed both for software and
1085     * hardware t&l drivers.  The above should be sufficient & should
1086     * be tested to verify this.
1087     */
1088    if (ctx->Light._NeedVertices)
1089       ctx->Light._NeedEyeCoords = GL_TRUE;
1090
1091    /* Precompute some shading values.  Although we reference
1092     * Light.Material here, we can get away without flushing
1093     * FLUSH_UPDATE_CURRENT, as when any outstanding material changes
1094     * are flushed, they will update the derived state at that time.
1095     */
1096    if (ctx->Light.Model.TwoSide)
1097       _mesa_update_material(ctx,
1098                             MAT_BIT_FRONT_EMISSION |
1099                             MAT_BIT_FRONT_AMBIENT |
1100                             MAT_BIT_FRONT_DIFFUSE |
1101                             MAT_BIT_FRONT_SPECULAR |
1102                             MAT_BIT_BACK_EMISSION |
1103                             MAT_BIT_BACK_AMBIENT |
1104                             MAT_BIT_BACK_DIFFUSE |
1105                             MAT_BIT_BACK_SPECULAR);
1106    else
1107       _mesa_update_material(ctx,
1108                             MAT_BIT_FRONT_EMISSION |
1109                             MAT_BIT_FRONT_AMBIENT |
1110                             MAT_BIT_FRONT_DIFFUSE |
1111                             MAT_BIT_FRONT_SPECULAR);
1112 }
1113
1114
1115 /**
1116  * Update state derived from light position, spot direction.
1117  * Called upon:
1118  *   _NEW_MODELVIEW
1119  *   _NEW_LIGHT
1120  *   _TNL_NEW_NEED_EYE_COORDS
1121  *
1122  * Update on (_NEW_MODELVIEW | _NEW_LIGHT) when lighting is enabled.
1123  * Also update on lighting space changes.
1124  */
1125 static void
1126 compute_light_positions( struct gl_context *ctx )
1127 {
1128    struct gl_light *light;
1129    static const GLfloat eye_z[3] = { 0, 0, 1 };
1130
1131    if (!ctx->Light.Enabled)
1132       return;
1133
1134    if (ctx->_NeedEyeCoords) {
1135       COPY_3V( ctx->_EyeZDir, eye_z );
1136    }
1137    else {
1138       TRANSFORM_NORMAL( ctx->_EyeZDir, eye_z, ctx->ModelviewMatrixStack.Top->m );
1139    }
1140
1141    foreach (light, &ctx->Light.EnabledList) {
1142
1143       if (ctx->_NeedEyeCoords) {
1144          /* _Position is in eye coordinate space */
1145          COPY_4FV( light->_Position, light->EyePosition );
1146       }
1147       else {
1148          /* _Position is in object coordinate space */
1149          TRANSFORM_POINT( light->_Position, ctx->ModelviewMatrixStack.Top->inv,
1150                           light->EyePosition );
1151       }
1152
1153       if (!(light->_Flags & LIGHT_POSITIONAL)) {
1154          /* VP (VP) = Normalize( Position ) */
1155          COPY_3V( light->_VP_inf_norm, light->_Position );
1156          NORMALIZE_3FV( light->_VP_inf_norm );
1157
1158          if (!ctx->Light.Model.LocalViewer) {
1159             /* _h_inf_norm = Normalize( V_to_P + <0,0,1> ) */
1160             ADD_3V( light->_h_inf_norm, light->_VP_inf_norm, ctx->_EyeZDir);
1161             NORMALIZE_3FV( light->_h_inf_norm );
1162          }
1163          light->_VP_inf_spot_attenuation = 1.0;
1164       }
1165       else {
1166          /* positional light w/ homogeneous coordinate, divide by W */
1167          GLfloat wInv = (GLfloat)1.0 / light->_Position[3];
1168          light->_Position[0] *= wInv;
1169          light->_Position[1] *= wInv;
1170          light->_Position[2] *= wInv;
1171       }
1172
1173       if (light->_Flags & LIGHT_SPOT) {
1174          /* Note: we normalize the spot direction now */
1175
1176          if (ctx->_NeedEyeCoords) {
1177             COPY_3V( light->_NormSpotDirection, light->SpotDirection );
1178             NORMALIZE_3FV( light->_NormSpotDirection );
1179          }
1180          else {
1181             GLfloat spotDir[3];
1182             COPY_3V(spotDir, light->SpotDirection);
1183             NORMALIZE_3FV(spotDir);
1184             TRANSFORM_NORMAL( light->_NormSpotDirection,
1185                               spotDir,
1186                               ctx->ModelviewMatrixStack.Top->m);
1187          }
1188
1189          NORMALIZE_3FV( light->_NormSpotDirection );
1190
1191          if (!(light->_Flags & LIGHT_POSITIONAL)) {
1192             GLfloat PV_dot_dir = - DOT3(light->_VP_inf_norm,
1193                                         light->_NormSpotDirection);
1194
1195             if (PV_dot_dir > light->_CosCutoff) {
1196                double x = PV_dot_dir * (EXP_TABLE_SIZE-1);
1197                int k = (int) x;
1198                light->_VP_inf_spot_attenuation =
1199                   (GLfloat) (light->_SpotExpTable[k][0] +
1200                    (x-k)*light->_SpotExpTable[k][1]);
1201             }
1202             else {
1203                light->_VP_inf_spot_attenuation = 0;
1204             }
1205          }
1206       }
1207    }
1208 }
1209
1210
1211
1212 static void
1213 update_modelview_scale( struct gl_context *ctx )
1214 {
1215    ctx->_ModelViewInvScale = 1.0F;
1216    if (!_math_matrix_is_length_preserving(ctx->ModelviewMatrixStack.Top)) {
1217       const GLfloat *m = ctx->ModelviewMatrixStack.Top->inv;
1218       GLfloat f = m[2] * m[2] + m[6] * m[6] + m[10] * m[10];
1219       if (f < 1e-12) f = 1.0;
1220       if (ctx->_NeedEyeCoords)
1221          ctx->_ModelViewInvScale = (GLfloat) INV_SQRTF(f);
1222       else
1223          ctx->_ModelViewInvScale = (GLfloat) SQRTF(f);
1224    }
1225 }
1226
1227
1228 /**
1229  * Bring up to date any state that relies on _NeedEyeCoords.
1230  */
1231 void
1232 _mesa_update_tnl_spaces( struct gl_context *ctx, GLuint new_state )
1233 {
1234    const GLuint oldneedeyecoords = ctx->_NeedEyeCoords;
1235
1236    (void) new_state;
1237    ctx->_NeedEyeCoords = GL_FALSE;
1238
1239    if (ctx->_ForceEyeCoords ||
1240        (ctx->Texture._GenFlags & TEXGEN_NEED_EYE_COORD) ||
1241        ctx->Point._Attenuated ||
1242        ctx->Light._NeedEyeCoords)
1243       ctx->_NeedEyeCoords = GL_TRUE;
1244
1245    if (ctx->Light.Enabled &&
1246        !_math_matrix_is_length_preserving(ctx->ModelviewMatrixStack.Top))
1247       ctx->_NeedEyeCoords = GL_TRUE;
1248
1249    /* Check if the truth-value interpretations of the bitfields have
1250     * changed:
1251     */
1252    if (oldneedeyecoords != ctx->_NeedEyeCoords) {
1253       /* Recalculate all state that depends on _NeedEyeCoords.
1254        */
1255       update_modelview_scale(ctx);
1256       compute_light_positions( ctx );
1257
1258       if (ctx->Driver.LightingSpaceChange)
1259          ctx->Driver.LightingSpaceChange( ctx );
1260    }
1261    else {
1262       GLuint new_state2 = ctx->NewState;
1263
1264       /* Recalculate that same state only if it has been invalidated
1265        * by other statechanges.
1266        */
1267       if (new_state2 & _NEW_MODELVIEW)
1268          update_modelview_scale(ctx);
1269
1270       if (new_state2 & (_NEW_LIGHT|_NEW_MODELVIEW))
1271          compute_light_positions( ctx );
1272    }
1273 }
1274
1275
1276 /**
1277  * Drivers may need this if the hardware tnl unit doesn't support the
1278  * light-in-modelspace optimization.  It's also useful for debugging.
1279  */
1280 void
1281 _mesa_allow_light_in_model( struct gl_context *ctx, GLboolean flag )
1282 {
1283    ctx->_ForceEyeCoords = !flag;
1284    ctx->NewState |= _NEW_POINT; /* one of the bits from
1285                                  * _MESA_NEW_NEED_EYE_COORDS.
1286                                  */
1287 }
1288
1289
1290
1291 /**********************************************************************/
1292 /*****                      Initialization                        *****/
1293 /**********************************************************************/
1294
1295 /**
1296  * Initialize the n-th light data structure.
1297  *
1298  * \param l pointer to the gl_light structure to be initialized.
1299  * \param n number of the light. 
1300  * \note The defaults for light 0 are different than the other lights.
1301  */
1302 static void
1303 init_light( struct gl_light *l, GLuint n )
1304 {
1305    make_empty_list( l );
1306
1307    ASSIGN_4V( l->Ambient, 0.0, 0.0, 0.0, 1.0 );
1308    if (n==0) {
1309       ASSIGN_4V( l->Diffuse, 1.0, 1.0, 1.0, 1.0 );
1310       ASSIGN_4V( l->Specular, 1.0, 1.0, 1.0, 1.0 );
1311    }
1312    else {
1313       ASSIGN_4V( l->Diffuse, 0.0, 0.0, 0.0, 1.0 );
1314       ASSIGN_4V( l->Specular, 0.0, 0.0, 0.0, 1.0 );
1315    }
1316    ASSIGN_4V( l->EyePosition, 0.0, 0.0, 1.0, 0.0 );
1317    ASSIGN_3V( l->SpotDirection, 0.0, 0.0, -1.0 );
1318    l->SpotExponent = 0.0;
1319    _mesa_invalidate_spot_exp_table( l );
1320    l->SpotCutoff = 180.0;
1321    l->_CosCutoffNeg = -1.0f;
1322    l->_CosCutoff = 0.0;         /* KW: -ve values not admitted */
1323    l->ConstantAttenuation = 1.0;
1324    l->LinearAttenuation = 0.0;
1325    l->QuadraticAttenuation = 0.0;
1326    l->Enabled = GL_FALSE;
1327 }
1328
1329
1330 /**
1331  * Initialize the light model data structure.
1332  *
1333  * \param lm pointer to the gl_lightmodel structure to be initialized.
1334  */
1335 static void
1336 init_lightmodel( struct gl_lightmodel *lm )
1337 {
1338    ASSIGN_4V( lm->Ambient, 0.2F, 0.2F, 0.2F, 1.0F );
1339    lm->LocalViewer = GL_FALSE;
1340    lm->TwoSide = GL_FALSE;
1341    lm->ColorControl = GL_SINGLE_COLOR;
1342 }
1343
1344
1345 /**
1346  * Initialize the material data structure.
1347  * 
1348  * \param m pointer to the gl_material structure to be initialized.
1349  */
1350 static void
1351 init_material( struct gl_material *m )
1352 {
1353    ASSIGN_4V( m->Attrib[MAT_ATTRIB_FRONT_AMBIENT],  0.2F, 0.2F, 0.2F, 1.0F );
1354    ASSIGN_4V( m->Attrib[MAT_ATTRIB_FRONT_DIFFUSE],  0.8F, 0.8F, 0.8F, 1.0F );
1355    ASSIGN_4V( m->Attrib[MAT_ATTRIB_FRONT_SPECULAR], 0.0F, 0.0F, 0.0F, 1.0F );
1356    ASSIGN_4V( m->Attrib[MAT_ATTRIB_FRONT_EMISSION], 0.0F, 0.0F, 0.0F, 1.0F );
1357    ASSIGN_4V( m->Attrib[MAT_ATTRIB_FRONT_SHININESS], 0.0F, 0.0F, 0.0F, 0.0F );
1358    ASSIGN_4V( m->Attrib[MAT_ATTRIB_FRONT_INDEXES], 0.0F, 1.0F, 1.0F, 0.0F );
1359  
1360    ASSIGN_4V( m->Attrib[MAT_ATTRIB_BACK_AMBIENT],  0.2F, 0.2F, 0.2F, 1.0F );
1361    ASSIGN_4V( m->Attrib[MAT_ATTRIB_BACK_DIFFUSE],  0.8F, 0.8F, 0.8F, 1.0F );
1362    ASSIGN_4V( m->Attrib[MAT_ATTRIB_BACK_SPECULAR], 0.0F, 0.0F, 0.0F, 1.0F );
1363    ASSIGN_4V( m->Attrib[MAT_ATTRIB_BACK_EMISSION], 0.0F, 0.0F, 0.0F, 1.0F );
1364    ASSIGN_4V( m->Attrib[MAT_ATTRIB_BACK_SHININESS], 0.0F, 0.0F, 0.0F, 0.0F );
1365    ASSIGN_4V( m->Attrib[MAT_ATTRIB_BACK_INDEXES], 0.0F, 1.0F, 1.0F, 0.0F );
1366 }
1367
1368
1369 /**
1370  * Initialize all lighting state for the given context.
1371  */
1372 void
1373 _mesa_init_lighting( struct gl_context *ctx )
1374 {
1375    GLuint i;
1376
1377    /* Lighting group */
1378    for (i = 0; i < MAX_LIGHTS; i++) {
1379       init_light( &ctx->Light.Light[i], i );
1380    }
1381    make_empty_list( &ctx->Light.EnabledList );
1382
1383    init_lightmodel( &ctx->Light.Model );
1384    init_material( &ctx->Light.Material );
1385    ctx->Light.ShadeModel = GL_SMOOTH;
1386    ctx->Light.ProvokingVertex = GL_LAST_VERTEX_CONVENTION_EXT;
1387    ctx->Light.Enabled = GL_FALSE;
1388    ctx->Light.ColorMaterialFace = GL_FRONT_AND_BACK;
1389    ctx->Light.ColorMaterialMode = GL_AMBIENT_AND_DIFFUSE;
1390    ctx->Light.ColorMaterialBitmask = _mesa_material_bitmask( ctx,
1391                                                GL_FRONT_AND_BACK,
1392                                                GL_AMBIENT_AND_DIFFUSE, ~0,
1393                                                NULL );
1394
1395    ctx->Light.ColorMaterialEnabled = GL_FALSE;
1396    ctx->Light.ClampVertexColor = GL_TRUE;
1397
1398    /* Lighting miscellaneous */
1399    ctx->_ShineTabList = MALLOC_STRUCT( gl_shine_tab );
1400    make_empty_list( ctx->_ShineTabList );
1401    /* Allocate 10 (arbitrary) shininess lookup tables */
1402    for (i = 0 ; i < 10 ; i++) {
1403       struct gl_shine_tab *s = MALLOC_STRUCT( gl_shine_tab );
1404       s->shininess = -1;
1405       s->refcount = 0;
1406       insert_at_tail( ctx->_ShineTabList, s );
1407    }
1408
1409    /* Miscellaneous */
1410    ctx->Light._NeedEyeCoords = GL_FALSE;
1411    ctx->_NeedEyeCoords = GL_FALSE;
1412    ctx->_ForceEyeCoords = GL_FALSE;
1413    ctx->_ModelViewInvScale = 1.0;
1414 }
1415
1416
1417 /**
1418  * Deallocate malloc'd lighting state attached to given context.
1419  */
1420 void
1421 _mesa_free_lighting_data( struct gl_context *ctx )
1422 {
1423    struct gl_shine_tab *s, *tmps;
1424
1425    /* Free lighting shininess exponentiation table */
1426    foreach_s( s, tmps, ctx->_ShineTabList ) {
1427       free( s );
1428    }
1429    free( ctx->_ShineTabList );
1430 }