增加File类和Resource类;图片和音乐资源统一为Resource map

This commit is contained in:
Nomango 2018-07-08 02:41:44 +08:00
parent 0423b49bb9
commit b7c4c409cb
12 changed files with 622 additions and 661 deletions

View File

@ -3,9 +3,7 @@
#include "..\e2dtool.h"
#include <map>
static std::map<size_t, ID2D1Bitmap*> s_mBitmapsFromFile;
static std::map<int, ID2D1Bitmap*> s_mBitmapsFromResource;
static std::set<ID2D1Bitmap*> s_vBitmaps;
static std::map<e2d::Resource, ID2D1Bitmap*> s_mBitmapsFromResource;
e2d::Image::Image()
@ -14,33 +12,33 @@ e2d::Image::Image()
{
}
e2d::Image::Image(const String& filePath)
e2d::Image::Image(const Resource& res)
: _bitmap(nullptr)
, _cropRect()
{
this->open(filePath);
this->open(res);
}
e2d::Image::Image(int resNameId, const String& resType)
e2d::Image::Image(const Resource& res, const Rect& cropRect)
: _bitmap(nullptr)
, _cropRect()
{
this->open(resNameId, resType);
}
e2d::Image::Image(const String& filePath, const Rect& cropRect)
: _bitmap(nullptr)
, _cropRect()
{
this->open(filePath);
this->open(res);
this->crop(cropRect);
}
e2d::Image::Image(int resNameId, const String& resType, const Rect& cropRect)
e2d::Image::Image(const String & fileName)
: _bitmap(nullptr)
, _cropRect()
{
this->open(resNameId, resType);
this->open(Resource(fileName));
}
e2d::Image::Image(const String & fileName, const Rect & cropRect)
: _bitmap(nullptr)
, _cropRect()
{
this->open(Resource(fileName));
this->crop(cropRect);
}
@ -48,33 +46,29 @@ e2d::Image::~Image()
{
}
bool e2d::Image::open(const String& filePath)
bool e2d::Image::open(const Resource& res)
{
WARN_IF(filePath.isEmpty(), "Image open failed! Invalid file name.");
if (!res.isResource())
{
WARN_IF(res.getFileName().isEmpty(), "Image open failed! Invalid file name.");
if (filePath.isEmpty())
if (res.getFileName().isEmpty())
return false;
}
if (!Image::preload(filePath))
if (!Image::preload(res))
{
WARN("Load Image from file failed!");
return false;
}
this->_setBitmap(s_mBitmapsFromFile.at(filePath.getHashCode()));
this->_setBitmap(s_mBitmapsFromResource.at(res));
return true;
}
bool e2d::Image::open(int resNameId, const String& resType)
bool e2d::Image::open(const String & fileName)
{
if (!Image::preload(resNameId, resType))
{
WARN("Load Image from file failed!");
return false;
}
this->_setBitmap(s_mBitmapsFromResource.at(resNameId));
return true;
return open(Resource(fileName));
}
void e2d::Image::crop(const Rect& cropRect)
@ -154,94 +148,9 @@ e2d::Point e2d::Image::getCropPos() const
return _cropRect.origin;
}
bool e2d::Image::preload(const String& filePath)
bool e2d::Image::preload(const Resource& res)
{
if (s_mBitmapsFromFile.find(filePath.getHashCode()) != s_mBitmapsFromFile.end())
{
return true;
}
String actualFilePath = Path::findFile(filePath);
if (actualFilePath.isEmpty())
{
return false;
}
HRESULT hr = S_OK;
IWICBitmapDecoder *pDecoder = nullptr;
IWICBitmapFrameDecode *pSource = nullptr;
IWICStream *pStream = nullptr;
IWICFormatConverter *pConverter = nullptr;
ID2D1Bitmap *pBitmap = nullptr;
// 创建解码器
hr = Renderer::getImagingFactory()->CreateDecoderFromFilename(
(LPCWSTR)actualFilePath,
nullptr,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
if (SUCCEEDED(hr))
{
// 创建初始化框架
hr = pDecoder->GetFrame(0, &pSource);
}
if (SUCCEEDED(hr))
{
// 创建图片格式转换器
// (DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED).
hr = Renderer::getImagingFactory()->CreateFormatConverter(&pConverter);
}
if (SUCCEEDED(hr))
{
// 图片格式转换成 32bbpPBGRA
hr = pConverter->Initialize(
pSource,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
nullptr,
0.f,
WICBitmapPaletteTypeMedianCut
);
}
if (SUCCEEDED(hr))
{
// 从 WIC 位图创建一个 Direct2D 位图
hr = Renderer::getInstance()->getRenderTarget()->CreateBitmapFromWicBitmap(
pConverter,
nullptr,
&pBitmap
);
}
if (SUCCEEDED(hr))
{
// 保存图片指针和图片的 Hash 名
s_mBitmapsFromFile.insert(
std::map<size_t, ID2D1Bitmap*>::value_type(
filePath.getHashCode(),
pBitmap)
);
}
// 释放相关资源
SafeRelease(pDecoder);
SafeRelease(pSource);
SafeRelease(pStream);
SafeRelease(pConverter);
return SUCCEEDED(hr);
}
bool e2d::Image::preload(int resNameId, const String& resType)
{
if (s_mBitmapsFromResource.find(resNameId) != s_mBitmapsFromResource.end())
if (s_mBitmapsFromResource.find(res) != s_mBitmapsFromResource.end())
{
return true;
}
@ -252,16 +161,22 @@ bool e2d::Image::preload(int resNameId, const String& resType)
IWICBitmapFrameDecode *pSource = nullptr;
IWICStream *pStream = nullptr;
IWICFormatConverter *pConverter = nullptr;
IWICBitmapScaler *pScaler = nullptr;
ID2D1Bitmap *pBitmap = nullptr;
IWICImagingFactory *pImagingFactory = Renderer::getImagingFactory();
if (res.isResource())
{
HRSRC imageResHandle = nullptr;
HGLOBAL imageResDataHandle = nullptr;
void *pImageFile = nullptr;
DWORD imageFileSize = 0;
// 定位资源
imageResHandle = ::FindResourceW(HINST_THISCOMPONENT, MAKEINTRESOURCE(resNameId), (LPCWSTR)resType);
imageResHandle = ::FindResourceW(
HINST_THISCOMPONENT,
MAKEINTRESOURCE(res.getResNameId()),
(LPCWSTR)res.getResType()
);
hr = imageResHandle ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
@ -291,7 +206,7 @@ bool e2d::Image::preload(int resNameId, const String& resType)
if (SUCCEEDED(hr))
{
// 创建 WIC 流
hr = Renderer::getImagingFactory()->CreateStream(&pStream);
hr = pImagingFactory->CreateStream(&pStream);
}
if (SUCCEEDED(hr))
@ -306,13 +221,31 @@ bool e2d::Image::preload(int resNameId, const String& resType)
if (SUCCEEDED(hr))
{
// 创建流的解码器
hr = Renderer::getImagingFactory()->CreateDecoderFromStream(
hr = pImagingFactory->CreateDecoderFromStream(
pStream,
nullptr,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
}
}
else
{
String actualFilePath = File(res.getFileName()).getFilePath();
if (actualFilePath.isEmpty())
{
return false;
}
// ´´½¨½âÂëÆ÷
hr = pImagingFactory->CreateDecoderFromFilename(
(LPCWSTR)actualFilePath,
nullptr,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
}
if (SUCCEEDED(hr))
{
@ -323,8 +256,7 @@ bool e2d::Image::preload(int resNameId, const String& resType)
if (SUCCEEDED(hr))
{
// 创建图片格式转换器
// (DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED).
hr = Renderer::getImagingFactory()->CreateFormatConverter(&pConverter);
hr = pImagingFactory->CreateFormatConverter(&pConverter);
}
if (SUCCEEDED(hr))
@ -352,7 +284,7 @@ bool e2d::Image::preload(int resNameId, const String& resType)
if (SUCCEEDED(hr))
{
s_mBitmapsFromResource.insert(std::pair<int, ID2D1Bitmap*>(resNameId, pBitmap));
s_mBitmapsFromResource.insert(std::make_pair(res, pBitmap));
}
// 释放相关资源
@ -360,31 +292,17 @@ bool e2d::Image::preload(int resNameId, const String& resType)
SafeRelease(pSource);
SafeRelease(pStream);
SafeRelease(pConverter);
SafeRelease(pScaler);
return SUCCEEDED(hr);
}
void e2d::Image::clearCache()
{
for (auto bitmap : s_mBitmapsFromFile)
{
SafeRelease(bitmap.second);
}
s_mBitmapsFromFile.clear();
for (auto bitmap : s_mBitmapsFromResource)
{
SafeRelease(bitmap.second);
}
s_mBitmapsFromResource.clear();
for (auto bitmap : s_vBitmaps)
{
SafeRelease(bitmap);
}
s_vBitmaps.clear();
}
void e2d::Image::_setBitmap(ID2D1Bitmap * bitmap)

69
core/Common/Resource.cpp Normal file
View File

@ -0,0 +1,69 @@
#include "..\e2dtool.h"
e2d::Resource::Resource(const String & fileName)
: _isResource(false)
, _fileName(fileName)
, _resNameId(0)
, _resType()
{
}
e2d::Resource::Resource(int resNameId, const String & resType)
: _isResource(true)
, _fileName()
, _resNameId(resNameId)
, _resType(resType)
{
}
bool e2d::Resource::isResource() const
{
return _isResource;
}
const e2d::String & e2d::Resource::getFileName() const
{
return _fileName;
}
int e2d::Resource::getResNameId() const
{
return _resNameId;
}
const e2d::String & e2d::Resource::getResType() const
{
return _resType;
}
int e2d::Resource::getKey() const
{
if (_isResource)
{
return _resNameId;
}
else
{
return _fileName.getHashCode();
}
}
bool e2d::Resource::operator>(const Resource &res) const
{
return this->getKey() > res.getKey();
}
bool e2d::Resource::operator>=(const Resource &res) const
{
return this->getKey() >= res.getKey();
}
bool e2d::Resource::operator<(const Resource &res) const
{
return this->getKey() < res.getKey();
}
bool e2d::Resource::operator<=(const Resource &res) const
{
return this->getKey() <= res.getKey();
}

View File

@ -12,29 +12,29 @@ e2d::Sprite::Sprite(Image * image)
open(image);
}
e2d::Sprite::Sprite(const String& filePath)
e2d::Sprite::Sprite(const Resource& res)
: _image(nullptr)
{
open(filePath);
open(res);
}
e2d::Sprite::Sprite(int resNameId, const String& resType)
e2d::Sprite::Sprite(const Resource& res, const Rect& cropRect)
: _image(nullptr)
{
open(resNameId, resType);
}
e2d::Sprite::Sprite(const String& filePath, const Rect& cropRect)
: _image(nullptr)
{
open(filePath);
open(res);
crop(cropRect);
}
e2d::Sprite::Sprite(int resNameId, const String& resType, const Rect& cropRect)
e2d::Sprite::Sprite(const String & fileName)
: _image(nullptr)
{
open(resNameId, resType);
open(fileName);
}
e2d::Sprite::Sprite(const String & fileName, const Rect & cropRect)
: _image(nullptr)
{
open(fileName);
crop(cropRect);
}
@ -57,7 +57,7 @@ bool e2d::Sprite::open(Image * image)
return false;
}
bool e2d::Sprite::open(const String& filePath)
bool e2d::Sprite::open(const Resource& res)
{
if (!_image)
{
@ -65,7 +65,7 @@ bool e2d::Sprite::open(const String& filePath)
GC::retain(_image);
}
if (_image->open(filePath))
if (_image->open(res))
{
Node::setSize(_image->getWidth(), _image->getHeight());
return true;
@ -73,20 +73,9 @@ bool e2d::Sprite::open(const String& filePath)
return false;
}
bool e2d::Sprite::open(int resNameId, const String& resType)
bool e2d::Sprite::open(const String & fileName)
{
if (!_image)
{
_image = new (e2d::autorelease) Image();
GC::retain(_image);
}
if (_image->open(resNameId, resType))
{
Node::setSize(_image->getWidth(), _image->getHeight());
return true;
}
return false;
return open(Resource(fileName));
}
void e2d::Sprite::crop(const Rect& cropRect)

182
core/Tool/File.cpp Normal file
View File

@ -0,0 +1,182 @@
#include "..\e2dtool.h"
#include <commdlg.h>
std::list<e2d::String> e2d::File::_searchPaths;
e2d::File::File()
: _fileName()
, _attributes(0)
{
}
e2d::File::File(const String & fileName)
: _fileName(fileName)
, _attributes(0)
{
this->open(fileName);
}
e2d::File::~File()
{
}
bool e2d::File::open(const String & fileName)
{
auto FindFile = [=](const String & path) -> bool
{
if (::_waccess((const wchar_t*)path, 0) == 0)
{
_attributes = ::GetFileAttributes((LPCTSTR)path);
return true;
}
return false;
};
if (FindFile(fileName))
{
_fileName = fileName;
return true;
}
else
{
for (auto& resPath : _searchPaths)
{
if (FindFile(resPath + fileName))
{
_fileName = resPath + fileName;
return true;
}
}
}
return false;
}
bool e2d::File::exists() const
{
return ::_waccess((const wchar_t*)_fileName, 0) == 0;
}
bool e2d::File::isFolder() const
{
return _attributes & FILE_ATTRIBUTE_DIRECTORY;
}
e2d::String e2d::File::getFilePath() const
{
return _fileName;
}
e2d::String e2d::File::getExtension() const
{
String fileExtension;
// 找到文件名中的最后一个 '.' 的位置
size_t pos = _fileName.getWString().find_last_of(L'.');
// 判断 pos 是否是有效位置
if (pos != std::wstring::npos)
{
// 截取扩展名
fileExtension = _fileName.subtract(static_cast<int>(pos));
// 转换为小写字母
fileExtension = fileExtension.toLower();
}
return fileExtension;
}
bool e2d::File::deleteFile()
{
if (::DeleteFile((LPCWSTR)_fileName))
return true;
return false;
}
e2d::File e2d::File::extract(int resNameId, const String & resType, const String& destFileName)
{
String destFilePath = Path::getTempPath() + destFileName;
// 创建文件
HANDLE hFile = ::CreateFile((LPCWSTR)destFilePath, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return std::move(File());
// 查找资源文件中、加载资源到内存、得到资源大小
HRSRC hRes = ::FindResource(NULL, MAKEINTRESOURCE(resNameId), (LPCWSTR)resType);
HGLOBAL hMem = ::LoadResource(NULL, hRes);
DWORD dwSize = ::SizeofResource(NULL, hRes);
if (hRes && hMem && dwSize)
{
// 写入文件
DWORD dwWrite = 0;
::WriteFile(hFile, hMem, dwSize, &dwWrite, NULL);
::CloseHandle(hFile);
return File(destFilePath);
}
else
{
::CloseHandle(hFile);
::DeleteFile((LPCWSTR)destFilePath);
return std::move(File());
}
}
void e2d::File::addSearchPath(const String & path)
{
String tmp = path;
tmp.replace(L"/", L"\\");
if (tmp[tmp.getLength() - 1] != L'\\')
{
tmp << L"\\";
}
auto iter = std::find(_searchPaths.cbegin(), _searchPaths.cend(), tmp);
if (iter == _searchPaths.cend())
{
_searchPaths.push_front(path);
}
}
bool e2d::File::createFolder(const String & dirPath)
{
if (dirPath.isEmpty() || dirPath.getLength() >= MAX_PATH)
return false;
wchar_t tmpDirPath[_MAX_PATH] = { 0 };
int length = dirPath.getLength();
for (int i = 0; i < length; ++i)
{
tmpDirPath[i] = dirPath.at(i);
if (tmpDirPath[i] == L'\\' || tmpDirPath[i] == L'/' || i == (length - 1))
{
if (::_waccess(tmpDirPath, 0) != 0)
{
if (::_wmkdir(tmpDirPath) != 0)
{
return false;
}
}
}
}
return true;
}
e2d::String e2d::File::getSaveFilePath(const String& title, const String& defExt)
{
// 弹出保存对话框
OPENFILENAME ofn = { 0 };
wchar_t strFilename[MAX_PATH] = { 0 }; // 用于接收文件名
ofn.lStructSize = sizeof(OPENFILENAME); // 结构体大小
ofn.hwndOwner = Window::getInstance()->getHWnd(); // 窗口句柄
ofn.lpstrFilter = L"所有文件\0*.*\0\0"; // 设置过滤
ofn.nFilterIndex = 1; // 过滤器索引
ofn.lpstrFile = strFilename; // 接收返回的文件路径和文件名
ofn.nMaxFile = sizeof(strFilename); // 缓冲区长度
ofn.lpstrInitialDir = nullptr; // 初始目录为默认
ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
ofn.lpstrTitle = (LPCWSTR)title; // 标题
ofn.lpstrDefExt = (LPCWSTR)defExt; // 默认追加的扩展名
if (GetSaveFileName(&ofn))
{
return strFilename;
}
return std::move(String());
}

View File

@ -49,7 +49,7 @@ e2d::Music::Music(const e2d::String & filePath)
this->open(filePath);
}
e2d::Music::Music(int resNameId, const String & resType)
e2d::Music::Music(const Resource& res)
: _opened(false)
, _playing(false)
, _wfx(nullptr)
@ -60,7 +60,7 @@ e2d::Music::Music(int resNameId, const String & resType)
, _voice(nullptr)
, _voiceCallback(this)
{
this->open(resNameId, resType);
this->open(res);
}
e2d::Music::~Music()
@ -69,6 +69,11 @@ e2d::Music::~Music()
}
bool e2d::Music::open(const e2d::String& filePath)
{
return open(Resource(filePath));
}
bool e2d::Music::open(const Resource& res)
{
if (_opened)
{
@ -76,92 +81,14 @@ bool e2d::Music::open(const e2d::String& filePath)
return false;
}
if (filePath.isEmpty())
if (res.isResource())
{
WARN("MusicInfo::open Invalid file name.");
return false;
}
String actualFilePath = Path::findFile(filePath);
if (actualFilePath.isEmpty())
{
WARN("MusicInfo::open File not found.");
return false;
}
// 定位 wave 文件
wchar_t pFilePath[MAX_PATH];
if (!_findMediaFileCch(pFilePath, MAX_PATH, (const wchar_t *)actualFilePath))
{
WARN("Failed to find media file: %s", pFilePath);
return false;
}
_hmmio = mmioOpen(pFilePath, nullptr, MMIO_ALLOCBUF | MMIO_READ);
if (nullptr == _hmmio)
{
return TraceError(L"mmioOpen");
}
if (!_readMMIO())
{
// 读取非 wave 文件时 ReadMMIO 调用失败
mmioClose(_hmmio, 0);
return TraceError(L"_readMMIO");
}
if (!_resetFile())
return TraceError(L"_resetFile");
// 重置文件后wave 文件的大小是 _ck.cksize
_dwSize = _ck.cksize;
// 将样本数据读取到内存中
_waveData = new BYTE[_dwSize];
if (!_read(_waveData, _dwSize))
{
TraceError(L"Failed to read WAV data");
SAFE_DELETE_ARRAY(_waveData);
return false;
}
// 创建音源
HRESULT hr = Player::getInstance()->getXAudio2()->CreateSourceVoice(
&_voice,
_wfx,
0,
XAUDIO2_DEFAULT_FREQ_RATIO,
&this->_voiceCallback
);
if (FAILED(hr))
{
TraceError(L"Create source voice error", hr);
SAFE_DELETE_ARRAY(_waveData);
return false;
}
_opened = true;
_playing = false;
return true;
}
bool e2d::Music::open(int resNameId, const e2d::String& resType)
{
HRSRC hResInfo;
HGLOBAL hResData;
DWORD dwSize;
void* pvRes;
if (_opened)
{
WARN("MusicInfo can be opened only once!");
return false;
}
if (nullptr == (hResInfo = FindResourceW(HINST_THISCOMPONENT, MAKEINTRESOURCE(resNameId), (LPCWSTR)resType)))
if (nullptr == (hResInfo = FindResourceW(HINST_THISCOMPONENT, MAKEINTRESOURCE(res.getResNameId()), (LPCWSTR)res.getResType())))
return TraceError(L"FindResource");
if (nullptr == (hResData = LoadResource(HINST_THISCOMPONENT, hResInfo)))
@ -183,6 +110,38 @@ bool e2d::Music::open(int resNameId, const e2d::String& resType)
mmioInfo.pchBuffer = (CHAR*)_resBuffer;
_hmmio = mmioOpen(nullptr, &mmioInfo, MMIO_ALLOCBUF | MMIO_READ);
}
else
{
String filePath = res.getFileName();
if (filePath.isEmpty())
{
WARN("MusicInfo::open Invalid file name.");
return false;
}
String actualFilePath = File(filePath).getFilePath();
if (actualFilePath.isEmpty())
{
WARN("MusicInfo::open File not found.");
return false;
}
// ¶¨Î» wave Îļþ
wchar_t pFilePath[MAX_PATH];
if (!_findMediaFileCch(pFilePath, MAX_PATH, (const wchar_t *)actualFilePath))
{
WARN("Failed to find media file: %s", pFilePath);
return false;
}
_hmmio = mmioOpen(pFilePath, nullptr, MMIO_ALLOCBUF | MMIO_READ);
}
if (nullptr == _hmmio)
{
return TraceError(L"mmioOpen");
}
if (!_readMMIO())
{

View File

@ -1,6 +1,5 @@
#include "..\e2dtool.h"
#include <algorithm>
#include <commdlg.h>
extern "C" const GUID DECLSPEC_SELECTANY FOLDERID_LocalAppData = {
@ -8,49 +7,33 @@ extern "C" const GUID DECLSPEC_SELECTANY FOLDERID_LocalAppData = {
};
e2d::String e2d::Path::_tempPath;
e2d::String e2d::Path::_dataPath;
std::list<e2d::String> e2d::Path::_paths;
void e2d::Path::addSearchPath(String path)
{
path.replace(L"/", L"\\");
if (path[path.getLength() - 1] != L'\\')
{
path << L"\\";
}
auto iter = std::find(_paths.cbegin(), _paths.cend(), path);
if (iter == _paths.cend())
{
_paths.push_front(path);
}
}
e2d::String e2d::Path::getDataPath()
{
if (_dataPath.isEmpty())
static String dataPath;
if (dataPath.isEmpty())
{
// 设置数据的保存路径
String localAppDataPath = Path::getLocalAppDataPath();
String gameName = Game::getInstance()->getConfig()->getGameName();
if (!localAppDataPath.isEmpty() && !gameName.isEmpty())
{
_dataPath = localAppDataPath + L"\\Easy2DGameData\\" << gameName << L"\\";
dataPath = localAppDataPath + L"\\Easy2DGameData\\" << gameName << L"\\";
if (!Path::exists(_dataPath) && !Path::createFolder(_dataPath))
File file(dataPath);
if (!file.exists() && !File::createFolder(dataPath))
{
_dataPath = L"";
dataPath = L"";
}
}
_dataPath << L"Data.ini";
dataPath << L"Data.ini";
}
return _dataPath;
return dataPath;
}
e2d::String e2d::Path::getTempPath()
{
if (_tempPath.isEmpty())
static String tempPath;
if (tempPath.isEmpty())
{
// 设置临时文件保存路径
wchar_t path[_MAX_PATH];
@ -58,15 +41,16 @@ e2d::String e2d::Path::getTempPath()
if (0 != ::GetTempPath(_MAX_PATH, path) && !gameName.isEmpty())
{
_tempPath << path << L"\\Easy2DGameTemp\\" << gameName << L"\\";
tempPath << path << L"\\Easy2DGameTemp\\" << gameName << L"\\";
if (!Path::exists(_tempPath) && !Path::createFolder(_tempPath))
File file(tempPath);
if (!file.exists() && !File::createFolder(tempPath))
{
_tempPath = L"";
tempPath = L"";
}
}
}
return _tempPath;
return tempPath;
}
e2d::String e2d::Path::getLocalAppDataPath()
@ -94,134 +78,14 @@ e2d::String e2d::Path::getLocalAppDataPath()
e2d::String e2d::Path::getCurrentFilePath()
{
static String currFilePath;
if (currFilePath.isEmpty())
{
TCHAR szPath[_MAX_PATH] = { 0 };
if (::GetModuleFileName(nullptr, szPath, _MAX_PATH) != 0)
{
return std::move(String(szPath));
currFilePath = szPath;
}
return std::move(String());
}
e2d::String e2d::Path::findFile(const String& path)
{
if (Path::exists(path))
{
return path;
}
else
{
for (auto& resPath : _paths)
{
if (Path::exists(resPath + path))
{
return resPath + path;
}
}
}
return std::move(String());
}
e2d::String e2d::Path::extractResource(int resNameId, const String & resType, const String & destFileName)
{
String destFilePath = _tempPath + destFileName;
// 创建文件
HANDLE hFile = ::CreateFile((LPCWSTR)destFilePath, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return std::move(String());
// 查找资源文件中、加载资源到内存、得到资源大小
HRSRC hRes = ::FindResource(NULL, MAKEINTRESOURCE(resNameId), (LPCWSTR)resType);
HGLOBAL hMem = ::LoadResource(NULL, hRes);
DWORD dwSize = ::SizeofResource(NULL, hRes);
if (hRes && hMem && dwSize)
{
// 写入文件
DWORD dwWrite = 0;
::WriteFile(hFile, hMem, dwSize, &dwWrite, NULL);
::CloseHandle(hFile);
return destFilePath;
}
else
{
::CloseHandle(hFile);
::DeleteFile((LPCWSTR)destFilePath);
return std::move(String());
}
}
e2d::String e2d::Path::getFileExtension(const String& filePath)
{
String fileExtension;
// 找到文件名中的最后一个 '.' 的位置
size_t pos = filePath.getWString().find_last_of(L'.');
// 判断 pos 是否是有效位置
if (pos != std::wstring::npos)
{
// 截取扩展名
fileExtension = filePath.subtract(static_cast<int>(pos));
// 转换为小写字母
fileExtension = fileExtension.toLower();
}
return fileExtension;
}
e2d::String e2d::Path::getSaveFilePath(const String& title, const String& defExt)
{
// 弹出保存对话框
OPENFILENAME ofn = { 0 };
wchar_t strFilename[MAX_PATH] = { 0 }; // 用于接收文件名
ofn.lStructSize = sizeof(OPENFILENAME); // 结构体大小
ofn.hwndOwner = Window::getInstance()->getHWnd(); // 窗口句柄
ofn.lpstrFilter = L"所有文件\0*.*\0\0"; // 设置过滤
ofn.nFilterIndex = 1; // 过滤器索引
ofn.lpstrFile = strFilename; // 接收返回的文件路径和文件名
ofn.nMaxFile = sizeof(strFilename); // 缓冲区长度
ofn.lpstrInitialDir = nullptr; // 初始目录为默认
ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
ofn.lpstrTitle = (LPCWSTR)title; // 标题
ofn.lpstrDefExt = (LPCWSTR)defExt; // 默认追加的扩展名
if (GetSaveFileName(&ofn))
{
return strFilename;
}
return std::move(String());
}
bool e2d::Path::createFolder(const String& dirPath)
{
if (dirPath.isEmpty() || dirPath.getLength() >= MAX_PATH)
{
return false;
}
wchar_t tmpDirPath[_MAX_PATH] = { 0 };
int length = dirPath.getLength();
for (int i = 0; i < length; ++i)
{
tmpDirPath[i] = dirPath.at(i);
if (tmpDirPath[i] == L'\\' || tmpDirPath[i] == L'/' || i == (length - 1))
{
if (::_waccess(tmpDirPath, 0) != 0)
{
if (::_wmkdir(tmpDirPath) != 0)
{
return false;
}
}
}
}
return true;
}
bool e2d::Path::exists(const String & path)
{
if (path.isEmpty() || path.getLength() >= MAX_PATH)
{
return false;
}
return ::_waccess((const wchar_t *)path, 0) == 0;
}
return currFilePath;
}

View File

@ -13,10 +13,6 @@ e2d::Player::Player()
e2d::Player::~Player()
{
for (auto pair : _fileList)
GC::release(pair.second);
_fileList.clear();
for (auto pair : _resList)
GC::release(pair.second);
_resList.clear();
@ -61,67 +57,42 @@ IXAudio2 * e2d::Player::getXAudio2()
bool e2d::Player::preload(const String& filePath)
{
UINT hash = filePath.getHashCode();
if (_fileList.end() != _fileList.find(hash))
{
return true;
}
else
{
Music * music = new (e2d::autorelease) Music();
if (music->open(filePath))
{
GC::retain(music);
music->setVolume(_volume);
_fileList.insert(std::pair<UINT, Music *>(hash, music));
return true;
}
}
if (filePath.isEmpty())
return false;
return preload(Resource(filePath));
}
bool e2d::Player::preload(int resNameId, const String& resType)
bool e2d::Player::preload(const Resource& res)
{
if (_resList.end() != _resList.find(resNameId))
{
if (_resList.end() != _resList.find(res))
return true;
}
else
{
Music * music = new (e2d::autorelease) Music();
if (music->open(resNameId, resType))
if (music->open(res))
{
GC::retain(music);
music->setVolume(_volume);
_resList.insert(std::pair<UINT, Music *>(resNameId, music));
_resList.insert(std::make_pair(res, music));
return true;
}
}
return false;
}
bool e2d::Player::play(const String& filePath, int nLoopCount)
{
if (Player::preload(filePath))
{
UINT hash = filePath.getHashCode();
auto music = _fileList[hash];
if (music->play(nLoopCount))
{
return true;
}
}
if (filePath.isEmpty())
return false;
return play(Resource(filePath), nLoopCount);
}
bool e2d::Player::play(int resNameId, const String& resType, int nLoopCount)
bool e2d::Player::play(const Resource& res, int nLoopCount)
{
if (Player::preload(resNameId, resType))
if (Player::preload(res))
{
auto music = _resList[resNameId];
auto music = _resList[res];
if (music->play(nLoopCount))
{
return true;
@ -135,16 +106,13 @@ void e2d::Player::pause(const String& filePath)
if (filePath.isEmpty())
return;
UINT hash = filePath.getHashCode();
if (_fileList.end() != _fileList.find(hash))
_fileList[hash]->pause();
pause(Resource(filePath));
}
void e2d::Player::pause(int resNameId, const String& resType)
void e2d::Player::pause(const Resource& res)
{
if (_resList.end() != _resList.find(resNameId))
_resList[resNameId]->pause();
if (_resList.end() != _resList.find(res))
_resList[res]->pause();
}
void e2d::Player::resume(const String& filePath)
@ -152,16 +120,13 @@ void e2d::Player::resume(const String& filePath)
if (filePath.isEmpty())
return;
UINT hash = filePath.getHashCode();
if (_fileList.end() != _fileList.find(hash))
_fileList[hash]->resume();
resume(Resource(filePath));
}
void e2d::Player::resume(int resNameId, const String& resType)
void e2d::Player::resume(const Resource& res)
{
if (_resList.end() != _resList.find(resNameId))
_resList[resNameId]->pause();
if (_resList.end() != _resList.find(res))
_resList[res]->pause();
}
void e2d::Player::stop(const String& filePath)
@ -169,16 +134,17 @@ void e2d::Player::stop(const String& filePath)
if (filePath.isEmpty())
return;
UINT hash = filePath.getHashCode();
if (_fileList.end() != _fileList.find(hash))
_fileList[hash]->stop();
stop(Resource(filePath));
}
void e2d::Player::stop(int resNameId, const String& resType)
void e2d::Player::stop(const Resource& res)
{
if (_resList.end() != _resList.find(resNameId))
_resList[resNameId]->stop();
if (res.isResource())
{
}
if (_resList.end() != _resList.find(res))
_resList[res]->stop();
}
bool e2d::Player::isPlaying(const String& filePath)
@ -186,18 +152,13 @@ bool e2d::Player::isPlaying(const String& filePath)
if (filePath.isEmpty())
return false;
UINT hash = filePath.getHashCode();
if (_fileList.end() != _fileList.find(hash))
return _fileList[hash]->isPlaying();
return false;
return isPlaying(Resource(filePath));
}
bool e2d::Player::isPlaying(int resNameId, const String& resType)
bool e2d::Player::isPlaying(const Resource& res)
{
if (_resList.end() != _resList.find(resNameId))
return _resList[resNameId]->isPlaying();
if (_resList.end() != _resList.find(res))
return _resList[res]->isPlaying();
return false;
}
@ -209,11 +170,6 @@ double e2d::Player::getVolume()
void e2d::Player::setVolume(double volume)
{
_volume = std::min(std::max(float(volume), -224.f), 224.f);
for (auto pair : _fileList)
{
pair.second->setVolume(_volume);
}
for (auto pair : _resList)
{
pair.second->setVolume(_volume);
@ -222,11 +178,6 @@ void e2d::Player::setVolume(double volume)
void e2d::Player::pauseAll()
{
for (auto pair : _fileList)
{
pair.second->pause();
}
for (auto pair : _resList)
{
pair.second->pause();
@ -235,11 +186,6 @@ void e2d::Player::pauseAll()
void e2d::Player::resumeAll()
{
for (auto pair : _fileList)
{
pair.second->resume();
}
for (auto pair : _resList)
{
pair.second->resume();
@ -248,11 +194,6 @@ void e2d::Player::resumeAll()
void e2d::Player::stopAll()
{
for (auto pair : _fileList)
{
pair.second->stop();
}
for (auto pair : _resList)
{
pair.second->stop();
@ -261,12 +202,6 @@ void e2d::Player::stopAll()
void e2d::Player::clearCache()
{
for (auto pair : _fileList)
{
GC::release(pair.second);
}
_fileList.clear();
for (auto pair : _resList)
{
GC::release(pair.second);

View File

@ -521,6 +521,44 @@ protected:
};
// 资源
class Resource
{
public:
Resource(
const String& fileName /* 文件路径 */
);
Resource(
int resNameId, /* 资源名称 */
const String& resType /* 资源类型 */
);
// 是否是资源类型
bool isResource() const;
const String& getFileName() const;
int getResNameId() const;
const String& getResType() const;
int getKey() const;
// 比较运算符
bool operator> (const Resource &) const;
bool operator>= (const Resource &) const;
bool operator< (const Resource &) const;
bool operator<= (const Resource &) const;
protected:
bool _isResource;
String _fileName;
int _resNameId;
String _resType;
};
// 引用计数对象
class Ref
{
@ -554,36 +592,33 @@ public:
Image();
explicit Image(
const String& filePath /* 图片文件路径 */
const Resource& res
);
explicit Image(
int resNameId, /* 图片资源名称 */
const String& resType /* 图片资源类型 */
);
explicit Image(
const String& filePath, /* 图片文件路径 */
const Resource& res,
const Rect& cropRect /* 裁剪矩形 */
);
explicit Image(
int resNameId, /* 图片资源名称 */
const String& resType, /* 图片资源类型 */
const String& fileName
);
explicit Image(
const String& fileName,
const Rect& cropRect /* 裁剪矩形 */
);
virtual ~Image();
// 加载图片文件
// 加载图片资源
bool open(
const String& filePath /* 图片文件路径 */
const Resource& res
);
// 加载图片资源
bool open(
int resNameId, /* 图片资源名称 */
const String& resType /* 图片资源类型 */
const String& fileName
);
// 将图片裁剪为矩形
@ -621,15 +656,9 @@ public:
// 获取 ID2D1Bitmap 对象
ID2D1Bitmap * getBitmap();
// 预加载图片文件
static bool preload(
const String& filePath /* 图片文件路径 */
);
// 预加载图片资源
static bool preload(
int resNameId, /* 图片资源名称 */
const String& resType /* 图片资源类型 */
const Resource& res
);
// 清空缓存

View File

@ -452,22 +452,20 @@ public:
);
explicit Sprite(
const String& filePath /* 图片文件路径 */
const Resource& res
);
explicit Sprite(
int resNameId, /* 图片资源名称 */
const String& resType /* 图片资源类型 */
);
explicit Sprite(
const String& filePath, /* 图片文件路径 */
const Resource& res,
const Rect& cropRect /* 裁剪矩形 */
);
explicit Sprite(
int resNameId, /* 图片资源名称 */
const String& resType, /* 图片资源类型 */
const String& fileName
);
explicit Sprite(
const String& fileName,
const Rect& cropRect /* 裁剪矩形 */
);
@ -475,13 +473,12 @@ public:
// 加载图片文件
bool open(
const String& filePath
const Resource& res
);
// 加载图片资源
// 加载图片文件
bool open(
int resNameId, /* 图片资源名称 */
const String& resType /* 图片资源类型 */
const String& fileName
);
// 加载图片

View File

@ -62,8 +62,7 @@ public:
);
explicit Music(
int resNameId, /* 音乐资源名称 */
const String& resType /* 音乐资源类型 */
const Resource& res
);
virtual ~Music();
@ -75,8 +74,7 @@ public:
// 打开音乐资源
bool open(
int resNameId, /* 音乐资源名称 */
const String& resType /* 音乐资源类型 */
const Resource& res
);
// 播放
@ -152,7 +150,7 @@ protected:
class Player
{
friend class Game;
typedef std::map<UINT, Music*> MusicMap;
typedef std::map<Resource, Music*> MusicMap;
public:
// 获取播放器实例
@ -194,39 +192,33 @@ public:
// 预加载音乐资源
bool preload(
int resNameId, /* 音乐资源名称 */
const String& resType /* 音乐资源类型 */
const Resource& res /* 音乐资源 */
);
// 播放音乐
bool play(
int resNameId, /* 音乐资源名称 */
const String& resType, /* 音乐资源类型 */
const Resource& res, /* 音乐资源 */
int nLoopCount = 0 /* 重复播放次数,设置 -1 为循环播放 */
);
// 暂停音乐
void pause(
int resNameId, /* 音乐资源名称 */
const String& resType /* 音乐资源类型 */
const Resource& res /* 音乐资源 */
);
// 继续播放音乐
void resume(
int resNameId, /* 音乐资源名称 */
const String& resType /* 音乐资源类型 */
const Resource& res /* 音乐资源 */
);
// 停止音乐
void stop(
int resNameId, /* 音乐资源名称 */
const String& resType /* 音乐资源类型 */
const Resource& res /* 音乐资源 */
);
// 获取音乐播放状态
bool isPlaying(
int resNameId, /* 音乐资源名称 */
const String& resType /* 音乐资源类型 */
const Resource& res /* 音乐资源 */
);
// 获取音量
@ -261,7 +253,6 @@ private:
private:
float _volume;
MusicMap _fileList;
MusicMap _resList;
IXAudio2* _xAudio2;
IXAudio2MasteringVoice* _masteringVoice;
@ -504,29 +495,75 @@ public:
};
// 路径工具
class Path
// 文件
class File
{
friend class Game;
public:
// 添加资源搜索路径
static void addSearchPath(
String path
File();
File(
const String& fileName
);
// 检索文件路径
static String findFile(
const String& path
virtual ~File();
// 打开文件
bool open(
const String& fileName
);
// 提取资源文件,返回提取后的文件路径
static String extractResource(
// 文件或文件夹是否存在
bool exists() const;
// 是否是文件夹
bool isFolder() const;
// 删除文件
bool deleteFile();
// 获取文件路径
String getFilePath() const;
// 获取文件扩展名
String getExtension() const;
// 释放资源到临时文件目录
static File extract(
int resNameId, /* 资源名称 */
const String& resType, /* 资源类型 */
const String& destFileName /* 目标文件名 */
);
// 添加文件搜索路径
static void addSearchPath(
const String& path
);
// 创建文件夹
static bool createFolder(
const String& dirPath /* 文件夹路径 */
);
// 打开保存文件对话框
static String getSaveFilePath(
const String& title = L"保存到", /* 对话框标题 */
const String& defExt = L"" /* 默认扩展名 */
);
protected:
DWORD _attributes;
String _fileName;
static std::list<String> _searchPaths;
};
// 路径
class Path
{
friend class Game;
public:
// 获取数据的默认保存路径
static String getDataPath();
@ -538,32 +575,6 @@ public:
// 获取当前程序的运行路径
static String getCurrentFilePath();
// 获取文件扩展名
static String getFileExtension(
const String& filePath
);
// 打开保存文件对话框
static String getSaveFilePath(
const String& title = L"保存到", /* 对话框标题 */
const String& defExt = L"" /* 默认扩展名 */
);
// 创建文件夹
static bool createFolder(
const String& dirPath /* 文件夹路径 */
);
// 判断文件或文件夹是否存在
static bool exists(
const String& dirPath /* 文件夹路径 */
);
private:
static String _tempPath;
static String _dataPath;
static std::list<String> _paths;
};
}

View File

@ -230,6 +230,7 @@
<ClCompile Include="..\..\core\Common\Point.cpp" />
<ClCompile Include="..\..\core\Common\Rect.cpp" />
<ClCompile Include="..\..\core\Common\Ref.cpp" />
<ClCompile Include="..\..\core\Common\Resource.cpp" />
<ClCompile Include="..\..\core\Common\Scene.cpp" />
<ClCompile Include="..\..\core\Common\Size.cpp" />
<ClCompile Include="..\..\core\Common\String.cpp" />
@ -253,6 +254,7 @@
<ClCompile Include="..\..\core\Node\Sprite.cpp" />
<ClCompile Include="..\..\core\Node\Text.cpp" />
<ClCompile Include="..\..\core\Tool\Data.cpp" />
<ClCompile Include="..\..\core\Tool\File.cpp" />
<ClCompile Include="..\..\core\Tool\Listener.cpp" />
<ClCompile Include="..\..\core\Tool\Music.cpp" />
<ClCompile Include="..\..\core\Tool\Path.cpp" />

View File

@ -240,6 +240,12 @@
<ClCompile Include="..\..\core\Common\Ref.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="..\..\core\Tool\File.cpp">
<Filter>Tool</Filter>
</ClCompile>
<ClCompile Include="..\..\core\Common\Resource.cpp">
<Filter>Common</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\core\easy2d.h" />