home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / coders / mesa-1.2.8 / src / light.c < prev    next >
C/C++ Source or Header  |  1996-05-27  |  51KB  |  1,582 lines

  1. /* $Id: light.c,v 1.40 1996/05/03 17:48:09 brianp Exp $ */
  2.  
  3. /*
  4.  * Mesa 3-D graphics library
  5.  * Version:  1.2
  6.  * Copyright (C) 1995-1996  Brian Paul  (brianp@ssec.wisc.edu)
  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.40  1996/05/03  17:48:09  brianp
  27.  * fixed bug involving 4th element of spot light direction vector
  28.  *
  29.  * Revision 1.39  1996/04/30  12:21:44  brianp
  30.  * changed gl_compute_material_shine_table() per Jacques Leroy
  31.  *
  32.  * Revision 1.38  1996/03/18  17:15:48  brianp
  33.  * material->ShineTable[0] should be 0.0, not 1.0
  34.  *
  35.  * Revision 1.37  1996/03/11  14:16:15  brianp
  36.  * fixed pow(0,0) error in gl_compute_material_shininess_table per Bill Henshaw
  37.  *
  38.  * Revision 1.36  1996/02/26  15:20:22  brianp
  39.  * replaced pow() calls with lookup tables as suggested by Jean-Luc Daems
  40.  *
  41.  * Revision 1.35  1996/02/14  16:56:23  brianp
  42.  * replaced gl_index_shade() with gl_index_shade_vertices()
  43.  *
  44.  * Revision 1.34  1996/02/13  17:53:02  brianp
  45.  * added gl_update_lighting() and gl_color_shade_vertices_fast()
  46.  *
  47.  * Revision 1.33  1996/01/22  15:28:48  brianp
  48.  * fixed a couple bugs in gl_index_shade()
  49.  *
  50.  * Revision 1.32  1996/01/09  19:52:28  brianp
  51.  * fixed an FP overflow bug in gl_init_lighting()
  52.  *
  53.  * Revision 1.31  1996/01/07  22:48:41  brianp
  54.  * removed gl_color_shade()
  55.  * introduced POW macro for computing specular exponent term
  56.  *
  57.  * Revision 1.30  1995/12/30  00:54:26  brianp
  58.  * return integer colors instead of floats in shading functions
  59.  *
  60.  * Revision 1.29  1995/12/20  15:27:03  brianp
  61.  * gl_index_shade changed to return GLuint color indexes instead of GLfloat
  62.  *
  63.  * Revision 1.28  1995/12/19  17:06:11  brianp
  64.  * new implementation of glColorMaterial
  65.  *
  66.  * Revision 1.27  1995/11/02  20:03:05  brianp
  67.  * changed some GLuints to GLints
  68.  *
  69.  * Revision 1.26  1995/11/01  23:18:47  brianp
  70.  * fixed a typo in gl_color_shade()
  71.  *
  72.  * Revision 1.25  1995/11/01  21:46:06  brianp
  73.  * optimized gl_color_shade(), added new gl_color_shade_vertices() function
  74.  *
  75.  * Revision 1.24  1995/10/24  18:36:58  brianp
  76.  * only set CC.NewState when ShadeModel really changes
  77.  *
  78.  * Revision 1.23  1995/10/14  17:41:52  brianp
  79.  * add code to compile glLightModel into display lists
  80.  *
  81.  * Revision 1.22  1995/10/06  13:02:56  brianp
  82.  * fixed glMaterial GL_AMBIENT_AND_DIFFUSE bug
  83.  *
  84.  * Revision 1.21  1995/09/26  17:20:33  brianp
  85.  * fixed uninitialized fmask,bmask bug in gl_material
  86.  *
  87.  * Revision 1.20  1995/09/25  19:24:19  brianp
  88.  * implemented per-vertex glMaterial calls
  89.  *
  90.  * Revision 1.19  1995/09/25  13:21:13  brianp
  91.  * fixed a bug in computing the specular coefficient per Olaf Flebbe
  92.  *
  93.  * Revision 1.18  1995/09/22  16:22:03  brianp
  94.  * added comment about glMaterial not working inside glBegin/glEnd
  95.  *
  96.  * Revision 1.17  1995/09/05  15:35:08  brianp
  97.  * introduced CC.NewState convention
  98.  * many small optimizations made in gl_color_shade() and gl_index_shade()
  99.  *
  100.  * Revision 1.16  1995/07/25  13:27:51  brianp
  101.  * gl_index_shade() returns GLfloats instead of GLuints
  102.  *
  103.  * Revision 1.15  1995/05/30  15:10:45  brianp
  104.  * use ROUND() macro in glGetMaterialiv
  105.  *
  106.  * Revision 1.14  1995/05/29  21:21:53  brianp
  107.  * added glGetMaterial*() functions
  108.  *
  109.  * Revision 1.13  1995/05/22  21:02:41  brianp
  110.  * Release 1.2
  111.  *
  112.  * Revision 1.12  1995/05/12  17:00:43  brianp
  113.  * changed CC.Mode!=0 to INSIDE_BEGIN_END
  114.  *
  115.  * Revision 1.11  1995/05/12  16:29:51  brianp
  116.  * fixed glGetLightiv()'s prototype
  117.  *
  118.  * Revision 1.10  1995/04/13  19:48:33  brianp
  119.  * fixed GL_LIGHT_MODEL_LOCAL_VIEWER bugs per Armin Liebchen
  120.  *
  121.  * Revision 1.9  1995/04/08  15:25:45  brianp
  122.  * compile glShadeModel
  123.  * fixed pow() domain error
  124.  * added spotlight and attenutation factor to gl_index_shade
  125.  *
  126.  * Revision 1.8  1995/03/28  20:28:03  brianp
  127.  * fixed alpha lighting bug
  128.  *
  129.  * Revision 1.7  1995/03/10  21:41:01  brianp
  130.  * added divide by zero checks
  131.  *
  132.  * Revision 1.6  1995/03/09  21:41:03  brianp
  133.  * new ModelViewInv matrix logic
  134.  *
  135.  * Revision 1.5  1995/03/09  20:07:08  brianp
  136.  * changed gl_transform_point to macro call
  137.  * changed order of arguments in gl_transform_vector
  138.  *
  139.  * Revision 1.4  1995/03/04  19:29:44  brianp
  140.  * 1.1 beta revision
  141.  *
  142.  * Revision 1.3  1995/02/25  21:01:56  brianp
  143.  * added underflow check for specular coefficient
  144.  *
  145.  * Revision 1.2  1995/02/25  18:52:12  brianp
  146.  * changed NORMALIZE macro
  147.  *
  148.  * Revision 1.1  1995/02/24  14:23:06  brianp
  149.  * Initial revision
  150.  *
  151.  */
  152.  
  153.  
  154. #include <assert.h>
  155. #include <math.h>
  156. #include "context.h"
  157. #include "light.h"
  158. #include "list.h"
  159. #include "macros.h"
  160. #include "vb.h"
  161. #include "xform.h"
  162.  
  163.  
  164.  
  165. #ifndef M_PI
  166. #  define M_PI (3.1415926)
  167. #endif
  168.  
  169. #define DEG2RAD (M_PI/180.0)
  170.  
  171.  
  172.  
  173. void glShadeModel( GLenum mode )
  174. {
  175.    if (CC.CompileFlag) {
  176.       gl_save_shademodel( mode );
  177.    }
  178.    if (CC.ExecuteFlag) {
  179.       if (INSIDE_BEGIN_END) {
  180.      gl_error( GL_INVALID_OPERATION, "glShadeModel" );
  181.      return;
  182.       }
  183.  
  184.       switch (mode) {
  185.      case GL_FLAT:
  186.      case GL_SMOOTH:
  187.             if (CC.Light.ShadeModel!=mode) {
  188.                CC.Light.ShadeModel = mode;
  189.                CC.NewState = GL_TRUE;
  190.             }
  191.         break;
  192.      default:
  193.         gl_error( GL_INVALID_ENUM, "glShadeModel" );
  194.       }
  195.    }
  196. }
  197.  
  198.  
  199.  
  200.  
  201. void glColorMaterial( GLenum face, GLenum mode )
  202. {
  203.    if (CC.CompileFlag) {
  204.       gl_save_colormaterial( face, mode );
  205.    }
  206.    if (CC.ExecuteFlag) {
  207.       if (INSIDE_BEGIN_END) {
  208.          gl_error( GL_INVALID_OPERATION, "glColorMaterial" );
  209.          return;
  210.       }
  211.       switch (face) {
  212.          case GL_FRONT:
  213.          case GL_BACK:
  214.          case GL_FRONT_AND_BACK:
  215.             CC.Light.ColorMaterialFace = face;
  216.             break;
  217.          default:
  218.             gl_error( GL_INVALID_ENUM, "glColorMaterial" );
  219.             return;
  220.       }
  221.       switch (mode) {
  222.          case GL_EMISSION:
  223.          case GL_AMBIENT:
  224.          case GL_DIFFUSE:
  225.          case GL_SPECULAR:
  226.          case GL_AMBIENT_AND_DIFFUSE:
  227.             CC.Light.ColorMaterialMode = mode;
  228.             break;
  229.          default:
  230.             gl_error( GL_INVALID_ENUM, "glColorMaterial" );
  231.             return;
  232.       }
  233.    }
  234. }
  235.  
  236.  
  237.  
  238. /*
  239.  * pname: GL_AMBIENT, red, green, blue, alpha in [-1,1]
  240.  *        GL_DIFFUSE, red, green, blue, alhpa in [-1,1]
  241.  *        GL_SPECULAR, red, green, blue, alpha in [-1,1]
  242.  *        GL_POSITION, x, y, z, w in homogeneous object coordinates
  243.  *        GL_SPOT_DIRECTION, dx, dy, dz
  244.  *        GL_SPOT_EXPONENT, intensity in [0,128]
  245.  *        GL_SPOT_CUTOFF, angle in [0,90] or 180
  246.  *        GL_CONSTANT_ATTENUATION, factor >= 0
  247.  *        GL_LINEAR_ATTENUATION, factor >= 0
  248.  *        GL_QUADRATIC_ATTENUATION, factor >= 0
  249.  */
  250. void gl_light( GLenum light, GLenum pname, const GLfloat *params )
  251. {
  252.    GLint l;
  253.  
  254.    if (INSIDE_BEGIN_END) {
  255.       gl_error( GL_INVALID_OPERATION, "glShadeModel" );
  256.       return;
  257.    }
  258.  
  259.    l = (GLint) (light - GL_LIGHT0);
  260.  
  261.    if (l<0 || l>=MAX_LIGHTS) {
  262.       gl_error( GL_INVALID_ENUM, "glLight" );
  263.       return;
  264.    }
  265.  
  266.    switch (pname) {
  267.       case GL_AMBIENT:
  268.          COPY_4V( CC.Light.Light[l].Ambient, params );
  269.          break;
  270.       case GL_DIFFUSE:
  271.          COPY_4V( CC.Light.Light[l].Diffuse, params );
  272.          break;
  273.       case GL_SPECULAR:
  274.          COPY_4V( CC.Light.Light[l].Specular, params );
  275.          break;
  276.       case GL_POSITION:
  277.      /* transform position by ModelView matrix */
  278.      TRANSFORM_POINT( CC.Light.Light[l].Position, CC.ModelViewMatrix,
  279.                           params );
  280.          break;
  281.       case GL_SPOT_DIRECTION:
  282.      /* transform direction by inverse modelview */
  283.          {
  284.             GLfloat direction[4];
  285.             direction[0] = params[0];
  286.             direction[1] = params[1];
  287.             direction[2] = params[2];
  288.             direction[3] = 0.0;
  289.             if (!CC.ModelViewInvValid) {
  290.                gl_compute_modelview_inverse();
  291.             }
  292.             gl_transform_vector( CC.Light.Light[l].Direction,
  293.                                  direction, CC.ModelViewInv);
  294.          }
  295.          break;
  296.       case GL_SPOT_EXPONENT:
  297.          if (params[0]<0.0 || params[0]>128.0) {
  298.             gl_error( GL_INVALID_VALUE, "glLight" );
  299.             return;
  300.          }
  301.          CC.Light.Light[l].SpotExponent = params[0];
  302.          gl_compute_spot_exp_table( &CC.Light.Light[l] );
  303.          break;
  304.       case GL_SPOT_CUTOFF:
  305.          if ((params[0]<0.0 || params[0]>90.0) && params[0]!=180.0) {
  306.             gl_error( GL_INVALID_VALUE, "glLight" );
  307.             return;
  308.          }
  309.          CC.Light.Light[l].SpotCutoff = params[0];
  310.          CC.Light.Light[l].CosCutoff = cos(params[0]*DEG2RAD);
  311.          break;
  312.       case GL_CONSTANT_ATTENUATION:
  313.          if (params[0]<0.0) {
  314.             gl_error( GL_INVALID_VALUE, "glLight" );
  315.             return;
  316.          }
  317.          CC.Light.Light[l].ConstantAttenuation = params[0];
  318.          break;
  319.       case GL_LINEAR_ATTENUATION:
  320.          if (params[0]<0.0) {
  321.             gl_error( GL_INVALID_VALUE, "glLight" );
  322.             return;
  323.          }
  324.          CC.Light.Light[l].LinearAttenuation = params[0];
  325.          break;
  326.       case GL_QUADRATIC_ATTENUATION:
  327.          if (params[0]<0.0) {
  328.             gl_error( GL_INVALID_VALUE, "glLight" );
  329.             return;
  330.          }
  331.          CC.Light.Light[l].QuadraticAttenuation = params[0];
  332.          break;
  333.       default:
  334.          gl_error( GL_INVALID_ENUM, "glLight" );
  335.          break;
  336.    }
  337.  
  338.    CC.NewState = GL_TRUE;
  339. }
  340.  
  341.  
  342.  
  343. /*
  344.  * light: GL_LIGHT0, GL_LIGHT1, ... GL_LIGHTn where n=GL_MAX_LIGHTS-1
  345.  * pname: GL_SPOT_EXPONENT, GL_SPOT_CUTOFF, GL_CONSTANT_ATTENUATION,
  346.  *        GL_LINEAR_ATTENUATION, GL_QUADRATIC_ATTENUATION
  347.  */
  348. void glLightf( GLenum light, GLenum pname, GLfloat param )
  349. {
  350.    if (CC.ExecuteFlag) {
  351.       gl_light( light, pname, ¶m );
  352.    }
  353.    if (CC.CompileFlag) {
  354.       gl_save_light( light, pname, ¶m, 1 );
  355.    }
  356. }
  357.  
  358.  
  359.  
  360. void glLighti( GLenum light, GLenum pname, GLint param )
  361. {
  362.    GLfloat fparam;
  363.  
  364.    fparam = (GLfloat) param;
  365.    if (CC.ExecuteFlag) {
  366.       gl_light( light, pname, &fparam );
  367.    }
  368.    if (CC.CompileFlag) {
  369.       gl_save_light( light, pname, &fparam, 1 );
  370.    }
  371. }
  372.  
  373.  
  374.  
  375. void glLightfv( GLenum light, GLenum pname, const GLfloat *params )
  376. {
  377.    if (CC.ExecuteFlag) {
  378.       gl_light( light, pname, params );
  379.    }
  380.    if (CC.CompileFlag) {
  381.       gl_save_light( light, pname, params, 4 );
  382.    }
  383. }
  384.  
  385.  
  386.  
  387. void glLightiv( GLenum light, GLenum pname, const GLint *params )
  388. {
  389.    GLfloat fparam[4];
  390.  
  391.    switch (pname) {
  392.       case GL_AMBIENT:
  393.       case GL_DIFFUSE:
  394.       case GL_SPECULAR:
  395.          fparam[0] = INT_TO_FLOAT( params[0] );
  396.          fparam[1] = INT_TO_FLOAT( params[1] );
  397.          fparam[2] = INT_TO_FLOAT( params[2] );
  398.          fparam[3] = INT_TO_FLOAT( params[3] );
  399.          break;
  400.       case GL_POSITION:
  401.          fparam[0] = (GLfloat) params[0];
  402.          fparam[1] = (GLfloat) params[1];
  403.          fparam[2] = (GLfloat) params[2];
  404.          fparam[3] = (GLfloat) params[3];
  405.          break;
  406.       case GL_SPOT_DIRECTION:
  407.          fparam[0] = (GLfloat) params[0];
  408.          fparam[1] = (GLfloat) params[1];
  409.          fparam[2] = (GLfloat) params[2];
  410.          break;
  411.       case GL_SPOT_EXPONENT:
  412.       case GL_SPOT_CUTOFF:
  413.       case GL_CONSTANT_ATTENUATION:
  414.       case GL_LINEAR_ATTENUATION:
  415.       case GL_QUADRATIC_ATTENUATION:
  416.          fparam[0] = (GLfloat) params[0];
  417.          break;
  418.       default:
  419.          gl_error( GL_INVALID_ENUM, "glLight" );
  420.          return;
  421.    }
  422.    if (CC.ExecuteFlag) {
  423.       gl_light( light, pname, fparam );
  424.    }
  425.    if (CC.CompileFlag) {
  426.       gl_save_light( light, pname, fparam, 4 );
  427.    }
  428. }
  429.  
  430.  
  431.  
  432. void glGetLightfv( GLenum light, GLenum pname, GLfloat *params )
  433. {
  434.    GLint l;
  435.  
  436.    l = (GLint) (light - GL_LIGHT0);
  437.  
  438.    if (l<0 || l>=MAX_LIGHTS) {
  439.       gl_error( GL_INVALID_ENUM, "glGetLightfv" );
  440.       return;
  441.    }
  442.  
  443.    switch (pname) {
  444.       case GL_AMBIENT:
  445.          COPY_4V( params, CC.Light.Light[l].Ambient );
  446.          break;
  447.       case GL_DIFFUSE:
  448.          COPY_4V( params, CC.Light.Light[l].Diffuse );
  449.          break;
  450.       case GL_SPECULAR:
  451.          COPY_4V( params, CC.Light.Light[l].Specular );
  452.          break;
  453.       case GL_POSITION:
  454.          COPY_4V( params, CC.Light.Light[l].Position );
  455.          break;
  456.       case GL_SPOT_DIRECTION:
  457.          COPY_3V( params, CC.Light.Light[l].Direction );
  458.          break;
  459.       case GL_SPOT_EXPONENT:
  460.          params[0] = CC.Light.Light[l].SpotExponent;
  461.          break;
  462.       case GL_SPOT_CUTOFF:
  463.          params[0] = CC.Light.Light[l].SpotCutoff;
  464.          break;
  465.       case GL_CONSTANT_ATTENUATION:
  466.          params[0] = CC.Light.Light[l].ConstantAttenuation;
  467.          break;
  468.       case GL_LINEAR_ATTENUATION:
  469.          params[0] = CC.Light.Light[l].LinearAttenuation;
  470.          break;
  471.       case GL_QUADRATIC_ATTENUATION:
  472.          params[0] = CC.Light.Light[l].QuadraticAttenuation;
  473.          break;
  474.       default:
  475.          gl_error( GL_INVALID_ENUM, "glGetLightfv" );
  476.          break;
  477.    }
  478. }
  479.  
  480.  
  481.  
  482. void glGetLightiv( GLenum light, GLenum pname, GLint *params )
  483. {
  484.    /* TODO */
  485. }
  486.  
  487.  
  488.  
  489. /**********************************************************************/
  490. /***                        Light Model                             ***/
  491. /**********************************************************************/
  492.  
  493.  
  494. void gl_lightmodel( GLenum pname, const GLfloat *params )
  495. {
  496.    switch (pname) {
  497.       case GL_LIGHT_MODEL_AMBIENT:
  498.          COPY_4V( CC.Light.Model.Ambient, params );
  499.          break;
  500.       case GL_LIGHT_MODEL_LOCAL_VIEWER:
  501.          if (params[0]==0.0)
  502.             CC.Light.Model.LocalViewer = GL_FALSE;
  503.          else
  504.             CC.Light.Model.LocalViewer = GL_TRUE;
  505.          break;
  506.       case GL_LIGHT_MODEL_TWO_SIDE:
  507.          if (params[0]==0.0)
  508.             CC.Light.Model.TwoSide = GL_FALSE;
  509.          else
  510.             CC.Light.Model.TwoSide = GL_TRUE;
  511.          CC.NewState = GL_TRUE;
  512.          break;
  513.       default:
  514.          gl_error( GL_INVALID_ENUM, "glLightModel" );
  515.          break;
  516.    }
  517.    CC.NewState = GL_TRUE;
  518. }
  519.  
  520.  
  521.  
  522. /*
  523.  * pname: GL_LIGHT_MODEL_LOCAL_VIEWER, GL_LIGHT_MODEL_TWO_SIDE
  524.  */
  525. void glLightModelf( GLenum pname, GLfloat param )
  526. {
  527.    if (CC.CompileFlag) {
  528.       gl_save_lightmodel( pname, ¶m );
  529.    }
  530.    if (CC.ExecuteFlag) {
  531.       gl_lightmodel( pname, ¶m );
  532.    }
  533. }
  534.  
  535.  
  536.  
  537. void glLightModeli( GLenum pname, GLint param )
  538. {
  539.    GLfloat fparam = (GLfloat) param;
  540.    if (CC.CompileFlag) {
  541.       gl_save_lightmodel( pname, &fparam );
  542.    }
  543.    if (CC.ExecuteFlag) {
  544.       gl_lightmodel( pname, &fparam );
  545.    }
  546. }
  547.  
  548.  
  549.  
  550. /*
  551.  * pname: GL_LIGHT_MODEL_AMBIENT red, green, blue in [1.0, -1.0]
  552.  *        GL_LIGHT_MODEL_LOCAL_VIEWER mode where 0.0 = point, else parallel
  553.  *        GL_LIGHT_MODEL_TWO_SIDE mode where 0.0 = one-sided, else 2-sided
  554.  */
  555. void glLightModelfv( GLenum pname, const GLfloat *params )
  556. {
  557.    if (CC.CompileFlag) {
  558.       gl_save_lightmodel( pname, params );
  559.    }
  560.    if (CC.ExecuteFlag) {
  561.       gl_lightmodel( pname, params );
  562.    }
  563. }
  564.  
  565.  
  566.  
  567. void glLightModeliv( GLenum pname, const GLint *params )
  568. {
  569.    GLfloat fparam[4];
  570.  
  571.    switch (pname) {
  572.       case GL_LIGHT_MODEL_AMBIENT:
  573.          fparam[0] = INT_TO_FLOAT( params[0] );
  574.          fparam[1] = INT_TO_FLOAT( params[1] );
  575.          fparam[2] = INT_TO_FLOAT( params[2] );
  576.          fparam[3] = INT_TO_FLOAT( params[3] );
  577.          break;
  578.       case GL_LIGHT_MODEL_LOCAL_VIEWER:
  579.       case GL_LIGHT_MODEL_TWO_SIDE:
  580.          fparam[0] = (GLfloat) params[0];
  581.          break;
  582.       default:
  583.          gl_error( GL_INVALID_ENUM, "glLightModeliv" );
  584.          return;
  585.    }
  586.    if (CC.CompileFlag) {
  587.       gl_save_lightmodel( pname, fparam );
  588.    }
  589.    if (CC.ExecuteFlag) {
  590.       gl_lightmodel( pname, fparam );
  591.    }
  592. }
  593.  
  594.  
  595.  
  596.  
  597. /********** MATERIAL **********/
  598.  
  599.  
  600.  
  601. void gl_material( GLenum face, GLenum pname, const GLfloat *params )
  602. {
  603.    GLuint bitmask = 0, fmask = 0, bmask = 0;
  604.    struct gl_material *mat;
  605.  
  606.    if (face!=GL_FRONT && face!=GL_BACK && face!=GL_FRONT_AND_BACK) {
  607.       gl_error( GL_INVALID_ENUM, "glMaterial" );
  608.       return;
  609.    }
  610.  
  611.    if (face==GL_FRONT || face==GL_FRONT_AND_BACK) {
  612.       fmask = 0xfff;
  613.    }
  614.    if (face==GL_BACK || face==GL_FRONT_AND_BACK) {
  615.       bmask = 0xfff;
  616.    }
  617.  
  618.    /* Make a bitmask indicating what material attribute(s) we're updating */
  619.    switch (pname) {
  620.       case GL_AMBIENT:
  621.          bitmask |= (FRONT_AMBIENT_BIT & fmask) | (BACK_AMBIENT_BIT & bmask);
  622.          break;
  623.       case GL_DIFFUSE:
  624.          bitmask |= (FRONT_DIFFUSE_BIT & fmask) | (BACK_DIFFUSE_BIT & bmask);
  625.          break;
  626.       case GL_SPECULAR:
  627.          bitmask |= (FRONT_SPECULAR_BIT & fmask) | (BACK_SPECULAR_BIT & bmask);
  628.          break;
  629.       case GL_EMISSION:
  630.          bitmask |= (FRONT_EMISSION_BIT & fmask) | (BACK_EMISSION_BIT & bmask);
  631.          break;
  632.       case GL_SHININESS:
  633.          bitmask |= (FRONT_SHININESS_BIT & fmask) | (BACK_SHININESS_BIT & bmask);
  634.          break;
  635.       case GL_AMBIENT_AND_DIFFUSE:
  636.          bitmask |= ((FRONT_AMBIENT_BIT | FRONT_DIFFUSE_BIT) & fmask)
  637.                   | ((BACK_AMBIENT_BIT | BACK_DIFFUSE_BIT) & bmask);
  638.          break;
  639.       case GL_COLOR_INDEXES:
  640.          bitmask |= (FRONT_INDEXES_BIT & fmask) | (BACK_INDEXES_BIT & bmask);
  641.          break;
  642.       default:
  643.          gl_error( GL_INVALID_ENUM, "glMaterial(pname)" );
  644.          return;
  645.    }
  646.  
  647.    if (INSIDE_BEGIN_END) {
  648.       /* Save per-vertex material changes in the Vertex Buffer.
  649.        * The update_material function will eventually update the global
  650.        * CC.Light.Material values.
  651.        */
  652.       mat = VB.Material[VB.Count];
  653.       VB.MaterialMask[VB.Count] |= bitmask;
  654.       VB.MaterialChanges = GL_TRUE;
  655.    }
  656.    else {
  657.       /* just update the global material property */
  658.       mat = CC.Light.Material;
  659.       CC.NewState = GL_TRUE;
  660.    }
  661.  
  662.    if (bitmask & FRONT_AMBIENT_BIT) {
  663.       COPY_4V( mat[0].Ambient, params );
  664.    }
  665.    if (bitmask & BACK_AMBIENT_BIT) {
  666.       COPY_4V( mat[1].Ambient, params );
  667.    }
  668.    if (bitmask & FRONT_DIFFUSE_BIT) {
  669.       COPY_4V( mat[0].Diffuse, params );
  670.    }
  671.    if (bitmask & BACK_DIFFUSE_BIT) {
  672.       COPY_4V( mat[1].Diffuse, params );
  673.    }
  674.    if (bitmask & FRONT_SPECULAR_BIT) {
  675.       COPY_4V( mat[0].Specular, params );
  676.    }
  677.    if (bitmask & BACK_SPECULAR_BIT) {
  678.       COPY_4V( mat[1].Specular, params );
  679.    }
  680.    if (bitmask & FRONT_EMISSION_BIT) {
  681.       COPY_4V( mat[0].Emission, params );
  682.    }
  683.    if (bitmask & BACK_EMISSION_BIT) {
  684.       COPY_4V( mat[1].Emission, params );
  685.    }
  686.    if (bitmask & FRONT_SHININESS_BIT) {
  687.       mat[0].Shininess = CLAMP( params[0], 0.0, 128.0 );
  688.       gl_compute_material_shine_table( &mat[0] );
  689.    }
  690.    if (bitmask & BACK_SHININESS_BIT) {
  691.       mat[1].Shininess = CLAMP( params[0], 0.0, 128.0 );
  692.       gl_compute_material_shine_table( &mat[1] );
  693.    }
  694.    if (bitmask & FRONT_INDEXES_BIT) {
  695.       mat[0].AmbientIndex = params[0];
  696.       mat[0].DiffuseIndex = params[1];
  697.       mat[0].SpecularIndex = params[2];
  698.    }
  699.    if (bitmask & BACK_INDEXES_BIT) {
  700.       mat[1].AmbientIndex = params[0];
  701.       mat[1].DiffuseIndex = params[1];
  702.       mat[1].SpecularIndex = params[2];
  703.    }
  704. }
  705.  
  706.  
  707.  
  708. void glMaterialf( GLenum face, GLenum pname, GLfloat param )
  709. {
  710.    if (CC.CompileFlag) {
  711.       gl_save_material( face, pname, ¶m );
  712.    }
  713.    if (CC.ExecuteFlag) {
  714.       gl_material( face, pname, ¶m );
  715.    }
  716. }
  717.  
  718.  
  719.  
  720. void glMateriali( GLenum face, GLenum pname, GLint param )
  721. {
  722.    GLfloat fparam;
  723.  
  724.    fparam = (GLfloat) param;
  725.  
  726.    if (CC.CompileFlag) {
  727.       gl_save_material( face, pname, &fparam );
  728.    }
  729.    if (CC.ExecuteFlag) {
  730.       gl_material( face, pname, &fparam );
  731.    }
  732. }
  733.  
  734.  
  735.  
  736. void glMaterialfv( GLenum face, GLenum pname, const GLfloat *params )
  737. {
  738.    if (CC.CompileFlag) {
  739.       gl_save_material( face, pname, params );
  740.    }
  741.    if (CC.ExecuteFlag) {
  742.       gl_material( face, pname, params );
  743.    }
  744. }
  745.  
  746.  
  747.  
  748. void glMaterialiv( GLenum face, GLenum pname, const GLint *params )
  749. {
  750.    GLfloat fparam[4];
  751.  
  752.    switch (pname) {
  753.       case GL_AMBIENT:
  754.       case GL_DIFFUSE:
  755.       case GL_SPECULAR:
  756.       case GL_EMISSION:
  757.       case GL_AMBIENT_AND_DIFFUSE:
  758.          fparam[0] = INT_TO_FLOAT( params[0] );
  759.          fparam[1] = INT_TO_FLOAT( params[1] );
  760.          fparam[2] = INT_TO_FLOAT( params[2] );
  761.          fparam[3] = INT_TO_FLOAT( params[3] );
  762.          break;
  763.       case GL_SHININESS:
  764.          fparam[0] = (GLfloat) params[0];
  765.          break;
  766.       case GL_COLOR_INDEXES:
  767.          fparam[0] = (GLfloat) params[0];
  768.          fparam[1] = (GLfloat) params[1];
  769.          fparam[2] = (GLfloat) params[2];
  770.          break;
  771.    }
  772.    if (CC.CompileFlag) {
  773.       gl_save_material( face, pname, fparam );
  774.    }
  775.    if (CC.ExecuteFlag) {
  776.       gl_material( face, pname, fparam );
  777.    }
  778. }
  779.  
  780.  
  781.  
  782. void glGetMaterialfv( GLenum face, GLenum pname, GLfloat *params )
  783. {
  784.    GLuint f;
  785.  
  786.    if (INSIDE_BEGIN_END) {
  787.       gl_error( GL_INVALID_OPERATION, "glGetMaterialfv" );
  788.       return;
  789.    }
  790.    if (face==GL_FRONT) {
  791.       f = 0;
  792.    }
  793.    else if (face==GL_BACK) {
  794.       f = 1;
  795.    }
  796.    else {
  797.       gl_error( GL_INVALID_ENUM, "glGetMaterialfv(face)" );
  798.       return;
  799.    }
  800.    switch (pname) {
  801.       case GL_AMBIENT:
  802.          COPY_4V( params, CC.Light.Material[f].Ambient );
  803.          break;
  804.       case GL_DIFFUSE:
  805.          COPY_4V( params, CC.Light.Material[f].Diffuse );
  806.      break;
  807.       case GL_SPECULAR:
  808.          COPY_4V( params, CC.Light.Material[f].Specular );
  809.      break;
  810.       case GL_EMISSION:
  811.      COPY_4V( params, CC.Light.Material[f].Emission );
  812.      break;
  813.       case GL_SHININESS:
  814.      *params = CC.Light.Material[f].Shininess;
  815.      break;
  816.       case GL_COLOR_INDEXES:
  817.      params[0] = CC.Light.Material[f].AmbientIndex;
  818.      params[1] = CC.Light.Material[f].DiffuseIndex;
  819.      params[2] = CC.Light.Material[f].SpecularIndex;
  820.      break;
  821.       default:
  822.          gl_error( GL_INVALID_ENUM, "glGetMaterialfv(pname)" );
  823.    }
  824.    CC.NewState = GL_TRUE;
  825. }
  826.  
  827.  
  828.  
  829. void glGetMaterialiv( GLenum face, GLenum pname, GLint *params )
  830. {
  831.    GLuint f;
  832.  
  833.    if (INSIDE_BEGIN_END) {
  834.       gl_error( GL_INVALID_OPERATION, "glGetMaterialiv" );
  835.       return;
  836.    }
  837.    if (face==GL_FRONT) {
  838.       f = 0;
  839.    }
  840.    else if (face==GL_BACK) {
  841.       f = 1;
  842.    }
  843.    else {
  844.       gl_error( GL_INVALID_ENUM, "glGetMaterialiv(face)" );
  845.       return;
  846.    }
  847.    switch (pname) {
  848.       case GL_AMBIENT:
  849.          params[0] = FLOAT_TO_INT( CC.Light.Material[f].Ambient[0] );
  850.          params[1] = FLOAT_TO_INT( CC.Light.Material[f].Ambient[1] );
  851.          params[2] = FLOAT_TO_INT( CC.Light.Material[f].Ambient[2] );
  852.          params[3] = FLOAT_TO_INT( CC.Light.Material[f].Ambient[3] );
  853.          break;
  854.       case GL_DIFFUSE:
  855.          params[0] = FLOAT_TO_INT( CC.Light.Material[f].Diffuse[0] );
  856.          params[1] = FLOAT_TO_INT( CC.Light.Material[f].Diffuse[1] );
  857.          params[2] = FLOAT_TO_INT( CC.Light.Material[f].Diffuse[2] );
  858.          params[3] = FLOAT_TO_INT( CC.Light.Material[f].Diffuse[3] );
  859.      break;
  860.       case GL_SPECULAR:
  861.          params[0] = FLOAT_TO_INT( CC.Light.Material[f].Specular[0] );
  862.          params[1] = FLOAT_TO_INT( CC.Light.Material[f].Specular[1] );
  863.          params[2] = FLOAT_TO_INT( CC.Light.Material[f].Specular[2] );
  864.          params[3] = FLOAT_TO_INT( CC.Light.Material[f].Specular[3] );
  865.      break;
  866.       case GL_EMISSION:
  867.          params[0] = FLOAT_TO_INT( CC.Light.Material[f].Emission[0] );
  868.          params[1] = FLOAT_TO_INT( CC.Light.Material[f].Emission[1] );
  869.          params[2] = FLOAT_TO_INT( CC.Light.Material[f].Emission[2] );
  870.          params[3] = FLOAT_TO_INT( CC.Light.Material[f].Emission[3] );
  871.      break;
  872.       case GL_SHININESS:
  873.          *params = ROUNDF( CC.Light.Material[f].Shininess );
  874.      break;
  875.       case GL_COLOR_INDEXES:
  876.      params[0] = ROUNDF( CC.Light.Material[f].AmbientIndex );
  877.      params[1] = ROUNDF( CC.Light.Material[f].DiffuseIndex );
  878.      params[2] = ROUNDF( CC.Light.Material[f].SpecularIndex );
  879.      break;
  880.       default:
  881.          gl_error( GL_INVALID_ENUM, "glGetMaterialfv(pname)" );
  882.    }
  883. }
  884.  
  885.  
  886.  
  887.  
  888. /**********************************************************************/
  889. /*****                  Lighting computation                      *****/
  890. /**********************************************************************/
  891.  
  892.  
  893. /*
  894.  * Notes:
  895.  *   When two-sided lighting is enabled we compute the color (or index)
  896.  *   for both the front and back side of the primitive.  Then, when the
  897.  *   orientation of the facet is later learned, we can determine which
  898.  *   color (or index) to use for rendering.
  899.  */
  900.  
  901.  
  902.  
  903. /*
  904.  * Whenever the spotlight exponent for a light changes we must call
  905.  * this function to recompute the exponent lookup table.
  906.  */
  907. void gl_compute_spot_exp_table( struct gl_light *l )
  908. {
  909.    int i;
  910.    double exponent = l->SpotExponent;
  911.  
  912.    l->SpotExpTable[0][0] = 0.0;
  913.    for (i=1;i<EXP_TABLE_SIZE;i++) {
  914.       l->SpotExpTable[i][0] = pow(i/(double)(EXP_TABLE_SIZE-1), exponent);
  915.    }
  916.    for (i=0;i<EXP_TABLE_SIZE-1;i++) {
  917.       l->SpotExpTable[i][1] = l->SpotExpTable[i+1][0] - l->SpotExpTable[i][0];
  918.    }
  919.    l->SpotExpTable[EXP_TABLE_SIZE-1][1] = 0.0;
  920. }
  921.  
  922.  
  923.  
  924. /*
  925.  * Whenever the shininess of a material changes we must call this
  926.  * function to recompute the exponential lookup table.
  927.  */
  928. void gl_compute_material_shine_table( struct gl_material *m )
  929. {
  930.    int i;
  931.    double exponent = m->Shininess;
  932.  
  933.    m->ShineTable[0] = 0.0;
  934.    for (i=1;i<SHINE_TABLE_SIZE;i++) {
  935.       double x = pow( i/(double)(SHINE_TABLE_SIZE-1), exponent );
  936.       if (x<1.0e-10) {
  937.          m->ShineTable[i] = 0.0;
  938.       }
  939.       else {
  940.          m->ShineTable[i] = x;
  941.       }
  942.    }
  943. }
  944.  
  945.  
  946.  
  947. /*
  948.  * Examine current lighting parameters to determine if the optimized lighting
  949.  * function can be used.  Also, precompute some lighting values which are
  950.  * used by gl_color_shade_vertices_fast().
  951.  */
  952. void gl_update_lighting( void )
  953. {
  954.    GLint i;
  955.  
  956.    if (!CC.Light.Enabled) {
  957.       /* If lighting is not enabled, we can skip all this. */
  958.       return;
  959.    }
  960.  
  961.    /* base color = material_emission + global_ambient */
  962.    CC.Light.BaseColor[0] = CC.Light.Material[0].Emission[0]
  963.              + CC.Light.Model.Ambient[0] * CC.Light.Material[0].Ambient[0];
  964.    CC.Light.BaseColor[1] = CC.Light.Material[0].Emission[1]
  965.              + CC.Light.Model.Ambient[1] * CC.Light.Material[0].Ambient[1];
  966.    CC.Light.BaseColor[2] = CC.Light.Material[0].Emission[2]
  967.              + CC.Light.Model.Ambient[2] * CC.Light.Material[0].Ambient[2];
  968.    CC.Light.BaseColor[3] = MIN2( CC.Light.Material[0].Diffuse[3], 1.0F );
  969.  
  970.    /* Compute CC.Light.LastEnabled */
  971.    CC.Light.LastEnabled = -1;
  972.    for (i=0;i<MAX_LIGHTS;i++) {
  973.       if (CC.Light.Light[i].Enabled) {
  974.          CC.Light.LastEnabled = i;
  975.       }
  976.    }
  977.  
  978.    for (i=0;i<=CC.Light.LastEnabled;i++) {
  979.       if (CC.Light.Light[i].Enabled) {
  980.          /* Add each light's ambient component to base color */
  981.          CC.Light.BaseColor[0] += CC.Light.Light[i].Ambient[0]
  982.                                 * CC.Light.Material[0].Ambient[0];
  983.          CC.Light.BaseColor[1] += CC.Light.Light[i].Ambient[1]
  984.                                 * CC.Light.Material[0].Ambient[1];
  985.          CC.Light.BaseColor[2] += CC.Light.Light[i].Ambient[2]
  986.                                 * CC.Light.Material[0].Ambient[2];
  987.          /* diffuse[light] = diffuse[light] * material_diffuse */
  988.          CC.Light.Diffuse[i][0] = CC.Light.Light[i].Diffuse[0]
  989.                                 * CC.Light.Material[0].Diffuse[0];
  990.          CC.Light.Diffuse[i][1] = CC.Light.Light[i].Diffuse[1]
  991.                                 * CC.Light.Material[0].Diffuse[1];
  992.          CC.Light.Diffuse[i][2] = CC.Light.Light[i].Diffuse[2]
  993.                                 * CC.Light.Material[0].Diffuse[2];
  994.          /* specular[light] = specular[light] * material_specular */
  995.          CC.Light.Specular[i][0] = CC.Light.Light[i].Specular[0]
  996.                                  * CC.Light.Material[0].Specular[0];
  997.          CC.Light.Specular[i][1] = CC.Light.Light[i].Specular[1]
  998.                                  * CC.Light.Material[0].Specular[1];
  999.          CC.Light.Specular[i][2] = CC.Light.Light[i].Specular[2]
  1000.                                  * CC.Light.Material[0].Specular[2];
  1001.       }
  1002.    }
  1003.  
  1004.    /* Compute normalized position and direction vectors for each light */
  1005.    for (i=0;i<=CC.Light.LastEnabled;i++) {
  1006.       COPY_3V( CC.Light.Light[i].NormPosition, CC.Light.Light[i].Position );
  1007.       NORMALIZE_3V( CC.Light.Light[i].NormPosition );
  1008.       COPY_3V( CC.Light.Light[i].NormDirection, CC.Light.Light[i].Direction );
  1009.       NORMALIZE_3V( CC.Light.Light[i].NormDirection );
  1010.    }
  1011.  
  1012.    /* Determine if the fast lighting function can be used */
  1013.    CC.Light.Fast = GL_TRUE;
  1014.    for (i=0;i<=CC.Light.LastEnabled;i++) {
  1015.       if (CC.Light.Light[i].Enabled) {
  1016.          if (   CC.Light.Light[i].Position[3]!=0.0F
  1017.              || CC.Light.Light[i].SpotCutoff!=180.0F
  1018.              || CC.Light.BaseColor[0]<0.0F
  1019.              || CC.Light.BaseColor[1]<0.0F
  1020.              || CC.Light.BaseColor[2]<0.0F
  1021.              || CC.Light.BaseColor[3]<0.0F
  1022.              || CC.Light.Diffuse[i][0]<0.0F
  1023.              || CC.Light.Diffuse[i][1]<0.0F
  1024.              || CC.Light.Diffuse[i][2]<0.0F
  1025.              || CC.Light.Specular[i][0]<0.0F
  1026.              || CC.Light.Specular[i][1]<0.0F
  1027.              || CC.Light.Specular[i][2]<0.0F) {
  1028.             CC.Light.Fast = GL_FALSE;
  1029.             break;
  1030.          }
  1031.       }
  1032.    }
  1033.    if (CC.Light.Model.TwoSide || CC.Light.Model.LocalViewer
  1034.        || CC.Light.ColorMaterialEnabled) {
  1035.       CC.Light.Fast = GL_FALSE;
  1036.    }
  1037. }
  1038.  
  1039.  
  1040.  
  1041.  
  1042.  
  1043. /*
  1044.  * Use current lighting/material settings to compute the RGBA colors of
  1045.  * an array of vertexes.
  1046.  * Input:  n - number of vertexes to process
  1047.  *         vertex - array of vertex positions in eye coordinates
  1048.  *         normal - array of surface normal vectors
  1049.  *         twoside - 0 = front face shading only, 1 = two-sided lighting
  1050.  * Output:  frontcolor - array of resulting front-face colors
  1051.  *          backcolor - array of resulting back-face colors
  1052.  */
  1053. void gl_color_shade_vertices( GLuint n,
  1054.                               GLfloat vertex[][4],
  1055.                               GLfloat normal[][3],
  1056.                               GLuint twoside,
  1057.                               GLfixed frontcolor[][4],
  1058.                               GLfixed backcolor[][4] )
  1059. {
  1060.    GLint side, i, j;
  1061.    GLfloat rscale, gscale, bscale, ascale;
  1062.  
  1063.    /* Compute scale factor to go from floats in [0,1] to integers or fixed
  1064.     * point values:
  1065.     */
  1066.    rscale = (GLfloat) ( (GLint) CC.RedScale   << CC.ColorShift );
  1067.    gscale = (GLfloat) ( (GLint) CC.GreenScale << CC.ColorShift );
  1068.    bscale = (GLfloat) ( (GLint) CC.BlueScale  << CC.ColorShift );
  1069.    ascale = (GLfloat) ( (GLint) CC.AlphaScale << CC.ColorShift );
  1070.  
  1071.  
  1072.    for (side=0;side<=twoside;side++) {
  1073.       GLfloat ambient[MAX_LIGHTS][3];
  1074.       GLfloat r0, g0, b0, a0;
  1075.       GLfixed A;
  1076.  
  1077.       /*** Compute color contribution from global lighting ***/
  1078.       r0 = CC.Light.Material[side].Emission[0]
  1079.          + CC.Light.Model.Ambient[0] * CC.Light.Material[side].Ambient[0];
  1080.       g0 = CC.Light.Material[side].Emission[1]
  1081.          + CC.Light.Model.Ambient[1] * CC.Light.Material[side].Ambient[1];
  1082.       b0 = CC.Light.Material[side].Emission[2]
  1083.          + CC.Light.Model.Ambient[2] * CC.Light.Material[side].Ambient[2];
  1084.  
  1085.       /* Alpha is simple, same for all vertices */
  1086.       a0 = CC.Light.Material[side].Diffuse[3];
  1087.       A = (GLfixed) (CLAMP( a0, 0.0F, 1.0F ) * ascale);
  1088.  
  1089.       /* Compute ambient color from each light.  Same for all vertices. */
  1090.       for (i=0;i<=CC.Light.LastEnabled;i++) {
  1091.          ambient[i][0] = CC.Light.Light[i].Ambient[0]
  1092.                        * CC.Light.Material[side].Ambient[0];
  1093.          ambient[i][1] = CC.Light.Light[i].Ambient[1]
  1094.                        * CC.Light.Material[side].Ambient[1];
  1095.          ambient[i][2] = CC.Light.Light[i].Ambient[2]
  1096.                        * CC.Light.Material[side].Ambient[2];
  1097.       }
  1098.  
  1099.  
  1100.       for (j=0;j<n;j++) {
  1101.          GLfloat R, G, B;
  1102.          GLfloat norm[3];
  1103.  
  1104.          if (side==0) {
  1105.             /* shade frontside */
  1106.             norm[0] = normal[j][0];
  1107.             norm[1] = normal[j][1];
  1108.             norm[2] = normal[j][2];
  1109.          }
  1110.          else {
  1111.             /* shade backside */
  1112.             norm[0] = -normal[j][0];
  1113.             norm[1] = -normal[j][1];
  1114.             norm[2] = -normal[j][2];
  1115.          }
  1116.  
  1117.          R = r0;
  1118.          G = g0;
  1119.          B = b0;
  1120.  
  1121.          /* Add contribution from each light source */
  1122.          for (i=0;i<=CC.Light.LastEnabled;i++) {
  1123.  
  1124.             if (CC.Light.Light[i].Enabled) {
  1125.                GLfloat attenuation;
  1126.                GLfloat l[3];  /* unit vector from vertex to light */
  1127.                GLfloat l_dot_norm;  /* dot product of l and norm */
  1128.  
  1129.                /* compute l and attenuation */
  1130.                if (CC.Light.Light[i].Position[3]==0.0) {
  1131.                   /* directional light */
  1132.                   /* Effectively, l is a vector from the origin to the light */
  1133.                   l[0] = CC.Light.Light[i].NormPosition[0];
  1134.                   l[1] = CC.Light.Light[i].NormPosition[1];
  1135.                   l[2] = CC.Light.Light[i].NormPosition[2];
  1136.                   attenuation = 1.0F;
  1137.                }
  1138.                else {
  1139.                   /* positional light */
  1140.                   GLfloat d;     /* distance from vertex to light */
  1141.                   l[0] = CC.Light.Light[i].Position[0] - vertex[j][0];
  1142.                   l[1] = CC.Light.Light[i].Position[1] - vertex[j][1];
  1143.                   l[2] = CC.Light.Light[i].Position[2] - vertex[j][2];
  1144.                   d = (GLfloat) sqrt( l[0]*l[0] + l[1]*l[1] + l[2]*l[2] );
  1145.                   if (d>0.001F) {
  1146.                      GLfloat invd = 1.0F / d;
  1147.                      l[0] *= invd;
  1148.                      l[1] *= invd;
  1149.                      l[2] *= invd;
  1150.                   }
  1151.                   attenuation = 1.0F / (CC.Light.Light[i].ConstantAttenuation
  1152.                               + d * (CC.Light.Light[i].LinearAttenuation
  1153.                               + d * CC.Light.Light[i].QuadraticAttenuation));
  1154.                }
  1155.  
  1156.                l_dot_norm = DOT3( l, norm );
  1157.  
  1158.                /* diffuse and specular terms */
  1159.                if (l_dot_norm<=0.0F) {
  1160.                   /* surface faces away from light, no diffuse or specular */
  1161.                   R += attenuation * ambient[i][0];
  1162.                   G += attenuation * ambient[i][1];
  1163.                   B += attenuation * ambient[i][2];
  1164.                   /* done with this light */
  1165.                }
  1166.                else {
  1167.                   GLfloat s[3], dot, t, spotlight_effect;
  1168.                   GLfloat diffuseR, diffuseG, diffuseB;
  1169.                   GLfloat specularR, specularG, specularB;
  1170.                   
  1171.                   /* spotlight factor */
  1172.                   if (CC.Light.Light[i].SpotCutoff==180.0F) {
  1173.                      /* not a spot light */
  1174.                      spotlight_effect = 1.0F;
  1175.                   }
  1176.                   else {
  1177.                      GLfloat v[3], dot;
  1178.                      v[0] = -l[0];  /* v points from light to vertex */
  1179.                      v[1] = -l[1];
  1180.                      v[2] = -l[2];
  1181.                      dot = DOT3( v, CC.Light.Light[i].NormDirection );
  1182.                      if (dot<=0.0F || dot<CC.Light.Light[i].CosCutoff) {
  1183.                         /* outside of cone */
  1184.                         spotlight_effect = 0.0F;
  1185.                      }
  1186.                      else {
  1187.                         double x = dot * (EXP_TABLE_SIZE-1);
  1188.                         int k = (int) x;
  1189.                         spotlight_effect = CC.Light.Light[i].SpotExpTable[k][0]
  1190.                            + (x-k)*CC.Light.Light[i].SpotExpTable[k][1];
  1191.                      }
  1192.                   }
  1193.  
  1194.                   /* diffuse term */
  1195.                   diffuseR = l_dot_norm * CC.Light.Light[i].Diffuse[0]
  1196.                                * CC.Light.Material[side].Diffuse[0];
  1197.                   diffuseG = l_dot_norm * CC.Light.Light[i].Diffuse[1]
  1198.                                * CC.Light.Material[side].Diffuse[1];
  1199.                   diffuseB = l_dot_norm * CC.Light.Light[i].Diffuse[2]
  1200.                                * CC.Light.Material[side].Diffuse[2];
  1201.  
  1202.                   /* specular term */
  1203.                   if (CC.Light.Model.LocalViewer) {
  1204.                      GLfloat v[3];
  1205.                      v[0] = vertex[j][0];
  1206.                      v[1] = vertex[j][1];
  1207.                      v[2] = vertex[j][2];
  1208.                      NORMALIZE_3V( v );
  1209.                      s[0] = l[0] - v[0];
  1210.                      s[1] = l[1] - v[1];
  1211.                      s[2] = l[2] - v[2];
  1212.                   }
  1213.                   else {
  1214.                      s[0] = l[0];
  1215.                      s[1] = l[1];
  1216.                      s[2] = l[2] + 1.0F;
  1217.                   }
  1218.                   /* attention: s is not normalized, done later if needed */
  1219.                   dot = DOT3(s,norm);
  1220.  
  1221.                   if (dot<=0.0) {
  1222.                      specularR = 0.0F;
  1223.                      specularG = 0.0F;
  1224.                      specularB = 0.0F;
  1225.                   }
  1226.                   else {
  1227.                      GLfloat spec_coef;
  1228.                      /* now `correct' the dot product */
  1229.                      dot = dot / sqrt(s[0]*s[0]+s[1]*s[1]+s[2]*s[2]);
  1230.                      if (dot>1.0F) {
  1231.                         /* only happens if normal vector length > 1.0 */
  1232.                         spec_coef = pow( dot,
  1233.                                          CC.Light.Material[side].Shininess );
  1234.                      }
  1235.                      else {
  1236.                         /* use table lookup approximation */
  1237.                         int k = (int) (dot * (GLfloat) (SHINE_TABLE_SIZE-1));
  1238.                         spec_coef = CC.Light.Material[side].ShineTable[k];
  1239.                      }
  1240.                      if (spec_coef<1.0e-10) {
  1241.                         specularR = 0.0F;
  1242.                         specularG = 0.0F;
  1243.                         specularB = 0.0F;
  1244.                      }
  1245.                      else {
  1246.                         specularR = spec_coef * CC.Light.Light[i].Specular[0]
  1247.                                     * CC.Light.Material[side].Specular[0];
  1248.                         specularG = spec_coef * CC.Light.Light[i].Specular[1]
  1249.                                     * CC.Light.Material[side].Specular[1];
  1250.                         specularB = spec_coef * CC.Light.Light[i].Specular[2]
  1251.                                     * CC.Light.Material[side].Specular[2];
  1252.                      }
  1253.                   }
  1254.                   t = attenuation * spotlight_effect;
  1255.                   R += t * (ambient[i][0] + diffuseR + specularR);
  1256.                   G += t * (ambient[i][1] + diffuseG + specularG);
  1257.                   B += t * (ambient[i][2] + diffuseB + specularB);
  1258.                }
  1259.  
  1260.             } /*if*/
  1261.  
  1262.          } /*for loop over lights*/
  1263.  
  1264.          if (side==0) {
  1265.             /* clamp and convert to integer or fixed point */
  1266.             frontcolor[j][0] = (GLfixed) (CLAMP( R, 0.0F, 1.0F ) * rscale);
  1267.             frontcolor[j][1] = (GLfixed) (CLAMP( G, 0.0F, 1.0F ) * gscale);
  1268.             frontcolor[j][2] = (GLfixed) (CLAMP( B, 0.0F, 1.0F ) * bscale);
  1269.             frontcolor[j][3] = A;
  1270.          }
  1271.          else {
  1272.             /* clamp and convert to integer or fixed point */
  1273.             backcolor[j][0] = (GLfixed) (CLAMP( R, 0.0F, 1.0F ) * rscale);
  1274.             backcolor[j][1] = (GLfixed) (CLAMP( G, 0.0F, 1.0F ) * gscale);
  1275.             backcolor[j][2] = (GLfixed) (CLAMP( B, 0.0F, 1.0F ) * bscale);
  1276.             backcolor[j][3] = A;
  1277.          }
  1278.       } /*loop over vertices*/
  1279.  
  1280.    } /*for side*/
  1281. }
  1282.  
  1283.  
  1284.  
  1285. /*
  1286.  * This is an optimized version of the above function.
  1287.  */
  1288. void gl_color_shade_vertices_fast( GLuint n,
  1289.                                    GLfloat vertex[][4],
  1290.                                    GLfloat normal[][3],
  1291.                                    GLuint twoside,
  1292.                                    GLfixed frontcolor[][4],
  1293.                                    GLfixed backcolor[][4] )
  1294. {
  1295.    GLint i, j;
  1296.    GLfloat rscale, gscale, bscale, ascale;
  1297.    GLint ishininess = CC.Light.Material[0].Shininess;
  1298.    GLdouble dshininess = CC.Light.Material[0].Shininess;
  1299.    GLfixed A;
  1300.  
  1301.    /* Compute scale factor to go from floats in [0,1] to integers or fixed
  1302.     * point values:
  1303.     */
  1304.    rscale = (GLfloat) ( (GLint) CC.RedScale   << CC.ColorShift );
  1305.    gscale = (GLfloat) ( (GLint) CC.GreenScale << CC.ColorShift );
  1306.    bscale = (GLfloat) ( (GLint) CC.BlueScale  << CC.ColorShift );
  1307.    ascale = (GLfloat) ( (GLint) CC.AlphaScale << CC.ColorShift );
  1308.  
  1309.    /* Alpha is easy to compute, same for all vertices */
  1310.    A = (GLfixed) ( CC.Light.BaseColor[3] * ascale);
  1311.  
  1312.    /* Loop over vertices */
  1313.    for (j=0;j<n;j++) {
  1314.       GLfloat R, G, B;
  1315.       GLfloat nx, ny, nz;
  1316.  
  1317.       /* the normal vector */
  1318.       nx = normal[j][0];
  1319.       ny = normal[j][1];
  1320.       nz = normal[j][2];
  1321.  
  1322.       /* base color from global illumination and enabled light's ambient */
  1323.       R = CC.Light.BaseColor[0];
  1324.       G = CC.Light.BaseColor[1];
  1325.       B = CC.Light.BaseColor[2];
  1326.  
  1327.       /* Add contribution from each light source */
  1328.       for (i=CC.Light.LastEnabled;i>=0;i--) {
  1329.          if (CC.Light.Light[i].Enabled) {
  1330.             GLfloat lx, ly, lz;  /* unit vector from vertex to light */
  1331.             GLfloat l_dot_norm;  /* dot product of l and norm */
  1332.  
  1333.             lx = CC.Light.Light[i].NormPosition[0];
  1334.             ly = CC.Light.Light[i].NormPosition[1];
  1335.             lz = CC.Light.Light[i].NormPosition[2];
  1336.  
  1337.             l_dot_norm = lx*nx + ly*ny + lz*nz;
  1338.  
  1339.             /* diffuse and specular terms */
  1340.             if (l_dot_norm>0.0F) {
  1341.                GLfloat dot;
  1342.  
  1343.                /* add diffuse term */
  1344.                R += l_dot_norm * CC.Light.Diffuse[i][0];
  1345.                G += l_dot_norm * CC.Light.Diffuse[i][1];
  1346.                B += l_dot_norm * CC.Light.Diffuse[i][2];
  1347.  
  1348.                /* dot product of n and s, s = l + <0,0,1> */
  1349.                dot = nx*lx + ny*ly + nz*(lz+1.0F);
  1350.  
  1351.                /* specular term */
  1352.                if (dot>0.0F) {
  1353.                   /* now `correct' the dot product */
  1354.                   dot = dot / sqrt(lx*lx+ly*ly+(lz+1.0F)*(lz+1.0F));
  1355.                   if (dot>1.0F) {
  1356.                      /* only happens if normal vector length > 1.0 */
  1357.                      GLfloat spec_coef = pow( dot,
  1358.                                               CC.Light.Material[0].Shininess );
  1359.                      if (spec_coef>1.0e-10F) {
  1360.                         R += spec_coef * CC.Light.Specular[i][0];
  1361.                         G += spec_coef * CC.Light.Specular[i][1];
  1362.                         B += spec_coef * CC.Light.Specular[i][2];
  1363.                      }
  1364.                   }
  1365.                   else {
  1366.                      /* use table lookup approximation */
  1367.                      int k = (int) (dot * (GLfloat) (SHINE_TABLE_SIZE-1));
  1368.                      GLfloat spec_coef = CC.Light.Material[0].ShineTable[k];
  1369.                      R += spec_coef * CC.Light.Specular[i][0];
  1370.                      G += spec_coef * CC.Light.Specular[i][1];
  1371.                      B += spec_coef * CC.Light.Specular[i][2];
  1372.                   }
  1373.                }
  1374.             }
  1375.  
  1376.          } /*if*/
  1377.  
  1378.       } /*for loop over lights*/
  1379.  
  1380.       /* clamp and convert to integer or fixed point */
  1381.       frontcolor[j][0] = (GLfixed) (MIN2( R, 1.0F ) * rscale);
  1382.       frontcolor[j][1] = (GLfixed) (MIN2( G, 1.0F ) * gscale);
  1383.       frontcolor[j][2] = (GLfixed) (MIN2( B, 1.0F ) * bscale);
  1384.       frontcolor[j][3] = A;
  1385.  
  1386.    } /*loop over vertices*/
  1387. }
  1388.  
  1389.  
  1390.  
  1391. /*
  1392.  * Use current lighting/material settings to compute the color indexes
  1393.  * for an array of vertices.
  1394.  * Input:  n - number of vertices to shade
  1395.  *         vertex - array of [n] vertex position in viewing coordinates
  1396.  *         normal - array of [n] surface normal vector
  1397.  *         twoside - 0 = front face shading only, 1 = two-sided lighting
  1398.  * Output:  frontindex - resulting array of [n] front-face color indexes
  1399.  *          backindex - resulting array of [n] back-face color indexes
  1400.  */
  1401. void gl_index_shade_vertices( GLuint n,
  1402.                               GLfloat vertex[][4],
  1403.                               GLfloat normal[][3],
  1404.                               GLuint twoside,
  1405.                               GLuint frontindex[],
  1406.                               GLuint backindex[] )
  1407. {
  1408.    GLint side, i, j;
  1409.  
  1410.    for (side=0;side<=twoside;side++) {
  1411.       GLint ishininess = CC.Light.Material[side].Shininess;
  1412.       GLdouble dshininess = CC.Light.Material[side].Shininess;
  1413.  
  1414.       /* loop over vertices */
  1415.       for (j=0;j<n;j++) {
  1416.          GLfloat d_ci, s_ci;
  1417.          GLfloat d_a, s_a, index;
  1418.          GLfloat diffuse, specular;  /* accumulated diffuse and specular terms */
  1419.          GLfloat norm[3];
  1420.  
  1421.          if (side==0) {
  1422.             /* shade frontside */
  1423.             norm[0] = normal[j][0];
  1424.             norm[1] = normal[j][1];
  1425.             norm[2] = normal[j][2];
  1426.          }
  1427.          else {
  1428.             /* shade backside */
  1429.             norm[0] = -normal[j][0];
  1430.             norm[1] = -normal[j][1];
  1431.             norm[2] = -normal[j][2];
  1432.          }
  1433.  
  1434.          diffuse = specular = 0.0;
  1435.  
  1436.          /* Accumulate diffuse and specular from each light source */
  1437.          for (i=0;i<=CC.Light.LastEnabled;i++) {
  1438.  
  1439.             if (CC.Light.Light[i].Enabled) {
  1440.                GLfloat attenuation;
  1441.                GLfloat spotlight_effect;
  1442.                GLfloat l[3];  /* unit vector from vertex to light */
  1443.                GLfloat l_dot_norm;  /* dot product of l and norm */
  1444.  
  1445.                /* compute l and  attenuation */
  1446.                if (CC.Light.Light[i].Position[3]==0.0) {
  1447.                   /* directional light */
  1448.                   /* Effectively, l is a vector from the origin to the light. */
  1449.                   l[0] = CC.Light.Light[i].NormPosition[0];
  1450.                   l[1] = CC.Light.Light[i].NormPosition[1];
  1451.                   l[2] = CC.Light.Light[i].NormPosition[2];
  1452.                   attenuation = 1.0F;
  1453.                }
  1454.                else {
  1455.                   /* positional light */
  1456.                   GLfloat d;     /* distance from vertex to light */
  1457.                   l[0] = CC.Light.Light[i].Position[0] - vertex[j][0];
  1458.                   l[1] = CC.Light.Light[i].Position[1] - vertex[j][1];
  1459.                   l[2] = CC.Light.Light[i].Position[2] - vertex[j][2];
  1460.                   d = (GLfloat) sqrt( l[0]*l[0] + l[1]*l[1] + l[2]*l[2] );
  1461.                   if (d>0.001) {
  1462.                      GLfloat invd = 1.0F / d;
  1463.                      l[0] *= invd;
  1464.                      l[1] *= invd;
  1465.                      l[2] *= invd;
  1466.                   }
  1467.                   attenuation = 1.0F / (CC.Light.Light[i].ConstantAttenuation
  1468.                                  + d * (CC.Light.Light[i].LinearAttenuation
  1469.                                  + d * CC.Light.Light[i].QuadraticAttenuation));
  1470.                }
  1471.  
  1472.                l_dot_norm = DOT3( l, norm );
  1473.  
  1474.                if (l_dot_norm>0.0F) {
  1475.  
  1476.                   /* spotlight factor */
  1477.                   if (CC.Light.Light[i].SpotCutoff==180.0F) {
  1478.                      /* not a spot light */
  1479.                      spotlight_effect = 1.0F;
  1480.                   }
  1481.                   else {
  1482.                      GLfloat v[3], dot;
  1483.                      v[0] = -l[0];  /* v points from light to vertex */
  1484.                      v[1] = -l[1];
  1485.                      v[2] = -l[2];
  1486.                      dot = DOT3( v, CC.Light.Light[i].NormDirection );
  1487.                      if (dot<=0.0F || dot<CC.Light.Light[i].CosCutoff) {
  1488.                         /* outside of cone */
  1489.                         spotlight_effect = 0.0F;
  1490.                      }
  1491.                      else {
  1492.                         double x = dot * (EXP_TABLE_SIZE-1);
  1493.                         int k = (int) x;
  1494.                         spotlight_effect = CC.Light.Light[i].SpotExpTable[k][0]
  1495.                                   + (x-k)*CC.Light.Light[i].SpotExpTable[k][1];
  1496.                      }
  1497.                   }
  1498.  
  1499.                   /* accumulate diffuse term */
  1500.                   d_ci = 0.30F * CC.Light.Light[i].Diffuse[0]
  1501.                        + 0.59F * CC.Light.Light[i].Diffuse[1]
  1502.                        + 0.11F * CC.Light.Light[i].Diffuse[2];
  1503.                   diffuse += l_dot_norm * d_ci * spotlight_effect * attenuation;
  1504.  
  1505.                   /* accumulate specular term */
  1506.                   {
  1507.                      GLfloat s[3], dot, spec_coef;
  1508.  
  1509.                      /* specular term */
  1510.                      if (CC.Light.Model.LocalViewer) {
  1511.                         GLfloat v[3];
  1512.                         v[0] = vertex[j][0];
  1513.                         v[1] = vertex[j][1];
  1514.                         v[2] = vertex[j][2];
  1515.                         NORMALIZE_3V( v );
  1516.                         s[0] = l[0] - v[0];
  1517.                         s[1] = l[1] - v[1];
  1518.                         s[2] = l[2] - v[2];
  1519.                      }
  1520.                      else {
  1521.                         s[0] = l[0];
  1522.                         s[1] = l[1];
  1523.                         s[2] = l[2] + 1.0F;
  1524.                      }
  1525.                      /* attention: s is not normalized, done later if necessary */
  1526.                      dot = DOT3(s,norm);
  1527.  
  1528.                      if (dot<=0.0F) {
  1529.                         spec_coef = 0.0;
  1530.                      }
  1531.                      else {
  1532.                         /* now `correct' the dot product */
  1533.                         dot = dot / sqrt(s[0]*s[0]+s[1]*s[1]+s[2]*s[2]);
  1534.                         if (dot>1.0F) {
  1535.                            spec_coef = pow( dot,
  1536.                                            CC.Light.Material[side].Shininess );
  1537.                         }
  1538.                         else {
  1539.                            int k = (int) (dot * (GLfloat)(SHINE_TABLE_SIZE-1));
  1540.                            GLfloat spec_coef = CC.Light.Material[side].ShineTable[k];
  1541.                         }
  1542.                      }
  1543.                      s_ci = 0.30F * CC.Light.Light[i].Specular[0]
  1544.                           + 0.59F * CC.Light.Light[i].Specular[1]
  1545.                           + 0.11F * CC.Light.Light[i].Specular[2];
  1546.                      specular += spec_coef * s_ci * spotlight_effect * attenuation;
  1547.                   }
  1548.                }
  1549.  
  1550.             } /* if */
  1551.  
  1552.          } /* for */
  1553.  
  1554.          /* Now compute color index */
  1555.          if (specular>1.0F)
  1556.             specular = 1.0F;
  1557.  
  1558.          d_a = CC.Light.Material[side].DiffuseIndex
  1559.              - CC.Light.Material[side].AmbientIndex;
  1560.          s_a = CC.Light.Material[side].SpecularIndex
  1561.              - CC.Light.Material[side].AmbientIndex;
  1562.  
  1563.          index = CC.Light.Material[side].AmbientIndex
  1564.                + diffuse * (1.0-specular) * d_a
  1565.                + specular * s_a;
  1566.  
  1567.          if (index>CC.Light.Material[side].SpecularIndex) {
  1568.             index = CC.Light.Material[side].SpecularIndex;
  1569.          }
  1570.  
  1571.          if (side==0) {
  1572.             frontindex[j] = (GLuint) (GLint) index;
  1573.          }
  1574.          else {
  1575.             backindex[j] = (GLuint) (GLint) index;
  1576.          }
  1577.  
  1578.       } /*for vertex*/
  1579.  
  1580.    } /*for side*/
  1581. }
  1582.