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
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_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
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的坐标就是显示屏幕上从上到下中间的那个点了,想象是不是这样的!?)。分离了之后,我们就可以分别调用绘制平底和平顶的三角形的算法来实现了。
- // 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++ 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
///////////////////////////////////////////////////////////
下图是运行结果:
Windows游戏编程大师技巧之三角形填充的更多相关文章
- 《Windows游戏编程大师技巧》学习笔记——关于创建显示表面
1.如你所知,显示在屏幕上的图像仅仅只是是以某种格式存储在内存中的有色像素组成的矩阵.或是调色板化的或是RGB模式的.在不论什么一种情况下.要想做点什么你都必须知道如何绘制图到内存中,然而Direct ...
- 3D游戏编程大师技巧──2D引擎的编译问题
接上一篇文章,这里将介绍2D引擎的编译,从现在开始才真正进入<3D游戏编程大师技巧>的学习.本书的第一.二章只是简介了游戏编程和windows编程,从第三章开始才是介绍<window ...
- 3D游戏编程大师技巧──环境搭建
刚开微博,想借助这个平台与大家交流,写下自己的学习记录,希望得到大家的批评指正. 好了,进入主题.这段时间对游戏编程很感兴趣,于是在网友的推荐下开始学习<3D游戏编程大师技巧>这本书.今天 ...
- 《逐梦旅程 WINDOWS游戏编程之从零开始》笔记5——Direct3D中的顶点缓存和索引缓存
第12章 Direct3D绘制基础 1. 顶点缓存 计算机所描绘的3D图形是通过多边形网格来构成的,网网格勾勒出轮廓,然后在网格轮廓的表面上贴上相应的图片,这样就构成了一个3D模型.三角形网格是构建物 ...
- Windows游戏编程之从零开始d
Windows游戏编程之从零开始d I'm back~~恩,几个月不见,大家还好吗? 这段时间真的好多童鞋在博客里留言说或者发邮件说浅墨你回来继续更新博客吧. woxiangnifrr童鞋说每天都在来 ...
- windows游戏编程 创建WIN32一个HelloWOrld程序
本系列文章由jadeshu编写,转载请注明出处.http://blog.csdn.net/jadeshu/article/details/22449085 作者:jadeshu 邮箱: jades ...
- 《逐梦旅程 WINDOWS游戏编程之从零开始》笔记2——透明贴图,动画技术
第5章 透明贴图 像这样直接贴图会产生这种情况,所以我们需要透明贴图. 透明遮罩法:主要利用BitBlt函数中Raser(光栅)值的运算,需要准备素材图和遮罩图: 这个方法的原理解释见书131页. 示 ...
- windows游戏编程 绘图基础
本系列文章由jadeshu编写,转载请注明出处.http://blog.csdn.net/jadeshu/article/details/22451353 作者:jadeshu 邮箱: jades ...
- 《逐梦旅程 WINDOWS游戏编程之从零开始》笔记3——输入消息处理,物理建模与粒子系统初步
第7章 Windows游戏输入消息处理 1. 键盘消息处理 之前提到的窗口过程函数有两参数与消息输出有关——wParam和llParam LRESULT CALLBACK WindowProc( _I ...
随机推荐
- map 类简介和例程
一.标准库的map类型 使用map得包含map类所在的头文件 template < class Key, class Type, class Traits = less<Key>, ...
- QQ窗体的控制,同步异步打开360网盘,控制360网盘窗体的移动
1.通过system启动飞秋进程的方式: 2.Windows下杀死进程的方式是:taskkill /f/im QQ.exe.截图例如以下: watermark/2/text/aHR0cDovL2 ...
- EF4
http://www.cnblogs.com/xray2005/category/189491.html http://kb.cnblogs.com/zt/ef/ http://www.cnblogs ...
- winform程序textbox滚动条保持在最下面 内容不闪烁
在开发winform程序时,会用到textbox控件来显示信息,当把textbox的Multiline属性改为Ture时(即多行显示状态),ScrollBars属性改为Vertical(内容过多时,显 ...
- ubuntu获取root权限
1.先在Terminal下设置root密码 执行 sudo passwd root 2.执行sudo su,然后根据提示来即可.
- Python中模拟C# Linq的一些操作
闲来无事时积累的一些Linq函数,有时间就更新. 需要注意python版本如果低于3.0不支持lambda,只能单独写函数传参,比较麻烦 1.FirstOrDefault: def FirstOrDe ...
- C++ string long double转char*
long long q = 10; ]; char* output; sprintf(s, "%ld", q); output = s; double ]; sprintf(s1, ...
- CYQ学习主要摘要4
http://www.cnblogs.com/cyq1162/archive/2010/11/03/1867642.html Xml的处理 http://www.cnblogs.com/cyq1162 ...
- 【Android】13.1 用Android自带的API访问SQLite数据库
分类:C#.Android.VS2015: 创建日期:2016-02-26 一.简介 这一节我们先来看看如何直接用Android自带的API创建和访问SQLite数据库. 1.创建SQLite数据库 ...
- 总结iOS9中的新的方法
iOS平台在快速的发展,各种接口正在不断的更新.随着iOS9的发布,又有一批老方法不推荐使用了,你若调用这些方法,运行的结果是没有问题的,但是会出现警告“***is deprecated :first ...