#include "stdafx.h" /** * @file TetrisRenderAssets.cpp * @brief 实现 GDI+ 初始化以及背景图、致谢页图片的加载与缓存。 */ #include "TetrisRenderInternal.h" #include "TetrisAssets.h" #include #include #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]; }