填充实心多边形(一)

可以利用前一篇文章中的Cohen-Sutherland裁剪算法对缓冲区的任意图形画出经裁剪的该图形,那么接下来该如何填充这些图形(一般是多边形)。若是四边形,我们可以把它分解成2个三角形。而对于任意三角形,又可以分解成一个平底三角形和一个平顶三角形。接下来给出填充任意三角形的代码,摘自《windows游戏编程大师技巧》。

  1. /* 2008/9/4
  2. 代码功能:填充任意三角形
  3. 并经过矩形裁剪*/
  4. #define WIN32_LEAN_AND_MEAN   //不使用MFC
  5. #define INITGUID      //使用GUID
  6. #include <windows.h>
  7. #include <windowsx.h>
  8. #include <mmsystem.h> //多媒体API
  9. #include <iostream.h>
  10. #include <conio.h>    //控制台IO支持
  11. #include <stdlib.h>   //声明定义的一些常用标准函数库
  12. #include <malloc.h>   //声明或定义一些内存的函数
  13. #include <memory.h>   //提供了内存操作相关的一些函数及声明
  14. #include <string.h>   //字符串的一些功能
  15. #include <stdarg.h>   //defines ANSI-style macros for variable argument functions
  16. #include <stdio.h>    //efinitions/declarations for standard I/O routines
  17. #include <math.h>     //一些数学方法
  18. #include <io.h>       //declarations for low-level file handling and I/O functions
  19. #include <fcntl.h>    //file control options used by open()
  20. #include <ddraw.h>
  21. //windows类名
  22. #define  WINDOW_CLASS_NAME "WINCLASS1"
  23. //宽,高,色深(像素)
  24. #define  SCREEN_WIDTH   640
  25. #define  SCREEN_HEIGHT   480
  26. #define  SCREEN_BPP     8
  27. #define  MAX_COLORS_PALETTE   256
  28. typedef unsigned short USHORT;
  29. typedef unsigned short WORD;
  30. typedef unsigned char UCHAR;
  31. typedef unsigned char BYTE;
  32. //GDI文字函数
  33. int Draw_Text_GDI(char* text,int x,int y,int color,LPDIRECTDRAWSURFACE7 lpdds);
  34. //填充表面
  35. int DDraw_Fill_Surface(LPDIRECTDRAWSURFACE7 lpdds,int color);
  36. //填充任意三角形
  37. void Draw_Triangle_2D(int x1,int y1,int x2,int y2,int x3,int y3,int color,UCHAR *dest_buffer,int mempitch);
  38. //填充平顶三角形
  39. void Draw_Top_Tri(int x1,int y1,int x2,int y2,int x3,int y3,int color,UCHAR *dest_buffer,int mempitch);
  40. //填充平底三角形
  41. void Draw_Bottom_Tri(int x1,int y1,int x2,int y2,int x3,int y3,int color,UCHAR *dest_buffer,int mempitch);
  42. //键盘按键宏
  43. #define  KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code)&0x8000)?1:0)
  44. #define  KEYUP(vk_code)   ((GetAsyncKeyState(vk_code)&0x8000)?0:1)
  45. //初始化结构体
  46. #define  DDRAW_INIT_STRUCT(ddstruct) { memset(&ddstruct,0,sizeof(ddstruct));ddstruct.dwSize=sizeof(ddstruct); }
  47. HWND main_window_handle =NULL;
  48. int  window_closed =0;
  49. HINSTANCE hinstance_app =NULL;
  50. LPDIRECTDRAW7 lpdd =NULL;
  51. LPDIRECTDRAWSURFACE7 lpddsprimary =NULL;  //主缓存
  52. LPDIRECTDRAWSURFACE7 lpddsback =NULL;     //后备缓冲
  53. LPDIRECTDRAWPALETTE  lpddpal =NULL;       //调色板接口
  54. LPDIRECTDRAWCLIPPER  lpddclipper =NULL;   //裁剪器
  55. PALETTEENTRY         palette[256];        //调色板
  56. DDSURFACEDESC2       ddsd;
  57. DDBLTFX              ddbltfx;
  58. DDSCAPS2             ddscaps;
  59. /*裁剪区域*/
  60. int min_clip_x = 0,
  61.     max_clip_x =SCREEN_WIDTH-1, 
  62.     min_clip_y = 0,
  63.     max_clip_y = SCREEN_HEIGHT-1;
  64. char buffer[80];
  65. int Draw_Text_GDI(char* text,int x,int y,int color,LPDIRECTDRAWSURFACE7 lpdds)
  66. {
  67.   HDC xdc;
  68.   if(FAILED(lpdds->GetDC(&xdc)))
  69.     return(0);
  70.   SetTextColor(xdc,RGB(palette[color].peRed,palette[color].peGreen,palette[color].peBlue));
  71.   SetBkMode(xdc,TRANSPARENT);
  72.   TextOut(xdc,x,y,text,strlen(text));
  73.   lpdds->ReleaseDC(xdc);
  74.   return(1);
  75. }
  76. int DDraw_Fill_Surface(LPDIRECTDRAWSURFACE7 lpdds,int color)
  77. {
  78.   DDRAW_INIT_STRUCT(ddbltfx);
  79.   ddbltfx.dwFillColor=color;
  80.   lpdds->Blt(NULL,
  81.              NULL,
  82.              NULL,
  83.              DDBLT_COLORFILL|DDBLT_WAIT,
  84.              &ddbltfx);
  85.   return(1);
  86. }
  87. //填充平顶三角形
  88. void Draw_Top_Tri(int x1,int y1,
  89.                   int x2,int y2,
  90.                   int x3,int y3,
  91.                   int color,
  92.                   UCHAR *dest_buffer,int mempitch)
  93. {
  94.   float dx_right,
  95.         dx_left,
  96.         xs,xe,
  97.         height;
  98.   int temp_x,
  99.       temp_y,
  100.       right,
  101.       left;
  102.   UCHAR *dest_addr=NULL;
  103.   if (x2<x1)
  104.   {
  105.     temp_x=x2;
  106.     x2=x1;
  107.     x1=temp_x;
  108.   }
  109.   height=y3-y1;
  110.   dx_left=(x3-x1)/height;
  111.   dx_right=(x3-x2)/height;
  112.   xs=(float)x1;
  113.   xe=(float)x2;
  114.   if(y1<min_clip_y)
  115.   {
  116.     xs=xs+dx_left*(float)(-y1+min_clip_y);
  117.     xe=xe+dx_right*(false)(-y1+min_clip_y);
  118.     y1=min_clip_y;
  119.   }
  120.   if(y3>max_clip_y)
  121.     y3=max_clip_y;
  122.   dest_addr=dest_buffer+y1*mempitch;
  123.   if(x1>min_clip_x&&x1<max_clip_x&
  124.       x2>min_clip_x&&x2<max_clip_x&
  125.       x3>min_clip_x&&x3<max_clip_x)
  126.   {/*若三角形完全在裁剪区域内*/
  127.     for (temp_y=y1;temp_y<=y3;temp_y++,dest_addr+=mempitch)
  128.     {
  129.       memset((UCHAR*)dest_addr+(size_t)xs,color,(size_t)(xe-xs+1));
  130.       xs+=dx_left;
  131.       xe+=dx_right;
  132.     }
  133.   }
  134.   else
  135.   {/*三角形有落在裁剪区域外的部分*/
  136.     for (temp_y=y1;temp_y<=y3;temp_y++,dest_addr+=mempitch)
  137.     {
  138.       left=(int)xs;
  139.       right=(int)xe;
  140.       xs+=dx_left;
  141.       xe+=dx_right;
  142.       if(left<min_clip_x)
  143.       {
  144.         left=min_clip_x;
  145.         if(right<min_clip_x)
  146.           continue;
  147.       }
  148.       if(right>max_clip_x)
  149.       {
  150.         right=max_clip_x;
  151.         if(left>max_clip_x)
  152.           continue;
  153.       }
  154.       memset((UCHAR*)dest_addr+(size_t)left,color,(size_t)(right-left+1));
  155.     }
  156.   }
  157. }
  158. //填充平底三角形
  159. void Draw_Bottom_Tri(int x1,int y1, 
  160.                      int x2,int y2, 
  161.                      int x3,int y3,
  162.                      int color,
  163.                      UCHAR *dest_buffer, int mempitch)
  164. {
  165. // this function draws a triangle that has a flat bottom
  166. float dx_right,    // the dx/dy ratio of the right edge of line
  167.       dx_left,     // the dx/dy ratio of the left edge of line
  168.       xs,xe,       // the starting and ending points of the edges
  169.       height;      // the height of the triangle
  170. int temp_x,        // used during sorting as temps
  171.     temp_y,
  172.     right,         // used by clipping
  173.     left;
  174. // destination address of next scanline
  175. UCHAR  *dest_addr;
  176. // test order of x1 and x2
  177. if (x3 < x2)
  178.    {
  179.    temp_x = x2;
  180.    x2     = x3;
  181.    x3     = temp_x;
  182.    } // end if swap
  183. // compute delta's
  184. height = y3-y1;
  185. dx_left  = (x2-x1)/height;
  186. dx_right = (x3-x1)/height;
  187. // set starting points
  188. xs = (float)x1;
  189. xe = (float)x1; // +(float)0.5;
  190. // perform y clipping
  191. if (y1<min_clip_y)
  192.    {
  193.    // compute new xs and ys
  194.    xs = xs+dx_left*(float)(-y1+min_clip_y);
  195.    xe = xe+dx_right*(float)(-y1+min_clip_y);
  196.    // reset y1
  197.    y1=min_clip_y;
  198.    } // end if top is off screen
  199. if (y3>max_clip_y)
  200.    y3=max_clip_y;
  201. // compute starting address in video memory
  202. dest_addr = dest_buffer+y1*mempitch;
  203. // test if x clipping is needed
  204. if (x1>=min_clip_x && x1<=max_clip_x &
  205.     x2>=min_clip_x && x2<=max_clip_x &
  206.     x3>=min_clip_x && x3<=max_clip_x)
  207.     {
  208.     // draw the triangle
  209.     for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  210.         {
  211.         memset((UCHAR  *)dest_addr+(unsigned int)xs,
  212.                 color,(unsigned int)(xe-xs+1));
  213.         // adjust starting point and ending point
  214.         xs+=dx_left;
  215.         xe+=dx_right;
  216.         } // end for
  217.     } // end if no x clipping needed
  218. else
  219.    {
  220.    // clip x axis with slower version
  221.    // draw the triangle
  222.    for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  223.        {
  224.        // do x clip
  225.        left  = (int)xs;
  226.        right = (int)xe;
  227.        // adjust starting point and ending point
  228.        xs+=dx_left;
  229.        xe+=dx_right;
  230.        // clip line
  231.        if (left < min_clip_x)
  232.           {
  233.           left = min_clip_x;
  234.           if (right < min_clip_x)
  235.              continue;
  236.           }
  237.        if (right > max_clip_x)
  238.           {
  239.           right = max_clip_x;
  240.           if (left > max_clip_x)
  241.              continue;
  242.           }
  243.        memset((UCHAR  *)dest_addr+(unsigned int)left,
  244.               color,(unsigned int)(right-left+1));
  245.        } // end for
  246.    } // end else x clipping needed
  247. // end Draw_Bottom_Tri
  248. //填充三角形
  249. void Draw_Triangle_2D(int x1,int y1,
  250.                       int x2,int y2,
  251.                       int x3,int y3,
  252.                       int color,
  253.                       UCHAR *dest_buffer,int mempitch)
  254. {
  255.   int temp_x,
  256.       temp_y,
  257.       new_x;
  258.   //三角形x||y坐标在同一直线
  259.   if ((x1==x2&&x2==x3)||(y1==y2&&y2==y3))
  260.     return;
  261.   //确定三角形三点的位置
  262.   if (y2<y1)
  263.   {
  264.     temp_x=x2;
  265.     temp_y=y2;
  266.     x2=x1;
  267.     y2=y1;
  268.     x1=temp_x;
  269.     y1=temp_y;
  270.   }
  271.   if (y3<y1)
  272.   {
  273.     temp_x=x3;
  274.     temp_y=y3;
  275.     x3=x1;
  276.     y3=y1;
  277.     x1=temp_x;
  278.     y1=temp_y;
  279.   }
  280.   if (y3<y2)
  281.   {
  282.     temp_x=x3;
  283.     temp_y=y3;
  284.     x3=x2;
  285.     y3=y2;
  286.     x2=temp_x;
  287.     y2=temp_y;
  288.   }
  289.   if (y3<min_clip_y||y1>max_clip_y||
  290.       (x1<min_clip_x&&x2<min_clip_x&&x3<min_clip_x)||
  291.       (x1>max_clip_x&&x2>max_clip_x&&x3>max_clip_x))
  292.       return;
  293.   if(y1==y2)
  294.     Draw_Top_Tri(x1,y1,x2,y2,x3,y3,color,dest_buffer,mempitch);
  295.   else
  296.   if(y2==y3)
  297.     Draw_Bottom_Tri(x1,y1,x2,y2,x3,y3,color,dest_buffer,mempitch);
  298.   else
  299.   {/*三角形是任意的*/
  300.     new_x=x1+(int)(0.5+(float)(y2-y1)*(float)(x3-x1)/(float)(y3-y1));
  301.     Draw_Bottom_Tri(x1,y1,new_x,y2,x2,y2,color,dest_buffer,mempitch);
  302.     Draw_Top_Tri(x2,y2,new_x,y2,x3,y3,color,dest_buffer,mempitch);
  303.   }
  304.   
  305. }
  306. LRESULT CALLBACK WindowProc(HWND hwnd,
  307.                             UINT msg,
  308.                             WPARAM wparam,
  309.                             LPARAM lparam)
  310. {
  311. PAINTSTRUCT     ps;     
  312. HDC             hdc;    
  313.        
  314. switch(msg)
  315.     {   
  316.     case WM_CREATE: 
  317.         {
  318.         return(0);
  319.         } break;
  320.    
  321.     case WM_PAINT: 
  322.         {
  323.         hdc = BeginPaint(hwnd,&ps);  
  324.         
  325.         EndPaint(hwnd,&ps);
  326.         return(0);
  327.         } break;
  328.     case WM_DESTROY: 
  329.         {
  330.         PostQuitMessage(0);
  331.         return(0);
  332.         } break;
  333.     default:break;
  334.     }
  335. return (DefWindowProc(hwnd, msg, wparam, lparam));
  336. }
  337. int Game_Init(void *parms=NULL,int num_parms=0)
  338. {
  339.   if(FAILED(DirectDrawCreateEx(NULL,(void **)&lpdd,IID_IDirectDraw7,NULL)))
  340.     return(0);
  341.   if(FAILED(lpdd->SetCooperativeLevel(main_window_handle,
  342.                                       DDSCL_FULLSCREEN|DDSCL_ALLOWMODEX|
  343.                                       DDSCL_EXCLUSIVE|DDSCL_ALLOWREBOOT)))
  344.     return(0);
  345.   if(FAILED(lpdd->SetDisplayMode(SCREEN_WIDTH,SCREEN_HEIGHT,SCREEN_BPP,0,0)))
  346.     return(0);
  347.   DDRAW_INIT_STRUCT(ddsd);
  348.   ddsd.dwFlags=DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
  349.   ddsd.dwBackBufferCount=1;
  350.   ddsd.ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE|DDSCAPS_COMPLEX|
  351.                         DDSCAPS_FLIP;
  352.   
  353.   if(FAILED(lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL)))
  354.     return(0);
  355.   ddsd.ddsCaps.dwCaps=DDSCAPS_BACKBUFFER;
  356.   if(FAILED(lpddsprimary->GetAttachedSurface(&ddsd.ddsCaps,&lpddsback)))
  357.     return(0);
  358.   for (int color=1; color < 255; color++)
  359.     {
  360.     palette[color].peRed   = rand()%256;
  361.     palette[color].peGreen = rand()%256;
  362.     palette[color].peBlue  = rand()%256;
  363.     palette[color].peFlags = PC_NOCOLLAPSE;
  364.     } 
  365. palette[0].peRed     = 0;
  366. palette[0].peGreen   = 0;
  367. palette[0].peBlue    = 0;
  368. palette[0].peFlags   = PC_NOCOLLAPSE;
  369. palette[255].peRed   = 255;
  370. palette[255].peGreen = 255;
  371. palette[255].peBlue  = 255;
  372. palette[255].peFlags = PC_NOCOLLAPSE;
  373. palette[1].peRed     = 255;
  374. palette[1].peGreen   = 0;
  375. palette[1].peBlue    = 0;
  376. palette[1].peFlags   = PC_NOCOLLAPSE;
  377. if(FAILED(lpdd->CreatePalette(DDPCAPS_8BIT|DDPCAPS_ALLOW256|
  378.                               DDPCAPS_INITIALIZE,palette,&lpddpal,NULL)))
  379.     return(0);
  380. if(FAILED(lpddsprimary->SetPalette(lpddpal)))
  381.     return(0);
  382. DDraw_Fill_Surface(lpddsprimary,0);
  383. DDraw_Fill_Surface(lpddsback,0);
  384. return(1);  
  385. }
  386. int Game_Main(void *parms = NULL, int num_parms = 0)
  387. {
  388.   if(window_closed)
  389.     return(0);
  390.   if(KEYDOWN(VK_ESCAPE))
  391.   {
  392.     PostMessage(main_window_handle,WM_CLOSE,0,0);
  393.     window_closed=1;
  394.   }
  395.   DDraw_Fill_Surface(lpddsback,0);
  396.   DDRAW_INIT_STRUCT(ddsd);
  397.   if(FAILED(lpddsback->Lock(NULL,&ddsd,DDLOCK_WAIT|DDLOCK_SURFACEMEMORYPTR,NULL)))
  398.     return(0);
  399.   Draw_Triangle_2D(rand()%SCREEN_WIDTH, rand()%SCREEN_HEIGHT,
  400.                  rand()%SCREEN_WIDTH, rand()%SCREEN_HEIGHT,
  401.                  rand()%SCREEN_WIDTH, rand()%SCREEN_HEIGHT,
  402.                  rand()%256,(UCHAR *)ddsd.lpSurface, ddsd.lPitch);
  403.   if (FAILED(lpddsback->Unlock(NULL)))
  404.    return(0);
  405. while(FAILED(lpddsprimary->Flip(NULL,DDFLIP_WAIT)));
  406.   
  407. Sleep(33);
  408. return(1);
  409. }
  410. int Game_Shutdown(void *parms = NULL, int num_parms = 0)
  411. {/*清除资源*/
  412. if (lpddpal)
  413.    {
  414.    lpddpal->Release();
  415.    lpddpal = NULL;
  416.    }
  417. if(lpddsback)
  418.   {
  419.   lpddsback->Release();
  420.   lpddsback=NULL;
  421.   }
  422. if (lpddsprimary)
  423.    {
  424.    lpddsprimary->Release();
  425.    lpddsprimary = NULL;
  426.    } 
  427. if (lpdd)
  428.    {
  429.    lpdd->Release();
  430.    lpdd = NULL;
  431.    } 
  432. return(1);
  433. }
  434. int WINAPI WinMain( HINSTANCE hinstance,
  435.                     HINSTANCE hprevinstance,
  436.                     LPSTR lpcmdline,
  437.                     int ncmdshow)
  438. {
  439. WNDCLASSEX winclass; 
  440. HWND       hwnd;    
  441. MSG        msg;      
  442. //HDC        hdc;    
  443. winclass.cbSize         = sizeof(WNDCLASSEX);
  444. winclass.style          = CS_DBLCLKS | CS_OWNDC | 
  445.                           CS_HREDRAW | CS_VREDRAW;
  446. winclass.lpfnWndProc    = WindowProc;
  447. winclass.cbClsExtra     = 0;
  448. winclass.cbWndExtra     = 0;
  449. winclass.hInstance      = hinstance;
  450. winclass.hIcon          = LoadIcon(NULL, IDI_APPLICATION);
  451. winclass.hCursor        = LoadCursor(NULL, IDC_ARROW); 
  452. winclass.hbrBackground  = (HBRUSH)GetStockObject(BLACK_BRUSH);
  453. winclass.lpszMenuName   = NULL;
  454. winclass.lpszClassName  = WINDOW_CLASS_NAME;
  455. winclass.hIconSm        = LoadIcon(NULL, IDI_APPLICATION);
  456. hinstance_app = hinstance;
  457. if (!RegisterClassEx(&winclass))
  458.     return(0);
  459. if (!(hwnd = CreateWindowEx(NULL,                  
  460.                             WINDOW_CLASS_NAME,    
  461.                             "DirectDraw 8-Bit Line Drawing Demo"
  462.                             WS_POPUP | WS_VISIBLE,
  463.                             0,0,    
  464.                             SCREEN_WIDTH,SCREEN_HEIGHT,  
  465.                             NULL,     
  466.                             NULL,  
  467.                             hinstance,
  468.                             NULL))) 
  469. return(0);
  470. main_window_handle = hwnd;
  471. Game_Init();
  472. while(TRUE)
  473.     {
  474.   
  475.     if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
  476.        { 
  477.        if (msg.message == WM_QUIT)
  478.            break;
  479.     
  480.        TranslateMessage(&msg);
  481.        DispatchMessage(&msg);
  482.        }
  483.      Game_Main();
  484.        
  485.     } 
  486. Game_Shutdown();
  487. return(msg.wParam);
  488. }

若是四边形则可以分解成2个三角形来进行填充。

  1. inline void Draw_Quad_2D(int x0,int y0,
  2.                     int x1,int y1,
  3.                     int x2,int y2,
  4.                     int x3, int y3,
  5.                     int color,
  6.                     UCHAR *dest_buffer, int mempitch)
  7. {//填充任意四边形
  8. Draw_Triangle_2D(x0,y0,x1,y1,x3,y3,color,dest_buffer,mempitch);
  9. Draw_Triangle_2D(x1,y1,x2,y2,x3,y3,color,dest_buffer,mempitch);
  10. }

这里把填充四边形的函数设为inline类型,因为该函数够简短,避免了无谓的压栈出栈操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值