# 2d图形旋转

4 篇文章 0 订阅

### 2d图形旋转

1.这里旋转使用数学公式:
xr = x * cos(theta) - y * sin(theta);
yr = x * sin(theta) + y * cos(theta);
2.如果以左上角为原点(0,0)，x方向向右增加,y方向向下增加的话，对于原图形旋转的100度并不等于连续20次的旋转5度的结果，可以举例对比一下。
3.memcpy对于复制对象真的很好用。
4.在这里我重画背景使用的是gdi的FillRect:
HDC hdc;
lpddsprimary->GetDC(&hdc);
FillRect(hdc, &client, (HBRUSH)GetStockObject(WHITE_BRUSH));
lpddsprimary->ReleaseDC(hdc);

#include <Windows.h>
#include <ddraw.h>
#include <math.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

typedef struct VERTEX2DI_TYP
{
int x, y;
}VERTEX2DI, * VERTEX2DI_PTR;

typedef struct POLYGON2D_TYP
{
int state;
int num_verts;
int x0, y0;
int xv, yv;
LONG color;
VERTEX2DI* vlist;
} POLYGON2D, * POLYGON2D_PTR;

HWND main_hwnd = nullptr;
RECT client;
LPDIRECTDRAW7 lpdd7 = nullptr;
LPDIRECTDRAWSURFACE7 lpddsprimary = nullptr;
LPDIRECTDRAWCLIPPER lpddclipper = nullptr;
DDSURFACEDESC2 ddsd;
int pixel;
int window_close = 0;
POLYGON2D triangles[4];
float cos_look[360];
float sin_look[360];
int theta = -5;	//旋转度数

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 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);
int Draw_Clip_Line(int x1, int y1, int x2, int y2, LONG color, LONG* vb_start, int iPitch);
int Draw_Polygon2D(POLYGON2D_PTR poly, LONG* vb_strat, int iPitch);
int Rotate_Polygon2D(POLYGON2D_PTR poly, int theta);

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.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
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};

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
return 0;
case WM_SIZE:
//change size
theta = -5;
return 0;
case WM_MOVE:
//move
theta = -5;
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;

//init triangles
for (int i = 0; i < 4; i++)
{
triangles[i].state = 1;
triangles[i].num_verts = 4;
RECT rect = { 300 + i * 50, 300 + i * 50, 300 + i * 50 + 50, 300 + i * 50 + 50 };
triangles[i].x0 = (rect.left + rect.right) / 2;
triangles[i].y0 = (rect.top + rect.bottom) / 2;
triangles[i].xv = triangles[i].yv = 10;
triangles[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
triangles[i].vlist = new VERTEX2DI[triangles[i].num_verts];
triangles[i].vlist[0] = { rect.left, rect.top };
triangles[i].vlist[1] = { rect.right, rect.top };
triangles[i].vlist[2] = { rect.right, rect.bottom };
triangles[i].vlist[3] = { rect.left, rect.bottom };
}

//generate the tables
for (int ang = 0; ang < 360; ang++)
{
float theta = (float)ang * 3.14159 / 180;
sin_look[ang] = sin(theta);
cos_look[ang] = cos(theta);
}

return 1;
}

int Game_Main(void* params, int num_params)
{
DDBLTFX ddbltfx;

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);

if (theta == -5)	//界面初始化为白色
{
HDC hdc;
lpddsprimary->GetDC(&hdc);
FillRect(hdc, &client, (HBRUSH)GetStockObject(WHITE_BRUSH));
lpddsprimary->ReleaseDC(hdc);
}

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)
{
if (theta < 355)
{
theta += 5;
if (theta == 360)
{
int x = 0;
}
//init temp_triangles
POLYGON2D temp_triangles[4];
memcpy(temp_triangles, triangles, sizeof(triangles));
for (int i = 0; i < 4; i++)
{
temp_triangles[i].vlist = new VERTEX2DI[temp_triangles[i].num_verts];
memcpy(temp_triangles[i].vlist, triangles[i].vlist, temp_triangles[i].num_verts * sizeof(VERTEX2DI));
}

for (int i = 0; i < 4; i++)
{
Rotate_Polygon2D(temp_triangles + i, theta);
Draw_Polygon2D(temp_triangles + i, video_buffer, ipitch >> 2);
}

//destroy temp_triangles.vlist
for (int i = 0; i < 4; i++)
delete[] temp_triangles[i].vlist;
}
}

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;
}

//destroy triangles
for (int i = 0; i < 4; i++)
delete[] triangles[i].vlist;

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 = client.left;
int min_clip_y = client.top;
int max_clip_x = client.right;
int max_clip_y = client.bottom;

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;

int iSpStatus1 = GetInterSectionPoint(p1_code, xc1, yc1, x1, y1, x2, y2, min_clip_x, min_clip_y, max_clip_x, max_clip_y);
int iSpStatus2 = GetInterSectionPoint(p2_code, xc2, yc2, x1, y1, x2, y2, min_clip_x, min_clip_y, max_clip_x, max_clip_y);

if (!(iSpStatus1 | iSpStatus2))
return  0;

x1 = xc1;
y1 = yc1;
x2 = xc2;
y2 = yc2;

return 1;
}

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);
break;
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;
}

int Draw_Clip_Line(int x1, int y1, int x2, int y2, LONG color, LONG* vb_start, int iPitch)
{
int iDcStatus = Clip_Line(x1, y1, x2, y2);
if (!iDcStatus)
return 0;
Draw_Line(x1, y1, x2, y2, color, vb_start, iPitch);
return 1;
}

int Draw_Polygon2D(POLYGON2D_PTR poly, LONG* vb_strat, int iPitch)
{
if (poly->state)
{
for (int i = 0; i < poly->num_verts - 1; i++)
{
Draw_Clip_Line(poly->vlist[i].x, poly->vlist[i].y, poly->vlist[i + 1].x, poly->vlist[i + 1].y, poly->color, vb_strat, iPitch);
}
Draw_Clip_Line(poly->vlist[poly->num_verts - 1].x, poly->vlist[poly->num_verts - 1].y, poly->vlist[0].x, poly->vlist[0].y, poly->color, vb_strat, iPitch);
return 1;
}
return 0;
}

int Rotate_Polygon2D(POLYGON2D_PTR poly, int theta)
{
if (!poly)
return 0;
for (int curr_vert = 0; curr_vert < poly->num_verts; curr_vert++)
{
float xr = poly->vlist[curr_vert].x * cos_look[theta] - poly->vlist[curr_vert].y * sin_look[theta];
float yr = poly->vlist[curr_vert].x * sin_look[theta] + poly->vlist[curr_vert].y * cos_look[theta];
poly->vlist[curr_vert].x = xr;
poly->vlist[curr_vert].y = yr;
}
return 1;
}


• 0
点赞
• 0
收藏
觉得还不错? 一键收藏
• 0
评论
04-29
05-05
10-02 1500
07-18 819
08-05 5943
12-01
07-24
10-14
04-15 1248

### “相关推荐”对你有帮助么？

• 非常没帮助
• 没帮助
• 一般
• 有帮助
• 非常有帮助

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、付费专栏及课程。