t3dlib8.cpp
上传用户:husern
上传日期:2018-01-20
资源大小:42486k
文件大小:215k
源码类别:

游戏

开发平台:

Visual C++

  1.               bi = ((lights[curr_light].c_ambient.b * b_base) / 256);
  2.             
  3.               // ambient light has the same affect on each vertex
  4.               r_sum0+=ri;
  5.               g_sum0+=gi;
  6.               b_sum0+=bi;
  7.   
  8.               r_sum1+=ri;
  9.               g_sum1+=gi;
  10.               b_sum1+=bi;
  11.               
  12.               r_sum2+=ri;
  13.               g_sum2+=gi;
  14.               b_sum2+=bi;
  15.               // there better only be one ambient light!
  16.               //Write_Error("nexiting ambient ,sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0,  r_sum1, g_sum1, b_sum1,  r_sum2, g_sum2, b_sum2);
  17.               } // end if
  18.            else
  19.            if (lights[curr_light].attr & LIGHTV2_ATTR_INFINITE) /////////////////////////////////
  20.               {
  21.               //Write_Error("nentering infinite light...");
  22.               // infinite lighting, we need the surface normal, and the direction
  23.               // of the light source
  24.               // no longer need to compute normal or length, we already have the vertex normal
  25.               // and it's length is 1.0  
  26.               // ....
  27.       
  28.               // ok, recalling the lighting model for infinite lights
  29.               // I(d)dir = I0dir * Cldir
  30.               // and for the diffuse model
  31.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  32.               // so we basically need to multiple it all together
  33.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  34.               // are slower, but the conversion to and from cost cycles
  35.               // need to perform lighting for each vertex (lots of redundant math, optimize later!)
  36.               //Write_Error("nv0=[%f, %f, %f]=%f, v1=[%f, %f, %f]=%f, v2=[%f, %f, %f]=%f",
  37.                 // curr_poly->tvlist[0].n.x, curr_poly->tvlist[0].n.y,curr_poly->tvlist[0].n.z, VECTOR4D_Length(&curr_poly->tvlist[0].n),
  38.                 // curr_poly->tvlist[1].n.x, curr_poly->tvlist[1].n.y,curr_poly->tvlist[1].n.z, VECTOR4D_Length(&curr_poly->tvlist[1].n),
  39.                 // curr_poly->tvlist[2].n.x, curr_poly->tvlist[2].n.y,curr_poly->tvlist[2].n.z, VECTOR4D_Length(&curr_poly->tvlist[2].n) );
  40.               // vertex 0
  41.               dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_0].n, &lights[curr_light].tdir); 
  42.               
  43.               // only add light if dp > 0
  44.               if (dp > 0)
  45.                  { 
  46.                  i = 128*dp; 
  47.                  r_sum0+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  48.                  g_sum0+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  49.                  b_sum0+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  50.                  } // end if
  51.               // vertex 1
  52.               dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_1].n, &lights[curr_light].tdir);
  53.               
  54.               // only add light if dp > 0
  55.               if (dp > 0)
  56.                  { 
  57.                  i = 128*dp; 
  58.                  r_sum1+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  59.                  g_sum1+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  60.                  b_sum1+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  61.                  } // end if
  62.               // vertex 2
  63.               dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_2].n, &lights[curr_light].tdir);
  64.               
  65.               // only add light if dp > 0
  66.               if (dp > 0)
  67.                  { 
  68.                  i = 128*dp; 
  69.                  r_sum2+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  70.                  g_sum2+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  71.                  b_sum2+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  72.                  } // end if
  73.               //Write_Error("nexiting infinite, color sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0,  r_sum1, g_sum1, b_sum1,  r_sum2, g_sum2, b_sum2);
  74.               } // end if infinite light
  75.            else
  76.            if (lights[curr_light].attr & LIGHTV2_ATTR_POINT) //////////////////////////////////////
  77.               {
  78.               // perform point light computations
  79.               // light model for point light is once again:
  80.               //              I0point * Clpoint
  81.               //  I(d)point = ___________________
  82.               //              kc +  kl*d + kq*d2              
  83.               //
  84.               //  Where d = |p - s|
  85.               // thus it's almost identical to the infinite light, but attenuates as a function
  86.               // of distance from the point source to the surface point being lit
  87.               // .. normal already in vertex
  88.               //Write_Error("nEntering point light....");
  89.               // compute vector from surface to light
  90.               VECTOR4D_Build(&obj->vlist_trans[ vindex_0].v, &lights[curr_light].tpos, &l);
  91.               // compute distance and attenuation
  92.               dist = VECTOR4D_Length_Fast2(&l);  
  93.               // and for the diffuse model
  94.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  95.               // so we basically need to multiple it all together
  96.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  97.               // are slower, but the conversion to and from cost cycles
  98.               // perform the calculation for all 3 vertices
  99.               // vertex 0
  100.               dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_0].n, &l);
  101.               
  102.               // only add light if dp > 0
  103.               if (dp > 0)
  104.                  { 
  105.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  106.                  i = 128*dp / (dist * atten ); 
  107.                  r_sum0 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  108.                  g_sum0 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  109.                  b_sum0 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  110.                  } // end if
  111.               // vertex 1
  112.               dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_1].n, &l);
  113.               
  114.               // only add light if dp > 0
  115.               if (dp > 0)
  116.                  { 
  117.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  118.                  i = 128*dp / (dist * atten ); 
  119.                  r_sum1 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  120.                  g_sum1 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  121.                  b_sum1 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  122.                  } // end if
  123.               // vertex 2
  124.               dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_2].n, &l);
  125.               
  126.               // only add light if dp > 0
  127.               if (dp > 0)
  128.                  { 
  129.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  130.                  i = 128*dp / (dist * atten ); 
  131.                  r_sum2 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  132.                  g_sum2 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  133.                  b_sum2 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  134.                  } // end if
  135.               //Write_Error("nexiting point light, rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0,  r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
  136.               } // end if point
  137.            else
  138.            if (lights[curr_light].attr & LIGHTV2_ATTR_SPOTLIGHT1) ///////////////////////////////////////
  139.               {
  140.               // perform spotlight/point computations simplified model that uses
  141.               // point light WITH a direction to simulate a spotlight
  142.               // light model for point light is once again:
  143.               //              I0point * Clpoint
  144.               //  I(d)point = ___________________
  145.               //              kc +  kl*d + kq*d2              
  146.               //
  147.               //  Where d = |p - s|
  148.               // thus it's almost identical to the infinite light, but attenuates as a function
  149.               // of distance from the point source to the surface point being lit
  150.               //Write_Error("nentering spotlight1....");
  151.               // .. normal is already computed
  152.        
  153.               // compute vector from surface to light
  154.               VECTOR4D_Build(&obj->vlist_trans[ vindex_0].v, &lights[curr_light].tpos, &l);
  155.               // compute distance and attenuation
  156.               dist = VECTOR4D_Length_Fast2(&l);  
  157.               // and for the diffuse model
  158.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  159.               // so we basically need to multiple it all together
  160.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  161.               // are slower, but the conversion to and from cost cycles
  162.               // note that I use the direction of the light here rather than a the vector to the light
  163.               // thus we are taking orientation into account which is similar to the spotlight model
  164.               // vertex 0
  165.               dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_0].n, &lights[curr_light].tdir);
  166.               
  167.               // only add light if dp > 0
  168.               if (dp > 0)
  169.                  { 
  170.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  171.                  i = 128*dp / ( atten ); 
  172.                  r_sum0 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  173.                  g_sum0 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  174.                  b_sum0 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  175.                  } // end if
  176.               // vertex 1
  177.               dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_1].n, &lights[curr_light].tdir);
  178.               
  179.               // only add light if dp > 0
  180.               if (dp > 0)
  181.                  { 
  182.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  183.                  i = 128*dp / ( atten ); 
  184.                  r_sum1 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  185.                  g_sum1 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  186.                  b_sum1 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  187.                  } // end i
  188.               // vertex 2
  189.               dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_2].n, &lights[curr_light].tdir);
  190.               
  191.               // only add light if dp > 0
  192.               if (dp > 0)
  193.                  { 
  194.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  195.                  i = 128*dp / ( atten ); 
  196.                  r_sum2 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  197.                  g_sum2 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  198.                  b_sum2 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  199.                  } // end i
  200.               //Write_Error("nexiting spotlight1, sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0,  r_sum1, g_sum1, b_sum1,  r_sum2, g_sum2, b_sum2);
  201.               } // end if spotlight1
  202.            else
  203.            if (lights[curr_light].attr & LIGHTV2_ATTR_SPOTLIGHT2) // simple version //////////////////////////
  204.               {
  205.               // perform spot light computations
  206.               // light model for spot light simple version is once again:
  207.               //               I0spotlight * Clspotlight * MAX( (l . s), 0)^pf                     
  208.               // I(d)spotlight = __________________________________________      
  209.               //                 kc + kl*d + kq*d2        
  210.               // Where d = |p - s|, and pf = power factor
  211.               // thus it's almost identical to the point, but has the extra term in the numerator
  212.               // relating the angle between the light source and the point on the surface
  213.               // .. already have normals and length are 1.0
  214.              
  215.               // and for the diffuse model
  216.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  217.               // so we basically need to multiple it all together
  218.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  219.               // are slower, but the conversion to and from cost cycles
  220.               //Write_Error("nEntering spotlight2...");
  221.               // tons of redundant math here! lots to optimize later!
  222.               
  223.               // vertex 0
  224.               dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_0].n, &lights[curr_light].tdir);
  225.               
  226.               // only add light if dp > 0
  227.               if (dp > 0)
  228.                  { 
  229.                  // compute vector from light to surface (different from l which IS the light dir)
  230.                  VECTOR4D_Build( &lights[curr_light].tpos, &obj->vlist_trans[ vindex_0].v, &s);
  231.                  // compute length of s (distance to light source) to normalize s for lighting calc
  232.                  dists = VECTOR4D_Length_Fast2(&s);  
  233.                  // compute spot light term (s . l)
  234.                  float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
  235.                  // proceed only if term is positive
  236.                  if (dpsl > 0) 
  237.                     {
  238.                     // compute attenuation
  239.                     atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);    
  240.        
  241.                     // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
  242.                     // must be integral
  243.                     float dpsl_exp = dpsl;
  244.  
  245.                     // exponentiate for positive integral powers
  246.                     for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
  247.                          dpsl_exp*=dpsl;
  248.                     // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf 
  249.                                                       
  250.                     i = 128*dp * dpsl_exp / ( atten ); 
  251.                     r_sum0 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  252.                     g_sum0 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  253.                     b_sum0 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  254.   
  255.                     } // end if
  256.                  } // end if
  257.               // vertex 1
  258.               dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_1].n, &lights[curr_light].tdir);
  259.               
  260.               // only add light if dp > 0
  261.               if (dp > 0)
  262.                  { 
  263.                  // compute vector from light to surface (different from l which IS the light dir)
  264.                  VECTOR4D_Build( &lights[curr_light].tpos, &obj->vlist_trans[ vindex_1].v, &s);
  265.                  // compute length of s (distance to light source) to normalize s for lighting calc
  266.                  dists = VECTOR4D_Length_Fast2(&s);  
  267.                  // compute spot light term (s . l)
  268.                  float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
  269.                  // proceed only if term is positive
  270.                  if (dpsl > 0) 
  271.                     {
  272.                     // compute attenuation
  273.                     atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);    
  274.        
  275.                     // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
  276.                     // must be integral
  277.                     float dpsl_exp = dpsl;
  278.  
  279.                     // exponentiate for positive integral powers
  280.                     for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
  281.                          dpsl_exp*=dpsl;
  282.                     // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf 
  283.                                                       
  284.                     i = 128*dp * dpsl_exp / ( atten ); 
  285.                     r_sum1 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  286.                     g_sum1 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  287.                     b_sum1 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  288.   
  289.                     } // end if
  290.                  } // end if
  291.               // vertex 2
  292.               dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_2].n, &lights[curr_light].tdir);
  293.               
  294.               // only add light if dp > 0
  295.               if (dp > 0)
  296.                  { 
  297.                  // compute vector from light to surface (different from l which IS the light dir)
  298.                  VECTOR4D_Build( &lights[curr_light].tpos, &obj->vlist_trans[ vindex_2].v, &s);
  299.                  // compute length of s (distance to light source) to normalize s for lighting calc
  300.                  dists = VECTOR4D_Length_Fast2(&s);  
  301.                  // compute spot light term (s . l)
  302.                  float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
  303.                  // proceed only if term is positive
  304.                  if (dpsl > 0) 
  305.                     {
  306.                     // compute attenuation
  307.                     atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);    
  308.        
  309.                     // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
  310.                     // must be integral
  311.                     float dpsl_exp = dpsl;
  312.  
  313.                     // exponentiate for positive integral powers
  314.                     for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
  315.                          dpsl_exp*=dpsl;
  316.                     // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf 
  317.                                                       
  318.                     i = 128*dp * dpsl_exp / ( atten ); 
  319.                     r_sum2 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  320.                     g_sum2 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  321.                     b_sum2 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  322.                     } // end if
  323.                  } // end if
  324.               //Write_Error("nexiting spotlight2, sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0,   r_sum1, g_sum1, b_sum1,  r_sum2, g_sum2, b_sum2);
  325.               } // end if spot light
  326.            } // end for light
  327.   
  328.        // make sure colors aren't out of range
  329.        if (r_sum0  > 255) r_sum0 = 255;
  330.        if (g_sum0  > 255) g_sum0 = 255;
  331.        if (b_sum0  > 255) b_sum0 = 255;
  332.        if (r_sum1  > 255) r_sum1 = 255;
  333.        if (g_sum1  > 255) g_sum1 = 255;
  334.        if (b_sum1  > 255) b_sum1 = 255;
  335.        if (r_sum2  > 255) r_sum2 = 255;
  336.        if (g_sum2  > 255) g_sum2 = 255;
  337.        if (b_sum2  > 255) b_sum2 = 255;
  338.        //Write_Error("nwriting color for poly %d", poly);
  339.        //Write_Error("n******** final sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0,  r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
  340.        // write the colors, leave in 5.6.5 format, so we have more color range
  341.        // since the rasterizer will scale down to 8-bit
  342.        curr_poly->lit_color[0] = RGB16Bit(r_sum0, g_sum0, b_sum0);
  343.        curr_poly->lit_color[1] = RGB16Bit(r_sum1, g_sum1, b_sum1);
  344.        curr_poly->lit_color[2] = RGB16Bit(r_sum2, g_sum2, b_sum2);
  345.        } // end if
  346.     else // assume POLY4DV2_ATTR_SHADE_MODE_CONSTANT
  347.        {
  348.        // emmisive shading only, do nothing
  349.        // ...
  350.        curr_poly->lit_color[0] = curr_poly->color;
  351.        //Write_Error("nentering constant shader, and exiting...");
  352.        } // end if
  353.     } // end for poly
  354. // return success
  355. return(1);
  356. } // end Light_OBJECT4DV2_World2
  357. //////////////////////////////////////////////////////////////////////////////
  358. int Light_RENDERLIST4DV2_World2_16(RENDERLIST4DV2_PTR rend_list,  // list to process
  359.                                    CAM4DV1_PTR cam,     // camera position
  360.                                    LIGHTV2_PTR lights,  // light list (might have more than one)
  361.                                    int max_lights)      // maximum lights in list
  362. {
  363. // 16-bit version of function
  364. // function lights the entire rendering list based on the sent lights and camera. the function supports
  365. // constant/pure shading (emmisive), flat shading with ambient, infinite, point lights, and spot lights
  366. // note that this lighting function is rather brute force and simply follows the math, however
  367. // there are some clever integer operations that are used in scale 256 rather than going to floating
  368. // point, but why? floating point and ints are the same speed, HOWEVER, the conversion to and from floating
  369. // point can be cycle intensive, so if you can keep your calcs in ints then you can gain some speed
  370. // also note, type 1 spot lights are simply point lights with direction, the "cone" is more of a function
  371. // of the falloff due to attenuation, but they still look like spot lights
  372. // type 2 spot lights are implemented with the intensity having a dot product relationship with the
  373. // angle from the surface point to the light direction just like in the optimized model, but the pf term
  374. // that is used for a concentration control must be 1,2,3,.... integral and non-fractional
  375. // this function now performs emissive, flat, and gouraud lighting, results are stored in the 
  376. // lit_color[] array of each polygon
  377. unsigned int r_base, g_base,   b_base,  // base color being lit
  378.              r_sum,  g_sum,    b_sum,   // sum of lighting process over all lights
  379.              r_sum0,  g_sum0,  b_sum0,
  380.              r_sum1,  g_sum1,  b_sum1,
  381.              r_sum2,  g_sum2,  b_sum2,
  382.              ri,gi,bi,
  383.              shaded_color;            // final color
  384. float dp,     // dot product 
  385.       dist,   // distance from light to surface
  386.       dists, 
  387.       i,      // general intensities
  388.       nl,     // length of normal
  389.       atten;  // attenuation computations
  390. VECTOR4D u, v, n, l, d, s; // used for cross product and light vector calculations
  391. //Write_Error("nEntering lighting function");
  392. // for each valid poly, light it...
  393. for (int poly=0; poly < rend_list->num_polys; poly++)
  394.     {
  395.     // acquire polygon
  396.     POLYF4DV2_PTR curr_poly = rend_list->poly_ptrs[poly];
  397.     // light this polygon if and only if it's not clipped, not culled,
  398.     // active, and visible
  399.     if (!(curr_poly->state & POLY4DV2_STATE_ACTIVE) ||
  400.          (curr_poly->state & POLY4DV2_STATE_CLIPPED ) ||
  401.          (curr_poly->state & POLY4DV2_STATE_BACKFACE) ||
  402.          (curr_poly->state & POLY4DV2_STATE_LIT) )
  403.        continue; // move onto next poly
  404.     //Write_Error("npoly %d",poly);
  405. #ifdef DEBUG_ON
  406. // track rendering stats
  407.     debug_polys_lit_per_frame++;
  408. #endif
  409.    
  410.     // set state of polygon to lit
  411.     SET_BIT(curr_poly->state, POLY4DV2_STATE_LIT);
  412.     // we will use the transformed polygon vertex list since the backface removal
  413.     // only makes sense at the world coord stage further of the pipeline 
  414.     // test the lighting mode of the polygon (use flat for flat, gouraud))
  415.     if (curr_poly->attr & POLY4DV2_ATTR_SHADE_MODE_FLAT)
  416.        {
  417.        //Write_Error("nEntering Flat Shader");
  418.        // step 1: extract the base color out in RGB mode
  419.        // assume 565 format
  420.        _RGB565FROM16BIT(curr_poly->color, &r_base, &g_base, &b_base);
  421.        // scale to 8 bit 
  422.        r_base <<= 3;
  423.        g_base <<= 2;
  424.        b_base <<= 3;
  425.        //Write_Error("nBase color=%d,%d,%d", r_base, g_base, b_base);
  426.        // initialize color sum
  427.        r_sum  = 0;
  428.        g_sum  = 0;
  429.        b_sum  = 0;
  430.        //Write_Error("nsum color=%d,%d,%d", r_sum, g_sum, b_sum);
  431.        // new optimization:
  432.        // when there are multiple lights in the system we will end up performing numerous
  433.        // redundant calculations to minimize this my strategy is to set key variables to 
  434.        // to MAX values on each loop, then during the lighting calcs to test the vars for
  435.        // the max value, if they are the max value then the first light that needs the math
  436.        // will do it, and then save the information into the variable (causing it to change state
  437.        // from an invalid number) then any other lights that need the math can use the previously
  438.        // computed value
  439.        
  440.        // set surface normal.z to FLT_MAX to flag it as non-computed
  441.        n.z = FLT_MAX;
  442.        // loop thru lights
  443.        for (int curr_light = 0; curr_light < max_lights; curr_light++)
  444.            {
  445.            // is this light active
  446.            if (lights[curr_light].state==LIGHTV2_STATE_OFF)
  447.               continue;
  448.            //Write_Error("nprocessing light %d",curr_light);
  449.            // what kind of light are we dealing with
  450.            if (lights[curr_light].attr & LIGHTV2_ATTR_AMBIENT)
  451.               {
  452.               //Write_Error("nEntering ambient light...");
  453.               // simply multiply each channel against the color of the 
  454.               // polygon then divide by 256 to scale back to 0..255
  455.               // use a shift in real life!!! >> 8
  456.               r_sum+= ((lights[curr_light].c_ambient.r * r_base) / 256);
  457.               g_sum+= ((lights[curr_light].c_ambient.g * g_base) / 256);
  458.               b_sum+= ((lights[curr_light].c_ambient.b * b_base) / 256);
  459.               //Write_Error("nambient sum=%d,%d,%d", r_sum, g_sum, b_sum);
  460.               // there better only be one ambient light!
  461.               } // end if
  462.            else
  463.            if (lights[curr_light].attr & LIGHTV2_ATTR_INFINITE) ///////////////////////////////////////////
  464.               {
  465.               //Write_Error("nEntering infinite light...");
  466.               // infinite lighting, we need the surface normal, and the direction
  467.               // of the light source
  468.               // test if we already computed poly normal in previous calculation
  469.               if (n.z==FLT_MAX)       
  470.                  {
  471.                  // we need to compute the normal of this polygon face, and recall
  472.                  // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  473.  
  474.                  // build u, v
  475.                  VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[1].v, &u);
  476.                  VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[2].v, &v);
  477.                  // compute cross product
  478.                  VECTOR4D_Cross(&u, &v, &n);
  479.                  } // end if
  480.               // at this point, we are almost ready, but we have to normalize the normal vector!
  481.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  482.               // normals, so this step can be optimized
  483.               // compute length of normal
  484.               //nl = VECTOR4D_Length_Fast2(&n);
  485.               nl = curr_poly->nlength;  
  486.       
  487.               // ok, recalling the lighting model for infinite lights
  488.               // I(d)dir = I0dir * Cldir
  489.               // and for the diffuse model
  490.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  491.               // so we basically need to multiple it all together
  492.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  493.               // are slower, but the conversion to and from cost cycles
  494.               dp = VECTOR4D_Dot(&n, &lights[curr_light].tdir);
  495.               
  496.               // only add light if dp > 0
  497.               if (dp > 0)
  498.                  { 
  499.                  i = 128*dp/nl; 
  500.                  r_sum+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  501.                  g_sum+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  502.                  b_sum+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  503.                  } // end if
  504.               //Write_Error("ninfinite sum=%d,%d,%d", r_sum, g_sum, b_sum);
  505.               } // end if infinite light
  506.            else
  507.            if (lights[curr_light].attr & LIGHTV2_ATTR_POINT) ///////////////////////////////////////
  508.               {
  509.               //Write_Error("nEntering point light...");
  510.               // perform point light computations
  511.               // light model for point light is once again:
  512.               //              I0point * Clpoint
  513.               //  I(d)point = ___________________
  514.               //              kc +  kl*d + kq*d2              
  515.               //
  516.               //  Where d = |p - s|
  517.               // thus it's almost identical to the infinite light, but attenuates as a function
  518.               // of distance from the point source to the surface point being lit
  519.               // test if we already computed poly normal in previous calculation
  520.               if (n.z==FLT_MAX)       
  521.                  {
  522.                  // we need to compute the normal of this polygon face, and recall
  523.                  // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  524.  
  525.                  // build u, v
  526.                  VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[1].v, &u);
  527.                  VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[2].v, &v);
  528.                  // compute cross product
  529.                  VECTOR4D_Cross(&u, &v, &n);
  530.                  } // end if
  531.               // at this point, we are almost ready, but we have to normalize the normal vector!
  532.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  533.               // normals, so this step can be optimized
  534.               // compute length of normal
  535.               //nl = VECTOR4D_Length_Fast2(&n);
  536.               nl = curr_poly->nlength;  
  537.               // compute vector from surface to light
  538.               VECTOR4D_Build(&curr_poly->tvlist[0].v, &lights[curr_light].tpos, &l);
  539.               // compute distance and attenuation
  540.               dist = VECTOR4D_Length_Fast2(&l);  
  541.               // and for the diffuse model
  542.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  543.               // so we basically need to multiple it all together
  544.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  545.               // are slower, but the conversion to and from cost cycles
  546.               dp = VECTOR4D_Dot(&n, &l);
  547.               
  548.               // only add light if dp > 0
  549.               if (dp > 0)
  550.                  { 
  551.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  552.                  i = 128*dp / (nl * dist * atten ); 
  553.                  r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  554.                  g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  555.                  b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  556.                  } // end if
  557.               //Write_Error("npoint sum=%d,%d,%d",r_sum,g_sum,b_sum);
  558.               } // end if point
  559.            else
  560.            if (lights[curr_light].attr & LIGHTV2_ATTR_SPOTLIGHT1) ////////////////////////////////////
  561.               {
  562.               //Write_Error("nentering spot light1...");
  563.               // perform spotlight/point computations simplified model that uses
  564.               // point light WITH a direction to simulate a spotlight
  565.               // light model for point light is once again:
  566.               //              I0point * Clpoint
  567.               //  I(d)point = ___________________
  568.               //              kc +  kl*d + kq*d2              
  569.               //
  570.               //  Where d = |p - s|
  571.               // thus it's almost identical to the infinite light, but attenuates as a function
  572.               // of distance from the point source to the surface point being lit
  573.               // test if we already computed poly normal in previous calculation
  574.               if (n.z==FLT_MAX)       
  575.                  {
  576.                  // we need to compute the normal of this polygon face, and recall
  577.                  // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  578.  
  579.                  // build u, v
  580.                  VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[1].v, &u);
  581.                  VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[2].v, &v);
  582.                  // compute cross product
  583.                  VECTOR4D_Cross(&u, &v, &n);
  584.                  } // end if
  585.               // at this point, we are almost ready, but we have to normalize the normal vector!
  586.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  587.               // normals, so this step can be optimized
  588.               // compute length of normal
  589.               //nl = VECTOR4D_Length_Fast2(&n);
  590.               nl = curr_poly->nlength;  
  591.        
  592.               // compute vector from surface to light
  593.               VECTOR4D_Build(&curr_poly->tvlist[0].v, &lights[curr_light].tpos, &l);
  594.               // compute distance and attenuation
  595.               dist = VECTOR4D_Length_Fast2(&l);  
  596.               // and for the diffuse model
  597.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  598.               // so we basically need to multiple it all together
  599.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  600.               // are slower, but the conversion to and from cost cycles
  601.               // note that I use the direction of the light here rather than a the vector to the light
  602.               // thus we are taking orientation into account which is similar to the spotlight model
  603.               dp = VECTOR4D_Dot(&n, &lights[curr_light].tdir);
  604.               
  605.               // only add light if dp > 0
  606.               if (dp > 0)
  607.                  { 
  608.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  609.                  i = 128*dp / (nl * atten ); 
  610.                  r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  611.                  g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  612.                  b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  613.                  } // end if
  614.               //Write_Error("nspotlight sum=%d,%d,%d",r_sum, g_sum, b_sum);
  615.               } // end if spotlight1
  616.            else
  617.            if (lights[curr_light].attr & LIGHTV2_ATTR_SPOTLIGHT2) // simple version ////////////////////
  618.               {
  619.               //Write_Error("nEntering spotlight2 ...");
  620.  
  621.               // perform spot light computations
  622.               // light model for spot light simple version is once again:
  623.               //               I0spotlight * Clspotlight * MAX( (l . s), 0)^pf                     
  624.               // I(d)spotlight = __________________________________________      
  625.               //                 kc + kl*d + kq*d2        
  626.               // Where d = |p - s|, and pf = power factor
  627.               // thus it's almost identical to the point, but has the extra term in the numerator
  628.               // relating the angle between the light source and the point on the surface
  629.               // test if we already computed poly normal in previous calculation
  630.               if (n.z==FLT_MAX)       
  631.                  {
  632.                  // we need to compute the normal of this polygon face, and recall
  633.                  // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  634.  
  635.                  // build u, v
  636.                  VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[1].v, &u);
  637.                  VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[2].v, &v);
  638.                  // compute cross product
  639.                  VECTOR4D_Cross(&u, &v, &n);
  640.                  } // end if
  641.               // at this point, we are almost ready, but we have to normalize the normal vector!
  642.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  643.               // normals, so this step can be optimized
  644.               // compute length of normal
  645.               //nl = VECTOR4D_Length_Fast2(&n);
  646.               nl = curr_poly->nlength;  
  647.              
  648.               // and for the diffuse model
  649.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  650.               // so we basically need to multiple it all together
  651.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  652.               // are slower, but the conversion to and from cost cycles
  653.               dp = VECTOR4D_Dot(&n, &lights[curr_light].tdir);
  654.               
  655.               // only add light if dp > 0
  656.               if (dp > 0)
  657.                  { 
  658.                  // compute vector from light to surface (different from l which IS the light dir)
  659.                  VECTOR4D_Build( &lights[curr_light].tpos, &curr_poly->tvlist[0].v, &s);
  660.                  // compute length of s (distance to light source) to normalize s for lighting calc
  661.                  dists = VECTOR4D_Length_Fast2(&s);  
  662.                  // compute spot light term (s . l)
  663.                  float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
  664.                  // proceed only if term is positive
  665.                  if (dpsl > 0) 
  666.                     {
  667.                     // compute attenuation
  668.                     atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);    
  669.        
  670.                     // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
  671.                     // must be integral
  672.                     float dpsl_exp = dpsl;
  673.  
  674.                     // exponentiate for positive integral powers
  675.                     for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
  676.                          dpsl_exp*=dpsl;
  677.                     // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf 
  678.                                                       
  679.                     i = 128*dp * dpsl_exp / (nl * atten ); 
  680.                     r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  681.                     g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  682.                     b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  683.   
  684.                     } // end if
  685.                  } // end if
  686.               //Write_Error("nSpotlight sum=%d,%d,%d",r_sum, g_sum, b_sum);
  687.      
  688.               } // end if spot light
  689.            } // end for light
  690.   
  691.        // make sure colors aren't out of range
  692.        if (r_sum  > 255) r_sum = 255;
  693.        if (g_sum  > 255) g_sum = 255;
  694.        if (b_sum  > 255) b_sum = 255;
  695.        //Write_Error("nWriting final values to polygon %d = %d,%d,%d", poly, r_sum, g_sum, b_sum);
  696.        // write the color over current color
  697.        curr_poly->lit_color[0] = RGB16Bit(r_sum, g_sum, b_sum);
  698.        } // end if
  699.     else
  700.     if (curr_poly->attr & POLY4DV2_ATTR_SHADE_MODE_GOURAUD) /////////////////////////////////
  701.        {
  702.        // gouraud shade, unfortunetly at this point in the pipeline, we have lost the original
  703.        // mesh, and only have triangles, thus, many triangles will share the same vertices and
  704.        // they will get lit 2x since we don't have any way to tell this, alas, performing lighting
  705.        // at the object level is a better idea when gouraud shading is performed since the 
  706.        // commonality of vertices is still intact, in any case, lighting here is similar to polygon
  707.        // flat shaded, but we do it 3 times, once for each vertex, additionally there are lots
  708.        // of opportunities for optimization, but I am going to lay off them for now, so the code
  709.        // is intelligible, later we will optimize
  710.        //Write_Error("nEntering gouraud shader...");
  711.        // step 1: extract the base color out in RGB mode
  712.        // assume 565 format
  713.        _RGB565FROM16BIT(curr_poly->color, &r_base, &g_base, &b_base);
  714.        // scale to 8 bit 
  715.        r_base <<= 3;
  716.        g_base <<= 2;
  717.        b_base <<= 3;
  718.        //Write_Error("nBase color=%d, %d, %d", r_base, g_base, b_base);
  719.        // initialize color sum(s) for vertices
  720.        r_sum0  = 0;
  721.        g_sum0  = 0;
  722.        b_sum0  = 0;
  723.        r_sum1  = 0;
  724.        g_sum1  = 0;
  725.        b_sum1  = 0;
  726.        r_sum2  = 0;
  727.        g_sum2  = 0;
  728.        b_sum2  = 0;
  729.        //Write_Error("nColor sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0,   r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
  730.        // new optimization:
  731.        // when there are multiple lights in the system we will end up performing numerous
  732.        // redundant calculations to minimize this my strategy is to set key variables to 
  733.        // to MAX values on each loop, then during the lighting calcs to test the vars for
  734.        // the max value, if they are the max value then the first light that needs the math
  735.        // will do it, and then save the information into the variable (causing it to change state
  736.        // from an invalid number) then any other lights that need the math can use the previously
  737.        // computed value, however, since we already have the normals, not much here to cache on
  738.        // a large scale, but small scale stuff is there, however, we will optimize those later
  739.        // loop thru lights
  740.        for (int curr_light = 0; curr_light < max_lights; curr_light++)
  741.            {
  742.            // is this light active
  743.            if (lights[curr_light].state==LIGHTV2_STATE_OFF)
  744.               continue;
  745.            //Write_Error("nprocessing light %d", curr_light);
  746.            // what kind of light are we dealing with
  747.            if (lights[curr_light].attr & LIGHTV2_ATTR_AMBIENT) ///////////////////////////////
  748.               {
  749.               //Write_Error("nEntering ambient light....");
  750.               // simply multiply each channel against the color of the 
  751.               // polygon then divide by 256 to scale back to 0..255
  752.               // use a shift in real life!!! >> 8
  753.               ri = ((lights[curr_light].c_ambient.r * r_base) / 256);
  754.               gi = ((lights[curr_light].c_ambient.g * g_base) / 256);
  755.               bi = ((lights[curr_light].c_ambient.b * b_base) / 256);
  756.             
  757.               // ambient light has the same affect on each vertex
  758.               r_sum0+=ri;
  759.               g_sum0+=gi;
  760.               b_sum0+=bi;
  761.   
  762.               r_sum1+=ri;
  763.               g_sum1+=gi;
  764.               b_sum1+=bi;
  765.               
  766.               r_sum2+=ri;
  767.               g_sum2+=gi;
  768.               b_sum2+=bi;
  769.               // there better only be one ambient light!
  770.               //Write_Error("nexiting ambient ,sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0,  r_sum1, g_sum1, b_sum1,  r_sum2, g_sum2, b_sum2);
  771.               } // end if
  772.            else
  773.            if (lights[curr_light].attr & LIGHTV2_ATTR_INFINITE) /////////////////////////////////
  774.               {
  775.               //Write_Error("nentering infinite light...");
  776.               // infinite lighting, we need the surface normal, and the direction
  777.               // of the light source
  778.               // no longer need to compute normal or length, we already have the vertex normal
  779.               // and it's length is 1.0  
  780.               // ....
  781.       
  782.               // ok, recalling the lighting model for infinite lights
  783.               // I(d)dir = I0dir * Cldir
  784.               // and for the diffuse model
  785.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  786.               // so we basically need to multiple it all together
  787.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  788.               // are slower, but the conversion to and from cost cycles
  789.               // need to perform lighting for each vertex (lots of redundant math, optimize later!)
  790.               //Write_Error("nv0=[%f, %f, %f]=%f, v1=[%f, %f, %f]=%f, v2=[%f, %f, %f]=%f",
  791.                 // curr_poly->tvlist[0].n.x, curr_poly->tvlist[0].n.y,curr_poly->tvlist[0].n.z, VECTOR4D_Length(&curr_poly->tvlist[0].n),
  792.                 // curr_poly->tvlist[1].n.x, curr_poly->tvlist[1].n.y,curr_poly->tvlist[1].n.z, VECTOR4D_Length(&curr_poly->tvlist[1].n),
  793.                 // curr_poly->tvlist[2].n.x, curr_poly->tvlist[2].n.y,curr_poly->tvlist[2].n.z, VECTOR4D_Length(&curr_poly->tvlist[2].n) );
  794.               // vertex 0
  795.               dp = VECTOR4D_Dot(&curr_poly->tvlist[0].n, &lights[curr_light].tdir); 
  796.               
  797.               // only add light if dp > 0
  798.               if (dp > 0)
  799.                  { 
  800.                  i = 128*dp; 
  801.                  r_sum0+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  802.                  g_sum0+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  803.                  b_sum0+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  804.                  } // end if
  805.               // vertex 1
  806.               dp = VECTOR4D_Dot(&curr_poly->tvlist[1].n, &lights[curr_light].tdir);
  807.               
  808.               // only add light if dp > 0
  809.               if (dp > 0)
  810.                  { 
  811.                  i = 128*dp; 
  812.                  r_sum1+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  813.                  g_sum1+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  814.                  b_sum1+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  815.                  } // end if
  816.               // vertex 2
  817.               dp = VECTOR4D_Dot(&curr_poly->tvlist[2].n, &lights[curr_light].tdir);
  818.               
  819.               // only add light if dp > 0
  820.               if (dp > 0)
  821.                  { 
  822.                  i = 128*dp; 
  823.                  r_sum2+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  824.                  g_sum2+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  825.                  b_sum2+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  826.                  } // end if
  827.               //Write_Error("nexiting infinite, color sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0,  r_sum1, g_sum1, b_sum1,  r_sum2, g_sum2, b_sum2);
  828.               } // end if infinite light
  829.            else
  830.            if (lights[curr_light].attr & LIGHTV2_ATTR_POINT) //////////////////////////////////////
  831.               {
  832.               // perform point light computations
  833.               // light model for point light is once again:
  834.               //              I0point * Clpoint
  835.               //  I(d)point = ___________________
  836.               //              kc +  kl*d + kq*d2              
  837.               //
  838.               //  Where d = |p - s|
  839.               // thus it's almost identical to the infinite light, but attenuates as a function
  840.               // of distance from the point source to the surface point being lit
  841.               // .. normal already in vertex
  842.               //Write_Error("nEntering point light....");
  843.               // compute vector from surface to light
  844.               VECTOR4D_Build(&curr_poly->tvlist[0].v, &lights[curr_light].tpos, &l);
  845.               // compute distance and attenuation
  846.               dist = VECTOR4D_Length_Fast2(&l);  
  847.               // and for the diffuse model
  848.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  849.               // so we basically need to multiple it all together
  850.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  851.               // are slower, but the conversion to and from cost cycles
  852.               // perform the calculation for all 3 vertices
  853.               // vertex 0
  854.               dp = VECTOR4D_Dot(&curr_poly->tvlist[0].n, &l);
  855.               
  856.               // only add light if dp > 0
  857.               if (dp > 0)
  858.                  { 
  859.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  860.                  i = 128*dp / (dist * atten ); 
  861.                  r_sum0 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  862.                  g_sum0 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  863.                  b_sum0 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  864.                  } // end if
  865.               // vertex 1
  866.               dp = VECTOR4D_Dot(&curr_poly->tvlist[1].n, &l);
  867.               
  868.               // only add light if dp > 0
  869.               if (dp > 0)
  870.                  { 
  871.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  872.                  i = 128*dp / (dist * atten ); 
  873.                  r_sum1 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  874.                  g_sum1 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  875.                  b_sum1 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  876.                  } // end if
  877.               // vertex 2
  878.               dp = VECTOR4D_Dot(&curr_poly->tvlist[2].n, &l);
  879.               
  880.               // only add light if dp > 0
  881.               if (dp > 0)
  882.                  { 
  883.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  884.                  i = 128*dp / (dist * atten ); 
  885.                  r_sum2 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  886.                  g_sum2 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  887.                  b_sum2 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  888.                  } // end if
  889.               //Write_Error("nexiting point light, rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0,  r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
  890.               } // end if point
  891.            else
  892.            if (lights[curr_light].attr & LIGHTV2_ATTR_SPOTLIGHT1) ///////////////////////////////////////
  893.               {
  894.               // perform spotlight/point computations simplified model that uses
  895.               // point light WITH a direction to simulate a spotlight
  896.               // light model for point light is once again:
  897.               //              I0point * Clpoint
  898.               //  I(d)point = ___________________
  899.               //              kc +  kl*d + kq*d2              
  900.               //
  901.               //  Where d = |p - s|
  902.               // thus it's almost identical to the infinite light, but attenuates as a function
  903.               // of distance from the point source to the surface point being lit
  904.               //Write_Error("nentering spotlight1....");
  905.               // .. normal is already computed
  906.        
  907.               // compute vector from surface to light
  908.               VECTOR4D_Build(&curr_poly->tvlist[0].v, &lights[curr_light].tpos, &l);
  909.               // compute distance and attenuation
  910.               dist = VECTOR4D_Length_Fast2(&l);  
  911.               // and for the diffuse model
  912.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  913.               // so we basically need to multiple it all together
  914.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  915.               // are slower, but the conversion to and from cost cycles
  916.               // note that I use the direction of the light here rather than a the vector to the light
  917.               // thus we are taking orientation into account which is similar to the spotlight model
  918.               // vertex 0
  919.               dp = VECTOR4D_Dot(&curr_poly->tvlist[0].n, &lights[curr_light].tdir);
  920.               
  921.               // only add light if dp > 0
  922.               if (dp > 0)
  923.                  { 
  924.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  925.                  i = 128*dp / ( atten ); 
  926.                  r_sum0 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  927.                  g_sum0 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  928.                  b_sum0 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  929.                  } // end if
  930.               // vertex 1
  931.               dp = VECTOR4D_Dot(&curr_poly->tvlist[1].n, &lights[curr_light].tdir);
  932.               
  933.               // only add light if dp > 0
  934.               if (dp > 0)
  935.                  { 
  936.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  937.                  i = 128*dp / ( atten ); 
  938.                  r_sum1 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  939.                  g_sum1 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  940.                  b_sum1 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  941.                  } // end i
  942.               // vertex 2
  943.               dp = VECTOR4D_Dot(&curr_poly->tvlist[2].n, &lights[curr_light].tdir);
  944.               
  945.               // only add light if dp > 0
  946.               if (dp > 0)
  947.                  { 
  948.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  949.                  i = 128*dp / ( atten ); 
  950.                  r_sum2 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  951.                  g_sum2 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  952.                  b_sum2 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  953.                  } // end i
  954.               //Write_Error("nexiting spotlight1, sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0,  r_sum1, g_sum1, b_sum1,  r_sum2, g_sum2, b_sum2);
  955.               } // end if spotlight1
  956.            else
  957.            if (lights[curr_light].attr & LIGHTV2_ATTR_SPOTLIGHT2) // simple version //////////////////////////
  958.               {
  959.               // perform spot light computations
  960.               // light model for spot light simple version is once again:
  961.               //               I0spotlight * Clspotlight * MAX( (l . s), 0)^pf                     
  962.               // I(d)spotlight = __________________________________________      
  963.               //                 kc + kl*d + kq*d2        
  964.               // Where d = |p - s|, and pf = power factor
  965.               // thus it's almost identical to the point, but has the extra term in the numerator
  966.               // relating the angle between the light source and the point on the surface
  967.               // .. already have normals and length are 1.0
  968.              
  969.               // and for the diffuse model
  970.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  971.               // so we basically need to multiple it all together
  972.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  973.               // are slower, but the conversion to and from cost cycles
  974.               //Write_Error("nEntering spotlight2...");
  975.               // tons of redundant math here! lots to optimize later!
  976.               
  977.               // vertex 0
  978.               dp = VECTOR4D_Dot(&curr_poly->tvlist[0].n, &lights[curr_light].tdir);
  979.               
  980.               // only add light if dp > 0
  981.               if (dp > 0)
  982.                  { 
  983.                  // compute vector from light to surface (different from l which IS the light dir)
  984.                  VECTOR4D_Build( &lights[curr_light].tpos, &curr_poly->tvlist[0].v, &s);
  985.                  // compute length of s (distance to light source) to normalize s for lighting calc
  986.                  dists = VECTOR4D_Length_Fast2(&s);  
  987.                  // compute spot light term (s . l)
  988.                  float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
  989.                  // proceed only if term is positive
  990.                  if (dpsl > 0) 
  991.                     {
  992.                     // compute attenuation
  993.                     atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);    
  994.        
  995.                     // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
  996.                     // must be integral
  997.                     float dpsl_exp = dpsl;
  998.  
  999.                     // exponentiate for positive integral powers
  1000.                     for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
  1001.                          dpsl_exp*=dpsl;
  1002.                     // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf 
  1003.                                                       
  1004.                     i = 128*dp * dpsl_exp / ( atten ); 
  1005.                     r_sum0 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1006.                     g_sum0 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1007.                     b_sum0 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1008.   
  1009.                     } // end if
  1010.                  } // end if
  1011.               // vertex 1
  1012.               dp = VECTOR4D_Dot(&curr_poly->tvlist[1].n, &lights[curr_light].tdir);
  1013.               
  1014.               // only add light if dp > 0
  1015.               if (dp > 0)
  1016.                  { 
  1017.                  // compute vector from light to surface (different from l which IS the light dir)
  1018.                  VECTOR4D_Build( &lights[curr_light].tpos, &curr_poly->tvlist[1].v, &s);
  1019.                  // compute length of s (distance to light source) to normalize s for lighting calc
  1020.                  dists = VECTOR4D_Length_Fast2(&s);  
  1021.                  // compute spot light term (s . l)
  1022.                  float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
  1023.                  // proceed only if term is positive
  1024.                  if (dpsl > 0) 
  1025.                     {
  1026.                     // compute attenuation
  1027.                     atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);    
  1028.        
  1029.                     // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
  1030.                     // must be integral
  1031.                     float dpsl_exp = dpsl;
  1032.  
  1033.                     // exponentiate for positive integral powers
  1034.                     for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
  1035.                          dpsl_exp*=dpsl;
  1036.                     // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf 
  1037.                                                       
  1038.                     i = 128*dp * dpsl_exp / ( atten ); 
  1039.                     r_sum1 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1040.                     g_sum1 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1041.                     b_sum1 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1042.   
  1043.                     } // end if
  1044.                  } // end if
  1045.               // vertex 2
  1046.               dp = VECTOR4D_Dot(&curr_poly->tvlist[2].n, &lights[curr_light].tdir);
  1047.               
  1048.               // only add light if dp > 0
  1049.               if (dp > 0)
  1050.                  { 
  1051.                  // compute vector from light to surface (different from l which IS the light dir)
  1052.                  VECTOR4D_Build( &lights[curr_light].tpos, &curr_poly->tvlist[2].v, &s);
  1053.                  // compute length of s (distance to light source) to normalize s for lighting calc
  1054.                  dists = VECTOR4D_Length_Fast2(&s);  
  1055.                  // compute spot light term (s . l)
  1056.                  float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
  1057.                  // proceed only if term is positive
  1058.                  if (dpsl > 0) 
  1059.                     {
  1060.                     // compute attenuation
  1061.                     atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);    
  1062.        
  1063.                     // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
  1064.                     // must be integral
  1065.                     float dpsl_exp = dpsl;
  1066.  
  1067.                     // exponentiate for positive integral powers
  1068.                     for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
  1069.                          dpsl_exp*=dpsl;
  1070.                     // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf 
  1071.                                                       
  1072.                     i = 128*dp * dpsl_exp / ( atten ); 
  1073.                     r_sum2 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1074.                     g_sum2 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1075.                     b_sum2 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1076.                     } // end if
  1077.                  } // end if
  1078.               //Write_Error("nexiting spotlight2, sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0,   r_sum1, g_sum1, b_sum1,  r_sum2, g_sum2, b_sum2);
  1079.               } // end if spot light
  1080.            } // end for light
  1081.   
  1082.        // make sure colors aren't out of range
  1083.        if (r_sum0  > 255) r_sum0 = 255;
  1084.        if (g_sum0  > 255) g_sum0 = 255;
  1085.        if (b_sum0  > 255) b_sum0 = 255;
  1086.        if (r_sum1  > 255) r_sum1 = 255;
  1087.        if (g_sum1  > 255) g_sum1 = 255;
  1088.        if (b_sum1  > 255) b_sum1 = 255;
  1089.        if (r_sum2  > 255) r_sum2 = 255;
  1090.        if (g_sum2  > 255) g_sum2 = 255;
  1091.        if (b_sum2  > 255) b_sum2 = 255;
  1092.        //Write_Error("nwriting color for poly %d", poly);
  1093.        //Write_Error("n******** final sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0,  r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
  1094.        // write the colors
  1095.        curr_poly->lit_color[0] = RGB16Bit(r_sum0, g_sum0, b_sum0);
  1096.        curr_poly->lit_color[1] = RGB16Bit(r_sum1, g_sum1, b_sum1);
  1097.        curr_poly->lit_color[2] = RGB16Bit(r_sum2, g_sum2, b_sum2);
  1098.        } // end if
  1099.     else // assume POLY4DV2_ATTR_SHADE_MODE_CONSTANT
  1100.        {
  1101.        // emmisive shading only, do nothing
  1102.        // ...
  1103.        curr_poly->lit_color[0] = curr_poly->color;
  1104.        //Write_Error("nentering constant shader, and exiting...");
  1105.        } // end if
  1106.     } // end for poly
  1107. // return success
  1108. return(1);
  1109. } // end Light_RENDERLIST4DV2_World2_16
  1110. //////////////////////////////////////////////////////////////////////////////
  1111. int Light_RENDERLIST4DV2_World2(RENDERLIST4DV2_PTR rend_list,  // list to process
  1112.                                    CAM4DV1_PTR cam,     // camera position
  1113.                                    LIGHTV2_PTR lights,  // light list (might have more than one)
  1114.                                    int max_lights)      // maximum lights in list
  1115. {
  1116. // {andre work in progress }
  1117. // 8-bit version of function
  1118. // function lights the entire rendering list based on the sent lights and camera. the function supports
  1119. // constant/pure shading (emmisive), flat shading with ambient, infinite, point lights, and spot lights
  1120. // note that this lighting function is rather brute force and simply follows the math, however
  1121. // there are some clever integer operations that are used in scale 256 rather than going to floating
  1122. // point, but why? floating point and ints are the same speed, HOWEVER, the conversion to and from floating
  1123. // point can be cycle intensive, so if you can keep your calcs in ints then you can gain some speed
  1124. // also note, type 1 spot lights are simply point lights with direction, the "cone" is more of a function
  1125. // of the falloff due to attenuation, but they still look like spot lights
  1126. // type 2 spot lights are implemented with the intensity having a dot product relationship with the
  1127. // angle from the surface point to the light direction just like in the optimized model, but the pf term
  1128. // that is used for a concentration control must be 1,2,3,.... integral and non-fractional
  1129. // also note since we are dealing with a rendering list and not object, the final lit color is
  1130. // immediately written over the real color
  1131. unsigned int r_base, g_base,   b_base,  // base color being lit
  1132.              r_sum,  g_sum,    b_sum,   // sum of lighting process over all lights
  1133.              r_sum0,  g_sum0,  b_sum0,
  1134.              r_sum1,  g_sum1,  b_sum1,
  1135.              r_sum2,  g_sum2,  b_sum2,
  1136.              ri,gi,bi,
  1137.              shaded_color;            // final color
  1138. float dp,     // dot product 
  1139.       dist,   // distance from light to surface
  1140.       dists, 
  1141.       i,      // general intensities
  1142.       nl,     // length of normal
  1143.       atten;  // attenuation computations
  1144. VECTOR4D u, v, n, l, d, s; // used for cross product and light vector calculations
  1145. //Write_Error("nEntering lighting function");
  1146. // for each valid poly, light it...
  1147. for (int poly=0; poly < rend_list->num_polys; poly++)
  1148.     {
  1149.     // acquire polygon
  1150.     POLYF4DV2_PTR curr_poly = rend_list->poly_ptrs[poly];
  1151.     // light this polygon if and only if it's not clipped, not culled,
  1152.     // active, and visible
  1153.     if (!(curr_poly->state & POLY4DV2_STATE_ACTIVE) ||
  1154.          (curr_poly->state & POLY4DV2_STATE_CLIPPED ) ||
  1155.          (curr_poly->state & POLY4DV2_STATE_BACKFACE) ||
  1156.          (curr_poly->state & POLY4DV2_STATE_LIT) )
  1157.        continue; // move onto next poly
  1158.     //Write_Error("npoly %d",poly);
  1159. #ifdef DEBUG_ON
  1160. // track rendering stats
  1161.     debug_polys_lit_per_frame++;
  1162. #endif
  1163.     // set state of polygon to lit
  1164.     SET_BIT(curr_poly->state, POLY4DV2_STATE_LIT);
  1165.    
  1166.     // we will use the transformed polygon vertex list since the backface removal
  1167.     // only makes sense at the world coord stage further of the pipeline 
  1168.     // test the lighting mode of the polygon (use flat for flat, gouraud))
  1169.     if (curr_poly->attr & POLY4DV2_ATTR_SHADE_MODE_FLAT)
  1170.        {
  1171.        //Write_Error("nEntering Flat Shader");
  1172.        r_base = palette[curr_poly->color].peRed;
  1173.        g_base = palette[curr_poly->color].peGreen;
  1174.        b_base = palette[curr_poly->color].peBlue;
  1175.        //Write_Error("nBase color=%d,%d,%d", r_base, g_base, b_base);
  1176.        // initialize color sum
  1177.        r_sum  = 0;
  1178.        g_sum  = 0;
  1179.        b_sum  = 0;
  1180.        //Write_Error("nsum color=%d,%d,%d", r_sum, g_sum, b_sum);
  1181.        // new optimization:
  1182.        // when there are multiple lights in the system we will end up performing numerous
  1183.        // redundant calculations to minimize this my strategy is to set key variables to 
  1184.        // to MAX values on each loop, then during the lighting calcs to test the vars for
  1185.        // the max value, if they are the max value then the first light that needs the math
  1186.        // will do it, and then save the information into the variable (causing it to change state
  1187.        // from an invalid number) then any other lights that need the math can use the previously
  1188.        // computed value
  1189.        
  1190.        // set surface normal.z to FLT_MAX to flag it as non-computed
  1191.        n.z = FLT_MAX;
  1192.        // loop thru lights
  1193.        for (int curr_light = 0; curr_light < max_lights; curr_light++)
  1194.            {
  1195.            // is this light active
  1196.            if (lights[curr_light].state==LIGHTV2_STATE_OFF)
  1197.               continue;
  1198.            //Write_Error("nprocessing light %d",curr_light);
  1199.            // what kind of light are we dealing with
  1200.            if (lights[curr_light].attr & LIGHTV2_ATTR_AMBIENT)
  1201.               {
  1202.               //Write_Error("nEntering ambient light...");
  1203.               // simply multiply each channel against the color of the 
  1204.               // polygon then divide by 256 to scale back to 0..255
  1205.               // use a shift in real life!!! >> 8
  1206.               r_sum+= ((lights[curr_light].c_ambient.r * r_base) / 256);
  1207.               g_sum+= ((lights[curr_light].c_ambient.g * g_base) / 256);
  1208.               b_sum+= ((lights[curr_light].c_ambient.b * b_base) / 256);
  1209.               //Write_Error("nambient sum=%d,%d,%d", r_sum, g_sum, b_sum);
  1210.               // there better only be one ambient light!
  1211.               } // end if
  1212.            else
  1213.            if (lights[curr_light].attr & LIGHTV2_ATTR_INFINITE) ///////////////////////////////////////////
  1214.               {
  1215.               //Write_Error("nEntering infinite light...");
  1216.               // infinite lighting, we need the surface normal, and the direction
  1217.               // of the light source
  1218.               // test if we already computed poly normal in previous calculation
  1219.               if (n.z==FLT_MAX)       
  1220.                  {
  1221.                  // we need to compute the normal of this polygon face, and recall
  1222.                  // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  1223.  
  1224.                  // build u, v
  1225.                  VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[1].v, &u);
  1226.                  VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[2].v, &v);
  1227.                  // compute cross product
  1228.                  VECTOR4D_Cross(&u, &v, &n);
  1229.                  } // end if
  1230.               // at this point, we are almost ready, but we have to normalize the normal vector!
  1231.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  1232.               // normals, so this step can be optimized
  1233.               // compute length of normal
  1234.               //nl = VECTOR4D_Length_Fast2(&n);
  1235.               nl = curr_poly->nlength;  
  1236.       
  1237.               // ok, recalling the lighting model for infinite lights
  1238.               // I(d)dir = I0dir * Cldir
  1239.               // and for the diffuse model
  1240.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  1241.               // so we basically need to multiple it all together
  1242.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  1243.               // are slower, but the conversion to and from cost cycles
  1244.               dp = VECTOR4D_Dot(&n, &lights[curr_light].tdir);
  1245.               
  1246.               // only add light if dp > 0
  1247.               if (dp > 0)
  1248.                  { 
  1249.                  i = 128*dp/nl; 
  1250.                  r_sum+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1251.                  g_sum+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1252.                  b_sum+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1253.                  } // end if
  1254.               //Write_Error("ninfinite sum=%d,%d,%d", r_sum, g_sum, b_sum);
  1255.               } // end if infinite light
  1256.            else
  1257.            if (lights[curr_light].attr & LIGHTV2_ATTR_POINT) ///////////////////////////////////////
  1258.               {
  1259.               //Write_Error("nEntering point light...");
  1260.               // perform point light computations
  1261.               // light model for point light is once again:
  1262.               //              I0point * Clpoint
  1263.               //  I(d)point = ___________________
  1264.               //              kc +  kl*d + kq*d2              
  1265.               //
  1266.               //  Where d = |p - s|
  1267.               // thus it's almost identical to the infinite light, but attenuates as a function
  1268.               // of distance from the point source to the surface point being lit
  1269.               // test if we already computed poly normal in previous calculation
  1270.               if (n.z==FLT_MAX)       
  1271.                  {
  1272.                  // we need to compute the normal of this polygon face, and recall
  1273.                  // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  1274.  
  1275.                  // build u, v
  1276.                  VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[1].v, &u);
  1277.                  VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[2].v, &v);
  1278.                  // compute cross product
  1279.                  VECTOR4D_Cross(&u, &v, &n);
  1280.                  } // end if
  1281.               // at this point, we are almost ready, but we have to normalize the normal vector!
  1282.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  1283.               // normals, so this step can be optimized
  1284.               // compute length of normal
  1285.               //nl = VECTOR4D_Length_Fast2(&n);
  1286.               nl = curr_poly->nlength;  
  1287.               // compute vector from surface to light
  1288.               VECTOR4D_Build(&curr_poly->tvlist[0].v, &lights[curr_light].tpos, &l);
  1289.               // compute distance and attenuation
  1290.               dist = VECTOR4D_Length_Fast2(&l);  
  1291.               // and for the diffuse model
  1292.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  1293.               // so we basically need to multiple it all together
  1294.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  1295.               // are slower, but the conversion to and from cost cycles
  1296.               dp = VECTOR4D_Dot(&n, &l);
  1297.               
  1298.               // only add light if dp > 0
  1299.               if (dp > 0)
  1300.                  { 
  1301.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  1302.                  i = 128*dp / (nl * dist * atten ); 
  1303.                  r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1304.                  g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1305.                  b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1306.                  } // end if
  1307.               //Write_Error("npoint sum=%d,%d,%d",r_sum,g_sum,b_sum);
  1308.               } // end if point
  1309.            else
  1310.            if (lights[curr_light].attr & LIGHTV2_ATTR_SPOTLIGHT1) ////////////////////////////////////
  1311.               {
  1312.               //Write_Error("nentering spot light1...");
  1313.               // perform spotlight/point computations simplified model that uses
  1314.               // point light WITH a direction to simulate a spotlight
  1315.               // light model for point light is once again:
  1316.               //              I0point * Clpoint
  1317.               //  I(d)point = ___________________
  1318.               //              kc +  kl*d + kq*d2              
  1319.               //
  1320.               //  Where d = |p - s|
  1321.               // thus it's almost identical to the infinite light, but attenuates as a function
  1322.               // of distance from the point source to the surface point being lit
  1323.               // test if we already computed poly normal in previous calculation
  1324.               if (n.z==FLT_MAX)       
  1325.                  {
  1326.                  // we need to compute the normal of this polygon face, and recall
  1327.                  // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  1328.  
  1329.                  // build u, v
  1330.                  VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[1].v, &u);
  1331.                  VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[2].v, &v);
  1332.                  // compute cross product
  1333.                  VECTOR4D_Cross(&u, &v, &n);
  1334.                  } // end if
  1335.               // at this point, we are almost ready, but we have to normalize the normal vector!
  1336.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  1337.               // normals, so this step can be optimized
  1338.               // compute length of normal
  1339.               //nl = VECTOR4D_Length_Fast2(&n);
  1340.               nl = curr_poly->nlength;  
  1341.        
  1342.               // compute vector from surface to light
  1343.               VECTOR4D_Build(&curr_poly->tvlist[0].v, &lights[curr_light].tpos, &l);
  1344.               // compute distance and attenuation
  1345.               dist = VECTOR4D_Length_Fast2(&l);  
  1346.               // and for the diffuse model
  1347.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  1348.               // so we basically need to multiple it all together
  1349.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  1350.               // are slower, but the conversion to and from cost cycles
  1351.               // note that I use the direction of the light here rather than a the vector to the light
  1352.               // thus we are taking orientation into account which is similar to the spotlight model
  1353.               dp = VECTOR4D_Dot(&n, &lights[curr_light].tdir);
  1354.               
  1355.               // only add light if dp > 0
  1356.               if (dp > 0)
  1357.                  { 
  1358.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  1359.                  i = 128*dp / (nl * atten ); 
  1360.                  r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1361.                  g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1362.                  b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1363.                  } // end if
  1364.               //Write_Error("nspotlight sum=%d,%d,%d",r_sum, g_sum, b_sum);
  1365.               } // end if spotlight1
  1366.            else
  1367.            if (lights[curr_light].attr & LIGHTV2_ATTR_SPOTLIGHT2) // simple version ////////////////////
  1368.               {
  1369.               //Write_Error("nEntering spotlight2 ...");
  1370.  
  1371.               // perform spot light computations
  1372.               // light model for spot light simple version is once again:
  1373.               //               I0spotlight * Clspotlight * MAX( (l . s), 0)^pf                     
  1374.               // I(d)spotlight = __________________________________________      
  1375.               //                 kc + kl*d + kq*d2        
  1376.               // Where d = |p - s|, and pf = power factor
  1377.               // thus it's almost identical to the point, but has the extra term in the numerator
  1378.               // relating the angle between the light source and the point on the surface
  1379.               // test if we already computed poly normal in previous calculation
  1380.               if (n.z==FLT_MAX)       
  1381.                  {
  1382.                  // we need to compute the normal of this polygon face, and recall
  1383.                  // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  1384.  
  1385.                  // build u, v
  1386.                  VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[1].v, &u);
  1387.                  VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[2].v, &v);
  1388.                  // compute cross product
  1389.                  VECTOR4D_Cross(&u, &v, &n);
  1390.                  } // end if
  1391.               // at this point, we are almost ready, but we have to normalize the normal vector!
  1392.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  1393.               // normals, so this step can be optimized
  1394.               // compute length of normal
  1395.               //nl = VECTOR4D_Length_Fast2(&n);
  1396.               nl = curr_poly->nlength;  
  1397.              
  1398.               // and for the diffuse model
  1399.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  1400.               // so we basically need to multiple it all together
  1401.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  1402.               // are slower, but the conversion to and from cost cycles
  1403.               dp = VECTOR4D_Dot(&n, &lights[curr_light].tdir);
  1404.               
  1405.               // only add light if dp > 0
  1406.               if (dp > 0)
  1407.                  { 
  1408.                  // compute vector from light to surface (different from l which IS the light dir)
  1409.                  VECTOR4D_Build( &lights[curr_light].tpos, &curr_poly->tvlist[0].v, &s);
  1410.                  // compute length of s (distance to light source) to normalize s for lighting calc
  1411.                  dists = VECTOR4D_Length_Fast2(&s);  
  1412.                  // compute spot light term (s . l)
  1413.                  float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
  1414.                  // proceed only if term is positive
  1415.                  if (dpsl > 0) 
  1416.                     {
  1417.                     // compute attenuation
  1418.                     atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);    
  1419.        
  1420.                     // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
  1421.                     // must be integral
  1422.                     float dpsl_exp = dpsl;
  1423.  
  1424.                     // exponentiate for positive integral powers
  1425.                     for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
  1426.                          dpsl_exp*=dpsl;
  1427.                     // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf 
  1428.                                                       
  1429.                     i = 128*dp * dpsl_exp / (nl * atten ); 
  1430.                     r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1431.                     g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1432.                     b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1433.   
  1434.                     } // end if
  1435.                  } // end if
  1436.               //Write_Error("nSpotlight sum=%d,%d,%d",r_sum, g_sum, b_sum);
  1437.      
  1438.               } // end if spot light
  1439.            } // end for light
  1440.   
  1441.        // make sure colors aren't out of range
  1442.        if (r_sum  > 255) r_sum = 255;
  1443.        if (g_sum  > 255) g_sum = 255;
  1444.        if (b_sum  > 255) b_sum = 255;
  1445.        //Write_Error("nWriting final values to polygon %d = %d,%d,%d", poly, r_sum, g_sum, b_sum);
  1446.        // write the color over current color       
  1447.        curr_poly->lit_color[0] = rgblookup[RGB16Bit565(r_sum, g_sum, b_sum)];
  1448.        } // end if
  1449.     else
  1450.     if (curr_poly->attr & POLY4DV2_ATTR_SHADE_MODE_GOURAUD) /////////////////////////////////
  1451.        {
  1452.        // gouraud shade, unfortunetly at this point in the pipeline, we have lost the original
  1453.        // mesh, and only have triangles, thus, many triangles will share the same vertices and
  1454.        // they will get lit 2x since we don't have any way to tell this, alas, performing lighting
  1455.        // at the object level is a better idea when gouraud shading is performed since the 
  1456.        // commonality of vertices is still intact, in any case, lighting here is similar to polygon
  1457.        // flat shaded, but we do it 3 times, once for each vertex, additionally there are lots
  1458.        // of opportunities for optimization, but I am going to lay off them for now, so the code
  1459.        // is intelligible, later we will optimize
  1460.        //Write_Error("nEntering gouraud shader...");
  1461.        // step 1: extract the base color out in RGB mode
  1462.        r_base = palette[curr_poly->color].peRed;
  1463.        g_base = palette[curr_poly->color].peGreen;
  1464.        b_base = palette[curr_poly->color].peBlue;
  1465.        //Write_Error("nBase color=%d, %d, %d", r_base, g_base, b_base);
  1466.        // initialize color sum(s) for vertices
  1467.        r_sum0  = 0;
  1468.        g_sum0  = 0;
  1469.        b_sum0  = 0;
  1470.        r_sum1  = 0;
  1471.        g_sum1  = 0;
  1472.        b_sum1  = 0;
  1473.        r_sum2  = 0;
  1474.        g_sum2  = 0;
  1475.        b_sum2  = 0;
  1476.        //Write_Error("nColor sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0,   r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
  1477.        // new optimization:
  1478.        // when there are multiple lights in the system we will end up performing numerous
  1479.        // redundant calculations to minimize this my strategy is to set key variables to 
  1480.        // to MAX values on each loop, then during the lighting calcs to test the vars for
  1481.        // the max value, if they are the max value then the first light that needs the math
  1482.        // will do it, and then save the information into the variable (causing it to change state
  1483.        // from an invalid number) then any other lights that need the math can use the previously
  1484.        // computed value       
  1485.        // loop thru lights
  1486.        for (int curr_light = 0; curr_light < max_lights; curr_light++)
  1487.            {
  1488.            // is this light active
  1489.            if (lights[curr_light].state==LIGHTV2_STATE_OFF)
  1490.               continue;
  1491.            //Write_Error("nprocessing light %d", curr_light);
  1492.            // what kind of light are we dealing with
  1493.            if (lights[curr_light].attr & LIGHTV2_ATTR_AMBIENT) ///////////////////////////////
  1494.               {
  1495.               //Write_Error("nEntering ambient light....");
  1496.               // simply multiply each channel against the color of the 
  1497.               // polygon then divide by 256 to scale back to 0..255
  1498.               // use a shift in real life!!! >> 8
  1499.               ri = ((lights[curr_light].c_ambient.r * r_base) / 256);
  1500.               gi = ((lights[curr_light].c_ambient.g * g_base) / 256);
  1501.               bi = ((lights[curr_light].c_ambient.b * b_base) / 256);
  1502.             
  1503.               // ambient light has the same affect on each vertex
  1504.               r_sum0+=ri;
  1505.               g_sum0+=gi;
  1506.               b_sum0+=bi;
  1507.   
  1508.               r_sum1+=ri;
  1509.               g_sum1+=gi;
  1510.               b_sum1+=bi;
  1511.               
  1512.               r_sum2+=ri;
  1513.               g_sum2+=gi;
  1514.               b_sum2+=bi;
  1515.               // there better only be one ambient light!
  1516.               //Write_Error("nexiting ambient ,sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0,  r_sum1, g_sum1, b_sum1,  r_sum2, g_sum2, b_sum2);
  1517.               } // end if
  1518.            else
  1519.            if (lights[curr_light].attr & LIGHTV2_ATTR_INFINITE) /////////////////////////////////
  1520.               {
  1521.               //Write_Error("nentering infinite light...");
  1522.               // infinite lighting, we need the surface normal, and the direction
  1523.               // of the light source
  1524.               // no longer need to compute normal or length, we already have the vertex normal
  1525.               // and it's length is 1.0  
  1526.               // ....
  1527.       
  1528.               // ok, recalling the lighting model for infinite lights
  1529.               // I(d)dir = I0dir * Cldir
  1530.               // and for the diffuse model
  1531.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  1532.               // so we basically need to multiple it all together
  1533.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  1534.               // are slower, but the conversion to and from cost cycles
  1535.               // need to perform lighting for each vertex (lots of redundant math, optimize later!)
  1536.               //Write_Error("nv0=[%f, %f, %f]=%f, v1=[%f, %f, %f]=%f, v2=[%f, %f, %f]=%f",
  1537.                 // curr_poly->tvlist[0].n.x, curr_poly->tvlist[0].n.y,curr_poly->tvlist[0].n.z, VECTOR4D_Length(&curr_poly->tvlist[0].n),
  1538.                 // curr_poly->tvlist[1].n.x, curr_poly->tvlist[1].n.y,curr_poly->tvlist[1].n.z, VECTOR4D_Length(&curr_poly->tvlist[1].n),
  1539.                 // curr_poly->tvlist[2].n.x, curr_poly->tvlist[2].n.y,curr_poly->tvlist[2].n.z, VECTOR4D_Length(&curr_poly->tvlist[2].n) );
  1540.               // vertex 0
  1541.               dp = VECTOR4D_Dot(&curr_poly->tvlist[0].n, &lights[curr_light].tdir); 
  1542.               
  1543.               // only add light if dp > 0
  1544.               if (dp > 0)
  1545.                  { 
  1546.                  i = 128*dp; 
  1547.                  r_sum0+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1548.                  g_sum0+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1549.                  b_sum0+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1550.                  } // end if
  1551.               // vertex 1
  1552.               dp = VECTOR4D_Dot(&curr_poly->tvlist[1].n, &lights[curr_light].tdir);
  1553.               
  1554.               // only add light if dp > 0
  1555.               if (dp > 0)
  1556.                  { 
  1557.                  i = 128*dp; 
  1558.                  r_sum1+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1559.                  g_sum1+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1560.                  b_sum1+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1561.                  } // end if
  1562.               // vertex 2
  1563.               dp = VECTOR4D_Dot(&curr_poly->tvlist[2].n, &lights[curr_light].tdir);
  1564.               
  1565.               // only add light if dp > 0
  1566.               if (dp > 0)
  1567.                  { 
  1568.                  i = 128*dp; 
  1569.                  r_sum2+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1570.                  g_sum2+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1571.                  b_sum2+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1572.                  } // end if
  1573.               //Write_Error("nexiting infinite, color sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0,  r_sum1, g_sum1, b_sum1,  r_sum2, g_sum2, b_sum2);
  1574.               } // end if infinite light
  1575.            else
  1576.            if (lights[curr_light].attr & LIGHTV2_ATTR_POINT) //////////////////////////////////////
  1577.               {
  1578.               // perform point light computations
  1579.               // light model for point light is once again:
  1580.               //              I0point * Clpoint
  1581.               //  I(d)point = ___________________
  1582.               //              kc +  kl*d + kq*d2              
  1583.               //
  1584.               //  Where d = |p - s|
  1585.               // thus it's almost identical to the infinite light, but attenuates as a function
  1586.               // of distance from the point source to the surface point being lit
  1587.               // .. normal already in vertex
  1588.               //Write_Error("nEntering point light....");
  1589.               // compute vector from surface to light
  1590.               VECTOR4D_Build(&curr_poly->tvlist[0].v, &lights[curr_light].tpos, &l);
  1591.               // compute distance and attenuation
  1592.               dist = VECTOR4D_Length_Fast2(&l);  
  1593.               // and for the diffuse model
  1594.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  1595.               // so we basically need to multiple it all together
  1596.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  1597.               // are slower, but the conversion to and from cost cycles
  1598.               // perform the calculation for all 3 vertices
  1599.               // vertex 0
  1600.               dp = VECTOR4D_Dot(&curr_poly->tvlist[0].n, &l);
  1601.               
  1602.               // only add light if dp > 0
  1603.               if (dp > 0)
  1604.                  { 
  1605.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  1606.                  i = 128*dp / (dist * atten ); 
  1607.                  r_sum0 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1608.                  g_sum0 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1609.                  b_sum0 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1610.                  } // end if
  1611.               // vertex 1
  1612.               dp = VECTOR4D_Dot(&curr_poly->tvlist[1].n, &l);
  1613.               
  1614.               // only add light if dp > 0
  1615.               if (dp > 0)
  1616.                  { 
  1617.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  1618.                  i = 128*dp / (dist * atten ); 
  1619.                  r_sum1 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1620.                  g_sum1 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1621.                  b_sum1 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1622.                  } // end if
  1623.               // vertex 2
  1624.               dp = VECTOR4D_Dot(&curr_poly->tvlist[2].n, &l);
  1625.               
  1626.               // only add light if dp > 0
  1627.               if (dp > 0)
  1628.                  { 
  1629.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  1630.                  i = 128*dp / (dist * atten ); 
  1631.                  r_sum2 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1632.                  g_sum2 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1633.                  b_sum2 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1634.                  } // end if
  1635.               //Write_Error("nexiting point light, rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0,  r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
  1636.               } // end if point
  1637.            else
  1638.            if (lights[curr_light].attr & LIGHTV2_ATTR_SPOTLIGHT1) ///////////////////////////////////////
  1639.               {
  1640.               // perform spotlight/point computations simplified model that uses
  1641.               // point light WITH a direction to simulate a spotlight
  1642.               // light model for point light is once again:
  1643.               //              I0point * Clpoint
  1644.               //  I(d)point = ___________________
  1645.               //              kc +  kl*d + kq*d2              
  1646.               //
  1647.               //  Where d = |p - s|
  1648.               // thus it's almost identical to the infinite light, but attenuates as a function
  1649.               // of distance from the point source to the surface point being lit
  1650.               //Write_Error("nentering spotlight1....");
  1651.               // .. normal is already computed
  1652.        
  1653.               // compute vector from surface to light
  1654.               VECTOR4D_Build(&curr_poly->tvlist[0].v, &lights[curr_light].tpos, &l);
  1655.               // compute distance and attenuation
  1656.               dist = VECTOR4D_Length_Fast2(&l);  
  1657.               // and for the diffuse model
  1658.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  1659.               // so we basically need to multiple it all together
  1660.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  1661.               // are slower, but the conversion to and from cost cycles
  1662.               // note that I use the direction of the light here rather than a the vector to the light
  1663.               // thus we are taking orientation into account which is similar to the spotlight model
  1664.               // vertex 0
  1665.               dp = VECTOR4D_Dot(&curr_poly->tvlist[0].n, &lights[curr_light].tdir);
  1666.               
  1667.               // only add light if dp > 0
  1668.               if (dp > 0)
  1669.                  { 
  1670.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  1671.                  i = 128*dp / ( atten ); 
  1672.                  r_sum0 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1673.                  g_sum0 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1674.                  b_sum0 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1675.                  } // end if
  1676.               // vertex 1
  1677.               dp = VECTOR4D_Dot(&curr_poly->tvlist[1].n, &lights[curr_light].tdir);
  1678.               
  1679.               // only add light if dp > 0
  1680.               if (dp > 0)
  1681.                  { 
  1682.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  1683.                  i = 128*dp / ( atten ); 
  1684.                  r_sum1 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1685.                  g_sum1 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1686.                  b_sum1 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1687.                  } // end i
  1688.               // vertex 2
  1689.               dp = VECTOR4D_Dot(&curr_poly->tvlist[2].n, &lights[curr_light].tdir);
  1690.               
  1691.               // only add light if dp > 0
  1692.               if (dp > 0)
  1693.                  { 
  1694.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  1695.                  i = 128*dp / ( atten ); 
  1696.                  r_sum2 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1697.                  g_sum2 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1698.                  b_sum2 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1699.                  } // end i
  1700.               //Write_Error("nexiting spotlight1, sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0,  r_sum1, g_sum1, b_sum1,  r_sum2, g_sum2, b_sum2);
  1701.               } // end if spotlight1
  1702.            else
  1703.            if (lights[curr_light].attr & LIGHTV2_ATTR_SPOTLIGHT2) // simple version //////////////////////////
  1704.               {
  1705.               // perform spot light computations
  1706.               // light model for spot light simple version is once again:
  1707.               //               I0spotlight * Clspotlight * MAX( (l . s), 0)^pf                     
  1708.               // I(d)spotlight = __________________________________________      
  1709.               //                 kc + kl*d + kq*d2        
  1710.               // Where d = |p - s|, and pf = power factor
  1711.               // thus it's almost identical to the point, but has the extra term in the numerator
  1712.               // relating the angle between the light source and the point on the surface
  1713.               // .. already have normals and length are 1.0
  1714.              
  1715.               // and for the diffuse model
  1716.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  1717.               // so we basically need to multiple it all together
  1718.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  1719.               // are slower, but the conversion to and from cost cycles
  1720.               //Write_Error("nEntering spotlight2...");
  1721.               // tons of redundant math here! lots to optimize later!
  1722.               
  1723.               // vertex 0
  1724.               dp = VECTOR4D_Dot(&curr_poly->tvlist[0].n, &lights[curr_light].tdir);
  1725.               
  1726.               // only add light if dp > 0
  1727.               if (dp > 0)
  1728.                  { 
  1729.                  // compute vector from light to surface (different from l which IS the light dir)
  1730.                  VECTOR4D_Build( &lights[curr_light].tpos, &curr_poly->tvlist[0].v, &s);
  1731.                  // compute length of s (distance to light source) to normalize s for lighting calc
  1732.                  dists = VECTOR4D_Length_Fast2(&s);  
  1733.                  // compute spot light term (s . l)
  1734.                  float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
  1735.                  // proceed only if term is positive
  1736.                  if (dpsl > 0) 
  1737.                     {
  1738.                     // compute attenuation
  1739.                     atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);    
  1740.        
  1741.                     // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
  1742.                     // must be integral
  1743.                     float dpsl_exp = dpsl;
  1744.  
  1745.                     // exponentiate for positive integral powers
  1746.                     for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
  1747.                          dpsl_exp*=dpsl;
  1748.                     // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf 
  1749.                                                       
  1750.                     i = 128*dp * dpsl_exp / ( atten ); 
  1751.                     r_sum0 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1752.                     g_sum0 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1753.                     b_sum0 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1754.   
  1755.                     } // end if
  1756.                  } // end if
  1757.               // vertex 1
  1758.               dp = VECTOR4D_Dot(&curr_poly->tvlist[1].n, &lights[curr_light].tdir);
  1759.               
  1760.               // only add light if dp > 0
  1761.               if (dp > 0)
  1762.                  { 
  1763.                  // compute vector from light to surface (different from l which IS the light dir)
  1764.                  VECTOR4D_Build( &lights[curr_light].tpos, &curr_poly->tvlist[1].v, &s);
  1765.                  // compute length of s (distance to light source) to normalize s for lighting calc
  1766.                  dists = VECTOR4D_Length_Fast2(&s);  
  1767.                  // compute spot light term (s . l)
  1768.                  float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
  1769.                  // proceed only if term is positive
  1770.                  if (dpsl > 0) 
  1771.                     {
  1772.                     // compute attenuation
  1773.                     atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);    
  1774.        
  1775.                     // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
  1776.                     // must be integral
  1777.                     float dpsl_exp = dpsl;
  1778.  
  1779.                     // exponentiate for positive integral powers
  1780.                     for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
  1781.                          dpsl_exp*=dpsl;
  1782.                     // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf 
  1783.                                                       
  1784.                     i = 128*dp * dpsl_exp / ( atten ); 
  1785.                     r_sum1 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1786.                     g_sum1 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1787.                     b_sum1 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1788.   
  1789.                     } // end if
  1790.                  } // end if
  1791.               // vertex 2
  1792.               dp = VECTOR4D_Dot(&curr_poly->tvlist[2].n, &lights[curr_light].tdir);
  1793.               
  1794.               // only add light if dp > 0
  1795.               if (dp > 0)
  1796.                  { 
  1797.                  // compute vector from light to surface (different from l which IS the light dir)
  1798.                  VECTOR4D_Build( &lights[curr_light].tpos, &curr_poly->tvlist[2].v, &s);
  1799.                  // compute length of s (distance to light source) to normalize s for lighting calc
  1800.                  dists = VECTOR4D_Length_Fast2(&s);  
  1801.                  // compute spot light term (s . l)
  1802.                  float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
  1803.                  // proceed only if term is positive
  1804.                  if (dpsl > 0) 
  1805.                     {
  1806.                     // compute attenuation
  1807.                     atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);    
  1808.        
  1809.                     // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
  1810.                     // must be integral
  1811.                     float dpsl_exp = dpsl;
  1812.  
  1813.                     // exponentiate for positive integral powers
  1814.                     for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
  1815.                          dpsl_exp*=dpsl;
  1816.                     // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf 
  1817.                                                       
  1818.                     i = 128*dp * dpsl_exp / ( atten ); 
  1819.                     r_sum2 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1820.                     g_sum2 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1821.                     b_sum2 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1822.                     } // end if
  1823.                  } // end if
  1824.               //Write_Error("nexiting spotlight2, sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0,   r_sum1, g_sum1, b_sum1,  r_sum2, g_sum2, b_sum2);
  1825.               } // end if spot light
  1826.            } // end for light
  1827.   
  1828.        // make sure colors aren't out of range
  1829.        if (r_sum0  > 255) r_sum0 = 255;
  1830.        if (g_sum0  > 255) g_sum0 = 255;
  1831.        if (b_sum0  > 255) b_sum0 = 255;
  1832.        if (r_sum1  > 255) r_sum1 = 255;
  1833.        if (g_sum1  > 255) g_sum1 = 255;
  1834.        if (b_sum1  > 255) b_sum1 = 255;
  1835.        if (r_sum2  > 255) r_sum2 = 255;
  1836.        if (g_sum2  > 255) g_sum2 = 255;
  1837.        if (b_sum2  > 255) b_sum2 = 255;
  1838.        //Write_Error("nwriting color for poly %d", poly);
  1839.        //Write_Error("n******** final sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0,  r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
  1840.        // write all colors in RGB form since we need to interpolate at the rasterizer
  1841.        curr_poly->lit_color[0] = RGB16Bit(r_sum0, g_sum0, b_sum0);
  1842.        curr_poly->lit_color[1] = RGB16Bit(r_sum1, g_sum1, b_sum1);
  1843.        curr_poly->lit_color[2] = RGB16Bit(r_sum2, g_sum2, b_sum2);
  1844.        } // end if
  1845.     else // assume POLY4DV2_ATTR_SHADE_MODE_CONSTANT
  1846.        {
  1847.        // emmisive shading only, do nothing
  1848.        // ...
  1849.        curr_poly->lit_color[0] = curr_poly->color;
  1850.        //Write_Error("nentering constant shader, and exiting...");
  1851.        } // end if
  1852.     } // end for poly
  1853. // return success
  1854. return(1);
  1855. } // end Light_RENDERLIST4DV2_World2
  1856. //////////////////////////////////////////////////////////////////////////////////////
  1857. void Transform_LIGHTSV2(LIGHTV2_PTR lights,  // array of lights to transform
  1858.                         int num_lights,      // number of lights to transform
  1859.                         MATRIX4X4_PTR mt,    // transformation matrix
  1860.                         int coord_select)    // selects coords to transform
  1861. {
  1862. // this function simply transforms all of the lights by the transformation matrix
  1863. // this function is used to place the lights in camera space for example, so that
  1864. // lighting calculations are correct if the lighting function is called AFTER
  1865. // the polygons have already been trasformed to camera coordinates
  1866. // also, later we may decided to optimize this a little by determining
  1867. // the light type and only rotating what is needed, however there are thousands
  1868. // of vertices in a scene and not rotating 10 more points isn't going to make 
  1869. // a difference
  1870. // NOTE: This function MUST be called even if a transform to the lights 
  1871. // is not desired, that is, you are lighting in world coords, in this case
  1872. // the local light positions and orientations MUST still be copied into the 
  1873. // working variables for the lighting engine to use pos->tpos, dir->tdir
  1874. // hence, call this function with TRANSFORM_COPY_LOCAL_TO_TRANS 
  1875. // with a matrix of NULL
  1876. int curr_light; // current light in loop
  1877. MATRIX4X4 mr;   // used to build up rotation aspect of matrix only
  1878. // we need to rotate the direction vectors of the lights also, but
  1879. // the translation factors must be zeroed out in the matrix otherwise
  1880. // the results will be incorrect, thus make a copy of the matrix and zero
  1881. // the translation factors
  1882. if (mt!=NULL)
  1883.    {
  1884.    MAT_COPY_4X4(mt, &mr);
  1885.    // zero translation factors
  1886.    mr.M30 = mr.M31 = mr.M32 = 0;
  1887.    } // end if
  1888. // what coordinates should be transformed?
  1889. switch(coord_select)
  1890.       {
  1891.       case TRANSFORM_COPY_LOCAL_TO_TRANS:
  1892.            {
  1893.            // loop thru all the lights
  1894.            for (curr_light = 0; curr_light < num_lights; curr_light++)
  1895.            {  
  1896.            lights[curr_light].tpos = lights[curr_light].pos;
  1897.            lights[curr_light].tdir = lights[curr_light].dir;
  1898.            } // end for
  1899.            } break;
  1900.       case TRANSFORM_LOCAL_ONLY:
  1901.            {
  1902.            // loop thru all the lights
  1903.            for (curr_light = 0; curr_light < num_lights; curr_light++)
  1904.            {   
  1905.            // transform the local/world light coordinates in place
  1906.            POINT4D presult; // hold result of each transformation
  1907.            // transform point position of each light
  1908.            Mat_Mul_VECTOR4D_4X4(&lights[curr_light].pos, mt, &presult);
  1909.            // store result back
  1910.            VECTOR4D_COPY(&lights[curr_light].pos, &presult); 
  1911.            // transform direction vector 
  1912.            Mat_Mul_VECTOR4D_4X4(&lights[curr_light].dir, &mr, &presult);
  1913.            // store result back
  1914.            VECTOR4D_COPY(&lights[curr_light].dir, &presult); 
  1915.            } // end for
  1916.            } break;
  1917.  
  1918.       case TRANSFORM_TRANS_ONLY:
  1919.            {
  1920.            // loop thru all the lights
  1921.            for (curr_light = 0; curr_light < num_lights; curr_light++)
  1922.                { 
  1923.                // transform each "transformed" light
  1924.                POINT4D presult; // hold result of each transformation
  1925.                // transform point position of each light
  1926.                Mat_Mul_VECTOR4D_4X4(&lights[curr_light].tpos, mt, &presult);
  1927.                // store result back
  1928.                VECTOR4D_COPY(&lights[curr_light].tpos, &presult); 
  1929.                // transform direction vector 
  1930.                Mat_Mul_VECTOR4D_4X4(&lights[curr_light].tdir, &mr, &presult);
  1931.                // store result back
  1932.                VECTOR4D_COPY(&lights[curr_light].tdir, &presult); 
  1933.                } // end for
  1934.              } break;
  1935.       case TRANSFORM_LOCAL_TO_TRANS:
  1936.            {
  1937.            // loop thru all the lights
  1938.            for (curr_light = 0; curr_light < num_lights; curr_light++)
  1939.            { 
  1940.            // transform each local/world light and place the results into the transformed
  1941.            // storage, this is the usual way the function will be called
  1942.            POINT4D presult; // hold result of each transformation
  1943.            // transform point position of each light
  1944.            Mat_Mul_VECTOR4D_4X4(&lights[curr_light].pos, mt, &lights[curr_light].tpos);
  1945.            // transform direction vector 
  1946.            Mat_Mul_VECTOR4D_4X4(&lights[curr_light].dir, &mr, &lights[curr_light].tdir);
  1947.            } // end for
  1948.            } break;
  1949.       default: break;
  1950.       } // end switch
  1951. } // end Transform_LIGHTSV2