diff --git a/ConsoleDemo/main.cpp b/ConsoleDemo/main.cpp index b3112a46..9d3e6070 100644 --- a/ConsoleDemo/main.cpp +++ b/ConsoleDemo/main.cpp @@ -10,7 +10,7 @@ int main() auto node = new ENode(); node->setPos(50, 80); - node->setSize(30, 180); + node->_setSize(30, 180); scene->add(node); /*auto listener = new EMouseListener([=] { diff --git a/Demo/main.cpp b/Demo/main.cpp index 53fb42be..8b21a0b1 100644 --- a/Demo/main.cpp +++ b/Demo/main.cpp @@ -14,25 +14,16 @@ int WINAPI WinMain( { auto scene = new EScene(); - auto sprite = new ESprite(L"test.png"); - sprite->setAnchor(0.5f, 0.5f); - sprite->setPos(EApp::getWidth() / 2, sprite->getHeight() / 2); + auto text = new EText(L"中文测试中文测试中文测试中文测试中文测试中文测试中文测试", EColor::WHITE, L"Microsoft Yahei"); + text->setPos(EApp::getWidth() / 2, EApp::getHeight() / 2); + //text->setWordWrapping(true); + //text->setWordWrappingWidth(130); + text->setRotation(40); + text->getFont()->setItalic(true); + text->setAnchor(0.5f, 0.5f); + text->setColor(EColor::WHITE); + scene->add(text); - auto sprite2 = new ESprite(L"test.png"); - sprite2->setPos(30, 0); - sprite2->setScale(0.5); - sprite2->setRotation(45); - - sprite->addChild(sprite2); - - auto mlistener = new EMouseDoubleClickListener([=](EPoint p) { - //sprite->setRotation(sprite->getRotation() + 10); - EApp::setWindowSize(640, 480); - }); - - mlistener->bindWith(sprite); - - scene->add(sprite); app.enterScene(scene); app.run(); } diff --git a/Easy2D/Base/EApp.cpp b/Easy2D/Base/EApp.cpp index d77c0308..2e4bb6ef 100644 --- a/Easy2D/Base/EApp.cpp +++ b/Easy2D/Base/EApp.cpp @@ -13,16 +13,16 @@ using namespace std::chrono; // 唯一实例指针 -e2d::EApp * s_pInstance = nullptr; +static e2d::EApp * s_pInstance = nullptr; // 场景栈 -std::stack s_SceneStack; +static std::stack s_SceneStack; // 游戏开始时间 static steady_clock::time_point s_tStart; e2d::EApp::EApp() : m_bRunning(false) , nAnimationInterval(17LL) - , m_ClearColor(EColor::Black) + , m_ClearColor(EColor::BLACK) , m_pCurrentScene(nullptr) , m_pNextScene(nullptr) { @@ -91,8 +91,12 @@ bool e2d::EApp::init(const EString &title, UINT32 width, UINT32 height, int wind height = static_cast(ceil(height * dpiY / 96.f)); // 获取屏幕分辨率 - int screenWidth = GetSystemMetrics(SM_CXSCREEN); - int screenHeight = GetSystemMetrics(SM_CYSCREEN); + UINT screenWidth = static_cast(GetSystemMetrics(SM_CXSCREEN)); + UINT screenHeight = static_cast(GetSystemMetrics(SM_CYSCREEN)); + // 当输入的窗口大小比分辨率大时,给出警告 + WARN_IF(screenWidth < width || screenHeight < height, "The window is larger than screen!"); + width = min(width, screenWidth); + height = min(height, screenHeight); // 创建屏幕居中的矩形 RECT rtWindow; rtWindow.left = (screenWidth - width) / 2; @@ -230,8 +234,9 @@ void e2d::EApp::onActivate() { } -void e2d::EApp::onInactive() +bool e2d::EApp::onInactive() { + return true; } bool e2d::EApp::onCloseWindow() @@ -310,7 +315,7 @@ bool e2d::EApp::_onRender() { GetRenderTarget()->BeginDraw(); // 使用背景色清空屏幕 - GetRenderTarget()->Clear(D2D1::ColorF(m_ClearColor)); + GetRenderTarget()->Clear(D2D1::ColorF(m_ClearColor.value)); // 绘制当前场景 m_pCurrentScene->_onRender(); @@ -480,7 +485,7 @@ void e2d::EApp::free() s_SceneStack.pop(); } // 删除图片缓存 - ESprite::clearCache(); + ETexture::clearCache(); // 删除所有对象 EObjectManager::clearAllObjects(); } @@ -671,9 +676,11 @@ LRESULT e2d::EApp::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam { if (LOWORD(wParam) == WA_INACTIVE) { - pEApp->getCurrentScene()->onInactive(); - pEApp->onInactive(); - pEApp->m_bPaused = true; + if (pEApp->getCurrentScene()->onInactive() && + pEApp->onInactive()) + { + pEApp->m_bPaused = true; + } } else { diff --git a/Easy2D/Base/EScene.cpp b/Easy2D/Base/EScene.cpp index 535398a9..cf83b0fd 100644 --- a/Easy2D/Base/EScene.cpp +++ b/Easy2D/Base/EScene.cpp @@ -30,8 +30,9 @@ void e2d::EScene::onActivate() { } -void e2d::EScene::onInactive() +bool e2d::EScene::onInactive() { + return true; } bool e2d::EScene::onCloseWindow() diff --git a/Easy2D/Easy2D.vcxproj b/Easy2D/Easy2D.vcxproj index 4b270f11..711ea382 100644 --- a/Easy2D/Easy2D.vcxproj +++ b/Easy2D/Easy2D.vcxproj @@ -206,9 +206,10 @@ - + + diff --git a/Easy2D/Easy2D.vcxproj.filters b/Easy2D/Easy2D.vcxproj.filters index a7c22c1f..cd427cd4 100644 --- a/Easy2D/Easy2D.vcxproj.filters +++ b/Easy2D/Easy2D.vcxproj.filters @@ -54,9 +54,6 @@ Tool - - Node - Node @@ -81,6 +78,12 @@ Node + + Node + + + Node + diff --git a/Easy2D/Node/EFont.cpp b/Easy2D/Node/EFont.cpp new file mode 100644 index 00000000..69515376 --- /dev/null +++ b/Easy2D/Node/EFont.cpp @@ -0,0 +1,91 @@ +#include "..\enodes.h" +#include "..\Win\winbase.h" + +e2d::EFont::EFont() + : m_pTextFormat(nullptr) + , m_fFontSize(22) + , m_FontWeight(EFontWeight::REGULAR) + , m_bItalic(false) + , m_bRecreateNeeded(true) +{ +} + +e2d::EFont::EFont(EString fontFamily, float fontSize, EFontWeight fontWeight, bool italic) +{ + this->setFamily(fontFamily); + this->setSize(fontSize); + this->setWeight(fontWeight); + this->setItalic(italic); +} + +e2d::EFont::~EFont() +{ + SafeReleaseInterface(&m_pTextFormat); +} + +float e2d::EFont::getFontSize() const +{ + return m_fFontSize; +} + +e2d::EFontWeight e2d::EFont::getFontWeight() const +{ + return m_FontWeight; +} + +bool e2d::EFont::isItalic() const +{ + return m_bItalic; +} + +void e2d::EFont::setFamily(EString fontFamily) +{ + m_sFontFamily = fontFamily; + m_bRecreateNeeded = true; +} + +void e2d::EFont::setSize(float fontSize) +{ + m_fFontSize = fontSize; + m_bRecreateNeeded = true; +} + +void e2d::EFont::setWeight(EFontWeight fontWeight) +{ + m_FontWeight = fontWeight; + m_bRecreateNeeded = true; +} + +void e2d::EFont::setItalic(bool value) +{ + m_bItalic = value; + m_bRecreateNeeded = true; +} + +void e2d::EFont::_initTextFormat() +{ + SafeReleaseInterface(&m_pTextFormat); + + HRESULT hr = GetDirectWriteFactory()->CreateTextFormat( + m_sFontFamily.c_str(), + NULL, // Font collection(NULL sets it to the system font collection) + DWRITE_FONT_WEIGHT(m_FontWeight.value), + m_bItalic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, + DWRITE_FONT_STRETCH_NORMAL, + m_fFontSize, + L"en-us", // Local + &m_pTextFormat + ); + + ASSERT(SUCCEEDED(hr), "Create IDWriteTextFormat Failed!"); +} + +IDWriteTextFormat * e2d::EFont::_getTextFormat() +{ + if (m_bRecreateNeeded) + { + _initTextFormat(); + m_bRecreateNeeded = false; + } + return m_pTextFormat; +} diff --git a/Easy2D/Node/ENode.cpp b/Easy2D/Node/ENode.cpp index 588a4f27..25575b7d 100644 --- a/Easy2D/Node/ENode.cpp +++ b/Easy2D/Node/ENode.cpp @@ -357,22 +357,22 @@ void e2d::ENode::move(const EVec & v) this->move(v.x, v.y); } -void e2d::ENode::setWidth(float width) +void e2d::ENode::_setWidth(float width) { - this->setSize(width, m_Size.height); + this->_setSize(width, m_Size.height); } -void e2d::ENode::setHeight(float height) +void e2d::ENode::_setHeight(float height) { - this->setSize(m_Size.width, height); + this->_setSize(m_Size.width, height); } -void e2d::ENode::setSize(const ESize & size) +void e2d::ENode::_setSize(const ESize & size) { - this->setSize(size.width, size.height); + this->_setSize(size.width, size.height); } -void e2d::ENode::setSize(float width, float height) +void e2d::ENode::_setSize(float width, float height) { if (m_Size.width == width && m_Size.height == height) return; diff --git a/Easy2D/Node/ERectangle.cpp b/Easy2D/Node/ERectangle.cpp deleted file mode 100644 index 62676b57..00000000 --- a/Easy2D/Node/ERectangle.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "..\enodes.h" -#include "..\Win\winbase.h" - - -e2d::ERectangle::ERectangle() -{ -} - -e2d::EColor e2d::ERectangle::getColor() const -{ - return m_Color; -} - -void e2d::ERectangle::setColor(EColor color) -{ - m_Color = color; -} - -void e2d::ERectangle::_onRender() -{ - D2D1_RECT_F rectangle = D2D1::RectF(0, 0, getWidth(), getHeight()); - GetSolidColorBrush()->SetColor(D2D1::ColorF(m_Color, m_fDisplayOpacity)); - GetRenderTarget()->FillRectangle(&rectangle, GetSolidColorBrush()); -} diff --git a/Easy2D/Node/ESprite.cpp b/Easy2D/Node/ESprite.cpp index 7836f249..ad9747af 100644 --- a/Easy2D/Node/ESprite.cpp +++ b/Easy2D/Node/ESprite.cpp @@ -1,452 +1,79 @@ #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); +#include "..\Win\winbase.h" e2d::ESprite::ESprite() - : m_pBitmap(nullptr) - , m_fSourcePosX(0) + : m_fSourcePosX(0) , m_fSourcePosY(0) - , m_fSourceWidth(0) - , m_fSourceHeight(0) + , m_pTexture(nullptr) { } e2d::ESprite::ESprite(const EString & imageFileName) : ESprite() { - setImage(imageFileName); + setTexture(new ETexture(imageFileName)); } e2d::ESprite::ESprite(const EString & imageFileName, float x, float y, float width, float height) { - setImage(imageFileName); - clipImage(x, y, width, height); + setTexture(new ETexture(imageFileName)); + clipTexture(x, y, width, height); } e2d::ESprite::ESprite(const EString & resourceName, const EString & resourceType) : ESprite() { - setImage(resourceName, resourceType); + setTexture(new ETexture(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); + setTexture(new ETexture(resourceName, resourceType)); + clipTexture(x, y, width, height); } -float e2d::ESprite::getWidth() const +e2d::ESprite::~ESprite() { - return m_fSourceWidth * m_fScaleX; + SafeRelease(&m_pTexture); } -float e2d::ESprite::getHeight() const +void e2d::ESprite::setTexture(ETexture * texture) { - 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!"); + SafeRelease(&m_pTexture); + m_pTexture = texture; + m_pTexture->retain(); m_fSourcePosX = m_fSourcePosY = 0; - m_fSourceWidth = m_pBitmap->GetSize().width; - m_fSourceHeight = m_pBitmap->GetSize().height; + ENode::_setWidth(m_pTexture->getSourceWidth()); + ENode::_setHeight(m_pTexture->getSourceHeight()); } -void e2d::ESprite::setImage(const EString & fileName, float x, float y, float width, float height) +void e2d::ESprite::setTexture(ETexture * texture, float x, float y, float width, float height) { - setImage(fileName); - clipImage(x, y, width, height); + setTexture(texture); + clipTexture(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) +void e2d::ESprite::clipTexture(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); + ENode::_setWidth(min(max(width, 0), m_pTexture->getSourceWidth() - m_fSourcePosX)); + ENode::_setHeight(min(max(height, 0), m_pTexture->getSourceHeight() - m_fSourcePosX)); } void e2d::ESprite::_onRender() { - if (m_pBitmap) + if (m_pTexture && m_pTexture->_getBitmap()) { // Draw bitmap GetRenderTarget()->DrawBitmap( - m_pBitmap, - D2D1::RectF(0, 0, m_fSourceWidth, m_fSourceHeight), + m_pTexture->_getBitmap(), + D2D1::RectF(0, 0, getRealWidth(), getRealHeight()), m_fDisplayOpacity, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, - D2D1::RectF(m_fSourcePosX, m_fSourcePosY, m_fSourceWidth, m_fSourceHeight) + D2D1::RectF(m_fSourcePosX, m_fSourcePosY, getRealWidth(), getRealHeight()) ); } } - -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); -} \ No newline at end of file diff --git a/Easy2D/Node/EText.cpp b/Easy2D/Node/EText.cpp index 6de60dab..e2a522a1 100644 --- a/Easy2D/Node/EText.cpp +++ b/Easy2D/Node/EText.cpp @@ -1 +1,166 @@ -#include "..\enodes.h" \ No newline at end of file +#include "..\enodes.h" +#include "..\Win\winbase.h" + +e2d::EText::EText() + : m_Color(EColor::WHITE) + , m_bWordWrapping(false) + , m_pFont(nullptr) + , m_fWordWrappingWidth(0) +{ + this->setFont(new EFont()); +} + +e2d::EText::EText(const EString & text) + : EText() +{ + this->setText(text); + this->setFont(new EFont()); +} + +e2d::EText::EText(EFont * font) + : EText() +{ + this->setFont(font); +} + +e2d::EText::EText(const EString & text, EColor color, EFont * font) + : EText() +{ + this->setText(text); + this->setColor(color); + this->setFont(font); +} + +e2d::EText::EText(const EString & text, EColor color, EString fontFamily, float fontSize, EFontWeight fontWeight, bool italic) +{ + this->setText(text); + this->setColor(color); + this->setFont(new EFont(fontFamily, fontSize, fontWeight, italic)); +} + +e2d::EText::~EText() +{ + SafeRelease(&m_pFont); +} + +e2d::EString e2d::EText::getText() const +{ + return m_sText; +} + +float e2d::EText::getWidth() const +{ + return m_fWordWrappingWidth * m_fScaleX; +} + +float e2d::EText::getRealWidth() const +{ + return m_fWordWrappingWidth; +} + +e2d::EColor e2d::EText::getColor() const +{ + return m_Color; +} + +e2d::EFont * e2d::EText::getFont() const +{ + return m_pFont; +} + +void e2d::EText::setText(const EString & text) +{ + m_sText = text; + _initTextLayout(); +} + +void e2d::EText::setColor(EColor color) +{ + m_Color = color; +} + +void e2d::EText::setFont(EFont * font) +{ + if (font) + { + SafeRelease(&m_pFont); + m_pFont = font; + font->retain(); + + _initTextLayout(); + } +} + +void e2d::EText::setWordWrapping(bool value) +{ + m_bWordWrapping = value; + _initTextLayout(); +} + +void e2d::EText::setWordWrappingWidth(float wordWrapWidth) +{ + m_fWordWrappingWidth = max(wordWrapWidth, 0); + _initTextLayout(); +} + +void e2d::EText::_onRender() +{ + GetSolidColorBrush()->SetColor(D2D1::ColorF(m_Color.value, m_fDisplayOpacity)); + GetRenderTarget()->DrawTextW( + m_sText.c_str(), + m_sText.length(), + m_pFont->_getTextFormat(), + D2D1::RectF( + 0, + 0, + m_bWordWrapping ? m_fWordWrappingWidth : m_Size.width, + getRealHeight() + ), + GetSolidColorBrush() + ); +} + +void e2d::EText::_initTextLayout() +{ + // 未设置字体或空字符串时,文本宽高为 0 + if (!m_pFont || m_sText.empty()) + { + this->_setHeight(0); + m_fWordWrappingWidth = 0; + return; + } + + // 未打开文本自动换行时,设置 TextFormat 属性为不换行 + if (!m_bWordWrapping) + { + m_pFont->_getTextFormat()->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP); + } + else + { + m_pFont->_getTextFormat()->SetWordWrapping(DWRITE_WORD_WRAPPING_WRAP); + } + + // 获取 TextLayout + IDWriteTextLayout * pDWriteTextLayout = nullptr; + + HRESULT hr = GetDirectWriteFactory()->CreateTextLayout( + m_sText.c_str(), + m_sText.size(), + m_pFont->_getTextFormat(), + m_bWordWrapping ? m_fWordWrappingWidth : 0, + 0, + &pDWriteTextLayout + ); + + ASSERT(SUCCEEDED(hr), "Create IDWriteTextFormat Failed!"); + + // 获取文本布局的宽度和高度 + DWRITE_TEXT_METRICS metrics; + pDWriteTextLayout->GetMetrics(&metrics); + + this->_setSize(metrics.widthIncludingTrailingWhitespace, metrics.height); + m_fWordWrappingWidth = metrics.widthIncludingTrailingWhitespace; + + // 删除相关资源 + SafeReleaseInterface(&pDWriteTextLayout); +} diff --git a/Easy2D/Node/ETexture.cpp b/Easy2D/Node/ETexture.cpp new file mode 100644 index 00000000..5f91721a --- /dev/null +++ b/Easy2D/Node/ETexture.cpp @@ -0,0 +1,369 @@ +#include "..\enodes.h" +#include "..\Win\winbase.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; + + +e2d::ETexture::ETexture() + : m_pBitmap(nullptr) +{ +} + +e2d::ETexture::ETexture(const EString & fileName) +{ + this->loadFromFile(fileName); +} + +e2d::ETexture::ETexture(const EString & resourceName, const EString & resourceType) +{ + this->loadFromResource(resourceName, resourceType); +} + +e2d::ETexture::~ETexture() +{ + SafeReleaseInterface(&m_pBitmap); +} + +void e2d::ETexture::loadFromFile(const EString & fileName) +{ + WARN_IF(fileName.empty(), "ETexture cannot load bitmap from NULL file name."); + + if (fileName.empty()) + return; + + SafeReleaseInterface(&m_pBitmap); + + if (!e2d::ETexture::preload(fileName)) + { + WARN_IF(true, "Load ETexture from file failed!"); + return; + } + + std::hash h; + size_t hash = h(fileName); + + m_pBitmap = s_mBitmapsFromFile.at(hash); +} + +void e2d::ETexture::loadFromResource(const EString & resourceName, const EString & resourceType) +{ + WARN_IF(resourceName.empty() || resourceType.empty(), "ETexture cannot load bitmap from NULL resource."); + + if (resourceName.empty() || resourceType.empty()) + return; + + SafeReleaseInterface(&m_pBitmap); + + if (!e2d::ETexture::preload(resourceName, resourceType)) + { + WARN_IF(true, "Load ETexture from resource failed!"); + return; + } + + ResKey key; + std::hash h; + key.resNameHash = h(resourceName); + key.resTypeHash = h(resourceType); + + m_pBitmap = s_mBitmapsFromResource.at(key); +} + +float e2d::ETexture::getSourceWidth() const +{ + if (m_pBitmap) + { + return m_pBitmap->GetSize().width; + } + else + { + return 0; + } +} + +float e2d::ETexture::getSourceHeight() const +{ + if (m_pBitmap) + { + return m_pBitmap->GetSize().height; + } + else + { + return 0; + } +} + +e2d::ESize e2d::ETexture::getSourceSize() const +{ + if (m_pBitmap) + { + return ESize(getSourceWidth(), getSourceHeight()); + } + else + { + return ESize(); + } +} + +bool e2d::ETexture::preload(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::ETexture::preload(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::ETexture::clearCache() +{ + for (auto child : s_mBitmapsFromFile) + { + SafeReleaseInterface(&child.second); + } + for (auto child : s_mBitmapsFromResource) + { + SafeReleaseInterface(&child.second); + } + s_mBitmapsFromFile.clear(); + s_mBitmapsFromResource.clear(); +} + +ID2D1Bitmap * e2d::ETexture::_getBitmap() +{ + return m_pBitmap; +} diff --git a/Easy2D/Win/winbase.cpp b/Easy2D/Win/winbase.cpp index e130dbbb..50d30ac7 100644 --- a/Easy2D/Win/winbase.cpp +++ b/Easy2D/Win/winbase.cpp @@ -2,12 +2,13 @@ using namespace std::chrono; -HWND s_HWnd = nullptr; -ID2D1Factory * s_pDirect2dFactory = nullptr; -ID2D1HwndRenderTarget * s_pRenderTarget = nullptr; -ID2D1SolidColorBrush * s_pSolidBrush = nullptr; -IWICImagingFactory * s_pIWICFactory = nullptr; -steady_clock::time_point s_tNow; +static HWND s_HWnd = nullptr; +static ID2D1Factory * s_pDirect2dFactory = nullptr; +static ID2D1HwndRenderTarget * s_pRenderTarget = nullptr; +static ID2D1SolidColorBrush * s_pSolidBrush = nullptr; +static IWICImagingFactory * s_pIWICFactory = nullptr; +static IDWriteFactory * s_pDWriteFactory = nullptr; +static steady_clock::time_point s_tNow; HWND &GetHWnd() @@ -60,6 +61,21 @@ ID2D1HwndRenderTarget * &GetRenderTarget() return s_pRenderTarget; } +IDWriteFactory * &GetDirectWriteFactory() +{ + if (!s_pDWriteFactory) + { + HRESULT hr; + hr = DWriteCreateFactory( + DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory), + reinterpret_cast(&s_pDWriteFactory) + ); + ASSERT(SUCCEEDED(hr), "Create DirectWrite Factory Failed!"); + } + return s_pDWriteFactory; +} + ID2D1SolidColorBrush * &GetSolidColorBrush() { if (!s_pSolidBrush) diff --git a/Easy2D/Win/winbase.h b/Easy2D/Win/winbase.h index 117df460..7256070f 100644 --- a/Easy2D/Win/winbase.h +++ b/Easy2D/Win/winbase.h @@ -19,6 +19,8 @@ ID2D1SolidColorBrush * &GetSolidColorBrush(); IWICImagingFactory * &GetImagingFactory(); +IDWriteFactory * &GetDirectWriteFactory(); + std::chrono::steady_clock::time_point &GetNow(); long long GetInterval(std::chrono::steady_clock::time_point tLast); diff --git a/Easy2D/ebase.h b/Easy2D/ebase.h index 6107702f..eb72e5da 100644 --- a/Easy2D/ebase.h +++ b/Easy2D/ebase.h @@ -50,7 +50,7 @@ public: virtual void onActivate(); // 重写这个函数,它将在窗口非激活时执行 - virtual void onInactive(); + virtual bool onInactive(); // 重写这个函数,它将在关闭窗口时执行 virtual bool onCloseWindow(); @@ -205,7 +205,7 @@ public: virtual void onActivate(); // 重写这个函数,它将在窗口非激活时执行 - virtual void onInactive(); + virtual bool onInactive(); // 重写这个函数,它将在关闭窗口时执行 virtual bool onCloseWindow(); diff --git a/Easy2D/ecommon.h b/Easy2D/ecommon.h index 947a093d..6b8ba5ab 100644 --- a/Easy2D/ecommon.h +++ b/Easy2D/ecommon.h @@ -82,148 +82,204 @@ typedef std::function TIMER_CALLBACK; -enum EColor +class EColor { - AliceBlue = 0xF0F8FF, - AntiqueWhite = 0xFAEBD7, - Aqua = 0x00FFFF, - Aquamarine = 0x7FFFD4, - Azure = 0xF0FFFF, - Beige = 0xF5F5DC, - Bisque = 0xFFE4C4, - Black = 0x000000, - BlanchedAlmond = 0xFFEBCD, - Blue = 0x0000FF, - BlueViolet = 0x8A2BE2, - Brown = 0xA52A2A, - BurlyWood = 0xDEB887, - CadetBlue = 0x5F9EA0, - Chartreuse = 0x7FFF00, - Chocolate = 0xD2691E, - Coral = 0xFF7F50, - CornflowerBlue = 0x6495ED, - Cornsilk = 0xFFF8DC, - Crimson = 0xDC143C, - Cyan = 0x00FFFF, - DarkBlue = 0x00008B, - DarkCyan = 0x008B8B, - DarkGoldenrod = 0xB8860B, - DarkGray = 0xA9A9A9, - DarkGreen = 0x006400, - DarkKhaki = 0xBDB76B, - DarkMagenta = 0x8B008B, - DarkOliveGreen = 0x556B2F, - DarkOrange = 0xFF8C00, - DarkOrchid = 0x9932CC, - DarkRed = 0x8B0000, - DarkSalmon = 0xE9967A, - DarkSeaGreen = 0x8FBC8F, - DarkSlateBlue = 0x483D8B, - DarkSlateGray = 0x2F4F4F, - DarkTurquoise = 0x00CED1, - DarkViolet = 0x9400D3, - DeepPink = 0xFF1493, - DeepSkyBlue = 0x00BFFF, - DimGray = 0x696969, - DodgerBlue = 0x1E90FF, - Firebrick = 0xB22222, - FloralWhite = 0xFFFAF0, - ForestGreen = 0x228B22, - Fuchsia = 0xFF00FF, - Gainsboro = 0xDCDCDC, - GhostWhite = 0xF8F8FF, - Gold = 0xFFD700, - Goldenrod = 0xDAA520, - Gray = 0x808080, - Green = 0x008000, - GreenYellow = 0xADFF2F, - Honeydew = 0xF0FFF0, - HotPink = 0xFF69B4, - IndianRed = 0xCD5C5C, - Indigo = 0x4B0082, - Ivory = 0xFFFFF0, - Khaki = 0xF0E68C, - Lavender = 0xE6E6FA, - LavenderBlush = 0xFFF0F5, - LawnGreen = 0x7CFC00, - LemonChiffon = 0xFFFACD, - LightBlue = 0xADD8E6, - LightCoral = 0xF08080, - LightCyan = 0xE0FFFF, - LightGoldenrodYellow = 0xFAFAD2, - LightGreen = 0x90EE90, - LightGray = 0xD3D3D3, - LightPink = 0xFFB6C1, - LightSalmon = 0xFFA07A, - LightSeaGreen = 0x20B2AA, - LightSkyBlue = 0x87CEFA, - LightSlateGray = 0x778899, - LightSteelBlue = 0xB0C4DE, - LightYellow = 0xFFFFE0, - Lime = 0x00FF00, - LimeGreen = 0x32CD32, - Linen = 0xFAF0E6, - Magenta = 0xFF00FF, - Maroon = 0x800000, - MediumAquamarine = 0x66CDAA, - MediumBlue = 0x0000CD, - MediumOrchid = 0xBA55D3, - MediumPurple = 0x9370DB, - MediumSeaGreen = 0x3CB371, - MediumSlateBlue = 0x7B68EE, - MediumSpringGreen = 0x00FA9A, - MediumTurquoise = 0x48D1CC, - MediumVioletRed = 0xC71585, - MidnightBlue = 0x191970, - MintCream = 0xF5FFFA, - MistyRose = 0xFFE4E1, - Moccasin = 0xFFE4B5, - NavajoWhite = 0xFFDEAD, - Navy = 0x000080, - OldLace = 0xFDF5E6, - Olive = 0x808000, - OliveDrab = 0x6B8E23, - Orange = 0xFFA500, - OrangeRed = 0xFF4500, - Orchid = 0xDA70D6, - PaleGoldenrod = 0xEEE8AA, - PaleGreen = 0x98FB98, - PaleTurquoise = 0xAFEEEE, - PaleVioletRed = 0xDB7093, - PapayaWhip = 0xFFEFD5, - PeachPuff = 0xFFDAB9, - Peru = 0xCD853F, - Pink = 0xFFC0CB, - Plum = 0xDDA0DD, - PowderBlue = 0xB0E0E6, - Purple = 0x800080, - Red = 0xFF0000, - RosyBrown = 0xBC8F8F, - RoyalBlue = 0x4169E1, - SaddleBrown = 0x8B4513, - Salmon = 0xFA8072, - SandyBrown = 0xF4A460, - SeaGreen = 0x2E8B57, - SeaShell = 0xFFF5EE, - Sienna = 0xA0522D, - Silver = 0xC0C0C0, - SkyBlue = 0x87CEEB, - SlateBlue = 0x6A5ACD, - SlateGray = 0x708090, - Snow = 0xFFFAFA, - SpringGreen = 0x00FF7F, - SteelBlue = 0x4682B4, - Tan = 0xD2B48C, - Teal = 0x008080, - Thistle = 0xD8BFD8, - Tomato = 0xFF6347, - Turquoise = 0x40E0D0, - Violet = 0xEE82EE, - Wheat = 0xF5DEB3, - White = 0xFFFFFF, - WhiteSmoke = 0xF5F5F5, - Yellow = 0xFFFF00, - YellowGreen = 0x9ACD32, +public: + + EColor() + { + value = VALUE::WHITE; + } + + EColor(int color) + { + value = VALUE(color); + } + + enum VALUE + { + ALICE_BLUE = 0xF0F8FF, + ANTIQUE_WHITE = 0xFAEBD7, + AQUA = 0x00FFFF, + AQUAMARINE = 0x7FFFD4, + AZURE = 0xF0FFFF, + BEIGE = 0xF5F5DC, + BISQUE = 0xFFE4C4, + BLACK = 0x000000, + BLANCHED_ALMOND = 0xFFEBCD, + BLUE = 0x0000FF, + BLUE_VIOLET = 0x8A2BE2, + BROWN = 0xA52A2A, + BURLY_WOOD = 0xDEB887, + CADET_BLUE = 0x5F9EA0, + CHARTREUSE = 0x7FFF00, + CHOCOLATE = 0xD2691E, + CORAL = 0xFF7F50, + CORNFLOWER_BLUE = 0x6495ED, + CORNSILK = 0xFFF8DC, + CRIMSON = 0xDC143C, + CYAN = 0x00FFFF, + DARK_BLUE = 0x00008B, + DARK_CYAN = 0x008B8B, + DARK_GOLDENROD = 0xB8860B, + DARK_GRAY = 0xA9A9A9, + DARK_GREEN = 0x006400, + DARK_KHAKI = 0xBDB76B, + DARK_MAGENTA = 0x8B008B, + DARK_OLIVE_GREEN = 0x556B2F, + DARK_ORANGE = 0xFF8C00, + DARK_ORCHID = 0x9932CC, + DARK_RED = 0x8B0000, + DARK_SALMON = 0xE9967A, + DARK_SEA_GREEN = 0x8FBC8F, + DARK_SLATE_BLUE = 0x483D8B, + DARK_SLATE_GRAY = 0x2F4F4F, + DARK_TURQUOISE = 0x00CED1, + DARK_VIOLET = 0x9400D3, + DEEP_PINK = 0xFF1493, + DEEP_SKY_BLUE = 0x00BFFF, + DIM_GRAY = 0x696969, + DODGER_BLUE = 0x1E90FF, + FIREBRICK = 0xB22222, + FLORAL_WHITE = 0xFFFAF0, + FOREST_GREEN = 0x228B22, + FUCHSIA = 0xFF00FF, + GAINSCORO = 0xDCDCDC, + GHOST_WHITE = 0xF8F8FF, + GOLD = 0xFFD700, + GOLDENROD = 0xDAA520, + GRAY = 0x808080, + GREEN = 0x008000, + GREEN_YELLOW = 0xADFF2F, + HONEYDEW = 0xF0FFF0, + HOT_PINK = 0xFF69B4, + INDIAN_RED = 0xCD5C5C, + INDIGO = 0x4B0082, + IVORY = 0xFFFFF0, + KHAKI = 0xF0E68C, + LAVENDER = 0xE6E6FA, + LAVENDER_BLUSH = 0xFFF0F5, + LAWN_GREEN = 0x7CFC00, + LEMON_CHIFFON = 0xFFFACD, + LIGHT_BLUE = 0xADD8E6, + LIGHT_CORAL = 0xF08080, + LIGHT_CYAN = 0xE0FFFF, + LIGHT_GOLDENROD_YELLOW = 0xFAFAD2, + LIGHT_GREEN = 0x90EE90, + LIGHT_GRAY = 0xD3D3D3, + LIGHT_PINK = 0xFFB6C1, + LIGHT_SALMON = 0xFFA07A, + LIGHT_SEA_GREEN = 0x20B2AA, + LIGHT_SKY_BLUE = 0x87CEFA, + LIGHT_SLATE_GRAY = 0x778899, + LIGHT_STEEL_BLUE = 0xB0C4DE, + LIGHT_YELLOW = 0xFFFFE0, + LIME = 0x00FF00, + LIME_GREEN = 0x32CD32, + LINEN = 0xFAF0E6, + MAGENTA = 0xFF00FF, + MAROON = 0x800000, + MEDIUM_AQUAMARINE = 0x66CDAA, + MEDIUM_BLUE = 0x0000CD, + MEDIUM_ORCHID = 0xBA55D3, + MEDIUM_PURPLE = 0x9370DB, + MEDIUM_SEA_GREEN = 0x3CB371, + MEDIUM_SLATE_BLUE = 0x7B68EE, + MEDIUM_SPRING_GREEN = 0x00FA9A, + MEDIUM_TURQUOISE = 0x48D1CC, + MEDUIM_VIOLET_RED = 0xC71585, + MIDNIGHT_BLUE = 0x191970, + MINT_CREAM = 0xF5FFFA, + MISTY_ROSE = 0xFFE4E1, + MOCCASIN = 0xFFE4B5, + NAVAJO_WHITE = 0xFFDEAD, + NAVY = 0x000080, + OLD_LACE = 0xFDF5E6, + OLIVE = 0x808000, + OLIVE_DRAB = 0x6B8E23, + ORANGE = 0xFFA500, + ORANGE_RED = 0xFF4500, + ORCHID = 0xDA70D6, + PALE_GOLDENROD = 0xEEE8AA, + PALE_GREEN = 0x98FB98, + PALE_TURQUOISE = 0xAFEEEE, + PALE_VIOLET_RED = 0xDB7093, + PAPAYA_WHIP = 0xFFEFD5, + PEACH_PUFF = 0xFFDAB9, + PERU = 0xCD853F, + PINK = 0xFFC0CB, + PLUM = 0xDDA0DD, + POWDER_BLUE = 0xB0E0E6, + PURPLE = 0x800080, + RED = 0xFF0000, + ROSY_BROWN = 0xBC8F8F, + ROYAL_BLUE = 0x4169E1, + SADDLE_BROWN = 0x8B4513, + SALMON = 0xFA8072, + SANDY_BROWN = 0xF4A460, + SEA_GREEN = 0x2E8B57, + SEA_SHELL = 0xFFF5EE, + SIENNA = 0xA0522D, + SILVER = 0xC0C0C0, + SKY_BLUE = 0x87CEEB, + SLATE_BLUE = 0x6A5ACD, + SLATE_GRAY = 0x708090, + SNOW = 0xFFFAFA, + SPRING_GREEN = 0x00FF7F, + STEEL_BLUE = 0x4682B4, + TAN = 0xD2B48C, + TEAL = 0x008080, + THISTLE = 0xD8BFD8, + TOMATO = 0xFF6347, + TURQUOISE = 0x40E0D0, + VIOLET = 0xEE82EE, + WHEAT = 0xF5DEB3, + WHITE = 0xFFFFFF, + WHITE_SMOKE = 0xF5F5F5, + YELLOW = 0xFFFF00, + YELLOW_GREEN = 0x9ACD32 + }; + + VALUE value; +}; + + +class EFontWeight +{ +public: + + EFontWeight() + { + value = VALUE::REGULAR; + } + + EFontWeight(int fontWeight) + { + value = VALUE(fontWeight); + } + + enum VALUE + { + THIN = 100, + EXTRA_LIGHT = 200, + ULTRA_LIGHT = 200, + LIGHT = 300, + SEMI_LIGHT = 350, + NORMAL = 400, + REGULAR = 400, + MEDIUM = 500, + DEMI_BOLD = 600, + SEMI_BOLD = 600, + BOLD = 700, + EXTRA_BOLD = 800, + ULTRA_BOLD = 800, + BLACK = 900, + HEAVY = 900, + EXTRA_BLACK = 950, + ULTRA_BLACK = 950 + }; + + VALUE value; }; } \ No newline at end of file diff --git a/Easy2D/emacros.h b/Easy2D/emacros.h index 460d32bc..5e6f55c1 100644 --- a/Easy2D/emacros.h +++ b/Easy2D/emacros.h @@ -56,4 +56,7 @@ template -inline void SafeDelete(T** p) { if (*p) { delete *p; *p = nullptr; } } \ No newline at end of file +inline void SafeDelete(T** p) { if (*p) { delete *p; *p = nullptr; } } + +template +inline void SafeRelease(T** p) { if (*p) { (*p)->autoRelease(); (*p)->release(); *p = nullptr; } } \ No newline at end of file diff --git a/Easy2D/enodes.h b/Easy2D/enodes.h index 0a0f15ac..ab0cd3a6 100644 --- a/Easy2D/enodes.h +++ b/Easy2D/enodes.h @@ -1,10 +1,12 @@ #pragma once #include "ebase.h" -#include "Win\winbase.h" namespace e2d { +class EText; +class ESprite; + class ENode : public EObject { @@ -138,27 +140,6 @@ public: const EVec & v ); - // 设置节点宽度 - virtual void setWidth( - float width - ); - - // 设置节点高度 - virtual void setHeight( - float height - ); - - // 设置节点大小 - virtual void setSize( - const ESize & size - ); - - // 设置节点大小 - virtual void setSize( - float width, - float height - ); - // 设置节点绘图顺序 // 默认为 0 virtual void setOrder( @@ -312,6 +293,27 @@ protected: // 更新节点透明度 static void _updateOpacity(ENode * node); + // 设置节点宽度 + virtual void _setWidth( + float width + ); + + // 设置节点高度 + virtual void _setHeight( + float height + ); + + // 设置节点大小 + virtual void _setSize( + const ESize & size + ); + + // 设置节点大小 + virtual void _setSize( + float width, + float height + ); + protected: EString m_sName; size_t m_nHashName; @@ -338,21 +340,67 @@ protected: }; -class ERectangle : - public ENode +class ETexture : + public EObject { + friend ESprite; + public: - ERectangle(); + // 创建一个空的纹理 + ETexture(); - EColor getColor() const; + // 从本地文件中读取资源 + ETexture( + const EString & fileName + ); - void setColor(EColor color); + // 读取程序资源 + ETexture( + const EString & resourceName, + const EString & resourceType + ); + + ~ETexture(); + + // 从本地文件中读取资源 + void loadFromFile( + const EString & fileName + ); + + // 读取程序资源 + void loadFromResource( + const EString & resourceName, + const EString & resourceType + ); + + // 获取源图片宽度 + virtual float getSourceWidth() const; + + // 获取源图片高度 + virtual float getSourceHeight() const; + + // 获取源图片大小 + virtual ESize getSourceSize() const; + + // 预加载资源 + static bool preload( + const EString & fileName + ); + + // 预加载资源 + static bool preload( + const EString & resourceName, + const EString & resourceType + ); + + // 清空缓存 + static void clearCache(); protected: - virtual void _onRender() override; + ID2D1Bitmap * _getBitmap(); protected: - EColor m_Color; + ID2D1Bitmap * m_pBitmap; }; @@ -393,85 +441,30 @@ public: float height ); - // 获取精灵宽度 - virtual float getWidth() const override; - - // 获取精灵高度 - virtual float getHeight() const override; - - // 获取精灵大小 - virtual ESize getSize() const override; - - // 获取精灵宽度(不考虑缩放) - virtual float getRealWidth() const override; - - // 获取精灵高度(不考虑缩放) - virtual float getRealHeight() const override; - - // 获取精灵大小(不考虑缩放) - virtual ESize getRealSize() const override; - - // 设置精灵宽度是失效的 - virtual void setWidth(float) override; - - // 设置精灵高度是失效的 - virtual void setHeight(float) override; - - // 设置精灵大小是失效的 - virtual void setSize(float, float) override; + ~ESprite(); - // 从文件加载图片 - void setImage( - const EString & fileName + // 设置精灵纹理 + void setTexture( + ETexture * texture ); - // 从文件加载图片并裁剪 - void setImage( - const EString & fileName, + // 设置精灵纹理并裁剪 + void setTexture( + ETexture * texture, float x, float y, float width, float height ); - // 从资源加载图片 - void setImage( - const EString & resourceName, - const EString & resourceType - ); - - // 从资源加载图片并裁剪 - void setImage( - const EString & resourceName, - const EString & resourceType, + // 裁剪纹理 + void clipTexture( float x, float y, float width, float height ); - // 裁剪原图片 - void clipImage( - float x, - float y, - float width, - float height - ); - - // 预加载资源 - static bool preloadImage( - const EString & fileName - ); - - // 预加载资源 - static bool preloadImage( - const EString & resourceName, - const EString & resourceType - ); - - // 清空图片缓存 - static void clearCache(); - protected: // 渲染精灵 virtual void _onRender() override; @@ -479,12 +472,157 @@ protected: protected: float m_fSourcePosX; float m_fSourcePosY; - float m_fSourceWidth; - float m_fSourceHeight; - EString m_sFileName; - EString m_sResourceName; - EString m_sResourceType; - ID2D1Bitmap * m_pBitmap; + ETexture * m_pTexture; +}; + + +class EFont : + public EObject +{ + friend EText; + +public: + EFont(); + + EFont( + EString fontFamily, + float fontSize = 22, + EFontWeight fontWeight = EFontWeight::REGULAR, + bool italic = false + ); + + ~EFont(); + + // 获取当前字号 + float getFontSize() const; + + // 获取当前字体粗细值 + EFontWeight getFontWeight() const; + + // 是否是斜体 + bool isItalic() const; + + // 设置字体 + void setFamily( + EString fontFamily + ); + + // 设置字号 + void setSize( + float fontSize + ); + + // 设置字体粗细值 + void setWeight( + EFontWeight fontWeight + ); + + // 设置文字斜体 + void setItalic( + bool value + ); + +protected: + // 创建文字格式 + void _initTextFormat(); + + // 获取文字格式 + IDWriteTextFormat * _getTextFormat(); + +protected: + EString m_sFontFamily; + float m_fFontSize; + EFontWeight m_FontWeight; + bool m_bItalic; + bool m_bRecreateNeeded; + IDWriteTextFormat * m_pTextFormat; +}; + + +class EText : + public ENode +{ +public: + EText(); + + EText( + const EString & text + ); + + EText( + EFont * font + ); + + EText( + const EString & text, + EColor color, + EFont * font + ); + + EText( + const EString & text, + EColor color, + EString fontFamily, + float fontSize = 22, + EFontWeight fontWeight = EFontWeight::REGULAR, + bool italic = false + ); + + ~EText(); + + // 获取文本 + EString getText() const; + + // 获取文本宽度 + virtual float getWidth() const override; + + // 获取文本宽度(不考虑缩放) + virtual float getRealWidth() const override; + + // 获取文字颜色 + EColor getColor() const; + + // 获取字体 + EFont * getFont() const; + + // 设置文本 + void setText( + const EString & text + ); + + // 设置文字颜色 + void setColor( + EColor color + ); + + // 设置字体 + void setFont( + EFont * font + ); + + // 设置文字自动换行 + void setWordWrapping( + bool value + ); + + // 设置文字换行宽度(WordWrapping 打开时生效) + void setWordWrappingWidth( + float wordWrapWidth + ); + +protected: + // 渲染文字 + virtual void _onRender() override; + + // 创建文字布局 + void _initTextLayout(); + +protected: + EString m_sText; + EColor m_Color; + bool m_bWordWrapping; + float m_fWordWrappingWidth; + EFont * m_pFont; }; } \ No newline at end of file