windows游戏大师编程技巧之以硬拷贝方式剪切位图
下面是完整的1920*1080 32位色深的实现
#include <Windows.h>
#include <ddraw.h>
#pragma comment(lib, "ddraw.lib")
#pragma comment(lib, "dxguid.lib")
#define SCREEN_WIDTH 1920
#define SCREEN_HEIGHT 1080
#define SCREEN_BPP 32
#define KEYDOWN(vk_code) (GetAsyncKeyState(vk_code)&0x8000 ? 1 : 0)
#define KEYUP(vk_code) (GetAsyncKeyState(vk_code)&0x8000 ? 0 : 1)
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);
void Blit_Clipped(int x, int y, int width, int height, LONG* bitmap, LONG* video_buffer, LONG lpitch);
HWND main_hwnd = nullptr;
LPDIRECTDRAW7 lpdd7 = nullptr;
LPDIRECTDRAWSURFACE7 lpddsprimary = nullptr;
LPDIRECTDRAWSURFACE7 lpddsback = nullptr;
DDSURFACEDESC2 ddsd;
int window_closed = 0;
LONG bitmap[64] = {
RGB(0,0,0), RGB(0,0,0), RGB(0,0,0), RGB(0,0,0), RGB(0,0,0), RGB(0,0,0), RGB(0,0,0), RGB(0,0,0),
RGB(0,0,0), RGB(0,0,0), RGB(0,255,0), RGB(0,255,0), RGB(0,255,0), RGB(0,255,0), RGB(0,0,0), RGB(0,0,0),
RGB(0,0,0), RGB(0,255,0), RGB(0,0,0), RGB(0,255,0), RGB(0,255,0), RGB(0,0,0), RGB(0,255,0), RGB(0,0,0),
RGB(0,0,0), RGB(0,255,0), RGB(0,255,0), RGB(0,255,0), RGB(0,255,0), RGB(0,255,0), RGB(0,255,0), RGB(0,0,0),
RGB(0,0,0), RGB(0,255,0), RGB(0,0,0), RGB(0,255,0), RGB(0,255,0), RGB(0,0,0), RGB(0,255,0), RGB(0,0,0),
RGB(0,0,0), RGB(0,0,0), RGB(0,255,0), RGB(0,255,0), RGB(0,255,0), RGB(0,255,0), RGB(0,0,0), RGB(0,0,0),
RGB(0,0,0), RGB(0,0,0), RGB(0,0,0), RGB(0,0,0), RGB(0,0,0), RGB(0,0,0), RGB(0,0,0), RGB(0,0,0)
};
struct face {
int x;
int y;
int xv;
int yv;
};
face happy_faces[100];
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow)
{
TCHAR szAppName[] = TEXT("DxDemo");
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | 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;
}
main_hwnd = CreateWindow(
szAppName, TEXT("DxDemo1"), WS_POPUP | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, SCREEN_WIDTH, SCREEN_HEIGHT,
nullptr, nullptr, hInstance, nullptr
);
Game_Init();
while (true)
{
if (PeekMessage(&msg, NULL, 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;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
//draw
EndPaint(hwnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
int Game_Init(void* params, int num_params)
{
//创建ddraw对象
if (FAILED(DirectDrawCreateEx(NULL, (LPVOID*)&lpdd7, IID_IDirectDraw7, NULL)))
return 0;
//设置协助等级:全屏模式
if (FAILED(lpdd7->SetCooperativeLevel(main_hwnd, DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT)))
return 0;
//设置显示模式
if (FAILED(lpdd7->SetDisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, 0, 0)))
return 0;
//clear ddsd and set size
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.dwBackBufferCount = 1;
//request primary surface
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
//create the primary surface
if (FAILED(lpdd7->CreateSurface(&ddsd, &lpddsprimary, NULL)))
return 0;
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
if (FAILED(lpddsprimary->GetAttachedSurface(&ddsd.ddsCaps, &lpddsback)))
return 0;
//init happy_faces
for (int i = 0; i < 100; i++)
{
happy_faces[i].x = rand() % SCREEN_WIDTH;
happy_faces[i].y = rand() % SCREEN_HEIGHT;
happy_faces[i].xv = 10;
happy_faces[i].yv = 10;
}
return 1;
}
int Game_Main(void* param, int num_params)
{
DDBLTFX ddbltfx;
if (window_closed)
return 0;
if (KEYDOWN(VK_ESCAPE))
{
SendMessage(main_hwnd, WM_CLOSE, 0, 0);
window_closed = 1;
}
//clear ddbltfx and set size
memset(&ddbltfx, 0, sizeof(ddbltfx));
ddbltfx.dwSize = sizeof(ddbltfx);
ddbltfx.dwFillColor = RGB(0, 0, 0);
if (FAILED(lpddsback->Blt(nullptr, nullptr, nullptr, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx)))
return 0;
//clear ddsd and set size
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
if (FAILED(lpddsback->Lock(nullptr, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, nullptr)))
return 0;
LONG* back_buffer = (LONG *)ddsd.lpSurface;
for (int i = 0; i < 100; i++)
Blit_Clipped(happy_faces[i].x, happy_faces[i].y, 8, 8, bitmap, back_buffer, ddsd.lPitch>>2);
for (int i = 0; i < 100; i++)
{
happy_faces[i].x += happy_faces[i].xv;
happy_faces[i].y += happy_faces[i].yv;
if (happy_faces[i].x > SCREEN_WIDTH)
happy_faces[i].x = -8;
else if (happy_faces[i].x < 0)
happy_faces[i].x = SCREEN_WIDTH - 1;
if (happy_faces[i].y > SCREEN_HEIGHT)
happy_faces[i].y = -8;
else if (happy_faces[i].y < 0)
happy_faces[i].y = SCREEN_HEIGHT - 1;
}
//clear the back buffer
/*if (ddsd.lPitch >> 2 == SCREEN_WIDTH)
memset(back_buffer, 0, SCREEN_WIDTH * SCREEN_HEIGHT * (SCREEN_BPP / 8));
else
{
for (int i = 0; i < SCREEN_HEIGHT; i++)
{
memset(back_buffer, 0, SCREEN_WIDTH * (SCREEN_BPP / 8));
back_buffer += ddsd.lPitch;
}
}
for (int i = 0; i < 5000; i++)
{
int x = rand() % SCREEN_WIDTH;
int y = rand() % SCREEN_HEIGHT;
back_buffer[x + y * (ddsd.lPitch >> 2)] = RGB(rand() % 256, rand() % 256, rand() % 256);
}*/
if (FAILED(lpddsback->Unlock(nullptr)))
return 0;
while (FAILED(lpddsprimary->Flip(nullptr, DDFLIP_WAIT)));
/*RECT source_rect, dest_rect;
source_rect.left = rand() % SCREEN_WIDTH;
source_rect.top = rand() % SCREEN_HEIGHT;
source_rect.right = rand() % SCREEN_WIDTH;
source_rect.bottom = rand() % SCREEN_HEIGHT;
dest_rect.left = rand() % SCREEN_WIDTH;
dest_rect.top = rand() % SCREEN_HEIGHT;
dest_rect.right = rand() % SCREEN_WIDTH;
dest_rect.bottom = rand() % SCREEN_HEIGHT;
if (FAILED(lpddsprimary->Blt(&dest_rect, lpddsback, &source_rect, DDBLT_WAIT, nullptr)))
return 0;*/
Sleep(30);
//if (FAILED(lpddsprimary->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL)))
// return 0;
//int mempitch = ddsd.lPitch;//32位色深1920个像素所占的字节数
//LONG* video_buffer = (LONG *)ddsd.lpSurface;
//for (int i = 0; i < 1000; i++)
//{
// int x = rand() % SCREEN_WIDTH;
// int y = rand() % SCREEN_HEIGHT;
// video_buffer[x + (y * mempitch >> 2)] = RGB(rand() % 256, rand() % 256, rand() % 256);
//}
//if (FAILED(lpddsprimary->Unlock(NULL)))
// return 0;
//Sleep(30);
return 1;
}
int Game_Shutdown(void* params, int num_params)
{
if (lpddsback)
{
lpddsback->Release();
lpddsback = nullptr;
}
if (lpddsprimary)
{
lpddsprimary->Release();
lpddsprimary = nullptr;
}
if (lpdd7)
{
lpdd7->Release();
lpdd7 = nullptr;
}
return 1;
}
void Blit_Clipped(int x, int y, int width, int height, LONG* bitmap, LONG* video_buffer, LONG lpitch)
{
int xStart = x, yStart = y;
int xEnd = xStart + width - 1, yEnd = yStart + height - 1;
if (xStart < 0)
xStart = 0;
if (yStart < 0)
yStart = 0;
if (xEnd > SCREEN_WIDTH)
xEnd = SCREEN_WIDTH - 1;
if (yEnd > SCREEN_HEIGHT)
yEnd = SCREEN_HEIGHT - 1;
int x_off = xStart - x;
int y_off = yStart - y;
int dx = xEnd - xStart;
int dy = yEnd - yStart;
//init video_buffer and bitmap
video_buffer += xStart + yStart * lpitch;
bitmap += x_off + y_off * width;
LONG pixel;
for (int index_y=0; index_y < dy; index_y++)
{
for (int index_x = 0; index_x < dx; index_x++)
{
if (pixel = bitmap[index_x])
video_buffer[index_x] = pixel;
}
video_buffer += lpitch;
bitmap += width;
}
}
下面是效果