diff --git a/Demo/main.cpp b/Demo/main.cpp index 4dee944b..fc1cbffb 100644 --- a/Demo/main.cpp +++ b/Demo/main.cpp @@ -14,7 +14,7 @@ int WINAPI WinMain( { auto scene = new EScene(); - auto node = new ENode(L"node1"); + /*auto node = new ENode(L"node1"); node->setPos(50, 80); node->setSize(30, 30); scene->add(node); @@ -25,13 +25,29 @@ int WINAPI WinMain( node->addChild(node2); auto mlistener = new EMouseClickListener([](EPoint p) { - EApp::getCurrentScene()->getChild(L"node1")->setPos(p.x, p.y); + EApp::getCurrentScene()->getChild(L"node1")->setPos(p.x, p.y); }); - mlistener->bindWith(node); + mlistener->bindWith(node);*/ + auto sprite = new ESprite(L"test.png"); + sprite->setAnchor(0.5f, 0.5f); + sprite->setPos(sprite->getWidth() / 2, sprite->getHeight() / 2); + + auto sprite2 = new ESprite(L"test.png"); + sprite2->setScale(0.5); + sprite2->setRotation(45); + + sprite->addChild(sprite2); + + auto mlistener = new EMouseClickListener([=](EPoint p) { + sprite->setRotation(sprite->getRotation() + 10); + }); + + mlistener->bindWith(sprite); + + scene->add(sprite); app.enterScene(scene); - app.run(); } diff --git a/Demo/test.png b/Demo/test.png new file mode 100644 index 00000000..23b60462 Binary files /dev/null and b/Demo/test.png differ diff --git a/Easy2D/Base/EApp.cpp b/Easy2D/Base/EApp.cpp index c3aa9232..90feea4b 100644 --- a/Easy2D/Base/EApp.cpp +++ b/Easy2D/Base/EApp.cpp @@ -9,12 +9,6 @@ using namespace std::chrono; using namespace std::this_thread; -#ifndef HINST_THISCOMPONENT -EXTERN_C IMAGE_DOS_HEADER __ImageBase; -#define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase) -#endif - - e2d::EApp * s_pInstance = nullptr; std::stack s_SceneStack; @@ -134,7 +128,7 @@ bool e2d::EApp::init(e2d::EString title, UINT32 width, UINT32 height, bool bShow // 获取窗口大小(包含菜单栏) tagRECT rcWindow; GetWindowRect(GetHWnd(), &rcWindow); - // 修改窗口大小,并设置窗口在屏幕居中 + // 设置窗口在屏幕居中 MoveWindow( GetHWnd(), (screenWidth - (rcWindow.right - rcWindow.left)) / 2, @@ -432,6 +426,7 @@ void e2d::EApp::_enterNextScene() if (m_pCurrentScene) { m_pCurrentScene->onExit(); + m_pCurrentScene->_onExit(); if (m_pCurrentScene->m_bWillSave) { @@ -444,7 +439,9 @@ void e2d::EApp::_enterNextScene() } } - m_pNextScene->onEnter(); // 执行下一场景的 onEnter 函数 + // 执行下一场景的 onEnter 函数 + m_pNextScene->_onEnter(); + m_pNextScene->onEnter(); m_pCurrentScene = m_pNextScene; // 切换场景 m_pNextScene = nullptr; // 下一场景置空 @@ -474,32 +471,10 @@ HRESULT e2d::EApp::_createDeviceIndependentResources() // changes, the window is remoted, etc. HRESULT e2d::EApp::_createDeviceResources() { - HRESULT hr = S_OK; + // 这个函数将自动创建设备相关资源 + GetRenderTarget(); - if (!GetRenderTarget()) - { - RECT rc; - GetClientRect(GetHWnd(), &rc); - - D2D1_SIZE_U size = D2D1::SizeU( - rc.right - rc.left, - rc.bottom - rc.top - ); - - // Create a Direct2D render target. - hr = GetFactory()->CreateHwndRenderTarget( - D2D1::RenderTargetProperties(), - D2D1::HwndRenderTargetProperties(GetHWnd(), size), - &GetRenderTarget() - ); - } - - if (FAILED(hr)) - { - MessageBox(nullptr, L"Create Device Resources Failed!", L"Error", MB_OK); - } - - return hr; + return S_OK; } // Discards device-dependent resources. These resources must be diff --git a/Easy2D/Base/EScene.cpp b/Easy2D/Base/EScene.cpp index c71c99a9..f5205e43 100644 --- a/Easy2D/Base/EScene.cpp +++ b/Easy2D/Base/EScene.cpp @@ -14,6 +14,14 @@ e2d::EScene::~EScene() clearAllChildren(); } +void e2d::EScene::onEnter() +{ +} + +void e2d::EScene::onExit() +{ +} + void e2d::EScene::_onRender() { this->_sortChildren(); @@ -23,7 +31,7 @@ void e2d::EScene::_onRender() // 访问所有节点 for (auto child : m_vChildren) { - child->callOn(); + child->_callOn(); } } @@ -44,7 +52,7 @@ void e2d::EScene::_sortChildren() } } -void e2d::EScene::onEnter() +void e2d::EScene::_onEnter() { // 启用场景上的所有定时器、监听器和动画 //Timer::notifyAllSceneTimers(m_pNextScene); @@ -52,7 +60,7 @@ void e2d::EScene::onEnter() //ActionManager::notifyAllSceneActions(m_pNextScene); } -void e2d::EScene::onExit() +void e2d::EScene::_onExit() { if (m_bWillSave) { diff --git a/Easy2D/Easy2D.vcxproj b/Easy2D/Easy2D.vcxproj index 7903b83a..135e7a09 100644 --- a/Easy2D/Easy2D.vcxproj +++ b/Easy2D/Easy2D.vcxproj @@ -200,10 +200,13 @@ - + + + + diff --git a/Easy2D/Easy2D.vcxproj.filters b/Easy2D/Easy2D.vcxproj.filters index caaf10a1..9405f3d5 100644 --- a/Easy2D/Easy2D.vcxproj.filters +++ b/Easy2D/Easy2D.vcxproj.filters @@ -48,9 +48,6 @@ Msg\Listener - - Msg\Listener - Msg\Listener @@ -66,6 +63,18 @@ Node + + Node + + + Msg\Listener + + + Msg\Listener + + + Msg\Listener + diff --git a/Easy2D/Msg/Listener/EMouseClickListener.cpp b/Easy2D/Msg/Listener/EMouseClickListener.cpp index 951030a7..367046bd 100644 --- a/Easy2D/Msg/Listener/EMouseClickListener.cpp +++ b/Easy2D/Msg/Listener/EMouseClickListener.cpp @@ -2,31 +2,41 @@ e2d::EMouseClickListener::EMouseClickListener() : EMouseListener() + , m_bPressed(false) { } e2d::EMouseClickListener::EMouseClickListener(EString name) : EMouseListener(name) + , m_bPressed(false) { } e2d::EMouseClickListener::EMouseClickListener(const MOUSE_CLICK_LISTENER_CALLBACK & callback) : EMouseListener() , m_callback(callback) + , m_bPressed(false) { } e2d::EMouseClickListener::EMouseClickListener(EString name, const MOUSE_CLICK_LISTENER_CALLBACK & callback) : EMouseListener(name) , m_callback(callback) + , m_bPressed(false) { } void e2d::EMouseClickListener::runCallback() { - if (EMouseMsg::getMsg() == EMouseMsg::MOUSE_MSG::LBUTTON_UP) + if (EMouseMsg::getMsg() == EMouseMsg::LBUTTON_DOWN || + EMouseMsg::getMsg() == EMouseMsg::LBUTTON_DBLCLK) + { + m_bPressed = true; + } + else if (m_bPressed && EMouseMsg::getMsg() == EMouseMsg::LBUTTON_UP) { m_callback(EMouseMsg::getPos()); + m_bPressed = false; } } diff --git a/Easy2D/Msg/Listener/EMouseDoubleClickListener.cpp b/Easy2D/Msg/Listener/EMouseDoubleClickListener.cpp new file mode 100644 index 00000000..1a8ee4f8 --- /dev/null +++ b/Easy2D/Msg/Listener/EMouseDoubleClickListener.cpp @@ -0,0 +1,45 @@ +#include "..\..\emsg.h" + +e2d::EMouseDoubleClickListener::EMouseDoubleClickListener() + : EMouseListener() + , m_bPressed(false) +{ +} + +e2d::EMouseDoubleClickListener::EMouseDoubleClickListener(EString name) + : EMouseListener(name) + , m_bPressed(false) +{ +} + +e2d::EMouseDoubleClickListener::EMouseDoubleClickListener(const MOUSE_DBLCLK_LISTENER_CALLBACK & callback) + : EMouseListener() + , m_callback(callback) + , m_bPressed(false) +{ +} + +e2d::EMouseDoubleClickListener::EMouseDoubleClickListener(EString name, const MOUSE_DBLCLK_LISTENER_CALLBACK & callback) + : EMouseListener(name) + , m_callback(callback) + , m_bPressed(false) +{ +} + +void e2d::EMouseDoubleClickListener::runCallback() +{ + if (EMouseMsg::getMsg() == EMouseMsg::LBUTTON_DBLCLK) + { + m_bPressed = true; + } + else if (m_bPressed && EMouseMsg::getMsg() == EMouseMsg::LBUTTON_UP) + { + m_callback(EMouseMsg::getPos()); + m_bPressed = false; + } +} + +void e2d::EMouseDoubleClickListener::setCallback(const MOUSE_DBLCLK_LISTENER_CALLBACK & callback) +{ + m_callback = callback; +} diff --git a/Easy2D/Msg/Listener/EMouseDragListener.cpp b/Easy2D/Msg/Listener/EMouseDragListener.cpp new file mode 100644 index 00000000..1eb9c705 --- /dev/null +++ b/Easy2D/Msg/Listener/EMouseDragListener.cpp @@ -0,0 +1,41 @@ +#include "..\..\emsg.h" + +e2d::EMouseDragListener::EMouseDragListener() + : EMouseListener() +{ +} + +e2d::EMouseDragListener::EMouseDragListener(EString name) + : EMouseListener(name) +{ +} + +e2d::EMouseDragListener::EMouseDragListener(const MOUSE_DRAG_LISTENER_CALLBACK & callback) + : EMouseListener() + , m_callback(callback) +{ +} + +e2d::EMouseDragListener::EMouseDragListener(EString name, const MOUSE_DRAG_LISTENER_CALLBACK & callback) + : EMouseListener(name) + , m_callback(callback) +{ +} + +void e2d::EMouseDragListener::runCallback() +{ + if (EMouseMsg::getMsg() == EMouseMsg::LBUTTON_DOWN || + EMouseMsg::getMsg() == EMouseMsg::LBUTTON_DBLCLK) + { + m_Begin = EMouseMsg::getPos(); + } + else if (EMouseMsg::isLButtonDown() && EMouseMsg::getMsg() == EMouseMsg::MOVE) + { + m_callback(m_Begin, EMouseMsg::getPos()); + } +} + +void e2d::EMouseDragListener::setCallback(const MOUSE_DRAG_LISTENER_CALLBACK & callback) +{ + m_callback = callback; +} diff --git a/Easy2D/Msg/Listener/EMouseDraggedListener.cpp b/Easy2D/Msg/Listener/EMouseDraggedListener.cpp deleted file mode 100644 index b944baed..00000000 --- a/Easy2D/Msg/Listener/EMouseDraggedListener.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "..\..\emsg.h" - -e2d::EMouseDraggedListener::EMouseDraggedListener() - : EMouseListener() -{ -} - -e2d::EMouseDraggedListener::EMouseDraggedListener(EString name) - : EMouseListener(name) -{ -} - -e2d::EMouseDraggedListener::EMouseDraggedListener(const MOUSE_DRAG_LISTENER_CALLBACK & callback) - : EMouseListener() - , m_callback(callback) -{ -} - -e2d::EMouseDraggedListener::EMouseDraggedListener(EString name, const MOUSE_DRAG_LISTENER_CALLBACK & callback) - : EMouseListener(name) - , m_callback(callback) -{ -} - -void e2d::EMouseDraggedListener::runCallback() -{ - if (EMouseMsg::getMsg() == EMouseMsg::MOUSE_MSG::LBUTTON_DOWN || - EMouseMsg::getMsg() == EMouseMsg::MOUSE_MSG::LBUTTON_DBLCLK) - { - m_Begin = EMouseMsg::getPos(); - } - else if (EMouseMsg::getMsg() == EMouseMsg::MOUSE_MSG::LBUTTON_UP) - { - m_End = EMouseMsg::getPos(); - m_callback(m_Begin, m_End); - } -} - -void e2d::EMouseDraggedListener::setCallback(const MOUSE_DRAG_LISTENER_CALLBACK & callback) -{ - m_callback = callback; -} diff --git a/Easy2D/Msg/Listener/EMousePressListener.cpp b/Easy2D/Msg/Listener/EMousePressListener.cpp new file mode 100644 index 00000000..ef0801e4 --- /dev/null +++ b/Easy2D/Msg/Listener/EMousePressListener.cpp @@ -0,0 +1,37 @@ +#include "..\..\emsg.h" + +e2d::EMousePressListener::EMousePressListener() + : EMouseListener() +{ +} + +e2d::EMousePressListener::EMousePressListener(EString name) + : EMouseListener(name) +{ +} + +e2d::EMousePressListener::EMousePressListener(const MOUSE_PRESS_LISTENER_CALLBACK & callback) + : EMouseListener() + , m_callback(callback) +{ +} + +e2d::EMousePressListener::EMousePressListener(EString name, const MOUSE_PRESS_LISTENER_CALLBACK & callback) + : EMouseListener(name) + , m_callback(callback) +{ +} + +void e2d::EMousePressListener::runCallback() +{ + if (EMouseMsg::getMsg() == EMouseMsg::LBUTTON_DOWN || + EMouseMsg::getMsg() == EMouseMsg::LBUTTON_DBLCLK) + { + m_callback(EMouseMsg::getPos()); + } +} + +void e2d::EMousePressListener::setCallback(const MOUSE_PRESS_LISTENER_CALLBACK & callback) +{ + m_callback = callback; +} diff --git a/Easy2D/Node/ENode.cpp b/Easy2D/Node/ENode.cpp index d16493bb..6c190c3c 100644 --- a/Easy2D/Node/ENode.cpp +++ b/Easy2D/Node/ENode.cpp @@ -8,20 +8,22 @@ e2d::ENode::ENode() , m_fPosY(0) , m_fWidth(0) , m_fHeight(0) - , m_fScaleX(1) - , m_fScaleY(1) + , m_fScaleX(1.0f) + , m_fScaleY(1.0f) , m_fRotation(0) , m_fSkewAngleX(0) , m_fSkewAngleY(0) - , m_fDisplayOpacity(1) - , m_fRealOpacity(1) + , m_fDisplayOpacity(1.0f) + , m_fRealOpacity(1.0f) + , m_fAnchorX(0) + , m_fAnchorY(0) , m_Matri(D2D1::Matrix3x2F::Identity()) , m_bVisiable(true) , m_pParent(nullptr) , m_pParentScene(nullptr) , m_nHashName(0) - , m_bSortNeeded(false) - , m_bTransformNeeded(false) + , m_bSortChildrenNeeded(false) + , m_bTransformChildrenNeeded(false) { } @@ -35,14 +37,17 @@ e2d::ENode::~ENode() { } -void e2d::ENode::callOn() +void e2d::ENode::_callOn() { if (!m_bVisiable) { return; } - this->_transfrom(); + if (m_bTransformChildrenNeeded) + { + _updateTransform(this); + } if (!m_vChildren.empty()) { @@ -56,7 +61,7 @@ void e2d::ENode::callOn() // 访问 Order 小于零的节点 if (child->getOrder() < 0) { - child->callOn(); + child->_callOn(); } else { @@ -70,7 +75,7 @@ void e2d::ENode::callOn() // 访问剩余节点 for (; i < size; i++) - m_vChildren[i]->callOn(); + m_vChildren[i]->_callOn(); } else { @@ -86,7 +91,7 @@ void e2d::ENode::_onRender() void e2d::ENode::_sortChildren() { - if (m_bSortNeeded) + if (m_bSortChildrenNeeded) { // 子节点排序 std::sort( @@ -97,36 +102,77 @@ void e2d::ENode::_sortChildren() } ); - m_bSortNeeded = false; + m_bSortChildrenNeeded = false; } } -void e2d::ENode::_transfrom() +void e2d::ENode::_updateTransformToReal() { - if (m_bTransformNeeded) + // 计算锚点坐标 + D2D1_POINT_2F anchorPos = D2D1::Point2F( + m_fWidth * m_fAnchorX, + m_fHeight * m_fAnchorY + ); + // 计算左上角坐标 + D2D1_POINT_2F upperLeftCorner = D2D1::Point2F( + m_fPosX - m_fWidth * m_fAnchorX, + m_fPosY - m_fHeight * m_fAnchorY + ); + // 二维矩形变换 + m_Matri = D2D1::Matrix3x2F::Scale( + m_fScaleX, + m_fScaleY, + anchorPos + ) * D2D1::Matrix3x2F::Rotation( + m_fRotation, + anchorPos + ) * D2D1::Matrix3x2F::Skew( + m_fSkewAngleX, + m_fSkewAngleY, + anchorPos + ) * D2D1::Matrix3x2F::Translation( + upperLeftCorner.x, + upperLeftCorner.y + ); +} + +void e2d::ENode::_updateChildrenTransform() +{ + for (const auto &child : m_vChildren) { - // 二维矩形变换 - m_Matri = D2D1::Matrix3x2F::Identity(); - m_Matri = m_Matri.Translation(m_fPosX, m_fPosY); - m_Matri = m_Matri.Rotation(m_fRotation); - m_Matri = m_Matri.Scale(m_fScaleX, m_fScaleY); - m_Matri = m_Matri.Skew(m_fSkewAngleX, m_fSkewAngleY); - - if (m_pParent) - { - //m_Matri.SetProduct() - } - - // 提示子节点更新属性 - for (const auto &child : m_vChildren) - { - child->m_bTransformNeeded = true; - } - - m_bTransformNeeded = false; + _updateTransform(child); } } +void e2d::ENode::_updateTransform(ENode * node) +{ + node->_updateTransformToReal(); + if (node->m_pParent) + { + node->m_Matri = node->m_Matri * node->m_pParent->m_Matri; + } + // 遍历子节点下的所有节点 + node->_updateChildrenTransform(); + node->m_bTransformChildrenNeeded = false; +} + +void e2d::ENode::_updateChildrenOpacity() +{ + for (const auto &child : m_vChildren) + { + _updateOpacity(child); + } +} + +void e2d::ENode::_updateOpacity(ENode * node) +{ + if (node->m_pParent) + { + node->m_fDisplayOpacity = node->m_fRealOpacity * node->m_pParent->m_fDisplayOpacity; + } + node->_updateChildrenOpacity(); +} + bool e2d::ENode::isVisiable() const { return m_bVisiable; @@ -179,7 +225,7 @@ float e2d::ENode::getRotation() const float e2d::ENode::getOpacity() const { - return m_fDisplayOpacity; + return m_fRealOpacity; } int e2d::ENode::getOrder() const @@ -207,10 +253,9 @@ void e2d::ENode::setPos(float x, float y) if (m_fPosX == x && m_fPosY == y) return; - //m_Matri.Translation(x, y); m_fPosX = x; m_fPosY = y; - m_bTransformNeeded = true; + m_bTransformChildrenNeeded = true; } void e2d::ENode::move(float x, float y) @@ -235,6 +280,7 @@ void e2d::ENode::setSize(float width, float height) m_fWidth = width; m_fHeight = height; + m_bTransformChildrenNeeded = true; } void e2d::ENode::setScaleX(float scaleX) @@ -257,10 +303,9 @@ void e2d::ENode::setScale(float scaleX, float scaleY) if (m_fScaleX == scaleX && m_fScaleY == scaleY) return; - //m_Matri.Scale(scaleX, scaleY); m_fScaleX = scaleX; m_fScaleY = scaleY; - m_bTransformNeeded = true; + m_bTransformChildrenNeeded = true; } void e2d::ENode::setSkewX(float angleX) @@ -278,10 +323,9 @@ void e2d::ENode::setSkew(float angleX, float angleY) if (m_fSkewAngleX == angleX && m_fSkewAngleY == angleY) return; - //m_Matri.Skew(angleX, angleY); m_fSkewAngleX = angleX; m_fSkewAngleY = angleY; - m_bTransformNeeded = true; + m_bTransformChildrenNeeded = true; } void e2d::ENode::setRotation(float angle) @@ -289,14 +333,38 @@ void e2d::ENode::setRotation(float angle) if (m_fRotation == angle) return; - //m_Matri.Rotation(angle); m_fRotation = angle; - m_bTransformNeeded = true; + m_bTransformChildrenNeeded = true; } void e2d::ENode::setOpacity(float opacity) { - m_fDisplayOpacity = m_fRealOpacity = opacity; + if (m_fRealOpacity == opacity) + return; + + m_fDisplayOpacity = m_fRealOpacity = min(max(opacity, 0), 1); + // 更新子节点透明度 + _updateChildrenOpacity(); +} + +void e2d::ENode::setAnchorX(float anchorX) +{ + this->setAnchor(anchorX, m_fAnchorY); +} + +void e2d::ENode::setAnchorY(float anchorY) +{ + this->setAnchor(m_fAnchorX, anchorY); +} + +void e2d::ENode::setAnchor(float anchorX, float anchorY) +{ + if (m_fAnchorX == anchorX && m_fAnchorY == anchorY) + return; + + m_fAnchorX = min(max(anchorX, 0), 1); + m_fAnchorY = min(max(anchorY, 0), 1); + m_bTransformChildrenNeeded = true; } void e2d::ENode::setParent(ENode * parent) @@ -325,13 +393,15 @@ void e2d::ENode::addChild(ENode * child, int order /* = 0 */) m_vChildren.push_back(child); - child->m_pParent = this; - child->setOrder(order); child->retain(); - m_bSortNeeded = true; + child->m_pParent = this; + + _updateOpacity(child); + + m_bSortChildrenNeeded = true; } } diff --git a/Easy2D/Node/ESprite.cpp b/Easy2D/Node/ESprite.cpp new file mode 100644 index 00000000..e284503a --- /dev/null +++ b/Easy2D/Node/ESprite.cpp @@ -0,0 +1,289 @@ +#include "..\enodes.h" +#include + +static std::map s_mBitmapsFromFile; +//static std::map s_mBitmapsFromResource; + +static ID2D1Bitmap * GetBitmapFromFile(e2d::EString fileName); +static ID2D1Bitmap * GetBitmapFromResource(e2d::EString resourceName, e2d::EString resourceType); + +static bool _loadBitmapFromFile(e2d::EString fileName); +static bool _loadBitmapFromResource(e2d::EString resourceName, e2d::EString resourceType); + + +e2d::ESprite::ESprite() +{ +} + +e2d::ESprite::ESprite(EString imageFileName) + : ESprite() +{ + setImage(imageFileName); +} + +e2d::ESprite::ESprite(EString resourceName, EString resourceType) + : ESprite() +{ + setImage(resourceName, resourceType); +} + +void e2d::ESprite::setImage(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(&pBitmap); + pBitmap = GetBitmapFromFile(m_sFileName); + + ASSERT(pBitmap, "ESprite create device resources failed!"); + + this->setSize(pBitmap->GetSize().width, pBitmap->GetSize().height); +} + +void e2d::ESprite::setImage(EString resourceName, 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(&pBitmap); + pBitmap = GetBitmapFromResource(resourceName, resourceType); + + ASSERT(pBitmap, "ESprite create device resources failed!"); + + this->setSize(pBitmap->GetSize().width, pBitmap->GetSize().height); +} + +void e2d::ESprite::_onRender() +{ + if (pBitmap) + { + // Draw bitmap + GetRenderTarget()->DrawBitmap( + pBitmap, + D2D1::RectF(0, 0, m_fWidth, m_fHeight), + m_fDisplayOpacity + ); + } +} + + + + +bool _loadBitmapFromFile(e2d::EString fileName) +{ + 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)) + { + // Create the initial frame. + hr = pDecoder->GetFrame(0, &pSource); + } + + if (SUCCEEDED(hr)) + { + // Convert the image format to 32bppPBGRA + // (DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED). + hr = GetImagingFactory()->CreateFormatConverter(&pConverter); + } + if (SUCCEEDED(hr)) + { + hr = pConverter->Initialize( + pSource, + GUID_WICPixelFormat32bppPBGRA, + WICBitmapDitherTypeNone, + NULL, + 0.f, + WICBitmapPaletteTypeMedianCut + ); + } + if (SUCCEEDED(hr)) + { + // Create a Direct2D bitmap from the WIC bitmap. + hr = GetRenderTarget()->CreateBitmapFromWicBitmap( + pConverter, + NULL, + &pBitmap + ); + } + if (SUCCEEDED(hr)) + { + 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 _loadBitmapFromResource(e2d::EString resourceName, e2d::EString resourceType) +{ + 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; + + // Locate the resource. + imageResHandle = FindResourceW(HINST_THISCOMPONENT, resourceName.c_str(), resourceType.c_str()); + + hr = imageResHandle ? S_OK : E_FAIL; + if (SUCCEEDED(hr)) + { + // Load the resource. + imageResDataHandle = LoadResource(HINST_THISCOMPONENT, imageResHandle); + + hr = imageResDataHandle ? S_OK : E_FAIL; + } + + if (SUCCEEDED(hr)) + { + // Lock it to get a system memory pointer. + pImageFile = LockResource(imageResDataHandle); + + hr = pImageFile ? S_OK : E_FAIL; + } + + if (SUCCEEDED(hr)) + { + // Calculate the size. + imageFileSize = SizeofResource(HINST_THISCOMPONENT, imageResHandle); + + hr = imageFileSize ? S_OK : E_FAIL; + } + + if (SUCCEEDED(hr)) + { + // Create a WIC stream to map onto the memory. + hr = GetImagingFactory()->CreateStream(&pStream); + } + + if (SUCCEEDED(hr)) + { + // Initialize the stream with the memory pointer and size. + hr = pStream->InitializeFromMemory( + reinterpret_cast(pImageFile), + imageFileSize + ); + } + + if (SUCCEEDED(hr)) + { + // Create a decoder for the stream. + hr = GetImagingFactory()->CreateDecoderFromStream( + pStream, + NULL, + WICDecodeMetadataCacheOnLoad, + &pDecoder + ); + } + + if (SUCCEEDED(hr)) + { + // Create the initial frame. + hr = pDecoder->GetFrame(0, &pSource); + } + + if (SUCCEEDED(hr)) + { + // Convert the image format to 32bppPBGRA + // (DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED). + hr = GetImagingFactory()->CreateFormatConverter(&pConverter); + } + + if (SUCCEEDED(hr)) + { + hr = pConverter->Initialize( + pSource, + GUID_WICPixelFormat32bppPBGRA, + WICBitmapDitherTypeNone, + NULL, + 0.f, + WICBitmapPaletteTypeMedianCut + ); + } + + if (SUCCEEDED(hr)) + { + //create a Direct2D bitmap from the WIC bitmap. + hr = GetRenderTarget()->CreateBitmapFromWicBitmap( + pConverter, + NULL, + &pBitmap + ); + } + + SafeReleaseInterface(&pDecoder); + SafeReleaseInterface(&pSource); + SafeReleaseInterface(&pStream); + SafeReleaseInterface(&pConverter); + SafeReleaseInterface(&pScaler); + + return SUCCEEDED(hr); +} + +ID2D1Bitmap * GetBitmapFromFile(e2d::EString fileName) +{ + std::hash h; + size_t hash = h(fileName); + + if (s_mBitmapsFromFile.find(hash) == s_mBitmapsFromFile.end()) + { + if (!_loadBitmapFromFile(fileName)) + { + return nullptr; + } + } + return s_mBitmapsFromFile.at(hash); +} + +ID2D1Bitmap * GetBitmapFromResource(e2d::EString resourceName, e2d::EString resourceType) +{ + return nullptr; +} \ No newline at end of file diff --git a/Easy2D/Win/winbase.cpp b/Easy2D/Win/winbase.cpp index 0773d764..60ace85c 100644 --- a/Easy2D/Win/winbase.cpp +++ b/Easy2D/Win/winbase.cpp @@ -4,6 +4,7 @@ HWND hwnd = nullptr; ID2D1Factory * pDirect2dFactory = nullptr; ID2D1HwndRenderTarget * pRenderTarget = nullptr; ID2D1SolidColorBrush * m_pSolidBrush = nullptr; +IWICImagingFactory * pIWICFactory = nullptr; HWND &GetHWnd() @@ -16,12 +17,47 @@ ID2D1Factory * &GetFactory() return pDirect2dFactory; } +IWICImagingFactory * &GetImagingFactory() +{ + if (!pIWICFactory) + { + CoCreateInstance( + CLSID_WICImagingFactory, + NULL, + CLSCTX_INPROC_SERVER, + IID_IWICImagingFactory, + reinterpret_cast(&pIWICFactory) + ); + } + return pIWICFactory; +} + ID2D1HwndRenderTarget * &GetRenderTarget() { + if (!pRenderTarget) + { + RECT rc; + GetClientRect(hwnd, &rc); + + D2D1_SIZE_U size = D2D1::SizeU( + rc.right - rc.left, + rc.bottom - rc.top + ); + + // Create a Direct2D render target. + HRESULT hr; + hr = pDirect2dFactory->CreateHwndRenderTarget( + D2D1::RenderTargetProperties(), + D2D1::HwndRenderTargetProperties(hwnd, size), + &pRenderTarget + ); + + ASSERT(SUCCEEDED(hr), "Create Render Target Failed!"); + } return pRenderTarget; } -ID2D1SolidColorBrush *& GetSolidColorBrush() +ID2D1SolidColorBrush * &GetSolidColorBrush() { if (!m_pSolidBrush) { diff --git a/Easy2D/Win/winbase.h b/Easy2D/Win/winbase.h index 1500d3ae..5185704f 100644 --- a/Easy2D/Win/winbase.h +++ b/Easy2D/Win/winbase.h @@ -6,7 +6,14 @@ #include #pragma comment(lib, "d2d1.lib") #pragma comment(lib, "dwrite.lib") -//#pragma comment(lib, "wincodec.lib") +#pragma comment(lib, "windowscodecs.lib") + + +#ifndef HINST_THISCOMPONENT +EXTERN_C IMAGE_DOS_HEADER __ImageBase; +#define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase) +#endif + HWND &GetHWnd(); @@ -16,6 +23,7 @@ ID2D1HwndRenderTarget * &GetRenderTarget(); ID2D1SolidColorBrush * &GetSolidColorBrush(); +IWICImagingFactory * &GetImagingFactory(); template inline void SafeReleaseInterface( diff --git a/Easy2D/ebase.h b/Easy2D/ebase.h index c6526bcc..db301a82 100644 --- a/Easy2D/ebase.h +++ b/Easy2D/ebase.h @@ -212,6 +212,12 @@ protected: // 子节点排序 void _sortChildren(); + // 进入场景时需调用该函数 + virtual void _onEnter(); + + // 退出场景时需调用该函数 + virtual void _onExit(); + protected: bool m_bSortNeeded; bool m_bWillSave; diff --git a/Easy2D/ecommon.h b/Easy2D/ecommon.h index 9c2a306d..1d226fd5 100644 --- a/Easy2D/ecommon.h +++ b/Easy2D/ecommon.h @@ -26,6 +26,8 @@ typedef struct typedef std::function KEY_LISTENER_CALLBACK; typedef std::function MOUSE_LISTENER_CALLBACK; typedef std::function MOUSE_CLICK_LISTENER_CALLBACK; +typedef MOUSE_CLICK_LISTENER_CALLBACK MOUSE_PRESS_LISTENER_CALLBACK; +typedef MOUSE_CLICK_LISTENER_CALLBACK MOUSE_DBLCLK_LISTENER_CALLBACK; typedef std::function MOUSE_DRAG_LISTENER_CALLBACK; diff --git a/Easy2D/emacros.h b/Easy2D/emacros.h index 26073f69..8d86d282 100644 --- a/Easy2D/emacros.h +++ b/Easy2D/emacros.h @@ -22,6 +22,11 @@ #include #include +// C RunTime Header Files +#include +#include +#include + #ifndef ASSERT_IF #if defined( DEBUG ) || defined( _DEBUG ) diff --git a/Easy2D/emsg.h b/Easy2D/emsg.h index bc5554a8..59cbee0b 100644 --- a/Easy2D/emsg.h +++ b/Easy2D/emsg.h @@ -244,6 +244,39 @@ protected: }; +// 鼠标按下消息监听器 +class EMousePressListener : + public EMouseListener +{ +public: + EMousePressListener(); + + EMousePressListener( + EString name + ); + + EMousePressListener( + const MOUSE_PRESS_LISTENER_CALLBACK &callback + ); + + EMousePressListener( + EString name, + const MOUSE_PRESS_LISTENER_CALLBACK &callback + ); + + // 执行监听器回调函数 + virtual void runCallback() override; + + // 设置监听器回调函数 + void setCallback( + const MOUSE_PRESS_LISTENER_CALLBACK &callback + ); + +protected: + MOUSE_PRESS_LISTENER_CALLBACK m_callback; +}; + + // 鼠标点击消息监听器 class EMouseClickListener : public EMouseListener @@ -273,26 +306,61 @@ public: ); protected: + bool m_bPressed; MOUSE_CLICK_LISTENER_CALLBACK m_callback; }; -// 鼠标拖动消息监听器 -class EMouseDraggedListener : +// 鼠标点击消息监听器 +class EMouseDoubleClickListener : public EMouseListener { public: - EMouseDraggedListener(); + EMouseDoubleClickListener(); - EMouseDraggedListener( + EMouseDoubleClickListener( EString name ); - EMouseDraggedListener( + EMouseDoubleClickListener( + const MOUSE_DBLCLK_LISTENER_CALLBACK &callback + ); + + EMouseDoubleClickListener( + EString name, + const MOUSE_DBLCLK_LISTENER_CALLBACK &callback + ); + + // 执行监听器回调函数 + virtual void runCallback() override; + + // 设置监听器回调函数 + void setCallback( + const MOUSE_DBLCLK_LISTENER_CALLBACK &callback + ); + +protected: + bool m_bPressed; + MOUSE_DBLCLK_LISTENER_CALLBACK m_callback; +}; + + +// 鼠标拖动消息监听器 +class EMouseDragListener : + public EMouseListener +{ +public: + EMouseDragListener(); + + EMouseDragListener( + EString name + ); + + EMouseDragListener( const MOUSE_DRAG_LISTENER_CALLBACK &callback ); - EMouseDraggedListener( + EMouseDragListener( EString name, const MOUSE_DRAG_LISTENER_CALLBACK &callback ); @@ -306,8 +374,7 @@ public: ); protected: - EPoint m_Begin; - EPoint m_End; + EPoint m_Begin; MOUSE_DRAG_LISTENER_CALLBACK m_callback; }; diff --git a/Easy2D/enodes.h b/Easy2D/enodes.h index eb50fb6f..40483a3e 100644 --- a/Easy2D/enodes.h +++ b/Easy2D/enodes.h @@ -8,6 +8,8 @@ namespace e2d class ENode : public EObject { + friend EScene; + public: ENode(); @@ -35,10 +37,10 @@ public: // 获取节点高度 virtual float getHeight() const; - // 获取节点横向缩放倍数 + // 获取节点横向缩放比例 virtual float getScaleX() const; - // 获取节点纵向缩放倍数 + // 获取节点纵向缩放比例 virtual float getScaleY() const; // 获取节点横向倾斜角度 @@ -125,57 +127,86 @@ public: ); // 设置节点绘图顺序 + // 默认为 0 virtual void setOrder( int order ); - // 设置横向缩放 + // 设置横向缩放比例 + // 默认为 1.0f virtual void setScaleX( float scaleX ); - // 设置纵向缩放 + // 设置纵向缩放比例 + // 默认为 1.0f virtual void setScaleY( float scaleY ); - // 设置缩放 + // 设置缩放比例 + // 默认为 (1.0f, 1.0f) virtual void setScale( float scaleX, float scaleY ); - // 设置缩放 + // 设置缩放比例 + // 默认为 1.0f virtual void setScale( float scale ); // 设置横向倾斜角度 + // 默认为 0 virtual void setSkewX( float angleX ); // 设置纵向倾斜角度 + // 默认为 0 virtual void setSkewY( float angleY ); // 设置倾斜角度 + // 默认为 (0, 0) virtual void setSkew( float angleX, float angleY ); // 设置旋转角度 + // 默认为 0 virtual void setRotation( float rotation ); // 设置透明度 + // 默认为 1.0f, 范围 [0, 1] virtual void setOpacity( float opacity ); + // 设置纵向锚点 + // 默认为 0, 范围 [0, 1] + virtual void setAnchorX( + float anchorX + ); + + // 设置横向锚点 + // 默认为 0, 范围 [0, 1] + virtual void setAnchorY( + float anchorY + ); + + // 设置锚点 + // 默认为 (0, 0), 范围 [0, 1] + virtual void setAnchor( + float anchorX, + float anchorY + ); + // 设置节点所在场景 virtual void setParentScene( EScene * scene @@ -209,18 +240,30 @@ public: bool release = false ); - // 访问节点 - virtual void callOn(); - protected: + // 访问节点 + virtual void _callOn(); + // 渲染节点 virtual void _onRender(); // 子节点排序 void _sortChildren(); - // 节点状态转换 - void _transfrom(); + // 只考虑自身进行二维矩阵变换 + void _updateTransformToReal(); + + // 更新所有子节点矩阵 + void _updateChildrenTransform(); + + // 更新所有子节点透明度 + void _updateChildrenOpacity(); + + // 更新节点矩阵 + static void _updateTransform(ENode * node); + + // 更新节点透明度 + static void _updateOpacity(ENode * node); protected: EString m_sName; @@ -236,11 +279,13 @@ protected: float m_fSkewAngleY; float m_fDisplayOpacity; float m_fRealOpacity; + float m_fAnchorX; + float m_fAnchorY; D2D1::Matrix3x2F m_Matri; int m_nOrder; bool m_bVisiable; - bool m_bSortNeeded; - bool m_bTransformNeeded; + bool m_bSortChildrenNeeded; + bool m_bTransformChildrenNeeded; EScene * m_pParentScene; ENode * m_pParent; std::vector m_vChildren; @@ -264,4 +309,29 @@ protected: EColor::Enum m_Color; }; + +class ESprite : + public ENode +{ +public: + ESprite(); + + ESprite(EString imageFileName); + + ESprite(EString resourceName, EString resourceType); + + void setImage(EString fileName); + + void setImage(EString resourceName, EString resourceType); + +protected: + virtual void _onRender() override; + +protected: + EString m_sFileName; + EString m_sResourceName; + EString m_sResourceType; + ID2D1Bitmap * pBitmap; +}; + } \ No newline at end of file