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