在这里有一个重要的获取坐标的区别GetClientRect(main_hwnd, &client)是获取显示客户端坐标,这个是相对坐标;
GetWindowRect(main_hwnd, &client)是获取相对于window窗口的坐标;
以下是1920*1080下的实现:
#include <Windows.h>
#include <ddraw.h>
#pragma comment(lib, "ddraw.lib")
#pragma comment(lib, "dxguid.lib")
#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480
#define SCREEN_BPP 32
#define SCREEN_WIDTH 1920
#define SCREEN_HEIGHT 1080
#define KEY_DOWN(vk_code) (GetAsyncKeyState(vk_code) & 0x8000 ? 1 : 0)
#define KEY_UP(vk_code) (GetAsyncKeyState(vk_code) & 0x8000 ? 0 : 1)
#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
HWND main_hwnd = nullptr;
RECT client;
LPDIRECTDRAW7 lpdd7 = nullptr;
LPDIRECTDRAWSURFACE7 lpddsprimary = nullptr;
LPDIRECTDRAWCLIPPER lpddclipper = nullptr;
DDSURFACEDESC2 ddsd;
int pixel;
int window_close = 0;
int Game_Init(void* params = nullptr, int num_params = 0);
int Game_Main(void* params = nullptr, int num_params = 0);
int Game_Shutdown(void* params = nullptr, int num_params = 0);
int Draw_Line(int x1, int y1, int x2, int y2, LONG color, LONG* vb_start, int iPitch);
int Clip_Line(int& x1, int& y1, int& x2, int& y2, int min_clip_x, int min_clip_y, int max_clip_x, int max_clip_y);
int GetInterSectionPoint(int p_code, int& xc, int& yc, int x1, int y1, int x2, int y2, int min_clip_x, int min_clip_y, int max_clip_x, int max_clip_y);
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
TCHAR szAppName[] = TEXT("normal window");
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_VREDRAW | CS_HREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(nullptr, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = nullptr;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(nullptr, TEXT("Register Class Failed"), szAppName, MB_ICONERROR);
return 0;
}
client = {0, 0, WINDOW_WIDTH-1, WINDOW_HEIGHT-1};
AdjustWindowRect(&client, WS_OVERLAPPEDWINDOW, false);
main_hwnd = CreateWindow(
szAppName, TEXT("normal_window"), WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, client.right - client.left, client.bottom - client.top,
nullptr, nullptr, hInstance, nullptr
);
Game_Init();
while (true)
{
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Game_Main();
}
Game_Shutdown();
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
int xPos;
int yPos;
switch (message)
{
case WM_CREATE:
//create
//GetClientRect(main_hwnd, &client);
GetWindowRect(main_hwnd, &client);
return 0;
case WM_SIZE:
//change size
//GetClientRect(main_hwnd, &client);
GetWindowRect(main_hwnd, &client);
return 0;
case WM_MOVE:
//move
//GetClientRect(main_hwnd, &client);
GetWindowRect(main_hwnd, &client);
return 0;
case WM_LBUTTONDOWN:
xPos = LOWORD(lParam);
yPos = HIWORD(lParam);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
//draw
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
window_close = 1;
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
int Game_Init(void* params, int num_params)
{
if (FAILED(DirectDrawCreateEx(nullptr, (LPVOID*)&lpdd7, IID_IDirectDraw7, nullptr)))
return 0;
lpdd7->SetCooperativeLevel(main_hwnd, DDSCL_NORMAL);
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
if (FAILED(lpdd7->CreateSurface(&ddsd, &lpddsprimary, nullptr)))
return 0;
//获取像素格式
DDPIXELFORMAT ddpixelformat;
memset(&ddpixelformat, 0, sizeof(ddpixelformat));
ddpixelformat.dwSize = sizeof(ddpixelformat);
lpddsprimary->GetPixelFormat(&ddpixelformat);
pixel = ddpixelformat.dwRGBBitCount;
if (FAILED(lpdd7->CreateClipper(0, &lpddclipper, nullptr)))
return 0;
if (FAILED(lpddclipper->SetHWnd(0, main_hwnd)))
return 0;
if (FAILED(lpddsprimary->SetClipper(lpddclipper)))
return 0;
return 1;
}
int Game_Main(void* params, int num_params)
{
if (KEY_DOWN(VK_ESCAPE))
{
window_close = 1;
SendMessage(main_hwnd, WM_CLOSE, 0, 0);
return 0;
}
if (window_close)
return 0;
//GetClientRect(main_hwnd, &client);
GetWindowRect(main_hwnd, &client);
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
if (FAILED(lpddsprimary->Lock(nullptr, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, nullptr)))
return 0;
LONG* video_buffer = (LONG*)ddsd.lpSurface;
int ipitch = ddsd.lPitch;
if (pixel == 32)
{
/*for (int i = 0; i < 10; i++)
{
int x = client.left + rand() % (client.right - client.left);
int y = client.top + rand() % (client.bottom - client.top);
video_buffer[x + y * (ipitch >> 2)] = RGB(rand() % 256, rand() % 256, rand() % 256);
}*/
int p1_x = 0, p1_y = 0;
int p2_x = SCREEN_WIDTH - 1, p2_y = SCREEN_HEIGHT - 1;
int isp1_x = p1_x, isp1_y = p1_y;
int isp2_x = p2_x, isp2_y = p2_y;
Clip_Line(isp1_x, isp1_y, isp2_x, isp2_y, client.left, client.top, client.right, client.bottom);
LONG color = RGB(rand() % 256, rand() % 256, rand() % 256);
Draw_Line(isp1_x, isp1_y, isp2_x, isp2_y, color, video_buffer, ipitch >> 2);
}
if (FAILED(lpddsprimary->Unlock(nullptr)))
return 0;
//Sleep(10000);
return 1;
}
int Game_Shutdown(void* params, int num_params)
{
if (lpddsprimary)
{
lpddsprimary->Release();
lpddsprimary = nullptr;
}
if (lpddclipper)
{
lpddclipper->Release();
lpddclipper = nullptr;
}
if (lpdd7)
{
lpdd7->Release();
lpdd7 = nullptr;
}
return 1;
}
int Draw_Line(int x1, int y1, int x2, int y2, LONG color, LONG* vb_start, int iPitch)
{
int dx = x2 - x1;
int dy = y2 - y1;
int inx, iny, dx2, dy2, error;
if (dx >= 0)
inx = 1;
else
{
inx = -1;
dx = -dx;
}
if (dy >= 0)
iny = iPitch;
else
{
iny = -iPitch;
dy = -dy;
}
dx2 = dx << 1;
dy2 = dy << 1;
vb_start += x1 + y1 * iPitch;
if (dx > dy)
{
error = dy2 - dx;
for (int i = 0; i <= dx; i++)
{
*vb_start = color;
if (error >= 0)
{
error -= dx2;
vb_start += iny;
}
error += dy2;
vb_start += inx;
}
}
else
{
error = dx2 - dy;
for (int i = 0; i <= dy; i++)
{
*vb_start = color;
if (error >= 0)
{
error -= dy2;
vb_start += inx;
}
error += dx2;
vb_start += iny;
}
}
return 1;
}
int Clip_Line(int& x1, int& y1, int& x2, int& y2, int min_clip_x, int min_clip_y, int max_clip_x, int max_clip_y)
{
int xc1 = x1, yc1 = y1, xc2 = x2, yc2 = y2;
int p1_code = 0, p2_code = 0;
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 (y2 < min_clip_y)
p2_code |= CLIP_CODE_N;
else if (y2 > max_clip_y)
p2_code |= CLIP_CODE_S;
if (x2 < min_clip_x)
p2_code |= CLIP_CODE_W;
else if (x2 > max_clip_x)
p2_code |= CLIP_CODE_E;
if (p1_code & p2_code)
return 0;
if (p1_code == 0 && p2_code == 0)
return 1;
GetInterSectionPoint(p1_code, xc1, yc1, x1, y1, x2, y2, min_clip_x, min_clip_y, max_clip_x, max_clip_y);
GetInterSectionPoint(p2_code, xc2, yc2, x1, y1, x2, y2, min_clip_x, min_clip_y, max_clip_x, max_clip_y);
x1 = xc1;
y1 = yc1;
x2 = xc2;
y2 = yc2;
}
int GetInterSectionPoint(int p_code, int& xc, int& yc, int x1, int y1, int x2, int y2, int min_clip_x, int min_clip_y, int max_clip_x, int max_clip_y)
{
switch (p_code)
{
case CLIP_CODE_N:
yc = min_clip_y;
xc = x1 + (min_clip_y - y1) * (x2 - x1) / (y2 - y1);
break;
case CLIP_CODE_S:
yc = max_clip_y;
xc = x1 + (max_clip_y - y1) * (x2 - x1) / (y2 - y1);
case CLIP_CODE_W:
xc = min_clip_x;
yc = y1 + (min_clip_x - x1) * (y2 - y1) / (x2 - x1);
break;
case CLIP_CODE_E:
xc = max_clip_x;
yc = y1 + (max_clip_x - x1) * (y2 - y1) / (x2 - x1);
break;
case CLIP_CODE_NW:
yc = min_clip_y;
xc = x1 + (min_clip_y - y1) * (x2 - x1) / (y2 - y1);
if (xc < min_clip_x)
{
xc = min_clip_x;
yc = y1 + (min_clip_x - x1) * (y2 - y1) / (x2 - x1);
}
break;
case CLIP_CODE_SW:
yc = max_clip_y;
xc = x1 + (max_clip_y - y1) * (x2 - x1) / (y2 - y1);
if (xc < min_clip_x)
{
xc = min_clip_x;
yc = y1 + (min_clip_x - x1) * (y2 - y1) / (x2 - x1);
}
break;
case CLIP_CODE_NE:
yc = min_clip_y;
xc = x1 + (min_clip_y - y1) * (x2 - x1) / (y2 - y1);
if (xc > max_clip_x)
{
xc = max_clip_x;
yc = y1 + (max_clip_x - x1) * (y2 - y1) / (x2 - x1);
}
break;
case CLIP_CODE_SE:
yc = max_clip_y;
xc = x1 + (max_clip_y - y1) * (x2 - x1) / (y2 - y1);
if (xc > max_clip_x)
{
xc = max_clip_x;
yc = y1 + (max_clip_x - x1) * (y2 - y1) / (x2 - x1);
}
break;
}
if (xc < min_clip_x || xc > max_clip_x || yc < min_clip_y || yc > max_clip_y)
return 0;
return 1;
}