首页 技术 正文
技术 2022年11月8日
0 收藏 685 点赞 1,628 浏览 38494 个字

一。三角形的种类

三角形一般可以分为如下的四种类型(这四种类型是对于计算机来说的,不是数学意义上的分类):平顶三角形:就是在计算机中显示的上面两个顶点的Y坐标相同。平底三角形:就是在计算机中显示的时候下面两个顶点的Y坐标相同。右边为主三角形:这种三角形三个点的Y坐标都不相同,但是右边的一条边是最长的斜边左边为主的三角形:这种三角形的三个点的Y坐标不相同,但是左边的一条边是最长的斜边。附上各个不同三角形的图:Windows游戏编程大师技巧之三角形填充是不是所有的三角形大致可以分为这四种?而我们要进行填充的时候,前面两种的填充应该比较简单,只要从顶点开始一行一行的进行填充就可以做到了,如下图所示:Windows游戏编程大师技巧之三角形填充进行这样的操作应该很容易实现吧,同样的对平顶的三角形我们也可以这样来一行一行的使用像素进行填充。至于后面两种情况的三角形,我们能够很简单的将他们分别变成两个三角形,一个平顶一个平底:Windows游戏编程大师技巧之三角形填充所以,我们实现了前面两个的三角形的填充,后面两个的也就很容易实现了。

二。代码实现

下面是实现平顶的三角形填充的代码:

  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 \brief 不是平顶三角形
  21. }
  22. if(x1<x0)
  23. {
  24. Swap(x1,x0);
  25. Swap(y1,y0);
  26. }
  27. else if(x1 == x0)
  28. {
  29. return 1 ;// error \brief不是三角形
  30. }
  31. //计算左右误差
  32. float dxy_left = (x2-x0)*1.0/(y2-y0) ;
  33. float dxy_right = (x1-x2)*1.0/(y1-y2);
  34. //开始进行填充
  35. float xs = x0 ,xe = x1 ;
  36. for(int y=y0 ; y <=y2 ;y++)
  37. {
  38. Draw_Simple_Line(int(xs+0.5),int(xe+0.5),y,video_buffer,color,mempitch);
  39. xs += dxy_left ;
  40. xe += dxy_right ;
  41. }
  42. } // end Draw_Top_Trangle

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

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

上面的算法开始的时候,检查下输入的三个点是否能够构成三角形,并且按照下面图中坐标点所示,来进行顺序的重新排列:Windows游戏编程大师技巧之三角形填充因为用户使用的时候,可能传递的三个点不是上图中所示的那样的顺序,所以我们计算的方便,我们先将这三个点转变成上图中相对应的位置。接下来就是计算在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 \brief 不是平顶三角形
  21. }
  22. if(x1<x2)
  23. {
  24. Swap(x1,x2);
  25. }
  26. else if(x1 == x2)
  27. {
  28. return 1 ;// error \brief不是三角形
  29. }
  30. //计算左右误差
  31. float dxy_left = (x2-x0)*1.0/(y2-y0) ;
  32. float dxy_right = (x1-x0)*1.0/(y1-y0);
  33. //开始进行填充
  34. float xs = x0 ,xe = x0 ;
  35. for(int y=y0 ; y <=y2 ;y++)
  36. {
  37. Draw_Simple_Line(int(xs+0.5),int(xe+0.5),y,video_buffer,color,mempitch);
  38. xs += dxy_left ;
  39. xe += dxy_right ;
  40. }
  41. }// end Draw_Bottom_Trangle

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

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

和上面平顶的算法基本上一致,只有图中点的顺序不同:Windows游戏编程大师技巧之三角形填充好了,这两个函数都实现了,接下来看看我们任意的三角形绘制的实现吧:

  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 \brief传进来的点无法构成三角形
  11. }
  12. //\brief 将三个顶点按照从上到下排序
  13. if(y0>y1)
  14. {
  15. Swap(x0,x1);
  16. Swap(y0,y1);
  17. }
  18. if(y0>y2)
  19. {
  20. Swap(x0,x2);
  21. Swap(y0,y2);
  22. }
  23. if(y1>y2)
  24. {
  25. Swap(y1,y2);
  26. Swap(x1,x2);
  27. }
  28. //\brief查找最大的x坐标,和最小的y坐标
  29. int min = (x0<x1?x0:x1);
  30. min = (min<x2?min:x2);
  31. int max = (x0>x1?x0:x1);
  32. max = (max>x2?max:x2);
  33. //\brief 进行绘制
  34. if(y2<=min_clip_y||y0>=max_clip_y
  35. ||min>=max_clip_x||max<=min_clip_x)
  36. return 1 ;  //\brief 全部在裁剪区之外
  37. if(y0 == y1) //\brief 平顶三角形
  38. {
  39. Draw_Top_Trangle(x0,y0,x1,y1,x2,y2,video_buffer,color,mempitch);
  40. }else if(y1 == y2)
  41. {
  42. Draw_Bottom_Trangle(x0,y0,x1,y1,x2,y2,video_buffer,color,mempitch);
  43. }else
  44. {
  45. int new_x = x0+0.5+(float)1.0*(y1-y0)*(x2-x0)/(y2-y0);
  46. Draw_Bottom_Trangle(x0,y0,new_x,y1,x1,y1,video_buffer,color,mempitch);
  47. Draw_Top_Trangle(new_x,y1,x1,y1,x2,y2,video_buffer,color,mempitch);
  48. }
  49. return 0 ; //\brief 成功画出三角形
  50. }// end Draw_Trangle_2D

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

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的坐标就是显示屏幕上从上到下中间的那个点了,想象是不是这样的!?)。分离了之后,我们就可以分别调用绘制平底和平顶的三角形的算法来实现了。以下是整个工程的完整代码:

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

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

// 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 stuffLPDIRECTDRAW7 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 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 system
PAINTSTRUCTps;// used in WM_PAINT
HDChdc;// 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 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 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 forreturn 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
///////////////////////////////////////////////////////////

下图是运行结果:Windows游戏编程大师技巧之三角形填充OK,今天就到这里的,明天继续学习 jpg改rarWindows游戏编程大师技巧之三角形填充

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,082
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,557
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,406
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,179
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,815
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,898