1 /* $Id: light.c,v 1.35 2001/01/23 23:39:36 brianp Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39 #include "simple_list.h"
42 #include "math/m_xform.h"
43 #include "math/m_matrix.h"
47 /* XXX this is a bit of a hack needed for compilation within XFree86 */
54 _mesa_ShadeModel( GLenum mode
)
56 GET_CURRENT_CONTEXT(ctx
);
57 ASSERT_OUTSIDE_BEGIN_END(ctx
);
59 if (MESA_VERBOSE
& VERBOSE_API
)
60 fprintf(stderr
, "glShadeModel %s\n", gl_lookup_enum_by_nr(mode
));
62 if (mode
!= GL_FLAT
&& mode
!= GL_SMOOTH
) {
63 gl_error( ctx
, GL_INVALID_ENUM
, "glShadeModel" );
67 if (ctx
->Light
.ShadeModel
== mode
)
70 FLUSH_VERTICES(ctx
, _NEW_LIGHT
);
71 ctx
->Light
.ShadeModel
= mode
;
72 ctx
->_TriangleCaps
^= DD_FLATSHADE
;
73 if (ctx
->Driver
.ShadeModel
)
74 (*ctx
->Driver
.ShadeModel
)( ctx
, mode
);
80 _mesa_Lightf( GLenum light
, GLenum pname
, GLfloat param
)
82 _mesa_Lightfv( light
, pname
, ¶m
);
87 _mesa_Lightfv( GLenum light
, GLenum pname
, const GLfloat
*params
)
89 GET_CURRENT_CONTEXT(ctx
);
90 GLint i
= (GLint
) (light
- GL_LIGHT0
);
91 struct gl_light
*l
= &ctx
->Light
.Light
[i
];
93 if (i
< 0 || i
>= ctx
->Const
.MaxLights
) {
94 gl_error( ctx
, GL_INVALID_ENUM
, "glLight" );
100 if (TEST_EQ_4V(l
->Ambient
, params
))
102 FLUSH_VERTICES(ctx
, _NEW_LIGHT
);
103 COPY_4V( l
->Ambient
, params
);
106 if (TEST_EQ_4V(l
->Diffuse
, params
))
108 FLUSH_VERTICES(ctx
, _NEW_LIGHT
);
109 COPY_4V( l
->Diffuse
, params
);
112 if (TEST_EQ_4V(l
->Specular
, params
))
114 FLUSH_VERTICES(ctx
, _NEW_LIGHT
);
115 COPY_4V( l
->Specular
, params
);
119 /* transform position by ModelView matrix */
120 TRANSFORM_POINT( tmp
, ctx
->ModelView
.m
, params
);
121 if (TEST_EQ_4V(l
->EyePosition
, tmp
))
123 FLUSH_VERTICES(ctx
, _NEW_LIGHT
);
124 COPY_4V(l
->EyePosition
, tmp
);
125 if (l
->EyePosition
[3] != 0.0F
)
126 l
->_Flags
|= LIGHT_POSITIONAL
;
128 l
->_Flags
&= ~LIGHT_POSITIONAL
;
131 case GL_SPOT_DIRECTION
: {
133 /* transform direction by inverse modelview */
134 if (ctx
->ModelView
.flags
& MAT_DIRTY_INVERSE
) {
135 _math_matrix_analyse( &ctx
->ModelView
);
137 TRANSFORM_NORMAL( tmp
, params
, ctx
->ModelView
.inv
);
138 if (TEST_EQ_3V(l
->EyeDirection
, tmp
))
140 FLUSH_VERTICES(ctx
, _NEW_LIGHT
);
141 COPY_3V(l
->EyeDirection
, tmp
);
144 case GL_SPOT_EXPONENT
:
145 if (params
[0]<0.0 || params
[0]>128.0) {
146 gl_error( ctx
, GL_INVALID_VALUE
, "glLight" );
149 if (l
->SpotExponent
== params
[0])
151 FLUSH_VERTICES(ctx
, _NEW_LIGHT
);
152 l
->SpotExponent
= params
[0];
153 gl_invalidate_spot_exp_table( l
);
156 if ((params
[0]<0.0 || params
[0]>90.0) && params
[0]!=180.0) {
157 gl_error( ctx
, GL_INVALID_VALUE
, "glLight" );
160 if (l
->SpotCutoff
== params
[0])
162 FLUSH_VERTICES(ctx
, _NEW_LIGHT
);
163 l
->SpotCutoff
= params
[0];
164 l
->_CosCutoff
= cos(params
[0]*DEG2RAD
);
165 if (l
->_CosCutoff
< 0)
167 if (l
->SpotCutoff
!= 180.0F
)
168 l
->_Flags
|= LIGHT_SPOT
;
170 l
->_Flags
&= ~LIGHT_SPOT
;
172 case GL_CONSTANT_ATTENUATION
:
174 gl_error( ctx
, GL_INVALID_VALUE
, "glLight" );
177 if (l
->ConstantAttenuation
== params
[0])
179 FLUSH_VERTICES(ctx
, _NEW_LIGHT
);
180 l
->ConstantAttenuation
= params
[0];
182 case GL_LINEAR_ATTENUATION
:
184 gl_error( ctx
, GL_INVALID_VALUE
, "glLight" );
187 if (l
->LinearAttenuation
== params
[0])
189 FLUSH_VERTICES(ctx
, _NEW_LIGHT
);
190 l
->LinearAttenuation
= params
[0];
192 case GL_QUADRATIC_ATTENUATION
:
194 gl_error( ctx
, GL_INVALID_VALUE
, "glLight" );
197 if (l
->QuadraticAttenuation
== params
[0])
199 FLUSH_VERTICES(ctx
, _NEW_LIGHT
);
200 l
->QuadraticAttenuation
= params
[0];
203 gl_error( ctx
, GL_INVALID_ENUM
, "glLight" );
207 if (ctx
->Driver
.Lightfv
)
208 ctx
->Driver
.Lightfv( ctx
, light
, pname
, params
);
213 _mesa_Lighti( GLenum light
, GLenum pname
, GLint param
)
215 _mesa_Lightiv( light
, pname
, ¶m
);
220 _mesa_Lightiv( GLenum light
, GLenum pname
, const GLint
*params
)
228 fparam
[0] = INT_TO_FLOAT( params
[0] );
229 fparam
[1] = INT_TO_FLOAT( params
[1] );
230 fparam
[2] = INT_TO_FLOAT( params
[2] );
231 fparam
[3] = INT_TO_FLOAT( params
[3] );
234 fparam
[0] = (GLfloat
) params
[0];
235 fparam
[1] = (GLfloat
) params
[1];
236 fparam
[2] = (GLfloat
) params
[2];
237 fparam
[3] = (GLfloat
) params
[3];
239 case GL_SPOT_DIRECTION
:
240 fparam
[0] = (GLfloat
) params
[0];
241 fparam
[1] = (GLfloat
) params
[1];
242 fparam
[2] = (GLfloat
) params
[2];
244 case GL_SPOT_EXPONENT
:
246 case GL_CONSTANT_ATTENUATION
:
247 case GL_LINEAR_ATTENUATION
:
248 case GL_QUADRATIC_ATTENUATION
:
249 fparam
[0] = (GLfloat
) params
[0];
252 /* error will be caught later in gl_Lightfv */
256 _mesa_Lightfv( light
, pname
, fparam
);
262 _mesa_GetLightfv( GLenum light
, GLenum pname
, GLfloat
*params
)
264 GET_CURRENT_CONTEXT(ctx
);
265 GLint l
= (GLint
) (light
- GL_LIGHT0
);
266 ASSERT_OUTSIDE_BEGIN_END(ctx
);
268 if (l
< 0 || l
>= ctx
->Const
.MaxLights
) {
269 gl_error( ctx
, GL_INVALID_ENUM
, "glGetLightfv" );
275 COPY_4V( params
, ctx
->Light
.Light
[l
].Ambient
);
278 COPY_4V( params
, ctx
->Light
.Light
[l
].Diffuse
);
281 COPY_4V( params
, ctx
->Light
.Light
[l
].Specular
);
284 COPY_4V( params
, ctx
->Light
.Light
[l
].EyePosition
);
286 case GL_SPOT_DIRECTION
:
287 COPY_3V( params
, ctx
->Light
.Light
[l
].EyeDirection
);
289 case GL_SPOT_EXPONENT
:
290 params
[0] = ctx
->Light
.Light
[l
].SpotExponent
;
293 params
[0] = ctx
->Light
.Light
[l
].SpotCutoff
;
295 case GL_CONSTANT_ATTENUATION
:
296 params
[0] = ctx
->Light
.Light
[l
].ConstantAttenuation
;
298 case GL_LINEAR_ATTENUATION
:
299 params
[0] = ctx
->Light
.Light
[l
].LinearAttenuation
;
301 case GL_QUADRATIC_ATTENUATION
:
302 params
[0] = ctx
->Light
.Light
[l
].QuadraticAttenuation
;
305 gl_error( ctx
, GL_INVALID_ENUM
, "glGetLightfv" );
313 _mesa_GetLightiv( GLenum light
, GLenum pname
, GLint
*params
)
315 GET_CURRENT_CONTEXT(ctx
);
316 GLint l
= (GLint
) (light
- GL_LIGHT0
);
317 ASSERT_OUTSIDE_BEGIN_END(ctx
);
319 if (l
< 0 || l
>= ctx
->Const
.MaxLights
) {
320 gl_error( ctx
, GL_INVALID_ENUM
, "glGetLightiv" );
326 params
[0] = FLOAT_TO_INT(ctx
->Light
.Light
[l
].Ambient
[0]);
327 params
[1] = FLOAT_TO_INT(ctx
->Light
.Light
[l
].Ambient
[1]);
328 params
[2] = FLOAT_TO_INT(ctx
->Light
.Light
[l
].Ambient
[2]);
329 params
[3] = FLOAT_TO_INT(ctx
->Light
.Light
[l
].Ambient
[3]);
332 params
[0] = FLOAT_TO_INT(ctx
->Light
.Light
[l
].Diffuse
[0]);
333 params
[1] = FLOAT_TO_INT(ctx
->Light
.Light
[l
].Diffuse
[1]);
334 params
[2] = FLOAT_TO_INT(ctx
->Light
.Light
[l
].Diffuse
[2]);
335 params
[3] = FLOAT_TO_INT(ctx
->Light
.Light
[l
].Diffuse
[3]);
338 params
[0] = FLOAT_TO_INT(ctx
->Light
.Light
[l
].Specular
[0]);
339 params
[1] = FLOAT_TO_INT(ctx
->Light
.Light
[l
].Specular
[1]);
340 params
[2] = FLOAT_TO_INT(ctx
->Light
.Light
[l
].Specular
[2]);
341 params
[3] = FLOAT_TO_INT(ctx
->Light
.Light
[l
].Specular
[3]);
344 params
[0] = (GLint
) ctx
->Light
.Light
[l
].EyePosition
[0];
345 params
[1] = (GLint
) ctx
->Light
.Light
[l
].EyePosition
[1];
346 params
[2] = (GLint
) ctx
->Light
.Light
[l
].EyePosition
[2];
347 params
[3] = (GLint
) ctx
->Light
.Light
[l
].EyePosition
[3];
349 case GL_SPOT_DIRECTION
:
350 params
[0] = (GLint
) ctx
->Light
.Light
[l
].EyeDirection
[0];
351 params
[1] = (GLint
) ctx
->Light
.Light
[l
].EyeDirection
[1];
352 params
[2] = (GLint
) ctx
->Light
.Light
[l
].EyeDirection
[2];
354 case GL_SPOT_EXPONENT
:
355 params
[0] = (GLint
) ctx
->Light
.Light
[l
].SpotExponent
;
358 params
[0] = (GLint
) ctx
->Light
.Light
[l
].SpotCutoff
;
360 case GL_CONSTANT_ATTENUATION
:
361 params
[0] = (GLint
) ctx
->Light
.Light
[l
].ConstantAttenuation
;
363 case GL_LINEAR_ATTENUATION
:
364 params
[0] = (GLint
) ctx
->Light
.Light
[l
].LinearAttenuation
;
366 case GL_QUADRATIC_ATTENUATION
:
367 params
[0] = (GLint
) ctx
->Light
.Light
[l
].QuadraticAttenuation
;
370 gl_error( ctx
, GL_INVALID_ENUM
, "glGetLightiv" );
377 /**********************************************************************/
378 /*** Light Model ***/
379 /**********************************************************************/
383 _mesa_LightModelfv( GLenum pname
, const GLfloat
*params
)
387 GET_CURRENT_CONTEXT(ctx
);
388 ASSERT_OUTSIDE_BEGIN_END(ctx
);
391 case GL_LIGHT_MODEL_AMBIENT
:
392 if (TEST_EQ_4V( ctx
->Light
.Model
.Ambient
, params
))
394 FLUSH_VERTICES(ctx
, _NEW_LIGHT
);
395 COPY_4V( ctx
->Light
.Model
.Ambient
, params
);
397 case GL_LIGHT_MODEL_LOCAL_VIEWER
:
398 newbool
= (params
[0]!=0.0);
399 if (ctx
->Light
.Model
.LocalViewer
== newbool
)
401 FLUSH_VERTICES(ctx
, _NEW_LIGHT
);
402 ctx
->Light
.Model
.LocalViewer
= newbool
;
404 case GL_LIGHT_MODEL_TWO_SIDE
:
405 newbool
= (params
[0]!=0.0);
406 if (ctx
->Light
.Model
.TwoSide
== newbool
)
408 FLUSH_VERTICES(ctx
, _NEW_LIGHT
);
409 ctx
->Light
.Model
.TwoSide
= newbool
;
411 case GL_LIGHT_MODEL_COLOR_CONTROL
:
412 if (params
[0] == (GLfloat
) GL_SINGLE_COLOR
)
413 newenum
= GL_SINGLE_COLOR
;
414 else if (params
[0] == (GLfloat
) GL_SEPARATE_SPECULAR_COLOR
)
415 newenum
= GL_SEPARATE_SPECULAR_COLOR
;
417 gl_error( ctx
, GL_INVALID_ENUM
, "glLightModel(param)" );
420 if (ctx
->Light
.Model
.ColorControl
== newenum
)
422 FLUSH_VERTICES(ctx
, _NEW_LIGHT
);
423 ctx
->Light
.Model
.ColorControl
= newenum
;
424 ctx
->_TriangleCaps
^= DD_SEPERATE_SPECULAR
;
427 gl_error( ctx
, GL_INVALID_ENUM
, "glLightModel" );
431 if (ctx
->Driver
.LightModelfv
)
432 ctx
->Driver
.LightModelfv( ctx
, pname
, params
);
437 _mesa_LightModeliv( GLenum pname
, const GLint
*params
)
442 case GL_LIGHT_MODEL_AMBIENT
:
443 fparam
[0] = INT_TO_FLOAT( params
[0] );
444 fparam
[1] = INT_TO_FLOAT( params
[1] );
445 fparam
[2] = INT_TO_FLOAT( params
[2] );
446 fparam
[3] = INT_TO_FLOAT( params
[3] );
448 case GL_LIGHT_MODEL_LOCAL_VIEWER
:
449 case GL_LIGHT_MODEL_TWO_SIDE
:
450 case GL_LIGHT_MODEL_COLOR_CONTROL
:
451 fparam
[0] = (GLfloat
) params
[0];
454 /* Error will be caught later in gl_LightModelfv */
457 _mesa_LightModelfv( pname
, fparam
);
462 _mesa_LightModeli( GLenum pname
, GLint param
)
464 _mesa_LightModeliv( pname
, ¶m
);
469 _mesa_LightModelf( GLenum pname
, GLfloat param
)
471 _mesa_LightModelfv( pname
, ¶m
);
476 /********** MATERIAL **********/
480 * Given a face and pname value (ala glColorMaterial), compute a bitmask
481 * of the targeted material values.
483 GLuint
gl_material_bitmask( GLcontext
*ctx
, GLenum face
, GLenum pname
,
489 /* Make a bitmask indicating what material attribute(s) we're updating */
492 bitmask
|= FRONT_EMISSION_BIT
| BACK_EMISSION_BIT
;
495 bitmask
|= FRONT_AMBIENT_BIT
| BACK_AMBIENT_BIT
;
498 bitmask
|= FRONT_DIFFUSE_BIT
| BACK_DIFFUSE_BIT
;
501 bitmask
|= FRONT_SPECULAR_BIT
| BACK_SPECULAR_BIT
;
504 bitmask
|= FRONT_SHININESS_BIT
| BACK_SHININESS_BIT
;
506 case GL_AMBIENT_AND_DIFFUSE
:
507 bitmask
|= FRONT_AMBIENT_BIT
| BACK_AMBIENT_BIT
;
508 bitmask
|= FRONT_DIFFUSE_BIT
| BACK_DIFFUSE_BIT
;
510 case GL_COLOR_INDEXES
:
511 bitmask
|= FRONT_INDEXES_BIT
| BACK_INDEXES_BIT
;
514 gl_error( ctx
, GL_INVALID_ENUM
, where
);
518 if (face
==GL_FRONT
) {
519 bitmask
&= FRONT_MATERIAL_BITS
;
521 else if (face
==GL_BACK
) {
522 bitmask
&= BACK_MATERIAL_BITS
;
524 else if (face
!= GL_FRONT_AND_BACK
) {
525 gl_error( ctx
, GL_INVALID_ENUM
, where
);
529 if (bitmask
& ~legal
) {
530 gl_error( ctx
, GL_INVALID_ENUM
, where
);
540 * Check if the global material has to be updated with info that was
541 * associated with a vertex via glMaterial.
542 * This function is used when any material values get changed between
543 * glBegin/glEnd either by calling glMaterial() or by calling glColor()
544 * when GL_COLOR_MATERIAL is enabled.
546 * src[0] is front material, src[1] is back material
548 * KW: Added code here to keep the precomputed variables uptodate.
549 * This means we can use the faster shade functions when using
550 * GL_COLOR_MATERIAL, and we can also now use the precomputed
551 * values in the slower shading functions, which further offsets
552 * the cost of doing this here.
554 void gl_update_material( GLcontext
*ctx
,
555 const struct gl_material src
[2],
558 struct gl_light
*light
, *list
= &ctx
->Light
.EnabledList
;
560 if (ctx
->Light
.ColorMaterialEnabled
)
561 bitmask
&= ~ctx
->Light
.ColorMaterialBitmask
;
563 if (MESA_VERBOSE
&VERBOSE_IMMEDIATE
)
564 fprintf(stderr
, "gl_update_material, mask 0x%x\n", bitmask
);
569 /* update material emission */
570 if (bitmask
& FRONT_EMISSION_BIT
) {
571 struct gl_material
*mat
= &ctx
->Light
.Material
[0];
572 COPY_4FV( mat
->Emission
, src
[0].Emission
);
574 if (bitmask
& BACK_EMISSION_BIT
) {
575 struct gl_material
*mat
= &ctx
->Light
.Material
[1];
576 COPY_4FV( mat
->Emission
, src
[1].Emission
);
579 /* update material ambience */
580 if (bitmask
& FRONT_AMBIENT_BIT
) {
581 struct gl_material
*mat
= &ctx
->Light
.Material
[0];
582 COPY_4FV( mat
->Ambient
, src
[0].Ambient
);
583 foreach (light
, list
) {
584 SCALE_3V( light
->_MatAmbient
[0], light
->Ambient
, src
[0].Ambient
);
587 if (bitmask
& BACK_AMBIENT_BIT
) {
588 struct gl_material
*mat
= &ctx
->Light
.Material
[1];
589 COPY_4FV( mat
->Ambient
, src
[1].Ambient
);
590 foreach (light
, list
) {
591 SCALE_3V( light
->_MatAmbient
[1], light
->Ambient
, src
[1].Ambient
);
595 /* update BaseColor = emission + scene's ambience * material's ambience */
596 if (bitmask
& (FRONT_EMISSION_BIT
| FRONT_AMBIENT_BIT
)) {
597 struct gl_material
*mat
= &ctx
->Light
.Material
[0];
598 COPY_3V( ctx
->Light
._BaseColor
[0], mat
->Emission
);
599 ACC_SCALE_3V( ctx
->Light
._BaseColor
[0], mat
->Ambient
,
600 ctx
->Light
.Model
.Ambient
);
602 if (bitmask
& (BACK_EMISSION_BIT
| BACK_AMBIENT_BIT
)) {
603 struct gl_material
*mat
= &ctx
->Light
.Material
[1];
604 COPY_3V( ctx
->Light
._BaseColor
[1], mat
->Emission
);
605 ACC_SCALE_3V( ctx
->Light
._BaseColor
[1], mat
->Ambient
,
606 ctx
->Light
.Model
.Ambient
);
609 /* update material diffuse values */
610 if (bitmask
& FRONT_DIFFUSE_BIT
) {
611 struct gl_material
*mat
= &ctx
->Light
.Material
[0];
612 COPY_4FV( mat
->Diffuse
, src
[0].Diffuse
);
613 /* fprintf(stderr, "FRONT_DIFFUSE %f %f %f %f\n", */
614 /* mat->Diffuse[0], mat->Diffuse[1], */
615 /* mat->Diffuse[2], mat->Diffuse[3]); */
616 foreach (light
, list
) {
617 SCALE_3V( light
->_MatDiffuse
[0], light
->Diffuse
, mat
->Diffuse
);
619 UNCLAMPED_FLOAT_TO_CHAN(ctx
->Light
._BaseAlpha
[0], mat
->Diffuse
[3]);
621 if (bitmask
& BACK_DIFFUSE_BIT
) {
622 struct gl_material
*mat
= &ctx
->Light
.Material
[1];
623 COPY_4FV( mat
->Diffuse
, src
[1].Diffuse
);
624 /* fprintf(stderr, "BACK_DIFFUSE %f %f %f %f\n", */
625 /* mat->Diffuse[0], mat->Diffuse[1], */
626 /* mat->Diffuse[2], mat->Diffuse[3]); */
627 foreach (light
, list
) {
628 SCALE_3V( light
->_MatDiffuse
[1], light
->Diffuse
, mat
->Diffuse
);
630 UNCLAMPED_FLOAT_TO_CHAN(ctx
->Light
._BaseAlpha
[1], mat
->Diffuse
[3]);
633 /* update material specular values */
634 if (bitmask
& FRONT_SPECULAR_BIT
) {
635 struct gl_material
*mat
= &ctx
->Light
.Material
[0];
636 COPY_4FV( mat
->Specular
, src
[0].Specular
);
637 foreach (light
, list
) {
638 SCALE_3V( light
->_MatSpecular
[0], light
->Specular
, mat
->Specular
);
641 if (bitmask
& BACK_SPECULAR_BIT
) {
642 struct gl_material
*mat
= &ctx
->Light
.Material
[1];
643 COPY_4FV( mat
->Specular
, src
[1].Specular
);
644 foreach (light
, list
) {
645 SCALE_3V( light
->_MatSpecular
[1], light
->Specular
, mat
->Specular
);
649 if (bitmask
& FRONT_SHININESS_BIT
) {
650 /* fprintf(stderr, "FRONT_SHININESS_BIT %f\n", src[0].Shininess); */
651 ctx
->Light
.Material
[0].Shininess
= src
[0].Shininess
;
652 gl_invalidate_shine_table( ctx
, 0 );
654 if (bitmask
& BACK_SHININESS_BIT
) {
655 ctx
->Light
.Material
[1].Shininess
= src
[1].Shininess
;
656 gl_invalidate_shine_table( ctx
, 1 );
659 if (bitmask
& FRONT_INDEXES_BIT
) {
660 ctx
->Light
.Material
[0].AmbientIndex
= src
[0].AmbientIndex
;
661 ctx
->Light
.Material
[0].DiffuseIndex
= src
[0].DiffuseIndex
;
662 ctx
->Light
.Material
[0].SpecularIndex
= src
[0].SpecularIndex
;
664 if (bitmask
& BACK_INDEXES_BIT
) {
665 ctx
->Light
.Material
[1].AmbientIndex
= src
[1].AmbientIndex
;
666 ctx
->Light
.Material
[1].DiffuseIndex
= src
[1].DiffuseIndex
;
667 ctx
->Light
.Material
[1].SpecularIndex
= src
[1].SpecularIndex
;
672 struct gl_material
*mat
= &ctx
->Light
.Material
[0];
673 fprintf(stderr
, "update_mat emission : %f %f %f\n",
677 fprintf(stderr
, "update_mat specular : %f %f %f\n",
681 fprintf(stderr
, "update_mat diffuse : %f %f %f\n",
685 fprintf(stderr
, "update_mat ambient : %f %f %f\n",
696 * Update the current materials from the given rgba color
697 * according to the bitmask in ColorMaterialBitmask, which is
698 * set by glColorMaterial().
700 void gl_update_color_material( GLcontext
*ctx
,
701 const GLchan rgba
[4] )
703 struct gl_light
*light
, *list
= &ctx
->Light
.EnabledList
;
704 GLuint bitmask
= ctx
->Light
.ColorMaterialBitmask
;
707 color
[0] = CHAN_TO_FLOAT(rgba
[0]);
708 color
[1] = CHAN_TO_FLOAT(rgba
[1]);
709 color
[2] = CHAN_TO_FLOAT(rgba
[2]);
710 color
[3] = CHAN_TO_FLOAT(rgba
[3]);
712 if (MESA_VERBOSE
&VERBOSE_IMMEDIATE
)
713 fprintf(stderr
, "gl_update_color_material, mask 0x%x\n", bitmask
);
715 /* update emissive colors */
716 if (bitmask
& FRONT_EMISSION_BIT
) {
717 struct gl_material
*mat
= &ctx
->Light
.Material
[0];
718 COPY_4FV( mat
->Emission
, color
);
721 if (bitmask
& BACK_EMISSION_BIT
) {
722 struct gl_material
*mat
= &ctx
->Light
.Material
[1];
723 COPY_4FV( mat
->Emission
, color
);
726 /* update light->_MatAmbient = light's ambient * material's ambient */
727 if (bitmask
& FRONT_AMBIENT_BIT
) {
728 struct gl_material
*mat
= &ctx
->Light
.Material
[0];
729 foreach (light
, list
) {
730 SCALE_3V( light
->_MatAmbient
[0], light
->Ambient
, color
);
732 COPY_4FV( mat
->Ambient
, color
);
735 if (bitmask
& BACK_AMBIENT_BIT
) {
736 struct gl_material
*mat
= &ctx
->Light
.Material
[1];
737 foreach (light
, list
) {
738 SCALE_3V( light
->_MatAmbient
[1], light
->Ambient
, color
);
740 COPY_4FV( mat
->Ambient
, color
);
743 /* update BaseColor = emission + scene's ambience * material's ambience */
744 if (bitmask
& (FRONT_EMISSION_BIT
| FRONT_AMBIENT_BIT
)) {
745 struct gl_material
*mat
= &ctx
->Light
.Material
[0];
746 COPY_3V( ctx
->Light
._BaseColor
[0], mat
->Emission
);
747 ACC_SCALE_3V( ctx
->Light
._BaseColor
[0], mat
->Ambient
, ctx
->Light
.Model
.Ambient
);
750 if (bitmask
& (BACK_EMISSION_BIT
| BACK_AMBIENT_BIT
)) {
751 struct gl_material
*mat
= &ctx
->Light
.Material
[1];
752 COPY_3V( ctx
->Light
._BaseColor
[1], mat
->Emission
);
753 ACC_SCALE_3V( ctx
->Light
._BaseColor
[1], mat
->Ambient
, ctx
->Light
.Model
.Ambient
);
756 /* update light->_MatDiffuse = light's diffuse * material's diffuse */
757 if (bitmask
& FRONT_DIFFUSE_BIT
) {
758 struct gl_material
*mat
= &ctx
->Light
.Material
[0];
759 COPY_4FV( mat
->Diffuse
, color
);
760 foreach (light
, list
) {
761 SCALE_3V( light
->_MatDiffuse
[0], light
->Diffuse
, mat
->Diffuse
);
763 UNCLAMPED_FLOAT_TO_CHAN(ctx
->Light
._BaseAlpha
[0], mat
->Diffuse
[3]);
766 if (bitmask
& BACK_DIFFUSE_BIT
) {
767 struct gl_material
*mat
= &ctx
->Light
.Material
[1];
768 COPY_4FV( mat
->Diffuse
, color
);
769 foreach (light
, list
) {
770 SCALE_3V( light
->_MatDiffuse
[1], light
->Diffuse
, mat
->Diffuse
);
772 UNCLAMPED_FLOAT_TO_CHAN(ctx
->Light
._BaseAlpha
[1], mat
->Diffuse
[3]);
775 /* update light->_MatSpecular = light's specular * material's specular */
776 if (bitmask
& FRONT_SPECULAR_BIT
) {
777 struct gl_material
*mat
= &ctx
->Light
.Material
[0];
778 COPY_4FV( mat
->Specular
, color
);
779 foreach (light
, list
) {
780 ACC_SCALE_3V( light
->_MatSpecular
[0], light
->Specular
, mat
->Specular
);
784 if (bitmask
& BACK_SPECULAR_BIT
) {
785 struct gl_material
*mat
= &ctx
->Light
.Material
[1];
786 COPY_4FV( mat
->Specular
, color
);
787 foreach (light
, list
) {
788 ACC_SCALE_3V( light
->_MatSpecular
[1], light
->Specular
, mat
->Specular
);
794 struct gl_material
*mat
= &ctx
->Light
.Material
[0];
795 fprintf(stderr
, "update_color_mat emission : %f %f %f\n",
799 fprintf(stderr
, "update_color_mat specular : %f %f %f\n",
803 fprintf(stderr
, "update_color_mat diffuse : %f %f %f\n",
807 fprintf(stderr
, "update_color_mat ambient : %f %f %f\n",
818 _mesa_ColorMaterial( GLenum face
, GLenum mode
)
820 GET_CURRENT_CONTEXT(ctx
);
822 GLuint legal
= (FRONT_EMISSION_BIT
| BACK_EMISSION_BIT
|
823 FRONT_SPECULAR_BIT
| BACK_SPECULAR_BIT
|
824 FRONT_DIFFUSE_BIT
| BACK_DIFFUSE_BIT
|
825 FRONT_AMBIENT_BIT
| BACK_AMBIENT_BIT
);
826 ASSERT_OUTSIDE_BEGIN_END(ctx
);
828 if (MESA_VERBOSE
&VERBOSE_API
)
829 fprintf(stderr
, "glColorMaterial %s %s\n",
830 gl_lookup_enum_by_nr(face
),
831 gl_lookup_enum_by_nr(mode
));
833 bitmask
= gl_material_bitmask( ctx
, face
, mode
, legal
, "glColorMaterial" );
835 if (ctx
->Light
.ColorMaterialBitmask
== bitmask
&&
836 ctx
->Light
.ColorMaterialFace
== face
&&
837 ctx
->Light
.ColorMaterialMode
== mode
)
840 FLUSH_VERTICES(ctx
, _NEW_LIGHT
);
841 ctx
->Light
.ColorMaterialBitmask
= bitmask
;
842 ctx
->Light
.ColorMaterialFace
= face
;
843 ctx
->Light
.ColorMaterialMode
= mode
;
845 if (ctx
->Light
.ColorMaterialEnabled
) {
846 FLUSH_CURRENT( ctx
, 0 );
847 gl_update_color_material( ctx
, ctx
->Current
.Color
);
856 _mesa_GetMaterialfv( GLenum face
, GLenum pname
, GLfloat
*params
)
858 GET_CURRENT_CONTEXT(ctx
);
860 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
); /* update materials */
862 if (face
==GL_FRONT
) {
865 else if (face
==GL_BACK
) {
869 gl_error( ctx
, GL_INVALID_ENUM
, "glGetMaterialfv(face)" );
874 COPY_4FV( params
, ctx
->Light
.Material
[f
].Ambient
);
877 COPY_4FV( params
, ctx
->Light
.Material
[f
].Diffuse
);
880 COPY_4FV( params
, ctx
->Light
.Material
[f
].Specular
);
883 COPY_4FV( params
, ctx
->Light
.Material
[f
].Emission
);
886 *params
= ctx
->Light
.Material
[f
].Shininess
;
888 case GL_COLOR_INDEXES
:
889 params
[0] = ctx
->Light
.Material
[f
].AmbientIndex
;
890 params
[1] = ctx
->Light
.Material
[f
].DiffuseIndex
;
891 params
[2] = ctx
->Light
.Material
[f
].SpecularIndex
;
894 gl_error( ctx
, GL_INVALID_ENUM
, "glGetMaterialfv(pname)" );
901 _mesa_GetMaterialiv( GLenum face
, GLenum pname
, GLint
*params
)
903 GET_CURRENT_CONTEXT(ctx
);
905 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
); /* update materials */
907 if (face
==GL_FRONT
) {
910 else if (face
==GL_BACK
) {
914 gl_error( ctx
, GL_INVALID_ENUM
, "glGetMaterialiv(face)" );
919 params
[0] = FLOAT_TO_INT( ctx
->Light
.Material
[f
].Ambient
[0] );
920 params
[1] = FLOAT_TO_INT( ctx
->Light
.Material
[f
].Ambient
[1] );
921 params
[2] = FLOAT_TO_INT( ctx
->Light
.Material
[f
].Ambient
[2] );
922 params
[3] = FLOAT_TO_INT( ctx
->Light
.Material
[f
].Ambient
[3] );
925 params
[0] = FLOAT_TO_INT( ctx
->Light
.Material
[f
].Diffuse
[0] );
926 params
[1] = FLOAT_TO_INT( ctx
->Light
.Material
[f
].Diffuse
[1] );
927 params
[2] = FLOAT_TO_INT( ctx
->Light
.Material
[f
].Diffuse
[2] );
928 params
[3] = FLOAT_TO_INT( ctx
->Light
.Material
[f
].Diffuse
[3] );
931 params
[0] = FLOAT_TO_INT( ctx
->Light
.Material
[f
].Specular
[0] );
932 params
[1] = FLOAT_TO_INT( ctx
->Light
.Material
[f
].Specular
[1] );
933 params
[2] = FLOAT_TO_INT( ctx
->Light
.Material
[f
].Specular
[2] );
934 params
[3] = FLOAT_TO_INT( ctx
->Light
.Material
[f
].Specular
[3] );
937 params
[0] = FLOAT_TO_INT( ctx
->Light
.Material
[f
].Emission
[0] );
938 params
[1] = FLOAT_TO_INT( ctx
->Light
.Material
[f
].Emission
[1] );
939 params
[2] = FLOAT_TO_INT( ctx
->Light
.Material
[f
].Emission
[2] );
940 params
[3] = FLOAT_TO_INT( ctx
->Light
.Material
[f
].Emission
[3] );
943 *params
= ROUNDF( ctx
->Light
.Material
[f
].Shininess
);
945 case GL_COLOR_INDEXES
:
946 params
[0] = ROUNDF( ctx
->Light
.Material
[f
].AmbientIndex
);
947 params
[1] = ROUNDF( ctx
->Light
.Material
[f
].DiffuseIndex
);
948 params
[2] = ROUNDF( ctx
->Light
.Material
[f
].SpecularIndex
);
951 gl_error( ctx
, GL_INVALID_ENUM
, "glGetMaterialfv(pname)" );
958 /**********************************************************************/
959 /***** Lighting computation *****/
960 /**********************************************************************/
965 * When two-sided lighting is enabled we compute the color (or index)
966 * for both the front and back side of the primitive. Then, when the
967 * orientation of the facet is later learned, we can determine which
968 * color (or index) to use for rendering.
970 * KW: We now know orientation in advance and only shade for
971 * the side or sides which are actually required.
975 * V = vertex position
976 * P = light source position
981 * // light at infinity
982 * IF local_viewer THEN
983 * _VP_inf_norm = unit vector from V to P // Precompute
986 * _h_inf_norm = Normalize( VP + <0,0,1> ) // Precompute
991 * Normalize( v ) = normalized vector v
992 * Magnitude( v ) = length of vector v
998 * Whenever the spotlight exponent for a light changes we must call
999 * this function to recompute the exponent lookup table.
1002 gl_invalidate_spot_exp_table( struct gl_light
*l
)
1004 l
->_SpotExpTable
[0][0] = -1;
1007 static void validate_spot_exp_table( struct gl_light
*l
)
1010 GLdouble exponent
= l
->SpotExponent
;
1014 l
->_SpotExpTable
[0][0] = 0.0;
1016 for (i
= EXP_TABLE_SIZE
- 1; i
> 0 ;i
--) {
1018 tmp
= pow(i
/ (GLdouble
) (EXP_TABLE_SIZE
- 1), exponent
);
1019 if (tmp
< FLT_MIN
* 100.0) {
1024 l
->_SpotExpTable
[i
][0] = tmp
;
1026 for (i
= 0; i
< EXP_TABLE_SIZE
- 1; i
++) {
1027 l
->_SpotExpTable
[i
][1] = (l
->_SpotExpTable
[i
+1][0] -
1028 l
->_SpotExpTable
[i
][0]);
1030 l
->_SpotExpTable
[EXP_TABLE_SIZE
-1][1] = 0.0;
1036 /* Calculate a new shine table. Doing this here saves a branch in
1037 * lighting, and the cost of doing it early may be partially offset
1038 * by keeping a MRU cache of shine tables for various shine values.
1041 gl_invalidate_shine_table( GLcontext
*ctx
, GLuint i
)
1043 if (ctx
->_ShineTable
[i
])
1044 ctx
->_ShineTable
[i
]->refcount
--;
1045 ctx
->_ShineTable
[i
] = 0;
1048 static void validate_shine_table( GLcontext
*ctx
, GLuint i
, GLfloat shininess
)
1050 struct gl_shine_tab
*list
= ctx
->_ShineTabList
;
1051 struct gl_shine_tab
*s
;
1054 if ( s
->shininess
== shininess
)
1062 if (s
->refcount
== 0)
1067 if (shininess
== 0.0) {
1068 for (j
= 1 ; j
<= SHINE_TABLE_SIZE
; j
++)
1072 for (j
= 1 ; j
< SHINE_TABLE_SIZE
; j
++) {
1073 GLdouble t
, x
= j
/ (GLfloat
) (SHINE_TABLE_SIZE
- 1);
1074 if (x
< 0.005) /* underflow check */
1076 t
= pow(x
, shininess
);
1082 m
[SHINE_TABLE_SIZE
] = 1.0;
1085 s
->shininess
= shininess
;
1088 if (ctx
->_ShineTable
[i
])
1089 ctx
->_ShineTable
[i
]->refcount
--;
1091 ctx
->_ShineTable
[i
] = s
;
1092 move_to_tail( list
, s
);
1097 gl_validate_all_lighting_tables( GLcontext
*ctx
)
1102 shininess
= ctx
->Light
.Material
[0].Shininess
;
1103 if (!ctx
->_ShineTable
[0]) validate_shine_table( ctx
, 0, shininess
);
1105 shininess
= ctx
->Light
.Material
[1].Shininess
;
1106 if (!ctx
->_ShineTable
[1]) validate_shine_table( ctx
, 1, shininess
);
1108 for (i
= 0 ; i
< MAX_LIGHTS
; i
++)
1109 if (ctx
->Light
.Light
[i
]._SpotExpTable
[0][0] == -1)
1110 validate_spot_exp_table( &ctx
->Light
.Light
[i
] );
1117 * Examine current lighting parameters to determine if the optimized lighting
1118 * function can be used.
1119 * Also, precompute some lighting values such as the products of light
1120 * source and material ambient, diffuse and specular coefficients.
1123 gl_update_lighting( GLcontext
*ctx
)
1125 struct gl_light
*light
;
1126 ctx
->_TriangleCaps
&= ~DD_TRI_LIGHT_TWOSIDE
;
1127 ctx
->_NeedEyeCoords
&= ~NEED_EYE_LIGHT
;
1128 ctx
->_NeedNormals
&= ~NEED_NORMALS_LIGHT
;
1129 ctx
->Light
._Flags
= 0;
1131 if (!ctx
->Light
.Enabled
)
1134 ctx
->_NeedNormals
|= NEED_NORMALS_LIGHT
;
1136 if (ctx
->Light
.Model
.TwoSide
)
1137 ctx
->_TriangleCaps
|= DD_TRI_LIGHT_TWOSIDE
;
1139 foreach(light
, &ctx
->Light
.EnabledList
) {
1140 ctx
->Light
._Flags
|= light
->_Flags
;
1143 ctx
->Light
._NeedVertices
=
1144 ((ctx
->Light
._Flags
& (LIGHT_POSITIONAL
|LIGHT_SPOT
)) ||
1145 ctx
->Light
.Model
.ColorControl
== GL_SEPARATE_SPECULAR_COLOR
||
1146 ctx
->Light
.Model
.LocalViewer
);
1148 if ((ctx
->Light
._Flags
& LIGHT_POSITIONAL
) ||
1149 ctx
->Light
.Model
.LocalViewer
)
1150 ctx
->_NeedEyeCoords
|= NEED_EYE_LIGHT
;
1153 /* XXX: This test is overkill & needs to be fixed both for software and
1154 * hardware t&l drivers. The above should be sufficient & should
1155 * be tested to verify this.
1157 if (ctx
->Light
._NeedVertices
)
1158 ctx
->_NeedEyeCoords
|= NEED_EYE_LIGHT
;
1161 /* Precompute some shading values. Although we reference
1162 * Light.Material here, we can get away without flushing
1163 * FLUSH_UPDATE_CURRENT, as when any outstanding material changes
1164 * are flushed, they will update the derived state at that time.
1166 if (ctx
->Visual
.rgbMode
) {
1167 GLuint sides
= ctx
->Light
.Model
.TwoSide
? 2 : 1;
1169 for (side
=0; side
< sides
; side
++) {
1170 struct gl_material
*mat
= &ctx
->Light
.Material
[side
];
1172 COPY_3V(ctx
->Light
._BaseColor
[side
], mat
->Emission
);
1173 ACC_SCALE_3V(ctx
->Light
._BaseColor
[side
],
1174 ctx
->Light
.Model
.Ambient
,
1177 UNCLAMPED_FLOAT_TO_CHAN(ctx
->Light
._BaseAlpha
[side
],
1178 ctx
->Light
.Material
[side
].Diffuse
[3] );
1181 foreach (light
, &ctx
->Light
.EnabledList
) {
1182 for (side
=0; side
< sides
; side
++) {
1183 const struct gl_material
*mat
= &ctx
->Light
.Material
[side
];
1184 SCALE_3V( light
->_MatDiffuse
[side
], light
->Diffuse
, mat
->Diffuse
);
1185 SCALE_3V( light
->_MatAmbient
[side
], light
->Ambient
, mat
->Ambient
);
1186 SCALE_3V( light
->_MatSpecular
[side
], light
->Specular
,
1192 static const GLfloat ci
[3] = { .30, .59, .11 };
1193 foreach(light
, &ctx
->Light
.EnabledList
) {
1194 light
->_dli
= DOT3(ci
, light
->Diffuse
);
1195 light
->_sli
= DOT3(ci
, light
->Specular
);
1203 * _TNL_NEW_NEED_EYE_COORDS
1205 * Update on (_NEW_MODELVIEW | _NEW_LIGHT) when lighting is enabled.
1206 * Also update on lighting space changes.
1209 gl_compute_light_positions( GLcontext
*ctx
)
1211 struct gl_light
*light
;
1212 static const GLfloat eye_z
[3] = { 0, 0, 1 };
1214 if (!ctx
->Light
.Enabled
)
1217 if (ctx
->_NeedEyeCoords
) {
1218 COPY_3V( ctx
->_EyeZDir
, eye_z
);
1221 TRANSFORM_NORMAL( ctx
->_EyeZDir
, eye_z
, ctx
->ModelView
.m
);
1224 foreach (light
, &ctx
->Light
.EnabledList
) {
1226 if (ctx
->_NeedEyeCoords
) {
1227 COPY_4FV( light
->_Position
, light
->EyePosition
);
1230 TRANSFORM_POINT( light
->_Position
, ctx
->ModelView
.inv
,
1231 light
->EyePosition
);
1234 if (!(light
->_Flags
& LIGHT_POSITIONAL
)) {
1235 /* VP (VP) = Normalize( Position ) */
1236 COPY_3V( light
->_VP_inf_norm
, light
->_Position
);
1237 NORMALIZE_3FV( light
->_VP_inf_norm
);
1239 if (!ctx
->Light
.Model
.LocalViewer
) {
1240 /* _h_inf_norm = Normalize( V_to_P + <0,0,1> ) */
1241 ADD_3V( light
->_h_inf_norm
, light
->_VP_inf_norm
, ctx
->_EyeZDir
);
1242 NORMALIZE_3FV( light
->_h_inf_norm
);
1244 light
->_VP_inf_spot_attenuation
= 1.0;
1247 if (light
->_Flags
& LIGHT_SPOT
) {
1248 if (ctx
->_NeedEyeCoords
) {
1249 COPY_3V( light
->_NormDirection
, light
->EyeDirection
);
1252 TRANSFORM_NORMAL( light
->_NormDirection
,
1253 light
->EyeDirection
,
1257 NORMALIZE_3FV( light
->_NormDirection
);
1259 if (!(light
->_Flags
& LIGHT_POSITIONAL
)) {
1260 GLfloat PV_dot_dir
= - DOT3(light
->_VP_inf_norm
,
1261 light
->_NormDirection
);
1263 if (PV_dot_dir
> light
->_CosCutoff
) {
1264 double x
= PV_dot_dir
* (EXP_TABLE_SIZE
-1);
1266 light
->_VP_inf_spot_attenuation
=
1267 (light
->_SpotExpTable
[k
][0] +
1268 (x
-k
)*light
->_SpotExpTable
[k
][1]);
1271 light
->_VP_inf_spot_attenuation
= 0;