#define _USE_MATH_DEFINES
#define NOMINMAX
#include <windows.h>
#include <gl/GL.h>
#include <gl/GLU.h>
#include <gdiplus.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <string>
#include <sstream>
#include <iomanip>
#include <algorithm>
#include <unordered_set>
#include <queue>
#include <tuple>
#include <limits>
#include <psapi.h>
#include <tchar.h>
#include <locale>
#pragma comment(lib, "psapi.lib")
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "gdiplus.lib")
using namespace std;
// ===================== 常量定义 =====================
#define SCREEN_W 1280
#define SCREEN_H 720
#define BLOCK_SIZE 30
#define WORLD_D 32
#define PLAYER_HP_MAX 100
#define INVENTORY_SLOT 5
#define BACKPACK_SLOT 10
#define FALL_DAMAGE_HEIGHT 3.0f
#define DRAW_DISTANCE_MIN 20.0f
#define DRAW_DISTANCE_MAX 100.0f
#define DRAW_DISTANCE_STEP 10.0f
#define DRAW_DISTANCE_DEFAULT 50.0f
#define NEAR_PLANE 0.1f
#define FAR_PLANE 200.0f
#define CHUNK_SIZE 16
#define TARGET_FPS 60
#define FRAME_TIME (1000 / TARGET_FPS)
#define MAX_MEMORY_MB 500
#define MEMORY_POOL_SIZE (MAX_MEMORY_MB * 1024 * 1024)
// 方块ID定义
#define BLOCK_AIR 1000
#define BLOCK_GRASS 1001
#define BLOCK_DIRT 1002
#define BLOCK_STONE 1003
#define BLOCK_LOG 2101
#define BLOCK_LEAF 2201
#define BLOCK_PLANK 2301
#define BLOCK_WORKBENCH 3001
const float FOV_MIN = 50.0f;
const float FOV_MAX = 140.0f;
const float FOV_STEP = 5.0f;
// ===================== 数据结构 =====================
struct Block {
int id;
Block() : id(BLOCK_AIR) {}
Block(int i) : id(i) {}
bool isSolid() const { return id != BLOCK_AIR; }
bool isTransparent() const { return id == BLOCK_LEAF; }
};
// ===================== 全局变量 =====================
int WORLD_W = 1024;
int WORLD_H = 1024;
std::vector<std::vector<std::vector<Block>>> world;
GLuint blockTextures[4000] = { 0 };
int textureCount = 0;
struct Color {
float r, g, b;
Color(float r = 0, float g = 0, float b = 0) : r(r / 255.0f), g(g / 255.0f), b(b / 255.0f) {}
};
// 修复:问题5 - 草方块绿色,树叶改为金合欢树叶黄褐色(RGB:191,168,106)
Color blockColorFallback[] = {
Color(0,0,0),
Color(34, 139, 34), // 草方块:森林绿
Color(153,102,51),
Color(136,136,136),
Color(153,102,0),
Color(191, 168, 106),// 树叶:金合欢树叶色
Color(204,153,102),
Color(153,85,34)
};
std::string blockName[] = {
"空气", "草方块", "泥土", "石头", "原木", "树叶", "木板", "工作台"
};
// ===================== 3D向量结构 =====================
struct Vector3 {
float x, y, z;
Vector3(float _x = 0, float _y = 0, float _z = 0) : x(_x), y(_y), z(_z) {}
Vector3 operator+(const Vector3& v) const { return Vector3(x + v.x, y + v.y, z + v.z); }
Vector3 operator-(const Vector3& v) const { return Vector3(x - v.x, y - v.y, z - v.z); }
Vector3 operator*(float f) const { return Vector3(x * f, y * f, z * f); }
Vector3 operator/(float f) const { return Vector3(x / f, y / f, z / f); }
Vector3& operator+=(const Vector3& v) {
x += v.x;
y += v.y;
z += v.z;
return *this;
}
Vector3& operator-=(const Vector3& v) {
x -= v.x;
y -= v.y;
z -= v.z;
return *this;
}
float length() const { return sqrt(x * x + y * y + z * z); }
Vector3 normalize() const {
float l = length();
return l > 0.0001f ? (*this) / l : Vector3(0, 0, 1);
}
float dot(const Vector3& v) const { return x * v.x + y * v.y + z * v.z; }
Vector3 cross(const Vector3& v) const {
return Vector3(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x);
}
};
// 物品槽结构
struct Slot {
int item;
int count;
Slot() : item(BLOCK_AIR), count(0) {}
Slot(int i, int c) : item(i), count(c) {}
};
// 玩家结构
struct Player {
Vector3 pos;
Vector3 vel;
float rotX, rotY;
int hp;
Slot inv[INVENTORY_SLOT];
Slot bag[BACKPACK_SLOT];
int selectSlot;
int bagSelectSlot;
Player() {
pos = Vector3((float)(int)(WORLD_W / 2.0f), 20.0f, (float)(int)(WORLD_H / 2.0f));
vel = Vector3(0, 0, 0);
rotX = rotY = 0;
hp = PLAYER_HP_MAX;
selectSlot = 0;
bagSelectSlot = 0;
inv[0] = Slot(BLOCK_GRASS, 64);
inv[1] = Slot(BLOCK_DIRT, 64);
inv[2] = Slot(BLOCK_STONE, 64);
}
Vector3 getForward() const {
return Vector3(
sin(rotY) * cos(rotX),
sin(rotX),
cos(rotY) * cos(rotX)
);
}
Vector3 getRight() const {
Vector3 forward = getForward();
Vector3 up(0, 1, 0);
return forward.cross(up).normalize();
}
};
// 区块结构
struct Chunk {
int x, z;
std::vector<std::tuple<int, int, int>> blocks;
bool isGenerated;
Chunk(int _x, int _z) : x(_x), z(_z), isGenerated(false) {}
void addBlock(int bx, int by, int bz) { blocks.push_back({ bx, by, bz }); }
};
// 世界边界检查
#define IN_WORLD_X(x) ((x) >= 0 && (x) < WORLD_W)
#define IN_WORLD_Y(y) ((y) >= 0 && (y) < WORLD_D)
#define IN_WORLD_Z(z) ((z) >= 0 && (z) < WORLD_H)
#define IN_WORLD(x,y,z) (IN_WORLD_X(x) && IN_WORLD_Y(y) && IN_WORLD_Z(z))
// ===================== 全局游戏变量 =====================
Player player;
std::vector<Chunk> chunks;
int g_numChunksX, g_numChunksZ;
bool isMenu = true;
bool isWorldGenMenu = false;
bool isGenerating = false;
bool isDead = false;
bool isBag = false, isCraft = false;
int menuSelect = 0;
int worldGenSelect = 1;
int selectedWorldSize = 1;
LARGE_INTEGER freq, lastTimeCounter;
bool needRedraw = true;
float drawDistance = DRAW_DISTANCE_DEFAULT;
bool isFirstPerson = true;
ULONGLONG fpsLastTime;
int fpsFrames = 0;
int currentFPS = 0;
bool cursorVisible = false;
float fov = 85.0f;
bool showDebug = true;
int hitX, hitY, hitZ;
bool hasHitBlock = false;
LPVOID g_MemoryPool = nullptr;
// 修复:问题4 - 文字渲染计数器,降低渲染频率(每2帧画一次)
int textRenderCounter = 0;
// Win32/OpenGL全局变量
HWND hWnd = NULL;
HDC hDC = NULL;
HGLRC hRC = NULL;
bool running = true;
HFONT hFont = NULL;
ULONG_PTR gdiplusToken = 0;
bool lastRButton = false, lastB = false, lastC = false, lastV = false;
bool lastMinus = false, lastEqual = false, lastLBracket = false, lastRBracket = false;
// ===================== 工具函数 =====================
std::string wstring_to_string(const std::wstring& wstr) {
if (wstr.empty()) return {};
int size = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.size(), NULL, 0, NULL, NULL);
std::string str(size, 0);
WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.size(), &str[0], size, NULL, NULL);
return str;
}
std::wstring string_to_wstring(const std::string& str) {
if (str.empty()) return {};
int size = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.size(), NULL, 0);
std::wstring wstr(size, 0);
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.size(), &wstr[0], size);
return wstr;
}
float GetCPUUsage() {
static ULONGLONG lastSysTime = 0, lastProcTime = 0;
FILETIME ftSysIdle, ftSysKernel, ftSysUser;
FILETIME ftProcCreation, ftProcExit, ftProcKernel, ftProcUser;
if (!GetSystemTimes(&ftSysIdle, &ftSysKernel, &ftSysUser) ||
!GetProcessTimes(GetCurrentProcess(), &ftProcCreation, &ftProcExit, &ftProcKernel, &ftProcUser)) {
return 0.0f;
}
ULONGLONG sysTime = ((((ULONGLONG)ftSysKernel.dwHighDateTime) << 32) | ftSysKernel.dwLowDateTime) +
((((ULONGLONG)ftSysUser.dwHighDateTime) << 32) | ftSysUser.dwLowDateTime);
ULONGLONG procTime = ((((ULONGLONG)ftProcKernel.dwHighDateTime) << 32) | ftProcKernel.dwLowDateTime) +
((((ULONGLONG)ftProcUser.dwHighDateTime) << 32) | ftProcUser.dwLowDateTime);
float cpuUsage = 0.0f;
if (lastSysTime && lastProcTime) {
ULONGLONG sysDiff = sysTime - lastSysTime;
ULONGLONG procDiff = procTime - lastProcTime;
if (sysDiff > 0) {
cpuUsage = (float)procDiff / sysDiff * 100.0f;
}
}
lastSysTime = sysTime;
lastProcTime = procTime;
return cpuUsage;
}
float GetProcessMemoryUsageMB() {
PROCESS_MEMORY_COUNTERS pmc;
if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
return (float)pmc.WorkingSetSize / (1024 * 1024);
return 0.0f;
}
void InitMemoryPool() {
g_MemoryPool = VirtualAlloc(NULL, MEMORY_POOL_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!g_MemoryPool) { MessageBox(NULL, L"内存池分配失败!", L"错误", MB_ICONERROR); exit(-1); }
}
double noise(int x, int y) {
int n = x + y * 57; n = (n << 13) ^ n;
return (1.0 - ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
}
double interNoise(double x, double y) {
int fx = (int)floor(x), fy = (int)floor(y);
double s = noise(fx, fy), t = noise(fx + 1, fy);
double u = noise(fx, fy + 1), v = noise(fx + 1, fy + 1);
double dx = x - fx, dy = y - fy;
double i1 = s + dx * (t - s), i2 = u + dx * (v - u);
return i1 + dy * (i2 - i1);
}
int getHeight(int x, int z) {
double h = interNoise(x / 10.0, z / 10.0) * 4 + interNoise(x / 20.0, z / 20.0) * 2 + 10;
return (int)h;
}
void generateChunk(Chunk& chunk) {
if (chunk.isGenerated) return;
int startX = chunk.x * CHUNK_SIZE;
int startZ = chunk.z * CHUNK_SIZE;
int endX = std::min(startX + CHUNK_SIZE, WORLD_W);
int endZ = std::min(startZ + CHUNK_SIZE, WORLD_H);
for (int x = startX; x < endX; x++) {
for (int z = startZ; z < endZ; z++) {
int h = getHeight(x, z);
for (int y = 0; y < WORLD_D; y++) {
if (y <= h) {
if (y == h) world[x][y][z] = Block(BLOCK_GRASS);
else if (y > h - 3) world[x][y][z] = Block(BLOCK_DIRT);
else world[x][y][z] = Block(BLOCK_STONE);
chunk.addBlock(x, y, z);
}
else world[x][y][z] = Block(BLOCK_AIR);
}
if (rand() % 100 == 0) {
int th = h;
if (th < WORLD_D - 7) {
for (int i = 0; i < 5; i++) {
world[x][th + i][z] = Block(BLOCK_LOG);
chunk.addBlock(x, th + i, z);
}
for (int dx = -2; dx <= 2; dx++)
for (int dz = -2; dz <= 2; dz++)
for (int dy = 0; dy < 3; dy++) {
int nx = x + dx, ny = th + 5 + dy, nz = z + dz;
if (IN_WORLD(nx, ny, nz) && !(abs(dx) == 2 && abs(dz) == 2 && dy == 2)) {
world[nx][ny][nz] = Block(BLOCK_LEAF);
chunk.addBlock(nx, ny, nz);
}
}
}
}
}
}
chunk.isGenerated = true;
}
// ===================== 世界生成 =====================
void initWorld() {
world.clear();
world.resize(WORLD_W);
for (int x = 0; x < WORLD_W; x++) {
world[x].resize(WORLD_D);
for (int y = 0; y < WORLD_D; y++) {
world[x][y].resize(WORLD_H, Block(BLOCK_AIR));
}
}
chunks.clear();
g_numChunksX = (WORLD_W + CHUNK_SIZE - 1) / CHUNK_SIZE;
g_numChunksZ = (WORLD_H + CHUNK_SIZE - 1) / CHUNK_SIZE;
for (int cx = 0; cx < g_numChunksX; cx++)
for (int cz = 0; cz < g_numChunksZ; cz++)
chunks.emplace_back(cx, cz);
int playerChunkX = (int)player.pos.x / CHUNK_SIZE;
int playerChunkZ = (int)player.pos.z / CHUNK_SIZE;
int loadRadius = (int)(drawDistance / CHUNK_SIZE) + 1;
for (int cx = playerChunkX - loadRadius; cx <= playerChunkX + loadRadius; cx++) {
for (int cz = playerChunkZ - loadRadius; cz <= playerChunkZ + loadRadius; cz++) {
if (cx >= 0 && cx < g_numChunksX && cz >= 0 && cz < g_numChunksZ) {
generateChunk(chunks[cx * g_numChunksZ + cz]);
}
}
}
}
// ===================== 射线检测 =====================
// 修复:问题1 - 射线检测floor取整,修复负数坐标穿透问题
bool raycastBlock(Vector3& hitPos, int& hx, int& hy, int& hz) {
Vector3 start = player.pos + Vector3(0, 1.7f, 0);
Vector3 dir = player.getForward().normalize();
float maxDist = drawDistance, step = 0.05f;
for (float t = 0; t < maxDist; t += step) {
Vector3 p = start + dir * t;
int x = (int)floor(p.x), y = (int)floor(p.y), z = (int)floor(p.z);
if (!IN_WORLD(x, y, z)) return false;
if (world[x][y][z].isSolid()) {
hitPos = p; hx = x; hy = y; hz = z;
return true;
}
}
return false;
}
// ===================== GDI+纹理加载 =====================
GLuint loadTexture(const wchar_t* filename) {
Gdiplus::Bitmap* bitmap = Gdiplus::Bitmap::FromFile(filename);
if (!bitmap || bitmap->GetLastStatus() != Gdiplus::Ok) {
delete bitmap;
return 0;
}
Gdiplus::Rect rect(0, 0, bitmap->GetWidth(), bitmap->GetHeight());
Gdiplus::BitmapData bitmapData;
bitmap->LockBits(&rect, Gdiplus::ImageLockModeRead, PixelFormat32bppARGB, &bitmapData);
GLuint texID;
glGenTextures(1, &texID);
glBindTexture(GL_TEXTURE_2D, texID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
unsigned char* pixels = (unsigned char*)bitmapData.Scan0;
int width = bitmap->GetWidth();
int height = bitmap->GetHeight();
unsigned char* rgbaPixels = new unsigned char[width * height * 4];
for (int i = 0; i < width * height; i++) {
rgbaPixels[i * 4 + 0] = pixels[i * 4 + 2];
rgbaPixels[i * 4 + 1] = pixels[i * 4 + 1];
rgbaPixels[i * 4 + 2] = pixels[i * 4 + 0];
rgbaPixels[i * 4 + 3] = pixels[i * 4 + 3];
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgbaPixels);
delete[] rgbaPixels;
bitmap->UnlockBits(&bitmapData);
delete bitmap;
return texID;
}
// 初始化方块纹理
void initBlockTextures() {
blockTextures[BLOCK_GRASS] = loadTexture(L"1001.png");
blockTextures[BLOCK_DIRT] = loadTexture(L"1002.png");
blockTextures[BLOCK_STONE] = loadTexture(L"1003.png");
blockTextures[BLOCK_LOG] = loadTexture(L"2101.png");
blockTextures[BLOCK_LEAF] = loadTexture(L"2201.png");
blockTextures[BLOCK_PLANK] = loadTexture(L"2301.png");
blockTextures[BLOCK_WORKBENCH] = loadTexture(L"3001.png");
}
// ===================== 文字绘制 =====================
// 修复:问题4 - 仅偶数帧渲染文字,降低频率消除闪烁
void drawText(float x, float y, const std::wstring& text, Gdiplus::Color color = Gdiplus::Color(255, 255, 255)) {
if (textRenderCounter % 2 != 0) return; // 每2帧渲染一次
if (!hDC || text.empty()) return;
Gdiplus::Graphics graphics(hDC);
graphics.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAliasGridFit);
graphics.SetSmoothingMode(Gdiplus::SmoothingModeNone);
Gdiplus::Font font(hDC, hFont);
Gdiplus::SolidBrush brush(color);
Gdiplus::PointF pos(x, y);
graphics.DrawString(text.c_str(), -1, &font, pos, &brush);
}
void drawText(float x, float y, const char* text, Gdiplus::Color color = Gdiplus::Color(255, 255, 255)) {
drawText(x, y, string_to_wstring(text), color);
}
void initFont() {
hFont = CreateFont(
24, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
GB2312_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
_T("微软雅黑")
);
if (hFont) {
SelectObject(hDC, hFont);
}
}
// 2D/3D切换
void begin2D() {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, SCREEN_W, 0, SCREEN_H);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
}
void end2D() {
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(fov, (float)SCREEN_W / SCREEN_H, NEAR_PLANE, FAR_PLANE);
glMatrixMode(GL_MODELVIEW);
}
// ===================== 方块绘制 =====================
void drawBlock(int x, int y, int z, int blockId) {
if (blockId == BLOCK_AIR) return;
bool faces[6] = {
z == 0 || !world[x][y][z - 1].isSolid(),
z == WORLD_H - 1 || !world[x][y][z + 1].isSolid(),
x == 0 || !world[x - 1][y][z].isSolid(),
x == WORLD_W - 1 || !world[x + 1][y][z].isSolid(),
y == 0 || !world[x][y - 1][z].isSolid(),
y == WORLD_D - 1 || !world[x][y + 1][z].isSolid()
};
// 修复:问题5 - 开启透明混合,修复树叶渲染
if (blockId == BLOCK_LEAF) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
glEnable(GL_TEXTURE_2D);
GLuint tex = blockTextures[blockId];
if (tex != 0) {
glBindTexture(GL_TEXTURE_2D, tex);
glColor3f(1,1,1);
}
else {
glDisable(GL_TEXTURE_2D);
int colorIdx = 0;
if (blockId == BLOCK_GRASS) colorIdx = 1;
else if (blockId == BLOCK_DIRT) colorIdx = 2;
else if (blockId == BLOCK_STONE) colorIdx = 3;
else if (blockId == BLOCK_LOG) colorIdx = 4;
else if (blockId == BLOCK_LEAF) colorIdx = 5;
else if (blockId == BLOCK_PLANK) colorIdx = 6;
else if (blockId == BLOCK_WORKBENCH) colorIdx = 7;
glColor3f(blockColorFallback[colorIdx].r, blockColorFallback[colorIdx].g, blockColorFallback[colorIdx].b);
}
glPushMatrix();
glTranslatef((GLfloat)x, (GLfloat)y, (GLfloat)z);
glBegin(GL_QUADS);
if (faces[0]) { glNormal3f(0, 0, -1); glTexCoord2f(0, 0); glVertex3f(-0.5, -0.5, -0.5); glTexCoord2f(1, 0); glVertex3f(0.5, -0.5, -0.5); glTexCoord2f(1, 1); glVertex3f(0.5, 0.5, -0.5); glTexCoord2f(0, 1); glVertex3f(-0.5, 0.5, -0.5); }
if (faces[1]) { glNormal3f(0, 0, 1); glTexCoord2f(0, 0); glVertex3f(-0.5, -0.5, 0.5); glTexCoord2f(1, 0); glVertex3f(0.5, -0.5, 0.5); glTexCoord2f(1, 1); glVertex3f(0.5, 0.5, 0.5); glTexCoord2f(0, 1); glVertex3f(-0.5, 0.5, 0.5); }
if (faces[2]) { glNormal3f(-1, 0, 0); glTexCoord2f(0, 0); glVertex3f(-0.5, -0.5, -0.5); glTexCoord2f(1, 0); glVertex3f(-0.5, -0.5, 0.5); glTexCoord2f(1, 1); glVertex3f(-0.5, 0.5, 0.5); glTexCoord2f(0, 1); glVertex3f(-0.5, 0.5, -0.5); }
if (faces[3]) { glNormal3f(1, 0, 0); glTexCoord2f(0, 0); glVertex3f(0.5, -0.5, -0.5); glTexCoord2f(1, 0); glVertex3f(0.5, -0.5, 0.5); glTexCoord2f(1, 1); glVertex3f(0.5, 0.5, 0.5); glTexCoord2f(0, 1); glVertex3f(0.5, 0.5, -0.5); }
if (faces[4]) { glNormal3f(0, -1, 0); glTexCoord2f(0, 0); glVertex3f(-0.5, -0.5, -0.5); glTexCoord2f(1, 0); glVertex3f(0.5, -0.5, -0.5); glTexCoord2f(1, 1); glVertex3f(0.5, -0.5, 0.5); glTexCoord2f(0, 1); glVertex3f(-0.5, -0.5, 0.5); }
if (faces[5]) { glNormal3f(0, 1, 0); glTexCoord2f(0, 0); glVertex3f(-0.5, 0.5, -0.5); glTexCoord2f(1, 0); glVertex3f(0.5, 0.5, -0.5); glTexCoord2f(1, 1); glVertex3f(0.5, 0.5, 0.5); glTexCoord2f(0, 1); glVertex3f(-0.5, 0.5, 0.5); }
glEnd();
glPopMatrix();
if (blockId == BLOCK_LEAF) glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
}
// ===================== UI绘制 =====================
// 修复:问题3 - 血量条居中,位于物品栏正上方,数值居中
void drawHP() {
begin2D();
const float barW = 300;
const float barH = 20;
// 屏幕下方正中间
float hpBarX = (SCREEN_W - barW) / 2.0f;
float hpBarY = SCREEN_H - 100; // 物品栏上方
// 背景
glColor3f(0.2f, 0.2f, 0.2f);
glRectf(hpBarX, hpBarY, hpBarX + barW, hpBarY + barH);
// 血条
glColor3f(1, 0, 0);
glRectf(hpBarX, hpBarY, hpBarX + barW * (float)player.hp / PLAYER_HP_MAX, hpBarY + barH);
// 血量数值居中绘制
char buf[50];
sprintf_s(buf, sizeof(buf), "%d/%d", player.hp, PLAYER_HP_MAX);
glColor3f(1, 1, 1);
float textX = hpBarX + (barW - 50) / 2.0f;
float textY = hpBarY + 2;
drawText(textX, textY, buf);
end2D();
}
void drawDebugInfo() {
begin2D();
float startX = SCREEN_W - 250;
float startY = 20;
float lineHeight = 25;
glColor4f(0.0f, 0.0f, 0.0f, 0.7f);
glRectf(startX - 10, startY - 10, SCREEN_W - 10, startY + lineHeight * 5 + 10);
glColor3f(1, 1, 1);
char fpsBuf[50]; sprintf_s(fpsBuf, "FPS: %d", currentFPS);
char posBuf[50]; sprintf_s(posBuf, "坐标: (%.1f, %.1f, %.1f)", player.pos.x, player.pos.y, player.pos.z);
char cpuBuf[50]; sprintf_s(cpuBuf, "CPU: %.1f%%", GetCPUUsage());
char drawDistBuf[50]; sprintf_s(drawDistBuf, "能见度: %.0f", drawDistance);
char fovBuf[50]; sprintf_s(fovBuf, "场视角: %.0f°", fov);
drawText(startX, startY, fpsBuf);
drawText(startX, startY + lineHeight * 1, posBuf);
drawText(startX, startY + lineHeight * 2, cpuBuf);
drawText(startX, startY + lineHeight * 3, drawDistBuf);
drawText(startX, startY + lineHeight * 4, fovBuf);
end2D();
}
// 修复:问题3 - 物品栏屏幕下方正中间绘制
void drawUI() {
begin2D();
const float slotSize = 60;
const float slotGap = 10;
float totalWidth = INVENTORY_SLOT * slotSize + (INVENTORY_SLOT - 1) * slotGap;
float startX = (SCREEN_W - totalWidth) / 2.0f;
float startY = SCREEN_H - 70;
for (int i = 0; i < INVENTORY_SLOT; i++) {
float x = startX + i * (slotSize + slotGap);
float y = startY;
// 插槽背景
glColor3f(0.2f, 0.2f, 0.2f);
glRectf((GLfloat)x, (GLfloat)y, (GLfloat)(x + slotSize), (GLfloat)(y + slotSize));
if (player.inv[i].item != BLOCK_AIR) {
glEnable(GL_TEXTURE_2D);
GLuint tex = blockTextures[player.inv[i].item];
if (tex != 0) {
glBindTexture(GL_TEXTURE_2D, tex);
glColor3f(1,1,1);
glBegin(GL_QUADS);
glTexCoord2f(0,0); glVertex2f(x+5, y+5);
glTexCoord2f(1,0); glVertex2f(x+55, y+5);
glTexCoord2f(1,1); glVertex2f(x+55, y+55);
glTexCoord2f(0,1); glVertex2f(x+5, y+55);
glEnd();
glDisable(GL_TEXTURE_2D);
}
else {
int colorIdx = 0;
if (player.inv[i].item == BLOCK_GRASS) colorIdx = 1;
else if (player.inv[i].item == BLOCK_DIRT) colorIdx = 2;
else if (player.inv[i].item == BLOCK_STONE) colorIdx = 3;
glColor3f(blockColorFallback[colorIdx].r, blockColorFallback[colorIdx].g, blockColorFallback[colorIdx].b);
glRectf(x+5, y+5, x+55, y+55);
}
char cnt[10]; sprintf_s(cnt, sizeof(cnt), "%d", player.inv[i].count);
glColor3f(1,1,1); drawText(x+10, y+10, cnt);
}
// 选中边框
if (i == player.selectSlot) {
glColor3f(1,1,0);
glRectf(x, y, x+slotSize, y+slotSize);
}
}
end2D();
}
void drawCrosshair() {
begin2D();
glColor3f(1, 1, 1);
glLineWidth(2);
int cx = SCREEN_W / 2, cy = SCREEN_H / 2, s = 10;
glBegin(GL_LINES);
glVertex2i(cx - s, cy); glVertex2i(cx - 3, cy);
glVertex2i(cx + 3, cy); glVertex2i(cx + s, cy);
glVertex2i(cx, cy - s); glVertex2i(cx, cy - 3);
glVertex2i(cx, cy + 3); glVertex2i(cx, cy + s);
glEnd();
glLineWidth(1);
end2D();
}
// 主菜单
void drawMenu() {
begin2D();
glColor3f(0.1f, 0.1f, 0.2f);
glRectf(0, 0, (GLfloat)SCREEN_W, (GLfloat)SCREEN_H);
glColor3f(1, 1, 1);
drawText((float)(SCREEN_W / 2 - 180), 50.0f, L"Voxel Horizon 优化3D GL版本 s2603c");
const wchar_t* options[] = { L"开始游戏", L"读取存档", L"保存游戏", L"退出游戏" };
int optionCount = sizeof(options) / sizeof(options[0]);
for (int i = 0; i < optionCount; i++) {
float y = 200.0f + i * 50.0f;
if (i == menuSelect) {
drawText((float)(SCREEN_W / 2 - 40), y, options[i], Gdiplus::Color(255, 255, 0));
}
else {
drawText((float)(SCREEN_W / 2 - 40), y, options[i], Gdiplus::Color(180, 180, 180));
}
}
const wchar_t* helpText[] = {
L"操作指南:",
L"W/A/S/D: 移动 空格: 跳跃 鼠标: 视角控制",
L"鼠标左键: 挖掘方块 鼠标右键: 放置方块 1-5: 切换物品栏",
L"B: 打开背包 C: 合成系统 V: 切换视角",
L"-/: 减少能见度 =: 增加能见度 ESC: 返回菜单",
L"[: 减小场视角 ]: 增加场视角 范围: 50-110°"
};
float helpY = 450.0f;
for (int i = 0; i < sizeof(helpText) / sizeof(helpText[0]); i++) {
drawText((float)(SCREEN_W / 2 - 200), helpY + i * 25, helpText[i], Gdiplus::Color(150, 150, 150));
}
end2D();
}
// 存档系统
void saveGame() {
std::ofstream fout("save.dat", std::ios::binary);
if (!fout) return;
fout.write((char*)&WORLD_W, sizeof(WORLD_W));
fout.write((char*)&WORLD_H, sizeof(WORLD_H));
fout.write((char*)&player, sizeof(player));
for (auto& wx : world) for (auto& wy : wx) for (auto& b : wy) fout.write((char*)&b, sizeof(Block));
fout.close();
}
void loadGame() {
std::ifstream fin("save.dat", std::ios::binary);
if (!fin) { initWorld(); return; }
fin.read((char*)&WORLD_W, sizeof(WORLD_W));
fin.read((char*)&WORLD_H, sizeof(WORLD_H));
world.clear();
world.resize(WORLD_W);
for (int x = 0; x < WORLD_W; x++) {
world[x].resize(WORLD_D);
for (int y = 0; y < WORLD_D; y++) {
world[x][y].resize(WORLD_H);
}
}
fin.read((char*)&player, sizeof(player));
for (auto& wx : world) for (auto& wy : wx) for (auto& b : wy) fin.read((char*)&b, sizeof(Block));
chunks.clear();
g_numChunksX = (WORLD_W + CHUNK_SIZE - 1) / CHUNK_SIZE;
g_numChunksZ = (WORLD_H + CHUNK_SIZE - 1) / CHUNK_SIZE;
for (int cx = 0; cx < g_numChunksX; cx++) for (int cz = 0; cz < g_numChunksZ; cz++) chunks.emplace_back(cx, cz);
for (int x = 0; x < WORLD_W; x++) for (int y = 0; y < WORLD_D; y++) for (int z = 0; z < WORLD_H; z++)
if (world[x][y][z].isSolid()) {
int cx = x / CHUNK_SIZE, cz = z / CHUNK_SIZE;
if (cx >= 0 && cx < g_numChunksX && cz >= 0 && cz < g_numChunksZ) {
chunks[cx * g_numChunksZ + cz].addBlock(x, y, z);
chunks[cx * g_numChunksZ + cz].isGenerated = true;
}
}
fin.close();
}
// 3D世界渲染
void draw3DWorld() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
Vector3 cam = player.pos + Vector3(0, 1.7f, 0);
Vector3 target = cam + player.getForward();
if (!isFirstPerson) {
cam = player.pos + player.getForward() * -8.0f + Vector3(0, 4, 0);
target = player.pos;
}
gluLookAt(cam.x, cam.y, cam.z, target.x, target.y, target.z, 0, 1, 0);
int playerChunkX = (int)player.pos.x / CHUNK_SIZE;
int playerChunkZ = (int)player.pos.z / CHUNK_SIZE;
int loadRadius = (int)(drawDistance / CHUNK_SIZE) + 1;
for (int cx = playerChunkX - loadRadius; cx <= playerChunkX + loadRadius; cx++) {
for (int cz = playerChunkZ - loadRadius; cz <= playerChunkZ + loadRadius; cz++) {
if (cx >= 0 && cx < g_numChunksX && cz >= 0 && cz < g_numChunksZ) {
Chunk& chunk = chunks[cx * g_numChunksZ + cz];
if (!chunk.isGenerated) {
generateChunk(chunk);
}
for (auto& pos : chunk.blocks) {
int x = std::get<0>(pos), y = std::get<1>(pos), z = std::get<2>(pos);
Vector3 center((float)x, (float)y, (float)z);
if ((center - cam).length() > drawDistance) continue;
drawBlock(x, y, z, world[x][y][z].id);
}
}
}
}
}
// 修复:问题1 - 重构碰撞检测,标准0.8宽×1.8高碰撞箱
bool checkCollision(Vector3 p, float w = 0.8f, float h = 1.8f) {
int mx = (int)floor(p.x - w / 2.0f);
int Mx = (int)ceil(p.x + w / 2.0f);
int my = (int)floor(p.y);
int My = (int)ceil(p.y + h);
int mz = (int)floor(p.z - w / 2.0f);
int Mz = (int)ceil(p.z + w / 2.0f);
for (int x = mx; x <= Mx; x++) {
for (int y = my; y <= My; y++) {
for (int z = mz; z <= Mz; z++) {
if (IN_WORLD(x, y, z) && world[x][y][z].isSolid()) {
return true;
}
}
}
}
return false;
}
// 修复:问题1/2 - 物理逻辑重构,防止穿透,跳跃高度1.275格
void playerPhysics() {
if (isDead) return;
LARGE_INTEGER now; QueryPerformanceCounter(&now);
float dt = (now.QuadPart - lastTimeCounter.QuadPart) / (float)freq.QuadPart;
lastTimeCounter = now;
dt = std::min(dt, 0.1f);
const float colliderW = 0.8f;
const float colliderH = 1.8f;
player.vel.y -= 9.8f * dt; // 标准重力
Vector3 np = player.pos;
// X轴移动(分步处理,防止穿透)
np.x += player.vel.x * dt;
if (checkCollision(np, colliderW, colliderH)) {
np.x = player.pos.x;
player.vel.x = 0;
}
// Z轴移动
np.z += player.vel.z * dt;
if (checkCollision(np, colliderW, colliderH)) {
np.z = player.pos.z;
player.vel.z = 0;
}
// Y轴移动
bool ground = false;
np.y += player.vel.y * dt;
if (checkCollision(np, colliderW, colliderH)) {
if (player.vel.y < 0) { // 落地
ground = true;
np.y = (float)floor(np.y) + colliderH;
} else { // 顶头
np.y = player.pos.y;
}
player.vel.y = 0;
}
// 边界限制
np.x = clamp(np.x, colliderW/2, WORLD_W - colliderW/2);
np.z = clamp(np.z, colliderW/2, WORLD_H - colliderW/2);
np.y = clamp(np.y, 0.0f, WORLD_D - colliderH);
// 坠落伤害
static float fallY = player.pos.y;
if (ground) {
float d = fallY - np.y;
if (d > FALL_DAMAGE_HEIGHT) player.hp -= max(0, (int)((d - FALL_DAMAGE_HEIGHT) * 10));
fallY = np.y;
} else if (player.vel.y < 0) fallY = max(fallY, np.y);
player.pos = np;
if (player.hp <= 0) { isDead = true; cursorVisible = true; }
}
// 修复:问题2 - 跳跃逻辑修复,仅地面可跳,高度1.275格
void inputControl() {
Vector3 hp; hasHitBlock = raycastBlock(hp, hitX, hitY, hitZ);
static bool lastUp = false, lastDown = false, lastEnter = false;
bool up = GetAsyncKeyState(VK_UP) & 0x8000;
bool down = GetAsyncKeyState(VK_DOWN) & 0x8000;
bool enter = GetAsyncKeyState(VK_RETURN) & 0x8000;
if (isMenu) {
int optionCount = 4;
if (up && !lastUp) menuSelect = (menuSelect - 1 + optionCount) % optionCount;
if (down && !lastDown) menuSelect = (menuSelect + 1) % optionCount;
if (enter && !lastEnter) {
if (menuSelect == 0) { isMenu = false; cursorVisible = false; ShowCursor(FALSE); }
else if (menuSelect == 1) { loadGame(); MessageBox(NULL, L"存档已读取!", L"提示", MB_OK); }
else if (menuSelect == 2) { saveGame(); MessageBox(NULL, L"游戏已保存!", L"提示", MB_OK); }
else if (menuSelect == 3) running = false;
}
lastUp = up; lastDown = down; lastEnter = enter;
return;
}
if (isGenerating || isDead) return;
if (!isMenu && !isBag && !cursorVisible) {
RECT r; GetWindowRect(hWnd, &r);
int cx = r.left + SCREEN_W / 2, cy = r.top + SCREEN_H / 2;
POINT m; GetCursorPos(&m);
float dx = (float)(m.x - cx) * 0.002f, dy = (float)(m.y - cy) * 0.002f;
player.rotY -= dx; player.rotX -= dy;
player.rotX = clamp(player.rotX, -(float)M_PI/2+0.01f, (float)M_PI/2-0.01f);
SetCursorPos(cx, cy);
}
// 移动逻辑
float moveSpeed = 8.0f;
Vector3 fwd = player.getForward();
Vector3 rgt = player.getRight();
Vector3 moveDir(0,0,0);
if (GetAsyncKeyState('W') & 0x8000) moveDir += Vector3(fwd.x, 0, fwd.z);
if (GetAsyncKeyState('S') & 0x8000) moveDir -= Vector3(fwd.x, 0, fwd.z);
if (GetAsyncKeyState('A') & 0x8000) moveDir -= Vector3(rgt.x, 0, rgt.z);
if (GetAsyncKeyState('D') & 0x8000) moveDir += Vector3(rgt.x, 0, rgt.z);
if (moveDir.length() > 0.001f) moveDir = moveDir.normalize();
player.vel.x = moveDir.x * moveSpeed;
player.vel.z = moveDir.z * moveSpeed;
// 修复:问题2 - 跳跃(1.275格高度,v=√(2gh)=5.0f),仅地面可跳
static bool lastSpace = false;
bool space = GetAsyncKeyState(VK_SPACE) & 0x8000;
bool isOnGround = (player.vel.y == 0);
if (space && !lastSpace && isOnGround) {
player.vel.y = 5.0f; // 精准对应1.275格跳跃高度
}
lastSpace = space;
// 挖掘/放置
if (GetAsyncKeyState(VK_LBUTTON) & 0x8000 && hasHitBlock) {
int t = world[hitX][hitY][hitZ].id;
world[hitX][hitY][hitZ] = Block(BLOCK_AIR);
for (int i = 0; i < INVENTORY_SLOT; i++) {
if (player.inv[i].item == t || player.inv[i].item == BLOCK_AIR) {
player.inv[i].item = t; player.inv[i].count++; break;
}
}
}
bool rButton = GetAsyncKeyState(VK_RBUTTON) & 0x8000;
if (rButton && !lastRButton && hasHitBlock && player.inv[player.selectSlot].count > 0) {
Vector3 d = player.getForward().normalize();
int px = hitX + (d.x > 0.1f ? 1 : (d.x < -0.1f ? -1 : 0));
int py = hitY + (d.y > 0.1f ? 1 : (d.y < -0.1f ? -1 : 0));
int pz = hitZ + (d.z > 0.1f ? 1 : (d.z < -0.1f ? -1 : 0));
if (IN_WORLD(px, py, pz) && world[px][py][pz].id == BLOCK_AIR) {
world[px][py][pz] = Block(player.inv[player.selectSlot].item);
player.inv[player.selectSlot].count--;
if (player.inv[player.selectSlot].count == 0) player.inv[player.selectSlot].item = BLOCK_AIR;
int cx = px / CHUNK_SIZE, cz = pz / CHUNK_SIZE;
if (cx >=0 && cx < g_numChunksX && cz >=0 && cz < g_numChunksZ) {
chunks[cx * g_numChunksZ + cz].addBlock(px, py, pz);
}
}
}
lastRButton = rButton;
// 快捷栏
if (GetAsyncKeyState('1') & 0x8000) player.selectSlot = 0;
if (GetAsyncKeyState('2') & 0x8000) player.selectSlot = 1;
if (GetAsyncKeyState('3') & 0x8000) player.selectSlot = 2;
if (GetAsyncKeyState('4') & 0x8000) player.selectSlot = 3;
if (GetAsyncKeyState('5') & 0x8000) player.selectSlot = 4;
// 功能键
bool bKey = GetAsyncKeyState('B') & 0x8000;
if (bKey && !lastB) { isBag = !isBag; cursorVisible = isBag; ShowCursor(cursorVisible); }
lastB = bKey;
bool cKey = GetAsyncKeyState('C') & 0x8000;
if (cKey && !lastC) { isCraft = !isCraft; cursorVisible = isCraft; ShowCursor(cursorVisible); }
lastC = cKey;
bool vKey = GetAsyncKeyState('V') & 0x8000;
if (vKey && !lastV) { isFirstPerson = !isFirstPerson; }
lastV = vKey;
bool minusKey = GetAsyncKeyState(VK_OEM_MINUS) & 0x8000;
if (minusKey && !lastMinus) { drawDistance = max(DRAW_DISTANCE_MIN, drawDistance - DRAW_DISTANCE_STEP); }
lastMinus = minusKey;
bool equalKey = GetAsyncKeyState(VK_OEM_PLUS) & 0x8000;
if (equalKey && !lastEqual) { drawDistance = min(DRAW_DISTANCE_MAX, drawDistance + DRAW_DISTANCE_STEP); }
lastEqual = equalKey;
bool lbracketKey = GetAsyncKeyState(VK_OEM_4) & 0x8000;
if (lbracketKey && !lastLBracket) {
fov = max(FOV_MIN, fov - FOV_STEP);
glMatrixMode(GL_PROJECTION); glLoadIdentity();
gluPerspective(fov, (float)SCREEN_W/SCREEN_H, NEAR_PLANE, FAR_PLANE);
glMatrixMode(GL_MODELVIEW);
}
lastLBracket = lbracketKey;
bool rbracketKey = GetAsyncKeyState(VK_OEM_6) & 0x8000;
if (rbracketKey && !lastRBracket) {
fov = min(FOV_MAX, fov + FOV_STEP);
glMatrixMode(GL_PROJECTION); glLoadIdentity();
gluPerspective(fov, (float)SCREEN_W/SCREEN_H, NEAR_PLANE, FAR_PLANE);
glMatrixMode(GL_MODELVIEW);
}
lastRBracket = rbracketKey;
static bool lastEsc = false;
bool esc = GetAsyncKeyState(VK_ESCAPE) & 0x8000;
if (esc && !lastEsc) { isMenu = true; cursorVisible = true; ShowCursor(TRUE); }
lastEsc = esc;
}
// OpenGL初始化
void initGL() {
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_NORMALIZE);
glShadeModel(GL_SMOOTH);
float lightPos[] = { 0.5f,1.0f,0.5f,0 };
float lightAmb[] = { 0.3f,0.3f,0.3f,1 };
float lightDif[] = { 0.7f,0.7f,0.7f,1 };
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmb);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDif);
glClearColor(0.53f, 0.81f, 0.92f, 1.0f);
glMatrixMode(GL_PROJECTION);
gluPerspective(fov, (float)SCREEN_W / SCREEN_H, NEAR_PLANE, FAR_PLANE);
glMatrixMode(GL_MODELVIEW);
initFont();
initBlockTextures();
}
// 渲染循环
void render() {
// 修复:问题4 - 文字渲染计数器自增
textRenderCounter++;
if (isMenu) {
drawMenu();
}
else {
draw3DWorld();
drawHP();
drawUI();
drawCrosshair();
drawDebugInfo();
}
SwapBuffers(hDC);
}
// 窗口过程
LRESULT CALLBACK WndProc(HWND h, UINT msg, WPARAM w, LPARAM l) {
switch (msg) {
case WM_DESTROY:
running = false;
PostQuitMessage(0);
break;
case WM_SIZE:
if (hRC) {
int width = LOWORD(l);
int height = HIWORD(l);
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(fov, (float)width / height, NEAR_PLANE, FAR_PLANE);
glMatrixMode(GL_MODELVIEW);
}
break;
default:
return DefWindowProc(h, msg, w, l);
}
return 0;
}
// 主函数
int main() {
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
setlocale(LC_ALL, "zh_CN.UTF-8");
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&lastTimeCounter);
srand((unsigned int)time(NULL));
InitMemoryPool();
loadGame();
WNDCLASSEX wc = { 0 };
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = WndProc;
wc.hInstance = GetModuleHandle(NULL);
wc.lpszClassName = L"OpenGLGame";
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
RegisterClassEx(&wc);
hWnd = CreateWindowEx(0, L"OpenGLGame", L"Voxel Horizon Dev",
WS_OVERLAPPEDWINDOW, 100, 100, SCREEN_W, SCREEN_H, NULL, NULL, wc.hInstance, NULL);
hDC = GetDC(hWnd);
PIXELFORMATDESCRIPTOR pfd = { 0 };
pfd.nSize = sizeof(pfd); pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32; pfd.cDepthBits = 24;
int pf = ChoosePixelFormat(hDC, &pfd);
SetPixelFormat(hDC, pf, &pfd);
hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hRC);
initGL();
ShowWindow(hWnd, SW_SHOW);
ShowCursor(TRUE);
fpsLastTime = GetTickCount64();
MSG msg;
while (running) {
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
continue;
}
ULONGLONG start = GetTickCount64();
inputControl();
if (!isMenu) playerPhysics();
render();
ULONGLONG frame = GetTickCount64() - start;
if (frame < FRAME_TIME) Sleep((DWORD)(FRAME_TIME - frame));
fpsFrames++;
ULONGLONG currentTime = GetTickCount64();
if (currentTime - fpsLastTime >= 1000) {
currentFPS = fpsFrames;
fpsFrames = 0;
fpsLastTime = currentTime;
}
}
if (hFont) DeleteObject(hFont);
wglMakeCurrent(NULL, NULL);
wglDeleteContext(hRC);
ReleaseDC(hWnd, hDC);
VirtualFree(g_MemoryPool, 0, MEM_RELEASE);
Gdiplus::GdiplusShutdown(gdiplusToken);
return 0;
}