home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 2 / AACD 2.iso / AACD / Magazine / GraphicsCards / StormMesa / src / shade.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-04  |  24.6 KB  |  914 lines

  1. /* $Id: shade.c,v 3.4 1998/07/01 02:39:14 brianp Exp $ */
  2.  
  3. /*
  4.  * Mesa 3-D graphics library
  5.  * Version:  3.0
  6.  * Copyright (C) 1995-1998  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: shade.c,v $
  26.  * Revision 3.4  1998/07/01 02:39:14  brianp
  27.  * added a hack to work around suspected gcc bug
  28.  *
  29.  * Revision 3.3  1998/04/18 05:00:28  brianp
  30.  * now using FLOAT_COLOR_TO_UBYTE_COLOR macro
  31.  *
  32.  * Revision 3.2  1998/03/27 04:17:31  brianp
  33.  * fixed G++ warnings
  34.  *
  35.  * Revision 3.1  1998/02/02 03:09:34  brianp
  36.  * added GL_LIGHT_MODEL_COLOR_CONTROL (separate specular color interpolation)
  37.  *
  38.  * Revision 3.0  1998/01/31 21:03:42  brianp
  39.  * initial rev
  40.  *
  41.  */
  42.  
  43.  
  44. #ifdef PC_HEADER
  45. #include "all.h"
  46. #else
  47. #include <math.h>
  48. #include "macros.h"
  49. #include "mmath.h"
  50. #include "shade.h"
  51. #include "types.h"
  52. #endif
  53.  
  54. #if defined(AMIGA) && defined(__PPC__)
  55. float fast_invsqrt(float x);
  56.  
  57. typedef struct
  58. {
  59.     GLfloat *h_inf_norm;
  60.     GLfloat *VP_inf_norm;
  61.     GLfloat *MatDiffuse;
  62.     GLfloat *MatSpecular;
  63.     GLfloat Shininess;
  64.     GLfloat *ShineTable;
  65. } shade_opt;
  66.  
  67. void asm_shade_rgba_fast(GLuint n, GLuint side, GLfloat normal[][3],
  68.              GLubyte color[][4], GLfloat basecolor[4],
  69.              shade_opt *sh);
  70. #endif
  71.  
  72. /*
  73.  * Return x^y.
  74.  */
  75. static GLfloat gl_pow( GLfloat x, GLfloat y )
  76. {
  77.    GLdouble z = pow(x, y);
  78.    if (z<1.0e-10)
  79.       return 0.0F;
  80.    else
  81.       return (GLfloat) z;
  82. }
  83.  
  84.  
  85.  
  86. /*
  87.  * Use current lighting/material settings to compute the RGBA colors of
  88.  * an array of vertexes.
  89.  * Input:  side - 0=use front material, 1=use back material
  90.  *         n - number of vertexes to process
  91.  *         vertex - array of vertex positions in eye coordinates
  92.  *         normal - array of surface normal vectors
  93.  * Output:  color - array of resulting colors
  94.  */
  95. void gl_shade_rgba( GLcontext *ctx,
  96.             GLuint side,
  97.             GLuint n,
  98.             /*const*/ GLfloat vertex[][4],
  99.             /*const*/ GLfloat normal[][3],
  100.             GLubyte color[][4] )
  101. {
  102.    GLuint j;
  103.    GLfloat baseR, baseG, baseB, baseA;
  104.    GLint sumA;
  105.    struct gl_light *light;
  106.    struct gl_material *mat;
  107.  
  108.    mat = &ctx->Light.Material[side];
  109.  
  110.    /*** Compute color contribution from global lighting ***/
  111.    baseR = mat->Emission[0] + ctx->Light.Model.Ambient[0] * mat->Ambient[0];
  112.    baseG = mat->Emission[1] + ctx->Light.Model.Ambient[1] * mat->Ambient[1];
  113.    baseB = mat->Emission[2] + ctx->Light.Model.Ambient[2] * mat->Ambient[2];
  114.    baseA = mat->Diffuse[3];  /* Alpha is simple, same for all vertices */
  115.  
  116.    FLOAT_COLOR_TO_UBYTE_COLOR( sumA, baseA );
  117.  
  118.    for (j=0;j<n;j++) {
  119.       GLfloat sumR, sumG, sumB;
  120.       GLfloat nx, ny, nz;
  121.  
  122.       if (side==0) {
  123.      /* shade frontside */
  124.      nx = normal[j][0];
  125.      ny = normal[j][1];
  126.      nz = normal[j][2];
  127.       }
  128.       else {
  129.      /* shade backside */
  130.      nx = -normal[j][0];
  131.      ny = -normal[j][1];
  132.      nz = -normal[j][2];
  133.       }
  134.  
  135.       sumR = baseR;
  136.       sumG = baseG;
  137.       sumB = baseB;
  138.  
  139.       /* Add contribution from each enabled light source */
  140.       for (light=ctx->Light.FirstEnabled; light; light=light->NextEnabled) {
  141.      GLfloat ambientR, ambientG, ambientB;
  142.      GLfloat attenuation, spot;
  143.      GLfloat VPx, VPy, VPz;  /* unit vector from vertex to light */
  144.      GLfloat n_dot_VP;       /* n dot VP */
  145.  
  146.      /* compute VP and attenuation */
  147.      if (light->Position[3]==0.0) {
  148.         /* directional light */
  149.         VPx = light->VP_inf_norm[0];
  150.         VPy = light->VP_inf_norm[1];
  151.         VPz = light->VP_inf_norm[2];
  152.         attenuation = 1.0F;
  153.      }
  154.      else {
  155.         /* positional light */
  156.         GLfloat d;     /* distance from vertex to light */
  157.         VPx = light->Position[0] - vertex[j][0];
  158.         VPy = light->Position[1] - vertex[j][1];
  159.         VPz = light->Position[2] - vertex[j][2];
  160.         d = (GLfloat) GL_SQRT( VPx*VPx + VPy*VPy + VPz*VPz );
  161.         if (d>0.001F) {
  162.            GLfloat invd = 1.0F / d;
  163.            VPx *= invd;
  164.            VPy *= invd;
  165.            VPz *= invd;
  166.         }
  167.         attenuation = 1.0F / (light->ConstantAttenuation
  168.             + d * (light->LinearAttenuation
  169.             + d * light->QuadraticAttenuation));
  170.      }
  171.  
  172.      /* spotlight factor */
  173.      if (light->SpotCutoff==180.0F) {
  174.         /* not a spot light */
  175.         spot = 1.0F;
  176.      }
  177.      else {
  178.         GLfloat PVx, PVy, PVz, PV_dot_dir;
  179.         PVx = -VPx;
  180.         PVy = -VPy;
  181.         PVz = -VPz;
  182.         PV_dot_dir = PVx*light->NormDirection[0]
  183.                + PVy*light->NormDirection[1]
  184.                + PVz*light->NormDirection[2];
  185.         if (PV_dot_dir<=0.0F || PV_dot_dir<light->CosCutoff) {
  186.            /* outside of cone */
  187.            spot = 0.0F;
  188.         }
  189.         else {
  190.            double x = PV_dot_dir * (EXP_TABLE_SIZE-1);
  191.            int k = (int) x;
  192.            spot = light->SpotExpTable[k][0]
  193.             + (x-k)*light->SpotExpTable[k][1];
  194.         }
  195.      }
  196.  
  197.      ambientR = mat->Ambient[0] * light->Ambient[0];
  198.      ambientG = mat->Ambient[1] * light->Ambient[1];
  199.      ambientB = mat->Ambient[2] * light->Ambient[2];
  200.  
  201.      /* Compute dot product or normal and vector from V to light pos */
  202.      n_dot_VP = nx * VPx + ny * VPy + nz * VPz;
  203.  
  204.      /* diffuse and specular terms */
  205.      if (n_dot_VP<=0.0F) {
  206.         /* surface face away from light, no diffuse or specular */
  207.         GLfloat t = attenuation * spot;
  208.         sumR += t * ambientR;
  209.         sumG += t * ambientG;
  210.         sumB += t * ambientB;
  211.         /* done with this light */
  212.      }
  213.      else {
  214.         GLfloat diffuseR, diffuseG, diffuseB;
  215.         GLfloat specularR, specularG, specularB;
  216.         GLfloat h_x, h_y, h_z, n_dot_h, t;
  217.           
  218.         /* diffuse term */
  219.         diffuseR = n_dot_VP * mat->Diffuse[0] * light->Diffuse[0];
  220.         diffuseG = n_dot_VP * mat->Diffuse[1] * light->Diffuse[1];
  221.         diffuseB = n_dot_VP * mat->Diffuse[2] * light->Diffuse[2];
  222.  
  223.         /* specular term */
  224.         if (ctx->Light.Model.LocalViewer) {
  225.            GLfloat vx, vy, vz, vlen;
  226.            vx = vertex[j][0];
  227.            vy = vertex[j][1];
  228.            vz = vertex[j][2];
  229.  
  230. #if !defined(AMIGA) || !defined(__PPC__)
  231.            vlen = GL_SQRT( vx*vx + vy*vy + vz*vz );
  232.            if (vlen>0.0001F) {
  233.           GLfloat invlen = 1.0F / vlen;
  234.           vx *= invlen;
  235.           vy *= invlen;
  236.           vz *= invlen;
  237.            }
  238. #else
  239.            vlen = vx*vx + vy*vy + vz*vz;
  240.            if (vlen >0.000001F)
  241.            {
  242.           GLfloat invlen = fast_invsqrt(vlen);
  243.           vx *= invlen;
  244.           vy *= invlen;
  245.           vz *= invlen;
  246.            }
  247. #endif
  248.            /* h = VP + VPe */
  249.            h_x = VPx - vx;
  250.            h_y = VPy - vy;
  251.            h_z = VPz - vz;
  252.         }
  253.         else {
  254.            /* h = VP + <0,0,1> */
  255.            h_x = VPx;
  256.            h_y = VPy;
  257.            h_z = VPz + 1.0F;
  258.         }
  259.  
  260.         /* attention: h is not normalized, done later if needed */
  261.         n_dot_h = nx*h_x + ny*h_y + nz*h_z;
  262.  
  263.         if (n_dot_h<=0.0F) {
  264.            specularR = 0.0F;
  265.            specularG = 0.0F;
  266.            specularB = 0.0F;
  267.         }
  268.         else {
  269.            GLfloat spec_coef;
  270.            /* now `correct' the dot product */
  271.  
  272. #if !defined(AMIGA) || !defined(__PPC__)
  273.            n_dot_h = n_dot_h / GL_SQRT( h_x*h_x + h_y*h_y + h_z*h_z );
  274. #else
  275.            n_dot_h = n_dot_h * fast_invsqrt( h_x*h_x + h_y*h_y + h_z*h_z );
  276. #endif
  277.            if (n_dot_h>1.0F) {
  278.           /* only happens if normal vector length > 1.0 */
  279.           spec_coef = pow( n_dot_h, mat->Shininess );
  280.            }
  281.            else {
  282.           /* use table lookup approximation */
  283.           int k = (int) (n_dot_h * (GLfloat) (SHINE_TABLE_SIZE-1));
  284.           if (mat->ShineTable[k] < 0.0F)
  285.           {
  286. #ifndef AMIGA
  287.              mat->ShineTable[k] = gl_pow( n_dot_h, mat->Shininess );
  288. #else
  289.              mat->ShineTable[k] = pow( n_dot_h, mat->Shininess );
  290. #endif
  291.           }
  292.           spec_coef = mat->ShineTable[k];
  293.            }
  294.            if (spec_coef<1.0e-10) {
  295.           specularR = 0.0F;
  296.           specularG = 0.0F;
  297.           specularB = 0.0F;
  298.            }
  299.            else {
  300.           specularR = spec_coef * mat->Specular[0]*light->Specular[0];
  301.           specularG = spec_coef * mat->Specular[1]*light->Specular[1];
  302.           specularB = spec_coef * mat->Specular[2]*light->Specular[2];
  303.            }
  304.         }
  305.  
  306.         t = attenuation * spot;
  307.         sumR += t * (ambientR + diffuseR + specularR);
  308.         sumG += t * (ambientG + diffuseG + specularG);
  309.         sumB += t * (ambientB + diffuseB + specularB);
  310.      }
  311.  
  312.       } /*loop over lights*/
  313.  
  314.       /* clamp and convert to integer or fixed point */
  315.       FLOAT_COLOR_TO_UBYTE_COLOR( color[j][0], sumR );
  316.       FLOAT_COLOR_TO_UBYTE_COLOR( color[j][1], sumG );
  317.       FLOAT_COLOR_TO_UBYTE_COLOR( color[j][2], sumB );
  318.       color[j][3] = sumA;
  319.  
  320.    } /*loop over vertices*/
  321. }
  322.  
  323.  
  324.  
  325. /*
  326.  * Compute separate base and specular colors.
  327.  * Input:  side - 0=use front material, 1=use back material
  328.  *         n - number of vertexes to process
  329.  *         vertex - array of vertex positions in eye coordinates
  330.  *         normal - array of surface normal vectors
  331.  * Output:  baseColor - array of base colors (emission, ambient, diffuse)
  332.  *          specColor - array of specular colors
  333.  */
  334. void gl_shade_rgba_spec( GLcontext *ctx,
  335.              GLuint side,
  336.              GLuint n,
  337.              /*const*/ GLfloat vertex[][4],
  338.              /*const*/ GLfloat normal[][3],
  339.              GLubyte baseColor[][4], GLubyte specColor[][4] )
  340. {
  341.    GLuint j;
  342.    GLfloat baseR, baseG, baseB, baseA;
  343.    GLint sumBaseA;
  344.    struct gl_light *light;
  345.    struct gl_material *mat;
  346.  
  347.    mat = &ctx->Light.Material[side];
  348.  
  349.    /*** Compute color contribution from global lighting ***/
  350.    baseR = mat->Emission[0] + ctx->Light.Model.Ambient[0] * mat->Ambient[0];
  351.    baseG = mat->Emission[1] + ctx->Light.Model.Ambient[1] * mat->Ambient[1];
  352.    baseB = mat->Emission[2] + ctx->Light.Model.Ambient[2] * mat->Ambient[2];
  353.    baseA = mat->Diffuse[3];  /* Alpha is simple, same for all vertices */
  354.  
  355.    FLOAT_COLOR_TO_UBYTE_COLOR( sumBaseA, baseA );
  356.  
  357.    for (j=0;j<n;j++) {
  358.       GLfloat sumBaseR, sumBaseG, sumBaseB;
  359.       GLfloat sumSpecR, sumSpecG, sumSpecB;
  360.       GLfloat nx, ny, nz;
  361.  
  362.       if (side==0) {
  363.      /* shade frontside */
  364.      nx = normal[j][0];
  365.      ny = normal[j][1];
  366.      nz = normal[j][2];
  367.       }
  368.       else {
  369.      /* shade backside */
  370.      nx = -normal[j][0];
  371.      ny = -normal[j][1];
  372.      nz = -normal[j][2];
  373.       }
  374.  
  375.       sumBaseR = baseR;
  376.       sumBaseG = baseG;
  377.       sumBaseB = baseB;
  378.       sumSpecR = sumSpecG = sumSpecB = 0.0;
  379.  
  380.       /* Add contribution from each enabled light source */
  381.       for (light=ctx->Light.FirstEnabled; light; light=light->NextEnabled) {
  382.      GLfloat ambientR, ambientG, ambientB;
  383.      GLfloat attenuation, spot;
  384.      GLfloat VPx, VPy, VPz;  /* unit vector from vertex to light */
  385.      GLfloat n_dot_VP;       /* n dot VP */
  386.  
  387.      /* compute VP and attenuation */
  388.      if (light->Position[3]==0.0) {
  389.         /* directional light */
  390.         VPx = light->VP_inf_norm[0];
  391.         VPy = light->VP_inf_norm[1];
  392.         VPz = light->VP_inf_norm[2];
  393.         attenuation = 1.0F;
  394.      }
  395.      else {
  396.         /* positional light */
  397.         GLfloat d;     /* distance from vertex to light */
  398.         VPx = light->Position[0] - vertex[j][0];
  399.         VPy = light->Position[1] - vertex[j][1];
  400.         VPz = light->Position[2] - vertex[j][2];
  401. #if !defined(AMIGA) || !defined(__PPC__)
  402.         d = (GLfloat) GL_SQRT( VPx*VPx + VPy*VPy + VPz*VPz );
  403.         if (d>0.001F) {
  404.            GLfloat invd = 1.0F / d;
  405.            VPx *= invd;
  406.            VPy *= invd;
  407.            VPz *= invd;
  408.         }
  409. #else
  410.         d = VPx*VPx + VPy*VPy + VPz*VPz;
  411.         if (d >0.01F)
  412.         {
  413.            GLfloat invd = fast_invsqrt(d);
  414.            VPx *= invd;
  415.            VPy *= invd;
  416.            VPz *= invd;
  417.         }
  418. #endif
  419.         attenuation = 1.0F / (light->ConstantAttenuation
  420.             + d * (light->LinearAttenuation
  421.             + d * light->QuadraticAttenuation));
  422.      }
  423.  
  424.      /* spotlight factor */
  425.      if (light->SpotCutoff==180.0F) {
  426.         /* not a spot light */
  427.         spot = 1.0F;
  428.      }
  429.      else {
  430.         GLfloat PVx, PVy, PVz, PV_dot_dir;
  431.         PVx = -VPx;
  432.         PVy = -VPy;
  433.         PVz = -VPz;
  434.         PV_dot_dir = PVx*light->NormDirection[0]
  435.                + PVy*light->NormDirection[1]
  436.                + PVz*light->NormDirection[2];
  437.         if (PV_dot_dir<=0.0F || PV_dot_dir<light->CosCutoff) {
  438.            /* outside of cone */
  439.            spot = 0.0F;
  440.         }
  441.         else {
  442.            double x = PV_dot_dir * (EXP_TABLE_SIZE-1);
  443.            int k = (int) x;
  444.            spot = light->SpotExpTable[k][0]
  445.             + (x-k)*light->SpotExpTable[k][1];
  446.         }
  447.      }
  448.  
  449.      ambientR = mat->Ambient[0] * light->Ambient[0];
  450.      ambientG = mat->Ambient[1] * light->Ambient[1];
  451.      ambientB = mat->Ambient[2] * light->Ambient[2];
  452.  
  453.      /* Compute dot product or normal and vector from V to light pos */
  454.      n_dot_VP = nx * VPx + ny * VPy + nz * VPz;
  455.  
  456.      /* diffuse and specular terms */
  457.      if (n_dot_VP<=0.0F) {
  458.         /* surface face away from light, no diffuse or specular */
  459.         GLfloat t = attenuation * spot;
  460.         sumBaseR += t * ambientR;
  461.         sumBaseG += t * ambientG;
  462.         sumBaseB += t * ambientB;
  463.         /* done with this light */
  464.      }
  465.      else {
  466.         GLfloat diffuseR, diffuseG, diffuseB;
  467.         GLfloat specularR, specularG, specularB;
  468.         GLfloat h_x, h_y, h_z, n_dot_h, t;
  469.           
  470.         /* diffuse term */
  471.         diffuseR = n_dot_VP * mat->Diffuse[0] * light->Diffuse[0];
  472.         diffuseG = n_dot_VP * mat->Diffuse[1] * light->Diffuse[1];
  473.         diffuseB = n_dot_VP * mat->Diffuse[2] * light->Diffuse[2];
  474.  
  475.         /* specular term */
  476.         if (ctx->Light.Model.LocalViewer) {
  477.            GLfloat vx, vy, vz, vlen;
  478.            vx = vertex[j][0];
  479.            vy = vertex[j][1];
  480.            vz = vertex[j][2];
  481. #if !defined(AMIGA) || !defined(__PPC__)
  482.            vlen = GL_SQRT( vx*vx + vy*vy + vz*vz );
  483.            if (vlen>0.0001F) {
  484.           GLfloat invlen = 1.0F / vlen;
  485.           vx *= invlen;
  486.           vy *= invlen;
  487.           vz *= invlen;
  488.            }
  489. #else
  490.            vlen = vx*vx + vy*vy + vz*vz;
  491.            if (vlen >0.001F)
  492.            {
  493.           GLfloat invlen = fast_invsqrt(vlen);
  494.           vx *= invlen;
  495.           vy *= invlen;
  496.           vz *= invlen;
  497.            }
  498. #endif
  499.            /* h = VP + VPe */
  500.            h_x = VPx - vx;
  501.            h_y = VPy - vy;
  502.            h_z = VPz - vz;
  503.         }
  504.         else {
  505.            /* h = VP + <0,0,1> */
  506.            h_x = VPx;
  507.            h_y = VPy;
  508.            h_z = VPz + 1.0F;
  509.         }
  510.  
  511.         /* attention: h is not normalized, done later if needed */
  512.         n_dot_h = nx*h_x + ny*h_y + nz*h_z;
  513.  
  514.         if (n_dot_h<=0.0F) {
  515.            specularR = 0.0F;
  516.            specularG = 0.0F;
  517.            specularB = 0.0F;
  518.         }
  519.         else {
  520.            GLfloat spec_coef;
  521.            /* now `correct' the dot product */
  522. #if !defined(AMIGA) || !defined(__PPC__)
  523.            n_dot_h = n_dot_h / GL_SQRT( h_x*h_x + h_y*h_y + h_z*h_z );
  524. #else
  525.            n_dot_h = n_dot_h * fast_invsqrt( h_x*h_x + h_y*h_y + h_z*h_z );
  526. #endif
  527.            if (n_dot_h>1.0F) {
  528.           /* only happens if normal vector length > 1.0 */
  529.           spec_coef = pow( n_dot_h, mat->Shininess );
  530.            }
  531.            else {
  532.           /* use table lookup approximation */
  533.           int k = (int) (n_dot_h * (GLfloat) (SHINE_TABLE_SIZE-1));
  534.           if (mat->ShineTable[k] < 0.0F)
  535. #ifndef AMIGA
  536.              mat->ShineTable[k] = gl_pow( n_dot_h, mat->Shininess );
  537. #else
  538.              mat->ShineTable[k] = pow( n_dot_h, mat->Shininess );
  539. #endif
  540.           spec_coef = mat->ShineTable[k];
  541.            }
  542.            if (spec_coef<1.0e-10) {
  543.           specularR = 0.0F;
  544.           specularG = 0.0F;
  545.           specularB = 0.0F;
  546.            }
  547.            else {
  548.           specularR = spec_coef * mat->Specular[0]*light->Specular[0];
  549.           specularG = spec_coef * mat->Specular[1]*light->Specular[1];
  550.           specularB = spec_coef * mat->Specular[2]*light->Specular[2];
  551.            }
  552.         }
  553.  
  554.         t = attenuation * spot;
  555.         sumBaseR += t * (ambientR + diffuseR);
  556.         sumBaseG += t * (ambientG + diffuseG);
  557.         sumBaseB += t * (ambientB + diffuseB);
  558.         sumSpecR += t * specularR;
  559.         sumSpecG += t * specularG;
  560.         sumSpecB += t * specularB;
  561.      }
  562.  
  563.       } /*loop over lights*/
  564.  
  565.       /* clamp and convert to integer or fixed point */
  566.       FLOAT_COLOR_TO_UBYTE_COLOR( baseColor[j][0], sumBaseR );
  567.       FLOAT_COLOR_TO_UBYTE_COLOR( baseColor[j][1], sumBaseG );
  568.       FLOAT_COLOR_TO_UBYTE_COLOR( baseColor[j][2], sumBaseB );
  569.       baseColor[j][3] = sumBaseA;
  570.  
  571.       FLOAT_COLOR_TO_UBYTE_COLOR( specColor[j][0], sumSpecR );
  572.       FLOAT_COLOR_TO_UBYTE_COLOR( specColor[j][1], sumSpecG );
  573.       FLOAT_COLOR_TO_UBYTE_COLOR( specColor[j][2], sumSpecB );
  574.       specColor[j][3] = 255;  /* but never used */
  575.  
  576.    } /*loop over vertices*/
  577. }
  578.  
  579.  
  580.  
  581. /*
  582.  * This is an optimized version of the above function.
  583.  */
  584. void gl_shade_rgba_fast( GLcontext *ctx,
  585.              GLuint side,
  586.              GLuint n,
  587.              /*const*/ GLfloat normal[][3],
  588.              GLubyte color[][4] )
  589. {
  590.    GLuint j;
  591.    GLint sumA;
  592.    GLfloat *baseColor = ctx->Light.BaseColor[side];
  593.  
  594. #if defined(AMIGA) && defined(__PPC__)
  595.    {
  596.     struct gl_light* light = ctx->Light.FirstEnabled;
  597.     if (!light)
  598.     {
  599.         asm_shade_rgba_fast(n,side,normal,color,baseColor,NULL);
  600.         return;
  601.     }
  602.     if (light && !light->NextEnabled)
  603.     {
  604.         shade_opt sh;
  605.  
  606.         sh.VP_inf_norm = light->VP_inf_norm;
  607.         sh.h_inf_norm = light->h_inf_norm;
  608.         sh.MatDiffuse = light->MatDiffuse[side];
  609.         sh.MatSpecular = light->MatSpecular[side];
  610.         sh.Shininess = ctx->Light.Material[side].Shininess;
  611.         sh.ShineTable = ctx->Light.Material[side].ShineTable;
  612.         asm_shade_rgba_fast(n,side,normal,color,baseColor,&sh);
  613.         return;
  614.     }
  615.    }
  616. #endif
  617.  
  618.    /* Alpha is easy to compute, same for all vertices */
  619.    sumA = (GLint) (baseColor[3] * 255.0F);
  620.  
  621.    /* Loop over vertices */
  622.    for (j=0;j<n;j++) {
  623.       GLfloat sumR, sumG, sumB;
  624.       GLfloat nx, ny, nz;
  625.       struct gl_light *light;
  626.  
  627.       /* the normal vector */
  628.       if (side==0) {
  629.      nx = normal[j][0];
  630.      ny = normal[j][1];
  631.      nz = normal[j][2];
  632.       }
  633.       else {
  634.      nx = -normal[j][0];
  635.      ny = -normal[j][1];
  636.      nz = -normal[j][2];
  637.       }
  638.  
  639. #ifdef SPEED_HACK
  640.       if (nz<0.0F) {
  641.      color[j][0] = 0.0F;
  642.      color[j][1] = 0.0F;
  643.      color[j][2] = 0.0F;
  644.      color[j][3] = A;
  645.      continue;
  646.       }
  647. #endif
  648.  
  649.       /* base color from global illumination and enabled light's ambient */
  650.       sumR = baseColor[0];
  651.       sumG = baseColor[1];
  652.       sumB = baseColor[2];
  653.  
  654.       /* Add contribution from each light source */
  655.       for (light=ctx->Light.FirstEnabled; light; light=light->NextEnabled) {
  656.      GLfloat n_dot_VP;     /* n dot VP */
  657.  
  658.      n_dot_VP = nx * light->VP_inf_norm[0]
  659.           + ny * light->VP_inf_norm[1]
  660.           + nz * light->VP_inf_norm[2];
  661.  
  662.      /* diffuse and specular terms */
  663.      if (n_dot_VP>0.0F) {
  664.         GLfloat n_dot_h;
  665.         GLfloat *lightMatDiffuse = light->MatDiffuse[side];
  666.  
  667.         /** add diffuse term **/
  668.         sumR += n_dot_VP * lightMatDiffuse[0];
  669.         sumG += n_dot_VP * lightMatDiffuse[1];
  670.         sumB += n_dot_VP * lightMatDiffuse[2];
  671.  
  672.         /** specular term **/
  673.         /* dot product of n and h_inf_norm */
  674.         n_dot_h = nx * light->h_inf_norm[0]
  675.             + ny * light->h_inf_norm[1]
  676.             + nz * light->h_inf_norm[2];
  677.         if (n_dot_h>0.0F) {
  678.            if (n_dot_h>1.0F) {
  679.           /* only happens if Magnitude(n) > 1.0 */
  680.           GLfloat spec_coef = pow( n_dot_h,
  681.                     ctx->Light.Material[side].Shininess );
  682.           if (spec_coef>1.0e-10F) {
  683.              sumR += spec_coef * light->MatSpecular[side][0];
  684.              sumG += spec_coef * light->MatSpecular[side][1];
  685.              sumB += spec_coef * light->MatSpecular[side][2];
  686.           }
  687.            }
  688.            else {
  689.           /* use table lookup approximation */
  690.           int k = (int) (n_dot_h * (GLfloat) (SHINE_TABLE_SIZE-1));
  691.           struct gl_material *m = &ctx->Light.Material[side];
  692.           GLfloat spec_coef;
  693.           if (m->ShineTable[k] < 0.0F)
  694.           {
  695. #ifndef AMIGA
  696.              m->ShineTable[k] = gl_pow( n_dot_h, m->Shininess );
  697. #else
  698.              m->ShineTable[k] = pow( n_dot_h, m->Shininess );
  699. #endif
  700.           }
  701.           spec_coef = m->ShineTable[k];
  702.           sumR += spec_coef * light->MatSpecular[side][0];
  703.           sumG += spec_coef * light->MatSpecular[side][1];
  704.           sumB += spec_coef * light->MatSpecular[side][2];
  705.            }
  706.         }
  707.      }
  708.  
  709.       } /*loop over lights*/
  710.  
  711.       /* clamp and convert to integer or fixed point */
  712.       FLOAT_COLOR_TO_UBYTE_COLOR( color[j][0], sumR );
  713.       FLOAT_COLOR_TO_UBYTE_COLOR( color[j][1], sumG );
  714.       FLOAT_COLOR_TO_UBYTE_COLOR( color[j][2], sumB );
  715.       color[j][3] = sumA;
  716.  
  717. #ifndef AMIGA
  718.       /* Ugh, I think there's a bug in gcc 2.7.2.3.  If the following
  719.        * no-op code isn't here then the results of the above
  720.        * FLOAT_COLOR_TO_UBYTE_COLOR() macro are unpredictable!
  721.        */
  722.       {
  723.      GLubyte r0 = FloatToInt(CLAMP(sumR, 0, 1) * 255.0);
  724.       }
  725. #endif
  726.  
  727.    } /*loop over vertices*/
  728. }
  729.  
  730.  
  731.  
  732. /*
  733.  * Use current lighting/material settings to compute the color indexes
  734.  * for an array of vertices.
  735.  * Input:  n - number of vertices to shade
  736.  *         side - 0=use front material, 1=use back material
  737.  *         vertex - array of [n] vertex position in eye coordinates
  738.  *         normal - array of [n] surface normal vector
  739.  * Output:  indexResult - resulting array of [n] color indexes
  740.  */
  741. void gl_shade_ci( GLcontext *ctx,
  742.           GLuint side,
  743.           GLuint n,
  744.           GLfloat vertex[][4],
  745.           GLfloat normal[][3],
  746.           GLuint indexResult[] )
  747. {
  748.    struct gl_material *mat = &ctx->Light.Material[side];
  749.    GLuint j;
  750.  
  751.    /* loop over vertices */
  752.    for (j=0;j<n;j++) {
  753.       GLfloat index;
  754.       GLfloat diffuse, specular;  /* accumulated diffuse and specular */
  755.       GLfloat nx, ny, nz;  /* normal vector */
  756.       struct gl_light *light;
  757.  
  758.       if (side==0) {
  759.      /* shade frontside */
  760.      nx = normal[j][0];
  761.      ny = normal[j][1];
  762.      nz = normal[j][2];
  763.       }
  764.       else {
  765.      /* shade backside */
  766.      nx = -normal[j][0];
  767.      ny = -normal[j][1];
  768.      nz = -normal[j][2];
  769.       }
  770.  
  771.       diffuse = specular = 0.0F;
  772.  
  773.       /* Accumulate diffuse and specular from each light source */
  774.       for (light=ctx->Light.FirstEnabled; light; light=light->NextEnabled) {
  775.      GLfloat attenuation;
  776.      GLfloat lx, ly, lz;  /* unit vector from vertex to light */
  777.      GLfloat l_dot_norm;  /* dot product of l and n */
  778.  
  779.      /* compute l and attenuation */
  780.      if (light->Position[3]==0.0) {
  781.         /* directional light */
  782.         /* Effectively, l is a vector from the origin to the light. */
  783.         lx = light->VP_inf_norm[0];
  784.         ly = light->VP_inf_norm[1];
  785.         lz = light->VP_inf_norm[2];
  786.         attenuation = 1.0F;
  787.      }
  788.      else {
  789.         /* positional light */
  790.         GLfloat d;     /* distance from vertex to light */
  791.         lx = light->Position[0] - vertex[j][0];
  792.         ly = light->Position[1] - vertex[j][1];
  793.         lz = light->Position[2] - vertex[j][2];
  794.         d = (GLfloat) GL_SQRT( lx*lx + ly*ly + lz*lz );
  795.         if (d>0.001F) {
  796.            GLfloat invd = 1.0F / d;
  797.            lx *= invd;
  798.            ly *= invd;
  799.            lz *= invd;
  800.         }
  801.         attenuation = 1.0F / (light->ConstantAttenuation
  802.             + d * (light->LinearAttenuation
  803.             + d * light->QuadraticAttenuation));
  804.      }
  805.  
  806.      l_dot_norm = lx*nx + ly*ny + lz*nz;
  807.  
  808.      if (l_dot_norm>0.0F) {
  809.         GLfloat spot_times_atten;
  810.  
  811.         /* spotlight factor */
  812.         if (light->SpotCutoff==180.0F) {
  813.            /* not a spot light */
  814.            spot_times_atten = attenuation;
  815.         }
  816.         else {
  817.            GLfloat v[3], dot;
  818.            v[0] = -lx;  /* v points from light to vertex */
  819.            v[1] = -ly;
  820.            v[2] = -lz;
  821.            dot = DOT3( v, light->NormDirection );
  822.            if (dot<=0.0F || dot<light->CosCutoff) {
  823.           /* outside of cone */
  824.           spot_times_atten = 0.0F;
  825.            }
  826.            else {
  827.           double x = dot * (EXP_TABLE_SIZE-1);
  828.           int k = (int) x;
  829.           GLfloat spot = light->SpotExpTable[k][0]
  830.                    + (x-k)*light->SpotExpTable[k][1];
  831.           spot_times_atten = spot * attenuation;
  832.            }
  833.         }
  834.  
  835.         /* accumulate diffuse term */
  836.         diffuse += l_dot_norm * light->dli * spot_times_atten;
  837.  
  838.         /* accumulate specular term */
  839.         {
  840.            GLfloat h_x, h_y, h_z, n_dot_h, spec_coef;
  841.  
  842.            /* specular term */
  843.            if (ctx->Light.Model.LocalViewer) {
  844.           GLfloat vx, vy, vz, vlen;
  845.           vx = vertex[j][0];
  846.           vy = vertex[j][1];
  847.           vz = vertex[j][2];
  848.           vlen = GL_SQRT( vx*vx + vy*vy + vz*vz );
  849.           if (vlen>0.0001F) {
  850.              GLfloat invlen = 1.0F / vlen;
  851.              vx *= invlen;
  852.              vy *= invlen;
  853.              vz *= invlen;
  854.           }
  855.           h_x = lx - vx;
  856.           h_y = ly - vy;
  857.           h_z = lz - vz;
  858.            }
  859.            else {
  860.           h_x = lx;
  861.           h_y = ly;
  862.           h_z = lz + 1.0F;
  863.            }
  864.            /* attention: s is not normalized, done later if necessary */
  865.            n_dot_h = h_x*nx + h_y*ny + h_z*nz;
  866.  
  867.            if (n_dot_h <= 0.0F) {
  868.           spec_coef = 0.0F;
  869.            }
  870.            else {
  871.           /* now `correct' the dot product */
  872.           n_dot_h = n_dot_h / GL_SQRT(h_x*h_x + h_y*h_y + h_z*h_z);
  873.           if (n_dot_h>1.0F) {
  874.              spec_coef = pow( n_dot_h, mat->Shininess );
  875.           }
  876.           else {
  877.              int k = (int) (n_dot_h * (GLfloat)(SHINE_TABLE_SIZE-1));
  878.              if (mat->ShineTable[k] < 0.0F)
  879. #ifndef AMIGA
  880.             mat->ShineTable[k] = gl_pow( n_dot_h, mat->Shininess );
  881. #else
  882.             mat->ShineTable[k] = pow( n_dot_h, mat->Shininess );
  883. #endif
  884.              spec_coef = mat->ShineTable[k];
  885.           }
  886.            }
  887.            specular += spec_coef * light->sli * spot_times_atten;
  888.         }
  889.      }
  890.  
  891.       } /*loop over lights*/
  892.  
  893.       /* Now compute final color index */
  894.       if (specular>1.0F) {
  895.      index = mat->SpecularIndex;
  896.       }
  897.       else {
  898.      GLfloat d_a, s_a;
  899.      d_a = mat->DiffuseIndex - mat->AmbientIndex;
  900.      s_a = mat->SpecularIndex - mat->AmbientIndex;
  901.  
  902.      index = mat->AmbientIndex
  903.            + diffuse * (1.0F-specular) * d_a
  904.            + specular * s_a;
  905.      if (index>mat->SpecularIndex) {
  906.         index = mat->SpecularIndex;
  907.      }
  908.       }
  909.       indexResult[j] = (GLuint) (GLint) index;
  910.  
  911.    } /*for vertex*/
  912. }
  913.  
  914.