• Windows游戏编程大师技巧之三角形填充


    一。三角形的种类

    三角形一般可以分为如下的四种类型(这四种类型是对于计算机来说的,不是数学意义上的分类):
    平顶三角形:就是在计算机中显示的上面两个顶点的Y坐标相同。
    平底三角形:就是在计算机中显示的时候下面两个顶点的Y坐标相同。
    右边为主三角形:这种三角形三个点的Y坐标都不相同,但是右边的一条边是最长的斜边
    左边为主的三角形:这种三角形的三个点的Y坐标不相同,但是左边的一条边是最长的斜边。
    附上各个不同三角形的图:

    是不是所有的三角形大致可以分为这四种?而我们要进行填充的时候,前面两种的填充应该比较简单,只要从顶点开始一行一行的进行填充就可以做到了,如下图所示:

    进行这样的操作应该很容易实现吧,同样的对平顶的三角形我们也可以这样来一行一行的使用像素进行填充。
    至于后面两种情况的三角形,我们能够很简单的将他们分别变成两个三角形,一个平顶一个平底:

    所以,我们实现了前面两个的三角形的填充,后面两个的也就很容易实现了。

    二。代码实现

    下面是实现平顶的三角形填充的代码:
    1. int Draw_Top_Trangle(int x0,int y0,  
    2.                     int x1,int y1,  
    3.                     int x2,int y2,  
    4.                     UINT * video_buffer,  
    5.                     DWORD color,int mempitch)  
    6. {  
    7.     //先判断下输入的三角形  
    8.     if(y0==y1)  
    9.     {  
    10.     }else if(y0==y2)  
    11.     {  
    12.         Swap(x2,x1);  
    13.         Swap(y2,y1);  
    14.     }else if(y1==y2)  
    15.     {  
    16.         Swap(x0,x2);  
    17.         Swap(y0,y2);  
    18.     }else  
    19.     {  
    20.         return 1 ; //error rief 不是平顶三角形  
    21.     }  
    22.   
    23.     if(x1<x0)  
    24.     {  
    25.         Swap(x1,x0);  
    26.         Swap(y1,y0);  
    27.     }  
    28.     else if(x1 == x0)  
    29.     {  
    30.         return 1 ;// error rief不是三角形  
    31.     }  
    32.   
    33.     //计算左右误差  
    34.     float dxy_left = (x2-x0)*1.0/(y2-y0) ;  
    35.     float dxy_right = (x1-x2)*1.0/(y1-y2);  
    36.   
    37.     //开始进行填充  
    38.     float xs = x0 ,xe = x1 ;  
    39.     for(int y=y0 ; y <=y2 ;y++)  
    40.     {  
    41.         Draw_Simple_Line(int(xs+0.5),int(xe+0.5),y,video_buffer,color,mempitch);  
    42.   
    43.         xs += dxy_left ;  
    44.         xe += dxy_right ;  
    45.     }  
    46. // end Draw_Top_Trangle  
    int Draw_Top_Trangle(int x0,int y0,
    					int x1,int y1,
    					int x2,int y2,
    					UINT * video_buffer,
    					DWORD color,int mempitch)
    {
    	//先判断下输入的三角形
    	if(y0==y1)
    	{
    	}else if(y0==y2)
    	{
    		Swap(x2,x1);
    		Swap(y2,y1);
    	}else if(y1==y2)
    	{
    		Swap(x0,x2);
    		Swap(y0,y2);
    	}else
    	{
    		return 1 ; //error rief 不是平顶三角形
    	}
    
    	if(x1<x0)
    	{
    		Swap(x1,x0);
    		Swap(y1,y0);
    	}
    	else if(x1 == x0)
    	{
    		return 1 ;// error rief不是三角形
    	}
    
    	//计算左右误差
    	float dxy_left = (x2-x0)*1.0/(y2-y0) ;
    	float dxy_right = (x1-x2)*1.0/(y1-y2);
    
    	//开始进行填充
    	float xs = x0 ,xe = x1 ;
    	for(int y=y0 ; y <=y2 ;y++)
    	{
    		Draw_Simple_Line(int(xs+0.5),int(xe+0.5),y,video_buffer,color,mempitch);
    
    		xs += dxy_left ;
    		xe += dxy_right ;
    	}
    } // end Draw_Top_Trangle
    

    上面的算法开始的时候,检查下输入的三个点是否能够构成三角形,并且按照下面图中坐标点所示,来进行顺序的重新排列:

    因为用户使用的时候,可能传递的三个点不是上图中所示的那样的顺序,所以我们计算的方便,我们先将这三个点转变成上图中相对应的位置。接下来就是计算在Y方向上,每移动一个像素,左边和右边的直线上X的平均该变量是多少。获得了这个值,我们就可以慢慢的向下迭代下去,从而将三角形进行了填充。当然,你也可以使用其他的方法来。
    (注:上面函数中的UINT*video_buffer,和int mempitch对于学习过DirectDraw的读者应该比较熟悉,分别是表面内存数据,和内存跨度,此函数是DirectDraw的实现版本)

    同样的,来看看我们的平底三角形填充的实现:
    1. int Draw_Bottom_Trangle(int x0,int y0,  
    2.                     int x1,int y1,  
    3.                     int x2,int y2,  
    4.                     UINT * video_buffer,  
    5.                     DWORD color,int mempitch)  
    6. {  
    7.     //先判断下输入的三角形  
    8.     if(y2==y1)  
    9.     {  
    10.     }else if(y2==y0)  
    11.     {  
    12.         Swap(x0,x1);  
    13.         Swap(y0,y1);  
    14.     }else if(y0==y1)  
    15.     {  
    16.         Swap(x0,x2);  
    17.         Swap(y0,y2);  
    18.     }else  
    19.     {  
    20.         return 1 ; //error rief 不是平顶三角形  
    21.     }  
    22.   
    23.     if(x1<x2)  
    24.     {  
    25.         Swap(x1,x2);  
    26.     }  
    27.     else if(x1 == x2)  
    28.     {  
    29.         return 1 ;// error rief不是三角形  
    30.     }  
    31.   
    32.     //计算左右误差  
    33.     float dxy_left = (x2-x0)*1.0/(y2-y0) ;  
    34.     float dxy_right = (x1-x0)*1.0/(y1-y0);  
    35.   
    36.     //开始进行填充  
    37.     float xs = x0 ,xe = x0 ;  
    38.     for(int y=y0 ; y <=y2 ;y++)  
    39.     {  
    40.         Draw_Simple_Line(int(xs+0.5),int(xe+0.5),y,video_buffer,color,mempitch);  
    41.   
    42.         xs += dxy_left ;  
    43.         xe += dxy_right ;  
    44.     }  
    45. }// end Draw_Bottom_Trangle  
    int Draw_Bottom_Trangle(int x0,int y0,
    					int x1,int y1,
    					int x2,int y2,
    					UINT * video_buffer,
    					DWORD color,int mempitch)
    {
    	//先判断下输入的三角形
    	if(y2==y1)
    	{
    	}else if(y2==y0)
    	{
    		Swap(x0,x1);
    		Swap(y0,y1);
    	}else if(y0==y1)
    	{
    		Swap(x0,x2);
    		Swap(y0,y2);
    	}else
    	{
    		return 1 ; //error rief 不是平顶三角形
    	}
    
    	if(x1<x2)
    	{
    		Swap(x1,x2);
    	}
    	else if(x1 == x2)
    	{
    		return 1 ;// error rief不是三角形
    	}
    
    	//计算左右误差
    	float dxy_left = (x2-x0)*1.0/(y2-y0) ;
    	float dxy_right = (x1-x0)*1.0/(y1-y0);
    
    	//开始进行填充
    	float xs = x0 ,xe = x0 ;
    	for(int y=y0 ; y <=y2 ;y++)
    	{
    		Draw_Simple_Line(int(xs+0.5),int(xe+0.5),y,video_buffer,color,mempitch);
    
    		xs += dxy_left ;
    		xe += dxy_right ;
    	}
    }// end Draw_Bottom_Trangle

    和上面平顶的算法基本上一致,只有图中点的顺序不同:

    好了,这两个函数都实现了,接下来看看我们任意的三角形绘制的实现吧:
    1. int Draw_Trangle_2D(int x0,int y0,  
    2.                     int x1,int y1,  
    3.                     int x2,int y2,  
    4.                     UINT * video_buffer,  
    5.                     DWORD color,int mempitch)  
    6. {  
    7.     if((x0==x1&&x1==x2)  
    8.         ||(y0==y1&&y1==y2))  
    9.     {  
    10.         return 1 ; //error rief传进来的点无法构成三角形  
    11.     }  
    12.   
    13.     //rief 将三个顶点按照从上到下排序  
    14.     if(y0>y1)  
    15.     {  
    16.         Swap(x0,x1);  
    17.         Swap(y0,y1);  
    18.     }  
    19.   
    20.     if(y0>y2)  
    21.     {  
    22.         Swap(x0,x2);  
    23.         Swap(y0,y2);  
    24.     }  
    25.   
    26.     if(y1>y2)  
    27.     {  
    28.         Swap(y1,y2);  
    29.         Swap(x1,x2);  
    30.     }  
    31.   
    32.     //rief查找最大的x坐标,和最小的y坐标  
    33.     int min = (x0<x1?x0:x1);  
    34.     min = (min<x2?min:x2);  
    35.     int max = (x0>x1?x0:x1);  
    36.     max = (max>x2?max:x2);  
    37.   
    38.     //rief 进行绘制  
    39.     if(y2<=min_clip_y||y0>=max_clip_y  
    40.         ||min>=max_clip_x||max<=min_clip_x)  
    41.         return 1 ;  //rief 全部在裁剪区之外  
    42.     if(y0 == y1) //rief 平顶三角形  
    43.     {  
    44.         Draw_Top_Trangle(x0,y0,x1,y1,x2,y2,video_buffer,color,mempitch);  
    45.     }else if(y1 == y2)  
    46.     {  
    47.         Draw_Bottom_Trangle(x0,y0,x1,y1,x2,y2,video_buffer,color,mempitch);  
    48.     }else  
    49.     {  
    50.         int new_x = x0+0.5+(float)1.0*(y1-y0)*(x2-x0)/(y2-y0);  
    51.         Draw_Bottom_Trangle(x0,y0,new_x,y1,x1,y1,video_buffer,color,mempitch);  
    52.         Draw_Top_Trangle(new_x,y1,x1,y1,x2,y2,video_buffer,color,mempitch);  
    53.     }  
    54.   
    55.   
    56.     return 0 ; //rief 成功画出三角形  
    57. }// end Draw_Trangle_2D  
    int Draw_Trangle_2D(int x0,int y0,
    					int x1,int y1,
    					int x2,int y2,
    					UINT * video_buffer,
    					DWORD color,int mempitch)
    {
    	if((x0==x1&&x1==x2)
    		||(y0==y1&&y1==y2))
    	{
    		return 1 ; //error rief传进来的点无法构成三角形
    	}
    
    	//rief 将三个顶点按照从上到下排序
    	if(y0>y1)
    	{
    		Swap(x0,x1);
    		Swap(y0,y1);
    	}
    
    	if(y0>y2)
    	{
    		Swap(x0,x2);
    		Swap(y0,y2);
    	}
    
    	if(y1>y2)
    	{
    		Swap(y1,y2);
    		Swap(x1,x2);
    	}
    
    	//rief查找最大的x坐标,和最小的y坐标
    	int min = (x0<x1?x0:x1);
    	min = (min<x2?min:x2);
    	int max = (x0>x1?x0:x1);
    	max = (max>x2?max:x2);
    
    	//rief 进行绘制
    	if(y2<=min_clip_y||y0>=max_clip_y
    		||min>=max_clip_x||max<=min_clip_x)
    		return 1 ;  //rief 全部在裁剪区之外
    	if(y0 == y1) //rief 平顶三角形
    	{
    		Draw_Top_Trangle(x0,y0,x1,y1,x2,y2,video_buffer,color,mempitch);
    	}else if(y1 == y2)
    	{
    		Draw_Bottom_Trangle(x0,y0,x1,y1,x2,y2,video_buffer,color,mempitch);
    	}else
    	{
    		int new_x = x0+0.5+(float)1.0*(y1-y0)*(x2-x0)/(y2-y0);
    		Draw_Bottom_Trangle(x0,y0,new_x,y1,x1,y1,video_buffer,color,mempitch);
    		Draw_Top_Trangle(new_x,y1,x1,y1,x2,y2,video_buffer,color,mempitch);
    	}
    
    
    	return 0 ; //rief 成功画出三角形
    }// end Draw_Trangle_2D

    这个函数,先将输入的三个点按照y坐标从小到大排序,这样我们就可以y1的坐标,来寻找分离一个右边为主或者左边为主的三角形成为一个平顶一个平底的三角形了。(由于排序了,所以y1的坐标就是显示屏幕上从上到下中间的那个点了,想象是不是这样的!?)。分离了之后,我们就可以分别调用绘制平底和平顶的三角形的算法来实现了。

    以下是整个工程的完整代码:
    1. // DEMO8_8.CPP 此Demo演示32位窗口模式下,创建任意填充三角形的算法  
    2.   
    3. // INCLUDES ///////////////////////////////////////////////  
    4.   
    5. #define WIN32_LEAN_AND_MEAN  // just say no to MFC  
    6.   
    7. #define INITGUID // make sure directX guids are included  
    8.   
    9. #include <windows.h>   // include important windows stuff  
    10. #include <windowsx.h>   
    11. #include <mmsystem.h>  
    12. #include <iostream> // include important C/C++ stuff  
    13. using namespace std ;  
    14. #include <conio.h>  
    15. #include <stdlib.h>  
    16. #include <malloc.h>  
    17. #include <memory.h>  
    18. #include <string.h>  
    19. #include <stdarg.h>  
    20. #include <stdio.h>   
    21. #include <math.h>  
    22. #include <io.h>  
    23. #include <fcntl.h>  
    24.   
    25. #include <ddraw.h> // include directdraw  
    26. #pragma comment(lib,"ddraw.lib")  
    27. // DEFINES ////////////////////////////////////////////////  
    28.   
    29. // defines for windows   
    30. #define WINDOW_CLASS_NAME L"WINCLASS1"  
    31.   
    32. // default screen size  
    33. #define SCREEN_WIDTH    640  // size of screen  
    34. #define SCREEN_HEIGHT   480  
    35. #define SCREEN_BPP      32   // bits per pixel  
    36. #define MAX_COLORS      256  // maximum colors  
    37.   
    38. // TYPES //////////////////////////////////////////////////////  
    39.   
    40. // basic unsigned types  
    41. typedef unsigned short USHORT;  
    42. typedef unsigned short WORD;  
    43. typedef unsigned char  UCHAR;  
    44. typedef unsigned char  BYTE;  
    45.   
    46. // MACROS /////////////////////////////////////////////////  
    47.   
    48. #define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)  
    49. #define KEYUP(vk_code)   ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)  
    50.   
    51. // initializes a direct draw struct  
    52. #define DD_INIT_STRUCT(ddstruct) { memset(&ddstruct,0,sizeof(ddstruct)); ddstruct.dwSize=sizeof(ddstruct); }  
    53.   
    54. //initializes a RGB value  
    55. #define _RGB16BIT565(r,g,b) ((b & 31) + ((g & 63) << 5) + ((r & 31) << 11))  
    56. #define _RGB32BIT(a,r,g,b) ((b) + ((g) << 8) + ((r) << 16) + ((a) << 24))  
    57.   
    58. // GLOBALS ////////////////////////////////////////////////  
    59. HWND      main_window_handle = NULL; // globally track main window  
    60. HINSTANCE hinstance_app      = NULL; // globally track hinstance  
    61.   
    62. // directdraw stuff  
    63.   
    64. LPDIRECTDRAW7         lpdd         = NULL;   // dd object  
    65. LPDIRECTDRAWSURFACE7  lpddsprimary = NULL;   // dd primary surface  
    66. LPDIRECTDRAWSURFACE7  lpddsback    = NULL;   // dd back surface  
    67. LPDIRECTDRAWPALETTE   lpddpal      = NULL;   // a pointer to the created dd palette  
    68. LPDIRECTDRAWCLIPPER   lpddclipper  = NULL;   // dd clipper  
    69. PALETTEENTRY          palette[256];          // color palette  
    70. PALETTEENTRY          save_palette[256];     // used to save palettes  
    71. DDSURFACEDESC2        ddsd;                  // a direct draw surface description struct  
    72. DDBLTFX               ddbltfx;               // used to fill  
    73. DDSCAPS2              ddscaps;               // a direct draw surface capabilities struct  
    74. HRESULT               ddrval;                // result back from dd calls  
    75. DWORD                 start_clock_count = 0; // used for timing  
    76. LPDIRECTDRAWSURFACE7  lpddsOffScreen = NULL ;  //离屏表面  
    77. int                   window_close  =  0 ;    //标识窗口是否关闭  
    78.   
    79. // these defined the general clipping rectangle  
    80. int min_clip_x = 0,                          // clipping rectangle   
    81.     max_clip_x = 1366-1,  
    82.     min_clip_y = 0,  
    83.     max_clip_y = 768-1;  
    84.   
    85. // these are overwritten globally by DD_Init()  
    86. int screen_width  = SCREEN_WIDTH,            // width of screen  
    87.     screen_height = SCREEN_HEIGHT,           // height of screen  
    88.     screen_bpp    = SCREEN_BPP;              // bits per pixel  
    89.   
    90.   
    91. char buffer[80];                     // general printing buffer  
    92.   
    93. //申明画线方法  
    94. int Draw_Line(int x0, int y0, int x1, int y1, DWORD color , UINT * video_buffer , int stepx , int stepy);  
    95.   
    96. //裁剪直线算法  
    97. int Clipper_Line(int& x0,int& y0,int& x1, int& y1,int screen_width,int screen_height);  
    98.   
    99. //交换值  
    100. void Swap(int &x , int &y) ;  
    101.   
    102. //绘制填充平顶三角形  
    103. int Draw_Top_Trangle(int x0,int y0,  
    104.                     int x1,int y1,  
    105.                     int x2,int y2,  
    106.                     UINT * video_buffer,  
    107.                     DWORD color,int mempitch);  
    108.   
    109. //绘制平底三角形  
    110. int Draw_Bottom_Trangle(int x0,int y0,  
    111.                     int x1,int y1,  
    112.                     int x2,int y2,  
    113.                     UINT * video_buffer,  
    114.                     DWORD color,int mempitch);  
    115.   
    116. //简单的平行绘制直线  
    117. int Draw_Simple_Line(int x0, int x1,int y , UINT * video_buffer,DWORD color,int mempitch);  
    118.   
    119. //绘制任意三角形  
    120. int Draw_Trangle_2D(int x0,int y0,  
    121.                     int x1,int y1,  
    122.                     int x2,int y2,  
    123.                     UINT * video_buffer,  
    124.                     DWORD color,int mempitch);  
    125. // FUNCTIONS //////////////////////////////////////////////  
    126. LRESULT CALLBACK WindowProc(HWND hwnd,   
    127.                             UINT msg,   
    128.                             WPARAM wparam,   
    129.                             LPARAM lparam)  
    130. {  
    131. // this is the main message handler of the system  
    132. PAINTSTRUCT     ps;     // used in WM_PAINT  
    133. HDC             hdc;    // handle to a device context  
    134. char buffer[80];        // used to print strings  
    135.   
    136. // what is the message   
    137. switch(msg)  
    138.     {     
    139.     case WM_CREATE:   
    140.         {  
    141.         // do initialization stuff here  
    142.         // return success  
    143.         return(0);  
    144.         } break;  
    145.      
    146.     case WM_PAINT:   
    147.         {  
    148.         // simply validate the window   
    149.         hdc = BeginPaint(hwnd,&ps);    
    150.           
    151.         // end painting  
    152.         EndPaint(hwnd,&ps);  
    153.   
    154.         // return success  
    155.         return(0);  
    156.         } break;  
    157.   
    158.     case WM_DESTROY:   
    159.         {  
    160.   
    161.         // kill the application, this sends a WM_QUIT message   
    162.         PostQuitMessage(0);  
    163.   
    164.         // return success  
    165.         return(0);  
    166.         } break;  
    167.   
    168.     default:break;  
    169.   
    170.     } // end switch  
    171.   
    172. // process any messages that we didn't take care of   
    173. return (DefWindowProc(hwnd, msg, wparam, lparam));  
    174.   
    175. // end WinProc  
    176.   
    177. ///////////////////////////////////////////////////////////  
    178.   
    179. //程序主循环  
    180. int Game_Main(void *parms = NULL, int num_parms = 0)  
    181. {  
    182. // this is the main loop of the game, do all your processing  
    183. // here  
    184.   
    185. // for now test if user is hitting ESC and send WM_CLOSE  
    186. if(window_close)  
    187.     return 1 ;  
    188. if (KEYDOWN(VK_ESCAPE))  
    189. {  
    190.     PostMessage(main_window_handle,WM_CLOSE,0,0);  
    191.     window_close = 1 ;  
    192. }  
    193.      
    194.   
    195. //清空表面  
    196. DDBLTFX bltfx ;  
    197. DD_INIT_STRUCT(bltfx);  
    198. bltfx.dwFillColor = 0 ;  
    199. if(FAILED(lpddsOffScreen->Blt(NULL,NULL,NULL,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx)))  
    200. {  
    201.     OutputDebugString(L"OffScreen Blt error");  
    202.     return 1 ;  
    203. }  
    204.   
    205. //锁定  
    206. DDSURFACEDESC2 ddsd ;  
    207. DD_INIT_STRUCT(ddsd);  
    208. if(FAILED(lpddsOffScreen->Lock(NULL,&ddsd,DDLOCK_WAIT|DDLOCK_SURFACEMEMORYPTR,NULL)))  
    209. {  
    210.     OutputDebugString(L"Lock error");  
    211.     return 1 ;  
    212. }  
    213.   
    214. //获取窗口位置  
    215. RECT rect ;  
    216. GetWindowRect(main_window_handle,&rect);  
    217. //画填充的三角形  
    218. int x0 = rand()%SCREEN_WIDTH+rect.left;  
    219. int x1 = rand()%SCREEN_WIDTH+rect.left ;  
    220. int x2 = rand()%SCREEN_WIDTH + rect.left ;  
    221. int y0 = rand()%SCREEN_HEIGHT + rect.top;  
    222. int y1 = rand()%SCREEN_HEIGHT+ rect.top+100;  
    223. int y2 = rand()%SCREEN_HEIGHT + rect.top;  
    224. Draw_Trangle_2D(x0,y0,x1,y1,x2,y2,(UINT*)ddsd.lpSurface,  
    225.     _RGB32BIT(0,255,255,255),ddsd.lPitch>>2);  
    226.   
    227. //解锁  
    228. if(FAILED(lpddsOffScreen->Unlock(NULL)))  
    229. {  
    230.     OutputDebugString(L"Unlock error");  
    231.     return 1 ;  
    232. }  
    233.   
    234. //Blt到主表面  
    235. if(FAILED(lpddsprimary->Blt(NULL,lpddsOffScreen,NULL,DDBLT_WAIT,NULL)))  
    236. {  
    237.     OutputDebugString(L"Blt error");  
    238.     return 1 ;  
    239. }  
    240.   
    241. // return success or failure or your own return code here  
    242. return(1);  
    243.   
    244. // end Game_Main  
    245.   
    246. ////////////////////////////////////////////////////////////  
    247.   
    248. int Game_Init(void *parms = NULL, int num_parms = 0)  
    249. {  
    250. // this is called once after the initial window is created and  
    251. // before the main event loop is entered, do all your initialization  
    252. // here  
    253.   
    254. // create IDirectDraw interface 7.0 object and test for error  
    255. if (FAILED(DirectDrawCreateEx(NULL, (void **)&lpdd, IID_IDirectDraw7, NULL)))  
    256.    return(0);  
    257.   
    258. // set cooperation to normal since this will be a windowed app  
    259. if(FAILED(lpdd->SetCooperativeLevel(main_window_handle, DDSCL_NORMAL)))  
    260. {  
    261.     MessageBox(NULL,L"SetCooperativeLevel error",L"error",MB_OK);  
    262.     return 0 ;  
    263. }  
    264.   
    265. //创建裁剪器  
    266. if(FAILED(lpdd->CreateClipper(0,&lpddclipper,NULL)))  
    267. {  
    268.     OutputDebugString(L"CreateClipper error");  
    269.     return 1 ;  
    270. }  
    271.   
    272. //将裁减器关联窗口,也就是用窗口的尺寸作为裁剪器的裁剪序列  
    273. if(FAILED(lpddclipper->SetHWnd(0,main_window_handle)))  
    274. {  
    275.     OutputDebugString(L"SetHWnd error");  
    276.     return 1 ;  
    277. }  
    278.   
    279. //创建主表面  
    280. memset(&ddsd,0,sizeof(ddsd));  
    281. ddsd.dwSize = sizeof(ddsd);  
    282. ddsd.dwFlags = DDSD_CAPS ;  
    283. ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;  
    284.   
    285. if(FAILED(lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL)))  
    286. {  
    287.     MessageBox(NULL,L"CreateSurface error",L"error",MB_OK);  
    288.     return 0 ;  
    289. }  
    290.   
    291. //将裁减器关联到表面  
    292. if(FAILED(lpddsprimary->SetClipper(lpddclipper)))  
    293. {  
    294.     OutputDebugString(L"SetClipper error");  
    295.     return 1 ;  
    296. }  
    297.   
    298. //创建一个离屏表面  
    299. DD_INIT_STRUCT(ddsd);  
    300. ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;  
    301. ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT ;  
    302. ddsd.dwHeight = 786 ;  
    303. ddsd.dwWidth = 1366 ;  
    304. if(FAILED(lpdd->CreateSurface(&ddsd,&lpddsOffScreen,NULL)))  
    305. {  
    306.     OutputDebugString(L"OffScreen CreateSurface error");  
    307.     return 1 ;  
    308. }  
    309.   
    310.   
    311.   
    312. // return success or failure or your own return code here  
    313. return(1);  
    314.   
    315. // end Game_Init  
    316.   
    317. /////////////////////////////////////////////////////////////  
    318.   
    319. int Game_Shutdown(void *parms = NULL, int num_parms = 0)  
    320. {  
    321. // this is called after the game is exited and the main event  
    322. // loop while is exited, do all you cleanup and shutdown here  
    323.   
    324. // simply blow away the IDirectDraw4 interface  
    325.   
    326. if(lpddclipper)  
    327. {  
    328.     lpddclipper->Release();  
    329.     lpddclipper = NULL ;  
    330. }  
    331.   
    332. if(lpddsprimary)  
    333. {  
    334.     lpddsprimary->Release();  
    335.     lpddsprimary = NULL ;  
    336. }  
    337.   
    338. if (lpdd)  
    339.    {  
    340.    lpdd->Release();  
    341.    lpdd = NULL;  
    342.    } // end if  
    343.   
    344. // return success or failure or your own return code here  
    345. return(1);  
    346.   
    347. // end Game_Shutdown  
    348.   
    349. // WINMAIN ////////////////////////////////////////////////  
    350. int WINAPI WinMain( HINSTANCE hinstance,  
    351.                     HINSTANCE hprevinstance,  
    352.                     LPSTR lpcmdline,  
    353.                     int ncmdshow)  
    354. {  
    355.   
    356.     WNDCLASSEX winclass; // this will hold the class we create  
    357.     HWND       hwnd;     // generic window handle  
    358.     MSG        msg;      // generic message  
    359.     HDC        hdc;      // graphics device context  
    360.   
    361.     // first fill in the window class stucture  
    362.     winclass.cbSize         = sizeof(WNDCLASSEX);  
    363.     winclass.style          = CS_DBLCLKS | CS_OWNDC |   
    364.                               CS_HREDRAW | CS_VREDRAW;  
    365.     winclass.lpfnWndProc    = WindowProc;  
    366.     winclass.cbClsExtra     = 0;  
    367.     winclass.cbWndExtra     = 0;  
    368.     winclass.hInstance      = hinstance;  
    369.     winclass.hIcon          = LoadIcon(NULL, IDI_APPLICATION);  
    370.     winclass.hCursor        = LoadCursor(NULL, IDC_ARROW);   
    371.     winclass.hbrBackground  = (HBRUSH)GetStockObject(BLACK_BRUSH);  
    372.     winclass.lpszMenuName   = NULL;  
    373.     winclass.lpszClassName  = WINDOW_CLASS_NAME;  
    374.     winclass.hIconSm        = LoadIcon(NULL, IDI_APPLICATION);  
    375.   
    376.     // save hinstance in global  
    377.     hinstance_app = hinstance;  
    378.   
    379.     // register the window class  
    380.     if (!RegisterClassEx(&winclass))  
    381.         return(0);  
    382.   
    383.     // create the window  
    384.     if (!(hwnd = CreateWindowEx(NULL,                  // extended style  
    385.                                 WINDOW_CLASS_NAME,     // class  
    386.                                 L"DirectDraw Initialization Demo"// title  
    387.                                 WS_OVERLAPPED|WS_VISIBLE,  
    388.                                 0,0,      // initial x,y  
    389.                                 SCREEN_WIDTH,SCREEN_HEIGHT,  // initial width, height  
    390.                                 NULL,     // handle to parent   
    391.                                 NULL,     // handle to menu  
    392.                                 hinstance,// instance of this application  
    393.                                 NULL))) // extra creation parms  
    394.         return(0);  
    395.   
    396.     // save main window handle  
    397.     main_window_handle = hwnd;  
    398.   
    399.     // initialize game here  
    400.     Game_Init();  
    401.   
    402.     //调整窗口大小  
    403.     RECT window_rect = {0,0,SCREEN_WIDTH,SCREEN_HEIGHT} ;  
    404.     AdjustWindowRectEx(&window_rect,GetWindowStyle(main_window_handle),GetMenu(main_window_handle)!=NULL,GetWindowExStyle(main_window_handle));  
    405.   
    406.     // enter main event loop  
    407.     while(TRUE)  
    408.         {  
    409.         // test if there is a message in queue, if so get it  
    410.         if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))  
    411.            {   
    412.            // test if this is a quit  
    413.            if (msg.message == WM_QUIT)  
    414.                break;  
    415.       
    416.            // translate any accelerator keys  
    417.            TranslateMessage(&msg);  
    418.   
    419.            // send the message to the window proc  
    420.            DispatchMessage(&msg);  
    421.            } // end if  
    422.       
    423.            // main game processing goes here  
    424.            Game_Main();  
    425.          
    426.         } // end while  
    427.   
    428.     // closedown game here  
    429.     Game_Shutdown();  
    430.   
    431.     // return to Windows like this  
    432.     return(msg.wParam);  
    433.   
    434. // end WinMain  
    435.   
    436. //定义交换函数  
    437. void Swap(int &x , int &y)  
    438. {  
    439.     int temp = y ;  
    440.     y = x ;  
    441.     x = temp ;  
    442. }  
    443.   
    444. //定义画线函数  
    445. int Draw_Line(int x0,int y0, int x1, int y1 , DWORD color , UINT *video_buffer, int stepx,int stepy)  
    446. {  
    447.     int dx ,  //起点与终点的X方向间距  
    448.         dy ,  //起点与终点的Y方向间距  
    449.         dx2, //两倍的dx  
    450.         dy2,  //两倍的dy  
    451.         x_inc ,  //实际的x步长值,带有符号  
    452.         y_inc , //实际的y步长值,带有符号  
    453.         p ;     //误差项  
    454.   
    455.     dx = x1 - x0 ;  //计算x间距  
    456.     dy = y1 - y0 ;  //计算y间距  
    457.   
    458.     //计算起点的缓冲地址  
    459.     video_buffer+=x0+y0*stepy ;  
    460.   
    461.     //确定x方向的步进值  
    462.     if(dx>=0)  
    463.     {  
    464.         x_inc = stepx;  
    465.     }  
    466.     else  
    467.     {  
    468.         x_inc = -stepx ;  
    469.         dx = -dx ;  
    470.     }  
    471.   
    472.     //确定y方向的步进值  
    473.     if(dy>=0)  
    474.     {  
    475.         y_inc = stepy ;  
    476.     }  
    477.     else  
    478.     {  
    479.         y_inc = -stepy ;  
    480.         dy = -dy ;  
    481.     }  
    482.   
    483.     //确定dx2,dy2的值  
    484.     dx2 = dx<<1;  
    485.     dy2 = dy<<1 ;  
    486.   
    487.     //进行步进的选择  
    488.     if(dx <= dy) //斜率绝对值大于1  
    489.     {  
    490.         Swap(dx,dy);  
    491.         Swap(x_inc,y_inc);  
    492.         Swap(dx2,dy2);  
    493.     }  
    494.     else //斜率绝对值小于1,不需要交换  
    495.     {  
    496.     }  
    497.   
    498.   
    499.     //绘制直线  
    500.     p = dy2 - dx ;  //计算起点的误差值  
    501.     for(int i = 0 ; i < dx ; i++)  
    502.     {  
    503.         *video_buffer = color ;  
    504.           
    505.         video_buffer += x_inc ;  
    506.         if(p>=0)  
    507.         {  
    508.             video_buffer += y_inc ;  
    509.             p = p + dy2 - dx2 ;  
    510.         }  
    511.         else  
    512.         {  
    513.             p = p + dy2 ;  
    514.         }  
    515.     }// end for  
    516.   
    517.   
    518.     return 0 ;  
    519. }// end Draw_Line  
    520.   
    521. //定义裁剪直线算法  
    522. int Clipper_Line(int& x0,int& y0,int& x1, int& y1,int screen_width,int screen_height)  
    523. {  
    524. #define CLIP_CODE_C 0x0000  
    525. #define CLIP_CODE_N 0x0008  
    526. #define CLIP_CODE_S 0x0004  
    527. #define CLIP_CODE_E 0x0002  
    528. #define CLIP_CODE_W 0x0001  
    529.   
    530. #define CLIP_CODE_NE 0x000a  
    531. #define CLIP_CODE_SE 0x0006  
    532. #define CLIP_CODE_NW 0x0009  
    533. #define CLIP_CODE_SW 0x0005  
    534.     int xc0 = x0 ,yc0 = y0 , xc1=x1 , yc1=y1 ;  
    535.     int min_clip_x = SCREEN_WIDTH/3 ,min_clip_y = SCREEN_HEIGHT/3 ,max_clip_x = screen_width*2/3-1,max_clip_y=screen_height*2/3-1 ;  
    536.     int p0_code = 0 ,p1_code = 0 ;  
    537.   
    538.     //确定各个顶点所在的位置代码  
    539.     if(y0<min_clip_y)  
    540.         p0_code|=CLIP_CODE_N;  
    541.     else if(y0>max_clip_y)  
    542.         p0_code|=CLIP_CODE_S;  
    543.   
    544.     if(x0<min_clip_x)  
    545.         p0_code|=CLIP_CODE_W;  
    546.     else if(x0>max_clip_x)  
    547.         p0_code|=CLIP_CODE_E;  
    548.   
    549.     if(y1<min_clip_y)  
    550.         p1_code|=CLIP_CODE_N;  
    551.     else if(y1>max_clip_y)  
    552.         p1_code|=CLIP_CODE_S;  
    553.   
    554.     if(x1<min_clip_x)  
    555.         p1_code|=CLIP_CODE_W;  
    556.     else if(x1>max_clip_x)  
    557.         p1_code|=CLIP_CODE_E;  
    558.   
    559.     //先检测一些简单的情况  
    560.     if(p0_code&p1_code) //有相同的位置代码,表示在裁剪区外部  
    561.         return 0 ;  
    562.     if(p0_code==0&&p1_code==0) //表示两个点都在裁剪区内,不需要裁剪  
    563.         return 1 ;  
    564.   
    565.     //判断第一个点的位置代码  
    566.     switch(p0_code)  
    567.     {  
    568.     case CLIP_CODE_C:  
    569.         break;  
    570.     case CLIP_CODE_N:  
    571.         {  
    572.             yc0 = min_clip_y ;  
    573.             xc0 = x0 + 0.5 + (yc0-y0)*(x1-x0)/(y1-y0);  
    574.             break ;  
    575.         }  
    576.     case CLIP_CODE_S:  
    577.         {  
    578.             yc0 = max_clip_y;  
    579.             xc0 = x0 + 0.5 + (yc0-y0)*(x1-x0)/(y1-y0);  
    580.             break ;  
    581.         }  
    582.     case CLIP_CODE_W:  
    583.         {  
    584.             xc0=min_clip_x;  
    585.             yc0=y0+0.5+(xc0-x0)*(y1-y0)/(x1-x0);  
    586.             break;  
    587.         }  
    588.     case CLIP_CODE_E:  
    589.         {  
    590.             xc0=max_clip_x;  
    591.             yc0=y0+0.5+(xc0-x0)*(y1-y0)/(x1-x0);  
    592.             break;  
    593.         }  
    594.     case CLIP_CODE_NE:  
    595.         {  
    596.             yc0 = min_clip_y;  
    597.             xc0 = x0 + 0.5 + (yc0-y0)*(x1-x0)/(y1-y0);  
    598.   
    599.             if(xc0<min_clip_x||xc0>max_clip_x)  
    600.             {  
    601.                 xc0=max_clip_x;  
    602.                 yc0=y0+0.5+(xc0-x0)*(y1-y0)/(x1-x0);  
    603.             }  
    604.             break;  
    605.         }  
    606.     case CLIP_CODE_SE:  
    607.         {  
    608.             yc0 = max_clip_y;  
    609.             xc0 = x0 + 0.5 + (yc0-y0)*(x1-x0)/(y1-y0);  
    610.   
    611.             if(xc0<min_clip_x||xc0>max_clip_x)  
    612.             {  
    613.                 xc0=max_clip_x;  
    614.                 yc0=y0+0.5+(xc0-x0)*(y1-y0)/(x1-x0);  
    615.             }  
    616.             break;  
    617.         }  
    618.     case CLIP_CODE_NW:  
    619.         {  
    620.             yc0=min_clip_y;  
    621.             xc0 = x0 + 0.5 + (yc0-y0)*(x1-x0)/(y1-y0);  
    622.   
    623.             if(xc0<min_clip_x||xc0>max_clip_x)  
    624.             {  
    625.                 xc0=min_clip_x;  
    626.                 yc0=y0+0.5+(xc0-x0)*(y1-y0)/(x1-x0);  
    627.             }  
    628.             break;  
    629.         }  
    630.     case CLIP_CODE_SW:  
    631.         {  
    632.             yc0=max_clip_y;  
    633.             xc0 = x0 + 0.5 + (yc0-y0)*(x1-x0)/(y1-y0);  
    634.   
    635.             if(xc0<min_clip_x||xc0>max_clip_x)  
    636.             {  
    637.                 xc0=min_clip_x;  
    638.                 yc0=y0+0.5+(xc0-x0)*(y1-y0)/(x1-x0);  
    639.             }  
    640.             break;  
    641.         }  
    642.     default:  
    643.         break;  
    644.     } // end switch(p0_code)  
    645.   
    646.     //判断第二个点的位置代码  
    647.     switch(p1_code)  
    648.     {  
    649.     case CLIP_CODE_C:  
    650.         break;  
    651.     case CLIP_CODE_N:  
    652.         {  
    653.             yc1 = min_clip_y ;  
    654.             xc1 = x1 + 0.5 + (yc1-y1)*(x1-x0)/(y1-y0);  
    655.             break ;  
    656.         }  
    657.     case CLIP_CODE_S:  
    658.         {  
    659.             yc1 = max_clip_y;  
    660.             xc1 = x1 + 0.5 + (yc1-y1)*(x1-x0)/(y1-y0);  
    661.             break ;  
    662.         }  
    663.     case CLIP_CODE_W:  
    664.         {  
    665.             xc1=min_clip_x;  
    666.             yc1=y1+0.5+(xc1-x1)*(y1-y0)/(x1-x0);  
    667.             break;  
    668.         }  
    669.     case CLIP_CODE_E:  
    670.         {  
    671.             xc1=max_clip_x;  
    672.             yc1=y1+0.5+(xc1-x1)*(y1-y0)/(x1-x0);  
    673.             break;  
    674.         }  
    675.     case CLIP_CODE_NE:  
    676.         {  
    677.             yc1 = min_clip_y;  
    678.             xc1 = x1 + 0.5 + (yc1-y1)*(x1-x0)/(y1-y0);  
    679.   
    680.             if(xc1<min_clip_x||xc1>max_clip_x)  
    681.             {  
    682.                 xc1=max_clip_x;  
    683.                 yc1=y1+0.5+(xc1-x1)*(y1-y0)/(x1-x0);  
    684.             }  
    685.             break;  
    686.         }  
    687.     case CLIP_CODE_SE:  
    688.         {  
    689.             yc1 = max_clip_y;  
    690.             xc1 = x1 + 0.5 + (yc1-y1)*(x1-x0)/(y1-y0);  
    691.   
    692.             if(xc1<min_clip_x||xc1>max_clip_x)  
    693.             {  
    694.                 xc1=max_clip_x;  
    695.                 yc1=y1+0.5+(xc1-x1)*(y1-y0)/(x1-x0);  
    696.             }  
    697.             break;  
    698.         }  
    699.     case CLIP_CODE_NW:  
    700.         {  
    701.             yc1=min_clip_y;  
    702.             xc1 = x1 + 0.5 + (yc1-y1)*(x1-x0)/(y1-y0);  
    703.   
    704.             if(xc1<min_clip_x||xc1>max_clip_x)  
    705.             {  
    706.                 xc1=min_clip_x;  
    707.                 yc1=y1+0.5+(xc1-x1)*(y1-y0)/(x1-x0);  
    708.             }  
    709.             break;  
    710.         }  
    711.     case CLIP_CODE_SW:  
    712.         {  
    713.             yc1=max_clip_y;  
    714.             xc1 = x1 + 0.5 + (yc1-y1)*(x1-x0)/(y1-y0);  
    715.   
    716.             if(xc1<min_clip_x||xc1>max_clip_x)  
    717.             {  
    718.                 xc1=min_clip_x;  
    719.                 yc1=y1+0.5+(xc1-x1)*(y1-y0)/(x1-x0);  
    720.             }  
    721.             break;  
    722.         }  
    723.     default:  
    724.         break;  
    725.     } // end switch(p1_code)  
    726.   
    727.     //进行最后的检测  
    728.     if(xc0>max_clip_x||xc0<min_clip_x||  
    729.         yc0>max_clip_y||yc0<min_clip_y||  
    730.         xc1>max_clip_x||xc1<min_clip_x||  
    731.         yc1>max_clip_y||yc1<min_clip_y)  
    732.     {  
    733.         //表示全部在裁剪区外部  
    734.         return 0 ;  
    735.     }  
    736.   
    737.     //将裁减后的数据返回  
    738.     x0 = xc0 ;  
    739.     x1 = xc1 ;  
    740.     y0 = yc0 ;  
    741.     y1 = yc1 ;  
    742.   
    743.     return 1 ;  
    744. }// end Clipper_Line  
    745.   
    746. //简单的平行绘制直线  
    747. int Draw_Simple_Line(int x0, int x1,int y , UINT * video_buffer,DWORD color,int mempitch)  
    748. {  
    749.     //进行裁剪  
    750.     if(y<min_clip_y)  
    751.         return 1 ;  
    752.     else if(y>max_clip_y)  
    753.         return 1 ;  
    754.     if(x0<min_clip_x)  
    755.         x0 = min_clip_x;  
    756.     else if(x0>max_clip_x)  
    757.         x0 = max_clip_x ;  
    758.     if(x1<min_clip_x)  
    759.         x1 = min_clip_x ;  
    760.     else if(x1>max_clip_x)  
    761.         x1 = max_clip_x ;  
    762.   
    763.     //进行绘制  
    764.     video_buffer+=y*mempitch;  
    765.     for(int x = x0 ; x<=x1;x++)  
    766.     {  
    767.         video_buffer[x]=color ;  
    768.     }  
    769. }  
    770.   
    771. //绘制填充平顶三角形  
    772. int Draw_Top_Trangle(int x0,int y0,  
    773.                     int x1,int y1,  
    774.                     int x2,int y2,  
    775.                     UINT * video_buffer,  
    776.                     DWORD color,int mempitch)  
    777. {  
    778.     //先判断下输入的三角形  
    779.     if(y0==y1)  
    780.     {  
    781.     }else if(y0==y2)  
    782.     {  
    783.         Swap(x2,x1);  
    784.         Swap(y2,y1);  
    785.     }else if(y1==y2)  
    786.     {  
    787.         Swap(x0,x2);  
    788.         Swap(y0,y2);  
    789.     }else  
    790.     {  
    791.         return 1 ; //error rief 不是平顶三角形  
    792.     }  
    793.   
    794.     if(x1<x0)  
    795.     {  
    796.         Swap(x1,x0);  
    797.         Swap(y1,y0);  
    798.     }  
    799.     else if(x1 == x0)  
    800.     {  
    801.         return 1 ;// error rief不是三角形  
    802.     }  
    803.   
    804.     //计算左右误差  
    805.     float dxy_left = (x2-x0)*1.0/(y2-y0) ;  
    806.     float dxy_right = (x1-x2)*1.0/(y1-y2);  
    807.   
    808.     //开始进行填充  
    809.     float xs = x0 ,xe = x1 ;  
    810.     for(int y=y0 ; y <=y2 ;y++)  
    811.     {  
    812.         Draw_Simple_Line(int(xs+0.5),int(xe+0.5),y,video_buffer,color,mempitch);  
    813.   
    814.         xs += dxy_left ;  
    815.         xe += dxy_right ;  
    816.     }  
    817. // end Draw_Top_Trangle  
    818.   
    819. //绘制平底三角形  
    820. int Draw_Bottom_Trangle(int x0,int y0,  
    821.                     int x1,int y1,  
    822.                     int x2,int y2,  
    823.                     UINT * video_buffer,  
    824.                     DWORD color,int mempitch)  
    825. {  
    826.     //先判断下输入的三角形  
    827.     if(y2==y1)  
    828.     {  
    829.     }else if(y2==y0)  
    830.     {  
    831.         Swap(x0,x1);  
    832.         Swap(y0,y1);  
    833.     }else if(y0==y1)  
    834.     {  
    835.         Swap(x0,x2);  
    836.         Swap(y0,y2);  
    837.     }else  
    838.     {  
    839.         return 1 ; //error rief 不是平顶三角形  
    840.     }  
    841.   
    842.     if(x1<x2)  
    843.     {  
    844.         Swap(x1,x2);  
    845.     }  
    846.     else if(x1 == x2)  
    847.     {  
    848.         return 1 ;// error rief不是三角形  
    849.     }  
    850.   
    851.     //计算左右误差  
    852.     float dxy_left = (x2-x0)*1.0/(y2-y0) ;  
    853.     float dxy_right = (x1-x0)*1.0/(y1-y0);  
    854.   
    855.     //开始进行填充  
    856.     float xs = x0 ,xe = x0 ;  
    857.     for(int y=y0 ; y <=y2 ;y++)  
    858.     {  
    859.         Draw_Simple_Line(int(xs+0.5),int(xe+0.5),y,video_buffer,color,mempitch);  
    860.   
    861.         xs += dxy_left ;  
    862.         xe += dxy_right ;  
    863.     }  
    864. }// end Draw_Bottom_Trangle  
    865.   
    866. //绘制任意三角形  
    867. int Draw_Trangle_2D(int x0,int y0,  
    868.                     int x1,int y1,  
    869.                     int x2,int y2,  
    870.                     UINT * video_buffer,  
    871.                     DWORD color,int mempitch)  
    872. {  
    873.     if((x0==x1&&x1==x2)  
    874.         ||(y0==y1&&y1==y2))  
    875.     {  
    876.         return 1 ; //error rief传进来的点无法构成三角形  
    877.     }  
    878.   
    879.     //rief 将三个顶点按照从上到下排序  
    880.     if(y0>y1)  
    881.     {  
    882.         Swap(x0,x1);  
    883.         Swap(y0,y1);  
    884.     }  
    885.   
    886.     if(y0>y2)  
    887.     {  
    888.         Swap(x0,x2);  
    889.         Swap(y0,y2);  
    890.     }  
    891.   
    892.     if(y1>y2)  
    893.     {  
    894.         Swap(y1,y2);  
    895.         Swap(x1,x2);  
    896.     }  
    897.   
    898.     //rief查找最大的x坐标,和最小的y坐标  
    899.     int min = (x0<x1?x0:x1);  
    900.     min = (min<x2?min:x2);  
    901.     int max = (x0>x1?x0:x1);  
    902.     max = (max>x2?max:x2);  
    903.   
    904.     //rief 进行绘制  
    905.     if(y2<=min_clip_y||y0>=max_clip_y  
    906.         ||min>=max_clip_x||max<=min_clip_x)  
    907.         return 1 ;  //rief 全部在裁剪区之外  
    908.     if(y0 == y1) //rief 平顶三角形  
    909.     {  
    910.         Draw_Top_Trangle(x0,y0,x1,y1,x2,y2,video_buffer,color,mempitch);  
    911.     }else if(y1 == y2)  
    912.     {  
    913.         Draw_Bottom_Trangle(x0,y0,x1,y1,x2,y2,video_buffer,color,mempitch);  
    914.     }else  
    915.     {  
    916.         int new_x = x0+0.5+(float)1.0*(y1-y0)*(x2-x0)/(y2-y0);  
    917.         Draw_Bottom_Trangle(x0,y0,new_x,y1,x1,y1,video_buffer,color,mempitch);  
    918.         Draw_Top_Trangle(new_x,y1,x1,y1,x2,y2,video_buffer,color,mempitch);  
    919.     }  
    920.   
    921.   
    922.     return 0 ; //rief 成功画出三角形  
    923. }// end Draw_Trangle_2D  
    924. ///////////////////////////////////////////////////////////  
    // DEMO8_8.CPP 此Demo演示32位窗口模式下,创建任意填充三角形的算法
    
    // INCLUDES ///////////////////////////////////////////////
    
    #define WIN32_LEAN_AND_MEAN  // just say no to MFC
    
    #define INITGUID // make sure directX guids are included
    
    #include <windows.h>   // include important windows stuff
    #include <windowsx.h> 
    #include <mmsystem.h>
    #include <iostream> // include important C/C++ stuff
    using namespace std ;
    #include <conio.h>
    #include <stdlib.h>
    #include <malloc.h>
    #include <memory.h>
    #include <string.h>
    #include <stdarg.h>
    #include <stdio.h> 
    #include <math.h>
    #include <io.h>
    #include <fcntl.h>
    
    #include <ddraw.h> // include directdraw
    #pragma comment(lib,"ddraw.lib")
    // DEFINES ////////////////////////////////////////////////
    
    // defines for windows 
    #define WINDOW_CLASS_NAME L"WINCLASS1"
    
    // default screen size
    #define SCREEN_WIDTH    640  // size of screen
    #define SCREEN_HEIGHT   480
    #define SCREEN_BPP      32   // bits per pixel
    #define MAX_COLORS      256  // maximum colors
    
    // TYPES //////////////////////////////////////////////////////
    
    // basic unsigned types
    typedef unsigned short USHORT;
    typedef unsigned short WORD;
    typedef unsigned char  UCHAR;
    typedef unsigned char  BYTE;
    
    // MACROS /////////////////////////////////////////////////
    
    #define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
    #define KEYUP(vk_code)   ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
    
    // initializes a direct draw struct
    #define DD_INIT_STRUCT(ddstruct) { memset(&ddstruct,0,sizeof(ddstruct)); ddstruct.dwSize=sizeof(ddstruct); }
    
    //initializes a RGB value
    #define _RGB16BIT565(r,g,b) ((b & 31) + ((g & 63) << 5) + ((r & 31) << 11))
    #define _RGB32BIT(a,r,g,b) ((b) + ((g) << 8) + ((r) << 16) + ((a) << 24))
    
    // GLOBALS ////////////////////////////////////////////////
    HWND      main_window_handle = NULL; // globally track main window
    HINSTANCE hinstance_app      = NULL; // globally track hinstance
    
    // directdraw stuff
    
    LPDIRECTDRAW7         lpdd         = NULL;   // dd object
    LPDIRECTDRAWSURFACE7  lpddsprimary = NULL;   // dd primary surface
    LPDIRECTDRAWSURFACE7  lpddsback    = NULL;   // dd back surface
    LPDIRECTDRAWPALETTE   lpddpal      = NULL;   // a pointer to the created dd palette
    LPDIRECTDRAWCLIPPER   lpddclipper  = NULL;   // dd clipper
    PALETTEENTRY          palette[256];          // color palette
    PALETTEENTRY          save_palette[256];     // used to save palettes
    DDSURFACEDESC2        ddsd;                  // a direct draw surface description struct
    DDBLTFX               ddbltfx;               // used to fill
    DDSCAPS2              ddscaps;               // a direct draw surface capabilities struct
    HRESULT               ddrval;                // result back from dd calls
    DWORD                 start_clock_count = 0; // used for timing
    LPDIRECTDRAWSURFACE7  lpddsOffScreen = NULL ;  //离屏表面
    int					  window_close  =  0 ;    //标识窗口是否关闭
    
    // these defined the general clipping rectangle
    int min_clip_x = 0,                          // clipping rectangle 
        max_clip_x = 1366-1,
        min_clip_y = 0,
        max_clip_y = 768-1;
    
    // these are overwritten globally by DD_Init()
    int screen_width  = SCREEN_WIDTH,            // width of screen
        screen_height = SCREEN_HEIGHT,           // height of screen
        screen_bpp    = SCREEN_BPP;              // bits per pixel
    
    
    char buffer[80];                     // general printing buffer
    
    //申明画线方法
    int Draw_Line(int x0, int y0, int x1, int y1, DWORD color , UINT * video_buffer , int stepx , int stepy);
    
    //裁剪直线算法
    int Clipper_Line(int& x0,int& y0,int& x1, int& y1,int screen_width,int screen_height);
    
    //交换值
    void Swap(int &x , int &y) ;
    
    //绘制填充平顶三角形
    int Draw_Top_Trangle(int x0,int y0,
    					int x1,int y1,
    					int x2,int y2,
    					UINT * video_buffer,
    					DWORD color,int mempitch);
    
    //绘制平底三角形
    int Draw_Bottom_Trangle(int x0,int y0,
    					int x1,int y1,
    					int x2,int y2,
    					UINT * video_buffer,
    					DWORD color,int mempitch);
    
    //简单的平行绘制直线
    int Draw_Simple_Line(int x0, int x1,int y , UINT * video_buffer,DWORD color,int mempitch);
    
    //绘制任意三角形
    int Draw_Trangle_2D(int x0,int y0,
    					int x1,int y1,
    					int x2,int y2,
    					UINT * video_buffer,
    					DWORD color,int mempitch);
    // FUNCTIONS //////////////////////////////////////////////
    LRESULT CALLBACK WindowProc(HWND hwnd, 
    						    UINT msg, 
                                WPARAM wparam, 
                                LPARAM lparam)
    {
    // this is the main message handler of the system
    PAINTSTRUCT		ps;		// used in WM_PAINT
    HDC				hdc;	// handle to a device context
    char buffer[80];        // used to print strings
    
    // what is the message 
    switch(msg)
    	{	
    	case WM_CREATE: 
            {
    		// do initialization stuff here
            // return success
    		return(0);
    		} break;
       
    	case WM_PAINT: 
    		{
    		// simply validate the window 
       	    hdc = BeginPaint(hwnd,&ps);	 
            
            // end painting
            EndPaint(hwnd,&ps);
    
            // return success
    		return(0);
       		} break;
    
    	case WM_DESTROY: 
    		{
    
    		// kill the application, this sends a WM_QUIT message 
    		PostQuitMessage(0);
    
            // return success
    		return(0);
    		} break;
    
    	default:break;
    
        } // end switch
    
    // process any messages that we didn't take care of 
    return (DefWindowProc(hwnd, msg, wparam, lparam));
    
    } // end WinProc
    
    ///////////////////////////////////////////////////////////
    
    //程序主循环
    int Game_Main(void *parms = NULL, int num_parms = 0)
    {
    // this is the main loop of the game, do all your processing
    // here
    
    // for now test if user is hitting ESC and send WM_CLOSE
    if(window_close)
    	return 1 ;
    if (KEYDOWN(VK_ESCAPE))
    {
    	PostMessage(main_window_handle,WM_CLOSE,0,0);
    	window_close = 1 ;
    }
       
    
    //清空表面
    DDBLTFX bltfx ;
    DD_INIT_STRUCT(bltfx);
    bltfx.dwFillColor = 0 ;
    if(FAILED(lpddsOffScreen->Blt(NULL,NULL,NULL,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx)))
    {
    	OutputDebugString(L"OffScreen Blt error");
    	return 1 ;
    }
    
    //锁定
    DDSURFACEDESC2 ddsd ;
    DD_INIT_STRUCT(ddsd);
    if(FAILED(lpddsOffScreen->Lock(NULL,&ddsd,DDLOCK_WAIT|DDLOCK_SURFACEMEMORYPTR,NULL)))
    {
    	OutputDebugString(L"Lock error");
    	return 1 ;
    }
    
    //获取窗口位置
    RECT rect ;
    GetWindowRect(main_window_handle,&rect);
    //画填充的三角形
    int x0 = rand()%SCREEN_WIDTH+rect.left;
    int x1 = rand()%SCREEN_WIDTH+rect.left ;
    int x2 = rand()%SCREEN_WIDTH + rect.left ;
    int y0 = rand()%SCREEN_HEIGHT + rect.top;
    int y1 = rand()%SCREEN_HEIGHT+ rect.top+100;
    int y2 = rand()%SCREEN_HEIGHT + rect.top;
    Draw_Trangle_2D(x0,y0,x1,y1,x2,y2,(UINT*)ddsd.lpSurface,
    	_RGB32BIT(0,255,255,255),ddsd.lPitch>>2);
    
    //解锁
    if(FAILED(lpddsOffScreen->Unlock(NULL)))
    {
    	OutputDebugString(L"Unlock error");
    	return 1 ;
    }
    
    //Blt到主表面
    if(FAILED(lpddsprimary->Blt(NULL,lpddsOffScreen,NULL,DDBLT_WAIT,NULL)))
    {
    	OutputDebugString(L"Blt error");
    	return 1 ;
    }
    
    // return success or failure or your own return code here
    return(1);
    
    } // end Game_Main
    
    ////////////////////////////////////////////////////////////
    
    int Game_Init(void *parms = NULL, int num_parms = 0)
    {
    // this is called once after the initial window is created and
    // before the main event loop is entered, do all your initialization
    // here
    
    // create IDirectDraw interface 7.0 object and test for error
    if (FAILED(DirectDrawCreateEx(NULL, (void **)&lpdd, IID_IDirectDraw7, NULL)))
       return(0);
    
    // set cooperation to normal since this will be a windowed app
    if(FAILED(lpdd->SetCooperativeLevel(main_window_handle, DDSCL_NORMAL)))
    {
    	MessageBox(NULL,L"SetCooperativeLevel error",L"error",MB_OK);
    	return 0 ;
    }
    
    //创建裁剪器
    if(FAILED(lpdd->CreateClipper(0,&lpddclipper,NULL)))
    {
    	OutputDebugString(L"CreateClipper error");
    	return 1 ;
    }
    
    //将裁减器关联窗口,也就是用窗口的尺寸作为裁剪器的裁剪序列
    if(FAILED(lpddclipper->SetHWnd(0,main_window_handle)))
    {
    	OutputDebugString(L"SetHWnd error");
    	return 1 ;
    }
    
    //创建主表面
    memset(&ddsd,0,sizeof(ddsd));
    ddsd.dwSize = sizeof(ddsd);
    ddsd.dwFlags = DDSD_CAPS ;
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
    
    if(FAILED(lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL)))
    {
    	MessageBox(NULL,L"CreateSurface error",L"error",MB_OK);
    	return 0 ;
    }
    
    //将裁减器关联到表面
    if(FAILED(lpddsprimary->SetClipper(lpddclipper)))
    {
    	OutputDebugString(L"SetClipper error");
    	return 1 ;
    }
    
    //创建一个离屏表面
    DD_INIT_STRUCT(ddsd);
    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT ;
    ddsd.dwHeight = 786 ;
    ddsd.dwWidth = 1366 ;
    if(FAILED(lpdd->CreateSurface(&ddsd,&lpddsOffScreen,NULL)))
    {
    	OutputDebugString(L"OffScreen CreateSurface error");
    	return 1 ;
    }
    
    
    
    // return success or failure or your own return code here
    return(1);
    
    } // end Game_Init
    
    /////////////////////////////////////////////////////////////
    
    int Game_Shutdown(void *parms = NULL, int num_parms = 0)
    {
    // this is called after the game is exited and the main event
    // loop while is exited, do all you cleanup and shutdown here
    
    // simply blow away the IDirectDraw4 interface
    
    if(lpddclipper)
    {
    	lpddclipper->Release();
    	lpddclipper = NULL ;
    }
    
    if(lpddsprimary)
    {
    	lpddsprimary->Release();
    	lpddsprimary = NULL ;
    }
    
    if (lpdd)
       {
       lpdd->Release();
       lpdd = NULL;
       } // end if
    
    // return success or failure or your own return code here
    return(1);
    
    } // end Game_Shutdown
    
    // WINMAIN ////////////////////////////////////////////////
    int WINAPI WinMain(	HINSTANCE hinstance,
    					HINSTANCE hprevinstance,
    					LPSTR lpcmdline,
    					int ncmdshow)
    {
    
    	WNDCLASSEX winclass; // this will hold the class we create
    	HWND	   hwnd;	 // generic window handle
    	MSG		   msg;		 // generic message
    	HDC        hdc;      // graphics device context
    
    	// first fill in the window class stucture
    	winclass.cbSize         = sizeof(WNDCLASSEX);
    	winclass.style			= CS_DBLCLKS | CS_OWNDC | 
    							  CS_HREDRAW | CS_VREDRAW;
    	winclass.lpfnWndProc	= WindowProc;
    	winclass.cbClsExtra		= 0;
    	winclass.cbWndExtra		= 0;
    	winclass.hInstance		= hinstance;
    	winclass.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
    	winclass.hCursor		= LoadCursor(NULL, IDC_ARROW); 
    	winclass.hbrBackground	= (HBRUSH)GetStockObject(BLACK_BRUSH);
    	winclass.lpszMenuName	= NULL;
    	winclass.lpszClassName	= WINDOW_CLASS_NAME;
    	winclass.hIconSm        = LoadIcon(NULL, IDI_APPLICATION);
    
    	// save hinstance in global
    	hinstance_app = hinstance;
    
    	// register the window class
    	if (!RegisterClassEx(&winclass))
    		return(0);
    
    	// create the window
    	if (!(hwnd = CreateWindowEx(NULL,                  // extended style
    								WINDOW_CLASS_NAME,     // class
    								L"DirectDraw Initialization Demo", // title
    								WS_OVERLAPPED|WS_VISIBLE,
    					 			0,0,	  // initial x,y
    								SCREEN_WIDTH,SCREEN_HEIGHT,  // initial width, height
    								NULL,	  // handle to parent 
    								NULL,	  // handle to menu
    								hinstance,// instance of this application
    								NULL)))	// extra creation parms
    		return(0);
    
    	// save main window handle
    	main_window_handle = hwnd;
    
    	// initialize game here
    	Game_Init();
    
    	//调整窗口大小
    	RECT window_rect = {0,0,SCREEN_WIDTH,SCREEN_HEIGHT} ;
    	AdjustWindowRectEx(&window_rect,GetWindowStyle(main_window_handle),GetMenu(main_window_handle)!=NULL,GetWindowExStyle(main_window_handle));
    
    	// enter main event loop
    	while(TRUE)
    		{
    		// test if there is a message in queue, if so get it
    		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
    		   { 
    		   // test if this is a quit
    		   if (msg.message == WM_QUIT)
    			   break;
    	
    		   // translate any accelerator keys
    		   TranslateMessage(&msg);
    
    		   // send the message to the window proc
    		   DispatchMessage(&msg);
    		   } // end if
        
    		   // main game processing goes here
    		   Game_Main();
           
    		} // end while
    
    	// closedown game here
    	Game_Shutdown();
    
    	// return to Windows like this
    	return(msg.wParam);
    
    } // end WinMain
    
    //定义交换函数
    void Swap(int &x , int &y)
    {
    	int temp = y ;
    	y = x ;
    	x = temp ;
    }
    
    //定义画线函数
    int Draw_Line(int x0,int y0, int x1, int y1 , DWORD color , UINT *video_buffer, int stepx,int stepy)
    {
    	int dx ,  //起点与终点的X方向间距
    		dy ,  //起点与终点的Y方向间距
    		dx2, //两倍的dx
    		dy2,  //两倍的dy
    		x_inc ,  //实际的x步长值,带有符号
    		y_inc , //实际的y步长值,带有符号
    		p ;     //误差项
    
    	dx = x1 - x0 ;  //计算x间距
    	dy = y1 - y0 ;  //计算y间距
    
    	//计算起点的缓冲地址
    	video_buffer+=x0+y0*stepy ;
    
    	//确定x方向的步进值
    	if(dx>=0)
    	{
    		x_inc = stepx;
    	}
    	else
    	{
    		x_inc = -stepx ;
    		dx = -dx ;
    	}
    
    	//确定y方向的步进值
    	if(dy>=0)
    	{
    		y_inc = stepy ;
    	}
    	else
    	{
    		y_inc = -stepy ;
    		dy = -dy ;
    	}
    
    	//确定dx2,dy2的值
    	dx2 = dx<<1;
    	dy2 = dy<<1 ;
    
    	//进行步进的选择
    	if(dx <= dy) //斜率绝对值大于1
    	{
    		Swap(dx,dy);
    		Swap(x_inc,y_inc);
    		Swap(dx2,dy2);
    	}
    	else //斜率绝对值小于1,不需要交换
    	{
    	}
    
    
    	//绘制直线
    	p = dy2 - dx ;  //计算起点的误差值
    	for(int i = 0 ; i < dx ; i++)
    	{
    		*video_buffer = color ;
    		
    		video_buffer += x_inc ;
    		if(p>=0)
    		{
    			video_buffer += y_inc ;
    			p = p + dy2 - dx2 ;
    		}
    		else
    		{
    			p = p + dy2 ;
    		}
    	}// end for
    
    
    	return 0 ;
    }// end Draw_Line
    
    //定义裁剪直线算法
    int Clipper_Line(int& x0,int& y0,int& x1, int& y1,int screen_width,int screen_height)
    {
    #define CLIP_CODE_C 0x0000
    #define CLIP_CODE_N 0x0008
    #define CLIP_CODE_S 0x0004
    #define CLIP_CODE_E 0x0002
    #define CLIP_CODE_W 0x0001
    
    #define CLIP_CODE_NE 0x000a
    #define CLIP_CODE_SE 0x0006
    #define CLIP_CODE_NW 0x0009
    #define CLIP_CODE_SW 0x0005
    	int xc0 = x0 ,yc0 = y0 , xc1=x1 , yc1=y1 ;
    	int min_clip_x = SCREEN_WIDTH/3 ,min_clip_y = SCREEN_HEIGHT/3 ,max_clip_x = screen_width*2/3-1,max_clip_y=screen_height*2/3-1 ;
    	int p0_code = 0 ,p1_code = 0 ;
    
    	//确定各个顶点所在的位置代码
    	if(y0<min_clip_y)
    		p0_code|=CLIP_CODE_N;
    	else if(y0>max_clip_y)
    		p0_code|=CLIP_CODE_S;
    
    	if(x0<min_clip_x)
    		p0_code|=CLIP_CODE_W;
    	else if(x0>max_clip_x)
    		p0_code|=CLIP_CODE_E;
    
    	if(y1<min_clip_y)
    		p1_code|=CLIP_CODE_N;
    	else if(y1>max_clip_y)
    		p1_code|=CLIP_CODE_S;
    
    	if(x1<min_clip_x)
    		p1_code|=CLIP_CODE_W;
    	else if(x1>max_clip_x)
    		p1_code|=CLIP_CODE_E;
    
    	//先检测一些简单的情况
    	if(p0_code&p1_code) //有相同的位置代码,表示在裁剪区外部
    		return 0 ;
    	if(p0_code==0&&p1_code==0) //表示两个点都在裁剪区内,不需要裁剪
    		return 1 ;
    
    	//判断第一个点的位置代码
    	switch(p0_code)
    	{
    	case CLIP_CODE_C:
    		break;
    	case CLIP_CODE_N:
    		{
    			yc0 = min_clip_y ;
    			xc0 = x0 + 0.5 + (yc0-y0)*(x1-x0)/(y1-y0);
    			break ;
    		}
    	case CLIP_CODE_S:
    		{
    			yc0 = max_clip_y;
    			xc0 = x0 + 0.5 + (yc0-y0)*(x1-x0)/(y1-y0);
    			break ;
    		}
    	case CLIP_CODE_W:
    		{
    			xc0=min_clip_x;
    			yc0=y0+0.5+(xc0-x0)*(y1-y0)/(x1-x0);
    			break;
    		}
    	case CLIP_CODE_E:
    		{
    			xc0=max_clip_x;
    			yc0=y0+0.5+(xc0-x0)*(y1-y0)/(x1-x0);
    			break;
    		}
    	case CLIP_CODE_NE:
    		{
    			yc0 = min_clip_y;
    			xc0 = x0 + 0.5 + (yc0-y0)*(x1-x0)/(y1-y0);
    
    			if(xc0<min_clip_x||xc0>max_clip_x)
    			{
    				xc0=max_clip_x;
    				yc0=y0+0.5+(xc0-x0)*(y1-y0)/(x1-x0);
    			}
    			break;
    		}
    	case CLIP_CODE_SE:
    		{
    			yc0 = max_clip_y;
    			xc0 = x0 + 0.5 + (yc0-y0)*(x1-x0)/(y1-y0);
    
    			if(xc0<min_clip_x||xc0>max_clip_x)
    			{
    				xc0=max_clip_x;
    				yc0=y0+0.5+(xc0-x0)*(y1-y0)/(x1-x0);
    			}
    			break;
    		}
    	case CLIP_CODE_NW:
    		{
    			yc0=min_clip_y;
    			xc0 = x0 + 0.5 + (yc0-y0)*(x1-x0)/(y1-y0);
    
    			if(xc0<min_clip_x||xc0>max_clip_x)
    			{
    				xc0=min_clip_x;
    				yc0=y0+0.5+(xc0-x0)*(y1-y0)/(x1-x0);
    			}
    			break;
    		}
    	case CLIP_CODE_SW:
    		{
    			yc0=max_clip_y;
    			xc0 = x0 + 0.5 + (yc0-y0)*(x1-x0)/(y1-y0);
    
    			if(xc0<min_clip_x||xc0>max_clip_x)
    			{
    				xc0=min_clip_x;
    				yc0=y0+0.5+(xc0-x0)*(y1-y0)/(x1-x0);
    			}
    			break;
    		}
    	default:
    		break;
    	} // end switch(p0_code)
    
    	//判断第二个点的位置代码
    	switch(p1_code)
    	{
    	case CLIP_CODE_C:
    		break;
    	case CLIP_CODE_N:
    		{
    			yc1 = min_clip_y ;
    			xc1 = x1 + 0.5 + (yc1-y1)*(x1-x0)/(y1-y0);
    			break ;
    		}
    	case CLIP_CODE_S:
    		{
    			yc1 = max_clip_y;
    			xc1 = x1 + 0.5 + (yc1-y1)*(x1-x0)/(y1-y0);
    			break ;
    		}
    	case CLIP_CODE_W:
    		{
    			xc1=min_clip_x;
    			yc1=y1+0.5+(xc1-x1)*(y1-y0)/(x1-x0);
    			break;
    		}
    	case CLIP_CODE_E:
    		{
    			xc1=max_clip_x;
    			yc1=y1+0.5+(xc1-x1)*(y1-y0)/(x1-x0);
    			break;
    		}
    	case CLIP_CODE_NE:
    		{
    			yc1 = min_clip_y;
    			xc1 = x1 + 0.5 + (yc1-y1)*(x1-x0)/(y1-y0);
    
    			if(xc1<min_clip_x||xc1>max_clip_x)
    			{
    				xc1=max_clip_x;
    				yc1=y1+0.5+(xc1-x1)*(y1-y0)/(x1-x0);
    			}
    			break;
    		}
    	case CLIP_CODE_SE:
    		{
    			yc1 = max_clip_y;
    			xc1 = x1 + 0.5 + (yc1-y1)*(x1-x0)/(y1-y0);
    
    			if(xc1<min_clip_x||xc1>max_clip_x)
    			{
    				xc1=max_clip_x;
    				yc1=y1+0.5+(xc1-x1)*(y1-y0)/(x1-x0);
    			}
    			break;
    		}
    	case CLIP_CODE_NW:
    		{
    			yc1=min_clip_y;
    			xc1 = x1 + 0.5 + (yc1-y1)*(x1-x0)/(y1-y0);
    
    			if(xc1<min_clip_x||xc1>max_clip_x)
    			{
    				xc1=min_clip_x;
    				yc1=y1+0.5+(xc1-x1)*(y1-y0)/(x1-x0);
    			}
    			break;
    		}
    	case CLIP_CODE_SW:
    		{
    			yc1=max_clip_y;
    			xc1 = x1 + 0.5 + (yc1-y1)*(x1-x0)/(y1-y0);
    
    			if(xc1<min_clip_x||xc1>max_clip_x)
    			{
    				xc1=min_clip_x;
    				yc1=y1+0.5+(xc1-x1)*(y1-y0)/(x1-x0);
    			}
    			break;
    		}
    	default:
    		break;
    	} // end switch(p1_code)
    
    	//进行最后的检测
    	if(xc0>max_clip_x||xc0<min_clip_x||
    		yc0>max_clip_y||yc0<min_clip_y||
    		xc1>max_clip_x||xc1<min_clip_x||
    		yc1>max_clip_y||yc1<min_clip_y)
    	{
    		//表示全部在裁剪区外部
    		return 0 ;
    	}
    
    	//将裁减后的数据返回
    	x0 = xc0 ;
    	x1 = xc1 ;
    	y0 = yc0 ;
    	y1 = yc1 ;
    
    	return 1 ;
    }// end Clipper_Line
    
    //简单的平行绘制直线
    int Draw_Simple_Line(int x0, int x1,int y , UINT * video_buffer,DWORD color,int mempitch)
    {
    	//进行裁剪
    	if(y<min_clip_y)
    		return 1 ;
    	else if(y>max_clip_y)
    		return 1 ;
    	if(x0<min_clip_x)
    		x0 = min_clip_x;
    	else if(x0>max_clip_x)
    		x0 = max_clip_x ;
    	if(x1<min_clip_x)
    		x1 = min_clip_x ;
    	else if(x1>max_clip_x)
    		x1 = max_clip_x ;
    
    	//进行绘制
    	video_buffer+=y*mempitch;
    	for(int x = x0 ; x<=x1;x++)
    	{
    		video_buffer[x]=color ;
    	}
    }
    
    //绘制填充平顶三角形
    int Draw_Top_Trangle(int x0,int y0,
    					int x1,int y1,
    					int x2,int y2,
    					UINT * video_buffer,
    					DWORD color,int mempitch)
    {
    	//先判断下输入的三角形
    	if(y0==y1)
    	{
    	}else if(y0==y2)
    	{
    		Swap(x2,x1);
    		Swap(y2,y1);
    	}else if(y1==y2)
    	{
    		Swap(x0,x2);
    		Swap(y0,y2);
    	}else
    	{
    		return 1 ; //error rief 不是平顶三角形
    	}
    
    	if(x1<x0)
    	{
    		Swap(x1,x0);
    		Swap(y1,y0);
    	}
    	else if(x1 == x0)
    	{
    		return 1 ;// error rief不是三角形
    	}
    
    	//计算左右误差
    	float dxy_left = (x2-x0)*1.0/(y2-y0) ;
    	float dxy_right = (x1-x2)*1.0/(y1-y2);
    
    	//开始进行填充
    	float xs = x0 ,xe = x1 ;
    	for(int y=y0 ; y <=y2 ;y++)
    	{
    		Draw_Simple_Line(int(xs+0.5),int(xe+0.5),y,video_buffer,color,mempitch);
    
    		xs += dxy_left ;
    		xe += dxy_right ;
    	}
    } // end Draw_Top_Trangle
    
    //绘制平底三角形
    int Draw_Bottom_Trangle(int x0,int y0,
    					int x1,int y1,
    					int x2,int y2,
    					UINT * video_buffer,
    					DWORD color,int mempitch)
    {
    	//先判断下输入的三角形
    	if(y2==y1)
    	{
    	}else if(y2==y0)
    	{
    		Swap(x0,x1);
    		Swap(y0,y1);
    	}else if(y0==y1)
    	{
    		Swap(x0,x2);
    		Swap(y0,y2);
    	}else
    	{
    		return 1 ; //error rief 不是平顶三角形
    	}
    
    	if(x1<x2)
    	{
    		Swap(x1,x2);
    	}
    	else if(x1 == x2)
    	{
    		return 1 ;// error rief不是三角形
    	}
    
    	//计算左右误差
    	float dxy_left = (x2-x0)*1.0/(y2-y0) ;
    	float dxy_right = (x1-x0)*1.0/(y1-y0);
    
    	//开始进行填充
    	float xs = x0 ,xe = x0 ;
    	for(int y=y0 ; y <=y2 ;y++)
    	{
    		Draw_Simple_Line(int(xs+0.5),int(xe+0.5),y,video_buffer,color,mempitch);
    
    		xs += dxy_left ;
    		xe += dxy_right ;
    	}
    }// end Draw_Bottom_Trangle
    
    //绘制任意三角形
    int Draw_Trangle_2D(int x0,int y0,
    					int x1,int y1,
    					int x2,int y2,
    					UINT * video_buffer,
    					DWORD color,int mempitch)
    {
    	if((x0==x1&&x1==x2)
    		||(y0==y1&&y1==y2))
    	{
    		return 1 ; //error rief传进来的点无法构成三角形
    	}
    
    	//rief 将三个顶点按照从上到下排序
    	if(y0>y1)
    	{
    		Swap(x0,x1);
    		Swap(y0,y1);
    	}
    
    	if(y0>y2)
    	{
    		Swap(x0,x2);
    		Swap(y0,y2);
    	}
    
    	if(y1>y2)
    	{
    		Swap(y1,y2);
    		Swap(x1,x2);
    	}
    
    	//rief查找最大的x坐标,和最小的y坐标
    	int min = (x0<x1?x0:x1);
    	min = (min<x2?min:x2);
    	int max = (x0>x1?x0:x1);
    	max = (max>x2?max:x2);
    
    	//rief 进行绘制
    	if(y2<=min_clip_y||y0>=max_clip_y
    		||min>=max_clip_x||max<=min_clip_x)
    		return 1 ;  //rief 全部在裁剪区之外
    	if(y0 == y1) //rief 平顶三角形
    	{
    		Draw_Top_Trangle(x0,y0,x1,y1,x2,y2,video_buffer,color,mempitch);
    	}else if(y1 == y2)
    	{
    		Draw_Bottom_Trangle(x0,y0,x1,y1,x2,y2,video_buffer,color,mempitch);
    	}else
    	{
    		int new_x = x0+0.5+(float)1.0*(y1-y0)*(x2-x0)/(y2-y0);
    		Draw_Bottom_Trangle(x0,y0,new_x,y1,x1,y1,video_buffer,color,mempitch);
    		Draw_Top_Trangle(new_x,y1,x1,y1,x2,y2,video_buffer,color,mempitch);
    	}
    
    
    	return 0 ; //rief 成功画出三角形
    }// end Draw_Trangle_2D
    ///////////////////////////////////////////////////////////
    

    下图是运行结果:


    OK,今天就到这里的,明天继续学习
     
    jpg改rar
  • 相关阅读:
    bzoj2298 [HAOI2011]problem a
    P5504 [JSOI2011]柠檬
    洛谷P4383 [八省联考2018]林克卡特树
    [USACO17DEC]Standing Out from the Herd
    bzoj3926: [Zjoi2015]诸神眷顾的幻想乡
    dtoj4680. 红黑兔
    dtoj2099. 字符串查询( find)
    dtoj1721. 字符串生成器 ( strgen )
    dtoj4542. 「TJOI / HEOI2016」字符串
    loj2278. 「HAOI2017」字符串
  • 原文地址:https://www.cnblogs.com/kuangke/p/6626918.html
Copyright © 2020-2023  润新知