From c5feaaf2d98812e78c18519ec5f0730df00d79d7 Mon Sep 17 00:00:00 2001 From: ThorsDev Date: Mon, 22 Sep 2025 17:48:21 +0200 Subject: [PATCH] scissor rect --- src/EterLib/StateManager.cpp | 11 ++ src/EterLib/StateManager.h | 4 + src/EterPythonLib/PythonWindow.cpp | 126 ++++++++++++++++-- src/EterPythonLib/PythonWindow.h | 6 + .../PythonWindowManagerModule.cpp | 33 +++++ 5 files changed, 172 insertions(+), 8 deletions(-) diff --git a/src/EterLib/StateManager.cpp b/src/EterLib/StateManager.cpp index c2db05c..e12c0b2 100644 --- a/src/EterLib/StateManager.cpp +++ b/src/EterLib/StateManager.cpp @@ -26,6 +26,16 @@ void CStateManager::GetLight(DWORD index, D3DLIGHT9* pLight) *pLight = m_kLightData.m_akD3DLight[index]; } +void CStateManager::SetScissorRect(const RECT& c_rRect) +{ + m_lpD3DDev->SetScissorRect(&c_rRect); +} + +void CStateManager::GetScissorRect(RECT* pRect) +{ + m_lpD3DDev->GetScissorRect(pRect); +} + bool CStateManager::BeginScene() { m_bScene = true; @@ -216,6 +226,7 @@ void CStateManager::SetDefaultState() SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_DISABLE); SetRenderState(D3DRS_CLIPPLANEENABLE, 0); SaveVertexProcessing(FALSE); + SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE); SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF); SetRenderState(D3DRS_PATCHEDGESTYLE, D3DPATCHEDGE_CONTINUOUS); diff --git a/src/EterLib/StateManager.h b/src/EterLib/StateManager.h index da88f93..4acd1c3 100644 --- a/src/EterLib/StateManager.h +++ b/src/EterLib/StateManager.h @@ -245,6 +245,10 @@ public: void SetLight(DWORD index, CONST D3DLIGHT9* pLight); void GetLight(DWORD index, D3DLIGHT9* pLight); + // Scissor Rect + void SetScissorRect(const RECT& c_rRect); + void GetScissorRect(RECT* pRect); + // Renderstates void SaveRenderState(D3DRENDERSTATETYPE Type, DWORD dwValue); void RestoreRenderState(D3DRENDERSTATETYPE Type); diff --git a/src/EterPythonLib/PythonWindow.cpp b/src/EterPythonLib/PythonWindow.cpp index ad0d4de..8e3c763 100644 --- a/src/EterPythonLib/PythonWindow.cpp +++ b/src/EterPythonLib/PythonWindow.cpp @@ -4,11 +4,63 @@ #include "PythonSlotWindow.h" #include "PythonWindowManager.h" +#include "EterLib/StateManager.h" + BOOL g_bOutlineBoxEnable = FALSE; namespace UI { - + struct ScopedScissorRect + { + DWORD __OldState = 0; + RECT __OldRect = { 0 }; + + bool __Enable; + RECT __Rect; + + ScopedScissorRect(const RECT& rect, bool enable) + : __Rect(rect), __Enable(enable) + { + __OldState = STATEMANAGER.GetRenderState(D3DRS_SCISSORTESTENABLE); + STATEMANAGER.GetScissorRect(&__OldRect); + + STATEMANAGER.SetRenderState(D3DRS_SCISSORTESTENABLE, enable); + STATEMANAGER.SetScissorRect(rect); + } + + ~ScopedScissorRect() + { + STATEMANAGER.SetRenderState(D3DRS_SCISSORTESTENABLE, __OldState); + STATEMANAGER.SetScissorRect(__OldRect); + } + }; + + template + CWindow* FindWindowUpwards(CWindow* start, Func& f) + { + while (start && start->IsWindow()) + { + if (f(start)) + return start; + + start = start->GetParent(); + } + + } + + static CWindow* GetParentScissorWindow(CWindow* pWin) + { + if (!pWin) + return nullptr; + + auto f = [](CWindow* pCurrWin) -> bool + { + return pCurrWin->IsScissorRectEnabled(); + }; + + return FindWindowUpwards(pWin, f); + } + CWindow::CWindow(PyObject * ppyObject) : m_x(0), m_y(0), @@ -16,6 +68,7 @@ namespace UI m_lHeight(0), m_poHandler(ppyObject), m_bShow(false), + m_bEnableScissorRect(false), m_pParent(NULL), m_dwFlag(0), m_isUpdatingChildren(FALSE) @@ -145,15 +198,57 @@ namespace UI if (!IsShow()) return; - OnRender(); - - if (g_bOutlineBoxEnable) + if (m_bEnableScissorRect) { - CPythonGraphic::Instance().SetDiffuseColor(1.0f, 1.0f, 1.0f); - CPythonGraphic::Instance().RenderBox2d(m_rect.left, m_rect.top, m_rect.right, m_rect.bottom); - } + + RECT scissorRect; + scissorRect.left = std::max(0, m_rect.left); + scissorRect.top = std::max(0, m_rect.top); + scissorRect.right = m_rect.left + m_lWidth; + scissorRect.bottom = m_rect.top + m_lHeight; - std::for_each(m_pChildList.begin(), m_pChildList.end(), std::mem_fn(&CWindow::Render)); + CWindow* pParentScissorWindow = GetParentScissorWindow(GetParent()); + + if (pParentScissorWindow) + { + const RECT& parentRect = pParentScissorWindow->m_rect; + RECT parentScissorRect; + + parentScissorRect.left = std::max(0, parentRect.left); + parentScissorRect.top = std::max(0, parentRect.top); + parentScissorRect.right = parentRect.left + pParentScissorWindow->GetWidth(); + parentScissorRect.bottom = parentRect.top + pParentScissorWindow->GetHeight(); + + scissorRect.left = std::max(scissorRect.left, parentScissorRect.left); + scissorRect.top = std::max(scissorRect.top, parentScissorRect.top); + scissorRect.right = std::min(scissorRect.right, parentScissorRect.right); + scissorRect.bottom = std::min(scissorRect.bottom, parentScissorRect.bottom); + } + + ScopedScissorRect scopedScissorRect(scissorRect, true); + + OnRender(); + + if (g_bOutlineBoxEnable) + { + CPythonGraphic::Instance().SetDiffuseColor(1.0f, 1.0f, 1.0f); + CPythonGraphic::Instance().RenderBox2d(m_rect.left, m_rect.top, m_rect.right, m_rect.bottom); + } + + std::for_each(m_pChildList.begin(), m_pChildList.end(), std::mem_fn(&CWindow::Render)); + } + else + { + OnRender(); + + if (g_bOutlineBoxEnable) + { + CPythonGraphic::Instance().SetDiffuseColor(1.0f, 1.0f, 1.0f); + CPythonGraphic::Instance().RenderBox2d(m_rect.left, m_rect.top, m_rect.right, m_rect.bottom); + } + + std::for_each(m_pChildList.begin(), m_pChildList.end(), std::mem_fn(&CWindow::Render)); + } } void CWindow::OnUpdate() @@ -171,6 +266,21 @@ namespace UI } + void CWindow::EnableScissorRect() + { + m_bEnableScissorRect = true; + } + + void CWindow::DisableScissorRect() + { + m_bEnableScissorRect = false; + } + + bool CWindow::IsScissorRectEnabled() const + { + return m_bEnableScissorRect; + } + void CWindow::OnRender() { if (!m_poHandler) diff --git a/src/EterPythonLib/PythonWindow.h b/src/EterPythonLib/PythonWindow.h index c05497b..6b08f0f 100644 --- a/src/EterPythonLib/PythonWindow.h +++ b/src/EterPythonLib/PythonWindow.h @@ -99,6 +99,11 @@ namespace UI void AddFlag(DWORD flag) { SET_BIT(m_dwFlag, flag); } void RemoveFlag(DWORD flag) { REMOVE_BIT(m_dwFlag, flag); } bool IsFlag(DWORD flag) { return (m_dwFlag & flag) ? true : false; } + + + void EnableScissorRect(); + void DisableScissorRect(); + bool IsScissorRectEnabled() const; ///////////////////////////////////// virtual void OnRender(); @@ -173,6 +178,7 @@ namespace UI bool m_bMovable; bool m_bShow; + bool m_bEnableScissorRect; DWORD m_dwFlag; diff --git a/src/EterPythonLib/PythonWindowManagerModule.cpp b/src/EterPythonLib/PythonWindowManagerModule.cpp index 44c8156..9262ef9 100644 --- a/src/EterPythonLib/PythonWindowManagerModule.cpp +++ b/src/EterPythonLib/PythonWindowManagerModule.cpp @@ -2307,6 +2307,35 @@ PyObject * wndMgrShowOverInWindowName(PyObject * poSelf, PyObject * poArgs) return Py_BuildNone(); } +PyObject* wndMgrEnableScissorRect(PyObject* poSelf, PyObject* poArgs) +{ + UI::CWindow* pWindow; + if (!PyTuple_GetWindow(poArgs, 0, &pWindow)) + return Py_BuildException(); + + pWindow->EnableScissorRect(); + Py_RETURN_NONE; +} + +PyObject* wndMgrDisableScissorRect(PyObject* poSelf, PyObject* poArgs) +{ + UI::CWindow* pWindow; + if (!PyTuple_GetWindow(poArgs, 0, &pWindow)) + return Py_BuildException(); + + pWindow->DisableScissorRect(); + Py_RETURN_NONE; +} + +PyObject* wndMgrIsScissorRectEnabled(PyObject* poSelf, PyObject* poArgs) +{ + UI::CWindow* pWindow; + if (!PyTuple_GetWindow(poArgs, 0, &pWindow)) + return Py_BuildException(); + + return Py_BuildValue("b", pWindow->IsScissorRectEnabled()); +} + void initwndMgr() { static PyMethodDef s_methods[] = @@ -2502,6 +2531,10 @@ void initwndMgr() { "SetOutlineFlag", wndMgrSetOutlineFlag, METH_VARARGS }, { "ShowOverInWindowName", wndMgrShowOverInWindowName, METH_VARARGS }, + { "EnableScissorRect", wndMgrEnableScissorRect, METH_VARARGS }, + { "DisableScissorRect", wndMgrDisableScissorRect, METH_VARARGS }, + { "IsScissorRectEnabled", wndMgrIsScissorRectEnabled, METH_VARARGS }, + { NULL, NULL, NULL }, };