diff --git a/projects/kiwano/kiwano.vcxproj b/projects/kiwano/kiwano.vcxproj index d4eadbbe..7199f26f 100644 --- a/projects/kiwano/kiwano.vcxproj +++ b/projects/kiwano/kiwano.vcxproj @@ -19,6 +19,7 @@ + @@ -123,6 +124,7 @@ + diff --git a/projects/kiwano/kiwano.vcxproj.filters b/projects/kiwano/kiwano.vcxproj.filters index 06a3e54e..4fd95326 100644 --- a/projects/kiwano/kiwano.vcxproj.filters +++ b/projects/kiwano/kiwano.vcxproj.filters @@ -300,6 +300,9 @@ platform\win32 + + core + @@ -509,5 +512,8 @@ render\DirectX + + core + \ No newline at end of file diff --git a/src/kiwano-audio/AudioEngine.cpp b/src/kiwano-audio/AudioEngine.cpp index 2a344c86..c6ada268 100644 --- a/src/kiwano-audio/AudioEngine.cpp +++ b/src/kiwano-audio/AudioEngine.cpp @@ -51,7 +51,7 @@ void AudioEngine::SetupComponent() hr = x_audio2_->CreateMasteringVoice(&mastering_voice_); } - win32::ThrowIfFailed(hr); + win32::ThrowIfFailed(hr, "Create audio resources failed"); } void AudioEngine::DestroyComponent() @@ -100,7 +100,7 @@ bool AudioEngine::CreateSound(Sound& sound, const Transcoder::Buffer& buffer) } } - win32::WarnIfFailed(hr); + win32::WarnIfFailed(hr, "Create sound failed"); return SUCCEEDED(hr); } diff --git a/src/kiwano/core/Exception.cpp b/src/kiwano/core/Exception.cpp new file mode 100644 index 00000000..a8418437 --- /dev/null +++ b/src/kiwano/core/Exception.cpp @@ -0,0 +1,60 @@ +// Copyright (c) 2016-2018 Kiwano - Nomango +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include + +namespace kiwano +{ + +Exception::Exception() +{ +} + +Exception::Exception(String const& message) + : message_(message) +{ +} + +Exception::~Exception() +{ +} + +const String& Exception::ToString() const +{ + return message_; +} + +const char* Exception::what() const +{ + return message_.c_str(); +} + +SystemException::SystemException() + : code_(0) +{ +} + +SystemException::SystemException(ErrorCodeType code, String const& message) + : Exception(message) + , code_(code) +{ +} + +} // namespace kiwano diff --git a/src/kiwano/core/Exception.h b/src/kiwano/core/Exception.h new file mode 100644 index 00000000..b616f1a1 --- /dev/null +++ b/src/kiwano/core/Exception.h @@ -0,0 +1,91 @@ +// Copyright (c) 2016-2018 Kiwano - Nomango +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#pragma once +#include +#include +#include + +namespace kiwano +{ + +/** + * \~chinese + * @brief 异常 + */ +class KGE_API Exception : public std::exception +{ +public: + Exception(); + + /// \~chinese + /// @brief 构造异常 + /// @param message 描述异常的信息 + explicit Exception(String const& message); + + virtual ~Exception(); + + /// \~chinese + /// @brief 转为解释性字符串 + const String& ToString() const; + + /// \~chinese + /// @brief 转为解释性字符串 + virtual const char* what() const override; + +protected: + String message_; +}; + +/** + * \~chinese + * @brief 系统异常 + */ +class SystemException : public Exception +{ +public: +#if defined(KGE_WIN32) + /// \~chinese + /// @brief 错误代码类型 + typedef HRESULT ErrorCodeType; +#endif + + SystemException(); + + /// \~chinese + /// @brief 构造系统异常 + /// @param code 错误代码 + /// @param message 描述异常的信息 + SystemException(ErrorCodeType code, String const& message); + + /// \~chinese + /// @brief 获取错误代码 + ErrorCodeType GetErrorCode() const; + +private: + ErrorCodeType code_; +}; + +inline SystemException::ErrorCodeType SystemException::GetErrorCode() const +{ + return code_; +} + +} // namespace kiwano diff --git a/src/kiwano/core/Time.cpp b/src/kiwano/core/Time.cpp index 5792a362..7072d98e 100644 --- a/src/kiwano/core/Time.cpp +++ b/src/kiwano/core/Time.cpp @@ -18,6 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include #include #include #include @@ -357,7 +358,7 @@ Duration Duration::Parse(const String& format) if (!std::regex_match(format.c_str(), duration_regex)) { - throw std::runtime_error("Duration::Parse failed, invalid duration"); + throw Exception("Duration::Parse failed, invalid duration"); } if (format.empty() || format == "0") @@ -390,7 +391,7 @@ Duration Duration::Parse(const String& format) pos = i; if (num_str.empty() || num_str == ".") - throw std::runtime_error("Duration::Parse failed, invalid duration"); + throw Exception("Duration::Parse failed, invalid duration"); // 单位 for (; i < len; ++i) @@ -407,7 +408,7 @@ Duration Duration::Parse(const String& format) pos = i; if (unit_map.find(unit_str) == unit_map.end()) - throw std::runtime_error("Duration::Parse failed, invalid duration"); + throw Exception("Duration::Parse failed, invalid duration"); double num = std::stod(num_str.c_str()); Duration unit = unit_map.at(unit_str); diff --git a/src/kiwano/core/Time.h b/src/kiwano/core/Time.h index 85cbbb03..b7306962 100644 --- a/src/kiwano/core/Time.h +++ b/src/kiwano/core/Time.h @@ -107,7 +107,7 @@ struct KGE_API Duration /// 例如: "300ms", "-1.5h", "2h45m" /// 允许的时间单位有 "ms", "s", "m", "h" /// @return 解析出的时间段 - /// @throw std::runtime_error 传入了一个不合法的格式 + /// @throw kiwano::Exception 传入一个不合法的格式时抛出 static Duration Parse(const String& str); static const Duration Ms; ///< 毫秒 diff --git a/src/kiwano/platform/Window.h b/src/kiwano/platform/Window.h index 0ef4c2b6..3fdd6c25 100644 --- a/src/kiwano/platform/Window.h +++ b/src/kiwano/platform/Window.h @@ -66,7 +66,7 @@ public: * @param icon 图标资源ID * @param resizable 窗口大小可拉伸 * @param fullscreen 全屏模式 - * @throw std::runtime_error 窗口创建失败时抛出 + * @throw kiwano::SystemException 窗口创建失败时抛出 */ virtual void Create(String const& title, uint32_t width, uint32_t height, uint32_t icon = 0, bool resizable = false, bool fullscreen = false) = 0; diff --git a/src/kiwano/platform/win32/WindowImpl.cpp b/src/kiwano/platform/win32/WindowImpl.cpp index c7385e6f..6ae6ebe2 100644 --- a/src/kiwano/platform/win32/WindowImpl.cpp +++ b/src/kiwano/platform/win32/WindowImpl.cpp @@ -24,6 +24,7 @@ #include // GET_X_LPARAM, GET_Y_LPARAM #include // ImmAssociateContext +#include #include #include #include @@ -236,7 +237,7 @@ void WindowImpl::Create(String const& title, uint32_t width, uint32_t height, ui ::UnregisterClassW(L"KiwanoAppWnd", hinst); KGE_ERROR("Failed with HRESULT of %08X", HRESULT_FROM_WIN32(GetLastError())); - throw std::runtime_error("Create window failed"); + throw SystemException(HRESULT_FROM_WIN32(GetLastError()), "Create window failed"); } width_ = width; diff --git a/src/kiwano/platform/win32/helper.h b/src/kiwano/platform/win32/helper.h index b5054afb..13a73723 100644 --- a/src/kiwano/platform/win32/helper.h +++ b/src/kiwano/platform/win32/helper.h @@ -19,9 +19,8 @@ // THE SOFTWARE. #pragma once +#include #include -#include -#include namespace kiwano { @@ -31,25 +30,23 @@ void PrintCallStack(); void PrintCallStackOnContext(PCONTEXT pContext); -inline void ThrowIfFailed(HRESULT hr) +inline void ThrowIfFailed(HRESULT hr, const String& message) { if (FAILED(hr)) { PrintCallStack(); - static char buffer[32]; - sprintf_s(buffer, "Failed with HRESULT of %08X", hr); - throw std::runtime_error(buffer); + throw SystemException(hr, message); } } -inline void WarnIfFailed(HRESULT hr) +inline void WarnIfFailed(HRESULT hr, const String& message) { if (FAILED(hr)) { PrintCallStack(); - KGE_WARN("Failed with HRESULT of %08X", hr); + KGE_WARN("Failed with HRESULT of %08X: ", hr, message.c_str()); } } diff --git a/src/kiwano/platform/win32/libraries.cpp b/src/kiwano/platform/win32/libraries.cpp index 2f2f0b94..c7221175 100644 --- a/src/kiwano/platform/win32/libraries.cpp +++ b/src/kiwano/platform/win32/libraries.cpp @@ -18,6 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include #include #include @@ -41,7 +42,7 @@ Shlwapi::Shlwapi() else { KGE_ERROR("Load shlapi.dll failed"); - throw std::runtime_error("Load shlapi.dll failed"); + throw SystemException(HRESULT_FROM_WIN32(GetLastError()), "Load shlapi.dll failed"); } } diff --git a/src/kiwano/render/DirectX/D3D10DeviceResources.cpp b/src/kiwano/render/DirectX/D3D10DeviceResources.cpp index 3d16b278..6e9f76d4 100644 --- a/src/kiwano/render/DirectX/D3D10DeviceResources.cpp +++ b/src/kiwano/render/DirectX/D3D10DeviceResources.cpp @@ -67,7 +67,7 @@ struct D3D10DeviceResources : public ID3D10DeviceResources public: HRESULT Present(bool vsync); - HRESULT ClearRenderTarget(Color& clear_color); + void ClearRenderTarget(Color& clear_color); HRESULT HandleDeviceLost(); @@ -164,14 +164,13 @@ HRESULT D3D10DeviceResources::Present(bool vsync) return dxgi_swap_chain_->Present(vsync ? 1 : 0, 0); } -HRESULT D3D10DeviceResources::ClearRenderTarget(Color& clear_color) +void D3D10DeviceResources::ClearRenderTarget(Color& clear_color) { KGE_ASSERT(device_ != nullptr && rt_view_ != nullptr && ds_view_ != nullptr); auto rt_view = rt_view_.get(); device_->OMSetRenderTargets(1, &rt_view, ds_view_.get()); device_->ClearRenderTargetView(rt_view, reinterpret_cast(&clear_color)); - return S_OK; } void D3D10DeviceResources::DiscardResources() diff --git a/src/kiwano/render/DirectX/D3D11DeviceResources.cpp b/src/kiwano/render/DirectX/D3D11DeviceResources.cpp index 89a33261..357dcb3a 100644 --- a/src/kiwano/render/DirectX/D3D11DeviceResources.cpp +++ b/src/kiwano/render/DirectX/D3D11DeviceResources.cpp @@ -56,7 +56,7 @@ struct D3D11DeviceResources : public ID3D11DeviceResources public: HRESULT Present(bool vsync) override; - HRESULT ClearRenderTarget(Color& clear_color) override; + void ClearRenderTarget(Color& clear_color) override; HRESULT HandleDeviceLost() override; @@ -156,14 +156,13 @@ HRESULT D3D11DeviceResources::Present(bool vsync) return dxgi_swap_chain_->Present(vsync ? 1 : 0, 0); } -HRESULT D3D11DeviceResources::ClearRenderTarget(Color& clear_color) +void D3D11DeviceResources::ClearRenderTarget(Color& clear_color) { KGE_ASSERT(device_context_ != nullptr && rt_view_ != nullptr && ds_view_ != nullptr); auto rt_view = rt_view_.get(); device_context_->OMSetRenderTargets(1, &rt_view, ds_view_.get()); device_context_->ClearRenderTargetView(rt_view, reinterpret_cast(&clear_color)); - return S_OK; } void D3D11DeviceResources::DiscardResources() diff --git a/src/kiwano/render/DirectX/D3DDeviceResourcesBase.h b/src/kiwano/render/DirectX/D3DDeviceResourcesBase.h index 3692cd15..5cdde8b1 100644 --- a/src/kiwano/render/DirectX/D3DDeviceResourcesBase.h +++ b/src/kiwano/render/DirectX/D3DDeviceResourcesBase.h @@ -29,7 +29,7 @@ ID3DDeviceResourcesBase : public IUnknown public: virtual HRESULT Present(bool vsync) = 0; - virtual HRESULT ClearRenderTarget(Color & clear_color) = 0; + virtual void ClearRenderTarget(Color & clear_color) = 0; virtual HRESULT HandleDeviceLost() = 0; diff --git a/src/kiwano/render/DirectX/RenderContextImpl.cpp b/src/kiwano/render/DirectX/RenderContextImpl.cpp index 9ec06307..8db2df29 100644 --- a/src/kiwano/render/DirectX/RenderContextImpl.cpp +++ b/src/kiwano/render/DirectX/RenderContextImpl.cpp @@ -86,7 +86,7 @@ void RenderContextImpl::BeginDraw() void RenderContextImpl::EndDraw() { - win32::ThrowIfFailed(render_target_->EndDraw()); + win32::ThrowIfFailed(render_target_->EndDraw(), "ID2D1RenderTarget EndDraw failed"); RenderContext::EndDraw(); @@ -314,7 +314,7 @@ void RenderContextImpl::CreateTexture(Texture& texture, math::Vec2T si texture.SetBitmap(saved_bitmap); } - win32::ThrowIfFailed(hr); + win32::ThrowIfFailed(hr, "Create texture failed"); } void RenderContextImpl::PushClipRect(Rect const& clip_rect) @@ -336,7 +336,8 @@ void RenderContextImpl::PushLayer(LayerArea& layer) if (!layer.IsValid()) { ComPtr output; - HRESULT hr = render_target_->CreateLayer(&output); + + HRESULT hr = render_target_->CreateLayer(&output); if (SUCCEEDED(hr)) { @@ -344,7 +345,7 @@ void RenderContextImpl::PushLayer(LayerArea& layer) } else { - win32::ThrowIfFailed(hr); + win32::ThrowIfFailed(hr, "Create ID2D1Layer failed"); } } diff --git a/src/kiwano/render/DirectX/RendererImpl.cpp b/src/kiwano/render/DirectX/RendererImpl.cpp index d42edfed..6aba373a 100644 --- a/src/kiwano/render/DirectX/RendererImpl.cpp +++ b/src/kiwano/render/DirectX/RendererImpl.cpp @@ -18,6 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include #include #include #include @@ -49,7 +50,7 @@ void RendererImpl::SetupComponent() { KGE_SYS_LOG("Creating device resources"); - win32::ThrowIfFailed(::CoInitialize(nullptr)); + win32::ThrowIfFailed(::CoInitialize(nullptr), "CoInitialize failed"); HWND target_window = WindowImpl::GetInstance().GetHandle(); output_size_ = Window::GetInstance().GetSize(); @@ -111,7 +112,7 @@ void RendererImpl::SetupComponent() } } - win32::ThrowIfFailed(hr); + win32::ThrowIfFailed(hr, "Create render resources failed"); } void RendererImpl::DestroyComponent() @@ -149,8 +150,7 @@ void RendererImpl::Clear() { KGE_ASSERT(d3d_res_); - HRESULT hr = d3d_res_->ClearRenderTarget(clear_color_); - win32::ThrowIfFailed(hr); + d3d_res_->ClearRenderTarget(clear_color_); } void RendererImpl::Present() @@ -165,7 +165,7 @@ void RendererImpl::Present() hr = HandleDeviceLost(); } - win32::ThrowIfFailed(hr); + win32::ThrowIfFailed(hr, "Unexpected DXGI exception"); } void RendererImpl::HandleEvent(Event* evt) @@ -244,7 +244,7 @@ void RendererImpl::CreateTexture(Texture& texture, String const& file_path) if (FAILED(hr)) { - KGE_WARN("Load texture failed with HRESULT of %08X!", hr); + win32::ThrowIfFailed(hr, "Load texture failed"); } } @@ -562,7 +562,7 @@ void RendererImpl::CreateFontCollection(Font& font, String const& file_path) } } - win32::ThrowIfFailed(hr); + win32::ThrowIfFailed(hr, "Create font collection failed"); } void RendererImpl::CreateFontCollection(Font& font, Resource const& res) @@ -593,7 +593,7 @@ void RendererImpl::CreateFontCollection(Font& font, Resource const& res) } } - win32::ThrowIfFailed(hr); + win32::ThrowIfFailed(hr, "Create font collection failed"); } void RendererImpl::CreateTextFormat(TextLayout& layout) @@ -620,7 +620,7 @@ void RendererImpl::CreateTextFormat(TextLayout& layout) layout.SetTextFormat(output); } - win32::ThrowIfFailed(hr); + win32::ThrowIfFailed(hr, "Create text format failed"); } void RendererImpl::CreateTextLayout(TextLayout& layout) @@ -644,7 +644,7 @@ void RendererImpl::CreateTextLayout(TextLayout& layout) layout.SetTextLayout(output); } - win32::ThrowIfFailed(hr); + win32::ThrowIfFailed(hr, "Create text layout failed"); } void RendererImpl::CreateLineShape(Shape& shape, Point const& begin_pos, Point const& end_pos) @@ -680,7 +680,7 @@ void RendererImpl::CreateLineShape(Shape& shape, Point const& begin_pos, Point c shape.SetGeometry(path_geo); } - win32::ThrowIfFailed(hr); + win32::ThrowIfFailed(hr, "Create ID2D1PathGeometry failed"); } void RendererImpl::CreateRectShape(Shape& shape, Rect const& rect) @@ -702,7 +702,7 @@ void RendererImpl::CreateRectShape(Shape& shape, Rect const& rect) shape.SetGeometry(output); } - win32::ThrowIfFailed(hr); + win32::ThrowIfFailed(hr, "Create ID2D1RectangleGeometry failed"); } void RendererImpl::CreateRoundedRectShape(Shape& shape, Rect const& rect, Vec2 const& radius) @@ -725,7 +725,7 @@ void RendererImpl::CreateRoundedRectShape(Shape& shape, Rect const& rect, Vec2 c shape.SetGeometry(output); } - win32::ThrowIfFailed(hr); + win32::ThrowIfFailed(hr, "Create ID2D1RoundedRectangleGeometry failed"); } void RendererImpl::CreateEllipseShape(Shape& shape, Point const& center, Vec2 const& radius) @@ -748,7 +748,7 @@ void RendererImpl::CreateEllipseShape(Shape& shape, Point const& center, Vec2 co shape.SetGeometry(output); } - win32::ThrowIfFailed(hr); + win32::ThrowIfFailed(hr, "Create ID2D1EllipseGeometry failed"); } void RendererImpl::CreateShapeSink(ShapeSink& sink) @@ -770,7 +770,133 @@ void RendererImpl::CreateShapeSink(ShapeSink& sink) sink.SetPathGeometry(output); } - win32::ThrowIfFailed(hr); + win32::ThrowIfFailed(hr, "Create ID2D1PathGeometry failed"); +} + +void RendererImpl::CreateBrush(Brush& brush, Color const& color) +{ + HRESULT hr = S_OK; + if (!d2d_res_) + { + hr = E_UNEXPECTED; + } + + if (SUCCEEDED(hr)) + { + ComPtr solid_brush; + + if (brush.GetType() == Brush::Type::SolidColor && brush.GetBrush()) + { + hr = brush.GetBrush()->QueryInterface(&solid_brush); + if (SUCCEEDED(hr)) + { + solid_brush->SetColor(DX::ConvertToColorF(color)); + } + } + else + { + hr = d2d_res_->GetDeviceContext()->CreateSolidColorBrush(DX::ConvertToColorF(color), &solid_brush); + + if (SUCCEEDED(hr)) + { + brush.SetBrush(solid_brush, Brush::Type::SolidColor); + } + } + } + + win32::ThrowIfFailed(hr, "Create ID2D1SolidBrush failed"); +} + +void RendererImpl::CreateBrush(Brush& brush, LinearGradientStyle const& style) +{ + HRESULT hr = S_OK; + if (!d2d_res_) + { + hr = E_UNEXPECTED; + } + + if (SUCCEEDED(hr)) + { + ComPtr collection; + hr = d2d_res_->GetDeviceContext()->CreateGradientStopCollection( + reinterpret_cast(&style.stops[0]), UINT32(style.stops.size()), D2D1_GAMMA_2_2, + D2D1_EXTEND_MODE(style.extend_mode), &collection); + + if (SUCCEEDED(hr)) + { + ComPtr output; + hr = d2d_res_->GetDeviceContext()->CreateLinearGradientBrush( + D2D1::LinearGradientBrushProperties(DX::ConvertToPoint2F(style.begin), DX::ConvertToPoint2F(style.end)), + collection.get(), &output); + + if (SUCCEEDED(hr)) + { + brush.SetBrush(output, Brush::Type::LinearGradient); + } + } + } + + win32::ThrowIfFailed(hr, "Create ID2D1LinearGradientBrush failed"); +} + +void RendererImpl::CreateBrush(Brush& brush, RadialGradientStyle const& style) +{ + HRESULT hr = S_OK; + if (!d2d_res_) + { + hr = E_UNEXPECTED; + } + + if (SUCCEEDED(hr)) + { + ComPtr collection; + hr = d2d_res_->GetDeviceContext()->CreateGradientStopCollection( + reinterpret_cast(&style.stops[0]), UINT32(style.stops.size()), D2D1_GAMMA_2_2, + D2D1_EXTEND_MODE(style.extend_mode), &collection); + + if (SUCCEEDED(hr)) + { + ComPtr output; + hr = d2d_res_->GetDeviceContext()->CreateRadialGradientBrush( + D2D1::RadialGradientBrushProperties(DX::ConvertToPoint2F(style.center), + DX::ConvertToPoint2F(style.offset), style.radius.x, style.radius.y), + collection.get(), &output); + + if (SUCCEEDED(hr)) + { + brush.SetBrush(output, Brush::Type::RadialGradient); + } + } + } + + win32::ThrowIfFailed(hr, "Create ID2D1RadialGradientBrush failed"); +} + +void RendererImpl::CreateStrokeStyle(StrokeStyle& stroke_style, CapStyle cap, LineJoinStyle line_join, + const float* dash_array, size_t dash_size, float dash_offset) +{ + HRESULT hr = S_OK; + if (!d2d_res_) + { + hr = E_UNEXPECTED; + } + + if (SUCCEEDED(hr)) + { + D2D1_STROKE_STYLE_PROPERTIES style = + D2D1::StrokeStyleProperties(D2D1_CAP_STYLE(cap), D2D1_CAP_STYLE(cap), D2D1_CAP_STYLE(cap), + D2D1_LINE_JOIN(line_join), 10.0f, D2D1_DASH_STYLE_CUSTOM, dash_offset); + + ComPtr output; + hr = d2d_res_->GetFactory()->CreateStrokeStyle(style, dash_array, dash_size, &output); + + if (SUCCEEDED(hr)) + { + stroke_style.SetStrokeStyle(output); + } + } + + win32::ThrowIfFailed(hr, "Create ID2D1StrokeStyle failed"); } TextureRenderContextPtr RendererImpl::CreateTextureRenderContext(const Size* desired_size) @@ -814,132 +940,6 @@ TextureRenderContextPtr RendererImpl::CreateTextureRenderContext(const Size* des return nullptr; } -void RendererImpl::CreateBrush(Brush& brush, Color const& color) -{ - HRESULT hr = S_OK; - if (!d2d_res_) - { - hr = E_UNEXPECTED; - } - - if (SUCCEEDED(hr)) - { - ComPtr solid_brush; - - if (brush.GetType() == Brush::Type::SolidColor && brush.GetBrush()) - { - hr = brush.GetBrush()->QueryInterface(&solid_brush); - if (SUCCEEDED(hr)) - { - solid_brush->SetColor(DX::ConvertToColorF(color)); - } - } - else - { - hr = d2d_res_->GetDeviceContext()->CreateSolidColorBrush(DX::ConvertToColorF(color), &solid_brush); - - if (SUCCEEDED(hr)) - { - brush.SetBrush(solid_brush, Brush::Type::SolidColor); - } - } - } - - win32::ThrowIfFailed(hr); -} - -void RendererImpl::CreateBrush(Brush& brush, LinearGradientStyle const& style) -{ - HRESULT hr = S_OK; - if (!d2d_res_) - { - hr = E_UNEXPECTED; - } - - if (SUCCEEDED(hr)) - { - ComPtr collection; - hr = d2d_res_->GetDeviceContext()->CreateGradientStopCollection( - reinterpret_cast(&style.stops[0]), UINT32(style.stops.size()), D2D1_GAMMA_2_2, - D2D1_EXTEND_MODE(style.extend_mode), &collection); - - if (SUCCEEDED(hr)) - { - ComPtr output; - hr = d2d_res_->GetDeviceContext()->CreateLinearGradientBrush( - D2D1::LinearGradientBrushProperties(DX::ConvertToPoint2F(style.begin), DX::ConvertToPoint2F(style.end)), - collection.get(), &output); - - if (SUCCEEDED(hr)) - { - brush.SetBrush(output, Brush::Type::LinearGradient); - } - } - } - - win32::ThrowIfFailed(hr); -} - -void RendererImpl::CreateBrush(Brush& brush, RadialGradientStyle const& style) -{ - HRESULT hr = S_OK; - if (!d2d_res_) - { - hr = E_UNEXPECTED; - } - - if (SUCCEEDED(hr)) - { - ComPtr collection; - hr = d2d_res_->GetDeviceContext()->CreateGradientStopCollection( - reinterpret_cast(&style.stops[0]), UINT32(style.stops.size()), D2D1_GAMMA_2_2, - D2D1_EXTEND_MODE(style.extend_mode), &collection); - - if (SUCCEEDED(hr)) - { - ComPtr output; - hr = d2d_res_->GetDeviceContext()->CreateRadialGradientBrush( - D2D1::RadialGradientBrushProperties(DX::ConvertToPoint2F(style.center), - DX::ConvertToPoint2F(style.offset), style.radius.x, style.radius.y), - collection.get(), &output); - - if (SUCCEEDED(hr)) - { - brush.SetBrush(output, Brush::Type::RadialGradient); - } - } - } - - win32::ThrowIfFailed(hr); -} - -void RendererImpl::CreateStrokeStyle(StrokeStyle& stroke_style, CapStyle cap, LineJoinStyle line_join, - const float* dash_array, size_t dash_size, float dash_offset) -{ - HRESULT hr = S_OK; - if (!d2d_res_) - { - hr = E_UNEXPECTED; - } - - if (SUCCEEDED(hr)) - { - D2D1_STROKE_STYLE_PROPERTIES style = - D2D1::StrokeStyleProperties(D2D1_CAP_STYLE(cap), D2D1_CAP_STYLE(cap), D2D1_CAP_STYLE(cap), - D2D1_LINE_JOIN(line_join), 10.0f, D2D1_DASH_STYLE_CUSTOM, dash_offset); - - ComPtr output; - hr = d2d_res_->GetFactory()->CreateStrokeStyle(style, dash_array, dash_size, &output); - - if (SUCCEEDED(hr)) - { - stroke_style.SetStrokeStyle(output); - } - } - - win32::ThrowIfFailed(hr); -} - void RendererImpl::Resize(uint32_t width, uint32_t height) { HRESULT hr = S_OK; @@ -965,7 +965,7 @@ void RendererImpl::Resize(uint32_t width, uint32_t height) render_ctx_->Resize(output_size_); } - win32::ThrowIfFailed(hr); + win32::ThrowIfFailed(hr, "Resize render target failed"); } } // namespace kiwano diff --git a/src/kiwano/render/Renderer.h b/src/kiwano/render/Renderer.h index ba115797..69594ecc 100644 --- a/src/kiwano/render/Renderer.h +++ b/src/kiwano/render/Renderer.h @@ -63,116 +63,134 @@ public: virtual void SetVSyncEnabled(bool enabled); /// \~chinese - /// @brief 创建纹理 + /// @brief 创建纹理内部资源 /// @param[out] texture 纹理 /// @param[in] file_path 图片路径 + /// @throw kiwano::SystemException 创建失败时抛出 virtual void CreateTexture(Texture& texture, String const& file_path) = 0; /// \~chinese - /// @brief 创建纹理 + /// @brief 创建纹理内部资源 /// @param[out] texture 纹理 /// @param[in] resource 图片资源 + /// @throw kiwano::SystemException 创建失败时抛出 virtual void CreateTexture(Texture& texture, Resource const& resource) = 0; /// \~chinese - /// @brief 创建GIF图像 + /// @brief 创建GIF图像内部资源 /// @param[out] gif GIF图像 /// @param[in] file_path 图片路径 + /// @throw kiwano::SystemException 创建失败时抛出 virtual void CreateGifImage(GifImage& gif, String const& file_path) = 0; /// \~chinese - /// @brief 创建GIF图像 + /// @brief 创建GIF图像内部资源 /// @param[out] gif GIF图像 /// @param[in] resource 图片资源 + /// @throw kiwano::SystemException 创建失败时抛出 virtual void CreateGifImage(GifImage& gif, Resource const& resource) = 0; /// \~chinese - /// @brief 创建GIF图像帧 + /// @brief 创建GIF图像帧内部资源 /// @param[out] frame GIF图像帧 /// @param[in] gif GIF图像 /// @param[in] frame_index 帧下标 + /// @throw kiwano::SystemException 创建失败时抛出 virtual void CreateGifImageFrame(GifImage::Frame& frame, GifImage const& gif, size_t frame_index) = 0; /// \~chinese - /// @brief 创建字体集 + /// @brief 创建字体集内部资源 /// @param[out] font 字体 /// @param[in] file_paths 字体文件路径 + /// @throw kiwano::SystemException 创建失败时抛出 virtual void CreateFontCollection(Font& font, String const& file_path) = 0; /// \~chinese - /// @brief 创建字体集 + /// @brief 创建字体集内部资源 /// @param[out] font 字体 /// @param[in] res_arr 字体资源 + /// @throw kiwano::SystemException 创建失败时抛出 virtual void CreateFontCollection(Font& font, Resource const& res) = 0; /// \~chinese - /// @brief 创建文字格式 + /// @brief 创建文字格式内部资源 /// @param[out] layout 字体布局 + /// @throw kiwano::SystemException 创建失败时抛出 virtual void CreateTextFormat(TextLayout& layout) = 0; /// \~chinese - /// @brief 创建文字布局 + /// @brief 创建文字布局内部资源 /// @param[out] layout 字体布局 + /// @throw kiwano::SystemException 创建失败时抛出 virtual void CreateTextLayout(TextLayout& layout) = 0; /// \~chinese - /// @brief 创建线段形状 - /// @param[out] geo 形状 + /// @brief 创建线段形状内部资源 + /// @param[out] shape 形状 /// @param[in] begin_pos 线段起点 /// @param[in] end_pos 线段终点 + /// @throw kiwano::SystemException 创建失败时抛出 virtual void CreateLineShape(Shape& shape, Point const& begin_pos, Point const& end_pos) = 0; /// \~chinese - /// @brief 创建矩形形状 - /// @param[out] geo 形状 + /// @brief 创建矩形形状内部资源 + /// @param[out] shape 形状 /// @param[in] rect 矩形大小 + /// @throw kiwano::SystemException 创建失败时抛出 virtual void CreateRectShape(Shape& shape, Rect const& rect) = 0; /// \~chinese - /// @brief 创建圆角矩形形状 - /// @param[out] geo 形状 + /// @brief 创建圆角矩形形状内部资源 + /// @param[out] shape 形状 /// @param[in] rect 矩形大小 /// @param[in] radius 圆角半径 + /// @throw kiwano::SystemException 创建失败时抛出 virtual void CreateRoundedRectShape(Shape& shape, Rect const& rect, Vec2 const& radius) = 0; /// \~chinese - /// @brief 创建椭圆形状 - /// @param[out] geo 形状 + /// @brief 创建椭圆形状内部资源 + /// @param[out] shape 形状 /// @param[in] center 椭圆圆心 /// @param[in] radius 椭圆半径 + /// @throw kiwano::SystemException 创建失败时抛出 virtual void CreateEllipseShape(Shape& shape, Point const& center, Vec2 const& radius) = 0; /// \~chinese - /// @brief 创建几何图形生成器 + /// @brief 创建几何图形生成器内部资源 /// @param[out] sink 形状生成器 + /// @throw kiwano::SystemException 创建失败时抛出 virtual void CreateShapeSink(ShapeSink& sink) = 0; /// \~chinese - /// @brief 创建纯色画刷 + /// @brief 创建纯色画刷内部资源 /// @param[out] brush 画刷 /// @param[in] color 颜色 + /// @throw kiwano::SystemException 创建失败时抛出 virtual void CreateBrush(Brush& brush, Color const& color) = 0; /// \~chinese - /// @brief 创建线性渐变画刷 + /// @brief 创建线性渐变画刷内部资源 /// @param[out] brush 画刷 /// @param[in] style 线性渐变样式 + /// @throw kiwano::SystemException 创建失败时抛出 virtual void CreateBrush(Brush& brush, LinearGradientStyle const& style) = 0; /// \~chinese - /// @brief 创建径向渐变画刷 + /// @brief 创建径向渐变画刷内部资源 /// @param[out] brush 画刷 /// @param[in] style 径向渐变样式 + /// @throw kiwano::SystemException 创建失败时抛出 virtual void CreateBrush(Brush& brush, RadialGradientStyle const& style) = 0; /// \~chinese - /// @brief 创建线条样式 + /// @brief 创建线条样式内部资源 /// @param[out] stroke_style 线条样式 /// @param[in] cap 线段端点样式 /// @param[in] line_join 线段相交样式 /// @param[in] dash_array 虚线长度与间隙数组 /// @param[in] dash_size 虚线数组大小 /// @param[in] dash_offset 虚线偏移量 + /// @throw kiwano::SystemException 创建失败时抛出 virtual void CreateStrokeStyle(StrokeStyle& stroke_style, CapStyle cap, LineJoinStyle line_join, const float* dash_array, size_t dash_size, float dash_offset) = 0; @@ -180,6 +198,7 @@ public: /// @brief 创建纹理渲染上下文 /// @param[in] desired_size 期望的输出大小 /// @return 纹理渲染上下文 + /// @throw kiwano::SystemException 创建失败时抛出 virtual TextureRenderContextPtr CreateTextureRenderContext(const Size* desired_size = nullptr) = 0; public: @@ -197,6 +216,7 @@ public: /// \~chinese /// @brief 将绘制内容呈现至窗口 + /// @throw kiwano::SystemException 呈现失败时抛出 virtual void Present() = 0; /// \~chinese diff --git a/src/kiwano/render/ShapeSink.cpp b/src/kiwano/render/ShapeSink.cpp index 95e14b58..7ddabaea 100644 --- a/src/kiwano/render/ShapeSink.cpp +++ b/src/kiwano/render/ShapeSink.cpp @@ -38,7 +38,7 @@ void ShapeSink::Open() path_geo_.reset(); Renderer::GetInstance().CreateShapeSink(*this); - win32::ThrowIfFailed(path_geo_->Open(&sink_)); + win32::ThrowIfFailed(path_geo_->Open(&sink_), "Open ID2D1GeometrySink failed"); } } @@ -46,7 +46,7 @@ void ShapeSink::Close() { if (IsOpened()) { - win32::ThrowIfFailed(sink_->Close()); + win32::ThrowIfFailed(sink_->Close(), "Close ID2D1GeometrySink failed"); sink_.reset(); } @@ -75,8 +75,10 @@ ShapeSink& ShapeSink::AddShape(ShapePtr input, const Matrix3x2* input_matrix) if (input && input->IsValid()) { ComPtr geo = input->GetGeometry(); - win32::ThrowIfFailed( - geo->Outline(DX::ConvertToMatrix3x2F(input_matrix), D2D1_DEFAULT_FLATTENING_TOLERANCE, sink_.get())); + + HRESULT hr = + geo->Outline(DX::ConvertToMatrix3x2F(input_matrix), D2D1_DEFAULT_FLATTENING_TOLERANCE, sink_.get()); + win32::ThrowIfFailed(hr, "Get outline of ID2D1Geometry failed"); } return (*this); } @@ -148,8 +150,10 @@ ShapeSink& ShapeSink::Combine(ShapePtr shape_a, ShapePtr shape_b, CombineMode mo { ComPtr geo_a_raw = shape_a->geo_; ComPtr geo_b_raw = shape_b->geo_; - win32::ThrowIfFailed(geo_a_raw->CombineWithGeometry(geo_b_raw.get(), D2D1_COMBINE_MODE(mode), - DX::ConvertToMatrix3x2F(matrix), sink_.get())); + + HRESULT hr = geo_a_raw->CombineWithGeometry(geo_b_raw.get(), D2D1_COMBINE_MODE(mode), + DX::ConvertToMatrix3x2F(matrix), sink_.get()); + win32::ThrowIfFailed(hr, "Combine ID2D1Geometry failed"); } return (*this); } diff --git a/src/kiwano/render/TextLayout.cpp b/src/kiwano/render/TextLayout.cpp index e7340b8c..55462960 100644 --- a/src/kiwano/render/TextLayout.cpp +++ b/src/kiwano/render/TextLayout.cpp @@ -183,7 +183,7 @@ void TextLayout::SetWrapWidth(float wrap_width) } } } - win32::ThrowIfFailed(hr); + win32::ThrowIfFailed(hr, "Apply word wrapping to text layout failed"); } } @@ -202,7 +202,7 @@ void TextLayout::SetLineSpacing(float line_spacing) { hr = text_layout_->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_UNIFORM, line_spacing, line_spacing * 0.8f); } - win32::ThrowIfFailed(hr); + win32::ThrowIfFailed(hr, "Apply line spacing to text layout failed"); } } @@ -213,7 +213,7 @@ void TextLayout::SetAlignment(TextAlign align) if (text_layout_) { HRESULT hr = text_layout_->SetTextAlignment(DWRITE_TEXT_ALIGNMENT(align)); - win32::ThrowIfFailed(hr); + win32::ThrowIfFailed(hr, "Apply alignment style to text layout failed"); } } @@ -228,7 +228,7 @@ void TextLayout::SetUnderline(bool enable, uint32_t start, uint32_t length) { hr = text_layout_->SetUnderline(enable, { start, length }); } - win32::ThrowIfFailed(hr); + win32::ThrowIfFailed(hr, "Apply underline style to text layout failed"); } void TextLayout::SetStrikethrough(bool enable, uint32_t start, uint32_t length) @@ -242,7 +242,7 @@ void TextLayout::SetStrikethrough(bool enable, uint32_t start, uint32_t length) { hr = text_layout_->SetStrikethrough(enable, { start, length }); } - win32::ThrowIfFailed(hr); + win32::ThrowIfFailed(hr, "Apply strikethrough style to text layout failed"); } } // namespace kiwano diff --git a/src/kiwano/render/Texture.cpp b/src/kiwano/render/Texture.cpp index 219f7dc6..cdbfdd73 100644 --- a/src/kiwano/render/Texture.cpp +++ b/src/kiwano/render/Texture.cpp @@ -139,7 +139,7 @@ void Texture::CopyFrom(TexturePtr copy_from) { HRESULT hr = bitmap_->CopyFromBitmap(nullptr, copy_from->GetBitmap().get(), nullptr); - win32::ThrowIfFailed(hr); + win32::ThrowIfFailed(hr, "Copy texture data failed"); } } @@ -152,7 +152,7 @@ void Texture::CopyFrom(TexturePtr copy_from, Rect const& src_rect, Point const& &D2D1::RectU(uint32_t(src_rect.GetLeft()), uint32_t(src_rect.GetTop()), uint32_t(src_rect.GetRight()), uint32_t(src_rect.GetBottom()))); - win32::ThrowIfFailed(hr); + win32::ThrowIfFailed(hr, "Copy texture data failed"); } } diff --git a/src/kiwano/utils/ResourceCache.cpp b/src/kiwano/utils/ResourceCache.cpp index 7259f1a6..58f39b6e 100644 --- a/src/kiwano/utils/ResourceCache.cpp +++ b/src/kiwano/utils/ResourceCache.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -55,7 +56,7 @@ bool ResourceCache::LoadFromJsonFile(String const& file_path) { if (!FileSystem::GetInstance().IsFileExists(file_path)) { - KGE_ERROR("ResourceCache::LoadFromJsonFile failed: File not found."); + KGE_ERROR("%s failed: File not found.", __FUNCTION__); return false; } @@ -73,12 +74,12 @@ bool ResourceCache::LoadFromJsonFile(String const& file_path) } catch (std::wifstream::failure& e) { - KGE_ERROR("ResourceCache::LoadFromJsonFile failed: Cannot open file. (%s)", e.what()); + KGE_ERROR("%s failed: Cannot open file. (%s)", __FUNCTION__, e.what()); return false; } catch (Json::exception& e) { - KGE_ERROR("ResourceCache::LoadFromJsonFile failed: Cannot parse to JSON. (%s)", e.what()); + KGE_ERROR("%s failed: Cannot parse to JSON. (%s)", __FUNCTION__, e.what()); return false; } return LoadFromJson(json_data); @@ -101,12 +102,12 @@ bool ResourceCache::LoadFromJson(Json const& json_data) } else { - throw std::runtime_error("unknown JSON data version"); + KGE_ERROR("%s failed: unknown resource data version", __FUNCTION__); } } catch (Json::exception& e) { - KGE_ERROR("ResourceCache::LoadFromJson failed: JSON data is invalid. (%s)", e.what()); + KGE_ERROR("%s failed: JSON data is invalid. (%s)", __FUNCTION__, e.what()); return false; } return false; @@ -116,7 +117,7 @@ bool ResourceCache::LoadFromXmlFile(String const& file_path) { if (!FileSystem::GetInstance().IsFileExists(file_path)) { - KGE_ERROR("ResourceCache::LoadFromXmlFile failed: File not found."); + KGE_ERROR("%s failed: File not found.", __FUNCTION__); return false; } @@ -131,7 +132,7 @@ bool ResourceCache::LoadFromXmlFile(String const& file_path) } else { - KGE_ERROR("XML [%s] parsed with errors: %s", full_path.c_str(), result.description()); + KGE_ERROR("%s failed: XML [%s] parsed with errors: %s", __FUNCTION__, full_path.c_str(), result.description()); return false; } } @@ -155,12 +156,9 @@ bool ResourceCache::LoadFromXml(const pugi::xml_document& doc) } else { - KGE_ERROR("Unknown version"); - return false; + KGE_ERROR("%s failed: unknown resource data version", __FUNCTION__); } } - - KGE_ERROR("Unknown version"); return false; }