home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 5 / MA_Cover_5.iso / ppc / mesa / src / light.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-01-31  |  24.9 KB  |  901 lines

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