郁金香外挂技术-郁金香灬老师

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

郁金香终身VIP管理员QQ150330575项目合作(有实力的+)视频教程+每月更新+QQ群
飞郁视频分享(每周更新)
查看: 4699|回复: 0

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

[复制链接]
发表于 2018-12-25 11:39:11 | 显示全部楼层 |阅读模式
Windows游戏编程大师技巧之三角形填充
一。三角形的种类三角形一般可以分为如下的四种类型(这四种类型是对于计算机来说的,不是数学意义上的分类):
平顶三角形:就是在计算机中显示的上面两个顶点的Y坐标相同。
平底三角形:就是在计算机中显示的时候下面两个顶点的Y坐标相同。
右边为主三角形:这种三角形三个点的Y坐标都不相同,但是右边的一条边是最长的斜边
左边为主的三角形:这种三角形的三个点的Y坐标不相同,但是左边的一条边是最长的斜边。
附上各个不同三角形的图:


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


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


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


二。代码实现下面是实现平顶的三角形填充的代码:
[cpp] view plain copy
print?


  • 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 \brief 不是平顶三角形  
  •     }  
  •   
  •     if(x1<x0)  
  •     {  
  •         Swap(x1,x0);  
  •         Swap(y1,y0);  
  •     }  
  •     else if(x1 == x0)  
  •     {  
  •         return 1 ;// error \brief不是三角形  
  •     }  
  •   
  •     //计算左右误差  
  •     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_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 \brief 不是平顶三角形        }        if(x1<x0)        {                Swap(x1,x0);                Swap(y1,y0);        }        else if(x1 == x0)        {                return 1 ;// error \brief不是三角形        }        //计算左右误差        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的实现版本)


同样的,来看看我们的平底三角形填充的实现:
[cpp] view plain copy
print?


  • 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 \brief 不是平顶三角形  
  •     }  
  •   
  •     if(x1<x2)  
  •     {  
  •         Swap(x1,x2);  
  •     }  
  •     else if(x1 == x2)  
  •     {  
  •         return 1 ;// error \brief不是三角形  
  •     }  
  •   
  •     //计算左右误差  
  •     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_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 \brief 不是平顶三角形        }        if(x1<x2)        {                Swap(x1,x2);        }        else if(x1 == x2)        {                return 1 ;// error \brief不是三角形        }        //计算左右误差        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
和上面平顶的算法基本上一致,只有图中点的顺序不同:


好了,这两个函数都实现了,接下来看看我们任意的三角形绘制的实现吧:
[cpp] view plain copy
print?


  • 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 \brief传进来的点无法构成三角形  
  •     }  
  •   
  •     //\brief 将三个顶点按照从上到下排序  
  •     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);  
  •     }  
  •   
  •     //\brief查找最大的x坐标,和最小的y坐标  
  •     int min = (x0<x1?x0:x1);  
  •     min = (min<x2?min:x2);  
  •     int max = (x0>x1?x0:x1);  
  •     max = (max>x2?max:x2);  
  •   
  •     //\brief 进行绘制  
  •     if(y2<=min_clip_y||y0>=max_clip_y  
  •         ||min>=max_clip_x||max<=min_clip_x)  
  •         return 1 ;  //\brief 全部在裁剪区之外  
  •     if(y0 == y1) //\brief 平顶三角形  
  •     {  
  •         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 ; //\brief 成功画出三角形  
  • }// 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 \brief传进来的点无法构成三角形        }        //\brief 将三个顶点按照从上到下排序        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);        }        //\brief查找最大的x坐标,和最小的y坐标        int min = (x0<x1?x0:x1);        min = (min<x2?min:x2);        int max = (x0>x1?x0:x1);        max = (max>x2?max:x2);        //\brief 进行绘制        if(y2<=min_clip_y||y0>=max_clip_y                ||min>=max_clip_x||max<=min_clip_x)                return 1 ;  //\brief 全部在裁剪区之外        if(y0 == y1) //\brief 平顶三角形        {                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 ; //\brief 成功画出三角形}// end Draw_Trangle_2D
这个函数,先将输入的三个点按照y坐标从小到大排序,这样我们就可以y1的坐标,来寻找分离一个右边为主或者左边为主的三角形成为一个平顶一个平底的三角形了。(由于排序了,所以y1的坐标就是显示屏幕上从上到下中间的那个点了,想象是不是这样的!?)。分离了之后,我们就可以分别调用绘制平底和平顶的三角形的算法来实现了。


以下是整个工程的完整代码:
[cpp] view plain copy
print?


  • // 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 \brief 不是平顶三角形  
  •     }  
  •   
  •     if(x1<x0)  
  •     {  
  •         Swap(x1,x0);  
  •         Swap(y1,y0);  
  •     }  
  •     else if(x1 == x0)  
  •     {  
  •         return 1 ;// error \brief不是三角形  
  •     }  
  •   
  •     //计算左右误差  
  •     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 \brief 不是平顶三角形  
  •     }  
  •   
  •     if(x1<x2)  
  •     {  
  •         Swap(x1,x2);  
  •     }  
  •     else if(x1 == x2)  
  •     {  
  •         return 1 ;// error \brief不是三角形  
  •     }  
  •   
  •     //计算左右误差  
  •     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 \brief传进来的点无法构成三角形  
  •     }  
  •   
  •     //\brief 将三个顶点按照从上到下排序  
  •     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);  
  •     }  
  •   
  •     //\brief查找最大的x坐标,和最小的y坐标  
  •     int min = (x0<x1?x0:x1);  
  •     min = (min<x2?min:x2);  
  •     int max = (x0>x1?x0:x1);  
  •     max = (max>x2?max:x2);  
  •   
  •     //\brief 进行绘制  
  •     if(y2<=min_clip_y||y0>=max_clip_y  
  •         ||min>=max_clip_x||max<=min_clip_x)  
  •         return 1 ;  //\brief 全部在裁剪区之外  
  •     if(y0 == y1) //\brief 平顶三角形  
  •     {  
  •         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 ; //\brief 成功画出三角形  
  • }// end Draw_Trangle_2D  
  • ///////////////////////////////////////////////////////////  

// 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++ stuffusing 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 typestypedef 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 windowHINSTANCE hinstance_app      = NULL; // globally track hinstance// directdraw stuffLPDIRECTDRAW7         lpdd         = NULL;   // dd objectLPDIRECTDRAWSURFACE7  lpddsprimary = NULL;   // dd primary surfaceLPDIRECTDRAWSURFACE7  lpddsback    = NULL;   // dd back surfaceLPDIRECTDRAWPALETTE   lpddpal      = NULL;   // a pointer to the created dd paletteLPDIRECTDRAWCLIPPER   lpddclipper  = NULL;   // dd clipperPALETTEENTRY          palette[256];          // color palettePALETTEENTRY          save_palette[256];     // used to save palettesDDSURFACEDESC2        ddsd;                  // a direct draw surface description structDDBLTFX               ddbltfx;               // used to fillDDSCAPS2              ddscaps;               // a direct draw surface capabilities structHRESULT               ddrval;                // result back from dd callsDWORD                 start_clock_count = 0; // used for timingLPDIRECTDRAWSURFACE7  lpddsOffScreen = NULL ;  //离屏表面int                                          window_close  =  0 ;    //标识窗口是否关闭// these defined the general clipping rectangleint 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 pixelchar 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 systemPAINTSTRUCT                ps;                // used in WM_PAINTHDC                                hdc;        // handle to a device contextchar 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_CLOSEif(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 herereturn(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 errorif (FAILED(DirectDrawCreateEx(NULL, (void **)&lpdd, IID_IDirectDraw7, NULL)))   return(0);// set cooperation to normal since this will be a windowed appif(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 herereturn(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 interfaceif(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 herereturn(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 \brief 不是平顶三角形        }        if(x1<x0)        {                Swap(x1,x0);                Swap(y1,y0);        }        else if(x1 == x0)        {                return 1 ;// error \brief不是三角形        }        //计算左右误差        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 \brief 不是平顶三角形        }        if(x1<x2)        {                Swap(x1,x2);        }        else if(x1 == x2)        {                return 1 ;// error \brief不是三角形        }        //计算左右误差        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 \brief传进来的点无法构成三角形        }        //\brief 将三个顶点按照从上到下排序        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);        }        //\brief查找最大的x坐标,和最小的y坐标        int min = (x0<x1?x0:x1);        min = (min<x2?min:x2);        int max = (x0>x1?x0:x1);        max = (max>x2?max:x2);        //\brief 进行绘制        if(y2<=min_clip_y||y0>=max_clip_y                ||min>=max_clip_x||max<=min_clip_x)                return 1 ;  //\brief 全部在裁剪区之外        if(y0 == y1) //\brief 平顶三角形        {                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 ; //\brief 成功画出三角形}// end Draw_Trangle_2D///////////////////////////////////////////////////////////
下图是运行结果:





郁金香外挂教程,学习中...
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

限时限量优惠

QQ|小黑屋|手机版|郁金香外挂技术-郁金香灬老师 ( 苏ICP备10059359号 )

GMT+8, 2021-4-13 01:02 , Processed in 0.233681 second(s), 18 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表