在上節完成了數學庫後,這節先寫出所需要的基本窗口結構。
win32的窗口很好建立,系統會自己生成代碼,然後我們再對代碼進行些許修改。
全局變量:
const int SCREEN_WIDTH = Screen::Width;
const int SCREEN_HEIGHT = Screen::Height;
//屏幕寬度和高度
const int BITS = 32; //每個像素的位數
HDC screen_hdc;
HWND screen_hwnd;
HDC hCompatibleDC; //兼容HDC
HBITMAP hCompatibleBitmap; //兼容BITMAP
BITMAPINFO binfo; //BITMAPINFO結構體
HINSTANCE ghInstance;
在原有基礎上添加了幾個方法:
void Display();
void SrcInit();
HWND Start(HINSTANCE hInstance, int nShowCmd, string wcName, string title);
void Update(HWND hwnd);
void Destroy(string wcName, HINSTANCE hInstance);
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lParam);
主函數:
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
{
//1.創建窗口
string windowClassName = "MyWindow";
string title = "3DRender";
HWND hwnd = Start(hInstance, nShowCmd, windowClassName, title);
//時間初始化
DWORD curTime = GetTickCount();
DWORD preTime = GetTickCount();
//2.消息循環
MSG msg = { 0 };
SrcInit();
while (msg.message != WM_QUIT)
{
//獲取消息
if (PeekMessage(&msg, 0, NULL, NULL, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
curTime = GetTickCount();
if (curTime - preTime > 30)
{
preTime = curTime;
Update(hwnd);
}
}
}
//3.遊戲結束
Destroy(windowClassName, hInstance);
return 0;
}
事件回調
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_KEYDOWN:
{
}
break;
default:
return DefWindowProc(hwnd, message, wparam, lParam);
}
return 0;
}
HWND Start(HINSTANCE hInstance, int nShowCmd, string wcName, string title)
{
ghInstance = hInstance;
//1.創建窗口類
WNDCLASSEX wndClass = {};
wndClass.cbSize = sizeof(WNDCLASSEX);
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = wcName.c_str();
//2.註冊窗口類
assert(RegisterClassEx(&wndClass));
//3.創建窗口
HWND hwnd = CreateWindow(wcName.c_str(), title.c_str(), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, hInstance, NULL);
//4.調整大小,移動,顯示,更新
if (!hwnd)
{
return FALSE;
}
RECT rectProgram, rectClient;
GetWindowRect(hwnd, &rectProgram); //獲得程序窗口位於屏幕座標
GetClientRect(hwnd, &rectClient); //獲得客戶區座標
//非客戶區寬,高
int nWidth = rectProgram.right - rectProgram.left - (rectClient.right - rectClient.left);
int nHeiht = rectProgram.bottom - rectProgram.top - (rectClient.bottom - rectClient.top);
nWidth += SCREEN_WIDTH;
nHeiht += SCREEN_HEIGHT;
rectProgram.right = nWidth;
rectProgram.bottom = nHeiht;
int showToScreenx = GetSystemMetrics(SM_CXSCREEN) / 2 - nWidth / 2; //居中處理
int showToScreeny = GetSystemMetrics(SM_CYSCREEN) / 2 - nHeiht / 2;
MoveWindow(hwnd, showToScreenx, showToScreeny, rectProgram.right, rectProgram.bottom, false);
memset(&binfo, 0, sizeof(BITMAPINFO));
binfo.bmiHeader.biBitCount = BITS; //每個像素多少位,也可直接寫24(RGB)或者32(RGBA)
binfo.bmiHeader.biCompression = BI_RGB;
binfo.bmiHeader.biHeight = -SCREEN_HEIGHT;
binfo.bmiHeader.biPlanes = 1;
binfo.bmiHeader.biSizeImage = 0;
binfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
binfo.bmiHeader.biWidth = SCREEN_WIDTH;
//獲取屏幕HDC
screen_hwnd = hwnd;
screen_hdc = GetDC(screen_hwnd);
//獲取兼容HDC和兼容Bitmap,兼容Bitmap選入兼容HDC(每個HDC內存每時刻僅能選入一個GDI資源,GDI資源要選入HDC才能進行繪製)
hCompatibleDC = CreateCompatibleDC(screen_hdc);
hCompatibleBitmap = CreateCompatibleBitmap(screen_hdc, SCREEN_WIDTH, SCREEN_HEIGHT);
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hCompatibleDC, hCompatibleBitmap);
ShowWindow(hwnd, nShowCmd);
UpdateWindow(hwnd);
return hwnd;
}
void SrcInit()
{
//資源加載
}
void Update(HWND hwnd)
{
//渲染更新
Display();
}
void Display()
{
////將顏色數據打印到屏幕上,這下面兩個函數每幀都得調用
SetDIBits(screen_hdc, hCompatibleBitmap, 0, SCREEN_HEIGHT, Buffer, (BITMAPINFO*)&binfo, DIB_RGB_COLORS);
BitBlt(screen_hdc, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, hCompatibleDC, 0, 0, SRCCOPY);
}
void Destroy(string wcName, HINSTANCE hInstance)
{
//5.註銷窗口類
UnregisterClass(wcName.c_str(), hInstance);
}
然後會看到: