diff options
Diffstat (limited to 'include/cru/platform')
30 files changed, 1336 insertions, 0 deletions
diff --git a/include/cru/platform/graphics/direct2d/Base.h b/include/cru/platform/graphics/direct2d/Base.h new file mode 100644 index 00000000..a2f6772c --- /dev/null +++ b/include/cru/platform/graphics/direct2d/Base.h @@ -0,0 +1,18 @@ +#pragma once +#include "cru/platform/win/WinPreConfig.h" + +#include <d2d1_2.h> +#include <d3d11.h> +#include <dwrite.h> +#include <dxgi1_2.h> +#include <wrl/client.h> + +#ifdef CRU_PLATFORM_WINDOWS +#ifdef CRU_WIN_GRAPHICS_DIRECT_EXPORT_API +#define CRU_WIN_GRAPHICS_DIRECT_API __declspec(dllexport) +#else +#define CRU_WIN_GRAPHICS_DIRECT_API __declspec(dllimport) +#endif +#else +#define CRU_WIN_GRAPHICS_DIRECT_API +#endif diff --git a/include/cru/platform/graphics/direct2d/Brush.h b/include/cru/platform/graphics/direct2d/Brush.h new file mode 100644 index 00000000..98f9018c --- /dev/null +++ b/include/cru/platform/graphics/direct2d/Brush.h @@ -0,0 +1,40 @@ +#pragma once +#include "ComResource.h" +#include "Resource.h" + +#include "cru/platform/graphics/Brush.h" + +namespace cru::platform::graphics::direct2d { +struct CRU_WIN_GRAPHICS_DIRECT_API ID2DBrush : virtual IBrush { + virtual ID2D1Brush* GetD2DBrushInterface() const = 0; +}; + +class CRU_WIN_GRAPHICS_DIRECT_API D2DSolidColorBrush + : public DirectGraphicsResource, + public virtual ISolidColorBrush, + public virtual ID2DBrush, + public virtual IComResource<ID2D1SolidColorBrush> { + public: + explicit D2DSolidColorBrush(DirectGraphicsFactory* factory); + + CRU_DELETE_COPY(D2DSolidColorBrush) + CRU_DELETE_MOVE(D2DSolidColorBrush) + + ~D2DSolidColorBrush() override = default; + + public: + Color GetColor() override { return color_; } + void SetColor(const Color& color) override; + + ID2D1Brush* GetD2DBrushInterface() const override { return brush_.Get(); } + + ID2D1SolidColorBrush* GetComInterface() const override { + return brush_.Get(); + } + + private: + Color color_ = colors::black; + + Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> brush_; +}; +} // namespace cru::platform::graphics::direct2d diff --git a/include/cru/platform/graphics/direct2d/ComResource.h b/include/cru/platform/graphics/direct2d/ComResource.h new file mode 100644 index 00000000..2beb4e20 --- /dev/null +++ b/include/cru/platform/graphics/direct2d/ComResource.h @@ -0,0 +1,11 @@ +#pragma once +#include "Base.h" + +#include "cru/common/Base.h" + +namespace cru::platform::graphics::direct2d { +template <typename TInterface> +struct CRU_WIN_GRAPHICS_DIRECT_API IComResource : virtual Interface { + virtual TInterface* GetComInterface() const = 0; +}; +} // namespace cru::platform::graphics::direct2d diff --git a/include/cru/platform/graphics/direct2d/ConvertUtil.h b/include/cru/platform/graphics/direct2d/ConvertUtil.h new file mode 100644 index 00000000..66fa37f8 --- /dev/null +++ b/include/cru/platform/graphics/direct2d/ConvertUtil.h @@ -0,0 +1,107 @@ +#pragma once +#include "Base.h" + +#include "cru/platform/graphics/Base.h" + +namespace cru::platform::graphics::direct2d { +inline D2D1_MATRIX_3X2_F Convert(const platform::Matrix& matrix) { + D2D1_MATRIX_3X2_F m; + m._11 = matrix.m11; + m._12 = matrix.m12; + m._21 = matrix.m21; + m._22 = matrix.m22; + m._31 = matrix.m31; + m._32 = matrix.m32; + return m; +} + +inline D2D1_COLOR_F Convert(const Color& color) { + return D2D1::ColorF(color.red / 255.0f, color.green / 255.0f, + color.blue / 255.0f, color.alpha / 255.0f); +} + +inline D2D1_POINT_2F Convert(const Point& point) { + return D2D1::Point2F(point.x, point.y); +} + +inline D2D1_RECT_F Convert(const Rect& rect) { + return D2D1::RectF(rect.left, rect.top, rect.left + rect.width, + rect.top + rect.height); +} + +inline D2D1_ROUNDED_RECT Convert(const RoundedRect& rounded_rect) { + return D2D1::RoundedRect(Convert(rounded_rect.rect), rounded_rect.radius_x, + rounded_rect.radius_y); +} + +inline D2D1_ELLIPSE Convert(const Ellipse& ellipse) { + return D2D1::Ellipse(Convert(ellipse.center), ellipse.radius_x, + ellipse.radius_y); +} + +inline platform::Matrix Convert(const D2D1_MATRIX_3X2_F& matrix) { + return platform::Matrix{matrix._11, matrix._12, matrix._21, + matrix._22, matrix._31, matrix._32}; +} + +inline Color Convert(const D2D1_COLOR_F& color) { + auto floor = [](float n) { return static_cast<std::uint8_t>(n + 0.5f); }; + return Color{floor(color.r * 255.0f), floor(color.g * 255.0f), + floor(color.b * 255.0f), floor(color.a * 255.0f)}; +} + +inline Point Convert(const D2D1_POINT_2F& point) { + return Point(point.x, point.y); +} + +inline Rect Convert(const D2D1_RECT_F& rect) { + return Rect(rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top); +} + +inline RoundedRect Convert(const D2D1_ROUNDED_RECT& rounded_rect) { + return RoundedRect(Convert(rounded_rect.rect), rounded_rect.radiusX, + rounded_rect.radiusY); +} + +inline Ellipse Convert(const D2D1_ELLIPSE& ellipse) { + return Ellipse(Convert(ellipse.point), ellipse.radiusX, ellipse.radiusY); +} + +inline bool operator==(const D2D1_POINT_2F& left, const D2D1_POINT_2F& right) { + return left.x == right.x && left.y == right.y; +} + +inline bool operator!=(const D2D1_POINT_2F& left, const D2D1_POINT_2F& right) { + return !(left == right); +} + +inline bool operator==(const D2D1_RECT_F& left, const D2D1_RECT_F& right) { + return left.left == right.left && left.top == right.top && + left.right == right.right && left.bottom == right.bottom; +} + +inline bool operator!=(const D2D1_RECT_F& left, const D2D1_RECT_F& right) { + return !(left == right); +} + +inline bool operator==(const D2D1_ROUNDED_RECT& left, + const D2D1_ROUNDED_RECT& right) { + return left.rect == right.rect && left.radiusX == right.radiusX && + left.radiusY == right.radiusY; +} + +inline bool operator!=(const D2D1_ROUNDED_RECT& left, + const D2D1_ROUNDED_RECT& right) { + return !(left == right); +} + +inline bool operator==(const D2D1_ELLIPSE& left, const D2D1_ELLIPSE& right) { + return left.point == right.point && left.radiusX == right.radiusX && + left.radiusY == right.radiusY; +} + +inline bool operator!=(const D2D1_ELLIPSE& left, const D2D1_ELLIPSE& right) { + return !(left == right); +} +} // namespace cru::platform::graphics::direct2d diff --git a/include/cru/platform/graphics/direct2d/Exception.h b/include/cru/platform/graphics/direct2d/Exception.h new file mode 100644 index 00000000..9be6f10a --- /dev/null +++ b/include/cru/platform/graphics/direct2d/Exception.h @@ -0,0 +1,7 @@ +#pragma once +#include "cru/platform/win/Exception.h" + +namespace cru::platform::graphics::direct2d { +using platform::win::HResultError; +using platform::win::ThrowIfFailed; +} // namespace cru::platform::graphics::direct2d diff --git a/include/cru/platform/graphics/direct2d/Factory.h b/include/cru/platform/graphics/direct2d/Factory.h new file mode 100644 index 00000000..d6c43d9f --- /dev/null +++ b/include/cru/platform/graphics/direct2d/Factory.h @@ -0,0 +1,68 @@ +#pragma once +#include "Resource.h" + +#include "ImageFactory.h" + +#include "cru/common/platform/win/ComAutoInit.h" +#include "cru/platform/graphics/Base.h" +#include "cru/platform/graphics/Factory.h" + +namespace cru::platform::graphics::direct2d { +class CRU_WIN_GRAPHICS_DIRECT_API DirectGraphicsFactory + : public DirectResource, + public virtual IGraphicsFactory { + public: + DirectGraphicsFactory(); + + CRU_DELETE_COPY(DirectGraphicsFactory) + CRU_DELETE_MOVE(DirectGraphicsFactory) + + ~DirectGraphicsFactory() override; + + public: + ID3D11Device* GetD3D11Device() const { return d3d11_device_.Get(); } + ID2D1Factory2* GetD2D1Factory() const { return d2d1_factory_.Get(); } + ID2D1Device1* GetD2D1Device() const { return d2d1_device_.Get(); } + IDXGIFactory2* GetDxgiFactory() const { return dxgi_factory_.Get(); } + IDWriteFactory* GetDWriteFactory() const { return dwrite_factory_.Get(); } + IDWriteFontCollection* GetSystemFontCollection() const { + return dwrite_system_font_collection_.Get(); + } + + public: + Microsoft::WRL::ComPtr<ID2D1DeviceContext1> CreateD2D1DeviceContext(); + + // This context should only be used to create graphic resources like brush. + // Because graphic resources can be shared if they are created in the same + // device. + ID2D1DeviceContext* GetDefaultD2D1DeviceContext() { + return d2d1_device_context_.Get(); + } + + public: + std::unique_ptr<ISolidColorBrush> CreateSolidColorBrush() override; + + std::unique_ptr<IGeometryBuilder> CreateGeometryBuilder() override; + + std::unique_ptr<IFont> CreateFont(String font_family, + float font_size) override; + + std::unique_ptr<ITextLayout> CreateTextLayout(std::shared_ptr<IFont> font, + String text) override; + + IImageFactory* GetImageFactory() override; + + private: + platform::win::ComAutoInit com_auto_init_; + + Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_; + Microsoft::WRL::ComPtr<ID2D1Factory2> d2d1_factory_; + Microsoft::WRL::ComPtr<ID2D1Device1> d2d1_device_; + Microsoft::WRL::ComPtr<ID2D1DeviceContext1> d2d1_device_context_; + Microsoft::WRL::ComPtr<IDXGIFactory2> dxgi_factory_; + Microsoft::WRL::ComPtr<IDWriteFactory> dwrite_factory_; + Microsoft::WRL::ComPtr<IDWriteFontCollection> dwrite_system_font_collection_; + + std::unique_ptr<WinImageFactory> image_factory_; +}; +} // namespace cru::platform::graphics::direct2d diff --git a/include/cru/platform/graphics/direct2d/Font.h b/include/cru/platform/graphics/direct2d/Font.h new file mode 100644 index 00000000..841a57b5 --- /dev/null +++ b/include/cru/platform/graphics/direct2d/Font.h @@ -0,0 +1,35 @@ +#pragma once +#include "ComResource.h" +#include "Resource.h" + +#include "cru/platform/graphics/Font.h" + +#include <string_view> + +namespace cru::platform::graphics::direct2d { +class CRU_WIN_GRAPHICS_DIRECT_API DWriteFont + : public DirectGraphicsResource, + public virtual IFont, + public virtual IComResource<IDWriteTextFormat> { + public: + DWriteFont(DirectGraphicsFactory* factory, String font_family, + float font_size); + + CRU_DELETE_COPY(DWriteFont) + CRU_DELETE_MOVE(DWriteFont) + + ~DWriteFont() override = default; + + public: + IDWriteTextFormat* GetComInterface() const override { + return text_format_.Get(); + } + + String GetFontName() override; + float GetFontSize() override; + + private: + String font_family_; + Microsoft::WRL::ComPtr<IDWriteTextFormat> text_format_; +}; +} // namespace cru::platform::graphics::direct2d diff --git a/include/cru/platform/graphics/direct2d/Geometry.h b/include/cru/platform/graphics/direct2d/Geometry.h new file mode 100644 index 00000000..64dbae84 --- /dev/null +++ b/include/cru/platform/graphics/direct2d/Geometry.h @@ -0,0 +1,71 @@ +#pragma once +#include "ComResource.h" +#include "Resource.h" + +#include "cru/platform/graphics/Geometry.h" + +namespace cru::platform::graphics::direct2d { +class CRU_WIN_GRAPHICS_DIRECT_API D2DGeometryBuilder + : public DirectGraphicsResource, + public virtual IGeometryBuilder { + public: + explicit D2DGeometryBuilder(DirectGraphicsFactory* factory); + + CRU_DELETE_COPY(D2DGeometryBuilder) + CRU_DELETE_MOVE(D2DGeometryBuilder) + + ~D2DGeometryBuilder() override = default; + + public: + Point GetCurrentPosition() override; + + void MoveTo(const Point& point) override; + void LineTo(const Point& point) override; + void CubicBezierTo(const Point& start_control_point, + const Point& end_control_point, + const Point& end_point) override; + void QuadraticBezierTo(const Point& control_point, + const Point& end_point) override; + void ArcTo(const Point& radius, float angle, bool is_large_arc, + bool is_clockwise, const Point& end_point) override; + void CloseFigure(bool close) override; + + std::unique_ptr<IGeometry> Build() override; + + private: + bool IsValid() { return geometry_ != nullptr; } + void CheckValidation(); + + private: + Microsoft::WRL::ComPtr<ID2D1PathGeometry> geometry_; + Microsoft::WRL::ComPtr<ID2D1GeometrySink> geometry_sink_; + Point start_point_; + Point current_position_; +}; + +class CRU_WIN_GRAPHICS_DIRECT_API D2DGeometry + : public DirectGraphicsResource, + public virtual IGeometry, + public IComResource<ID2D1Geometry> { + public: + D2DGeometry(DirectGraphicsFactory* factory, + Microsoft::WRL::ComPtr<ID2D1Geometry> geometry); + + CRU_DELETE_COPY(D2DGeometry) + CRU_DELETE_MOVE(D2DGeometry) + + ~D2DGeometry() override = default; + + public: + ID2D1Geometry* GetComInterface() const override { return geometry_.Get(); } + + public: + bool FillContains(const Point& point) override; + Rect GetBounds() override; + std::unique_ptr<IGeometry> Transform(const Matrix& matrix) override; + std::unique_ptr<IGeometry> CreateStrokeGeometry(float width) override; + + private: + Microsoft::WRL::ComPtr<ID2D1Geometry> geometry_; +}; +} // namespace cru::platform::graphics::direct2d diff --git a/include/cru/platform/graphics/direct2d/Image.h b/include/cru/platform/graphics/direct2d/Image.h new file mode 100644 index 00000000..9f3f247f --- /dev/null +++ b/include/cru/platform/graphics/direct2d/Image.h @@ -0,0 +1,33 @@ +#pragma once +#include "Resource.h" +#include "cru/platform/graphics/Image.h" + +namespace cru::platform::graphics::direct2d { +class CRU_WIN_GRAPHICS_DIRECT_API Direct2DImage : public DirectGraphicsResource, + public virtual IImage { + public: + Direct2DImage(DirectGraphicsFactory* graphics_factory, + Microsoft::WRL::ComPtr<ID2D1Bitmap1> d2d_bitmap); + + CRU_DELETE_COPY(Direct2DImage) + CRU_DELETE_MOVE(Direct2DImage) + + ~Direct2DImage() override; + + public: + float GetWidth() override; + float GetHeight() override; + + std::unique_ptr<IImage> CreateWithRect(const Rect& rect) override; + + std::unique_ptr<IPainter> CreatePainter() override; + + const Microsoft::WRL::ComPtr<ID2D1Bitmap1>& GetD2DBitmap() const { + return d2d_bitmap_; + } + + private: + Microsoft::WRL::ComPtr<ID2D1Bitmap1> d2d_bitmap_; +}; + +} // namespace cru::platform::graphics::direct2d diff --git a/include/cru/platform/graphics/direct2d/ImageFactory.h b/include/cru/platform/graphics/direct2d/ImageFactory.h new file mode 100644 index 00000000..87f6c0ee --- /dev/null +++ b/include/cru/platform/graphics/direct2d/ImageFactory.h @@ -0,0 +1,30 @@ +#pragma once + +#include "Resource.h" +#include "cru/platform/graphics/Image.h" +#include "cru/platform/graphics/ImageFactory.h" + +namespace cru::platform::graphics::direct2d { +class CRU_WIN_GRAPHICS_DIRECT_API WinImageFactory + : public DirectGraphicsResource, + public virtual IImageFactory { + public: + explicit WinImageFactory(DirectGraphicsFactory* graphics_factory); + + CRU_DELETE_COPY(WinImageFactory) + CRU_DELETE_MOVE(WinImageFactory) + + ~WinImageFactory() override; + + public: + std::unique_ptr<IImage> DecodeFromStream(io::Stream* stream) override; + + void EncodeToStream(IImage* image, io::Stream* stream, ImageFormat format, + float quality) override; + + std::unique_ptr<IImage> CreateBitmap(int width, int height) override; + + private: + Microsoft::WRL::ComPtr<IWICImagingFactory> wic_imaging_factory_; +}; +} // namespace cru::platform::graphics::direct2d diff --git a/include/cru/platform/graphics/direct2d/Painter.h b/include/cru/platform/graphics/direct2d/Painter.h new file mode 100644 index 00000000..f85d840a --- /dev/null +++ b/include/cru/platform/graphics/direct2d/Painter.h @@ -0,0 +1,80 @@ +#pragma once +#include "ComResource.h" +#include "Resource.h" + +#include "cru/common/Base.h" +#include "cru/platform/graphics/Painter.h" + +#include <vector> + +namespace cru::platform::graphics::direct2d { +class CRU_WIN_GRAPHICS_DIRECT_API D2DDeviceContextPainter + : public DirectResource, + public virtual IPainter, + public virtual IComResource<ID2D1DeviceContext1> { + CRU_DEFINE_CLASS_LOG_TAG(u"D2DDeviceContextPainter") + public: + explicit D2DDeviceContextPainter(ID2D1DeviceContext1* device_context, + bool release = false); + + CRU_DELETE_COPY(D2DDeviceContextPainter) + CRU_DELETE_MOVE(D2DDeviceContextPainter) + + ~D2DDeviceContextPainter() override; + + public: + ID2D1DeviceContext1* GetComInterface() const override { + return device_context_; + } + + public: + Matrix GetTransform() override; + void SetTransform(const platform::Matrix& matrix) override; + void ConcatTransform(const Matrix& matrix) override; + + void Clear(const Color& color) override; + + void DrawLine(const Point& start, const Point& end, IBrush* brush, + float width) override; + void StrokeRectangle(const Rect& rectangle, IBrush* brush, + float width) override; + void FillRectangle(const Rect& rectangle, IBrush* brush) override; + void StrokeEllipse(const Rect& outline_rect, IBrush* brush, + float width) override; + void FillEllipse(const Rect& outline_rect, IBrush* brush) override; + + void StrokeGeometry(IGeometry* geometry, IBrush* brush, float width) override; + void FillGeometry(IGeometry* geometry, IBrush* brush) override; + + void DrawText(const Point& offset, ITextLayout* text_layout, + IBrush* brush) override; + + void DrawImage(const Point& offset, IImage* image) override; + + void PushLayer(const Rect& bounds) override; + void PopLayer() override; + + void PushState() override; + void PopState() override; + + void EndDraw() override final; + + protected: + virtual void DoEndDraw() {} + + private: + bool IsValid() { return is_drawing_; } + void CheckValidation(); + + private: + ID2D1DeviceContext1* device_context_; + + std::vector<Microsoft::WRL::ComPtr<ID2D1Layer>> layers_; + std::vector<Microsoft::WRL::ComPtr<ID2D1DrawingStateBlock>> + drawing_state_stack_; + + bool is_drawing_ = true; + + bool release_; +}; +} // namespace cru::platform::graphics::direct2d diff --git a/include/cru/platform/graphics/direct2d/Resource.h b/include/cru/platform/graphics/direct2d/Resource.h new file mode 100644 index 00000000..6d2f968c --- /dev/null +++ b/include/cru/platform/graphics/direct2d/Resource.h @@ -0,0 +1,52 @@ +#pragma once +#include "Base.h" + +#include "cru/platform/graphics/Resource.h" + +#include <string_view> + +namespace cru::platform::graphics::direct2d { +class DirectGraphicsFactory; + +class CRU_WIN_GRAPHICS_DIRECT_API DirectResource + : public Object, + public virtual IPlatformResource { + public: + static String kPlatformId; + + protected: + DirectResource() = default; + + public: + CRU_DELETE_COPY(DirectResource) + CRU_DELETE_MOVE(DirectResource) + + ~DirectResource() override = default; + + public: + String GetPlatformId() const final { return kPlatformId; } +}; + +class CRU_WIN_GRAPHICS_DIRECT_API DirectGraphicsResource + : public DirectResource, + public virtual IGraphicsResource { + protected: + // Param factory can't be null. + explicit DirectGraphicsResource(DirectGraphicsFactory* factory); + + public: + CRU_DELETE_COPY(DirectGraphicsResource) + CRU_DELETE_MOVE(DirectGraphicsResource) + + ~DirectGraphicsResource() override = default; + + public: + IGraphicsFactory* GetGraphicsFactory() final; + + public: + DirectGraphicsFactory* GetDirectFactory() const { return factory_; } + + private: + DirectGraphicsFactory* factory_; +}; +} // namespace cru::platform::graphics::direct2d diff --git a/include/cru/platform/graphics/direct2d/TextLayout.h b/include/cru/platform/graphics/direct2d/TextLayout.h new file mode 100644 index 00000000..9f2e75a9 --- /dev/null +++ b/include/cru/platform/graphics/direct2d/TextLayout.h @@ -0,0 +1,63 @@ +#pragma once +#include "ComResource.h" +#include "Resource.h" + +#include "cru/platform/graphics/TextLayout.h" + +#include <limits> +#include <memory> + +namespace cru::platform::graphics::direct2d { +class DWriteFont; + +class CRU_WIN_GRAPHICS_DIRECT_API DWriteTextLayout + : public DirectGraphicsResource, + public virtual ITextLayout, + public virtual IComResource<IDWriteTextLayout> { + public: + DWriteTextLayout(DirectGraphicsFactory* factory, std::shared_ptr<IFont> font, + String text); + + CRU_DELETE_COPY(DWriteTextLayout) + CRU_DELETE_MOVE(DWriteTextLayout) + + ~DWriteTextLayout() override; + + public: + IDWriteTextLayout* GetComInterface() const override { + return text_layout_.Get(); + } + + public: + String GetText() override; + void SetText(String new_text) override; + + std::shared_ptr<IFont> GetFont() override; + void SetFont(std::shared_ptr<IFont> font) override; + + void SetMaxWidth(float max_width) override; + void SetMaxHeight(float max_height) override; + + bool IsEditMode() override; + void SetEditMode(bool enable) override; + + Index GetLineIndexFromCharIndex(Index char_index) override; + float GetLineHeight(Index line_index) override; + Index GetLineCount() override; + + Rect GetTextBounds(bool includingTrailingSpace = false) override; + // Return empty vector if text_range.count is 0. Text range could be in + // reverse direction, it should be normalized first in implementation. + std::vector<Rect> TextRangeRect(const TextRange& text_range) override; + Rect TextSinglePoint(Index position, bool trailing) override; + TextHitTestResult HitTest(const Point& point) override; + + private: + bool edit_mode_ = false; + String text_; + std::shared_ptr<DWriteFont> font_; + float max_width_ = std::numeric_limits<float>::max(); + float max_height_ = std::numeric_limits<float>::max(); + Microsoft::WRL::ComPtr<IDWriteTextLayout> text_layout_; +}; +} // namespace cru::platform::graphics::direct2d diff --git a/include/cru/platform/graphics/direct2d/WindowPainter.h b/include/cru/platform/graphics/direct2d/WindowPainter.h new file mode 100644 index 00000000..01ff3b32 --- /dev/null +++ b/include/cru/platform/graphics/direct2d/WindowPainter.h @@ -0,0 +1,22 @@ +#pragma once +#include "Painter.h" +#include "WindowRenderTarget.h" + +namespace cru::platform::graphics::direct2d { +class CRU_WIN_GRAPHICS_DIRECT_API D2DWindowPainter + : public graphics::direct2d::D2DDeviceContextPainter { + public: + explicit D2DWindowPainter(D2DWindowRenderTarget* window); + + CRU_DELETE_COPY(D2DWindowPainter) + CRU_DELETE_MOVE(D2DWindowPainter) + + ~D2DWindowPainter() override; + + protected: + void DoEndDraw() override; + + private: + D2DWindowRenderTarget* render_target_; +}; +} // namespace cru::platform::graphics::direct2d diff --git a/include/cru/platform/graphics/direct2d/WindowRenderTarget.h b/include/cru/platform/graphics/direct2d/WindowRenderTarget.h new file mode 100644 index 00000000..c0251880 --- /dev/null +++ b/include/cru/platform/graphics/direct2d/WindowRenderTarget.h @@ -0,0 +1,43 @@ +#pragma once +#include "Factory.h" + +namespace cru::platform::graphics::direct2d { +// Represents a window render target. +class CRU_WIN_GRAPHICS_DIRECT_API D2DWindowRenderTarget : public Object { + public: + D2DWindowRenderTarget(gsl::not_null<DirectGraphicsFactory*> factory, + HWND hwnd); + + CRU_DELETE_COPY(D2DWindowRenderTarget) + CRU_DELETE_MOVE(D2DWindowRenderTarget) + + ~D2DWindowRenderTarget() override = default; + + public: + graphics::direct2d::DirectGraphicsFactory* GetDirectFactory() const { + return factory_; + } + + ID2D1DeviceContext1* GetD2D1DeviceContext() { + return d2d1_device_context_.Get(); + } + + void SetDpi(float x, float y); + + // Resize the underlying buffer. + void ResizeBuffer(int width, int height); + + // Present the data of the underlying buffer to the window. + void Present(); + + private: + void CreateTargetBitmap(); + + private: + DirectGraphicsFactory* factory_; + HWND hwnd_; + Microsoft::WRL::ComPtr<ID2D1DeviceContext1> d2d1_device_context_; + Microsoft::WRL::ComPtr<IDXGISwapChain1> dxgi_swap_chain_; + Microsoft::WRL::ComPtr<ID2D1Bitmap1> target_bitmap_; +}; +} // namespace cru::platform::graphics::direct2d diff --git a/include/cru/platform/gui/win/Base.h b/include/cru/platform/gui/win/Base.h new file mode 100644 index 00000000..78068827 --- /dev/null +++ b/include/cru/platform/gui/win/Base.h @@ -0,0 +1,27 @@ +#pragma once +#include "cru/platform/win/WinPreConfig.h" + +#include "cru/common/Base.h" + +#ifdef CRU_PLATFORM_WINDOWS +#ifdef CRU_WIN_GUI_EXPORT_API +#define CRU_WIN_GUI_API __declspec(dllexport) +#else +#define CRU_WIN_GUI_API __declspec(dllimport) +#endif +#else +#define CRU_WIN_GUI_API +#endif + +namespace cru::platform::gui::win { +class GodWindow; +class TimerManager; +class WinCursor; +class WinCursorManager; +class WindowClass; +class WindowManager; +class WinNativeWindow; +class WinUiApplication; +class WinInputMethodContext; +class WinClipboard; +} // namespace cru::platform::gui::win diff --git a/include/cru/platform/gui/win/Clipboard.h b/include/cru/platform/gui/win/Clipboard.h new file mode 100644 index 00000000..dc4bc9b5 --- /dev/null +++ b/include/cru/platform/gui/win/Clipboard.h @@ -0,0 +1,25 @@ +#pragma once +#include "Resource.h" +#include "cru/common/Base.h" +#include "cru/platform/gui/Clipboard.h" +#include "cru/platform/gui/win/Base.h" + +namespace cru::platform::gui::win { +class WinClipboard : public WinNativeResource, public virtual IClipboard { + CRU_DEFINE_CLASS_LOG_TAG(u"WinClipboard") + public: + explicit WinClipboard(WinUiApplication* application); + + CRU_DELETE_COPY(WinClipboard) + CRU_DELETE_MOVE(WinClipboard) + + ~WinClipboard() override; + + public: + String GetText() override; + void SetText(String text) override; + + private: + WinUiApplication* application_; +}; +} // namespace cru::platform::gui::win diff --git a/include/cru/platform/gui/win/Cursor.h b/include/cru/platform/gui/win/Cursor.h new file mode 100644 index 00000000..f9cb0a09 --- /dev/null +++ b/include/cru/platform/gui/win/Cursor.h @@ -0,0 +1,51 @@ +#pragma once +#include "Resource.h" + +#include "cru/platform/gui/Cursor.h" + +#include <memory> + +namespace cru::platform::gui::win { +class CRU_WIN_GUI_API WinCursor : public WinNativeResource, + public virtual ICursor { + CRU_DEFINE_CLASS_LOG_TAG(u"WinCursor") + + public: + WinCursor(HCURSOR handle, bool auto_destroy); + + CRU_DELETE_COPY(WinCursor) + CRU_DELETE_MOVE(WinCursor) + + ~WinCursor() override; + + public: + HCURSOR GetHandle() const { return handle_; } + + private: + HCURSOR handle_; + bool auto_destroy_; +}; + +class WinCursorManager : public WinNativeResource, + public virtual ICursorManager { + public: + WinCursorManager(); + + CRU_DELETE_COPY(WinCursorManager) + CRU_DELETE_MOVE(WinCursorManager) + + ~WinCursorManager() override = default; + + public: + std::shared_ptr<WinCursor> GetSystemWinCursor(SystemCursorType type); + + std::shared_ptr<ICursor> GetSystemCursor(SystemCursorType type) override { + return std::static_pointer_cast<ICursor>(GetSystemWinCursor(type)); + } + + private: + std::shared_ptr<WinCursor> sys_arrow_; + std::shared_ptr<WinCursor> sys_hand_; + std::shared_ptr<WinCursor> sys_ibeam_; +}; +} // namespace cru::platform::gui::win diff --git a/include/cru/platform/gui/win/Exception.h b/include/cru/platform/gui/win/Exception.h new file mode 100644 index 00000000..a0689075 --- /dev/null +++ b/include/cru/platform/gui/win/Exception.h @@ -0,0 +1,7 @@ +#pragma once +#include "cru/platform/win/Exception.h" + +namespace cru::platform::gui::win { +using platform::win::HResultError; +using platform::win::Win32Error; +} // namespace cru::platform::gui::win diff --git a/include/cru/platform/gui/win/GodWindow.h b/include/cru/platform/gui/win/GodWindow.h new file mode 100644 index 00000000..fe61c80d --- /dev/null +++ b/include/cru/platform/gui/win/GodWindow.h @@ -0,0 +1,39 @@ +#pragma once +#include "Base.h" + +#include "WindowNativeMessageEventArgs.h" +#include "cru/common/Event.h" +#include "cru/common/String.h" + +#include <memory> + +namespace cru::platform::gui::win { +class CRU_WIN_GUI_API GodWindow : public Object { + CRU_DEFINE_CLASS_LOG_TAG(u"GodWindow") + + public: + explicit GodWindow(WinUiApplication* application); + + CRU_DELETE_COPY(GodWindow) + CRU_DELETE_MOVE(GodWindow) + + ~GodWindow() override; + + HWND GetHandle() const { return hwnd_; } + + bool HandleGodWindowMessage(HWND hwnd, UINT msg, WPARAM w_param, + LPARAM l_param, LRESULT* result); + + IEvent<WindowNativeMessageEventArgs&>* MessageEvent() { + return &message_event_; + } + + private: + WinUiApplication* application_; + + std::unique_ptr<WindowClass> god_window_class_; + HWND hwnd_; + + Event<WindowNativeMessageEventArgs&> message_event_; +}; +} // namespace cru::platform::gui::win diff --git a/include/cru/platform/gui/win/InputMethod.h b/include/cru/platform/gui/win/InputMethod.h new file mode 100644 index 00000000..8e28f857 --- /dev/null +++ b/include/cru/platform/gui/win/InputMethod.h @@ -0,0 +1,88 @@ +// Some useful information can be found from chromium code: +// https://chromium.googlesource.com/chromium/chromium/+/refs/heads/master/ui/base/win/ime_input.h +// https://chromium.googlesource.com/chromium/chromium/+/refs/heads/master/ui/base/win/ime_input.cc + +#pragma once +#include "Resource.h" + +#include "WindowNativeMessageEventArgs.h" +#include "cru/platform/gui/InputMethod.h" + +#include <imm.h> + +namespace cru::platform::gui::win { +class CRU_WIN_GUI_API AutoHIMC : public Object { + CRU_DEFINE_CLASS_LOG_TAG(u"AutoHIMC") + + public: + explicit AutoHIMC(HWND hwnd); + + CRU_DELETE_COPY(AutoHIMC) + + AutoHIMC(AutoHIMC&& other); + AutoHIMC& operator=(AutoHIMC&& other); + + ~AutoHIMC() override; + + HWND GetHwnd() const { return hwnd_; } + + HIMC Get() const { return handle_; } + + private: + HWND hwnd_; + HIMC handle_; +}; + +class CRU_WIN_GUI_API WinInputMethodContext + : public WinNativeResource, + public virtual IInputMethodContext { + CRU_DEFINE_CLASS_LOG_TAG(u"WinInputMethodContext") + + public: + WinInputMethodContext(gsl::not_null<WinNativeWindow*> window); + + CRU_DELETE_COPY(WinInputMethodContext) + CRU_DELETE_MOVE(WinInputMethodContext) + + ~WinInputMethodContext() override; + + bool ShouldManuallyDrawCompositionText() override { return true; } + + void EnableIME() override; + + void DisableIME() override; + + void CompleteComposition() override; + + void CancelComposition() override; + + CompositionText GetCompositionText() override; + + void SetCandidateWindowPosition(const Point& point) override; + + IEvent<std::nullptr_t>* CompositionStartEvent() override; + + IEvent<std::nullptr_t>* CompositionEndEvent() override; + + IEvent<std::nullptr_t>* CompositionEvent() override; + + IEvent<StringView>* TextEvent() override; + + private: + void OnWindowNativeMessage(WindowNativeMessageEventArgs& args); + + String GetResultString(); + + AutoHIMC GetHIMC(); + + private: + WinNativeWindow* native_window_; + + EventRevokerListGuard event_guard_; + + Event<std::nullptr_t> composition_start_event_; + Event<std::nullptr_t> composition_end_event_; + Event<std::nullptr_t> composition_event_; + Event<StringView> text_event_; +}; +} // namespace cru::platform::gui::win diff --git a/include/cru/platform/gui/win/Keyboard.h b/include/cru/platform/gui/win/Keyboard.h new file mode 100644 index 00000000..18b37b60 --- /dev/null +++ b/include/cru/platform/gui/win/Keyboard.h @@ -0,0 +1,9 @@ +#pragma once +#include "Base.h" + +#include "cru/platform/gui/Keyboard.h" + +namespace cru::platform::gui::win { +KeyCode CRU_WIN_GUI_API VirtualKeyToKeyCode(int virtual_key); +KeyModifier CRU_WIN_GUI_API RetrieveKeyMofifier(); +} // namespace cru::platform::gui::win diff --git a/include/cru/platform/gui/win/Resource.h b/include/cru/platform/gui/win/Resource.h new file mode 100644 index 00000000..ed43bec3 --- /dev/null +++ b/include/cru/platform/gui/win/Resource.h @@ -0,0 +1,24 @@ +#pragma once +#include "Base.h" + +#include "cru/platform/Resource.h" + +namespace cru::platform::gui::win { +class CRU_WIN_GUI_API WinNativeResource : public Object, + public virtual IPlatformResource { + public: + static String kPlatformId; + + protected: + WinNativeResource() = default; + + public: + CRU_DELETE_COPY(WinNativeResource) + CRU_DELETE_MOVE(WinNativeResource) + + ~WinNativeResource() override = default; + + public: + String GetPlatformId() const final { return kPlatformId; } +}; +} // namespace cru::platform::gui::win diff --git a/include/cru/platform/gui/win/UiApplication.h b/include/cru/platform/gui/win/UiApplication.h new file mode 100644 index 00000000..5abe7356 --- /dev/null +++ b/include/cru/platform/gui/win/UiApplication.h @@ -0,0 +1,87 @@ +#pragma once +#include "Resource.h" + +#include "cru/platform/gui/Base.h" +#include "cru/platform/gui/UiApplication.h" + +#include <memory> + +namespace cru::platform::graphics::direct2d { +class DirectGraphicsFactory; +} + +namespace cru::platform::gui::win { +class CRU_WIN_GUI_API WinUiApplication : public WinNativeResource, + public virtual IUiApplication { + public: + static WinUiApplication* GetInstance() { return instance; } + + private: + static WinUiApplication* instance; + + public: + WinUiApplication(); + + CRU_DELETE_COPY(WinUiApplication) + CRU_DELETE_MOVE(WinUiApplication) + + ~WinUiApplication() override; + + public: + int Run() override; + void RequestQuit(int quit_code) override; + + void AddOnQuitHandler(std::function<void()> handler) override; + + bool IsQuitOnAllWindowClosed() override { + return is_quit_on_all_window_closed_; + } + void SetQuitOnAllWindowClosed(bool quit_on_all_window_closed) override { + is_quit_on_all_window_closed_ = quit_on_all_window_closed; + } + + long long SetImmediate(std::function<void()> action) override; + long long SetTimeout(std::chrono::milliseconds milliseconds, + std::function<void()> action) override; + long long SetInterval(std::chrono::milliseconds milliseconds, + std::function<void()> action) override; + void CancelTimer(long long id) override; + + std::vector<INativeWindow*> GetAllWindow() override; + INativeWindow* CreateWindow() override; + + cru::platform::graphics::IGraphicsFactory* GetGraphicsFactory() override; + + cru::platform::graphics::direct2d::DirectGraphicsFactory* + GetDirectFactory() { + return graph_factory_.get(); + } + + ICursorManager* GetCursorManager() override; + + IClipboard* GetClipboard() override; + + HINSTANCE GetInstanceHandle() const { return instance_handle_; } + + GodWindow* GetGodWindow() const { return god_window_.get(); } + TimerManager* GetTimerManager() const { return timer_manager_.get(); } + WindowManager* GetWindowManager() const { return window_manager_.get(); } + + private: + HINSTANCE instance_handle_; + + bool is_quit_on_all_window_closed_ = true; + + std::unique_ptr<cru::platform::graphics::direct2d::DirectGraphicsFactory> + graph_factory_; + + std::unique_ptr<GodWindow> god_window_; + std::unique_ptr<TimerManager> timer_manager_; + std::unique_ptr<WindowManager> window_manager_; + + std::unique_ptr<WinCursorManager> cursor_manager_; + std::unique_ptr<WinClipboard> clipboard_; + + std::vector<std::function<void()>> quit_handlers_; +}; +} // namespace cru::platform::gui::win diff --git a/include/cru/platform/gui/win/Window.h b/include/cru/platform/gui/win/Window.h new file mode 100644 index 00000000..292bdee2 --- /dev/null +++ b/include/cru/platform/gui/win/Window.h @@ -0,0 +1,217 @@ +#pragma once +#include "Resource.h" + +#include "WindowNativeMessageEventArgs.h" +#include "cru/platform/gui/Base.h" +#include "cru/platform/gui/Window.h" +#include "cru/platform/graphics/direct2d/WindowRenderTarget.h" + +#include <memory> + +namespace cru::platform::gui::win { +class CRU_WIN_GUI_API WinNativeWindow : public WinNativeResource, + public virtual INativeWindow { + CRU_DEFINE_CLASS_LOG_TAG(u"WinNativeWindow") + + public: + explicit WinNativeWindow(WinUiApplication* application); + + CRU_DELETE_COPY(WinNativeWindow) + CRU_DELETE_MOVE(WinNativeWindow) + + ~WinNativeWindow() override; + + public: + void Close() override; + + WinNativeWindow* GetParent() override { return parent_window_; } + void SetParent(INativeWindow* parent) override; + + WindowStyleFlag GetStyleFlag() override { return style_flag_; } + void SetStyleFlag(WindowStyleFlag flag) override; + + String GetTitle() override; + void SetTitle(String title) override; + + WindowVisibilityType GetVisibility() override { return visibility_; } + void SetVisibility(WindowVisibilityType visibility) override; + + Size GetClientSize() override; + void SetClientSize(const Size& size) override; + + Rect GetClientRect() override; + void SetClientRect(const Rect& rect) override; + + // Get the rect of the window containing frame. + // The lefttop of the rect is relative to screen lefttop. + Rect GetWindowRect() override; + + // Set the rect of the window containing frame. + // The lefttop of the rect is relative to screen lefttop. + void SetWindowRect(const Rect& rect) override; + + bool RequestFocus() override; + + Point GetMousePosition() override; + + bool CaptureMouse() override; + bool ReleaseMouse() override; + + void RequestRepaint() override; + std::unique_ptr<graphics::IPainter> BeginPaint() override; + + void SetCursor(std::shared_ptr<ICursor> cursor) override; + + void SetToForeground() override; + + IEvent<std::nullptr_t>* CreateEvent() override { return &create_event_; } + IEvent<std::nullptr_t>* DestroyEvent() override { return &destroy_event_; } + IEvent<std::nullptr_t>* PaintEvent() override { return &paint_event_; } + IEvent<WindowVisibilityType>* VisibilityChangeEvent() override { + return &visibility_change_event_; + } + IEvent<Size>* ResizeEvent() override { return &resize_event_; } + IEvent<FocusChangeType>* FocusEvent() override { return &focus_event_; } + IEvent<MouseEnterLeaveType>* MouseEnterLeaveEvent() override { + return &mouse_enter_leave_event_; + } + IEvent<Point>* MouseMoveEvent() override { return &mouse_move_event_; } + IEvent<platform::gui::NativeMouseButtonEventArgs>* MouseDownEvent() override { + return &mouse_down_event_; + } + IEvent<platform::gui::NativeMouseButtonEventArgs>* MouseUpEvent() override { + return &mouse_up_event_; + } + IEvent<NativeMouseWheelEventArgs>* MouseWheelEvent() override { + return &mouse_wheel_event_; + } + + IEvent<platform::gui::NativeKeyEventArgs>* KeyDownEvent() override { + return &key_down_event_; + } + IEvent<platform::gui::NativeKeyEventArgs>* KeyUpEvent() override { + return &key_up_event_; + } + + IEvent<WindowNativeMessageEventArgs&>* NativeMessageEvent() { + return &native_message_event_; + } + + IInputMethodContext* GetInputMethodContext() override; + + // Get the handle of the window. Return null if window is invalid. + HWND GetWindowHandle() const { return hwnd_; } + + bool HandleNativeWindowMessage(HWND hwnd, UINT msg, WPARAM w_param, + LPARAM l_param, LRESULT* result); + + graphics::direct2d::D2DWindowRenderTarget* GetWindowRenderTarget() const { + return window_render_target_.get(); + } + + //*************** region: dpi *************** + float GetDpi() const { return dpi_; } + + inline int DipToPixel(const float dip) { + return static_cast<int>(dip * GetDpi() / 96.0f); + } + + inline POINT DipToPixel(const Point& dip_point) { + POINT result; + result.x = DipToPixel(dip_point.x); + result.y = DipToPixel(dip_point.y); + return result; + } + + inline RECT DipToPixel(const Rect& dip_rect) { + RECT result; + result.left = DipToPixel(dip_rect.left); + result.top = DipToPixel(dip_rect.top); + result.right = DipToPixel(dip_rect.GetRight()); + result.bottom = DipToPixel(dip_rect.GetBottom()); + return result; + } + + inline float PixelToDip(const int pixel) { + return static_cast<float>(pixel) * 96.0f / GetDpi(); + } + + inline Point PixelToDip(const POINT& pi_point) { + return Point(PixelToDip(pi_point.x), PixelToDip(pi_point.y)); + } + + inline Rect PixelToDip(const RECT& pi_rect) { + return Rect::FromVertices(PixelToDip(pi_rect.left), PixelToDip(pi_rect.top), + PixelToDip(pi_rect.right), + PixelToDip(pi_rect.bottom)); + } + + private: + // Get the client rect in pixel. + RECT GetClientRectPixel(); + + void RecreateWindow(); + + //*************** region: native messages *************** + + void OnCreateInternal(); + void OnDestroyInternal(); + void OnPaintInternal(); + void OnMoveInternal(int new_left, int new_top); + void OnResizeInternal(int new_width, int new_height); + + void OnSetFocusInternal(); + void OnKillFocusInternal(); + + void OnMouseMoveInternal(POINT point); + void OnMouseLeaveInternal(); + void OnMouseDownInternal(platform::gui::MouseButton button, POINT point); + void OnMouseUpInternal(platform::gui::MouseButton button, POINT point); + + void OnMouseWheelInternal(short delta, POINT point); + void OnKeyDownInternal(int virtual_code); + void OnKeyUpInternal(int virtual_code); + + void OnActivatedInternal(); + void OnDeactivatedInternal(); + + private: + WinUiApplication* application_; + + WindowStyleFlag style_flag_{}; + WindowVisibilityType visibility_ = WindowVisibilityType::Hide; + Rect client_rect_{100, 100, 400, 300}; + String title_; + + HWND hwnd_ = nullptr; + WinNativeWindow* parent_window_ = nullptr; + + float dpi_; + + bool has_focus_ = false; + bool is_mouse_in_ = false; + + std::unique_ptr<graphics::direct2d::D2DWindowRenderTarget> + window_render_target_; + + std::shared_ptr<WinCursor> cursor_; + + std::unique_ptr<WinInputMethodContext> input_method_context_; + + Event<std::nullptr_t> create_event_; + Event<std::nullptr_t> destroy_event_; + Event<std::nullptr_t> paint_event_; + Event<Size> resize_event_; + Event<WindowVisibilityType> visibility_change_event_; + Event<FocusChangeType> focus_event_; + Event<MouseEnterLeaveType> mouse_enter_leave_event_; + Event<Point> mouse_move_event_; + Event<platform::gui::NativeMouseButtonEventArgs> mouse_down_event_; + Event<platform::gui::NativeMouseButtonEventArgs> mouse_up_event_; + Event<platform::gui::NativeMouseWheelEventArgs> mouse_wheel_event_; + Event<platform::gui::NativeKeyEventArgs> key_down_event_; + Event<platform::gui::NativeKeyEventArgs> key_up_event_; + + Event<WindowNativeMessageEventArgs&> native_message_event_; +}; +} // namespace cru::platform::gui::win diff --git a/include/cru/platform/gui/win/WindowClass.h b/include/cru/platform/gui/win/WindowClass.h new file mode 100644 index 00000000..50729887 --- /dev/null +++ b/include/cru/platform/gui/win/WindowClass.h @@ -0,0 +1,24 @@ +#pragma once +#include "Base.h" + +#include <string> + +namespace cru::platform::gui::win { +class CRU_WIN_GUI_API WindowClass : public Object { + public: + WindowClass(std::wstring name, WNDPROC window_proc, HINSTANCE h_instance); + + CRU_DELETE_COPY(WindowClass) + CRU_DELETE_MOVE(WindowClass) + + ~WindowClass() override = default; + + const wchar_t* GetName() const { return name_.c_str(); } + + ATOM GetAtom() const { return atom_; } + + private: + std::wstring name_; + ATOM atom_; +}; +} // namespace cru::platform::gui::win diff --git a/include/cru/platform/gui/win/WindowNativeMessageEventArgs.h b/include/cru/platform/gui/win/WindowNativeMessageEventArgs.h new file mode 100644 index 00000000..bc85a597 --- /dev/null +++ b/include/cru/platform/gui/win/WindowNativeMessageEventArgs.h @@ -0,0 +1,40 @@ +#pragma once +#include "Base.h" + +#include "cru/common/Base.h" + +namespace cru::platform::gui::win { +struct CRU_WIN_GUI_API WindowNativeMessage { + HWND hwnd; + UINT msg; + WPARAM w_param; + LPARAM l_param; +}; + +class CRU_WIN_GUI_API WindowNativeMessageEventArgs : public Object { + public: + WindowNativeMessageEventArgs(const WindowNativeMessage& message) + : message_(message) {} + CRU_DEFAULT_COPY(WindowNativeMessageEventArgs) + CRU_DEFAULT_MOVE(WindowNativeMessageEventArgs) + ~WindowNativeMessageEventArgs() override = default; + + const WindowNativeMessage& GetWindowMessage() const { return message_; } + + LRESULT GetResult() const { return result_; } + void SetResult(LRESULT result) { result_ = result; } + + bool IsHandled() const { return handled_; } + void SetHandled(bool handled) { handled_ = handled; } + + void HandleWithResult(LRESULT result) { + handled_ = true; + result_ = result; + } + + private: + WindowNativeMessage message_; + LRESULT result_; + bool handled_ = false; +}; +} // namespace cru::platform::gui::win diff --git a/include/cru/platform/win/Base.h b/include/cru/platform/win/Base.h new file mode 100644 index 00000000..75da7287 --- /dev/null +++ b/include/cru/platform/win/Base.h @@ -0,0 +1,13 @@ +#pragma once + +#include "WinPreConfig.h" + +#ifdef CRU_PLATFORM_WINDOWS +#ifdef CRU_WIN_EXPORT_API +#define CRU_WIN_API __declspec(dllexport) +#else +#define CRU_WIN_API __declspec(dllimport) +#endif +#else +#define CRU_WIN_API +#endif diff --git a/include/cru/platform/win/Exception.h b/include/cru/platform/win/Exception.h new file mode 100644 index 00000000..af8b495c --- /dev/null +++ b/include/cru/platform/win/Exception.h @@ -0,0 +1,3 @@ +#pragma once +#include "cru/common/platform/win/Exception.h" +#include "cru/platform/Exception.h" diff --git a/include/cru/platform/win/WinPreConfig.h b/include/cru/platform/win/WinPreConfig.h new file mode 100644 index 00000000..e714bf5e --- /dev/null +++ b/include/cru/platform/win/WinPreConfig.h @@ -0,0 +1,2 @@ +#pragma once +#include "cru/common/platform/win/WinPreConfig.h" |