2d图形旋转

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);
该程序以左上角(0,0)为原点,支持移动、改变窗口大小重画360°图形。

#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.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
		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
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值