Files
Tereis/src/source/render/TetrisRenderAssets.cpp
T
2026-05-01 16:27:27 +08:00

158 lines
4.6 KiB
C++

#include "stdafx.h"
/**
* @file TetrisRenderAssets.cpp
* @brief 实现 GDI+ 初始化以及背景图、致谢页图片的加载与缓存。
*/
#include "TetrisRenderInternal.h"
#include "TetrisAssets.h"
#include <objidl.h>
#include <string>
#pragma comment(lib, "gdiplus.lib")
using namespace Gdiplus;
/**
* @brief 尝试从指定路径加载 GDI+ 位图。
* @param path 图片文件路径。
* @return 加载成功返回位图指针,失败返回 nullptr。
*/
static Bitmap* TryLoadBitmap(const std::wstring& path)
{
// 空路径和不存在的文件不交给 GDI+,减少无效加载开销。
if (path.empty() || !FileExists(path))
{
return nullptr;
}
// GDI+ 返回对象后仍需检查状态,失败对象要立即释放。
Bitmap* loadedImage = Bitmap::FromFile(path.c_str(), FALSE);
if (loadedImage != nullptr && loadedImage->GetLastStatus() == Ok)
{
return loadedImage;
}
delete loadedImage;
return nullptr;
}
/**
* @brief 确保 GDI+ 已初始化,返回初始化是否成功。
* @return GDI+ 可用返回 true,否则返回 false。
*/
static bool EnsureGdiplusStarted()
{
static ULONG_PTR gdiplusToken = 0;
static bool attempted = false;
static bool started = false;
if (!attempted)
{
// GDI+ 只需要初始化一次,静态标记避免重复启动。
attempted = true;
GdiplusStartupInput startupInput;
started = GdiplusStartup(&gdiplusToken, &startupInput, nullptr) == Ok;
}
return started;
}
/**
* @brief 加载并缓存主背景图片。
* @return 成功时返回缓存位图指针,失败时返回 nullptr。
*/
Bitmap* LoadBackgroundImage()
{
static Bitmap* backgroundImage = nullptr;
static bool attempted = false;
// 背景图只查找一次,失败后也记住结果,避免每帧重复访问磁盘。
if (!attempted)
{
attempted = true;
if (EnsureGdiplusStarted())
{
const std::wstring candidates[] =
{
BuildAssetPath(L"assets\\images\\background.png"),
BuildWorkingDirAssetPath(L"assets\\images\\background.png"),
BuildAssetPath(L"assets\\images\\background.bmp"),
BuildWorkingDirAssetPath(L"assets\\images\\background.bmp")
};
// 同时支持构建目录运行和项目根目录运行两种启动方式。
for (const std::wstring& candidate : candidates)
{
backgroundImage = TryLoadBitmap(candidate);
if (backgroundImage != nullptr)
{
break;
}
}
}
}
return backgroundImage;
}
/**
* @brief 按序号加载并缓存致谢页图片。
* @param index 致谢页图片序号。
* @return 成功时返回缓存位图指针,失败或越界时返回 nullptr。
*/
Bitmap* LoadCreditImage(int index)
{
constexpr int creditPageCount = 5;
static Bitmap* creditImages[creditPageCount] = {};
static bool attempted[creditPageCount] = {};
if (index < 0 || index >= creditPageCount)
{
return nullptr;
}
// 每张致谢图单独缓存,只有首次进入对应页时才加载。
if (!attempted[index])
{
attempted[index] = true;
if (EnsureGdiplusStarted())
{
const wchar_t* imageNames[creditPageCount] =
{
L"assets\\images\\qls.jpg",
L"assets\\images\\wyk.jpg",
L"assets\\images\\swj.jpg",
L"assets\\images\\qhy.jpg",
L"assets\\images\\syc.jpg"
};
const std::wstring creditExtraCandidates[] =
{
BuildAssetPath(imageNames[index]),
BuildWorkingDirAssetPath(imageNames[index]),
BuildAssetPath(L"assets\\images\\qhy.png"),
BuildWorkingDirAssetPath(L"assets\\images\\qhy.png"),
BuildAssetPath(L"assets\\images\\qhy.jpeg"),
BuildWorkingDirAssetPath(L"assets\\images\\qhy.jpeg"),
BuildAssetPath(L"assets\\images\\qhy.bmp"),
BuildWorkingDirAssetPath(L"assets\\images\\qhy.bmp")
};
int candidateCount = (index == 3) ? 8 : 2;
// 第四张致谢图历史上有多种扩展名,这里保留兼容查找。
for (int i = 0; i < candidateCount; i++)
{
creditImages[index] = TryLoadBitmap(creditExtraCandidates[i]);
if (creditImages[index] != nullptr)
{
break;
}
}
}
}
return creditImages[index];
}