158 lines
4.6 KiB
C++
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];
|
|
}
|