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