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

游戏

开发平台:

Visual C++

  1.    // finally write out the correct number of bits
  2.    bitmap->bitmapinfoheader.biBitCount=16;
  3.    // release working buffer
  4.    free(temp_buffer);
  5.    } // end if 24 bit
  6. else
  7.    {
  8.    // serious problem
  9.    return(0);
  10.    } // end else
  11. #if 0
  12. // write the file info out 
  13. printf("nfilename:%s nsize=%d nwidth=%d nheight=%d nbitsperpixel=%d ncolors=%d nimpcolors=%d",
  14.         filename,
  15.         bitmap->bitmapinfoheader.biSizeImage,
  16.         bitmap->bitmapinfoheader.biWidth,
  17.         bitmap->bitmapinfoheader.biHeight,
  18. bitmap->bitmapinfoheader.biBitCount,
  19.         bitmap->bitmapinfoheader.biClrUsed,
  20.         bitmap->bitmapinfoheader.biClrImportant);
  21. #endif
  22. // close the file
  23. _lclose(file_handle);
  24. // flip the bitmap
  25. Flip_Bitmap(bitmap->buffer, 
  26.             bitmap->bitmapinfoheader.biWidth*(bitmap->bitmapinfoheader.biBitCount/8), 
  27.             bitmap->bitmapinfoheader.biHeight);
  28. // return success
  29. return(1);
  30. } // end Load_Bitmap_File
  31. ///////////////////////////////////////////////////////////
  32. int Unload_Bitmap_File(BITMAP_FILE_PTR bitmap)
  33. {
  34. // this function releases all memory associated with "bitmap"
  35. if (bitmap->buffer)
  36.    {
  37.    // release memory
  38.    free(bitmap->buffer);
  39.    // reset pointer
  40.    bitmap->buffer = NULL;
  41.    } // end if
  42. // return success
  43. return(1);
  44. } // end Unload_Bitmap_File
  45. ///////////////////////////////////////////////////////////
  46. int Flip_Bitmap(UCHAR *image, int bytes_per_line, int height)
  47. {
  48. // this function is used to flip bottom-up .BMP images
  49. UCHAR *buffer; // used to perform the image processing
  50. int index;     // looping index
  51. // allocate the temporary buffer
  52. if (!(buffer = (UCHAR *)malloc(bytes_per_line*height)))
  53.    return(0);
  54. // copy image to work area
  55. memcpy(buffer,image,bytes_per_line*height);
  56. // flip vertically
  57. for (index=0; index < height; index++)
  58.     memcpy(&image[((height-1) - index)*bytes_per_line],
  59.            &buffer[index*bytes_per_line], bytes_per_line);
  60. // release the memory
  61. free(buffer);
  62. // return success
  63. return(1);
  64. } // end Flip_Bitmap
  65. ///////////////////////////////////////////////////////////
  66. void HLine16(int x1,int x2,int y,int color, UCHAR *vbuffer, int lpitch)
  67. {
  68. // draw a horizontal line using the memset function
  69. int temp; // used for temporary storage during endpoint swap
  70. USHORT *vbuffer2 = (USHORT *)vbuffer; // short pointer to buffer
  71. // convert pitch to words
  72. lpitch = lpitch >> 1;
  73. // perform trivial rejections
  74. if (y > max_clip_y || y < min_clip_y)
  75.    return;
  76. // sort x1 and x2, so that x2 > x1
  77. if (x1>x2)
  78.    {
  79.    temp = x1;
  80.    x1   = x2;
  81.    x2   = temp;
  82.    } // end swap
  83. // perform trivial rejections
  84. if (x1 > max_clip_x || x2 < min_clip_x)
  85.    return;
  86. // now clip
  87. x1 = ((x1 < min_clip_x) ? min_clip_x : x1);
  88. x2 = ((x2 > max_clip_x) ? max_clip_x : x2);
  89. // draw the row of pixels
  90. Mem_Set_WORD((vbuffer2+(y*lpitch)+x1), color,x2-x1+1);
  91. } // end HLine16
  92. //////////////////////////////////////////////////////////////////////////////
  93. void VLine16(int y1,int y2,int x,int color,UCHAR *vbuffer, int lpitch)
  94. {
  95. // draw a vertical line, note that a memset function can no longer be
  96. // used since the pixel addresses are no longer contiguous in memory
  97. // note that the end points of the line must be on the screen
  98. USHORT *start_offset; // starting memory offset of line
  99. int index, // loop index
  100.     temp;  // used for temporary storage during swap
  101. // convert lpitch to number of words
  102. lpitch = lpitch >> 1;
  103. // perform trivial rejections
  104. if (x > max_clip_x || x < min_clip_x)
  105.    return;
  106. // make sure y2 > y1
  107. if (y1>y2)
  108.    {
  109.    temp = y1;
  110.    y1   = y2;
  111.    y2   = temp;
  112.    } // end swap
  113. // perform trivial rejections
  114. if (y1 > max_clip_y || y2 < min_clip_y)
  115.    return;
  116. // now clip
  117. y1 = ((y1 < min_clip_y) ? min_clip_y : y1);
  118. y2 = ((y2 > max_clip_y) ? max_clip_y : y2);
  119. // compute starting position
  120. start_offset = (USHORT *)vbuffer + (y1*lpitch) + x;
  121. // draw line one pixel at a time
  122. for (index=0; index<=y2-y1; index++)
  123.     {
  124.     // set the pixel
  125.     *start_offset = color;
  126.     // move downward to next line
  127.     start_offset+=lpitch;
  128.     } // end for index
  129. } // end VLine16
  130. ///////////////////////////////////////////////////////////
  131. void HLine(int x1,int x2,int y,int color, UCHAR *vbuffer, int lpitch)
  132. {
  133. // draw a horizontal line using the memset function
  134. int temp; // used for temporary storage during endpoint swap
  135. // perform trivial rejections
  136. if (y > max_clip_y || y < min_clip_y)
  137.    return;
  138. // sort x1 and x2, so that x2 > x1
  139. if (x1>x2)
  140.    {
  141.    temp = x1;
  142.    x1   = x2;
  143.    x2   = temp;
  144.    } // end swap
  145. // perform trivial rejections
  146. if (x1 > max_clip_x || x2 < min_clip_x)
  147.    return;
  148. // now clip
  149. x1 = ((x1 < min_clip_x) ? min_clip_x : x1);
  150. x2 = ((x2 > max_clip_x) ? max_clip_x : x2);
  151. // draw the row of pixels
  152. memset((UCHAR *)(vbuffer+(y*lpitch)+x1),
  153.        (UCHAR)color,x2-x1+1);
  154. } // end HLine
  155. //////////////////////////////////////////////////////////////////////////////
  156. void VLine(int y1,int y2,int x,int color,UCHAR *vbuffer, int lpitch)
  157. {
  158. // draw a vertical line, note that a memset function can no longer be
  159. // used since the pixel addresses are no longer contiguous in memory
  160. // note that the end points of the line must be on the screen
  161. UCHAR *start_offset; // starting memory offset of line
  162. int index, // loop index
  163.     temp;  // used for temporary storage during swap
  164. // perform trivial rejections
  165. if (x > max_clip_x || x < min_clip_x)
  166.    return;
  167. // make sure y2 > y1
  168. if (y1>y2)
  169.    {
  170.    temp = y1;
  171.    y1   = y2;
  172.    y2   = temp;
  173.    } // end swap
  174. // perform trivial rejections
  175. if (y1 > max_clip_y || y2 < min_clip_y)
  176.    return;
  177. // now clip
  178. y1 = ((y1 < min_clip_y) ? min_clip_y : y1);
  179. y2 = ((y2 > max_clip_y) ? max_clip_y : y2);
  180. // compute starting position
  181. start_offset = vbuffer + (y1*lpitch) + x;
  182. // draw line one pixel at a time
  183. for (index=0; index<=y2-y1; index++)
  184.     {
  185.     // set the pixel
  186.     *start_offset = (UCHAR)color;
  187.     // move downward to next line
  188.     start_offset+=lpitch;
  189.     } // end for index
  190. } // end VLine
  191. ///////////////////////////////////////////////////////////
  192. void Screen_Transitions(int effect, UCHAR *vbuffer, int lpitch)
  193. {
  194. // this function can be called to perform a myraid of screen transitions
  195. // to the destination buffer, make sure to save and restore the palette
  196. // when performing color transitions in 8-bit modes
  197. int pal_reg;         // used as loop counter
  198. int index;           // used as loop counter
  199. int red,green,blue;           // used in fad algorithm
  200. PALETTEENTRY color;              // temporary color
  201. PALETTEENTRY work_palette[MAX_COLORS_PALETTE];  // used as a working palette
  202. PALETTEENTRY work_color;         // used in color algorithms
  203. // test which screen effect is being selected
  204. switch(effect)
  205.       {
  206.       case SCREEN_DARKNESS:
  207.            {
  208.            // fade to black
  209.            for (index=0; index<80; index++)
  210.                {
  211.                // get the palette 
  212.                Save_Palette(work_palette);
  213.                // process each color
  214.                for (pal_reg=1; pal_reg<MAX_COLORS_PALETTE; pal_reg++)
  215.                    {
  216.                    // get the entry data
  217.                    color = work_palette[pal_reg];
  218.                    // test if this color register is already black
  219.                    if (color.peRed > 4) color.peRed-=3;
  220.                    else
  221.                       color.peRed = 0;
  222.                    if (color.peGreen > 4) color.peGreen-=3;
  223.                    else
  224.                       color.peGreen = 0;
  225.                    if (color.peBlue  > 4) color.peBlue-=3;
  226.                    else
  227.                       color.peBlue = 0;
  228.                    // set the color to a diminished intensity
  229.                    work_palette[pal_reg] = color;
  230.                    } // end for pal_reg
  231.                // write the palette back out
  232.                Set_Palette(work_palette);
  233.                // wait a bit
  234.                
  235.                Start_Clock(); Wait_Clock(12);
  236.                
  237.                } // end for index
  238.            } break;
  239.       case SCREEN_WHITENESS:
  240.            {
  241.            // fade to white
  242.            for (index=0; index<64; index++)
  243.                {
  244.                // get the palette 
  245.                Save_Palette(work_palette);
  246.                // loop thru all palette registers
  247.                for (pal_reg=0; pal_reg < MAX_COLORS_PALETTE; pal_reg++)
  248.                    {
  249.                    // get the entry data
  250.                    color = work_palette[pal_reg];
  251.                    // make 32 bit copy of color
  252.                    red   = color.peRed;
  253.                    green = color.peGreen;
  254.                    blue  = color.peBlue; 
  255.                    if ((red+=4) >=255)
  256.                       red=255;
  257.                    if ((green+=4) >=255)
  258.                       green=255;
  259.                    if ((blue+=4) >=255)
  260.                       blue=255;
  261.                           
  262.                    // store colors back
  263.                    color.peRed   = red;
  264.                    color.peGreen = green;
  265.                    color.peBlue  = blue;
  266.                    // set the color to a diminished intensity
  267.                    work_palette[pal_reg] = color;
  268.                    
  269.                    } // end for pal_reg
  270.                // write the palette back out
  271.                Set_Palette(work_palette);
  272.                // wait a bit
  273.                
  274.                Start_Clock(); Wait_Clock(12);
  275.                } // end for index
  276.            } break;
  277.       case SCREEN_REDNESS:
  278.            {
  279.            // fade to red
  280.            for (index=0; index<64; index++)
  281.                {
  282.                // get the palette 
  283.                Save_Palette(work_palette);
  284.                
  285.                // loop thru all palette registers
  286.                for (pal_reg=0; pal_reg < MAX_COLORS_PALETTE; pal_reg++)
  287.                    {
  288.                    // get the entry data
  289.                    color = work_palette[pal_reg];
  290.                    // make 32 bit copy of color
  291.                    red   = color.peRed;
  292.                    green = color.peGreen;
  293.                    blue  = color.peBlue; 
  294.                    if ((red+=6) >=255)
  295.                       red=255; 
  296.                    if ((green-=4) < 0)
  297.                       green=0;
  298.                    if ((blue-=4) < 0)
  299.                       blue=0;
  300.                           
  301.                    // store colors back
  302.                    color.peRed   = red;
  303.                    color.peGreen = green;
  304.                    color.peBlue  = blue;
  305.                   
  306.                    // set the color to a diminished intensity
  307.                    work_palette[pal_reg] = color;
  308.                    } // end for pal_reg
  309.                // write the palette back out
  310.                Set_Palette(work_palette);
  311.                // wait a bit
  312.                
  313.                Start_Clock(); Wait_Clock(12);
  314.                } // end for index
  315.            } break;
  316.       case SCREEN_BLUENESS:
  317.            {
  318.            // fade to blue
  319.            for (index=0; index<64; index++)
  320.                {
  321.                // get the palette 
  322.                Save_Palette(work_palette);
  323.                
  324.                // loop thru all palette registers
  325.                for (pal_reg=0; pal_reg < MAX_COLORS_PALETTE; pal_reg++)
  326.                    {
  327.                    // get the entry data
  328.                    color = work_palette[pal_reg];
  329.                    // make 32 bit copy of color
  330.                    red   = color.peRed;
  331.                    green = color.peGreen;
  332.                    blue  = color.peBlue; 
  333.                    if ((red-=4) < 0)
  334.                       red=0;
  335.                    if ((green-=4) < 0)
  336.                       green=0;
  337.                    if ((blue+=6) >=255)
  338.                       blue=255;
  339.                           
  340.                    // store colors back
  341.                    color.peRed   = red;
  342.                    color.peGreen = green;
  343.                    color.peBlue  = blue;
  344.                   
  345.                    // set the color to a diminished intensity
  346.                    work_palette[pal_reg] = color;
  347.                    } // end for pal_reg
  348.                // write the palette back out
  349.                Set_Palette(work_palette);
  350.                // wait a bit
  351.                
  352.                Start_Clock(); Wait_Clock(12);
  353.                } // end for index
  354.            } break;
  355.       case SCREEN_GREENNESS:
  356.            {
  357.            // fade to green
  358.            for (index=0; index<64; index++)
  359.                {
  360.                // get the palette 
  361.                Save_Palette(work_palette);
  362.                // loop thru all palette registers
  363.                for (pal_reg=0; pal_reg < MAX_COLORS_PALETTE; pal_reg++)
  364.                    {
  365.                    // get the entry data
  366.                    color = work_palette[pal_reg];                  
  367.                    // make 32 bit copy of color
  368.                    red   = color.peRed;
  369.                    green = color.peGreen;
  370.                    blue  = color.peBlue; 
  371.                    if ((red-=4) < 0)
  372.                       red=0;
  373.                    if ((green+=6) >=255)
  374.                       green=255;
  375.                    if ((blue-=4) < 0)
  376.                       blue=0;
  377.                           
  378.                    // store colors back
  379.                    color.peRed   = red;
  380.                    color.peGreen = green;
  381.                    color.peBlue  = blue;
  382.                    // set the color to a diminished intensity
  383.                    work_palette[pal_reg] = color; 
  384.                    } // end for pal_reg
  385.                // write the palette back out
  386.                Set_Palette(work_palette);
  387.                // wait a bit
  388.                
  389.                Start_Clock(); Wait_Clock(12);
  390.                } // end for index
  391.            } break;
  392.       case SCREEN_SWIPE_X:
  393.            {
  394.            // do a screen wipe from right to left, left to right
  395.            for (index=0; index < (screen_width/2); index+=2)
  396.                {
  397.                // use this as a 1/70th of second time delay
  398.                
  399.                Start_Clock(); Wait_Clock(12);
  400.                // test screen depth
  401.                if (screen_bpp==8)
  402.                {    
  403.                // draw two vertical lines at opposite ends of the screen
  404.                VLine(0,(screen_height-1),(screen_width-1)-index,0,vbuffer,lpitch);
  405.                VLine(0,(screen_height-1),index,0,vbuffer,lpitch);
  406.                VLine(0,(screen_height-1),(screen_width-1)-(index+1),0,vbuffer,lpitch);
  407.                VLine(0,(screen_height-1),index+1,0,vbuffer,lpitch);
  408.                } // end if 8-bit mode
  409.                else
  410.                if (screen_bpp==16)
  411.                {    
  412.                // 16-bit mode draw two vertical lines at opposite ends of the screen
  413.                VLine16(0,(screen_height-1),(screen_width-1)-index,0,vbuffer,lpitch);
  414.                VLine16(0,(screen_height-1),index,0,vbuffer,lpitch);
  415.                VLine16(0,(screen_height-1),(screen_width-1)-(index+1),0,vbuffer,lpitch);
  416.                VLine16(0,(screen_height-1),index+1,0,vbuffer,lpitch);
  417.                } // end if 16-bit mode
  418.                } // end for index
  419.            } break;
  420.       case SCREEN_SWIPE_Y:
  421.            {
  422.            // do a screen wipe from top to bottom, bottom to top
  423.            for (index=0; index < (screen_height/2); index+=2)
  424.                {
  425.                // use this as a 1/70th of second time delay
  426.                
  427.                Start_Clock(); Wait_Clock(12);
  428.                // test screen depth             
  429.                if (screen_bpp==8)
  430.                {
  431.                // draw two horizontal lines at opposite ends of the screen
  432.                HLine(0,(screen_width-1),(screen_height-1)-index,0,vbuffer,lpitch);
  433.                HLine(0,(screen_width-1),index,0,vbuffer,lpitch);
  434.                HLine(0,(screen_width-1),(screen_height-1)-(index+1),0,vbuffer,lpitch);
  435.                HLine(0,(screen_width-1),index+1,0,vbuffer,lpitch);
  436.                } // end if 8-bit mode
  437.                else 
  438.                if (screen_bpp==16)
  439.                {
  440.                // draw two horizontal lines at opposite ends of the screen
  441.                HLine16(0,(screen_width-1),(screen_height-1)-index,0,vbuffer,lpitch);
  442.                HLine16(0,(screen_width-1),index,0,vbuffer,lpitch);
  443.                HLine16(0,(screen_width-1),(screen_height-1)-(index+1),0,vbuffer,lpitch);
  444.                HLine16(0,(screen_width-1),index+1,0,vbuffer,lpitch);
  445.                } // end if 16-bit mode
  446.                } // end for index
  447.             } break;
  448.       case SCREEN_SCRUNCH:
  449.            {
  450.            // do a screen wipe from top to bottom, bottom to top
  451.            for (index=0; index < (screen_width/2); index+=2)
  452.                {
  453.                // use this as a 1/70th of second time delay
  454.                
  455.                Start_Clock(); Wait_Clock(12);
  456.                // test screen depth             
  457.                if (screen_bpp==8)
  458.                { 
  459.                // draw two horizontal lines at opposite ends of the screen
  460.                HLine(0,(screen_width-1),(screen_height-1)-index%(screen_height/2),0,vbuffer,lpitch);
  461.                HLine(0,(screen_width-1),index%(screen_height/2),0,vbuffer,lpitch);
  462.                HLine(0,(screen_width-1),(screen_height-1)-(index%(screen_height/2)+1),0,vbuffer,lpitch);
  463.                HLine(0,(screen_width-1),index%(screen_height/2)+1,0,vbuffer,lpitch);
  464.                // draw two vertical lines at opposite ends of the screen
  465.                VLine(0,(screen_height-1),(screen_width-1)-index,0,vbuffer,lpitch);
  466.                VLine(0,(screen_height-1),index,0,vbuffer,lpitch);
  467.                VLine(0,(screen_height-1),(screen_width-1)-(index+1),0,vbuffer,lpitch);
  468.                VLine(0,(screen_height-1),index+1,0,vbuffer,lpitch);
  469.                } // end if 8-bit mode
  470.                else
  471.                // test screen depth             
  472.                if (screen_bpp==16)
  473.                { 
  474.                // draw two horizontal lines at opposite ends of the screen
  475.                HLine16(0,(screen_width-1),(screen_height-1)-index%(screen_height/2),0,vbuffer,lpitch);
  476.                HLine16(0,(screen_width-1),index%(screen_height/2),0,vbuffer,lpitch);
  477.                HLine16(0,(screen_width-1),(screen_height-1)-(index%(screen_height/2)+1),0,vbuffer,lpitch);
  478.                HLine16(0,(screen_width-1),index%(screen_height/2)+1,0,vbuffer,lpitch);
  479.                // draw two vertical lines at opposite ends of the screen
  480.                VLine16(0,(screen_height-1),(screen_width-1)-index,0,vbuffer,lpitch);
  481.                VLine16(0,(screen_height-1),index,0,vbuffer,lpitch);
  482.                VLine16(0,(screen_height-1),(screen_width-1)-(index+1),0,vbuffer,lpitch);
  483.                VLine16(0,(screen_height-1),index+1,0,vbuffer,lpitch);
  484.                } // end if 8-bit mode
  485.                } // end for index
  486.            } break;
  487.       case SCREEN_DISOLVE:
  488.            {
  489.            // disolve the screen by plotting zillions of little black dots
  490.            if (screen_bpp==8)
  491.                for (index=0; index<=screen_width*screen_height*4; index++)
  492.                    Draw_Pixel(rand()%screen_width,rand()%screen_height,0,vbuffer,lpitch);
  493.            else
  494.            if (screen_bpp==16)
  495.                for (index=0; index<=screen_width*screen_height*4; index++)
  496.                    Draw_Pixel16(rand()%screen_width,rand()%screen_height,0,vbuffer,lpitch);
  497.            } break;
  498.        default:break;
  499.       } // end switch
  500. } // end Screen_Transitions
  501. //////////////////////////////////////////////////////////////////////////////
  502. int Collision_Test(int x1, int y1, int w1, int h1, 
  503.                    int x2, int y2, int w2, int h2) 
  504. {
  505. // this function tests if the two rects overlap
  506. // get the radi of each rect
  507. int width1  = (w1>>1) - (w1>>3);
  508. int height1 = (h1>>1) - (h1>>3);
  509. int width2  = (w2>>1) - (w2>>3);
  510. int height2 = (h2>>1) - (h2>>3);
  511. // compute center of each rect
  512. int cx1 = x1 + width1;
  513. int cy1 = y1 + height1;
  514. int cx2 = x2 + width2;
  515. int cy2 = y2 + height2;
  516. // compute deltas
  517. int dx = abs(cx2 - cx1);
  518. int dy = abs(cy2 - cy1);
  519. // test if rects overlap
  520. if (dx < (width1+width2) && dy < (height1+height2))
  521.    return(1);
  522. else
  523. // else no collision
  524. return(0);
  525. } // end Collision_Test
  526. ///////////////////////////////////////////////////////////
  527. int Color_Scan(int x1, int y1, int x2, int y2, 
  528.                UCHAR scan_start, UCHAR scan_end,
  529.                UCHAR *scan_buffer, int scan_lpitch)
  530. {
  531. // this function implements a crude collision technique
  532. // based on scanning for a range of colors within a rectangle
  533. // clip rectangle
  534. // x coords first    
  535. if (x1 >= screen_width)
  536.    x1=screen_width-1;
  537. else
  538. if (x1 < 0)
  539.    x1=0;
  540. if (x2 >= screen_width)
  541.    x2=screen_width-1;
  542. else
  543. if (x2 < 0)
  544.    x2=0;
  545. // now y-coords
  546. if (y1 >= screen_height)
  547.    y1=screen_height-1;
  548. else
  549. if (y1 < 0)
  550.    y1=0;
  551. if (y2 >= screen_height)
  552.    y2=screen_height-1;
  553. else
  554. if (y2 < 0)
  555.    y2=0;
  556. // scan the region
  557. scan_buffer +=y1*scan_lpitch;
  558. for (int scan_y=y1; scan_y<=y2; scan_y++)
  559.     {
  560.     for (int scan_x=x1; scan_x<=x2; scan_x++)
  561.         {
  562.         if (scan_buffer[scan_x] >= scan_start && scan_buffer[scan_x] <= scan_end )
  563.             return(1);
  564.         } // end for x
  565.     // move down a line
  566.     scan_buffer+=scan_lpitch;
  567.     } // end for y
  568. // return failure
  569. return(0);
  570. } // end Color_Scan
  571. ////////////////////////////////////////////////////////////////
  572. int Color_Scan16(int x1, int y1, int x2, int y2, 
  573.                USHORT scan_start, USHORT scan_end,
  574.                UCHAR *scan_buffer, int scan_lpitch)
  575. {
  576. // this function implements a crude collision technique
  577. // based on scanning for a range of colors within a rectangle
  578. // this is the 16-bit version, thus the interpretation of scan_start
  579. // and end are different, they are they EXACT RGB values you are looking
  580. // for, thus you can test for 2 values at most, else make them equal to
  581. // test for one value
  582. USHORT *scan_buffer2 = (USHORT *)scan_buffer;
  583. // convert number of bytes per line to number of 16-bit shorts
  584. scan_lpitch = (scan_lpitch >> 1);
  585. // clip rectangle
  586. // x coords first    
  587. if (x1 >= screen_width)
  588.    x1=screen_width-1;
  589. else
  590. if (x1 < 0)
  591.    x1=0;
  592. if (x2 >= screen_width)
  593.    x2=screen_width-1;
  594. else
  595. if (x2 < 0)
  596.    x2=0;
  597. // now y-coords
  598. if (y1 >= screen_height)
  599.    y1=screen_height-1;
  600. else
  601. if (y1 < 0)
  602.    y1=0;
  603. if (y2 >= screen_height)
  604.    y2=screen_height-1;
  605. else
  606. if (y2 < 0)
  607.    y2=0;
  608. // scan the region
  609. scan_buffer2 +=y1*scan_lpitch;
  610. for (int scan_y=y1; scan_y<=y2; scan_y++)
  611.     {
  612.     for (int scan_x=x1; scan_x<=x2; scan_x++)
  613.         {
  614.         if (scan_buffer2[scan_x] == scan_start || scan_buffer2[scan_x] == scan_end )
  615.             return(1);
  616.         } // end for x
  617.     // move down a line
  618.     scan_buffer2+=scan_lpitch;
  619.     } // end for y
  620. // return failure
  621. return(0);
  622. } // end Color_Scan16
  623. ////////////////////////////////////////////////////////////////
  624. int Scan_Image_Bitmap(BITMAP_FILE_PTR bitmap,     // bitmap file to scan image data from
  625.                       LPDIRECTDRAWSURFACE7 lpdds, // surface to hold data
  626.                       int cx,int cy)              // cell to scan image from
  627. {
  628. // this function extracts a bitmap out of a bitmap file
  629. UCHAR *source_ptr,   // working pointers
  630.       *dest_ptr;
  631. DDSURFACEDESC2 ddsd;  //  direct draw surface description 
  632. // get the addr to destination surface memory
  633. // set size of the structure
  634. ddsd.dwSize = sizeof(ddsd);
  635. // lock the display surface
  636. lpdds->Lock(NULL,
  637.             &ddsd,
  638.             DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,
  639.             NULL);
  640. // compute position to start scanning bits from
  641. cx = cx*(ddsd.dwWidth+1) + 1;
  642. cy = cy*(ddsd.dwHeight+1) + 1;
  643.   
  644. // extract bitmap data
  645. source_ptr = bitmap->buffer + cy*bitmap->bitmapinfoheader.biWidth+cx;
  646. // assign a pointer to the memory surface for manipulation
  647. dest_ptr = (UCHAR *)ddsd.lpSurface;
  648. // iterate thru each scanline and copy bitmap
  649. for (int index_y=0; index_y < ddsd.dwHeight; index_y++)
  650.     {
  651.     // copy next line of data to destination
  652.     memcpy(dest_ptr, source_ptr, ddsd.dwWidth);
  653.     // advance pointers
  654.     dest_ptr   += (ddsd.lPitch);
  655.     source_ptr += bitmap->bitmapinfoheader.biWidth;
  656.     } // end for index_y
  657. // unlock the surface 
  658. lpdds->Unlock(NULL);
  659. // return success
  660. return(1);
  661. } // end Scan_Image_Bitmap
  662. //////////////////////////////////////////////////////////////////////////////
  663. void Draw_Top_Tri(int x1,int y1, 
  664.                   int x2,int y2, 
  665.                   int x3,int y3,
  666.                   int color, 
  667.                   UCHAR *dest_buffer, int mempitch)
  668. {
  669. // this function draws a triangle that has a flat top
  670. float dx_right,    // the dx/dy ratio of the right edge of line
  671.       dx_left,     // the dx/dy ratio of the left edge of line
  672.       xs,xe,       // the starting and ending points of the edges
  673.       height;      // the height of the triangle
  674. int temp_x,        // used during sorting as temps
  675.     temp_y,
  676.     right,         // used by clipping
  677.     left;
  678. // destination address of next scanline
  679. UCHAR  *dest_addr = NULL;
  680. // test order of x1 and x2
  681. if (x2 < x1)
  682.    {
  683.    temp_x = x2;
  684.    x2     = x1;
  685.    x1     = temp_x;
  686.    } // end if swap
  687. // compute delta's
  688. height = y3-y1;
  689. dx_left  = (x3-x1)/height;
  690. dx_right = (x3-x2)/height;
  691. // set starting points
  692. xs = (float)x1;
  693. xe = (float)x2+(float)0.5;
  694. // perform y clipping
  695. if (y1 < min_clip_y)
  696.    {
  697.    // compute new xs and ys
  698.    xs = xs+dx_left*(float)(-y1+min_clip_y);
  699.    xe = xe+dx_right*(float)(-y1+min_clip_y);
  700.    // reset y1
  701.    y1=min_clip_y;
  702.    } // end if top is off screen
  703. if (y3>max_clip_y)
  704.    y3=max_clip_y;
  705. // compute starting address in video memory
  706. dest_addr = dest_buffer+y1*mempitch;
  707. // test if x clipping is needed
  708. if (x1>=min_clip_x && x1<=max_clip_x &&
  709.     x2>=min_clip_x && x2<=max_clip_x &&
  710.     x3>=min_clip_x && x3<=max_clip_x)
  711.     {
  712.     // draw the triangle
  713.     for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  714.         {
  715.         memset((UCHAR *)dest_addr+(unsigned int)xs, color,(unsigned int)((int)xe-(int)xs+1));
  716.         // adjust starting point and ending point
  717.         xs+=dx_left;
  718.         xe+=dx_right;
  719.         } // end for
  720.     } // end if no x clipping needed
  721. else
  722.    {
  723.    // clip x axis with slower version
  724.    // draw the triangle
  725.    for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  726.        {
  727.        // do x clip
  728.        left  = (int)xs;
  729.        right = (int)xe;
  730.        // adjust starting point and ending point
  731.        xs+=dx_left;
  732.        xe+=dx_right;
  733.        // clip line
  734.        if (left < min_clip_x)
  735.           {
  736.           left = min_clip_x;
  737.           if (right < min_clip_x)
  738.              continue;
  739.           }
  740.        if (right > max_clip_x)
  741.           {
  742.           right = max_clip_x;
  743.           if (left > max_clip_x)
  744.              continue;
  745.           }
  746.        memset((UCHAR  *)dest_addr+(unsigned int)left, color,(unsigned int)(right-left+1));
  747.        } // end for
  748.    } // end else x clipping needed
  749. } // end Draw_Top_Tri
  750. /////////////////////////////////////////////////////////////////////////////
  751. void Draw_Bottom_Tri(int x1,int y1, 
  752.                      int x2,int y2, 
  753.                      int x3,int y3,
  754.                      int color,
  755.                      UCHAR *dest_buffer, int mempitch)
  756. {
  757. // this function draws a triangle that has a flat bottom
  758. float dx_right,    // the dx/dy ratio of the right edge of line
  759.       dx_left,     // the dx/dy ratio of the left edge of line
  760.       xs,xe,       // the starting and ending points of the edges
  761.       height;      // the height of the triangle
  762. int temp_x,        // used during sorting as temps
  763.     temp_y,
  764.     right,         // used by clipping
  765.     left;
  766. // destination address of next scanline
  767. UCHAR  *dest_addr;
  768. // test order of x1 and x2
  769. if (x3 < x2)
  770.    {
  771.    temp_x = x2;
  772.    x2     = x3;
  773.    x3     = temp_x;
  774.    } // end if swap
  775. // compute delta's
  776. height = y3-y1;
  777. dx_left  = (x2-x1)/height;
  778. dx_right = (x3-x1)/height;
  779. // set starting points
  780. xs = (float)x1;
  781. xe = (float)x1; // +(float)0.5;
  782. // perform y clipping
  783. if (y1<min_clip_y)
  784.    {
  785.    // compute new xs and ys
  786.    xs = xs+dx_left*(float)(-y1+min_clip_y);
  787.    xe = xe+dx_right*(float)(-y1+min_clip_y);
  788.    // reset y1
  789.    y1=min_clip_y;
  790.    } // end if top is off screen
  791. if (y3>max_clip_y)
  792.    y3=max_clip_y;
  793. // compute starting address in video memory
  794. dest_addr = dest_buffer+y1*mempitch;
  795. // test if x clipping is needed
  796. if (x1>=min_clip_x && x1<=max_clip_x &&
  797.     x2>=min_clip_x && x2<=max_clip_x &&
  798.     x3>=min_clip_x && x3<=max_clip_x)
  799.     {
  800.     // draw the triangle
  801.     for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  802.         {
  803.         memset((UCHAR  *)dest_addr+(unsigned int)xs, color,(unsigned int)((int)xe-(int)xs+1));
  804.         // adjust starting point and ending point
  805.         xs+=dx_left;
  806.         xe+=dx_right;
  807.         } // end for
  808.     } // end if no x clipping needed
  809. else
  810.    {
  811.    // clip x axis with slower version
  812.    // draw the triangle
  813.    for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  814.        {
  815.        // do x clip
  816.        left  = (int)xs;
  817.        right = (int)xe;
  818.        // adjust starting point and ending point
  819.        xs+=dx_left;
  820.        xe+=dx_right;
  821.        // clip line
  822.        if (left < min_clip_x)
  823.           {
  824.           left = min_clip_x;
  825.           if (right < min_clip_x)
  826.              continue;
  827.           }
  828.        if (right > max_clip_x)
  829.           {
  830.           right = max_clip_x;
  831.           if (left > max_clip_x)
  832.              continue;
  833.           }
  834.        memset((UCHAR  *)dest_addr+(unsigned int)left, color,(unsigned int)(right-left+1));
  835.        } // end for
  836.    } // end else x clipping needed
  837. } // end Draw_Bottom_Tri
  838. ///////////////////////////////////////////////////////////////////////////////
  839. void Draw_Top_Tri16(int x1,int y1, 
  840.                     int x2,int y2, 
  841.                     int x3,int y3,
  842.                     int color, 
  843.                     UCHAR *_dest_buffer, int mempitch)
  844. {
  845. // this function draws a triangle that has a flat top
  846. float dx_right,    // the dx/dy ratio of the right edge of line
  847.       dx_left,     // the dx/dy ratio of the left edge of line
  848.       xs,xe,       // the starting and ending points of the edges
  849.       height;      // the height of the triangle
  850. int temp_x,        // used during sorting as temps
  851.     temp_y,
  852.     right,         // used by clipping
  853.     left;
  854. // cast dest buffer to ushort
  855. USHORT *dest_buffer = (USHORT *)_dest_buffer;
  856. // destination address of next scanline
  857. USHORT  *dest_addr = NULL;
  858. // recompute mempitch in 16-bit words
  859. mempitch = (mempitch >> 1);
  860. // test order of x1 and x2
  861. if (x2 < x1)
  862.    {
  863.    temp_x = x2;
  864.    x2     = x1;
  865.    x1     = temp_x;
  866.    } // end if swap
  867. // compute delta's
  868. height = y3-y1;
  869. dx_left  = (x3-x1)/height;
  870. dx_right = (x3-x2)/height;
  871. // set starting points
  872. xs = (float)x1;
  873. xe = (float)x2; // +(float)0.5;
  874. // perform y clipping
  875. if (y1 < min_clip_y)
  876.    {
  877.    // compute new xs and ys
  878.    xs = xs+dx_left*(float)(-y1+min_clip_y);
  879.    xe = xe+dx_right*(float)(-y1+min_clip_y);
  880.    // reset y1
  881.    y1=min_clip_y;
  882.    } // end if top is off screen
  883. if (y3>max_clip_y)
  884.    y3=max_clip_y;
  885. // compute starting address in video memory
  886. dest_addr = dest_buffer+y1*mempitch;
  887. // test if x clipping is needed
  888. if (x1>=min_clip_x && x1<=max_clip_x &&
  889.     x2>=min_clip_x && x2<=max_clip_x &&
  890.     x3>=min_clip_x && x3<=max_clip_x)
  891.     {
  892.     // draw the triangle
  893.     for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  894.         {
  895.         // draw the line
  896.         Mem_Set_WORD(dest_addr+(unsigned int)(xs),color,(unsigned int)((int)xe-(int)xs+1));
  897.         // adjust starting point and ending point
  898.         xs+=dx_left;
  899.         xe+=dx_right;
  900.         } // end for
  901.     } // end if no x clipping needed
  902. else
  903.    {
  904.    // clip x axis with slower version
  905.    // draw the triangle
  906.    for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  907.        {
  908.        // do x clip
  909.        left  = (int)xs;
  910.        right = (int)xe;
  911.        // adjust starting point and ending point
  912.        xs+=dx_left;
  913.        xe+=dx_right;
  914.        // clip line
  915.        if (left < min_clip_x)
  916.           {
  917.           left = min_clip_x;
  918.           if (right < min_clip_x)
  919.              continue;
  920.           }
  921.        if (right > max_clip_x)
  922.           {
  923.           right = max_clip_x;
  924.           if (left > max_clip_x)
  925.              continue;
  926.           }
  927.         // draw the line
  928.         Mem_Set_WORD(dest_addr+(unsigned int)(left),color,(unsigned int)(right-left+1));
  929.        } // end for
  930.    } // end else x clipping needed
  931. } // end Draw_Top_Tri16
  932. /////////////////////////////////////////////////////////////////////////////
  933. void Draw_Bottom_Tri16(int x1,int y1, 
  934.                        int x2,int y2, 
  935.                        int x3,int y3,
  936.                        int color,
  937.                        UCHAR *_dest_buffer, int mempitch)
  938. {
  939. // this function draws a triangle that has a flat bottom
  940. float dx_right,    // the dx/dy ratio of the right edge of line
  941.       dx_left,     // the dx/dy ratio of the left edge of line
  942.       xs,xe,       // the starting and ending points of the edges
  943.       height;      // the height of the triangle
  944. int temp_x,        // used during sorting as temps
  945.     temp_y,
  946.     right,         // used by clipping
  947.     left;
  948. // cast dest buffer to ushort
  949. USHORT *dest_buffer = (USHORT *)_dest_buffer;
  950. // destination address of next scanline
  951. USHORT  *dest_addr = NULL;
  952. // recompute mempitch in 16-bit words
  953. mempitch = (mempitch >> 1);
  954. // test order of x1 and x2
  955. if (x3 < x2)
  956.    {
  957.    temp_x = x2;
  958.    x2     = x3;
  959.    x3     = temp_x;
  960.    } // end if swap
  961. // compute delta's
  962. height = y3-y1;
  963. dx_left  = (x2-x1)/height;
  964. dx_right = (x3-x1)/height;
  965. // set starting points
  966. xs = (float)x1;
  967. xe = (float)x1; // +(float)0.5;
  968. // perform y clipping
  969. if (y1 < min_clip_y)
  970.    {
  971.    // compute new xs and ys
  972.    xs = xs+dx_left*(float)(-y1+min_clip_y);
  973.    xe = xe+dx_right*(float)(-y1+min_clip_y);
  974.    // reset y1
  975.    y1 = min_clip_y;
  976.    } // end if top is off screen
  977. if (y3 > max_clip_y)
  978.    y3 = max_clip_y;
  979. // compute starting address in video memory
  980. dest_addr = dest_buffer+y1*mempitch;
  981. // test if x clipping is needed
  982. if (x1>=min_clip_x && x1<=max_clip_x &&
  983.     x2>=min_clip_x && x2<=max_clip_x &&
  984.     x3>=min_clip_x && x3<=max_clip_x)
  985.     {
  986.     // draw the triangle
  987.     for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  988.         {
  989.         // draw the line
  990.         Mem_Set_WORD(dest_addr+(unsigned int)(xs),color,(unsigned int)((int)xe-(int)xs+1));
  991.         // adjust starting point and ending point
  992.         xs+=dx_left;
  993.         xe+=dx_right;
  994.         } // end for
  995.     } // end if no x clipping needed
  996. else
  997.    {
  998.    // clip x axis with slower version
  999.    // draw the triangle
  1000.    for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  1001.        {
  1002.        // do x clip
  1003.        left  = (int)xs;
  1004.        right = (int)xe;
  1005.        // adjust starting point and ending point
  1006.        xs+=dx_left;
  1007.        xe+=dx_right;
  1008.        // clip line
  1009.        if (left < min_clip_x)
  1010.           {
  1011.           left = min_clip_x;
  1012.           if (right < min_clip_x)
  1013.              continue;
  1014.           }
  1015.        if (right > max_clip_x)
  1016.           {
  1017.           right = max_clip_x;
  1018.           if (left > max_clip_x)
  1019.              continue;
  1020.           }
  1021.        // draw the line
  1022.        Mem_Set_WORD(dest_addr+(unsigned int)(left),color,(unsigned int)(right-left+1));
  1023.        } // end for
  1024.    } // end else x clipping needed
  1025. } // end Draw_Bottom_Tri16
  1026. ///////////////////////////////////////////////////////////////////////////////
  1027. void Draw_TriangleFP_2D(int x1,int y1,
  1028.                         int x2,int y2,
  1029.                         int x3,int y3,
  1030.                         int color,
  1031.              UCHAR *dest_buffer, int mempitch)
  1032. {
  1033. // this function draws a triangle on the destination buffer using fixed point
  1034. // it decomposes all triangles into a pair of flat top, flat bottom
  1035. int temp_x, // used for sorting
  1036.     temp_y,
  1037.     new_x;
  1038. #ifdef DEBUG_ON
  1039. // track rendering stats
  1040.     debug_polys_rendered_per_frame++;
  1041. #endif
  1042. // test for h lines and v lines
  1043. if ((x1==x2 && x2==x3)  ||  (y1==y2 && y2==y3))
  1044.    return;
  1045. // sort p1,p2,p3 in ascending y order
  1046. if (y2<y1)
  1047.    {
  1048.    temp_x = x2;
  1049.    temp_y = y2;
  1050.    x2     = x1;
  1051.    y2     = y1;
  1052.    x1     = temp_x;
  1053.    y1     = temp_y;
  1054.    } // end if
  1055. // now we know that p1 and p2 are in order
  1056. if (y3<y1)
  1057.    {
  1058.    temp_x = x3;
  1059.    temp_y = y3;
  1060.    x3     = x1;
  1061.    y3     = y1;
  1062.    x1     = temp_x;
  1063.    y1     = temp_y;
  1064.    } // end if
  1065. // finally test y3 against y2
  1066. if (y3<y2)
  1067.    {
  1068.    temp_x = x3;
  1069.    temp_y = y3;
  1070.    x3     = x2;
  1071.    y3     = y2;
  1072.    x2     = temp_x;
  1073.    y2     = temp_y;
  1074.    } // end if
  1075. // do trivial rejection tests for clipping
  1076. if ( y3<min_clip_y || y1>max_clip_y ||
  1077.     (x1<min_clip_x && x2<min_clip_x && x3<min_clip_x) ||
  1078.     (x1>max_clip_x && x2>max_clip_x && x3>max_clip_x) )
  1079.    return;
  1080. // test if top of triangle is flat
  1081. if (y1==y2)
  1082.    {
  1083.    Draw_Top_TriFP(x1,y1,x2,y2,x3,y3,color, dest_buffer, mempitch);
  1084.    } // end if
  1085. else
  1086. if (y2==y3)
  1087.    {
  1088.    Draw_Bottom_TriFP(x1,y1,x2,y2,x3,y3,color, dest_buffer, mempitch);
  1089.    } // end if bottom is flat
  1090. else
  1091.    {
  1092.    // general triangle that's needs to be broken up along long edge
  1093.    new_x = x1 + (int)(0.5+(float)(y2-y1)*(float)(x3-x1)/(float)(y3-y1));
  1094.    // draw each sub-triangle
  1095.    Draw_Bottom_TriFP(x1,y1,new_x,y2,x2,y2,color, dest_buffer, mempitch);
  1096.    Draw_Top_TriFP(x2,y2,new_x,y2,x3,y3,color, dest_buffer, mempitch);
  1097.    } // end else
  1098. } // end Draw_TriangleFP_2D
  1099. /////////////////////////////////////////////////////////////
  1100. void Draw_Triangle_2D(int x1,int y1,
  1101.                       int x2,int y2,
  1102.                       int x3,int y3,
  1103.                       int color,
  1104.   UCHAR *dest_buffer, int mempitch)
  1105. {
  1106. // this function draws a triangle on the destination buffer
  1107. // it decomposes all triangles into a pair of flat top, flat bottom
  1108. int temp_x, // used for sorting
  1109.     temp_y,
  1110.     new_x;
  1111. #ifdef DEBUG_ON
  1112. // track rendering stats
  1113.     debug_polys_rendered_per_frame++;
  1114. #endif
  1115. // test for h lines and v lines
  1116. if ((x1==x2 && x2==x3)  ||  (y1==y2 && y2==y3))
  1117.    return;
  1118. // sort p1,p2,p3 in ascending y order
  1119. if (y2<y1)
  1120.    {
  1121.    temp_x = x2;
  1122.    temp_y = y2;
  1123.    x2     = x1;
  1124.    y2     = y1;
  1125.    x1     = temp_x;
  1126.    y1     = temp_y;
  1127.    } // end if
  1128. // now we know that p1 and p2 are in order
  1129. if (y3<y1)
  1130.    {
  1131.    temp_x = x3;
  1132.    temp_y = y3;
  1133.    x3     = x1;
  1134.    y3     = y1;
  1135.    x1     = temp_x;
  1136.    y1     = temp_y;
  1137.    } // end if
  1138. // finally test y3 against y2
  1139. if (y3<y2)
  1140.    {
  1141.    temp_x = x3;
  1142.    temp_y = y3;
  1143.    x3     = x2;
  1144.    y3     = y2;
  1145.    x2     = temp_x;
  1146.    y2     = temp_y;
  1147.    } // end if
  1148. // do trivial rejection tests for clipping
  1149. if ( y3<min_clip_y || y1>max_clip_y ||
  1150.     (x1<min_clip_x && x2<min_clip_x && x3<min_clip_x) ||
  1151.     (x1>max_clip_x && x2>max_clip_x && x3>max_clip_x) )
  1152.    return;
  1153. // test if top of triangle is flat
  1154. if (y1==y2)
  1155.    {
  1156.    Draw_Top_Tri(x1,y1,x2,y2,x3,y3,color, dest_buffer, mempitch);
  1157.    } // end if
  1158. else
  1159. if (y2==y3)
  1160.    {
  1161.    Draw_Bottom_Tri(x1,y1,x2,y2,x3,y3,color, dest_buffer, mempitch);
  1162.    } // end if bottom is flat
  1163. else
  1164.    {
  1165.    // general triangle that's needs to be broken up along long edge
  1166.    new_x = x1 + (int)(0.5+(float)(y2-y1)*(float)(x3-x1)/(float)(y3-y1));
  1167.    // draw each sub-triangle
  1168.    Draw_Bottom_Tri(x1,y1,new_x,y2,x2,y2,color, dest_buffer, mempitch);
  1169.    Draw_Top_Tri(x2,y2,new_x,y2,x3,y3,color, dest_buffer, mempitch);
  1170.    } // end else
  1171. } // end Draw_Triangle_2D
  1172. ///////////////////////////////////////////////////////////////////////////////
  1173. void Draw_Triangle_2D16(int x1,int y1,
  1174.                         int x2,int y2,
  1175.                         int x3,int y3,
  1176.                         int color,
  1177.     UCHAR *dest_buffer, int mempitch)
  1178. {
  1179. // this function draws a triangle on the destination buffer
  1180. // it decomposes all triangles into a pair of flat top, flat bottom
  1181. int temp_x, // used for sorting
  1182.     temp_y,
  1183.     new_x;
  1184. #ifdef DEBUG_ON
  1185. // track rendering stats
  1186.     debug_polys_rendered_per_frame++;
  1187. #endif
  1188. // test for h lines and v lines
  1189. if ((x1==x2 && x2==x3)  ||  (y1==y2 && y2==y3))
  1190.    return;
  1191. // sort p1,p2,p3 in ascending y order
  1192. if (y2<y1)
  1193.    {
  1194.    temp_x = x2;
  1195.    temp_y = y2;
  1196.    x2     = x1;
  1197.    y2     = y1;
  1198.    x1     = temp_x;
  1199.    y1     = temp_y;
  1200.    } // end if
  1201. // now we know that p1 and p2 are in order
  1202. if (y3<y1)
  1203.    {
  1204.    temp_x = x3;
  1205.    temp_y = y3;
  1206.    x3     = x1;
  1207.    y3     = y1;
  1208.    x1     = temp_x;
  1209.    y1     = temp_y;
  1210.    } // end if
  1211. // finally test y3 against y2
  1212. if (y3<y2)
  1213.    {
  1214.    temp_x = x3;
  1215.    temp_y = y3;
  1216.    x3     = x2;
  1217.    y3     = y2;
  1218.    x2     = temp_x;
  1219.    y2     = temp_y;
  1220.    } // end if
  1221. // do trivial rejection tests for clipping
  1222. if ( y3<min_clip_y || y1>max_clip_y ||
  1223.     (x1<min_clip_x && x2<min_clip_x && x3<min_clip_x) ||
  1224.     (x1>max_clip_x && x2>max_clip_x && x3>max_clip_x) )
  1225.    return;
  1226. // test if top of triangle is flat
  1227. if (y1==y2)
  1228.    {
  1229.    Draw_Top_Tri16(x1,y1,x2,y2,x3,y3,color, dest_buffer, mempitch);
  1230.    } // end if
  1231. else
  1232. if (y2==y3)
  1233.    {
  1234.    Draw_Bottom_Tri16(x1,y1,x2,y2,x3,y3,color, dest_buffer, mempitch);
  1235.    } // end if bottom is flat
  1236. else
  1237.    {
  1238.    // general triangle that's needs to be broken up along long edge
  1239.    new_x = x1 + (int)(0.5+(float)(y2-y1)*(float)(x3-x1)/(float)(y3-y1));
  1240.    // draw each sub-triangle
  1241.    Draw_Bottom_Tri16(x1,y1,new_x,y2,x2,y2,color, dest_buffer, mempitch);
  1242.    Draw_Top_Tri16(x2,y2,new_x,y2,x3,y3,color, dest_buffer, mempitch);
  1243.    } // end else
  1244. } // end Draw_Triangle_2D16
  1245. ////////////////////////////////////////////////////////////////////////////////
  1246. #if 0
  1247. inline void Draw_QuadFP_2D(int x0,int y0,
  1248.                     int x1,int y1,
  1249.                     int x2,int y2,
  1250.                     int x3, int y3,
  1251.                     int color,
  1252.                     UCHAR *dest_buffer, int mempitch)
  1253. {
  1254. // this function draws a 2D quadrilateral
  1255. // simply call the triangle function 2x, let it do all the work
  1256. Draw_TriangleFP_2D(x0,y0,x1,y1,x3,y3,color,dest_buffer,mempitch);
  1257. Draw_TriangleFP_2D(x1,y1,x2,y2,x3,y3,color,dest_buffer,mempitch);
  1258. } // end Draw_QuadFP_2D
  1259. #endif
  1260. ////////////////////////////////////////////////////////////////////////////////
  1261. void Draw_Top_TriFP(int x1,int y1,
  1262.                     int x2,int y2, 
  1263.                     int x3,int y3,
  1264.                     int color, 
  1265.                     UCHAR *dest_buffer, int mempitch)
  1266. {
  1267. // this function draws a triangle that has a flat top using fixed point math
  1268. int dx_right,    // the dx/dy ratio of the right edge of line
  1269.     dx_left,     // the dx/dy ratio of the left edge of line
  1270.     xs,xe,       // the starting and ending points of the edges
  1271.     height;      // the height of the triangle
  1272. int temp_x,        // used during sorting as temps
  1273.     temp_y,
  1274.     right,         // used by clipping
  1275.     left;
  1276. UCHAR  *dest_addr;
  1277. // test for degenerate
  1278. if (y1==y3 || y2==y3)
  1279. return;
  1280. // test order of x1 and x2
  1281. if (x2 < x1)
  1282.    {
  1283.    temp_x = x2;
  1284.    x2     = x1;
  1285.    x1     = temp_x;
  1286.    } // end if swap
  1287. // compute delta's
  1288. height = y3-y1;
  1289. dx_left  = ((x3-x1)<<FIXP16_SHIFT)/height;
  1290. dx_right = ((x3-x2)<<FIXP16_SHIFT)/height;
  1291. // set starting points
  1292. xs = (x1<<FIXP16_SHIFT);
  1293. xe = (x2<<FIXP16_SHIFT);
  1294. // perform y clipping
  1295. if (y1<min_clip_y)
  1296.    {
  1297.    // compute new xs and ys
  1298.    xs = xs+dx_left*(-y1+min_clip_y);
  1299.    xe = xe+dx_right*(-y1+min_clip_y);
  1300.    // reset y1
  1301.    y1=min_clip_y;
  1302.    } // end if top is off screen
  1303. if (y3>max_clip_y)
  1304.    y3=max_clip_y;
  1305. // compute starting address in video memory
  1306. dest_addr = dest_buffer+y1*mempitch;
  1307. // test if x clipping is needed
  1308. if (x1>=min_clip_x && x1<=max_clip_x &&
  1309.     x2>=min_clip_x && x2<=max_clip_x &&
  1310.     x3>=min_clip_x && x3<=max_clip_x)
  1311.     {
  1312.     // draw the triangle
  1313.     for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  1314.         {
  1315.         memset((UCHAR *)dest_addr+((xs+FIXP16_ROUND_UP)>>FIXP16_SHIFT),
  1316.                color, (((xe-xs+FIXP16_ROUND_UP)>>FIXP16_SHIFT)+1));
  1317.         // adjust starting point and ending point
  1318.         xs+=dx_left;
  1319.         xe+=dx_right;
  1320.         } // end for
  1321.     } // end if no x clipping needed
  1322. else
  1323.    {
  1324.    // clip x axis with slower version
  1325.    // draw the triangle
  1326.    for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  1327.        {
  1328.        // do x clip
  1329.        left  = ((xs+FIXP16_ROUND_UP)>>16);
  1330.        right = ((xe+FIXP16_ROUND_UP)>>16);
  1331.        // adjust starting point and ending point
  1332.        xs+=dx_left;
  1333.        xe+=dx_right;
  1334.        // clip line
  1335.        if (left < min_clip_x)
  1336.           {
  1337.           left = min_clip_x;
  1338.           if (right < min_clip_x)
  1339.              continue;
  1340.           }
  1341.        if (right > max_clip_x)
  1342.           {
  1343.           right = max_clip_x;
  1344.           if (left > max_clip_x)
  1345.              continue;
  1346.           }
  1347.        memset((UCHAR  *)dest_addr+(unsigned int)left,
  1348.               color,(unsigned int)(right-left+1));
  1349.        } // end for
  1350.    } // end else x clipping needed
  1351. } // end Draw_Top_TriFP
  1352. /////////////////////////////////////////////////////////////////////////////
  1353. void Draw_Bottom_TriFP(int x1,int y1, 
  1354.                        int x2,int y2, 
  1355.                        int x3,int y3,
  1356.                        int color,
  1357.                        UCHAR *dest_buffer, int mempitch)
  1358. {
  1359. // this function draws a triangle that has a flat bottom using fixed point math
  1360. int dx_right,    // the dx/dy ratio of the right edge of line
  1361.     dx_left,     // the dx/dy ratio of the left edge of line
  1362.     xs,xe,       // the starting and ending points of the edges
  1363.     height;      // the height of the triangle
  1364. int temp_x,        // used during sorting as temps
  1365.     temp_y,
  1366.     right,         // used by clipping
  1367.     left;
  1368. UCHAR  *dest_addr;
  1369. if (y1==y2 || y1==y3)
  1370. return;
  1371. // test order of x1 and x2
  1372. if (x3 < x2)
  1373.    {
  1374.    temp_x = x2;
  1375.    x2     = x3;
  1376.    x3     = temp_x;
  1377.    } // end if swap
  1378. // compute delta's
  1379. height = y3-y1;
  1380. dx_left  = ((x2-x1)<<FIXP16_SHIFT)/height;
  1381. dx_right = ((x3-x1)<<FIXP16_SHIFT)/height;
  1382. // set starting points
  1383. xs = (x1<<FIXP16_SHIFT);
  1384. xe = (x1<<FIXP16_SHIFT); 
  1385. // perform y clipping
  1386. if (y1<min_clip_y)
  1387.    {
  1388.    // compute new xs and ys
  1389.    xs = xs+dx_left*(-y1+min_clip_y);
  1390.    xe = xe+dx_right*(-y1+min_clip_y);
  1391.    // reset y1
  1392.    y1=min_clip_y;
  1393.    } // end if top is off screen
  1394. if (y3>max_clip_y)
  1395.    y3=max_clip_y;
  1396. // compute starting address in video memory
  1397. dest_addr = dest_buffer+y1*mempitch;
  1398. // test if x clipping is needed
  1399. if (x1>=min_clip_x && x1<=max_clip_x &&
  1400.     x2>=min_clip_x && x2<=max_clip_x &&
  1401.     x3>=min_clip_x && x3<=max_clip_x)
  1402.     {
  1403.     // draw the triangle
  1404.     for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  1405.         {
  1406.         memset((UCHAR *)dest_addr+((xs+FIXP16_ROUND_UP)>>FIXP16_SHIFT),
  1407.                 color, (((xe-xs+FIXP16_ROUND_UP)>>FIXP16_SHIFT)+1));
  1408.         // adjust starting point and ending point
  1409.         xs+=dx_left;
  1410.         xe+=dx_right;
  1411.         } // end for
  1412.     } // end if no x clipping needed
  1413. else
  1414.    {
  1415.    // clip x axis with slower version
  1416.    // draw the triangle
  1417.    for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  1418.        {
  1419.        // do x clip
  1420.        left  = ((xs+FIXP16_ROUND_UP)>>FIXP16_SHIFT);
  1421.        right = ((xe+FIXP16_ROUND_UP)>>FIXP16_SHIFT);
  1422.        // adjust starting point and ending point
  1423.        xs+=dx_left;
  1424.        xe+=dx_right;
  1425.        // clip line
  1426.        if (left < min_clip_x)
  1427.           {
  1428.           left = min_clip_x;
  1429.           if (right < min_clip_x)
  1430.              continue;
  1431.           }
  1432.        if (right > max_clip_x)
  1433.           {
  1434.           right = max_clip_x;
  1435.           if (left > max_clip_x)
  1436.              continue;
  1437.           }
  1438.        memset((UCHAR *)dest_addr+left,
  1439.               color, (right-left+1));
  1440.        } // end for
  1441.    } // end else x clipping needed
  1442. } // end Draw_Bottom_TriFP
  1443. ////////////////////////////////////////////////////////////////////////////
  1444. int Fast_Distance_2D(int x, int y)
  1445. {
  1446. // this function computes the distance from 0,0 to x,y with 3.5% error
  1447. // first compute the absolute value of x,y
  1448. x = abs(x);
  1449. y = abs(y);
  1450. // compute the minimum of x,y
  1451. int mn = MIN(x,y);
  1452. // return the distance
  1453. return(x+y-(mn>>1)-(mn>>2)+(mn>>4));
  1454. } // end Fast_Distance_2D
  1455. ///////////////////////////////////////////////////////////////////////////////
  1456. float Fast_Distance_3D(float fx, float fy, float fz)
  1457. {
  1458. // this function computes the distance from the origin to x,y,z
  1459. int temp;  // used for swaping
  1460. int x,y,z; // used for algorithm
  1461. // make sure values are all positive
  1462. x = fabs(fx) * 1024;
  1463. y = fabs(fy) * 1024;
  1464. z = fabs(fz) * 1024;
  1465. // sort values
  1466. if (y < x) SWAP(x,y,temp)
  1467. if (z < y) SWAP(y,z,temp)
  1468. if (y < x) SWAP(x,y,temp)
  1469. int dist = (z + 11 * (y >> 5) + (x >> 2) );
  1470. // compute distance with 8% error
  1471. return((float)(dist >> 10));
  1472. } // end Fast_Distance_3D
  1473. ///////////////////////////////////////////////////////////////////////////////
  1474. int Find_Bounding_Box_Poly2D(POLYGON2D_PTR poly, 
  1475.                              float &min_x, float &max_x, 
  1476.                              float &min_y, float &max_y)
  1477. {
  1478. // this function finds the bounding box of a 2D polygon 
  1479. // and returns the values in the sent vars
  1480. // is this poly valid?
  1481. if (poly->num_verts == 0)
  1482.     return(0);
  1483. // initialize output vars (note they are pointers)
  1484. // also note that the algorithm assumes local coordinates
  1485. // that is, the poly verts are relative to 0,0
  1486. max_x = max_y = min_x = min_y = 0;
  1487. // process each vertex
  1488. for (int index=0; index < poly->num_verts; index++)
  1489.     {
  1490.     // update vars - run min/max seek
  1491.     if (poly->vlist[index].x > max_x)
  1492.        max_x = poly->vlist[index].x;
  1493.     if (poly->vlist[index].x < min_x)
  1494.        min_x = poly->vlist[index].x;
  1495.     if (poly->vlist[index].y > max_y)
  1496.        max_y = poly->vlist[index].y;
  1497.     if (poly->vlist[index].y < min_y)
  1498.        min_y = poly->vlist[index].y;
  1499. } // end for index
  1500. // return success
  1501. return(1);
  1502. } // end Find_Bounding_Box_Poly2D
  1503. ////////////////////////////////////////////////////////////////
  1504. void Draw_Filled_Polygon2D(POLYGON2D_PTR poly, UCHAR *vbuffer, int mempitch)
  1505. {
  1506. // this function draws a general n sided polygon 
  1507. int ydiff1, ydiff2,         // difference between starting x and ending x
  1508. xdiff1, xdiff2,         // difference between starting y and ending y
  1509.     start,                  // starting offset of line between edges
  1510. length,                 // distance from edge 1 to edge 2
  1511. errorterm1, errorterm2, // error terms for edges 1 & 2
  1512.     offset1, offset2,       // offset of current pixel in edges 1 & 2
  1513. count1, count2,         // increment count for edges 1 & 2
  1514.     xunit1, xunit2;         // unit to advance x offset for edges 1 & 2
  1515. #ifdef DEBUG_ON
  1516. // track rendering stats
  1517.     debug_polys_rendered_per_frame++;
  1518. #endif
  1519. // initialize count of number of edges drawn:
  1520. int edgecount = poly->num_verts-1;
  1521. // determine which vertex is at top of polygon:
  1522. int firstvert=0;         // start by assuming vertex 0 is at top
  1523. int min_y=poly->vlist[0].y; // find y coordinate of vertex 0
  1524. for (int index=1; index < poly->num_verts; index++) 
  1525.     {  
  1526.     // Search thru vertices
  1527.   if ((poly->vlist[index].y) < min_y) 
  1528.         {  
  1529.         // is another vertex higher?
  1530. firstvert=index;                   
  1531. min_y=poly->vlist[index].y;
  1532. } // end if
  1533. } // end for index
  1534. // finding starting and ending vertices of first two edges:
  1535. int startvert1=firstvert;      // get starting vertex of edge 1
  1536. int startvert2=firstvert;      // get starting vertex of edge 2
  1537. int xstart1=poly->vlist[startvert1].x+poly->x0;
  1538. int ystart1=poly->vlist[startvert1].y+poly->y0;
  1539. int xstart2=poly->vlist[startvert2].x+poly->x0;
  1540. int ystart2=poly->vlist[startvert2].y+poly->y0;
  1541. int endvert1=startvert1-1;           // get ending vertex of edge 1
  1542. if (endvert1 < 0) 
  1543.    endvert1=poly->num_verts-1;    // check for wrap
  1544. int xend1=poly->vlist[endvert1].x+poly->x0;      // get x & y coordinates
  1545. int yend1=poly->vlist[endvert1].y+poly->y0;      // of ending vertices
  1546. int endvert2=startvert2+1;           // get ending vertex of edge 2
  1547. if (endvert2==(poly->num_verts)) 
  1548.     endvert2=0;  // Check for wrap
  1549. int xend2=poly->vlist[endvert2].x+poly->x0;      // get x & y coordinates
  1550. int yend2=poly->vlist[endvert2].y+poly->y0;      // of ending vertices
  1551. // draw the polygon:
  1552. while (edgecount>0) 
  1553.       {    
  1554.       // continue drawing until all edges drawn
  1555.   offset1=mempitch*ystart1+xstart1;  // offset of edge 1
  1556.   offset2=mempitch*ystart2+xstart2;  // offset of edge 2
  1557.   
  1558.       // initialize error terms
  1559.       // for edges 1 & 2
  1560.       errorterm1=0;        
  1561.   errorterm2=0;           
  1562.       // get absolute value of
  1563.       if ((ydiff1=yend1-ystart1) < 0) 
  1564.          ydiff1=-ydiff1;
  1565.       // x & y lengths of edges
  1566.   if ((ydiff2=yend2-ystart2) < 0) 
  1567.          ydiff2=-ydiff2; 
  1568.      if ((xdiff1=xend1-xstart1) < 0) 
  1569.          {               
  1570.          // get value of length
  1571.  xunit1=-1;                    // calculate X increment
  1572.  xdiff1=-xdiff1;
  1573.  } // end if
  1574.   else 
  1575.          {
  1576.  xunit1=1;
  1577.  } // end else
  1578.       if ((xdiff2=xend2-xstart2) < 0) 
  1579.          {
  1580.          // Get value of length
  1581.     xunit2=-1;                   // calculate X increment
  1582.  xdiff2=-xdiff2;
  1583.  } // end else
  1584.   else 
  1585.          {
  1586.  xunit2=1;
  1587.  } // end else
  1588.   // choose which of four routines to use
  1589.   if (xdiff1 > ydiff1) 
  1590.          {    
  1591.          // if x length of edge 1 is greater than y length
  1592.  if (xdiff2 > ydiff2) 
  1593.             {  
  1594.             // if X length of edge 2 is greater than y length
  1595. // increment edge 1 on X and edge 2 on X:
  1596. count1=xdiff1;    // count for x increment on edge 1
  1597. count2=xdiff2;    // count for x increment on edge 2
  1598. while (count1 && count2) 
  1599.                   {  
  1600.                   // continue drawing until one edge is done
  1601.        // calculate edge 1:
  1602.      while ((errorterm1 < xdiff1) && (count1 > 0)) 
  1603.                         { 
  1604.                         // finished w/edge 1?
  1605. if (count1--) 
  1606.                            {     
  1607.                            // count down on edge 1
  1608.    offset1+=xunit1;  // increment pixel offset
  1609.    xstart1+=xunit1;
  1610.    } // end if
  1611.            errorterm1+=ydiff1; // increment error term
  1612.           if (errorterm1 < xdiff1) 
  1613.                            {  // if not more than XDIFF
  1614.        vbuffer[offset1]=(UCHAR)poly->color; // ...plot a pixel
  1615.        } // end if
  1616.      } // end while
  1617.                   errorterm1-=xdiff1; // if time to increment X, restore error term
  1618.       // calculate edge 2:
  1619.   while ((errorterm2 < xdiff2) && (count2 > 0)) 
  1620.                         {  
  1621.                         // finished w/edge 2?
  1622. if (count2--) 
  1623.                            {     
  1624.                            // count down on edge 2
  1625.    offset2+=xunit2;  // increment pixel offset
  1626.    xstart2+=xunit2;
  1627.    } // end if
  1628.      errorterm2+=ydiff2; // increment error term
  1629.   if (errorterm2 < xdiff2) 
  1630.                              {  // if not more than XDIFF
  1631.  vbuffer[offset2]=(UCHAR)poly->color;  // ...plot a pixel
  1632.      } // end if
  1633.           } // end while
  1634. errorterm2-=xdiff2; // if time to increment X, restore error term
  1635.         // draw line from edge 1 to edge 2:
  1636. length=offset2-offset1; // determine length of horizontal line
  1637. if (length < 0) 
  1638.                        { // if negative...
  1639.    length=-length;       // make it positive
  1640.    start=offset2;        // and set START to edge 2
  1641.           } // end if
  1642. else 
  1643.                        start=offset1;     // else set START to edge 1
  1644.  
  1645.               for (int index=start; index < start+length+1; index++)
  1646.                   {  // From edge to edge...
  1647.        vbuffer[index]=(UCHAR)poly->color;         // ...draw the line
  1648.                   } // end for index
  1649. offset1+=mempitch;           // advance edge 1 offset to next line
  1650.        ystart1++;
  1651. offset2+=mempitch;           // advance edge 2 offset to next line
  1652. ystart2++;
  1653.           } // end if
  1654. } // end if
  1655. else 
  1656.             {
  1657.           // increment edge 1 on X and edge 2 on Y:
  1658.     count1=xdiff1;    // count for X increment on edge 1
  1659.     count2=ydiff2;    // count for Y increment on edge 2
  1660.             while (count1 && count2) 
  1661.                   {  // continue drawing until one edge is done
  1662.              // calculate edge 1:
  1663.     while ((errorterm1 < xdiff1) && (count1 > 0)) 
  1664.                         { // finished w/edge 1?
  1665.         if (count1--) 
  1666.                            {
  1667.                            // count down on edge 1
  1668.    offset1+=xunit1;  // increment pixel offset
  1669.    xstart1+=xunit1;
  1670.    } // end if
  1671. errorterm1+=ydiff1; // increment error term
  1672. if (errorterm1 < xdiff1) 
  1673.                            {  // If not more than XDIFF
  1674.    vbuffer[offset1]=(UCHAR)poly->color; // ...plot a pixel
  1675.    } // end if
  1676.           } // end while
  1677. errorterm1-=xdiff1; // If time to increment X, restore error term
  1678.            // calculate edge 2:
  1679. errorterm2+=xdiff2; // increment error term
  1680.                     if (errorterm2 >= ydiff2)  
  1681.                        { // if time to increment Y...
  1682.    errorterm2-=ydiff2;        // ...restore error term
  1683.    offset2+=xunit2;           // ...and advance offset to next pixel
  1684.    xstart2+=xunit2;
  1685.          } // end if
  1686.         count2--;
  1687.         // draw line from edge 1 to edge 2:
  1688. length=offset2-offset1; // determine length of horizontal line
  1689. if (length < 0)  
  1690.                        { // if negative...
  1691.    length=-length;       // ...make it positive
  1692.    start=offset2;        // and set START to edge 2
  1693.    } // end if
  1694. else 
  1695.                        start=offset1;        // else set START to edge 1
  1696.         for (int index=start; index < start+length+1; index++)  // from edge to edge
  1697.         {
  1698.                         vbuffer[index]=(UCHAR)poly->color;         // ...draw the line
  1699.                         } // end for index
  1700.  
  1701.              offset1+=mempitch;           // advance edge 1 offset to next line
  1702. ystart1++;
  1703. offset2+=mempitch;           // advance edge 2 offset to next line
  1704. ystart2++;
  1705. } // end while
  1706. } // end if
  1707. } // end if
  1708. else 
  1709.             {
  1710. if (xdiff2 > ydiff2) 
  1711.                {
  1712.            // increment edge 1 on Y and edge 2 on X:
  1713.    count1=ydiff1;  // count for Y increment on edge 1
  1714.    count2=xdiff2;  // count for X increment on edge 2
  1715.    while(count1 && count2) 
  1716.                     {  // continue drawing until one edge is done
  1717.           // calculate edge 1:
  1718. errorterm1+=xdiff1; // Increment error term
  1719. if (errorterm1 >= ydiff1)  
  1720.                        {  // if time to increment Y...
  1721.    errorterm1-=ydiff1;         // ...restore error term
  1722.    offset1+=xunit1;            // ...and advance offset to next pixel
  1723.    xstart1+=xunit1;
  1724.    } // end if
  1725.            count1--;
  1726.          // Calculate edge 2:
  1727. while ((errorterm2 < xdiff2) && (count2 > 0)) 
  1728.                           { // finished w/edge 1?
  1729.   if (count2--) 
  1730.                              { // count down on edge 2
  1731.  offset2+=xunit2;  // increment pixel offset
  1732.  xstart2+=xunit2;
  1733.      } // end if
  1734.   errorterm2+=ydiff2; // increment error term
  1735.   if (errorterm2 < xdiff2) 
  1736.                              {  // if not more than XDIFF
  1737.  vbuffer[offset2]=(UCHAR)poly->color; // ...plot a pixel
  1738.      } // end if
  1739.        } // end while
  1740. errorterm2-=xdiff2;  // if time to increment X, restore error term
  1741.        // draw line from edge 1 to edge 2:
  1742. length=offset2-offset1; // determine length of horizontal line
  1743. if (length < 0) 
  1744.                        {    // if negative...
  1745.    length=-length;  // ...make it positive
  1746.    start=offset2;   // and set START to edge 2
  1747.    } // end if
  1748. else 
  1749.                        start=offset1;  // else set START to edge 1
  1750.            for (int index=start; index < start+length+1; index++) // from edge to edge...
  1751.         {
  1752.                         vbuffer[index]=(UCHAR)poly->color;      // ...draw the line
  1753.                         } // end for index
  1754. offset1+=mempitch;         // advance edge 1 offset to next line
  1755. ystart1++;
  1756. offset2+=mempitch;         // advance edge 2 offset to next line
  1757. ystart2++;
  1758.          } // end if
  1759. } // end if
  1760. else 
  1761.                {
  1762.    // increment edge 1 on Y and edge 2 on Y:
  1763.       count1=ydiff1;  // count for Y increment on edge 1
  1764.    count2=ydiff2;  // count for Y increment on edge 2
  1765.    while(count1 && count2) 
  1766.                     {  
  1767.                     // continue drawing until one edge is done
  1768.            // calculate edge 1:
  1769. errorterm1+=xdiff1;  // increment error term
  1770. if (errorterm1 >= ydiff1)  
  1771.                        {                           // if time to increment Y
  1772.    errorterm1-=ydiff1;         // ...restore error term
  1773.    offset1+=xunit1;            // ...and advance offset to next pixel
  1774.    xstart1+=xunit1;
  1775.    } // end if
  1776.  
  1777.                     count1--;
  1778.              // calculate edge 2:
  1779. errorterm2+=xdiff2;            // increment error term
  1780. if (errorterm2 >= ydiff2)  
  1781.                        {                           // if time to increment Y
  1782.    errorterm2-=ydiff2;         // ...restore error term
  1783.    offset2+=xunit2;            // ...and advance offset to next pixel
  1784.    xstart2+=xunit2;
  1785.    } // end if
  1786.             --count2;
  1787.         // draw line from edge 1 to edge 2:
  1788. length=offset2-offset1;  // determine length of horizontal line
  1789. if (length < 0) 
  1790.                        {          
  1791.                        // if negative...
  1792.    length=-length;        // ...make it positive
  1793.    start=offset2;         // and set START to edge 2
  1794.    } // end if
  1795. else 
  1796.                        start=offset1;         // else set START to edge 1
  1797.         for (int index=start; index < start+length+1; index++)   
  1798.                         { // from edge to edge
  1799.         vbuffer[index]=(UCHAR)poly->color;   // ...draw the linee
  1800.                         } // end for index
  1801. offset1+=mempitch;            // advance edge 1 offset to next line
  1802. ystart1++;
  1803. offset2+=mempitch;            // advance edge 2 offset to next line
  1804. ystart2++;
  1805. } // end while
  1806. } // end else
  1807. } // end if
  1808.     // another edge (at least) is complete. Start next edge, if any.
  1809. if (!count1) 
  1810.            {                      // if edge 1 is complete...
  1811.    --edgecount;           // decrement the edge count
  1812.    startvert1=endvert1;   // make ending vertex into start vertex
  1813.    --endvert1;            // and get new ending vertex
  1814.            if (endvert1 < 0) 
  1815.               endvert1=poly->num_verts-1; // check for wrap
  1816. xend1=poly->vlist[endvert1].x+poly->x0;  // get x & y of new end vertex
  1817. yend1=poly->vlist[endvert1].y+poly->y0;
  1818.     } // end if
  1819. if (!count2) 
  1820.            {                     // if edge 2 is complete...
  1821.    --edgecount;          // decrement the edge count
  1822.    startvert2=endvert2;  // make ending vertex into start vertex
  1823.    endvert2++;           // and get new ending vertex
  1824.            if (endvert2==(poly->num_verts)) 
  1825.               endvert2=0;                // check for wrap
  1826. xend2=poly->vlist[endvert2].x+poly->x0;  // get x & y of new end vertex
  1827. yend2=poly->vlist[endvert2].y+poly->y0;
  1828.    } // end if
  1829. } // end while
  1830. } // end Draw_Filled_Polygon2D
  1831. ///////////////////////////////////////////////////////////////
  1832. void Draw_Filled_Polygon2D16(POLYGON2D_PTR poly, UCHAR *_vbuffer, int mempitch)
  1833. {
  1834. // this function draws a general n sided polygon 
  1835. int ydiff1, ydiff2,         // difference between starting x and ending x
  1836. xdiff1, xdiff2,         // difference between starting y and ending y
  1837.     start,                  // starting offset of line between edges
  1838. length,                 // distance from edge 1 to edge 2
  1839. errorterm1, errorterm2, // error terms for edges 1 & 2
  1840.     offset1, offset2,       // offset of current pixel in edges 1 & 2
  1841. count1, count2,         // increment count for edges 1 & 2
  1842.     xunit1, xunit2;         // unit to advance x offset for edges 1 & 2
  1843. #ifdef DEBUG_ON
  1844. // track rendering stats
  1845.     debug_polys_rendered_per_frame++;
  1846. #endif
  1847. // recast vbuffer into short version since this is a 16 bit mode
  1848. USHORT *vbuffer = (USHORT *)_vbuffer;
  1849. // convert mempitch into WORD or 16bit stride
  1850. mempitch = (mempitch >> 1);
  1851. // initialize count of number of edges drawn:
  1852. int edgecount = poly->num_verts-1;
  1853. // determine which vertex is at top of polygon:
  1854. int firstvert=0;         // start by assuming vertex 0 is at top
  1855. int min_y=poly->vlist[0].y; // find y coordinate of vertex 0
  1856. for (int index=1; index < poly->num_verts; index++) 
  1857.     {  
  1858.     // Search thru vertices
  1859.   if ((poly->vlist[index].y) < min_y) 
  1860.         {  
  1861.         // is another vertex higher?
  1862. firstvert=index;                   
  1863. min_y=poly->vlist[index].y;
  1864. } // end if
  1865. } // end for index
  1866. // finding starting and ending vertices of first two edges:
  1867. int startvert1=firstvert;      // get starting vertex of edge 1
  1868. int startvert2=firstvert;      // get starting vertex of edge 2
  1869. int xstart1=poly->vlist[startvert1].x+poly->x0;
  1870. int ystart1=poly->vlist[startvert1].y+poly->y0;
  1871. int xstart2=poly->vlist[startvert2].x+poly->x0;
  1872. int ystart2=poly->vlist[startvert2].y+poly->y0;
  1873. int endvert1=startvert1-1;           // get ending vertex of edge 1
  1874. if (endvert1 < 0) 
  1875.    endvert1=poly->num_verts-1;    // check for wrap
  1876. int xend1=poly->vlist[endvert1].x+poly->x0;      // get x & y coordinates
  1877. int yend1=poly->vlist[endvert1].y+poly->y0;      // of ending vertices
  1878. int endvert2=startvert2+1;           // get ending vertex of edge 2
  1879. if (endvert2==(poly->num_verts)) 
  1880.     endvert2=0;  // Check for wrap
  1881. int xend2=poly->vlist[endvert2].x+poly->x0;      // get x & y coordinates
  1882. int yend2=poly->vlist[endvert2].y+poly->y0;      // of ending vertices
  1883. // draw the polygon:
  1884. while (edgecount>0) 
  1885.       {    
  1886.       // continue drawing until all edges drawn
  1887.   offset1=mempitch*ystart1+xstart1;  // offset of edge 1
  1888.   offset2=mempitch*ystart2+xstart2;  // offset of edge 2
  1889.   
  1890.       // initialize error terms
  1891.       // for edges 1 & 2
  1892.       errorterm1=0;        
  1893.   errorterm2=0;           
  1894.       // get absolute value of
  1895.       if ((ydiff1=yend1-ystart1) < 0) 
  1896.          ydiff1=-ydiff1;
  1897.       // x & y lengths of edges
  1898.   if ((ydiff2=yend2-ystart2) < 0) 
  1899.          ydiff2=-ydiff2; 
  1900.      if ((xdiff1=xend1-xstart1) < 0) 
  1901.          {               
  1902.          // get value of length
  1903.  xunit1=-1;                    // calculate X increment
  1904.  xdiff1=-xdiff1;
  1905.  } // end if
  1906.   else 
  1907.          {
  1908.  xunit1=1;
  1909.  } // end else
  1910.       if ((xdiff2=xend2-xstart2) < 0) 
  1911.          {
  1912.          // Get value of length
  1913.     xunit2=-1;                   // calculate X increment
  1914.  xdiff2=-xdiff2;
  1915.  } // end else
  1916.   else 
  1917.          {
  1918.  xunit2=1;
  1919.  } // end else
  1920.   // choose which of four routines to use
  1921.   if (xdiff1 > ydiff1) 
  1922.          {    
  1923.          // if x length of edge 1 is greater than y length
  1924.  if (xdiff2 > ydiff2) 
  1925.             {  
  1926.             // if X length of edge 2 is greater than y length
  1927. // increment edge 1 on X and edge 2 on X:
  1928. count1=xdiff1;    // count for x increment on edge 1
  1929. count2=xdiff2;    // count for x increment on edge 2
  1930. while (count1 && count2) 
  1931.                   {  
  1932.                   // continue drawing until one edge is done
  1933.        // calculate edge 1:
  1934.      while ((errorterm1 < xdiff1) && (count1 > 0)) 
  1935.                         { 
  1936.                         // finished w/edge 1?
  1937. if (count1--) 
  1938.                            {     
  1939.                            // count down on edge 1
  1940.    offset1+=xunit1;  // increment pixel offset
  1941.    xstart1+=xunit1;
  1942.    } // end if
  1943.            errorterm1+=ydiff1; // increment error term
  1944.           if (errorterm1 < xdiff1) 
  1945.                            {  // if not more than XDIFF
  1946.        vbuffer[offset1]=(USHORT)poly->color; // ...plot a pixel
  1947.        } // end if
  1948.      } // end while
  1949.                   errorterm1-=xdiff1; // if time to increment X, restore error term
  1950.       // calculate edge 2:
  1951.   while ((errorterm2 < xdiff2) && (count2 > 0)) 
  1952.                         {  
  1953.                         // finished w/edge 2?
  1954. if (count2--) 
  1955.                            {     
  1956.                            // count down on edge 2
  1957.    offset2+=xunit2;  // increment pixel offset
  1958.    xstart2+=xunit2;
  1959.    } // end if
  1960.      errorterm2+=ydiff2; // increment error term
  1961.   if (errorterm2 < xdiff2) 
  1962.                              {  // if not more than XDIFF
  1963.  vbuffer[offset2]=(USHORT)poly->color;  // ...plot a pixel
  1964.      } // end if
  1965.           } // end while
  1966. errorterm2-=xdiff2; // if time to increment X, restore error term
  1967.         // draw line from edge 1 to edge 2:
  1968. length=offset2-offset1; // determine length of horizontal line
  1969. if (length < 0) 
  1970.                        { // if negative...
  1971.    length=-length;       // make it positive
  1972.    start=offset2;        // and set START to edge 2
  1973.           } // end if
  1974. else 
  1975.                        start=offset1;     // else set START to edge 1
  1976.  
  1977.               for (int index=start; index < start+length+1; index++)
  1978.                   {  // From edge to edge...
  1979.        vbuffer[index]=(USHORT)poly->color;         // ...draw the line
  1980.                   } // end for index
  1981. offset1+=mempitch;           // advance edge 1 offset to next line
  1982.        ystart1++;
  1983. offset2+=mempitch;           // advance edge 2 offset to next line
  1984. ystart2++;
  1985.           } // end if
  1986. } // end if
  1987. else 
  1988.             {
  1989.           // increment edge 1 on X and edge 2 on Y:
  1990.     count1=xdiff1;    // count for X increment on edge 1
  1991.     count2=ydiff2;    // count for Y increment on edge 2
  1992.             while (count1 && count2) 
  1993.                   {  // continue drawing until one edge is done
  1994.              // calculate edge 1:
  1995.     while ((errorterm1 < xdiff1) && (count1 > 0)) 
  1996.                         { // finished w/edge 1?
  1997.         if (count1--) 
  1998.                            {
  1999.                            // count down on edge 1
  2000.    offset1+=xunit1;  // increment pixel offset
  2001.    xstart1+=xunit1;
  2002.    } // end if
  2003. errorterm1+=ydiff1; // increment error term
  2004. if (errorterm1 < xdiff1) 
  2005.                            {  // If not more than XDIFF
  2006.    vbuffer[offset1]=(USHORT)poly->color; // ...plot a pixel
  2007.    } // end if
  2008.           } // end while
  2009. errorterm1-=xdiff1; // If time to increment X, restore error term
  2010.            // calculate edge 2:
  2011. errorterm2+=xdiff2; // increment error term
  2012.                     if (errorterm2 >= ydiff2)  
  2013.                        { // if time to increment Y...
  2014.    errorterm2-=ydiff2;        // ...restore error term
  2015.    offset2+=xunit2;           // ...and advance offset to next pixel
  2016.    xstart2+=xunit2;
  2017.          } // end if
  2018.         count2--;
  2019.         // draw line from edge 1 to edge 2:
  2020. length=offset2-offset1; // determine length of horizontal line
  2021. if (length < 0)  
  2022.                        { // if negative...
  2023.    length=-length;       // ...make it positive
  2024.    start=offset2;        // and set START to edge 2
  2025.    } // end if
  2026. else 
  2027.                        start=offset1;        // else set START to edge 1
  2028.         for (int index=start; index < start+length+1; index++)  // from edge to edge
  2029.         {
  2030.                         vbuffer[index]=(USHORT)poly->color;         // ...draw the line
  2031.                         } // end for index
  2032.  
  2033.              offset1+=mempitch;           // advance edge 1 offset to next line
  2034. ystart1++;
  2035. offset2+=mempitch;           // advance edge 2 offset to next line
  2036. ystart2++;
  2037. } // end while
  2038. } // end if
  2039. } // end if
  2040. else 
  2041.             {
  2042. if (xdiff2 > ydiff2) 
  2043.                {
  2044.            // increment edge 1 on Y and edge 2 on X:
  2045.    count1=ydiff1;  // count for Y increment on edge 1
  2046.    count2=xdiff2;  // count for X increment on edge 2
  2047.    while(count1 && count2) 
  2048.                     {  // continue drawing until one edge is done
  2049.           // calculate edge 1:
  2050. errorterm1+=xdiff1; // Increment error term
  2051. if (errorterm1 >= ydiff1)  
  2052.                        {  // if time to increment Y...
  2053.    errorterm1-=ydiff1;         // ...restore error term
  2054.    offset1+=xunit1;            // ...and advance offset to next pixel
  2055.    xstart1+=xunit1;
  2056.    } // end if
  2057.            count1--;
  2058.          // Calculate edge 2:
  2059. while ((errorterm2 < xdiff2) && (count2 > 0)) 
  2060.                           { // finished w/edge 1?
  2061.   if (count2--) 
  2062.                              { // count down on edge 2
  2063.  offset2+=xunit2;  // increment pixel offset
  2064.  xstart2+=xunit2;
  2065.      } // end if
  2066.   errorterm2+=ydiff2; // increment error term
  2067.   if (errorterm2 < xdiff2) 
  2068.                              {  // if not more than XDIFF
  2069.  vbuffer[offset2]=(USHORT)poly->color; // ...plot a pixel
  2070.      } // end if
  2071.        } // end while
  2072. errorterm2-=xdiff2;  // if time to increment X, restore error term
  2073.        // draw line from edge 1 to edge 2:
  2074. length=offset2-offset1; // determine length of horizontal line
  2075. if (length < 0) 
  2076.                        {    // if negative...
  2077.    length=-length;  // ...make it positive
  2078.    start=offset2;   // and set START to edge 2
  2079.    } // end if
  2080. else 
  2081.                        start=offset1;  // else set START to edge 1
  2082.            for (int index=start; index < start+length+1; index++) // from edge to edge...
  2083.         {
  2084.                         vbuffer[index]=(USHORT)poly->color;      // ...draw the line
  2085.                         } // end for index
  2086. offset1+=mempitch;         // advance edge 1 offset to next line
  2087. ystart1++;
  2088. offset2+=mempitch;         // advance edge 2 offset to next line
  2089. ystart2++;
  2090.          } // end if
  2091. } // end if
  2092. else 
  2093.                {
  2094.    // increment edge 1 on Y and edge 2 on Y:
  2095.       count1=ydiff1;  // count for Y increment on edge 1
  2096.    count2=ydiff2;  // count for Y increment on edge 2
  2097.    while(count1 && count2) 
  2098.                     {  
  2099.                     // continue drawing until one edge is done
  2100.            // calculate edge 1:
  2101. errorterm1+=xdiff1;  // increment error term
  2102. if (errorterm1 >= ydiff1)  
  2103.                        {                           // if time to increment Y
  2104.    errorterm1-=ydiff1;         // ...restore error term
  2105.    offset1+=xunit1;            // ...and advance offset to next pixel
  2106.    xstart1+=xunit1;
  2107.    } // end if
  2108.  
  2109.                     count1--;
  2110.              // calculate edge 2:
  2111. errorterm2+=xdiff2;            // increment error term
  2112. if (errorterm2 >= ydiff2)  
  2113.                        {                           // if time to increment Y
  2114.    errorterm2-=ydiff2;         // ...restore error term
  2115.    offset2+=xunit2;            // ...and advance offset to next pixel
  2116.    xstart2+=xunit2;
  2117.    } // end if
  2118.             --count2;
  2119.         // draw line from edge 1 to edge 2:
  2120. length=offset2-offset1;  // determine length of horizontal line
  2121. if (length < 0) 
  2122.                        {          
  2123.                        // if negative...
  2124.    length=-length;        // ...make it positive
  2125.    start=offset2;         // and set START to edge 2
  2126.    } // end if
  2127. else 
  2128.                        start=offset1;         // else set START to edge 1
  2129.         for (int index=start; index < start+length+1; index++)   
  2130.                         { // from edge to edge
  2131.         vbuffer[index]=(USHORT)poly->color;   // ...draw the linee
  2132.                         } // end for index
  2133. offset1+=mempitch;            // advance edge 1 offset to next line
  2134. ystart1++;
  2135. offset2+=mempitch;            // advance edge 2 offset to next line
  2136. ystart2++;
  2137. } // end while
  2138. } // end else
  2139. } // end if
  2140.     // another edge (at least) is complete. Start next edge, if any.
  2141. if (!count1) 
  2142.            {                      // if edge 1 is complete...
  2143.    --edgecount;           // decrement the edge count
  2144.    startvert1=endvert1;   // make ending vertex into start vertex
  2145.    --endvert1;            // and get new ending vertex
  2146.            if (endvert1 < 0) 
  2147.               endvert1=poly->num_verts-1; // check for wrap
  2148. xend1=poly->vlist[endvert1].x+poly->x0;  // get x & y of new end vertex
  2149. yend1=poly->vlist[endvert1].y+poly->y0;
  2150.     } // end if
  2151. if (!count2) 
  2152.            {                     // if edge 2 is complete...
  2153.    --edgecount;          // decrement the edge count
  2154.    startvert2=endvert2;  // make ending vertex into start vertex
  2155.    endvert2++;           // and get new ending vertex
  2156.            if (endvert2==(poly->num_verts)) 
  2157.               endvert2=0;                // check for wrap
  2158. xend2=poly->vlist[endvert2].x+poly->x0;  // get x & y of new end vertex
  2159. yend2=poly->vlist[endvert2].y+poly->y0;
  2160.    } // end if
  2161. } // end while
  2162. } // end Draw_Filled_Polygon2D16
  2163. ///////////////////////////////////////////////////////////////
  2164. void Build_Sin_Cos_Tables(void)
  2165. {
  2166.   
  2167. // create sin/cos lookup table
  2168. // note the creation of one extra element; 360
  2169. // this helps with logic in using the tables
  2170. // generate the tables 0 - 360 inclusive
  2171. for (int ang = 0; ang <= 360; ang++)
  2172.     {
  2173.     // convert ang to radians
  2174.     float theta = (float)ang*PI/(float)180;
  2175.     // insert next entry into table
  2176.     cos_look[ang] = cos(theta);
  2177.     sin_look[ang] = sin(theta);
  2178.     } // end for ang
  2179. } // end Build_Sin_Cos_Tables
  2180. //////////////////////////////////////////////////////////////
  2181. int Translate_Polygon2D(POLYGON2D_PTR poly, int dx, int dy)
  2182. {
  2183. // this function translates the center of a polygon
  2184. // test for valid pointer
  2185. if (!poly)
  2186.    return(0);
  2187. // translate
  2188. poly->x0+=dx;
  2189. poly->y0+=dy;
  2190. // return success
  2191. return(1);
  2192. } // end Translate_Polygon2D
  2193. ///////////////////////////////////////////////////////////////
  2194. int Rotate_Polygon2D(POLYGON2D_PTR poly, int theta)
  2195. {
  2196. // this function rotates the local coordinates of the polygon
  2197. // test for valid pointer
  2198. if (!poly)
  2199.    return(0);
  2200. // test for negative rotation angle
  2201. if (theta < 0)
  2202.    theta+=360;
  2203. // loop and rotate each point, very crude, no lookup!!!
  2204. for (int curr_vert = 0; curr_vert < poly->num_verts; curr_vert++)
  2205.     {
  2206.     // perform rotation
  2207.     float xr = (float)poly->vlist[curr_vert].x*cos_look[theta] - 
  2208.                     (float)poly->vlist[curr_vert].y*sin_look[theta];
  2209.     float yr = (float)poly->vlist[curr_vert].x*sin_look[theta] + 
  2210.                     (float)poly->vlist[curr_vert].y*cos_look[theta];
  2211.     // store result back
  2212.     poly->vlist[curr_vert].x = xr;
  2213.     poly->vlist[curr_vert].y = yr;
  2214.     } // end for curr_vert
  2215. // return success
  2216. return(1);
  2217. } // end Rotate_Polygon2D
  2218. ////////////////////////////////////////////////////////
  2219. int Scale_Polygon2D(POLYGON2D_PTR poly, float sx, float sy)
  2220. {
  2221. // this function scalesthe local coordinates of the polygon
  2222. // test for valid pointer
  2223. if (!poly)
  2224.    return(0);
  2225. // loop and scale each point
  2226. for (int curr_vert = 0; curr_vert < poly->num_verts; curr_vert++)
  2227.     {
  2228.     // scale and store result back
  2229.     poly->vlist[curr_vert].x *= sx;
  2230.     poly->vlist[curr_vert].y *= sy;
  2231.     } // end for curr_vert
  2232. // return success
  2233. return(1);
  2234. } // end Scale_Polygon2D
  2235. ///////////////////////////////////////////////////////////
  2236. int Draw_Polygon2D16(POLYGON2D_PTR poly, UCHAR *vbuffer, int lpitch)
  2237. {
  2238. // this function draws a POLYGON2D based on 
  2239. // test if the polygon is visible
  2240. if (poly->state)
  2241.    {
  2242.    // loop thru and draw a line from vertices 1 to n
  2243.    for (int index=0; index < poly->num_verts-1; index++)
  2244.         {
  2245.         // draw line from ith to ith+1 vertex
  2246.         Draw_Clip_Line16(poly->vlist[index].x+poly->x0, 
  2247.                          poly->vlist[index].y+poly->y0,
  2248.                          poly->vlist[index+1].x+poly->x0, 
  2249.                          poly->vlist[index+1].y+poly->y0,
  2250.                          poly->color,
  2251.                          vbuffer, lpitch);
  2252.         } // end for
  2253.        // now close up polygon
  2254.        // draw line from last vertex to 0th
  2255.        Draw_Clip_Line16(poly->vlist[0].x+poly->x0, 
  2256.                         poly->vlist[0].y+poly->y0,
  2257.                         poly->vlist[index].x+poly->x0, 
  2258.                         poly->vlist[index].y+poly->y0,
  2259.                         poly->color,
  2260.                         vbuffer, lpitch);
  2261.    // return success
  2262.    return(1);
  2263.    } // end if
  2264. else 
  2265.    return(0);
  2266. } // end Draw_Polygon2D16
  2267. ///////////////////////////////////////////////////////////
  2268. int Draw_Polygon2D(POLYGON2D_PTR poly, UCHAR *vbuffer, int lpitch)
  2269. {
  2270. // this function draws a POLYGON2D based on 
  2271. // test if the polygon is visible
  2272. if (poly->state)
  2273.    {
  2274.    // loop thru and draw a line from vertices 1 to n
  2275.    for (int index=0; index < poly->num_verts-1; index++)
  2276.         {
  2277.         // draw line from ith to ith+1 vertex
  2278.         Draw_Clip_Line(poly->vlist[index].x+poly->x0, 
  2279.                        poly->vlist[index].y+poly->y0,
  2280.                        poly->vlist[index+1].x+poly->x0, 
  2281.                        poly->vlist[index+1].y+poly->y0,
  2282.                        poly->color,
  2283.                        vbuffer, lpitch);
  2284.         } // end for
  2285.        // now close up polygon
  2286.        // draw line from last vertex to 0th
  2287.        Draw_Clip_Line(poly->vlist[0].x+poly->x0, 
  2288.                       poly->vlist[0].y+poly->y0,
  2289.                       poly->vlist[index].x+poly->x0, 
  2290.                       poly->vlist[index].y+poly->y0,
  2291.                       poly->color,
  2292.                       vbuffer, lpitch);
  2293.    // return success
  2294.    return(1);
  2295.    } // end if
  2296. else 
  2297.    return(0);
  2298. } // end Draw_Polygon2D
  2299. ///////////////////////////////////////////////////////////////
  2300. // these are the matrix versions, note they are more inefficient for
  2301. // single transforms, but their power comes into play when you concatenate
  2302. // multiple transformations, not to mention that all transforms are accomplished
  2303. // with the same code, just the matrix differs
  2304. int Translate_Polygon2D_Mat(POLYGON2D_PTR poly, int dx, int dy)
  2305. {
  2306. // this function translates the center of a polygon by using a matrix multiply
  2307. // on the the center point, this is incredibly inefficient, but for educational purposes
  2308. // if we had an object that wasn't in local coordinates then it would make more sense to
  2309. // use a matrix, but since the origin of the object is at x0,y0 then 2 lines of code can
  2310. // translate, but lets do it the hard way just to see :)
  2311. // test for valid pointer
  2312. if (!poly)
  2313.    return(0);
  2314. MATRIX3X2 mt; // used to hold translation transform matrix
  2315. // initialize the matrix with translation values dx dy
  2316. Mat_Init_3X2(&mt,1,0, 0,1, dx, dy); 
  2317. // create a 1x2 matrix to do the transform
  2318. MATRIX1X2 p0 = {poly->x0, poly->y0};
  2319. MATRIX1X2 p1 = {0,0}; // this will hold result
  2320. // now translate via a matrix multiply
  2321. Mat_Mul_1X2_3X2(&p0, &mt, &p1);
  2322. // now copy the result back into polygon
  2323. poly->x0 = p1.M[0];
  2324. poly->y0 = p1.M[1];
  2325. // return success
  2326. return(1);
  2327. } // end Translate_Polygon2D_Mat
  2328. ///////////////////////////////////////////////////////////////
  2329. int Rotate_Polygon2D_Mat(POLYGON2D_PTR poly, int theta)
  2330. {
  2331. // this function rotates the local coordinates of the polygon
  2332. // test for valid pointer
  2333. if (!poly)
  2334.    return(0);
  2335. // test for negative rotation angle
  2336. if (theta < 0)
  2337.    theta+=360;
  2338. MATRIX3X2 mr; // used to hold rotation transform matrix
  2339. // initialize the matrix with translation values dx dy
  2340. Mat_Init_3X2(&mr,cos_look[theta],sin_look[theta], 
  2341.                  -sin_look[theta],cos_look[theta], 
  2342.                   0, 0); 
  2343. // loop and rotate each point, very crude, no lookup!!!
  2344. for (int curr_vert = 0; curr_vert < poly->num_verts; curr_vert++)
  2345.     {
  2346.     // create a 1x2 matrix to do the transform
  2347.     MATRIX1X2 p0 = {poly->vlist[curr_vert].x, poly->vlist[curr_vert].y};
  2348.     MATRIX1X2 p1 = {0,0}; // this will hold result
  2349.     // now rotate via a matrix multiply
  2350.     Mat_Mul_1X2_3X2(&p0, &mr, &p1);
  2351.     // now copy the result back into vertex
  2352.     poly->vlist[curr_vert].x = p1.M[0];
  2353.     poly->vlist[curr_vert].y = p1.M[1];
  2354.     } // end for curr_vert
  2355. // return success
  2356. return(1);
  2357. } // end Rotate_Polygon2D_Mat
  2358. ////////////////////////////////////////////////////////
  2359. int Scale_Polygon2D_Mat(POLYGON2D_PTR poly, float sx, float sy)
  2360. {
  2361. // this function scalesthe local coordinates of the polygon
  2362. // test for valid pointer
  2363. if (!poly)
  2364.    return(0);
  2365. MATRIX3X2 ms; // used to hold scaling transform matrix
  2366. // initialize the matrix with translation values dx dy
  2367. Mat_Init_3X2(&ms,sx,0, 
  2368.                  0,sy, 
  2369.                  0, 0); 
  2370. // loop and scale each point
  2371. for (int curr_vert = 0; curr_vert < poly->num_verts; curr_vert++)
  2372.     {
  2373.     // scale and store result back
  2374.     
  2375.     // create a 1x2 matrix to do the transform
  2376.     MATRIX1X2 p0 = {poly->vlist[curr_vert].x, poly->vlist[curr_vert].y};
  2377.     MATRIX1X2 p1 = {0,0}; // this will hold result
  2378.     // now scale via a matrix multiply
  2379.     Mat_Mul_1X2_3X2(&p0, &ms, &p1);
  2380.     // now copy the result back into vertex
  2381.     poly->vlist[curr_vert].x = p1.M[0];
  2382.     poly->vlist[curr_vert].y = p1.M[1];
  2383.     } // end for curr_vert
  2384. // return success
  2385. return(1);
  2386. } // end Scale_Polygon2D_Mat
  2387. ///////////////////////////////////////////////////////////
  2388. int Mat_Mul_3X3(MATRIX3X3_PTR ma, 
  2389.                MATRIX3X3_PTR mb,
  2390.                MATRIX3X3_PTR mprod)
  2391. {
  2392. // this function multiplies two matrices together and 
  2393. // and stores the result
  2394. for (int row=0; row<3; row++)
  2395.     {
  2396.     for (int col=0; col<3; col++)
  2397.         {
  2398.         // compute dot product from row of ma 
  2399.         // and column of mb
  2400.         float sum = 0; // used to hold result
  2401.         for (int index=0; index<3; index++)
  2402.              {
  2403.              // add in next product pair
  2404.              sum+=(ma->M[row][index]*mb->M[index][col]);
  2405.              } // end for index
  2406.         // insert resulting row,col element
  2407.         mprod->M[row][col] = sum;
  2408.         } // end for col
  2409.     } // end for row
  2410. return(1);
  2411. } // end Mat_Mul_3X3
  2412. ////////////////////////////////////////////////////////////////
  2413. int Mat_Mul_1X3_3X3(MATRIX1X3_PTR ma, 
  2414.                    MATRIX3X3_PTR mb,
  2415.                    MATRIX1X3_PTR mprod)
  2416. {
  2417. // this function multiplies a 1x3 matrix against a 
  2418. // 3x3 matrix - ma*mb and stores the result
  2419.     for (int col=0; col<3; col++)
  2420.         {
  2421.         // compute dot product from row of ma 
  2422.         // and column of mb
  2423.         float sum = 0; // used to hold result
  2424.         for (int index=0; index<3; index++)
  2425.              {
  2426.              // add in next product pair
  2427.              sum+=(ma->M[index]*mb->M[index][col]);
  2428.              } // end for index
  2429.         // insert resulting col element
  2430.         mprod->M[col] = sum;
  2431.         } // end for col
  2432. return(1);
  2433. } // end Mat_Mul_1X3_3X3
  2434. ////////////////////////////////////////////////////////////////
  2435. int Mat_Mul_1X2_3X2(MATRIX1X2_PTR ma, 
  2436.                    MATRIX3X2_PTR mb,
  2437.                    MATRIX1X2_PTR mprod)
  2438. {
  2439. // this function multiplies a 1x2 matrix against a 
  2440. // 3x2 matrix - ma*mb and stores the result
  2441. // using a dummy element for the 3rd element of the 1x2 
  2442. // to make the matrix multiply valid i.e. 1x3 X 3x2
  2443.     for (int col=0; col<2; col++)
  2444.         {
  2445.         // compute dot product from row of ma 
  2446.         // and column of mb
  2447.         float sum = 0; // used to hold result
  2448.         for (int index=0; index<2; index++)
  2449.              {
  2450.              // add in next product pair
  2451.              sum+=(ma->M[index]*mb->M[index][col]);
  2452.              } // end for index
  2453.         // add in last element * 1 
  2454.         sum+= mb->M[index][col];
  2455.         // insert resulting col element
  2456.         mprod->M[col] = sum;
  2457.         } // end for col
  2458. return(1);
  2459. } // end Mat_Mul_1X2_3X2
  2460. //////////////////////////////////////////////////////////////
  2461. #if 0
  2462. inline int Mat_Init_3X2(MATRIX3X2_PTR ma, 
  2463.                         float m00, float m01,
  2464.                         float m10, float m11,
  2465.                         float m20, float m21)
  2466. {
  2467. // this function fills a 3x2 matrix with the sent data in row major form
  2468. ma->M[0][0] = m00; ma->M[0][1] = m01; 
  2469. ma->M[1][0] = m10; ma->M[1][1] = m11; 
  2470. ma->M[2][0] = m20; ma->M[2][1] = m21; 
  2471. // return success
  2472. return(1);
  2473. } // end Mat_Init_3X2
  2474. #endif
  2475. /////////////////////////////////////////////////////////////////