#include "..\enodes.h" #include struct ResKey { ResKey() { resNameHash = 0; resTypeHash = 0; } bool operator < (ResKey const& key) const { if (resNameHash > key.resNameHash) return true; else if (resNameHash == key.resNameHash) return resTypeHash > key.resTypeHash; else return false; } size_t resNameHash; size_t resTypeHash; }; static std::map s_mBitmapsFromFile; static std::map s_mBitmapsFromResource; static ID2D1Bitmap * GetBitmapFromFile(const e2d::EString & fileName); static ID2D1Bitmap * GetBitmapFromResource(const e2d::EString & resourceName, const e2d::EString & resourceType); e2d::ESprite::ESprite() : m_pBitmap(nullptr) , m_fSourcePosX(0) , m_fSourcePosY(0) , m_fSourceWidth(0) , m_fSourceHeight(0) { } e2d::ESprite::ESprite(const EString & imageFileName) : ESprite() { setImage(imageFileName); } e2d::ESprite::ESprite(const EString & imageFileName, float x, float y, float width, float height) { setImage(imageFileName); clipImage(x, y, width, height); } e2d::ESprite::ESprite(const EString & resourceName, const EString & resourceType) : ESprite() { setImage(resourceName, resourceType); } e2d::ESprite::ESprite(const EString & resourceName, const EString & resourceType, float x, float y, float width, float height) { setImage(resourceName, resourceType); clipImage(x, y, width, height); } float e2d::ESprite::getWidth() const { return m_fSourceWidth * m_fScaleX; } float e2d::ESprite::getHeight() const { return m_fSourceHeight * m_fScaleY; } e2d::ESize e2d::ESprite::getSize() const { return ESize(getWidth(), getHeight()); } float e2d::ESprite::getRealWidth() const { return m_fSourceWidth; } float e2d::ESprite::getRealHeight() const { return m_fSourceHeight; } e2d::ESize e2d::ESprite::getRealSize() const { return ESize(m_fSourceWidth, m_fSourceHeight); } void e2d::ESprite::setWidth(float) { } void e2d::ESprite::setHeight(float) { } void e2d::ESprite::setSize(float, float) { } void e2d::ESprite::setImage(const EString & fileName) { WARN_IF(fileName.empty(), "ESprite cannot load bitmap from NULL file name."); if (fileName.empty() || m_sFileName == fileName) return; m_sFileName = fileName; SafeReleaseInterface(&m_pBitmap); m_pBitmap = GetBitmapFromFile(m_sFileName); ASSERT(m_pBitmap, "ESprite create device resources failed!"); m_fSourcePosX = m_fSourcePosY = 0; m_fSourceWidth = m_pBitmap->GetSize().width; m_fSourceHeight = m_pBitmap->GetSize().height; } void e2d::ESprite::setImage(const EString & fileName, float x, float y, float width, float height) { setImage(fileName); clipImage(x, y, width, height); } void e2d::ESprite::setImage(const EString & resourceName, const EString & resourceType) { WARN_IF(resourceName.empty() || resourceType.empty(), "ESprite cannot load bitmap from NULL resource."); if (resourceName.empty() || resourceType.empty()) return; if (m_sResourceName == resourceName && m_sResourceType == resourceType) return; if (!m_sFileName.empty()) m_sFileName.clear(); m_sResourceName = resourceName; m_sResourceType = resourceType; SafeReleaseInterface(&m_pBitmap); m_pBitmap = GetBitmapFromResource(resourceName, resourceType); ASSERT(m_pBitmap, "ESprite create device resources failed!"); m_fSourcePosX = m_fSourcePosY = 0; m_fSourceWidth = m_pBitmap->GetSize().width; m_fSourceHeight = m_pBitmap->GetSize().height; } void e2d::ESprite::setImage(const EString & resourceName, const EString & resourceType, float x, float y, float width, float height) { setImage(resourceName, resourceType); clipImage(x, y, width, height); } void e2d::ESprite::clipImage(float x, float y, float width, float height) { m_fSourcePosX = max(x, 0); m_fSourcePosY = max(y, 0); m_fSourceWidth = min(max(width, 0), m_pBitmap->GetSize().width - m_fSourcePosX); m_fSourceHeight = min(max(height, 0), m_pBitmap->GetSize().width - m_fSourcePosX); } void e2d::ESprite::_onRender() { if (m_pBitmap) { // Draw bitmap GetRenderTarget()->DrawBitmap( m_pBitmap, D2D1::RectF(0, 0, m_fSourceWidth, m_fSourceHeight), m_fDisplayOpacity, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, D2D1::RectF(m_fSourcePosX, m_fSourcePosY, m_fSourceWidth, m_fSourceHeight) ); } } bool e2d::ESprite::preloadImage(const EString & fileName) { std::hash h; size_t hash = h(fileName); if (s_mBitmapsFromFile.find(hash) != s_mBitmapsFromFile.end()) { return true; } HRESULT hr = S_OK; IWICBitmapDecoder *pDecoder = nullptr; IWICBitmapFrameDecode *pSource = nullptr; IWICStream *pStream = nullptr; IWICFormatConverter *pConverter = nullptr; ID2D1Bitmap *pBitmap = nullptr; // 创建解码器 hr = GetImagingFactory()->CreateDecoderFromFilename( fileName.c_str(), NULL, GENERIC_READ, WICDecodeMetadataCacheOnLoad, &pDecoder ); if (SUCCEEDED(hr)) { // 创建初始化框架 hr = pDecoder->GetFrame(0, &pSource); } if (SUCCEEDED(hr)) { // 创建图片格式转换器 // (DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED). hr = GetImagingFactory()->CreateFormatConverter(&pConverter); } if (SUCCEEDED(hr)) { // 图片格式转换成 32bbpPBGRA hr = pConverter->Initialize( pSource, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0.f, WICBitmapPaletteTypeMedianCut ); } if (SUCCEEDED(hr)) { // 从 WIC 位图创建一个 Direct2D 位图 hr = GetRenderTarget()->CreateBitmapFromWicBitmap( pConverter, NULL, &pBitmap ); } if (SUCCEEDED(hr)) { // 保存图片指针和图片的 Hash 名 std::hash h; size_t hash = h(fileName); s_mBitmapsFromFile.insert( std::map::value_type( hash, pBitmap) ); } // 释放相关资源 SafeReleaseInterface(&pDecoder); SafeReleaseInterface(&pSource); SafeReleaseInterface(&pStream); SafeReleaseInterface(&pConverter); return SUCCEEDED(hr); } bool e2d::ESprite::preloadImage(const EString & resourceName, const EString & resourceType) { std::hash h; ResKey key; key.resNameHash = h(resourceName); key.resTypeHash = h(resourceType); if (s_mBitmapsFromResource.find(key) != s_mBitmapsFromResource.end()) { return true; } HRESULT hr = S_OK; IWICBitmapDecoder *pDecoder = nullptr; IWICBitmapFrameDecode *pSource = nullptr; IWICStream *pStream = nullptr; IWICFormatConverter *pConverter = nullptr; IWICBitmapScaler *pScaler = nullptr; ID2D1Bitmap *pBitmap = nullptr; HRSRC imageResHandle = nullptr; HGLOBAL imageResDataHandle = nullptr; void *pImageFile = nullptr; DWORD imageFileSize = 0; // 定位资源 imageResHandle = ::FindResourceW(HINST_THISCOMPONENT, resourceName.c_str(), resourceType.c_str()); hr = imageResHandle ? S_OK : E_FAIL; if (SUCCEEDED(hr)) { // 加载资源 imageResDataHandle = ::LoadResource(HINST_THISCOMPONENT, imageResHandle); hr = imageResDataHandle ? S_OK : E_FAIL; } if (SUCCEEDED(hr)) { // 获取文件指针,并锁定资源 pImageFile = ::LockResource(imageResDataHandle); hr = pImageFile ? S_OK : E_FAIL; } if (SUCCEEDED(hr)) { // 计算大小 imageFileSize = SizeofResource(HINST_THISCOMPONENT, imageResHandle); hr = imageFileSize ? S_OK : E_FAIL; } if (SUCCEEDED(hr)) { // 创建 WIC 流 hr = GetImagingFactory()->CreateStream(&pStream); } if (SUCCEEDED(hr)) { // 初始化流 hr = pStream->InitializeFromMemory( reinterpret_cast(pImageFile), imageFileSize ); } if (SUCCEEDED(hr)) { // 创建流的解码器 hr = GetImagingFactory()->CreateDecoderFromStream( pStream, NULL, WICDecodeMetadataCacheOnLoad, &pDecoder ); } if (SUCCEEDED(hr)) { // 创建初始化框架 hr = pDecoder->GetFrame(0, &pSource); } if (SUCCEEDED(hr)) { // 创建图片格式转换器 // (DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED). hr = GetImagingFactory()->CreateFormatConverter(&pConverter); } if (SUCCEEDED(hr)) { // 图片格式转换成 32bppPBGRA hr = pConverter->Initialize( pSource, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0.f, WICBitmapPaletteTypeMedianCut ); } if (SUCCEEDED(hr)) { // 从 WIC 位图创建一个 Direct2D 位图 hr = GetRenderTarget()->CreateBitmapFromWicBitmap( pConverter, NULL, &pBitmap ); } if (SUCCEEDED(hr)) { std::hash h; ResKey key; key.resNameHash = h(resourceName); key.resTypeHash = h(resourceType); s_mBitmapsFromResource.insert( std::map::value_type( key, pBitmap) ); } // 释放相关资源 SafeReleaseInterface(&pDecoder); SafeReleaseInterface(&pSource); SafeReleaseInterface(&pStream); SafeReleaseInterface(&pConverter); SafeReleaseInterface(&pScaler); return SUCCEEDED(hr); } void e2d::ESprite::clearCache() { for (auto child : s_mBitmapsFromFile) { SafeReleaseInterface(&child.second); } for (auto child : s_mBitmapsFromResource) { SafeReleaseInterface(&child.second); } s_mBitmapsFromFile.clear(); s_mBitmapsFromResource.clear(); } ID2D1Bitmap * GetBitmapFromFile(const e2d::EString & fileName) { if (!e2d::ESprite::preloadImage(fileName)) { return nullptr; } std::hash h; size_t hash = h(fileName); return s_mBitmapsFromFile.at(hash); } ID2D1Bitmap * GetBitmapFromResource(const e2d::EString & resourceName, const e2d::EString & resourceType) { if (!e2d::ESprite::preloadImage(resourceName, resourceType)) { return nullptr; } ResKey key; std::hash h; key.resNameHash = h(resourceName); key.resTypeHash = h(resourceType); return s_mBitmapsFromResource.at(key); }