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

游戏

开发平台:

Visual C++

  1.                // file name: string "D:Sourcemodelstextureswall01.bmp"
  2.           
  3.                // of course the filename in the quotes will change
  4.                // so lets hunt until we find it...
  5.                while(1)
  6.                     {
  7.                     // get the next line
  8.                     if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  9.                        {
  10.                        Write_Error("ncouldnt find texture name! in .COB file %s.", filename);
  11.                        return(0);
  12.                        } // end if
  13.                     // replace the " with spaces
  14.                     ReplaceChars(parser.buffer, parser.buffer, """, ' ', 1);
  15.                     // is this the file name?
  16.                     if (parser.Pattern_Match(parser.buffer, "['file'] ['name:'] ['string'] [s>0]") )
  17.                        {
  18.                        // ok, simply convert to a real file name by changing the slashes
  19.                        ReplaceChars(parser.pstrings[3], parser.pstrings[3], "\", '/',1);
  20.                        // and save the filename
  21.                        strcpy(materials[material_index + num_materials].texture_file, parser.pstrings[3]);
  22.                        break;
  23.                        } // end if
  24.                     } // end while
  25.                 break;
  26.                 } // end if
  27.             } // end while 
  28.        // alright, finally! Now we need to know what the actual shader type, now in the COB format
  29.        // I have decided that in the "reflectance" class that's where we will look at what kind
  30.        // of shader is supposed to be used on the polygon
  31.        //  look for the "Shader class: reflectance"
  32.        while(1)
  33.             {
  34.             // get the next line
  35.             if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  36.                {
  37.                Write_Error("nshader reflectance class not found in .COB file %s.", filename);
  38.                return(0);
  39.                } // end if
  40.             // look for "Shader class: reflectance"
  41.             if (parser.Pattern_Match(parser.buffer, "['Shader'] ['class:'] ['reflectance']") )
  42.                {
  43.                // now we know the next "shader name" is what we are looking for so, break
  44.                break;
  45.                } // end if
  46.              } // end while    
  47.         // looking for "Shader name: "xxxxxx" (xxxxxx) " again, 
  48.         // and based on it's value we map it to our shading system as follows:
  49.         // "constant" -> MATV1_ATTR_SHADE_MODE_CONSTANT 
  50.         // "matte"    -> MATV1_ATTR_SHADE_MODE_FLAT
  51.         // "plastic"  -> MATV1_ATTR_SHADE_MODE_GOURAUD
  52.         // "phong"    -> MATV1_ATTR_SHADE_MODE_FASTPHONG 
  53.         // and in the case that in the "color" class, we found a "texture map" then the "shading mode" is
  54.         // "texture map" -> MATV1_ATTR_SHADE_MODE_TEXTURE 
  55.         // which must be logically or'ed with the other previous modes
  56.         while(1)
  57.              {
  58.              // get the next line
  59.              if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  60.                 {
  61.                 Write_Error("nshader name ended abruptly! in .COB file %s.", filename);
  62.                 return(0);
  63.                 } // end if
  64.          
  65.              // get rid of those quotes
  66.              ReplaceChars(parser.buffer, parser.buffer, """,' ',1);
  67.              // did we find the name?
  68.             if (parser.Pattern_Match(parser.buffer, "['Shader'] ['name:'] [s>0]" ) )
  69.                {
  70.                // figure out which shader to use
  71.                if (strcmp(parser.pstrings[2], "constant") == 0)
  72.                   {
  73.                   // set the shading mode flag in material
  74.                   SET_BIT(materials[material_index + num_materials].attr, MATV1_ATTR_SHADE_MODE_CONSTANT);
  75.                   } // end if
  76.                else
  77.                if (strcmp(parser.pstrings[2], "matte") == 0)
  78.                   {
  79.                   // set the shading mode flag in material
  80.                   SET_BIT(materials[material_index + num_materials].attr, MATV1_ATTR_SHADE_MODE_FLAT);
  81.                   } // end if
  82.                else
  83.                if (strcmp(parser.pstrings[2], "plastic") == 0)
  84.                   {
  85.                   // set the shading mode flag in material
  86.                   SET_BIT(materials[curr_material + num_materials].attr, MATV1_ATTR_SHADE_MODE_GOURAUD);
  87.                   } // end if
  88.                else
  89.                if (strcmp(parser.pstrings[2], "phong") == 0)
  90.                   {
  91.                   // set the shading mode flag in material
  92.                   SET_BIT(materials[material_index + num_materials].attr, MATV1_ATTR_SHADE_MODE_FASTPHONG);
  93.                   } // end if
  94.                else
  95.                   {
  96.                   // set the shading mode flag in material
  97.                   SET_BIT(materials[material_index + num_materials].attr, MATV1_ATTR_SHADE_MODE_FLAT);
  98.                   } // end else
  99.             break;
  100.             } // end if
  101.          } // end while
  102.           
  103.        // found the material, break out of while for another pass
  104.        break;
  105.        } // end if found material
  106.     } // end while looking for mat#1
  107.     } // end for curr_material
  108. // at this point poly_material[] holds all the indices for the polygon materials (zero based, so they need fix up)
  109. // and we must access the materials array to fill in each polygon with the polygon color, etc.
  110. // now that we finally have the material libary loaded
  111. for (int curr_poly = 0; curr_poly < obj->num_polys; curr_poly++)
  112.     {
  113.     Write_Error("nfixing poly material %d from index %d to index %d", curr_poly, 
  114.                                                                        poly_material[curr_poly],
  115.                                                                        poly_material[curr_poly] + num_materials  );
  116.     // fix up offset
  117.     poly_material[curr_poly]  = poly_material[curr_poly] + num_materials;
  118.     // we need to know what color depth we are dealing with, so check
  119.     // the bits per pixel, this assumes that the system has already
  120.     // made the call to DDraw_Init() or set the bit depth
  121.     if (screen_bpp == 16)
  122.        {
  123.        // cool, 16 bit mode
  124.        SET_BIT(obj->plist[curr_poly].attr,POLY4DV1_ATTR_RGB16);
  125.        obj->plist[curr_poly].color = RGB16Bit(materials[ poly_material[curr_poly] ].color.r, 
  126.                                               materials[ poly_material[curr_poly] ].color.g, 
  127.                                               materials[ poly_material[curr_poly] ].color.b);
  128.        Write_Error("nPolygon 16-bit");
  129.        } // end
  130.     else
  131.        {
  132.        // 8 bit mode
  133.        SET_BIT(obj->plist[curr_poly].attr,POLY4DV1_ATTR_8BITCOLOR);
  134.        obj->plist[curr_poly].color = RGBto8BitIndex(materials[ poly_material[curr_poly] ].color.r,
  135.                                                     materials[ poly_material[curr_poly] ].color.g,
  136.                                                     materials[ poly_material[curr_poly] ].color.b,
  137.                                                     palette, 0);
  138.        Write_Error("nPolygon 8-bit, index=%d", obj->plist[curr_poly].color);
  139.        } // end else
  140.      // now set all the shading flags
  141.      // figure out which shader to use
  142.      if (materials[ poly_material[curr_poly] ].attr & MATV1_ATTR_SHADE_MODE_CONSTANT)
  143.         {
  144.         // set shading mode
  145.         SET_BIT(obj->plist[curr_poly].attr, POLY4DV1_ATTR_SHADE_MODE_CONSTANT);
  146.         } // end if
  147.      else
  148.      if (materials[ poly_material[curr_poly] ].attr & MATV1_ATTR_SHADE_MODE_FLAT)
  149.         {
  150.         // set shading mode
  151.         SET_BIT(obj->plist[curr_poly].attr, POLY4DV1_ATTR_SHADE_MODE_FLAT);
  152.         } // end if
  153.      else
  154.      if (materials[ poly_material[curr_poly] ].attr & MATV1_ATTR_SHADE_MODE_GOURAUD)
  155.         {
  156.         // set shading mode
  157.         SET_BIT(obj->plist[curr_poly].attr, POLY4DV1_ATTR_SHADE_MODE_GOURAUD);
  158.         } // end if
  159.      else
  160.      if (materials[ poly_material[curr_poly] ].attr & MATV1_ATTR_SHADE_MODE_FASTPHONG)
  161.         {
  162.         // set shading mode
  163.         SET_BIT(obj->plist[curr_poly].attr, POLY4DV1_ATTR_SHADE_MODE_FASTPHONG);
  164.         } // end if
  165.      else
  166.         {
  167.         // set shading mode
  168.         SET_BIT(obj->plist[curr_poly].attr, POLY4DV1_ATTR_SHADE_MODE_GOURAUD);
  169.         } // end if
  170.      if (materials[ poly_material[curr_poly] ].attr & MATV1_ATTR_SHADE_MODE_TEXTURE)
  171.         {
  172.         // set shading mode
  173.         SET_BIT(obj->plist[curr_poly].attr, POLY4DV1_ATTR_SHADE_MODE_TEXTURE);
  174.         } // end if
  175.     } // end for curr_poly
  176. // local object materials have been added to database, update total materials in system
  177. num_materials+=num_materials_object;
  178. #ifdef DEBUG_ON
  179. for (curr_material = 0; curr_material < num_materials; curr_material++)
  180.     {
  181.     Write_Error("nMaterial %d", curr_material);
  182.     Write_Error("nint  state    = %d", materials[curr_material].state);
  183.     Write_Error("nint  id       = %d", materials[curr_material].id);
  184.     Write_Error("nchar name[64] = %s", materials[curr_material].name);
  185.     Write_Error("nint  attr     = %d", materials[curr_material].attr); 
  186.     Write_Error("nint r         = %d", materials[curr_material].color.r); 
  187.     Write_Error("nint g         = %d", materials[curr_material].color.g); 
  188.     Write_Error("nint b         = %d", materials[curr_material].color.b); 
  189.     Write_Error("nint alpha     = %d", materials[curr_material].color.a);
  190.     Write_Error("nint color     = %d", materials[curr_material].attr); 
  191.     Write_Error("nfloat ka      = %f", materials[curr_material].ka); 
  192.     Write_Error("nkd            = %f", materials[curr_material].kd); 
  193.     Write_Error("nks            = %f", materials[curr_material].ks); 
  194.     Write_Error("npower         = %f", materials[curr_material].power);
  195.     Write_Error("nchar texture_file = %sn", materials[curr_material].texture_file);
  196.     } // end for curr_material
  197. #endif
  198. // return success
  199. return(1);
  200. } // end Load_OBJECT4DV1_COB
  201. ///////////////////////////////////////////////////////////////////////////////
  202. int RGBto8BitIndex(UCHAR r, UCHAR g, UCHAR b, LPPALETTEENTRY palette, int flush_cache=0)
  203. {
  204. // this function hunts thru the loaded 8-bit palette and tries to find the 
  205. // best match to the sent rgb color, the 8-bit index is returned. The algorithm
  206. // performings a least squares match on the values in the CLUT, also to speed up
  207. // the process, the last few translated colored are stored in a stack in the format
  208. // rgbi, so when a new rgb comes in, it is compared against the rgb entries in the
  209. // table, if found then that index is used, else, the rgb is translated and added to
  210. // the table, and the table is shifted one slot, so the last element is thrown away,
  211. // hence the table is FIFO in as much as the first discarded value will be the first
  212. // this way the system keeps previously translated colors cached, so the fairly long
  213. // least squared scan doesn't take forever!
  214. // also note the compression of the RGBI data, a compare is performed on the upper 24 bits only
  215. // also, if flush_cache = 1 then the local cache is flushed, for example a new palette is loaded
  216. #define COLOR_CACHE_SIZE 16 // 16 entries should do for now
  217. typedef struct 
  218.         { 
  219.         UCHAR r,g,b;    // the rgb value of this translated color
  220.         UCHAR index;    // the color index that matched is most closely
  221.         } RGBINDEX, *RGBINDEX_PTR;
  222. static RGBINDEX color_cache[COLOR_CACHE_SIZE];  // the color cache
  223. static int cache_entries=0;                     // number of entries in the cache
  224. // test for flush cache command, new palette coming in...
  225. if (flush_cache==1)
  226.    cache_entries = 0;
  227. // test if the color is in the cache
  228. for (int cache_index=0; cache_index < cache_entries; cache_index++)
  229.     {
  230.     // is this a match?
  231.     if (r==color_cache[cache_index].r &&
  232.         g==color_cache[cache_index].g &&
  233.         b==color_cache[cache_index].b )
  234.        return(color_cache[cache_index].index);
  235.     } // end for
  236. // if we get here then we had no luck, so least sqaures scan for best match
  237. // and make sure to add results to cache
  238. int  curr_index  = -1;        // current color index of best match
  239. long curr_error = INT_MAX;    // distance in color space to nearest match or "error"
  240. for (int color_index = 0; color_index < 256; color_index++)
  241.     {
  242.     // compute distance to color from target
  243.     long delta_red   = abs(palette[color_index].peRed   - r);
  244.     long delta_green = abs(palette[color_index].peGreen - g);
  245.     long delta_blue  = abs(palette[color_index].peBlue  - b);
  246.  
  247.     long error = (delta_red*delta_red) + (delta_green*delta_green) + (delta_blue*delta_blue);
  248.    
  249.     // is this color a better match?
  250.     if (error < curr_error)
  251.        { 
  252.        curr_index = color_index;
  253.        curr_error = error;   
  254.        } // end if
  255.     } // end for color_index
  256.   
  257. // at this point we have the new color, insert it into cache
  258. // shift cache over one entry, copy elements [0 - (n-1)] -> [1 - n]
  259. memmove((void *)&color_cache[1], (void *)&color_cache[0],  COLOR_CACHE_SIZE*sizeof(RGBINDEX) - sizeof(RGBINDEX) );
  260. // now insert the new element
  261. color_cache[0].r     = r;
  262. color_cache[0].b     = b;
  263. color_cache[0].g     = g;
  264. color_cache[0].index = curr_index; 
  265. // increment number of elements in the cache until saturation
  266. if (++cache_entries > COLOR_CACHE_SIZE)
  267.    cache_entries = COLOR_CACHE_SIZE;
  268. // return results
  269. return(curr_index);
  270. } // end RGBto8BitIndex
  271.       
  272. //////////////////////////////////////////////////////////////////////////////
  273. int Init_Light_LIGHTV1(int           index,      // index of light to create (0..MAX_LIGHTS-1)
  274.                        int          _state,      // state of light
  275.                        int          _attr,       // type of light, and extra qualifiers
  276.                        RGBAV1       _c_ambient,  // ambient light intensity
  277.                        RGBAV1       _c_diffuse,  // diffuse light intensity
  278.                        RGBAV1       _c_specular, // specular light intensity
  279.                        POINT4D_PTR  _pos,        // position of light
  280.                        VECTOR4D_PTR _dir,        // direction of light
  281.                        float        _kc,         // attenuation factors
  282.                        float        _kl, 
  283.                        float        _kq,  
  284.                        float        _spot_inner, // inner angle for spot light
  285.                        float        _spot_outer, // outer angle for spot light
  286.                        float        _pf)         // power factor/falloff for spot lights
  287. {
  288. // this function initializes a light based on the flags sent in _attr, values that
  289. // aren't needed are set to 0 by caller
  290. // make sure light is in range 
  291. if (index < 0 || index >= MAX_LIGHTS)
  292.     return(0);
  293. // all good, initialize the light (many fields may be dead)
  294. lights[index].state       = _state;      // state of light
  295. lights[index].id          = index;       // id of light
  296. lights[index].attr        = _attr;       // type of light, and extra qualifiers
  297. lights[index].c_ambient   = _c_ambient;  // ambient light intensity
  298. lights[index].c_diffuse   = _c_diffuse;  // diffuse light intensity
  299. lights[index].c_specular  = _c_specular; // specular light intensity
  300. lights[index].kc          = _kc;         // constant, linear, and quadratic attenuation factors
  301. lights[index].kl          = _kl;   
  302. lights[index].kq          = _kq;   
  303. if (_pos)
  304.    VECTOR4D_COPY(&lights[index].pos, _pos);  // position of light
  305.    
  306. if (_dir)
  307.    {
  308.    VECTOR4D_COPY(&lights[index].dir, _dir);  // direction of light
  309.    // normalize it
  310.    VECTOR4D_Normalize(&lights[index].dir);
  311.    } // end if
  312. lights[index].spot_inner  = _spot_inner; // inner angle for spot light
  313. lights[index].spot_outer  = _spot_outer; // outer angle for spot light
  314. lights[index].pf          = _pf;         // power factor/falloff for spot lights
  315. // return light index as success
  316. return(index);
  317. } // end Create_Light_LIGHTV1
  318. //////////////////////////////////////////////////////////////////////////////
  319. int Reset_Lights_LIGHTV1(void)
  320. {
  321. // this function simply resets all lights in the system
  322. static int first_time = 1;
  323. memset(lights, 0, MAX_LIGHTS*sizeof(LIGHTV1));
  324. // reset number of lights
  325. num_lights = 0;
  326. // reset first time
  327. first_time = 0;
  328. // return success
  329. return(1);
  330. } // end Reset_Lights_LIGHTV1
  331. //////////////////////////////////////////////////////////////////////////////
  332. int Reset_Materials_MATV1(void)
  333. {
  334. // this function resets all the materials
  335. static int first_time = 1;
  336. // if this is the first time then zero EVERYTHING out
  337. if (first_time)
  338.    {
  339.    memset(materials, 0, MAX_MATERIALS*sizeof(MATV1));
  340.    first_time = 0;
  341.    } // end if
  342. // scan thru materials and release all textures, if any?
  343. for (int curr_matt = 0; curr_matt < MAX_MATERIALS; curr_matt++)
  344.     {
  345.     // regardless if the material is active check to see if there is a 
  346.     // dangling texture map
  347.     Destroy_Bitmap(&materials[curr_matt].texture);
  348.     
  349.     // now it's safe to zero memory out
  350.     memset(&materials[curr_matt], 0, sizeof(MATV1));
  351.     } // end if
  352. return(1);
  353. } // end Reset_Materials_MATV1
  354. //////////////////////////////////////////////////////////////////////////////
  355. int RGB_16_8_IndexedRGB_Table_Builder(int rgb_format,             // format we want to build table for
  356.                                                                   // 99/100 565
  357.                                       LPPALETTEENTRY src_palette, // source palette
  358.                                       UCHAR *rgblookup)           // lookup table
  359. {
  360. // this function takes as input the rgb format that it should generate the lookup table
  361. // for;  dd_pixel_format = DD_PIXEL_FORMAT565, or DD_PIXEL_FORMAT555
  362. // notice in 5.5.5 format the input has only 32K possible colors and the high most
  363. // bit will be disregarded, thus the look up table will only need to be 32K
  364. // in either case, it's up to the caller to send in the rgblookup table pre-allocated
  365. // the function doesn't allocate memory for the caller
  366. // the function uses a simple least squares scan for all possible RGB colors in the
  367. // 16-bit color space that map to the discrete RGB space in the 8-bit palette 
  368. // first check the pointers
  369. if (!src_palette || !rgblookup)
  370.    return(-1);
  371. // what is the color depth we are building a table for?
  372. if (rgb_format==DD_PIXEL_FORMAT565)
  373.    {
  374.    // there are a total of 64k entries, perform a loop and look them up, do the least 
  375.    // amount of work, even with a pentium, there are 65536*256 interations here!
  376.    for (int rgbindex = 0; rgbindex < 65536; rgbindex++)
  377.        {
  378.        int  curr_index  = -1;        // current color index of best match
  379.        long curr_error  = INT_MAX;    // distance in color space to nearest match or "error"
  380.        for (int color_index = 0; color_index < 256; color_index++)
  381.            {
  382.            // extract r,g,b from rgbindex, assuming an encoding of 5.6.5, then scale to 8.8.8 since 
  383.            // palette is in that format always
  384.            int r = (rgbindex >> 11) << 3;;
  385.            int g = ((rgbindex >> 5) & 0x3f) << 2;
  386.            int b = (rgbindex & 0x1f) << 3;
  387.            // compute distance to color from target
  388.            long delta_red   = abs(src_palette[color_index].peRed   - r);
  389.            long delta_green = abs(src_palette[color_index].peGreen - g);
  390.            long delta_blue  = abs(src_palette[color_index].peBlue  - b);
  391.            long error = (delta_red*delta_red) + (delta_green*delta_green) + (delta_blue*delta_blue);
  392.    
  393.            // is this color a better match?
  394.            if (error < curr_error)
  395.               { 
  396.               curr_index = color_index;
  397.               curr_error = error;   
  398.               } // end if
  399.           } // end for color_index
  400.        // best match has been found, enter it into table
  401.        rgblookup[rgbindex] = curr_index;             
  402.        } // end for rgbindex
  403.    } // end if
  404. else 
  405. if (rgb_format==DD_PIXEL_FORMAT555)
  406.    {
  407.    // there are a total of 32k entries, perform a loop and look them up, do the least 
  408.    // amount of work, even with a pentium, there are 32768*256 interations here!
  409.    for (int rgbindex = 0; rgbindex < 32768; rgbindex++)
  410.        {
  411.        int  curr_index  = -1;        // current color index of best match
  412.        long curr_error  = INT_MAX;    // distance in color space to nearest match or "error"
  413.        for (int color_index = 0; color_index < 256; color_index++)
  414.            {
  415.            // extract r,g,b from rgbindex, assuming an encoding of 5.6.5, then scale to 8.8.8 since 
  416.            // palette is in that format always
  417.            int r =  (rgbindex >> 10) << 3;;
  418.            int g = ((rgbindex >> 5) & 0x1f) << 3;
  419.            int b =  (rgbindex & 0x1f) << 3;
  420.            // compute distance to color from target
  421.            long delta_red   = abs(src_palette[color_index].peRed   - r);
  422.            long delta_green = abs(src_palette[color_index].peGreen - g);
  423.            long delta_blue  = abs(src_palette[color_index].peBlue  - b);
  424.            long error = (delta_red*delta_red) + (delta_green*delta_green) + (delta_blue*delta_blue);
  425.    
  426.            // is this color a better match?
  427.            if (error < curr_error)
  428.               { 
  429.               curr_index = color_index;
  430.               curr_error = error;   
  431.               } // end if
  432.           } // end for color_index
  433.        // best match has been found, enter it into table
  434.        rgblookup[rgbindex] = curr_index;             
  435.        } // end for rgbindex
  436.  
  437.    } // end if
  438. else
  439.     return(-1); // serious problem! unsupported format, what are you doing to me!!!!
  440. // return success
  441. return(1);
  442. } // end RGB_16_8_IndexedRGB_Table_Builder
  443. //////////////////////////////////////////////////////////////////////////////
  444. int RGB_16_8_Indexed_Intensity_Table_Builder(LPPALETTEENTRY src_palette,  // source palette
  445.                                              UCHAR rgbilookup[256][256],  // lookup table
  446.                                              int intensity_normalization)
  447. {
  448. // this function takes the source palette to compute the intensity shading table with
  449. // the table will be formatted such that each row is a color index, and each column
  450. // is the shade 0..255 desired, the output is a single byte index
  451. // in either case, it's up to the caller to send in the rgbilookup table pre-allocated
  452. // 64k buffer byte [256][256]the function doesn't allocate memory for the caller
  453. // the function builds the table by looping thru each color in the color palette and then
  454. // for each color, it scales the color to maximum intensity without overflow the RGB channels
  455. // and then uses this as the 100% intensity value of the color, then the algorithm computes
  456. // the 256 shades of the color, and then uses the standard least squares scan the find the 
  457. // colors in the palette and stores them in the row of the current color under intensity 
  458. // translation, sounds diabolical huh? Note: if you set intensity normalization to 0
  459. // the the maximization step isn't performed.
  460. int ri,gi,bi;        // initial color 
  461. int rw,gw,bw;        // current working color
  462. float ratio;         // scaling ratio
  463. float dl,dr,db,dg;   // intensity gradients for 256 shades
  464. // first check the pointers
  465. if (!src_palette || !rgbilookup)
  466.    return(-1);
  467. // for each color in the palette, compute maximum intensity value then scan
  468. // for 256 shades of it
  469. for (int col_index = 0; col_index < 256; col_index++)
  470. {
  471. // extract color from palette
  472. ri = src_palette[col_index].peRed;
  473. gi = src_palette[col_index].peGreen;
  474. bi = src_palette[col_index].peBlue;
  475. // find largest channel then max it out and scale other
  476. // channels based on ratio
  477. if (intensity_normalization==1)
  478. {
  479. // red largest?
  480. if (ri >= gi && ri >= bi)
  481.    {
  482.    // compute scaling ratio
  483.    ratio = (float)255/(float)ri;
  484.    // max colors out
  485.    ri = 255;
  486.    gi = (int)((float)gi * ratio + 0.5);
  487.    bi = (int)((float)bi * ratio + 0.5);
  488.    } // end if
  489. else // green largest?
  490. if (gi >= ri && gi >= bi)
  491.    {
  492.    // compute scaling ratio
  493.    ratio = (float)255/(float)gi;
  494.    // max colors out
  495.    gi = 255;
  496.    ri = (int)((float)ri * ratio + 0.5);
  497.    bi = (int)((float)bi * ratio + 0.5);
  498.    } // end if
  499. else // blue is largest
  500.    {
  501.    // compute scaling ratio
  502.    ratio = (float)255/(float)bi;
  503.    // max colors out
  504.    bi = 255;
  505.    ri = (int)((float)ri * ratio + 0.5);
  506.    gi = (int)((float)gi * ratio + 0.5);
  507.    } // end if
  508. } // end if
  509. // at this point, we need to compute the intensity gradients for this color,
  510. // so we can compute the RGB values for 256 shades of the current color
  511. dl = sqrt(ri*ri + gi*gi + bi*bi)/(float)256;
  512. dr = ri/dl,
  513. db = gi/dl,
  514. dg = bi/dl;
  515. // initialize working color
  516. rw = 0;
  517. gw = 0;
  518. bw = 0;
  519. // at this point rw,gw,bw, is the color that we need to compute the 256 intensities for to 
  520. // enter into the col_index (th) row of the table
  521. for (int intensity_index = 0; intensity_index < 256; intensity_index++)
  522.     {
  523.     int  curr_index  = -1;        // current color index of best match
  524.     long curr_error  = INT_MAX;    // distance in color space to nearest match or "error"
  525.     for (int color_index = 0; color_index < 256; color_index++)
  526.         {
  527.         // compute distance to color from target
  528.         long delta_red   = abs(src_palette[color_index].peRed   - rw);
  529.         long delta_green = abs(src_palette[color_index].peGreen - gw);
  530.         long delta_blue  = abs(src_palette[color_index].peBlue  - bw);
  531.         long error = (delta_red*delta_red) + (delta_green*delta_green) + (delta_blue*delta_blue);
  532.    
  533.         // is this color a better match?
  534.         if (error < curr_error)
  535.            { 
  536.            curr_index = color_index;
  537.            curr_error = error;   
  538.            } // end if
  539.         } // end for color_index
  540.        // best match has been found, enter it into table
  541.        rgbilookup[col_index][intensity_index] = curr_index;             
  542.     // compute next intensity level (test for overflow, shouldn't happen, but never know)
  543.     if (rw+=dr > 255) rw=255;
  544.     if (gw+=dg > 255) gw=255;
  545.     if (bw+=db > 255) bw=255;
  546.     } // end for intensity_index
  547. } // end for c_index
  548. // return success
  549. return(1);
  550. } // end RGB_16_8_Indexed_Intensity_Table_Builder
  551. ///////////////////////////////////////////////////////////////////////////////
  552. int Insert_OBJECT4DV1_RENDERLIST4DV12(RENDERLIST4DV1_PTR rend_list, 
  553.                                       OBJECT4DV1_PTR obj,
  554.                                       int insert_local,
  555.                                       int lighting_on) 
  556. {
  557. // converts the entire object into a face list and then inserts
  558. // the visible, active, non-clipped, non-culled polygons into
  559. // the render list, also note the flag insert_local control 
  560. // whether or not the vlist_local or vlist_trans vertex list
  561. // is used, thus you can insert an object "raw" totally untranformed
  562. // if you set insert_local to 1, default is 0, that is you would
  563. // only insert an object after at least the local to world transform
  564. // the last parameter is used to control if their has been
  565. // a lighting step that has generated a light value stored
  566. // in the upper 16-bits of color, if lighting_on = 1 then
  567. // this value is used to overwrite the base color of the 
  568. // polygon when its sent to the rendering list
  569. unsigned int base_color; // save base color of polygon
  570. // is this objective inactive or culled or invisible?
  571. if (!(obj->state & OBJECT4DV1_STATE_ACTIVE) ||
  572.      (obj->state & OBJECT4DV1_STATE_CULLED) ||
  573.      !(obj->state & OBJECT4DV1_STATE_VISIBLE))
  574.    return(0); 
  575. // the object is valid, let's rip it apart polygon by polygon
  576. for (int poly = 0; poly < obj->num_polys; poly++)
  577.     {
  578.     // acquire polygon
  579.     POLY4DV1_PTR curr_poly = &obj->plist[poly];
  580.     // first is this polygon even visible?
  581.     if (!(curr_poly->state & POLY4DV1_STATE_ACTIVE) ||
  582.          (curr_poly->state & POLY4DV1_STATE_CLIPPED ) ||
  583.          (curr_poly->state & POLY4DV1_STATE_BACKFACE) )
  584.     continue; // move onto next poly
  585.     // override vertex list polygon refers to
  586.     // the case that you want the local coords used
  587.     // first save old pointer
  588.     POINT4D_PTR vlist_old = curr_poly->vlist;
  589.     if (insert_local)
  590.        curr_poly->vlist = obj->vlist_local;
  591.     else
  592.        curr_poly->vlist = obj->vlist_trans;
  593.     // test if we should overwrite color with upper 16-bits
  594.     if (lighting_on==1)
  595.        {
  596.        // save color for a sec
  597.        base_color = (unsigned int)(curr_poly->color);
  598.        curr_poly->color = (int)(base_color >> 16);
  599.        } // end if
  600.     // now insert this polygon
  601.     if (!Insert_POLY4DV1_RENDERLIST4DV1(rend_list, curr_poly))
  602.        {
  603.        // fix vertex list pointer
  604.        curr_poly->vlist = vlist_old;
  605.    
  606.        // the whole object didn't fit!
  607.        return(0);
  608.        } // end if
  609.     // test if we should overwrite color with upper 16-bits
  610.     if (lighting_on==1)
  611.        {
  612.        // fix color upc
  613.        curr_poly->color = (int)(base_color & 0xffff);
  614.        } // end if
  615.     // fix vertex list pointer
  616.     curr_poly->vlist = vlist_old;
  617.     } // end for
  618. // return success
  619. return(1);
  620. } // end Insert_OBJECT4DV1_RENDERLIST4DV12
  621. ///////////////////////////////////////////////////////////////////////////////
  622. int Light_OBJECT4DV1_World16(OBJECT4DV1_PTR obj,  // object to process
  623.                              CAM4DV1_PTR cam,     // camera position
  624.                              LIGHTV1_PTR lights,  // light list (might have more than one)
  625.                              int max_lights)      // maximum lights in list
  626. {
  627. // 16-bit version of function
  628. // function lights an object based on the sent lights and camera. the function supports
  629. // constant/pure shading (emmisive), flat shading with ambient, infinite, point lights, and spot lights
  630. // note that this lighting function is rather brute force and simply follows the math, however
  631. // there are some clever integer operations that are used in scale 256 rather than going to floating
  632. // point, but why? floating point and ints are the same speed, HOWEVER, the conversion to and from floating
  633. // point can be cycle intensive, so if you can keep your calcs in ints then you can gain some speed
  634. // also note, type 1 spot lights are simply point lights with direction, the "cone" is more of a function
  635. // of the falloff due to attenuation, but they still look like spot lights
  636. // type 2 spot lights are implemented with the intensity having a dot product relationship with the
  637. // angle from the surface point to the light direction just like in the optimized model, but the pf term
  638. // that is used for a concentration control must be 1,2,3,.... integral and non-fractional
  639. unsigned int r_base, g_base, b_base,  // base color being lit
  640.              r_sum,  g_sum,  b_sum,   // sum of lighting process over all lights
  641.              shaded_color;            // final color
  642. float dp,     // dot product 
  643.       dist,   // distance from light to surface
  644.       i,      // general intensities
  645.       nl,     // length of normal
  646.       atten;  // attenuation computations
  647. // test if the object is culled
  648. if (!(obj->state & OBJECT4DV1_STATE_ACTIVE) ||
  649.      (obj->state & OBJECT4DV1_STATE_CULLED) ||
  650.      !(obj->state & OBJECT4DV1_STATE_VISIBLE))
  651.    return(0); 
  652. // process each poly in mesh
  653. for (int poly=0; poly < obj->num_polys; poly++)
  654.     {
  655.     // acquire polygon
  656.     POLY4DV1_PTR curr_poly = &obj->plist[poly];
  657.     // is this polygon valid?
  658.     // test this polygon if and only if it's not clipped, not culled,
  659.     // active, and visible. Note we test for backface in the event that
  660.     // a previous call might have already determined this, so why work
  661.     // harder!
  662.     if (!(curr_poly->state & POLY4DV1_STATE_ACTIVE) ||
  663.          (curr_poly->state & POLY4DV1_STATE_CLIPPED ) ||
  664.          (curr_poly->state & POLY4DV1_STATE_BACKFACE) )
  665.        continue; // move onto next poly
  666.     
  667.     // extract vertex indices into master list, rember the polygons are 
  668.     // NOT self contained, but based on the vertex list stored in the object
  669.     // itself
  670.     int vindex_0 = curr_poly->vert[0];
  671.     int vindex_1 = curr_poly->vert[1];
  672.     int vindex_2 = curr_poly->vert[2];
  673.     
  674.     // we will use the transformed polygon vertex list since the backface removal
  675.     // only makes sense at the world coord stage further of the pipeline 
  676.     // test the lighting mode of the polygon (use flat for flat, gouraud))
  677.     if (curr_poly->attr & POLY4DV1_ATTR_SHADE_MODE_FLAT || curr_poly->attr & POLY4DV1_ATTR_SHADE_MODE_GOURAUD)
  678.        {
  679.        // step 1: extract the base color out in RGB mode
  680.        if (dd_pixel_format == DD_PIXEL_FORMAT565)
  681.           {
  682.           _RGB565FROM16BIT(curr_poly->color, &r_base, &g_base, &b_base);
  683.           // scale to 8 bit 
  684.           r_base <<= 3;
  685.           g_base <<= 2;
  686.           b_base <<= 3;
  687.           } // end if
  688.        else
  689.           {
  690.           _RGB555FROM16BIT(curr_poly->color, &r_base, &g_base, &b_base);
  691.           // scale to 8 bit 
  692.           r_base <<= 3;
  693.           g_base <<= 3;
  694.           b_base <<= 3;
  695.           } // end if
  696.        // initialize color sum
  697.        r_sum  = 0;
  698.        g_sum  = 0;
  699.        b_sum  = 0;
  700.        // loop thru lights
  701.        for (int curr_light = 0; curr_light < max_lights; curr_light++)
  702.            {
  703.            // is this light active
  704.            if (lights[curr_light].state==LIGHTV1_STATE_OFF)
  705.               continue;
  706.            // what kind of light are we dealing with
  707.            if (lights[curr_light].attr & LIGHTV1_ATTR_AMBIENT)
  708.               {
  709.               // simply multiply each channel against the color of the 
  710.               // polygon then divide by 256 to scale back to 0..255
  711.               // use a shift in real life!!! >> 8
  712.               r_sum+= ((lights[curr_light].c_ambient.r * r_base) / 256);
  713.               g_sum+= ((lights[curr_light].c_ambient.g * g_base) / 256);
  714.               b_sum+= ((lights[curr_light].c_ambient.b * b_base) / 256);
  715.               // there better only be one ambient light!
  716.               } // end if
  717.            else
  718.            if (lights[curr_light].attr & LIGHTV1_ATTR_INFINITE)
  719.               {
  720.               // infinite lighting, we need the surface normal, and the direction
  721.               // of the light source
  722.               // we need to compute the normal of this polygon face, and recall
  723.               // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  724.               VECTOR4D u, v, n;
  725.  
  726.               // build u, v
  727.               VECTOR4D_Build(&obj->vlist_trans[ vindex_0 ], &obj->vlist_trans[ vindex_1 ], &u);
  728.               VECTOR4D_Build(&obj->vlist_trans[ vindex_0 ], &obj->vlist_trans[ vindex_2 ], &v);
  729.               // compute cross product
  730.               VECTOR4D_Cross(&u, &v, &n);
  731.               // at this point, we are almost ready, but we have to normalize the normal vector!
  732.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  733.               // normals, so this step can be optimized
  734.               // compute length of normal
  735.               nl = VECTOR4D_Length_Fast(&n);
  736.       
  737.               // ok, recalling the lighting model for infinite lights
  738.               // I(d)dir = I0dir * Cldir
  739.               // and for the diffuse model
  740.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  741.               // so we basically need to multiple it all together
  742.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  743.               // are slower, but the conversion to and from cost cycles
  744.               dp = VECTOR4D_Dot(&n, &lights[curr_light].dir);
  745.               
  746.               // only add light if dp > 0
  747.               if (dp > 0)
  748.                  { 
  749.                  i = 128*dp/nl; 
  750.                  r_sum+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  751.                  g_sum+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  752.                  b_sum+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  753.                  } // end if
  754.               } // end if infinite light
  755.            else
  756.            if (lights[curr_light].attr & LIGHTV1_ATTR_POINT)
  757.               {
  758.               // perform point light computations
  759.               // light model for point light is once again:
  760.               //              I0point * Clpoint
  761.               //  I(d)point = ___________________
  762.               //              kc +  kl*d + kq*d2              
  763.               //
  764.               //  Where d = |p - s|
  765.               // thus it's almost identical to the infinite light, but attenuates as a function
  766.               // of distance from the point source to the surface point being lit
  767.               // we need to compute the normal of this polygon face, and recall
  768.               // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  769.               VECTOR4D u, v, n, l;
  770.  
  771.               // build u, v
  772.               VECTOR4D_Build(&obj->vlist_trans[ vindex_0 ], &obj->vlist_trans[ vindex_1 ], &u);
  773.               VECTOR4D_Build(&obj->vlist_trans[ vindex_0 ], &obj->vlist_trans[ vindex_2 ], &v);
  774.               // compute cross product
  775.               VECTOR4D_Cross(&u, &v, &n);
  776.               // at this point, we are almost ready, but we have to normalize the normal vector!
  777.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  778.               // normals, so this step can be optimized
  779.               // compute length of normal
  780.               nl = VECTOR4D_Length_Fast(&n);
  781.              
  782.               // compute vector from surface to light
  783.               VECTOR4D_Build(&obj->vlist_trans[ vindex_0 ], &lights[curr_light].pos, &l);
  784.               // compute distance and attenuation
  785.               dist = VECTOR4D_Length_Fast(&l);  
  786.               // and for the diffuse model
  787.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  788.               // so we basically need to multiple it all together
  789.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  790.               // are slower, but the conversion to and from cost cycles
  791.               dp = VECTOR4D_Dot(&n, &l);
  792.               
  793.               // only add light if dp > 0
  794.               if (dp > 0)
  795.                  { 
  796.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  797.                  i = 128*dp / (nl * dist * atten ); 
  798.                  r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  799.                  g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  800.                  b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  801.                  } // end if
  802.               } // end if point
  803.            else
  804.            if (lights[curr_light].attr & LIGHTV1_ATTR_SPOTLIGHT1)
  805.               {
  806.               // perform spotlight/point computations simplified model that uses
  807.               // point light WITH a direction to simulate a spotlight
  808.               // light model for point light is once again:
  809.               //              I0point * Clpoint
  810.               //  I(d)point = ___________________
  811.               //              kc +  kl*d + kq*d2              
  812.               //
  813.               //  Where d = |p - s|
  814.               // thus it's almost identical to the infinite light, but attenuates as a function
  815.               // of distance from the point source to the surface point being lit
  816.               // we need to compute the normal of this polygon face, and recall
  817.               // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  818.               VECTOR4D u, v, n, l;
  819.  
  820.               // build u, v
  821.               VECTOR4D_Build(&obj->vlist_trans[ vindex_0 ], &obj->vlist_trans[ vindex_1 ], &u);
  822.               VECTOR4D_Build(&obj->vlist_trans[ vindex_0 ], &obj->vlist_trans[ vindex_2 ], &v);
  823.               // compute cross product (we need -n, so do vxu)
  824.               VECTOR4D_Cross(&v, &u, &n);
  825.               // at this point, we are almost ready, but we have to normalize the normal vector!
  826.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  827.               // normals, so this step can be optimized
  828.               // compute length of normal
  829.               nl = VECTOR4D_Length_Fast(&n);
  830.              
  831.               // compute vector from surface to light
  832.               VECTOR4D_Build(&obj->vlist_trans[ vindex_0 ], &lights[curr_light].pos, &l);
  833.               // compute distance and attenuation
  834.               dist = VECTOR4D_Length_Fast(&l);  
  835.               // and for the diffuse model
  836.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  837.               // so we basically need to multiple it all together
  838.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  839.               // are slower, but the conversion to and from cost cycles
  840.               // note that I use the direction of the light here rather than a the vector to the light
  841.               // thus we are taking orientation into account which is similar to the spotlight model
  842.               dp = VECTOR4D_Dot(&n, &lights[curr_light].dir);
  843.               
  844.               // only add light if dp > 0
  845.               if (dp > 0)
  846.                  { 
  847.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  848.                  i = 128*dp / (nl * atten ); 
  849.                  r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  850.                  g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  851.                  b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  852.                  } // end if
  853.               } // end if spotlight1
  854.            else
  855.            if (lights[curr_light].attr & LIGHTV1_ATTR_SPOTLIGHT2) // simple version
  856.               {
  857.               // perform spot light computations
  858.               // light model for spot light simple version is once again:
  859.               //               I0spotlight * Clspotlight * MAX( (l . s), 0)^pf                     
  860.               // I(d)spotlight = __________________________________________      
  861.               //                 kc + kl*d + kq*d2        
  862.               // Where d = |p - s|, and pf = power factor
  863.               // thus it's almost identical to the point, but has the extra term in the numerator
  864.               // relating the angle between the light source and the point on the surface
  865.               // we need to compute the normal of this polygon face, and recall
  866.               // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  867.               VECTOR4D u, v, n, d, s;
  868.  
  869.               // build u, v
  870.               VECTOR4D_Build(&obj->vlist_trans[ vindex_0 ], &obj->vlist_trans[ vindex_1 ], &u);
  871.               VECTOR4D_Build(&obj->vlist_trans[ vindex_0 ], &obj->vlist_trans[ vindex_2 ], &v);
  872.               // compute cross product (v x u, to invert n)
  873.               VECTOR4D_Cross(&v, &u, &n);
  874.               // at this point, we are almost ready, but we have to normalize the normal vector!
  875.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  876.               // normals, so this step can be optimized
  877.               // compute length of normal
  878.               nl = VECTOR4D_Length_Fast(&n);
  879.              
  880.               // and for the diffuse model
  881.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  882.               // so we basically need to multiple it all together
  883.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  884.               // are slower, but the conversion to and from cost cycles
  885.               dp = VECTOR4D_Dot(&n, &lights[curr_light].dir);
  886.               
  887.               // only add light if dp > 0
  888.               if (dp > 0)
  889.                  { 
  890.                  // compute vector from light to surface (different from l which IS the light dir)
  891.                  VECTOR4D_Build( &lights[curr_light].pos, &obj->vlist_trans[ vindex_0 ], &s);
  892.                  // compute length of s (distance to light source) to normalize s for lighting calc
  893.                  dist = VECTOR4D_Length_Fast(&s);  
  894.                  // compute spot light term (s . l)
  895.                  float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].dir)/dist;
  896.                  // proceed only if term is positive
  897.                  if (dpsl > 0) 
  898.                     {
  899.                     // compute attenuation
  900.                     atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  901.        
  902.                     // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
  903.                     // must be integral
  904.                     float dpsl_exp = dpsl;
  905.  
  906.                     // exponentiate for positive integral powers
  907.                     for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
  908.                          dpsl_exp*=dpsl;
  909.                     // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf 
  910.                                                       
  911.                     i = 128*dp * dpsl_exp / (nl * atten ); 
  912.                     r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  913.                     g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  914.                     b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  915.   
  916.                     } // end if
  917.                  } // end if
  918.               } // end if spot light
  919.            } // end for light
  920.   
  921.        // make sure colors aren't out of range
  922.        if (r_sum  > 255) r_sum = 255;
  923.        if (g_sum  > 255) g_sum = 255;
  924.        if (b_sum  > 255) b_sum = 255;
  925.        // write the color
  926.        shaded_color = RGB16Bit(r_sum, g_sum, b_sum);
  927.        curr_poly->color = (int)((shaded_color << 16) | curr_poly->color);
  928.        } // end if
  929.     else // assume POLY4DV1_ATTR_SHADE_MODE_CONSTANT
  930.        {
  931.        // emmisive shading only, copy base color into upper 16-bits
  932.        // without any change
  933.        curr_poly->color = (int)((curr_poly->color << 16) | curr_poly->color);
  934.        } // end if
  935.     } // end for poly
  936. // return success
  937. return(1);
  938. } // end Light_OBJECT4DV1_World16
  939. ///////////////////////////////////////////////////////////////////////////////
  940. int Light_OBJECT4DV1_World(OBJECT4DV1_PTR obj,  // object to process
  941.                            CAM4DV1_PTR cam,     // camera position
  942.                            LIGHTV1_PTR lights,  // light list (might have more than one)
  943.                            int max_lights)      // maximum lights in list
  944. {
  945. // 8 bit version
  946. // function lights an object based on the sent lights and camera. the function supports
  947. // constant/pure shading (emmisive), flat shading with ambient, infinite, point lights, and spot lights
  948. // note that this lighting function is rather brute force and simply follows the math, however
  949. // there are some clever integer operations that are used in scale 256 rather than going to floating
  950. // point, but why? floating point and ints are the same speed, HOWEVER, the conversion to and from floating
  951. // point can be cycle intensive, so if you can keep your calcs in ints then you can gain some speed
  952. // also note, type 1 spot lights are simply point lights with direction, the "cone" is more of a function
  953. // of the falloff due to attenuation, but they still look like spot lights
  954. // type 2 spot lights are implemented with the intensity having a dot product relationship with the
  955. // angle from the surface point to the light direction just like in the optimized model, but the pf term
  956. // that is used for a concentration control must be 1,2,3,.... integral and non-fractional
  957. // the function works in 8-bit color space, and uses the rgblookup[] to look colors up from RGB values
  958. // basically, the function converts the 8-bit color index into an RGB value performs the lighting
  959. // operations and then back into an 8-bit color index with the table, so we loose a little bit during the incoming and 
  960. // outgoing transformations, however, the next step for optimization will be to make a purely monochromatic
  961. // 8-bit system that assumes ALL lights are white, but this function works with color for now
  962. unsigned int r_base, g_base, b_base,  // base color being lit
  963.              r_sum,  g_sum,  b_sum,   // sum of lighting process over all lights
  964.              shaded_color;            // final color
  965. float dp,     // dot product 
  966.       dist,   // distance from light to surface
  967.       i,      // general intensities
  968.       nl,     // length of normal
  969.       atten;  // attenuation computations
  970. // test if the object is culled
  971. if (!(obj->state & OBJECT4DV1_STATE_ACTIVE) ||
  972.      (obj->state & OBJECT4DV1_STATE_CULLED) ||
  973.      !(obj->state & OBJECT4DV1_STATE_VISIBLE))
  974.    return(0); 
  975. // process each poly in mesh
  976. for (int poly=0; poly < obj->num_polys; poly++)
  977.     {
  978.     // acquire polygon
  979.     POLY4DV1_PTR curr_poly = &obj->plist[poly];
  980.     // is this polygon valid?
  981.     // test this polygon if and only if it's not clipped, not culled,
  982.     // active, and visible. Note we test for backface in the event that
  983.     // a previous call might have already determined this, so why work
  984.     // harder!
  985.     if (!(curr_poly->state & POLY4DV1_STATE_ACTIVE) ||
  986.          (curr_poly->state & POLY4DV1_STATE_CLIPPED ) ||
  987.          (curr_poly->state & POLY4DV1_STATE_BACKFACE) )
  988.        continue; // move onto next poly
  989.     
  990.     // extract vertex indices into master list, rember the polygons are 
  991.     // NOT self contained, but based on the vertex list stored in the object
  992.     // itself
  993.     int vindex_0 = curr_poly->vert[0];
  994.     int vindex_1 = curr_poly->vert[1];
  995.     int vindex_2 = curr_poly->vert[2];
  996.     
  997.     // we will use the transformed polygon vertex list since the backface removal
  998.     // only makes sense at the world coord stage further of the pipeline 
  999.     // test the lighting mode of the polygon (use flat for flat, gouraud))
  1000.     if (curr_poly->attr & POLY4DV1_ATTR_SHADE_MODE_FLAT || curr_poly->attr & POLY4DV1_ATTR_SHADE_MODE_GOURAUD)
  1001.        {
  1002.        // step 1: extract the base color out in RGB mode (it's already in 8 bits per channel)
  1003.        r_base = palette[curr_poly->color].peRed;
  1004.        g_base = palette[curr_poly->color].peGreen;
  1005.        b_base = palette[curr_poly->color].peBlue;
  1006.        // initialize color sum
  1007.        r_sum  = 0;
  1008.        g_sum  = 0;
  1009.        b_sum  = 0;
  1010.        // loop thru lights
  1011.        for (int curr_light = 0; curr_light < max_lights; curr_light++)
  1012.            {
  1013.            // is this light active
  1014.            if (lights[curr_light].state==LIGHTV1_STATE_OFF)
  1015.               continue;
  1016.            // what kind of light are we dealing with
  1017.            if (lights[curr_light].attr & LIGHTV1_ATTR_AMBIENT)
  1018.               {
  1019.               // simply multiply each channel against the color of the 
  1020.               // polygon then divide by 256 to scale back to 0..255
  1021.               // use a shift in real life!!! >> 8
  1022.               r_sum+= ((lights[curr_light].c_ambient.r * r_base) / 256);
  1023.               g_sum+= ((lights[curr_light].c_ambient.g * g_base) / 256);
  1024.               b_sum+= ((lights[curr_light].c_ambient.b * b_base) / 256);
  1025.               // there better only be one ambient light!
  1026.               } // end if
  1027.            else
  1028.            if (lights[curr_light].attr & LIGHTV1_ATTR_INFINITE)
  1029.               {
  1030.               // infinite lighting, we need the surface normal, and the direction
  1031.               // of the light source
  1032.               // we need to compute the normal of this polygon face, and recall
  1033.               // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  1034.               VECTOR4D u, v, n;
  1035.  
  1036.               // build u, v
  1037.               VECTOR4D_Build(&obj->vlist_trans[ vindex_0 ], &obj->vlist_trans[ vindex_1 ], &u);
  1038.               VECTOR4D_Build(&obj->vlist_trans[ vindex_0 ], &obj->vlist_trans[ vindex_2 ], &v);
  1039.               // compute cross product
  1040.               VECTOR4D_Cross(&u, &v, &n);
  1041.               // at this point, we are almost ready, but we have to normalize the normal vector!
  1042.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  1043.               // normals, so this step can be optimized
  1044.               // compute length of normal
  1045.               nl = VECTOR4D_Length_Fast(&n);
  1046.       
  1047.               // ok, recalling the lighting model for infinite lights
  1048.               // I(d)dir = I0dir * Cldir
  1049.               // and for the diffuse model
  1050.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  1051.               // so we basically need to multiple it all together
  1052.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  1053.               // are slower, but the conversion to and from cost cycles
  1054.               dp = VECTOR4D_Dot(&n, &lights[curr_light].dir);
  1055.               
  1056.               // only add light if dp > 0
  1057.               if (dp > 0)
  1058.                  { 
  1059.                  i = 128*dp/nl; 
  1060.                  r_sum+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1061.                  g_sum+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1062.                  b_sum+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1063.                  } // end if
  1064.               } // end if infinite light
  1065.            else
  1066.            if (lights[curr_light].attr & LIGHTV1_ATTR_POINT)
  1067.               {
  1068.               // perform point light computations
  1069.               // light model for point light is once again:
  1070.               //              I0point * Clpoint
  1071.               //  I(d)point = ___________________
  1072.               //              kc +  kl*d + kq*d2              
  1073.               //
  1074.               //  Where d = |p - s|
  1075.               // thus it's almost identical to the infinite light, but attenuates as a function
  1076.               // of distance from the point source to the surface point being lit
  1077.               // we need to compute the normal of this polygon face, and recall
  1078.               // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  1079.               VECTOR4D u, v, n, l;
  1080.  
  1081.               // build u, v
  1082.               VECTOR4D_Build(&obj->vlist_trans[ vindex_0 ], &obj->vlist_trans[ vindex_1 ], &u);
  1083.               VECTOR4D_Build(&obj->vlist_trans[ vindex_0 ], &obj->vlist_trans[ vindex_2 ], &v);
  1084.               // compute cross product
  1085.               VECTOR4D_Cross(&u, &v, &n);
  1086.               // at this point, we are almost ready, but we have to normalize the normal vector!
  1087.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  1088.               // normals, so this step can be optimized
  1089.               // compute length of normal
  1090.               nl = VECTOR4D_Length_Fast(&n);
  1091.              
  1092.               // compute vector from surface to light
  1093.               VECTOR4D_Build(&obj->vlist_trans[ vindex_0 ], &lights[curr_light].pos, &l);
  1094.               // compute distance and attenuation
  1095.               dist = VECTOR4D_Length_Fast(&l);  
  1096.               // and for the diffuse model
  1097.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  1098.               // so we basically need to multiple it all together
  1099.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  1100.               // are slower, but the conversion to and from cost cycles
  1101.               dp = VECTOR4D_Dot(&n, &l);
  1102.               
  1103.               // only add light if dp > 0
  1104.               if (dp > 0)
  1105.                  { 
  1106.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  1107.                  i = 128*dp / (nl * dist * atten ); 
  1108.                  r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1109.                  g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1110.                  b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1111.                  } // end if
  1112.               } // end if point
  1113.            else
  1114.            if (lights[curr_light].attr & LIGHTV1_ATTR_SPOTLIGHT1)
  1115.               {
  1116.               // perform spotlight/point computations simplified model that uses
  1117.               // point light WITH a direction to simulate a spotlight
  1118.               // light model for point light is once again:
  1119.               //              I0point * Clpoint
  1120.               //  I(d)point = ___________________
  1121.               //              kc +  kl*d + kq*d2              
  1122.               //
  1123.               //  Where d = |p - s|
  1124.               // thus it's almost identical to the infinite light, but attenuates as a function
  1125.               // of distance from the point source to the surface point being lit
  1126.               // we need to compute the normal of this polygon face, and recall
  1127.               // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  1128.               VECTOR4D u, v, n, l;
  1129.  
  1130.               // build u, v
  1131.               VECTOR4D_Build(&obj->vlist_trans[ vindex_0 ], &obj->vlist_trans[ vindex_1 ], &u);
  1132.               VECTOR4D_Build(&obj->vlist_trans[ vindex_0 ], &obj->vlist_trans[ vindex_2 ], &v);
  1133.               // compute cross product (we need -n, so do vxu)
  1134.               VECTOR4D_Cross(&v, &u, &n);
  1135.               // at this point, we are almost ready, but we have to normalize the normal vector!
  1136.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  1137.               // normals, so this step can be optimized
  1138.               // compute length of normal
  1139.               nl = VECTOR4D_Length_Fast(&n);
  1140.              
  1141.               // compute vector from surface to light
  1142.               VECTOR4D_Build(&obj->vlist_trans[ vindex_0 ], &lights[curr_light].pos, &l);
  1143.               // compute distance and attenuation
  1144.               dist = VECTOR4D_Length_Fast(&l);  
  1145.               // and for the diffuse model
  1146.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  1147.               // so we basically need to multiple it all together
  1148.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  1149.               // are slower, but the conversion to and from cost cycles
  1150.               // note that I use the direction of the light here rather than a the vector to the light
  1151.               // thus we are taking orientation into account which is similar to the spotlight model
  1152.               dp = VECTOR4D_Dot(&n, &lights[curr_light].dir);
  1153.               
  1154.               // only add light if dp > 0
  1155.               if (dp > 0)
  1156.                  { 
  1157.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  1158.                  i = 128*dp / (nl * atten ); 
  1159.                  r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1160.                  g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1161.                  b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1162.                  } // end if
  1163.               } // end if spotlight1
  1164.            else
  1165.            if (lights[curr_light].attr & LIGHTV1_ATTR_SPOTLIGHT2) // simple version
  1166.               {
  1167.               // perform spot light computations
  1168.               // light model for spot light simple version is once again:
  1169.               //               I0spotlight * Clspotlight * MAX( (l . s), 0)^pf                     
  1170.               // I(d)spotlight = __________________________________________      
  1171.               //                 kc + kl*d + kq*d2        
  1172.               // Where d = |p - s|, and pf = power factor
  1173.               // thus it's almost identical to the point, but has the extra term in the numerator
  1174.               // relating the angle between the light source and the point on the surface
  1175.               // we need to compute the normal of this polygon face, and recall
  1176.               // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  1177.               VECTOR4D u, v, n, d, s;
  1178.  
  1179.               // build u, v
  1180.               VECTOR4D_Build(&obj->vlist_trans[ vindex_0 ], &obj->vlist_trans[ vindex_1 ], &u);
  1181.               VECTOR4D_Build(&obj->vlist_trans[ vindex_0 ], &obj->vlist_trans[ vindex_2 ], &v);
  1182.               // compute cross product (v x u, to invert n)
  1183.               VECTOR4D_Cross(&v, &u, &n);
  1184.               // at this point, we are almost ready, but we have to normalize the normal vector!
  1185.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  1186.               // normals, so this step can be optimized
  1187.               // compute length of normal
  1188.               nl = VECTOR4D_Length_Fast(&n);
  1189.              
  1190.               // and for the diffuse model
  1191.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  1192.               // so we basically need to multiple it all together
  1193.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  1194.               // are slower, but the conversion to and from cost cycles
  1195.               dp = VECTOR4D_Dot(&n, &lights[curr_light].dir);
  1196.               
  1197.               // only add light if dp > 0
  1198.               if (dp > 0)
  1199.                  { 
  1200.                  // compute vector from light to surface (different from l which IS the light dir)
  1201.                  VECTOR4D_Build( &lights[curr_light].pos, &obj->vlist_trans[ vindex_0 ], &s);
  1202.                  // compute length of s (distance to light source) to normalize s for lighting calc
  1203.                  dist = VECTOR4D_Length_Fast(&s);  
  1204.                  // compute spot light term (s . l)
  1205.                  float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].dir)/dist;
  1206.                  // proceed only if term is positive
  1207.                  if (dpsl > 0) 
  1208.                     {
  1209.                     // compute attenuation
  1210.                     atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  1211.        
  1212.                     // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
  1213.                     // must be integral
  1214.                     float dpsl_exp = dpsl;
  1215.  
  1216.                     // exponentiate for positive integral powers
  1217.                     for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
  1218.                          dpsl_exp*=dpsl;
  1219.                     // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf 
  1220.                                                   
  1221.                     i = 128*dp * dpsl_exp / (nl * atten ); 
  1222.                     r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1223.                     g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1224.                     b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1225.   
  1226.                     } // end if
  1227.                  } // end if
  1228.               } // end if spot light
  1229.            } // end for light
  1230.   
  1231.        // make sure colors aren't out of range
  1232.        if (r_sum  > 255) r_sum = 255;
  1233.        if (g_sum  > 255) g_sum = 255;
  1234.        if (b_sum  > 255) b_sum = 255;
  1235.        // use straght rgb look up, assume 565 format, more color space
  1236.        int rgbindex = RGB16Bit565(r_sum, g_sum, b_sum);          
  1237.        shaded_color = rgblookup[rgbindex];
  1238.        // and now insert color index into upper 16 bits
  1239.        curr_poly->color = (int)((shaded_color << 16) | curr_poly->color);
  1240.        } // end if
  1241.     else // assume POLY4DV1_ATTR_SHADE_MODE_CONSTANT
  1242.        {
  1243.        // emmisive shading only, copy base color into upper 16-bits
  1244.        // without any change
  1245.        curr_poly->color = (int)((curr_poly->color << 16) | curr_poly->color);
  1246.        } // end if
  1247.     } // end for poly
  1248. // return success
  1249. return(1);
  1250. } // end Light_OBJECT4DV1_World
  1251. //////////////////////////////////////////////////////////////////////////////
  1252. int Light_RENDERLIST4DV1_World16(RENDERLIST4DV1_PTR rend_list,  // list to process
  1253.                                  CAM4DV1_PTR cam,     // camera position
  1254.                                  LIGHTV1_PTR lights,  // light list (might have more than one)
  1255.                                  int max_lights)      // maximum lights in list
  1256. {
  1257. // 16-bit version of function
  1258. // function lights the enture rendering list based on the sent lights and camera. the function supports
  1259. // constant/pure shading (emmisive), flat shading with ambient, infinite, point lights, and spot lights
  1260. // note that this lighting function is rather brute force and simply follows the math, however
  1261. // there are some clever integer operations that are used in scale 256 rather than going to floating
  1262. // point, but why? floating point and ints are the same speed, HOWEVER, the conversion to and from floating
  1263. // point can be cycle intensive, so if you can keep your calcs in ints then you can gain some speed
  1264. // also note, type 1 spot lights are simply point lights with direction, the "cone" is more of a function
  1265. // of the falloff due to attenuation, but they still look like spot lights
  1266. // type 2 spot lights are implemented with the intensity having a dot product relationship with the
  1267. // angle from the surface point to the light direction just like in the optimized model, but the pf term
  1268. // that is used for a concentration control must be 1,2,3,.... integral and non-fractional
  1269. // also note since we are dealing with a rendering list and not object, the final lit color is
  1270. // immediately written over the real color
  1271. unsigned int r_base, g_base, b_base,  // base color being lit
  1272.              r_sum,  g_sum,  b_sum,   // sum of lighting process over all lights
  1273.              shaded_color;            // final color
  1274. float dp,     // dot product 
  1275.       dist,   // distance from light to surface
  1276.       i,      // general intensities
  1277.       nl,     // length of normal
  1278.       atten;  // attenuation computations
  1279. // for each valid poly, light it...
  1280. for (int poly=0; poly < rend_list->num_polys; poly++)
  1281.     {
  1282.     // acquire polygon
  1283.     POLYF4DV1_PTR curr_poly = rend_list->poly_ptrs[poly];
  1284.     // light this polygon if and only if it's not clipped, not culled,
  1285.     // active, and visible
  1286.     if (!(curr_poly->state & POLY4DV1_STATE_ACTIVE) ||
  1287.          (curr_poly->state & POLY4DV1_STATE_CLIPPED ) ||
  1288.          (curr_poly->state & POLY4DV1_STATE_BACKFACE) )
  1289.        continue; // move onto next poly
  1290.    
  1291.     // we will use the transformed polygon vertex list since the backface removal
  1292.     // only makes sense at the world coord stage further of the pipeline 
  1293.     // test the lighting mode of the polygon (use flat for flat, gouraud))
  1294.     if (curr_poly->attr & POLY4DV1_ATTR_SHADE_MODE_FLAT || curr_poly->attr & POLY4DV1_ATTR_SHADE_MODE_GOURAUD)
  1295.        {
  1296.        // step 1: extract the base color out in RGB mode
  1297.        if (dd_pixel_format == DD_PIXEL_FORMAT565)
  1298.           {
  1299.           _RGB565FROM16BIT(curr_poly->color, &r_base, &g_base, &b_base);
  1300.           // scale to 8 bit 
  1301.           r_base <<= 3;
  1302.           g_base <<= 2;
  1303.           b_base <<= 3;
  1304.           } // end if
  1305.        else
  1306.           {
  1307.           _RGB555FROM16BIT(curr_poly->color, &r_base, &g_base, &b_base);
  1308.           // scale to 8 bit 
  1309.           r_base <<= 3;
  1310.           g_base <<= 3;
  1311.           b_base <<= 3;
  1312.           } // end if
  1313.        // initialize color sum
  1314.        r_sum  = 0;
  1315.        g_sum  = 0;
  1316.        b_sum  = 0;
  1317.        // loop thru lights
  1318.        for (int curr_light = 0; curr_light < max_lights; curr_light++)
  1319.            {
  1320.            // is this light active
  1321.            if (lights[curr_light].state==LIGHTV1_STATE_OFF)
  1322.               continue;
  1323.            // what kind of light are we dealing with
  1324.            if (lights[curr_light].attr & LIGHTV1_ATTR_AMBIENT)
  1325.               {
  1326.               // simply multiply each channel against the color of the 
  1327.               // polygon then divide by 256 to scale back to 0..255
  1328.               // use a shift in real life!!! >> 8
  1329.               r_sum+= ((lights[curr_light].c_ambient.r * r_base) / 256);
  1330.               g_sum+= ((lights[curr_light].c_ambient.g * g_base) / 256);
  1331.               b_sum+= ((lights[curr_light].c_ambient.b * b_base) / 256);
  1332.               // there better only be one ambient light!
  1333.               } // end if
  1334.            else
  1335.            if (lights[curr_light].attr & LIGHTV1_ATTR_INFINITE)
  1336.               {
  1337.               // infinite lighting, we need the surface normal, and the direction
  1338.               // of the light source
  1339.               // we need to compute the normal of this polygon face, and recall
  1340.               // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  1341.               VECTOR4D u, v, n;
  1342.  
  1343.               // build u, v
  1344.               VECTOR4D_Build(&curr_poly->tvlist[0], &curr_poly->tvlist[1], &u);
  1345.               VECTOR4D_Build(&curr_poly->tvlist[0], &curr_poly->tvlist[2], &v);
  1346.               // compute cross product
  1347.               VECTOR4D_Cross(&u, &v, &n);
  1348.               // at this point, we are almost ready, but we have to normalize the normal vector!
  1349.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  1350.               // normals, so this step can be optimized
  1351.               // compute length of normal
  1352.               nl = VECTOR4D_Length_Fast(&n);
  1353.       
  1354.               // ok, recalling the lighting model for infinite lights
  1355.               // I(d)dir = I0dir * Cldir
  1356.               // and for the diffuse model
  1357.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  1358.               // so we basically need to multiple it all together
  1359.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  1360.               // are slower, but the conversion to and from cost cycles
  1361.               dp = VECTOR4D_Dot(&n, &lights[curr_light].dir);
  1362.               
  1363.               // only add light if dp > 0
  1364.               if (dp > 0)
  1365.                  { 
  1366.                  i = 128*dp/nl; 
  1367.                  r_sum+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1368.                  g_sum+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1369.                  b_sum+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1370.                  } // end if
  1371.               } // end if infinite light
  1372.            else
  1373.            if (lights[curr_light].attr & LIGHTV1_ATTR_POINT)
  1374.               {
  1375.               // perform point light computations
  1376.               // light model for point light is once again:
  1377.               //              I0point * Clpoint
  1378.               //  I(d)point = ___________________
  1379.               //              kc +  kl*d + kq*d2              
  1380.               //
  1381.               //  Where d = |p - s|
  1382.               // thus it's almost identical to the infinite light, but attenuates as a function
  1383.               // of distance from the point source to the surface point being lit
  1384.               // we need to compute the normal of this polygon face, and recall
  1385.               // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  1386.               VECTOR4D u, v, n, l;
  1387.  
  1388.               // build u, v
  1389.               VECTOR4D_Build(&curr_poly->tvlist[0], &curr_poly->tvlist[1], &u);
  1390.               VECTOR4D_Build(&curr_poly->tvlist[0], &curr_poly->tvlist[2], &v);
  1391.               // compute cross product
  1392.               VECTOR4D_Cross(&u, &v, &n);
  1393.               // at this point, we are almost ready, but we have to normalize the normal vector!
  1394.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  1395.               // normals, so this step can be optimized
  1396.               // compute length of normal
  1397.               nl = VECTOR4D_Length_Fast(&n);
  1398.              
  1399.               // compute vector from surface to light
  1400.               VECTOR4D_Build(&curr_poly->tvlist[0], &lights[curr_light].pos, &l);
  1401.               // compute distance and attenuation
  1402.               dist = VECTOR4D_Length_Fast(&l);  
  1403.               // and for the diffuse model
  1404.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  1405.               // so we basically need to multiple it all together
  1406.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  1407.               // are slower, but the conversion to and from cost cycles
  1408.               dp = VECTOR4D_Dot(&n, &l);
  1409.               
  1410.               // only add light if dp > 0
  1411.               if (dp > 0)
  1412.                  { 
  1413.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  1414.                  i = 128*dp / (nl * dist * atten ); 
  1415.                  r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1416.                  g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1417.                  b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1418.                  } // end if
  1419.               } // end if point
  1420.            else
  1421.            if (lights[curr_light].attr & LIGHTV1_ATTR_SPOTLIGHT1)
  1422.               {
  1423.               // perform spotlight/point computations simplified model that uses
  1424.               // point light WITH a direction to simulate a spotlight
  1425.               // light model for point light is once again:
  1426.               //              I0point * Clpoint
  1427.               //  I(d)point = ___________________
  1428.               //              kc +  kl*d + kq*d2              
  1429.               //
  1430.               //  Where d = |p - s|
  1431.               // thus it's almost identical to the infinite light, but attenuates as a function
  1432.               // of distance from the point source to the surface point being lit
  1433.               // we need to compute the normal of this polygon face, and recall
  1434.               // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  1435.               VECTOR4D u, v, n, l;
  1436.  
  1437.               // build u, v
  1438.               VECTOR4D_Build(&curr_poly->tvlist[0], &curr_poly->tvlist[1], &u);
  1439.               VECTOR4D_Build(&curr_poly->tvlist[0], &curr_poly->tvlist[2], &v);
  1440.               // compute cross product (we need -n, so do vxu)
  1441.               VECTOR4D_Cross(&v, &u, &n);
  1442.               // at this point, we are almost ready, but we have to normalize the normal vector!
  1443.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  1444.               // normals, so this step can be optimized
  1445.               // compute length of normal
  1446.               nl = VECTOR4D_Length_Fast(&n);
  1447.              
  1448.               // compute vector from surface to light
  1449.               VECTOR4D_Build(&curr_poly->tvlist[0], &lights[curr_light].pos, &l);
  1450.               // compute distance and attenuation
  1451.               dist = VECTOR4D_Length_Fast(&l);  
  1452.               // and for the diffuse model
  1453.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  1454.               // so we basically need to multiple it all together
  1455.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  1456.               // are slower, but the conversion to and from cost cycles
  1457.               // note that I use the direction of the light here rather than a the vector to the light
  1458.               // thus we are taking orientation into account which is similar to the spotlight model
  1459.               dp = VECTOR4D_Dot(&n, &lights[curr_light].dir);
  1460.               
  1461.               // only add light if dp > 0
  1462.               if (dp > 0)
  1463.                  { 
  1464.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  1465.                  i = 128*dp / (nl * atten ); 
  1466.                  r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1467.                  g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1468.                  b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1469.                  } // end if
  1470.               } // end if spotlight1
  1471.            else
  1472.            if (lights[curr_light].attr & LIGHTV1_ATTR_SPOTLIGHT2) // simple version
  1473.               {
  1474.               // perform spot light computations
  1475.               // light model for spot light simple version is once again:
  1476.               //               I0spotlight * Clspotlight * MAX( (l . s), 0)^pf                     
  1477.               // I(d)spotlight = __________________________________________      
  1478.               //                 kc + kl*d + kq*d2        
  1479.               // Where d = |p - s|, and pf = power factor
  1480.               // thus it's almost identical to the point, but has the extra term in the numerator
  1481.               // relating the angle between the light source and the point on the surface
  1482.               // we need to compute the normal of this polygon face, and recall
  1483.               // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  1484.               VECTOR4D u, v, n, d, s;
  1485.  
  1486.               // build u, v
  1487.               VECTOR4D_Build(&curr_poly->tvlist[0], &curr_poly->tvlist[1], &u);
  1488.               VECTOR4D_Build(&curr_poly->tvlist[0], &curr_poly->tvlist[2], &v);
  1489.               // compute cross product (v x u, to invert n)
  1490.               VECTOR4D_Cross(&v, &u, &n);
  1491.               // at this point, we are almost ready, but we have to normalize the normal vector!
  1492.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  1493.               // normals, so this step can be optimized
  1494.               // compute length of normal
  1495.               nl = VECTOR4D_Length_Fast(&n);
  1496.              
  1497.               // and for the diffuse model
  1498.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  1499.               // so we basically need to multiple it all together
  1500.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  1501.               // are slower, but the conversion to and from cost cycles
  1502.               dp = VECTOR4D_Dot(&n, &lights[curr_light].dir);
  1503.               
  1504.               // only add light if dp > 0
  1505.               if (dp > 0)
  1506.                  { 
  1507.                  // compute vector from light to surface (different from l which IS the light dir)
  1508.                  VECTOR4D_Build( &lights[curr_light].pos, &curr_poly->tvlist[0], &s);
  1509.                  // compute length of s (distance to light source) to normalize s for lighting calc
  1510.                  dist = VECTOR4D_Length_Fast(&s);  
  1511.                  // compute spot light term (s . l)
  1512.                  float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].dir)/dist;
  1513.                  // proceed only if term is positive
  1514.                  if (dpsl > 0) 
  1515.                     {
  1516.                     // compute attenuation
  1517.                     atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  1518.        
  1519.                     // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
  1520.                     // must be integral
  1521.                     float dpsl_exp = dpsl;
  1522.  
  1523.                     // exponentiate for positive integral powers
  1524.                     for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
  1525.                          dpsl_exp*=dpsl;
  1526.                     // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf 
  1527.                                                       
  1528.                     i = 128*dp * dpsl_exp / (nl * atten ); 
  1529.                     r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1530.                     g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1531.                     b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1532.   
  1533.                     } // end if
  1534.                  } // end if
  1535.               } // end if spot light
  1536.            } // end for light
  1537.   
  1538.        // make sure colors aren't out of range
  1539.        if (r_sum  > 255) r_sum = 255;
  1540.        if (g_sum  > 255) g_sum = 255;
  1541.        if (b_sum  > 255) b_sum = 255;
  1542.        // write the color over current color
  1543.        curr_poly->color = RGB16Bit(r_sum, g_sum, b_sum);
  1544.        } // end if
  1545.     else // assume POLY4DV1_ATTR_SHADE_MODE_CONSTANT
  1546.        {
  1547.        // emmisive shading only, do nothing
  1548.        // ...
  1549.        } // end if
  1550.     } // end for poly
  1551. // return success
  1552. return(1);
  1553. } // end Light_RENDERLIST4DV1_World16
  1554. //////////////////////////////////////////////////////////////////////////////
  1555. int Light_RENDERLIST4DV1_World(RENDERLIST4DV1_PTR rend_list,  // list to process
  1556.                                CAM4DV1_PTR cam,     // camera position
  1557.                                LIGHTV1_PTR lights,  // light list (might have more than one)
  1558.                                int max_lights)      // maximum lights in list
  1559. {
  1560. // 8-bit version of function
  1561. // function lights the enture rendering list based on the sent lights and camera. the function supports
  1562. // constant/pure shading (emmisive), flat shading with ambient, infinite, point lights, and spot lights
  1563. // note that this lighting function is rather brute force and simply follows the math, however
  1564. // there are some clever integer operations that are used in scale 256 rather than going to floating
  1565. // point, but why? floating point and ints are the same speed, HOWEVER, the conversion to and from floating
  1566. // point can be cycle intensive, so if you can keep your calcs in ints then you can gain some speed
  1567. // also note, type 1 spot lights are simply point lights with direction, the "cone" is more of a function
  1568. // of the falloff due to attenuation, but they still look like spot lights
  1569. // type 2 spot lights are implemented with the intensity having a dot product relationship with the
  1570. // angle from the surface point to the light direction just like in the optimized model, but the pf term
  1571. // that is used for a concentration control must be 1,2,3,.... integral and non-fractional
  1572. // the function works in 8-bit color space, and uses the rgblookup[] to look colors up from RGB values
  1573. // basically, the function converts the 8-bit color index into an RGB value performs the lighting
  1574. // operations and then back into an 8-bit color index with the table, so we loose a little bit during the incoming and 
  1575. // outgoing transformations, however, the next step for optimization will be to make a purely monochromatic
  1576. // 8-bit system that assumes ALL lights are white, but this function works with color for now
  1577. // also note since we are dealing with a rendering list and not object, the final lit color is
  1578. // immediately written over the real color
  1579. unsigned int r_base, g_base, b_base,  // base color being lit
  1580.              r_sum,  g_sum,  b_sum,   // sum of lighting process over all lights
  1581.              shaded_color;            // final color
  1582. float dp,     // dot product 
  1583.       dist,   // distance from light to surface
  1584.       i,      // general intensities
  1585.       nl,     // length of normal
  1586.       atten;  // attenuation computations
  1587. // for each valid poly, light it...
  1588. for (int poly=0; poly < rend_list->num_polys; poly++)
  1589.     {
  1590.     // acquire polygon
  1591.     POLYF4DV1_PTR curr_poly = rend_list->poly_ptrs[poly];
  1592.     // light this polygon if and only if it's not clipped, not culled,
  1593.     // active, and visible
  1594.     if (!(curr_poly->state & POLY4DV1_STATE_ACTIVE) ||
  1595.          (curr_poly->state & POLY4DV1_STATE_CLIPPED ) ||
  1596.          (curr_poly->state & POLY4DV1_STATE_BACKFACE) )
  1597.        continue; // move onto next poly
  1598.    
  1599.     // we will use the transformed polygon vertex list since the backface removal
  1600.     // only makes sense at the world coord stage further of the pipeline 
  1601.     // test the lighting mode of the polygon (use flat for flat, gouraud))
  1602.     if (curr_poly->attr & POLY4DV1_ATTR_SHADE_MODE_FLAT || curr_poly->attr & POLY4DV1_ATTR_SHADE_MODE_GOURAUD)
  1603.        {
  1604.        // step 1: extract the base color out in RGB mode (it's already in 8 bits per channel)
  1605.        r_base = palette[curr_poly->color].peRed;
  1606.        g_base = palette[curr_poly->color].peGreen;
  1607.        b_base = palette[curr_poly->color].peBlue;
  1608.        // initialize color sum
  1609.        r_sum  = 0;
  1610.        g_sum  = 0;
  1611.        b_sum  = 0;
  1612.        // loop thru lights
  1613.        for (int curr_light = 0; curr_light < max_lights; curr_light++)
  1614.            {
  1615.            // is this light active
  1616.            if (lights[curr_light].state==LIGHTV1_STATE_OFF)
  1617.               continue;
  1618.            // what kind of light are we dealing with
  1619.            if (lights[curr_light].attr & LIGHTV1_ATTR_AMBIENT)
  1620.               {
  1621.               // simply multiply each channel against the color of the 
  1622.               // polygon then divide by 256 to scale back to 0..255
  1623.               // use a shift in real life!!! >> 8
  1624.               r_sum+= ((lights[curr_light].c_ambient.r * r_base) / 256);
  1625.               g_sum+= ((lights[curr_light].c_ambient.g * g_base) / 256);
  1626.               b_sum+= ((lights[curr_light].c_ambient.b * b_base) / 256);
  1627.               // there better only be one ambient light!
  1628.               } // end if
  1629.            else
  1630.            if (lights[curr_light].attr & LIGHTV1_ATTR_INFINITE)
  1631.               {
  1632.               // infinite lighting, we need the surface normal, and the direction
  1633.               // of the light source
  1634.               // we need to compute the normal of this polygon face, and recall
  1635.               // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  1636.               VECTOR4D u, v, n;
  1637.  
  1638.               // build u, v
  1639.               VECTOR4D_Build(&curr_poly->tvlist[0], &curr_poly->tvlist[1], &u);
  1640.               VECTOR4D_Build(&curr_poly->tvlist[0], &curr_poly->tvlist[2], &v);
  1641.               // compute cross product
  1642.               VECTOR4D_Cross(&u, &v, &n);
  1643.               // at this point, we are almost ready, but we have to normalize the normal vector!
  1644.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  1645.               // normals, so this step can be optimized
  1646.               // compute length of normal
  1647.               nl = VECTOR4D_Length_Fast(&n);
  1648.       
  1649.               // ok, recalling the lighting model for infinite lights
  1650.               // I(d)dir = I0dir * Cldir
  1651.               // and for the diffuse model
  1652.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  1653.               // so we basically need to multiple it all together
  1654.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  1655.               // are slower, but the conversion to and from cost cycles
  1656.               dp = VECTOR4D_Dot(&n, &lights[curr_light].dir);
  1657.               
  1658.               // only add light if dp > 0
  1659.               if (dp > 0)
  1660.                  { 
  1661.                  i = 128*dp/nl; 
  1662.                  r_sum+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1663.                  g_sum+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1664.                  b_sum+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1665.                  } // end if
  1666.               } // end if infinite light
  1667.            else
  1668.            if (lights[curr_light].attr & LIGHTV1_ATTR_POINT)
  1669.               {
  1670.               // perform point light computations
  1671.               // light model for point light is once again:
  1672.               //              I0point * Clpoint
  1673.               //  I(d)point = ___________________
  1674.               //              kc +  kl*d + kq*d2              
  1675.               //
  1676.               //  Where d = |p - s|
  1677.               // thus it's almost identical to the infinite light, but attenuates as a function
  1678.               // of distance from the point source to the surface point being lit
  1679.               // we need to compute the normal of this polygon face, and recall
  1680.               // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  1681.               VECTOR4D u, v, n, l;
  1682.  
  1683.               // build u, v
  1684.               VECTOR4D_Build(&curr_poly->tvlist[0], &curr_poly->tvlist[1], &u);
  1685.               VECTOR4D_Build(&curr_poly->tvlist[0], &curr_poly->tvlist[2], &v);
  1686.               // compute cross product
  1687.               VECTOR4D_Cross(&u, &v, &n);
  1688.               // at this point, we are almost ready, but we have to normalize the normal vector!
  1689.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  1690.               // normals, so this step can be optimized
  1691.               // compute length of normal
  1692.               nl = VECTOR4D_Length_Fast(&n);
  1693.              
  1694.               // compute vector from surface to light
  1695.               VECTOR4D_Build(&curr_poly->tvlist[0], &lights[curr_light].pos, &l);
  1696.               // compute distance and attenuation
  1697.               dist = VECTOR4D_Length_Fast(&l);  
  1698.               // and for the diffuse model
  1699.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  1700.               // so we basically need to multiple it all together
  1701.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  1702.               // are slower, but the conversion to and from cost cycles
  1703.               dp = VECTOR4D_Dot(&n, &l);
  1704.               
  1705.               // only add light if dp > 0
  1706.               if (dp > 0)
  1707.                  { 
  1708.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  1709.                  i = 128*dp / (nl * dist * atten ); 
  1710.                  r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1711.                  g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1712.                  b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1713.                  } // end if
  1714.               } // end if point
  1715.            else
  1716.            if (lights[curr_light].attr & LIGHTV1_ATTR_SPOTLIGHT1)
  1717.               {
  1718.               // perform spotlight/point computations simplified model that uses
  1719.               // point light WITH a direction to simulate a spotlight
  1720.               // light model for point light is once again:
  1721.               //              I0point * Clpoint
  1722.               //  I(d)point = ___________________
  1723.               //              kc +  kl*d + kq*d2              
  1724.               //
  1725.               //  Where d = |p - s|
  1726.               // thus it's almost identical to the infinite light, but attenuates as a function
  1727.               // of distance from the point source to the surface point being lit
  1728.               // we need to compute the normal of this polygon face, and recall
  1729.               // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  1730.               VECTOR4D u, v, n, l;
  1731.  
  1732.               // build u, v
  1733.               VECTOR4D_Build(&curr_poly->tvlist[0], &curr_poly->tvlist[1], &u);
  1734.               VECTOR4D_Build(&curr_poly->tvlist[0], &curr_poly->tvlist[2], &v);
  1735.               // compute cross product (we need -n, so do vxu)
  1736.               VECTOR4D_Cross(&v, &u, &n);
  1737.               // at this point, we are almost ready, but we have to normalize the normal vector!
  1738.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  1739.               // normals, so this step can be optimized
  1740.               // compute length of normal
  1741.               nl = VECTOR4D_Length_Fast(&n);
  1742.              
  1743.               // compute vector from surface to light
  1744.               VECTOR4D_Build(&curr_poly->tvlist[0], &lights[curr_light].pos, &l);
  1745.               // compute distance and attenuation
  1746.               dist = VECTOR4D_Length_Fast(&l);  
  1747.               // and for the diffuse model
  1748.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  1749.               // so we basically need to multiple it all together
  1750.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  1751.               // are slower, but the conversion to and from cost cycles
  1752.               // note that I use the direction of the light here rather than a the vector to the light
  1753.               // thus we are taking orientation into account which is similar to the spotlight model
  1754.               dp = VECTOR4D_Dot(&n, &lights[curr_light].dir);
  1755.               
  1756.               // only add light if dp > 0
  1757.               if (dp > 0)
  1758.                  { 
  1759.                  atten =  (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  1760.                  i = 128*dp / (nl * atten ); 
  1761.                  r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1762.                  g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1763.                  b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1764.                  } // end if
  1765.               } // end if spotlight1
  1766.            else
  1767.            if (lights[curr_light].attr & LIGHTV1_ATTR_SPOTLIGHT2) // simple version
  1768.               {
  1769.               // perform spot light computations
  1770.               // light model for spot light simple version is once again:
  1771.               //               I0spotlight * Clspotlight * MAX( (l . s), 0)^pf                     
  1772.               // I(d)spotlight = __________________________________________      
  1773.               //                 kc + kl*d + kq*d2        
  1774.               // Where d = |p - s|, and pf = power factor
  1775.               // thus it's almost identical to the point, but has the extra term in the numerator
  1776.               // relating the angle between the light source and the point on the surface
  1777.               // we need to compute the normal of this polygon face, and recall
  1778.               // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  1779.               VECTOR4D u, v, n, d, s;
  1780.  
  1781.               // build u, v
  1782.               VECTOR4D_Build(&curr_poly->tvlist[0], &curr_poly->tvlist[1], &u);
  1783.               VECTOR4D_Build(&curr_poly->tvlist[0], &curr_poly->tvlist[2], &v);
  1784.               // compute cross product (v x u, to invert n)
  1785.               VECTOR4D_Cross(&v, &u, &n);
  1786.               // at this point, we are almost ready, but we have to normalize the normal vector!
  1787.               // this is a key optimization we can make later, we can pre-compute the length of all polygon
  1788.               // normals, so this step can be optimized
  1789.               // compute length of normal
  1790.               nl = VECTOR4D_Length_Fast(&n);
  1791.              
  1792.               // and for the diffuse model
  1793.               // Itotald =   Rsdiffuse*Idiffuse * (n . l)
  1794.               // so we basically need to multiple it all together
  1795.               // notice the scaling by 128, I want to avoid floating point calculations, not because they 
  1796.               // are slower, but the conversion to and from cost cycles
  1797.               dp = VECTOR4D_Dot(&n, &lights[curr_light].dir);
  1798.               
  1799.               // only add light if dp > 0
  1800.               if (dp > 0)
  1801.                  { 
  1802.                  // compute vector from light to surface (different from l which IS the light dir)
  1803.                  VECTOR4D_Build( &lights[curr_light].pos, &curr_poly->tvlist[0], &s);
  1804.                  // compute length of s (distance to light source) to normalize s for lighting calc
  1805.                  dist = VECTOR4D_Length_Fast(&s);  
  1806.                  // compute spot light term (s . l)
  1807.                  float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].dir)/dist;
  1808.                  // proceed only if term is positive
  1809.                  if (dpsl > 0) 
  1810.                     {
  1811.                     // compute attenuation
  1812.                     atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);    
  1813.        
  1814.                     // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
  1815.                     // must be integral
  1816.                     float dpsl_exp = dpsl;
  1817.  
  1818.                     // exponentiate for positive integral powers
  1819.                     for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
  1820.                          dpsl_exp*=dpsl;
  1821.                     // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf 
  1822.                                                       
  1823.                     i = 128*dp * dpsl_exp / (nl * atten ); 
  1824.                     r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
  1825.                     g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
  1826.                     b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
  1827.   
  1828.                     } // end if
  1829.                  } // end if
  1830.               } // end if spot light
  1831.            } // end for light
  1832.   
  1833.        // make sure colors aren't out of range
  1834.        if (r_sum  > 255) r_sum = 255;
  1835.        if (g_sum  > 255) g_sum = 255;
  1836.        if (b_sum  > 255) b_sum = 255;
  1837.        // look color up
  1838.        int rgbindex = RGB16Bit565(r_sum, g_sum, b_sum);          
  1839.        // write the color over current color
  1840.        curr_poly->color = rgblookup[rgbindex];
  1841.        } // end if
  1842.     else // assume POLY4DV1_ATTR_SHADE_MODE_CONSTANT
  1843.        {
  1844.        // emmisive shading only, do nothing
  1845.        // ...
  1846.        } // end if
  1847.     } // end for poly
  1848. // return success
  1849. return(1);
  1850. } // end Light_RENDERLIST4DV1_World
  1851. ///////////////////////////////////////////////////////////////////////////////
  1852. void Sort_RENDERLIST4DV1(RENDERLIST4DV1_PTR rend_list, int sort_method)
  1853. {
  1854. // this function sorts the rendering list based on the polygon z-values 
  1855. // the specific sorting method is controlled by sending in control flags
  1856. // #define SORT_POLYLIST_AVGZ  0 - sorts on average of all vertices
  1857. // #define SORT_POLYLIST_NEARZ 1 - sorts on closest z vertex of each poly
  1858. // #define SORT_POLYLIST_FARZ  2 - sorts on farthest z vertex of each poly
  1859. switch(sort_method)
  1860.       {
  1861.       case SORT_POLYLIST_AVGZ:  //  - sorts on average of all vertices
  1862.            {
  1863.            qsort((void *)rend_list->poly_ptrs, rend_list->num_polys, sizeof(POLYF4DV1_PTR), Compare_AvgZ_POLYF4DV1);
  1864.            } break;
  1865.       case SORT_POLYLIST_NEARZ: // - sorts on closest z vertex of each poly
  1866.            {
  1867.            qsort((void *)rend_list->poly_ptrs, rend_list->num_polys, sizeof(POLYF4DV1_PTR), Compare_NearZ_POLYF4DV1);
  1868.            } break;
  1869.       case SORT_POLYLIST_FARZ:  //  - sorts on farthest z vertex of each poly
  1870.            {
  1871.            qsort((void *)rend_list->poly_ptrs, rend_list->num_polys, sizeof(POLYF4DV1_PTR), Compare_FarZ_POLYF4DV1);
  1872.            } break;
  1873.        default: break;
  1874.        } // end switch
  1875. } // end Sort_RENDERLIST4DV1
  1876. ////////////////////////////////////////////////////////////////////////////////
  1877. int Compare_AvgZ_POLYF4DV1(const void *arg1, const void *arg2)
  1878. {
  1879. // this function comapares the average z's of two polygons and is used by the
  1880. // depth sort surface ordering algorithm
  1881. float z1, z2;
  1882. POLYF4DV1_PTR poly_1, poly_2;
  1883. // dereference the poly pointers
  1884. poly_1 = *((POLYF4DV1_PTR *)(arg1));
  1885. poly_2 = *((POLYF4DV1_PTR *)(arg2));
  1886. // compute z average of each polygon
  1887. z1 = (float)0.33333*(poly_1->tvlist[0].z + poly_1->tvlist[1].z + poly_1->tvlist[2].z);
  1888. // now polygon 2
  1889. z2 = (float)0.33333*(poly_2->tvlist[0].z + poly_2->tvlist[1].z + poly_2->tvlist[2].z);
  1890. // compare z1 and z2, such that polys' will be sorted in descending Z order
  1891. if (z1 > z2)
  1892.    return(-1);
  1893. else
  1894. if (z1 < z2)
  1895.    return(1);
  1896. else
  1897.    return(0);
  1898. } // end Compare_AvgZ_POLYF4DV1
  1899. ////////////////////////////////////////////////////////////////////////////////
  1900. int Compare_NearZ_POLYF4DV1(const void *arg1, const void *arg2)
  1901. {
  1902. // this function comapares the closest z's of two polygons and is used by the
  1903. // depth sort surface ordering algorithm
  1904. float z1, z2;
  1905. POLYF4DV1_PTR poly_1, poly_2;
  1906. // dereference the poly pointers
  1907. poly_1 = *((POLYF4DV1_PTR *)(arg1));
  1908. poly_2 = *((POLYF4DV1_PTR *)(arg2));
  1909. // compute the near z of each polygon
  1910. z1 = MIN(poly_1->tvlist[0].z, poly_1->tvlist[1].z);
  1911. z1 = MIN(z1, poly_1->tvlist[2].z);
  1912. z2 = MIN(poly_2->tvlist[0].z, poly_2->tvlist[1].z);
  1913. z2 = MIN(z2, poly_2->tvlist[2].z);
  1914. // compare z1 and z2, such that polys' will be sorted in descending Z order
  1915. if (z1 > z2)
  1916.    return(-1);
  1917. else
  1918. if (z1 < z2)
  1919.    return(1);
  1920. else
  1921.    return(0);
  1922. } // end Compare_NearZ_POLYF4DV1
  1923. ////////////////////////////////////////////////////////////////////////////////
  1924. int Compare_FarZ_POLYF4DV1(const void *arg1, const void *arg2)
  1925. {
  1926. // this function comapares the farthest z's of two polygons and is used by the
  1927. // depth sort surface ordering algorithm
  1928. float z1, z2;
  1929. POLYF4DV1_PTR poly_1, poly_2;
  1930. // dereference the poly pointers
  1931. poly_1 = *((POLYF4DV1_PTR *)(arg1));
  1932. poly_2 = *((POLYF4DV1_PTR *)(arg2));
  1933. // compute the near z of each polygon
  1934. z1 = MAX(poly_1->tvlist[0].z, poly_1->tvlist[1].z);
  1935. z1 = MAX(z1, poly_1->tvlist[2].z);
  1936. z2 = MAX(poly_2->tvlist[0].z, poly_2->tvlist[1].z);
  1937. z2 = MAX(z2, poly_2->tvlist[2].z);
  1938. // compare z1 and z2, such that polys' will be sorted in descending Z order
  1939. if (z1 > z2)
  1940.    return(-1);
  1941. else
  1942. if (z1 < z2)
  1943.    return(1);
  1944. else
  1945.    return(0);
  1946. } // end Compare_FarZ_POLYF4DV1