diff --git a/src/kiwano-imgui/ImGuiModule.cpp b/src/kiwano-imgui/ImGuiModule.cpp index ccfe6a28..84d1dff8 100644 --- a/src/kiwano-imgui/ImGuiModule.cpp +++ b/src/kiwano-imgui/ImGuiModule.cpp @@ -65,12 +65,12 @@ void ImGuiModule::DestroyModule() ImGui::DestroyContext(); } -void ImGuiModule::OnUpdate(Duration dt) +void ImGuiModule::OnUpdate(UpdateModuleContext& ctx) { ImGuiIO& io = ImGui::GetIO(); // Setup time step - io.DeltaTime = dt.Seconds(); + io.DeltaTime = ctx.dt.Seconds(); // Read keyboard modifiers inputs io.KeyCtrl = Input::GetInstance().IsDown(KeyCode::Ctrl); @@ -84,86 +84,97 @@ void ImGuiModule::OnUpdate(Duration dt) // Update OS mouse cursor with the cursor requested by imgui UpdateMouseCursor(); + + ctx.Next(); } -void ImGuiModule::BeforeRender() +void ImGuiModule::OnRender(RenderModuleContext& ctx) { - ImGui_Impl_NewFrame(); - - ImGuiIO& io = ImGui::GetIO(); - KGE_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built!"); - - // Setup display size (every frame to accommodate for window resizing) - Size display_size = Renderer::GetInstance().GetOutputSize(); - io.DisplaySize = ImVec2(display_size.x, display_size.y); - - ImGui::NewFrame(); -} - -void ImGuiModule::AfterRender() -{ - ImGui::Render(); - - ImGui_Impl_RenderDrawData(ImGui::GetDrawData()); -} - -void ImGuiModule::HandleEvent(Event* evt) -{ - if (ImGui::GetCurrentContext() == NULL) - return; - - ImGuiIO& io = ImGui::GetIO(); - if (evt->IsType()) + // Before render { - if (evt->IsType()) + ImGui_Impl_NewFrame(); + + ImGuiIO& io = ImGui::GetIO(); + KGE_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built!"); + + // Setup display size (every frame to accommodate for window resizing) + Size display_size = Renderer::GetInstance().GetOutputSize(); + io.DisplaySize = ImVec2(display_size.x, display_size.y); + + ImGui::NewFrame(); + } + + ctx.Next(); + + // After render + { + ImGui::Render(); + + ImGui_Impl_RenderDrawData(ImGui::GetDrawData()); + } +} + +void ImGuiModule::HandleEvent(EventModuleContext& ctx) +{ + if (ImGui::GetCurrentContext() != NULL) + { + Event* evt = ctx.evt; + + ImGuiIO& io = ImGui::GetIO(); + if (evt->IsType()) { - MouseButton button = dynamic_cast(evt)->button; - int index = 0; - if (button == MouseButton::Left) - index = 0; - else if (button == MouseButton::Right) - index = 1; - else if (button == MouseButton::Middle) - index = 2; - io.MouseDown[index] = true; + if (evt->IsType()) + { + MouseButton button = dynamic_cast(evt)->button; + int index = 0; + if (button == MouseButton::Left) + index = 0; + else if (button == MouseButton::Right) + index = 1; + else if (button == MouseButton::Middle) + index = 2; + io.MouseDown[index] = true; + } + else if (evt->IsType()) + { + MouseButton button = dynamic_cast(evt)->button; + int index = 0; + if (button == MouseButton::Left) + index = 0; + else if (button == MouseButton::Right) + index = 1; + else if (button == MouseButton::Middle) + index = 2; + io.MouseDown[index] = false; + } + else if (evt->IsType()) + { + float wheel = dynamic_cast(evt)->wheel; + io.MouseWheel += wheel; + } } - else if (evt->IsType()) + else if (evt->IsType()) { - MouseButton button = dynamic_cast(evt)->button; - int index = 0; - if (button == MouseButton::Left) - index = 0; - else if (button == MouseButton::Right) - index = 1; - else if (button == MouseButton::Middle) - index = 2; - io.MouseDown[index] = false; - } - else if (evt->IsType()) - { - float wheel = dynamic_cast(evt)->wheel; - io.MouseWheel += wheel; - } - } - else if (evt->IsType()) - { - if (evt->IsType()) - { - KeyCode key = dynamic_cast(evt)->code; - io.KeysDown[(int)key] = true; - } - else if (evt->IsType()) - { - KeyCode key = dynamic_cast(evt)->code; - io.KeysDown[(int)key] = false; - } - else if (evt->IsType()) - { - // You can also use ToAscii()+GetKeyboardState() to retrieve characters. - char ch = dynamic_cast(evt)->value; - io.AddInputCharacter(static_cast(ch)); + if (evt->IsType()) + { + KeyCode key = dynamic_cast(evt)->code; + io.KeysDown[(int)key] = true; + } + else if (evt->IsType()) + { + KeyCode key = dynamic_cast(evt)->code; + io.KeysDown[(int)key] = false; + } + else if (evt->IsType()) + { + // You can also use ToAscii()+GetKeyboardState() to retrieve characters. + char ch = dynamic_cast(evt)->value; + io.AddInputCharacter(static_cast(ch)); + } } } + + ctx.Next(); } void ImGuiModule::UpdateMousePos() diff --git a/src/kiwano-imgui/ImGuiModule.h b/src/kiwano-imgui/ImGuiModule.h index b5c2d159..53ec924c 100644 --- a/src/kiwano-imgui/ImGuiModule.h +++ b/src/kiwano-imgui/ImGuiModule.h @@ -34,9 +34,7 @@ namespace imgui */ class ImGuiModule : public Singleton - , public RenderModule - , public UpdateModule - , public EventModule + , public Module { friend Singleton; @@ -47,13 +45,11 @@ public: void DestroyModule() override; - void BeforeRender() override; + void OnUpdate(UpdateModuleContext& ctx) override; - void AfterRender() override; + void OnRender(RenderModuleContext& ctx) override; - void HandleEvent(Event* evt) override; - - void OnUpdate(Duration dt) override; + void HandleEvent(EventModuleContext& ctx) override; private: void UpdateMousePos(); diff --git a/src/kiwano/base/Director.cpp b/src/kiwano/base/Director.cpp index 6b221030..d4d09a92 100644 --- a/src/kiwano/base/Director.cpp +++ b/src/kiwano/base/Director.cpp @@ -23,7 +23,6 @@ #include #include #include -#include namespace kiwano { @@ -119,11 +118,11 @@ void Director::ClearStages() debug_actor_.Reset(); } -void Director::OnUpdate(Duration dt) +void Director::OnUpdate(UpdateModuleContext& ctx) { if (transition_) { - transition_->Update(dt); + transition_->Update(ctx.dt); if (transition_->IsDone()) transition_ = nullptr; @@ -143,47 +142,53 @@ void Director::OnUpdate(Duration dt) } if (current_stage_) - current_stage_->Update(dt); + current_stage_->Update(ctx.dt); if (next_stage_) - next_stage_->Update(dt); + next_stage_->Update(ctx.dt); if (debug_actor_) - debug_actor_->Update(dt); + debug_actor_->Update(ctx.dt); + + ctx.Next(); } -void Director::OnRender(RenderContext& ctx) +void Director::OnRender(RenderModuleContext& ctx) { if (transition_) { - transition_->Render(ctx); + transition_->Render(ctx.render_ctx); } else if (current_stage_) { - current_stage_->Render(ctx); + current_stage_->Render(ctx.render_ctx); if (render_border_enabled_) { - current_stage_->RenderBorder(ctx); + current_stage_->RenderBorder(ctx.render_ctx); } } if (debug_actor_) { - debug_actor_->Render(ctx); + debug_actor_->Render(ctx.render_ctx); } + + ctx.Next(); } -void Director::HandleEvent(Event* evt) +void Director::HandleEvent(EventModuleContext& ctx) { if (current_stage_) - current_stage_->DispatchEvent(evt); + current_stage_->DispatchEvent(ctx.evt); if (next_stage_) - next_stage_->DispatchEvent(evt); + next_stage_->DispatchEvent(ctx.evt); if (debug_actor_) - debug_actor_->DispatchEvent(evt); + debug_actor_->DispatchEvent(ctx.evt); + + ctx.Next(); } } // namespace kiwano diff --git a/src/kiwano/base/Director.h b/src/kiwano/base/Director.h index 6a775670..c216e590 100644 --- a/src/kiwano/base/Director.h +++ b/src/kiwano/base/Director.h @@ -34,9 +34,7 @@ namespace kiwano */ class KGE_API Director : public Singleton - , public UpdateModule - , public RenderModule - , public EventModule + , public Module { friend Singleton; @@ -92,15 +90,11 @@ public: void ClearStages(); public: - void SetupModule() override {} + void OnUpdate(UpdateModuleContext& ctx) override; - void DestroyModule() override {} + void OnRender(RenderModuleContext& ctx) override; - void OnUpdate(Duration dt) override; - - void OnRender(RenderContext& ctx) override; - - void HandleEvent(Event* evt) override; + void HandleEvent(EventModuleContext& ctx) override; virtual ~Director(); diff --git a/src/kiwano/base/Module.cpp b/src/kiwano/base/Module.cpp index 009100bb..5f492049 100644 --- a/src/kiwano/base/Module.cpp +++ b/src/kiwano/base/Module.cpp @@ -19,28 +19,86 @@ // THE SOFTWARE. #include +#include namespace kiwano { -Module::Module() - : flag_(0) +ModuleContext::ModuleContext(ModuleList& modules) + : index_(-1) + , modules_(modules) { } -RenderModule::RenderModule() +ModuleContext::~ModuleContext() {} + +void ModuleContext::Next() { - flag_ |= ModuleFlag::value; + index_++; + for (; index_ < (int)modules_.size(); index_++) + { + this->Handle(modules_.at(index_)); + } } -UpdateModule::UpdateModule() +RenderModuleContext::RenderModuleContext(ModuleList& modules, RenderContext& ctx) + : ModuleContext(modules) + , render_ctx(ctx) { - flag_ |= ModuleFlag::value; + render_ctx.BeginDraw(); } -EventModule::EventModule() +RenderModuleContext::~RenderModuleContext() { - flag_ |= ModuleFlag::value; + render_ctx.EndDraw(); +} + +void RenderModuleContext::Handle(Module* m) +{ + m->OnRender(*this); +} + +UpdateModuleContext::UpdateModuleContext(ModuleList& modules, Duration dt) + : ModuleContext(modules) + , dt(dt) +{ +} + +void UpdateModuleContext::Handle(Module* m) +{ + m->OnUpdate(*this); +} + +EventModuleContext::EventModuleContext(ModuleList& modules, Event* evt) + : ModuleContext(modules) + , evt(evt) +{ +} + +void EventModuleContext::Handle(Module* m) +{ + m->HandleEvent(*this); +} + +Module::Module() {} + +void Module::SetupModule() {} + +void Module::DestroyModule() {} + +void Module::OnRender(RenderModuleContext& ctx) +{ + ctx.Next(); +} + +void Module::OnUpdate(UpdateModuleContext& ctx) +{ + ctx.Next(); +} + +void Module::HandleEvent(EventModuleContext& ctx) +{ + ctx.Next(); } } // namespace kiwano diff --git a/src/kiwano/base/Module.h b/src/kiwano/base/Module.h index f9a95340..68c66676 100644 --- a/src/kiwano/base/Module.h +++ b/src/kiwano/base/Module.h @@ -25,124 +25,104 @@ namespace kiwano { class RenderContext; class Event; +class Module; -template -struct ModuleFlag; +/// \~chinese +/// @brief 模块列表 +typedef Vector ModuleList; + +/// \~chinese +/// @brief 模块上下文 +class KGE_API ModuleContext +{ +public: + void Next(); + +protected: + ModuleContext(ModuleList& modules); + + virtual ~ModuleContext(); + + virtual void Handle(Module* m) = 0; + +private: + int index_; + ModuleList& modules_; +}; + +/// \~chinese +/// @brief 渲染模块上下文 +class KGE_API RenderModuleContext : public ModuleContext +{ +public: + RenderContext& render_ctx; + + RenderModuleContext(ModuleList& modules, RenderContext& ctx); + + virtual ~RenderModuleContext(); + +protected: + void Handle(Module* m) override; +}; + +/// \~chinese +/// @brief 更新模块上下文 +class KGE_API UpdateModuleContext : public ModuleContext +{ +public: + Duration dt; + + UpdateModuleContext(ModuleList& modules, Duration dt); + +protected: + void Handle(Module* m) override; +}; + +/// \~chinese +/// @brief 时间模块上下文 +class KGE_API EventModuleContext : public ModuleContext +{ +public: + Event* evt; + + EventModuleContext(ModuleList& modules, Event* evt); + +protected: + void Handle(Module* m) override; +}; /** * \~chinese * @brief 基础模块 */ -class KGE_API Module +class KGE_API Module : Noncopyable { public: /// \~chinese /// @brief 启动模块 - virtual void SetupModule() {} + virtual void SetupModule(); /// \~chinese /// @brief 销毁模块 - virtual void DestroyModule() {} - - template - _CompTy* Cast() - { - if (flag_ & ModuleFlag<_CompTy>::value) - return dynamic_cast<_CompTy*>(this); - return nullptr; - } - -protected: - Module(); - -protected: - int flag_; -}; - -/** - * \~chinese - * @brief 渲染模块 - */ -class KGE_API RenderModule : public virtual Module -{ -public: - /// \~chinese - /// @brief 渲染前 - virtual void BeforeRender() {} + virtual void DestroyModule(); /// \~chinese /// @brief 渲染时 /// @param ctx 渲染上下文 - virtual void OnRender(RenderContext& ctx) {} - - /// \~chinese - /// @brief 渲染后 - virtual void AfterRender() {} - -public: - RenderModule(); -}; - -/** - * \~chinese - * @brief 更新模块 - */ -class KGE_API UpdateModule : public virtual Module -{ -public: - /// \~chinese - /// @brief 更新前 - virtual void BeforeUpdate() {} + virtual void OnRender(RenderModuleContext& ctx); /// \~chinese /// @brief 更新时 - /// @param dt 间隔时间 - virtual void OnUpdate(Duration dt) {} + /// @param ctx 更新上下文 + virtual void OnUpdate(UpdateModuleContext& ctx); - /// \~chinese - /// @brief 更新后 - virtual void AfterUpdate() {} - -public: - UpdateModule(); -}; - -/** - * \~chinese - * @brief 事件模块 - */ -class KGE_API EventModule : public virtual Module -{ -public: /// \~chinese /// @brief 事件处理 - /// @param evt 事件 - virtual void HandleEvent(Event* evt) {} + /// @param ctx 事件上下文 + virtual void HandleEvent(EventModuleContext& ctx); -public: - EventModule(); +protected: + Module(); }; -#define KGE_DEFINE_COMPONENT_FLAG(OFFSET) (0x01 << (OFFSET % 32)) - -template <> -struct ModuleFlag -{ - static constexpr int value = KGE_DEFINE_COMPONENT_FLAG(0); -}; - -template <> -struct ModuleFlag -{ - static constexpr int value = KGE_DEFINE_COMPONENT_FLAG(1); -}; - -template <> -struct ModuleFlag -{ - static constexpr int value = KGE_DEFINE_COMPONENT_FLAG(2); -}; - -#undef KGE_DEFINE_COMPONENT_FLAG - } // namespace kiwano diff --git a/src/kiwano/platform/Application.cpp b/src/kiwano/platform/Application.cpp index a117aa31..8e94e6bd 100644 --- a/src/kiwano/platform/Application.cpp +++ b/src/kiwano/platform/Application.cpp @@ -162,13 +162,8 @@ void Application::DispatchEvent(Event* evt) if (!running_ /* Dispatch events even if application is paused */) return; - for (auto comp : modules_) - { - if (auto event_comp = comp->Cast()) - { - event_comp->HandleEvent(evt); - } - } + auto ctx = EventModuleContext(modules_, evt); + ctx.Next(); } void Application::Update(Duration dt) @@ -176,51 +171,24 @@ void Application::Update(Duration dt) if (!running_ || is_paused_) return; - // Before update - for (auto comp : modules_) - { - if (auto update_comp = comp->Cast()) - { - update_comp->BeforeUpdate(); - } - } + auto ctx = UpdateModuleContext(modules_, dt); + ctx.Next(); // perform functions + if (!functions_to_perform_.empty()) { - if (!functions_to_perform_.empty()) - { - perform_mutex_.lock(); - auto functions = std::move(functions_to_perform_); - perform_mutex_.unlock(); + perform_mutex_.lock(); + auto functions = std::move(functions_to_perform_); + perform_mutex_.unlock(); - while (!functions.empty()) + while (!functions.empty()) + { + auto& func = functions.front(); + if (func) { - auto& func = functions.front(); - if (func) - { - func(); - } - functions.pop(); + func(); } - } - } - - // Updating - Duration scaled_dt = dt * time_scale_; - for (auto comp : modules_) - { - if (auto update_comp = comp->Cast()) - { - update_comp->OnUpdate(scaled_dt); - } - } - - // After update - for (auto rit = modules_.rbegin(); rit != modules_.rend(); ++rit) - { - if (auto update_comp = (*rit)->Cast()) - { - update_comp->AfterUpdate(); + functions.pop(); } } } @@ -233,33 +201,9 @@ void Application::Render() Renderer& renderer = Renderer::GetInstance(); renderer.Clear(); - // Before render - for (auto comp : modules_) { - if (auto render_comp = comp->Cast()) - { - render_comp->BeforeRender(); - } - } - - // Rendering - renderer.BeginDraw(); - for (auto comp : modules_) - { - if (auto render_comp = comp->Cast()) - { - render_comp->OnRender(renderer.GetContext()); - } - } - renderer.EndDraw(); - - // After render - for (auto rit = modules_.rbegin(); rit != modules_.rend(); ++rit) - { - if (auto render_comp = (*rit)->Cast()) - { - render_comp->AfterRender(); - } + auto ctx = RenderModuleContext(modules_, renderer.GetContext()); + ctx.Next(); } renderer.Present(); diff --git a/src/kiwano/platform/Application.h b/src/kiwano/platform/Application.h index 670440c3..85e0fc21 100644 --- a/src/kiwano/platform/Application.h +++ b/src/kiwano/platform/Application.h @@ -42,7 +42,8 @@ extern KGE_API int GetVersion(); * \~chinese * @brief 应用程序,控制游戏的整个生命周期,包括初始化、启动、结束以及事件分发等 */ -class KGE_API Application : public Singleton +class KGE_API Application + : public Singleton { friend Singleton; @@ -169,7 +170,7 @@ private: float time_scale_; RunnerPtr runner_; TimerPtr timer_; - List modules_; + ModuleList modules_; std::mutex perform_mutex_; Queue> functions_to_perform_; }; diff --git a/src/kiwano/platform/Input.cpp b/src/kiwano/platform/Input.cpp index 8dd82307..d5451c0e 100644 --- a/src/kiwano/platform/Input.cpp +++ b/src/kiwano/platform/Input.cpp @@ -34,21 +34,6 @@ Input::Input() Input::~Input() {} -void Input::AfterUpdate() -{ - if (want_update_keys_) - { - want_update_keys_ = false; - ::memcpy(keys_[Prev].data(), keys_[Current].data(), KEY_NUM * sizeof(bool)); - } - - if (want_update_buttons_) - { - want_update_buttons_ = false; - buttons_[Prev] = buttons_[Current]; - } -} - bool Input::IsDown(KeyCode key) const { if (key == KeyCode::Unknown || key == KeyCode::Last) @@ -129,8 +114,27 @@ void Input::UpdateMousePos(const Point& pos) mouse_pos_ = pos; } -void Input::HandleEvent(Event* evt) +void Input::OnUpdate(UpdateModuleContext& ctx) { + ctx.Next(); + + if (want_update_keys_) + { + want_update_keys_ = false; + ::memcpy(keys_[Prev].data(), keys_[Current].data(), KEY_NUM * sizeof(bool)); + } + + if (want_update_buttons_) + { + want_update_buttons_ = false; + buttons_[Prev] = buttons_[Current]; + } +} + +void Input::HandleEvent(EventModuleContext& ctx) +{ + Event* evt = ctx.evt; + if (evt->IsType()) { if (evt->IsType()) @@ -157,5 +161,8 @@ void Input::HandleEvent(Event* evt) UpdateKey(dynamic_cast(evt)->code, false); } } + + ctx.Next(); } + } // namespace kiwano diff --git a/src/kiwano/platform/Input.h b/src/kiwano/platform/Input.h index 2bd4ad84..b731e0a5 100644 --- a/src/kiwano/platform/Input.h +++ b/src/kiwano/platform/Input.h @@ -35,8 +35,7 @@ namespace kiwano */ class KGE_API Input : public Singleton - , public UpdateModule - , public EventModule + , public Module { friend Singleton; @@ -104,13 +103,9 @@ public: Point GetMousePos() const; public: - void SetupModule() override {} + void OnUpdate(UpdateModuleContext& ctx) override; - void DestroyModule() override {} - - void AfterUpdate() override; - - void HandleEvent(Event* evt) override; + void HandleEvent(EventModuleContext& ctx) override; ~Input(); diff --git a/src/kiwano/platform/Runner.cpp b/src/kiwano/platform/Runner.cpp index e2e0463c..642704b1 100644 --- a/src/kiwano/platform/Runner.cpp +++ b/src/kiwano/platform/Runner.cpp @@ -91,6 +91,7 @@ void Runner::InitSettings() Renderer::GetInstance().SetVSyncEnabled(settings_.vsync_enabled); // Use defaut modules + Application::GetInstance().Use(Renderer::GetInstance()); Application::GetInstance().Use(Input::GetInstance()); Application::GetInstance().Use(Director::GetInstance()); diff --git a/src/kiwano/render/DirectX/D3D11DeviceResources.cpp b/src/kiwano/render/DirectX/D3D11DeviceResources.cpp index 31e0c3f4..3f5408ca 100644 --- a/src/kiwano/render/DirectX/D3D11DeviceResources.cpp +++ b/src/kiwano/render/DirectX/D3D11DeviceResources.cpp @@ -20,7 +20,6 @@ #include #include -#include KGE_SUPPRESS_WARNING_PUSH KGE_SUPPRESS_WARNING(4800) // Implicit conversion from 'type' to bool diff --git a/src/kiwano/render/DirectX/RendererImpl.cpp b/src/kiwano/render/DirectX/RendererImpl.cpp index 0fc654fa..ef4d04b7 100644 --- a/src/kiwano/render/DirectX/RendererImpl.cpp +++ b/src/kiwano/render/DirectX/RendererImpl.cpp @@ -166,6 +166,15 @@ void RendererImpl::Destroy() ::CoUninitialize(); } +void RendererImpl::HandleEvent(EventModuleContext& ctx) +{ + if (ctx.evt->IsType()) + { + auto evt = ctx.evt->SafeCast(); + Resize(evt->width, evt->height); + } +} + void RendererImpl::Clear() { KGE_ASSERT(d3d_res_); diff --git a/src/kiwano/render/DirectX/RendererImpl.h b/src/kiwano/render/DirectX/RendererImpl.h index 8825d135..dfce0ea0 100644 --- a/src/kiwano/render/DirectX/RendererImpl.h +++ b/src/kiwano/render/DirectX/RendererImpl.h @@ -83,6 +83,8 @@ public: void Destroy() override; + void HandleEvent(EventModuleContext& ctx) override; + protected: RendererImpl(); diff --git a/src/kiwano/render/Renderer.cpp b/src/kiwano/render/Renderer.cpp index ef165491..53904c2c 100644 --- a/src/kiwano/render/Renderer.cpp +++ b/src/kiwano/render/Renderer.cpp @@ -19,8 +19,6 @@ // THE SOFTWARE. #include -#include -#include namespace kiwano { @@ -31,18 +29,4 @@ Renderer::Renderer() { } -void Renderer::BeginDraw() -{ - KGE_ASSERT(render_ctx_); - - render_ctx_->BeginDraw(); -} - -void Renderer::EndDraw() -{ - KGE_ASSERT(render_ctx_); - - render_ctx_->EndDraw(); -} - } // namespace kiwano diff --git a/src/kiwano/render/Renderer.h b/src/kiwano/render/Renderer.h index 742cfb11..48005faf 100644 --- a/src/kiwano/render/Renderer.h +++ b/src/kiwano/render/Renderer.h @@ -44,7 +44,7 @@ namespace kiwano * \~chinese * @brief 渲染器 */ -class KGE_API Renderer : public Noncopyable +class KGE_API Renderer : public Module { public: /// \~chinese @@ -218,14 +218,6 @@ public: virtual RenderContextPtr CreateTextureRenderContext(Texture& texture, const Size* desired_size = nullptr) = 0; public: - /// \~chinese - /// @brief 开始渲染 - virtual void BeginDraw(); - - /// \~chinese - /// @brief 结束渲染 - virtual void EndDraw(); - /// \~chinese /// @brief 清除绘制内容 virtual void Clear() = 0;