diff --git a/Common/Gfx/Canvas.cpp b/Common/Gfx/Canvas.cpp new file mode 100644 index 00000000..534072ca --- /dev/null +++ b/Common/Gfx/Canvas.cpp @@ -0,0 +1,39 @@ +/* + Copyright (C) 2013 Birunthan Mohanathas + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "Canvas.h" + +namespace Gfx { + +Canvas::Canvas() : + m_W(), + m_H() +{ +} + +Canvas::~Canvas() +{ +} + +void Canvas::Resize(int w, int h) +{ + m_W = w; + m_H = h; +} + +} // namespace Gfx \ No newline at end of file diff --git a/Common/Gfx/Canvas.h b/Common/Gfx/Canvas.h new file mode 100644 index 00000000..b8afa649 --- /dev/null +++ b/Common/Gfx/Canvas.h @@ -0,0 +1,84 @@ +/* + Copyright (C) 2013 Birunthan Mohanathas + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef RM_GFX_CANVAS_H_ +#define RM_GFX_CANVAS_H_ + +#include "TextFormat.h" +#include +#include + +namespace Gfx { + +class Canvas +{ +public: + Canvas(); + virtual ~Canvas(); + + int GetW() const { return m_W; } + int GetH() const { return m_H; } + + virtual void Resize(int w, int h); + + // BeginDraw() must be matched by a corresponding call to EndDraw(). Drawing functions must be + // be called only between BeginDraw() and EndDraw(). + virtual bool BeginDraw() = 0; + virtual void EndDraw() = 0; + + // Allows the use of Gdiplus::Graphics to perform drawing. Must be called between BeginDraw() + // and EndDraw(). BeginGdiplusGraphicsContext() must be matched by a corresponding call to + // EndGdiplusGraphicsContext(). While in the Gdiplus context, non-const member functions of + // this class must not be called. + virtual Gdiplus::Graphics& BeginGdiplusContext() = 0; + virtual void EndGdiplusContext() = 0; + + // Returns a read-only DC. Must be called between BeginDraw() and EndDraw(). GetDC() must be + // matched by a corresponding call to ReleaseDC(). While in the Gdiplus context, non-const + // member functions of this class must not be called. + virtual HDC GetDC() = 0; + virtual void ReleaseDC(HDC dc) = 0; + + virtual TextFormat* CreateTextFormat() = 0; + + virtual bool IsTransparentPixel(int x, int y) = 0; + + virtual void SetAntiAliasing(bool enable) = 0; + virtual void SetTextAntiAliasing(bool enable) = 0; + + virtual void Clear(const Gdiplus::Color& color = Gdiplus::Color(0, 0, 0, 0)) = 0; + + virtual void DrawTextW(const WCHAR* str, UINT strLen, const TextFormat& format, Gdiplus::RectF& rect, const Gdiplus::SolidBrush& brush) = 0; + virtual bool MeasureTextW(const WCHAR* str, UINT strLen, const TextFormat& format, Gdiplus::RectF& rect) = 0; + virtual bool MeasureTextLinesW(const WCHAR* str, UINT strLen, const TextFormat& format, Gdiplus::RectF& rect, UINT& lines) = 0; + + virtual void DrawBitmap(Gdiplus::Bitmap* bitmap, const Gdiplus::Rect& dstRect, const Gdiplus::Rect& srcRect) = 0; + + virtual void FillRectangle(Gdiplus::Rect& rect, const Gdiplus::SolidBrush& brush) = 0; + +protected: + int m_W; + int m_H; + +private: + Canvas(const Canvas& other) {} +}; + +} // namespace Gfx + +#endif \ No newline at end of file diff --git a/Common/Gfx/CanvasD2D.cpp b/Common/Gfx/CanvasD2D.cpp new file mode 100644 index 00000000..332f40c1 --- /dev/null +++ b/Common/Gfx/CanvasD2D.cpp @@ -0,0 +1,444 @@ +/* + Copyright (C) 2013 Birunthan Mohanathas + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "CanvasD2D.h" +#include "TextFormatD2D.h" +#include "WICBitmapLockGDIP.h" +#include "../../Library/Litestep.h" + +template +inline void SafeRelease(T** t) +{ + if (*t) + { + (*t)->Release(); + *t = nullptr; + } +} + +namespace { + +D2D1_COLOR_F ToColorF(const Gdiplus::Color& color) +{ + return D2D1::ColorF(color.GetR() / 255.0f, color.GetG() / 255.0f, color.GetB() / 255.0f, color.GetA() / 255.0f); +} + +D2D1_RECT_F ToRectF(const Gdiplus::Rect& rect) +{ + return D2D1::RectF(rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height); +} + +D2D1_RECT_F ToRectF(const Gdiplus::RectF& rect) +{ + return D2D1::RectF(rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height); +} + +} // namespace + +namespace Gfx { + +UINT CanvasD2D::c_Instances = 0; +ID2D1Factory* CanvasD2D::c_D2D = nullptr; +IDWriteFactory* CanvasD2D::c_DW = nullptr; +IWICImagingFactory* CanvasD2D::c_WIC = nullptr; + +CanvasD2D::CanvasD2D() : Canvas(), + m_Target(), + m_InteropTarget(), + m_Bitmap(), + m_GdipGraphics(), + m_GdipBitmap(), + m_BeginDrawCalled(false), + m_TargetBeginDrawCalled(false) +{ + Initialize(); +} + +CanvasD2D::~CanvasD2D() +{ + DiscardDeviceResources(); + Finalize(); +} + +bool CanvasD2D::Initialize() +{ + ++c_Instances; + if (c_Instances == 1) + { + D2D1_FACTORY_OPTIONS fo = {}; +#ifdef _DEBUG + fo.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION; +#endif + + HRESULT hr = D2D1CreateFactory( + D2D1_FACTORY_TYPE_SINGLE_THREADED, + fo, + &c_D2D); + if (FAILED(hr)) return false; + + hr = CoCreateInstance( + CLSID_WICImagingFactory, + nullptr, + CLSCTX_INPROC_SERVER, + IID_IWICImagingFactory, + (LPVOID*)&c_WIC); + if (FAILED(hr)) return false; + + hr = DWriteCreateFactory( + DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory), + (IUnknown**)&c_DW); + if (FAILED(hr)) return false; + } + + return true; +} + +void CanvasD2D::Finalize() +{ + --c_Instances; + if (c_Instances == 0) + { + SafeRelease(&c_D2D); + SafeRelease(&c_WIC); + SafeRelease(&c_DW); + } +} + +void CanvasD2D::DiscardDeviceResources() +{ + SafeRelease(&m_InteropTarget); + SafeRelease(&m_Target); + SafeRelease(&m_Bitmap); + + delete m_GdipGraphics; + m_GdipGraphics = nullptr; + + delete m_GdipBitmap; + m_GdipBitmap = nullptr; +} + +void CanvasD2D::Resize(int w, int h) +{ + __super::Resize(w, h); + + DiscardDeviceResources(); + + const D2D1_PIXEL_FORMAT format = D2D1::PixelFormat( + DXGI_FORMAT_B8G8R8A8_UNORM, + D2D1_ALPHA_MODE_PREMULTIPLIED); + + const D2D1_RENDER_TARGET_PROPERTIES properties = D2D1::RenderTargetProperties( + D2D1_RENDER_TARGET_TYPE_DEFAULT, + format, + 0.0f, // Default DPI + 0.0f, // Default DPI + D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE); + + c_WIC->CreateBitmap( + w, + h, + GUID_WICPixelFormat32bppPBGRA, + WICBitmapCacheOnLoad, + &m_Bitmap); + + HRESULT hr = c_D2D->CreateWicBitmapRenderTarget(m_Bitmap, properties, &m_Target); + if (SUCCEEDED(hr)) + { + hr = m_Target->QueryInterface(&m_InteropTarget); // Always succeeds + + // Get the data pointer of the created IWICBitmap to create a Gdiplus::Bitmap + // that shares the data. It is assumed that the data pointer will stay valid + // and writable until the next resize. + WICRect rect = {0, 0, w, h}; + IWICBitmapLock* lock = nullptr; + hr = m_Bitmap->Lock(&rect, WICBitmapLockRead | WICBitmapLockWrite, &lock); + if (SUCCEEDED(hr)) + { + UINT size; + BYTE* data; + HRESULT hr = lock->GetDataPointer(&size, &data); + if (SUCCEEDED(hr)) + { + m_GdipBitmap = new Gdiplus::Bitmap(w, h, w * 4, PixelFormat32bppPARGB, data); + m_GdipGraphics = new Gdiplus::Graphics(m_GdipBitmap); + } + + lock->Release(); + } + } +} + +bool CanvasD2D::BeginDraw() +{ + if (m_Target) + { + m_BeginDrawCalled = true; + } + + return true; +} + +void CanvasD2D::EndDraw() +{ + m_BeginDrawCalled = false; + EndTargetDraw(); +} + +void CanvasD2D::BeginTargetDraw() +{ + if (m_BeginDrawCalled && !m_TargetBeginDrawCalled) + { + m_TargetBeginDrawCalled = true; + m_Target->BeginDraw(); + } +} + +void CanvasD2D::EndTargetDraw() +{ + if (m_TargetBeginDrawCalled) + { + m_TargetBeginDrawCalled = false; + HRESULT hr = m_Target->EndDraw(); + if (hr == D2DERR_RECREATE_TARGET) + { + DiscardDeviceResources(); + + // Attempt to recreate target. + Resize(m_W, m_H); + } + } +} + +Gdiplus::Graphics& CanvasD2D::BeginGdiplusContext() +{ + if (m_BeginDrawCalled) + { + EndTargetDraw(); + + // Pretend that the render target BeginDraw() has been called. This will cause draw calls + // on the render target to fail until EndGdiplusContext() is used. + m_TargetBeginDrawCalled = true; + } + + return *m_GdipGraphics; +} + +void CanvasD2D::EndGdiplusContext() +{ + // See BeginGdiplusContext(). + m_TargetBeginDrawCalled = false; +} + +HDC CanvasD2D::GetDC() +{ + BeginTargetDraw(); + + HDC dcMemory = nullptr; + m_InteropTarget->GetDC(D2D1_DC_INITIALIZE_MODE_COPY, &dcMemory); + return dcMemory; +} + +void CanvasD2D::ReleaseDC(HDC dc) +{ + // Assume that the DC was not modified. + RECT r = {0, 0, 0, 0}; + m_InteropTarget->ReleaseDC(&r); +} + +bool CanvasD2D::IsTransparentPixel(int x, int y) +{ + if (!(x >= 0 && y >= 0 && x < m_W && y < m_H)) return false; + + bool transparent = true; + + WICRect rect = {0, 0, m_W, m_H}; + IWICBitmapLock* lock = nullptr; + HRESULT hr = m_Bitmap->Lock(&rect, WICBitmapLockRead, &lock); + if (SUCCEEDED(hr)) + { + UINT size; + DWORD* data; + hr = lock->GetDataPointer(&size, (BYTE**)&data); + if (SUCCEEDED(hr)) + { + DWORD pixel = data[y * m_W + x]; // top-down DIB + transparent = (pixel & 0xFF000000) != 0; + } + + lock->Release(); + } + + return transparent; +} + +void CanvasD2D::SetAntiAliasing(bool enable) +{ + // TODO: Set m_Target aliasing? + m_GdipGraphics->SetSmoothingMode( + enable ? Gdiplus::SmoothingModeHighQuality : Gdiplus::SmoothingModeNone); + m_GdipGraphics->SetPixelOffsetMode( + enable ? Gdiplus::PixelOffsetModeHighQuality : Gdiplus::PixelOffsetModeDefault); +} + +void CanvasD2D::SetTextAntiAliasing(bool enable) +{ + // TODO: Add support for D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE? + m_Target->SetTextAntialiasMode( + enable ? D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE : D2D1_TEXT_ANTIALIAS_MODE_ALIASED); +} + +void CanvasD2D::Clear(const Gdiplus::Color& color) +{ + BeginTargetDraw(); + m_Target->Clear(ToColorF(color)); +} + +void CanvasD2D::DrawTextW(const WCHAR* str, UINT strLen, const TextFormat& format, Gdiplus::RectF& rect, const Gdiplus::SolidBrush& brush) +{ + BeginTargetDraw(); + + Gdiplus::Color color; + brush.GetColor(&color); + + ID2D1SolidColorBrush* solidBrush; + m_Target->CreateSolidColorBrush(ToColorF(color), &solidBrush); + + bool right = ((TextFormatD2D&)format).GetHorizontalAlignment() == Gfx::HorizontalAlignment::Right; + + // TODO: Draw cached layout? + //m_Target->DrawTextLayout( + // D2D1::Point2F(right ? rect.X - 2 : rect.X + 2.0f, rect.Y - 1.0f), + // textLayout, + // solidBrush); + + m_Target->DrawTextW( + str, + strLen, + ((TextFormatD2D&)format).m_TextFormat, + D2D1::RectF(right ? rect.X - 2 : rect.X + 2.0f, rect.Y - 1.0f, (right ? rect.X - 2 : rect.X + 2.0f) + rect.Width, rect.Y + rect.Height - 1.0f), + solidBrush, + D2D1_DRAW_TEXT_OPTIONS_NONE); + + solidBrush->Release(); +} + +bool CanvasD2D::MeasureTextW(const WCHAR* str, UINT strLen, const TextFormat& format, Gdiplus::RectF& rect) +{ + IDWriteTextLayout* textLayout; + HRESULT hr = c_DW->CreateTextLayout( + str, + strLen, + ((TextFormatD2D&)format).m_TextFormat, + 10000, + 10000, + &textLayout); + if (SUCCEEDED(hr)) + { + DWRITE_TEXT_METRICS metrics; + textLayout->GetMetrics(&metrics); + rect.Width = metrics.width + 5.0f; + rect.Height = metrics.height + 1.0f; // 1.0f to get same result as GDI+. + + textLayout->Release(); + return true; + } + + return false; +} + +bool CanvasD2D::MeasureTextLinesW(const WCHAR* str, UINT strLen, const TextFormat& format, Gdiplus::RectF& rect, UINT& lines) +{ + ((TextFormatD2D&)format).m_TextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_WRAP); + + IDWriteTextLayout* textLayout; + HRESULT hr = c_DW->CreateTextLayout( + str, + strLen, + ((TextFormatD2D&)format).m_TextFormat, + rect.Width, + 10000, + &textLayout); + if (SUCCEEDED(hr)) + { + DWRITE_TEXT_METRICS metrics; + textLayout->GetMetrics(&metrics); + rect.Width = metrics.width + 5.0f; + rect.Height = metrics.height + 1.0f; // 1.0f to get same result as GDI+. + lines = metrics.lineCount; + + textLayout->Release(); + return true; + } + + return false; +} + +void CanvasD2D::DrawBitmap(Gdiplus::Bitmap* bitmap, const Gdiplus::Rect& dstRect, const Gdiplus::Rect& srcRect) +{ + // The D2D DrawBitmap seems to perform exactly like Gdiplus::Graphics::DrawImage since we are + // not using a hardware accelerated render target. Nevertheless, we will use it to avoid + // the EndDraw() call needed for GDI+ drawing. + bool draw = false; + WICBitmapLockGDIP* bitmapLock = new WICBitmapLockGDIP(); + Gdiplus::Status status = bitmap->LockBits( + &srcRect, Gdiplus::ImageLockModeRead, PixelFormat32bppPARGB, bitmapLock->GetBitmapData()); + if (status == Gdiplus::Ok) + { + D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties( + D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)); + ID2D1Bitmap* d2dBitmap; + HRESULT hr = m_Target->CreateSharedBitmap(__uuidof(IWICBitmapLock), bitmapLock, &props, &d2dBitmap); + if (SUCCEEDED(hr)) + { + BeginTargetDraw(); + + auto rDst = ToRectF(dstRect); + auto rSrc = ToRectF(srcRect); + m_Target->DrawBitmap(d2dBitmap, rDst, 1.0F, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, rSrc); + draw = true; + + d2dBitmap->Release(); + } + + // D2D will still use the pixel data after this call (at the next Flush() or EndDraw()). + bitmap->UnlockBits(bitmapLock->GetBitmapData()); + } + + if (!draw) + { + delete bitmapLock; + } +} + +void CanvasD2D::FillRectangle(Gdiplus::Rect& rect, const Gdiplus::SolidBrush& brush) +{ + BeginTargetDraw(); + + Gdiplus::Color color; + brush.GetColor(&color); + + ID2D1SolidColorBrush* solidBrush; + m_Target->CreateSolidColorBrush(ToColorF(color), &solidBrush); + + m_Target->FillRectangle(ToRectF(rect), solidBrush); + + solidBrush->Release(); +} + +} // namespace Gfx \ No newline at end of file diff --git a/Common/Gfx/CanvasD2D.h b/Common/Gfx/CanvasD2D.h new file mode 100644 index 00000000..84da9f3d --- /dev/null +++ b/Common/Gfx/CanvasD2D.h @@ -0,0 +1,105 @@ +/* + Copyright (C) 2013 Birunthan Mohanathas + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef RM_GFX_CANVASD2D_H_ +#define RM_GFX_CANVASD2D_H_ + +#include "Canvas.h" +#include "TextFormatD2D.h" +#include +#include +#include +#include +#include +#include + +namespace Gfx { + +// Provides a Direct2D/DirectWrite implementation of Canvas. +class CanvasD2D : public Canvas +{ +public: + CanvasD2D(); + ~CanvasD2D(); + + virtual void Resize(int w, int h); + + virtual bool BeginDraw(); + virtual void EndDraw(); + + virtual Gdiplus::Graphics& BeginGdiplusContext() override; + virtual void EndGdiplusContext() override; + + virtual HDC GetDC() override; + virtual void ReleaseDC(HDC dc) override; + + virtual TextFormat* CreateTextFormat() override { return new TextFormatD2D(); } + + virtual bool IsTransparentPixel(int x, int y) override; + + virtual void SetAntiAliasing(bool enable) override; + virtual void SetTextAntiAliasing(bool enable) override; + + virtual void Clear(const Gdiplus::Color& color) override; + + virtual void DrawTextW(const WCHAR* str, UINT strLen, const TextFormat& format, Gdiplus::RectF& rect, const Gdiplus::SolidBrush& brush) override; + virtual bool MeasureTextW(const WCHAR* str, UINT strLen, const TextFormat& format, Gdiplus::RectF& rect) override; + virtual bool MeasureTextLinesW(const WCHAR* str, UINT strLen, const TextFormat& format, Gdiplus::RectF& rect, UINT& lines) override; + + virtual void DrawBitmap(Gdiplus::Bitmap* bitmap, const Gdiplus::Rect& dstRect, const Gdiplus::Rect& srcRect) override; + + virtual void FillRectangle(Gdiplus::Rect& rect, const Gdiplus::SolidBrush& brush) override; + +private: + friend class TextFormatD2D; + + CanvasD2D(const CanvasD2D& other) {} + + static bool Initialize(); + static void Finalize(); + + void DiscardDeviceResources(); + + void BeginTargetDraw(); + void EndTargetDraw(); + + ID2D1RenderTarget* m_Target; + ID2D1GdiInteropRenderTarget* m_InteropTarget; + IWICBitmap* m_Bitmap; + + // GDI+ objects that share the pixel data of m_Bitmap. + Gdiplus::Graphics* m_GdipGraphics; + Gdiplus::Bitmap* m_GdipBitmap; + + // If true, the BeginDraw() function of this class has been called and the matching EndDraw() + // has not been called yet. + bool m_BeginDrawCalled; + + // If true, the BeginDraw() function of the render target has been called and the matching + // EndDraw() has not been called yet. + bool m_TargetBeginDrawCalled; + + static UINT c_Instances; + static ID2D1Factory* c_D2D; + static IDWriteFactory* c_DW; + static IWICImagingFactory* c_WIC; +}; + +} // namespace Gfx + +#endif \ No newline at end of file diff --git a/Common/Gfx/CanvasGDIP.cpp b/Common/Gfx/CanvasGDIP.cpp new file mode 100644 index 00000000..d798c037 --- /dev/null +++ b/Common/Gfx/CanvasGDIP.cpp @@ -0,0 +1,194 @@ +/* + Copyright (C) 2013 Birunthan Mohanathas + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "CanvasGDIP.h" + +namespace Gfx { + +CanvasGDIP::CanvasGDIP() : Canvas(), + m_Graphics(), + m_DoubleBuffer(), + m_DIBSectionBuffer(), + m_DIBSectionBufferPixels() +{ +} + +CanvasGDIP::~CanvasGDIP() +{ + delete m_DoubleBuffer; + if (m_DIBSectionBuffer) DeleteObject(m_DIBSectionBuffer); +} + +void CanvasGDIP::Resize(int w, int h) +{ + __super::Resize(w, h); + + delete m_Graphics; + + if (m_DIBSectionBuffer) + { + delete m_DoubleBuffer; + DeleteObject(m_DIBSectionBuffer); + m_DIBSectionBufferPixels = nullptr; + } + + BITMAPV4HEADER bh = {sizeof(BITMAPV4HEADER)}; + bh.bV4Width = w; + bh.bV4Height = -h; // Top-down DIB + bh.bV4Planes = 1; + bh.bV4BitCount = 32; + bh.bV4V4Compression = BI_BITFIELDS; + bh.bV4RedMask = 0x00FF0000; + bh.bV4GreenMask = 0x0000FF00; + bh.bV4BlueMask = 0x000000FF; + bh.bV4AlphaMask = 0xFF000000; + + m_DIBSectionBuffer = CreateDIBSection( + nullptr, + (BITMAPINFO*)&bh, + DIB_RGB_COLORS, + (void**)&m_DIBSectionBufferPixels, + nullptr, + 0); + + // Create GDI+ bitmap from the DIBSection pixels + m_DoubleBuffer = new Gdiplus::Bitmap( + w, + h, + w * 4, + PixelFormat32bppPARGB, + (BYTE*)m_DIBSectionBufferPixels); + + m_Graphics = new Gdiplus::Graphics(m_DoubleBuffer); +} + +bool CanvasGDIP::BeginDraw() +{ + m_Graphics->SetInterpolationMode(Gdiplus::InterpolationModeDefault); + m_Graphics->SetCompositingQuality(Gdiplus::CompositingQualityDefault); + return true; +} + +void CanvasGDIP::EndDraw() +{ +} + +Gdiplus::Graphics& CanvasGDIP::BeginGdiplusContext() +{ + return *m_Graphics; +} + +void CanvasGDIP::EndGdiplusContext() +{ +} + +HDC CanvasGDIP::GetDC() +{ + HDC dcMemory = CreateCompatibleDC(nullptr); + SelectObject(dcMemory, m_DIBSectionBuffer); + return dcMemory; +} + +void CanvasGDIP::ReleaseDC(HDC dc) +{ + DeleteDC(dc); +} + +bool CanvasGDIP::IsTransparentPixel(int x, int y) +{ + if (m_DIBSectionBufferPixels && x >= 0 && y >= 0 && x < m_W && y < m_H) + { + DWORD pixel = m_DIBSectionBufferPixels[y * m_W + x]; // top-down DIB + return ((pixel & 0xFF000000) != 0); + } + + return false; +} + +void CanvasGDIP::SetAntiAliasing(bool enable) +{ + m_Graphics->SetSmoothingMode( + enable ? Gdiplus::SmoothingModeHighQuality : Gdiplus::SmoothingModeNone); + m_Graphics->SetPixelOffsetMode( + enable ? Gdiplus::PixelOffsetModeHighQuality : Gdiplus::PixelOffsetModeDefault); +} + +void CanvasGDIP::SetTextAntiAliasing(bool enable) +{ + m_Graphics->SetTextRenderingHint( + enable ? Gdiplus::TextRenderingHintAntiAlias : Gdiplus::TextRenderingHintSingleBitPerPixelGridFit); +} + +void CanvasGDIP::Clear(const Gdiplus::Color& color) +{ + if (color.GetValue() == 0x00000000) + { + memset(m_DIBSectionBufferPixels, 0, m_W * m_H * 4); + } + else + { + m_Graphics->Clear(color); + } +} + +void CanvasGDIP::DrawTextW(const WCHAR* str, UINT strLen, const TextFormat& format, Gdiplus::RectF& rect, const Gdiplus::SolidBrush& brush) +{ + Gdiplus::StringFormat& stringFormat = ((TextFormatGDIP&)format).m_StringFormat; + m_Graphics->DrawString(str, (INT)strLen, ((TextFormatGDIP&)format).m_Font, rect, &stringFormat, &brush); +} + +bool CanvasGDIP::MeasureTextW(const WCHAR* str, UINT strLen, const TextFormat& format, Gdiplus::RectF& rect) +{ + Gdiplus::StringFormat& stringFormat = ((TextFormatGDIP&)format).m_StringFormat; + const Gdiplus::Status status = m_Graphics->MeasureString(str, (INT)strLen, ((TextFormatGDIP&)format).m_Font, rect, &stringFormat, &rect); + return status == Gdiplus::Ok; +} + +bool CanvasGDIP::MeasureTextLinesW(const WCHAR* str, UINT strLen, const TextFormat& format, Gdiplus::RectF& rect, UINT& lines) +{ + Gdiplus::StringFormat& stringFormat = ((TextFormatGDIP&)format).m_StringFormat; + + // Set trimming and format temporarily. + const Gdiplus::StringTrimming stringTrimming = stringFormat.GetTrimming(); + stringFormat.SetTrimming(Gdiplus::StringTrimmingNone); + + const INT stringFormatFlags = stringFormat.GetFormatFlags(); + stringFormat.SetFormatFlags(Gdiplus::StringFormatFlagsNoClip); + + INT linesFilled = 0; + const Gdiplus::Status status = m_Graphics->MeasureString(str, (INT)strLen, ((TextFormatGDIP&)format).m_Font, rect, &stringFormat, &rect, nullptr, &linesFilled); + lines = linesFilled; + + // Restore old options. + stringFormat.SetTrimming(stringTrimming); + stringFormat.SetFormatFlags(stringFormatFlags); + + return status == Gdiplus::Ok; +} + +void CanvasGDIP::DrawBitmap(Gdiplus::Bitmap* bitmap, const Gdiplus::Rect& dstRect, const Gdiplus::Rect& srcRect) +{ + m_Graphics->DrawImage(bitmap, dstRect, srcRect.X, srcRect.Y, srcRect.Width, srcRect.Height, Gdiplus::UnitPixel); +} + +void CanvasGDIP::FillRectangle(Gdiplus::Rect& rect, const Gdiplus::SolidBrush& brush) +{ + m_Graphics->FillRectangle(&brush, rect); +} + +} // namespace Gfx \ No newline at end of file diff --git a/Common/Gfx/CanvasGDIP.h b/Common/Gfx/CanvasGDIP.h new file mode 100644 index 00000000..938a448b --- /dev/null +++ b/Common/Gfx/CanvasGDIP.h @@ -0,0 +1,77 @@ +/* + Copyright (C) 2013 Birunthan Mohanathas + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef RM_GFX_CANVASGDI_H_ +#define RM_GFX_CANVASGDI_H_ + +#include "Canvas.h" +#include "TextFormatGDIP.h" +#include +#include + +namespace Gfx { + +// Provides a GDI+ implementation of Canvas. +class CanvasGDIP : public Canvas +{ +public: + CanvasGDIP(); + ~CanvasGDIP(); + + virtual void Resize(int w, int h); + + virtual bool BeginDraw(); + virtual void EndDraw(); + + virtual Gdiplus::Graphics& BeginGdiplusContext() override; + virtual void EndGdiplusContext() override; + + virtual HDC GetDC() override; + virtual void ReleaseDC(HDC dc) override; + + virtual TextFormat* CreateTextFormat() override { return new TextFormatGDIP(); } + + virtual bool IsTransparentPixel(int x, int y) override; + + virtual void SetAntiAliasing(bool enable) override; + virtual void SetTextAntiAliasing(bool enable) override; + + virtual void Clear(const Gdiplus::Color& color) override; + + virtual void DrawTextW(const WCHAR* str, UINT strLen, const TextFormat& format, Gdiplus::RectF& rect, const Gdiplus::SolidBrush& brush) override; + virtual bool MeasureTextW(const WCHAR* str, UINT strLen, const TextFormat& format, Gdiplus::RectF& rect) override; + virtual bool MeasureTextLinesW(const WCHAR* str, UINT strLen, const TextFormat& format, Gdiplus::RectF& rect, UINT& lines) override; + + virtual void DrawBitmap(Gdiplus::Bitmap* bitmap, const Gdiplus::Rect& dstRect, const Gdiplus::Rect& srcRect) override; + + virtual void FillRectangle(Gdiplus::Rect& rect, const Gdiplus::SolidBrush& brush) override; + +private: + CanvasGDIP(const CanvasGDIP& other) {} + + Gdiplus::Graphics* m_Graphics; + Gdiplus::Bitmap* m_DoubleBuffer; + HBITMAP m_DIBSectionBuffer; + LPDWORD m_DIBSectionBufferPixels; + + //static ULONG_PTR c_GdiToken; +}; + +} // namespace Gfx + +#endif \ No newline at end of file diff --git a/Common/Gfx/TextFormat.cpp b/Common/Gfx/TextFormat.cpp new file mode 100644 index 00000000..0718a7ea --- /dev/null +++ b/Common/Gfx/TextFormat.cpp @@ -0,0 +1,43 @@ +/* + Copyright (C) 2013 Birunthan Mohanathas + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "TextFormat.h" + +namespace Gfx { + +TextFormat::TextFormat() : + m_HorizontalAlignment(HorizontalAlignment::Left), + m_VerticalAlignment(VerticalAlignment::Top) +{ +} + +TextFormat::~TextFormat() +{ +} + +void TextFormat::SetHorizontalAlignment(HorizontalAlignment alignment) +{ + m_HorizontalAlignment = alignment; +} + +void TextFormat::SetVerticalAlignment(VerticalAlignment alignment) +{ + m_VerticalAlignment = alignment; +} + +} // namespace Gfx \ No newline at end of file diff --git a/Common/Gfx/TextFormat.h b/Common/Gfx/TextFormat.h new file mode 100644 index 00000000..29a733ea --- /dev/null +++ b/Common/Gfx/TextFormat.h @@ -0,0 +1,66 @@ +/* + Copyright (C) 2013 Birunthan Mohanathas + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef RM_GFX_TEXTFORMAT_H_ +#define RM_GFX_TEXTFORMAT_H_ + +#include + +namespace Gfx { + +enum class HorizontalAlignment : BYTE +{ + Left, + Center, + Right +}; + +enum class VerticalAlignment : BYTE +{ + Top, + Center, + Bottom +}; + +class TextFormat +{ +public: + TextFormat(); + virtual ~TextFormat(); + + virtual bool IsInitialized() = 0; + virtual void SetProperties(const WCHAR* fontFamily, int size, bool bold, bool italic) = 0; + + virtual void SetTrimming(bool trim) = 0; + + virtual void SetHorizontalAlignment(HorizontalAlignment alignment); + HorizontalAlignment GetHorizontalAlignment() { return m_HorizontalAlignment; } + + virtual void SetVerticalAlignment(VerticalAlignment alignment); + VerticalAlignment GetVerticalAlignment() { return m_VerticalAlignment; } + +private: + TextFormat(const TextFormat& other) {} + + HorizontalAlignment m_HorizontalAlignment; + VerticalAlignment m_VerticalAlignment; +}; + +} // namespace Gfx + +#endif \ No newline at end of file diff --git a/Common/Gfx/TextFormatD2D.cpp b/Common/Gfx/TextFormatD2D.cpp new file mode 100644 index 00000000..357957ad --- /dev/null +++ b/Common/Gfx/TextFormatD2D.cpp @@ -0,0 +1,119 @@ +/* + Copyright (C) 2013 Birunthan Mohanathas + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "TextFormatD2D.h" +#include "CanvasD2D.h" + +namespace Gfx { + +TextFormatD2D::TextFormatD2D() : + m_TextFormat(), + m_InlineEllipsis() +{ +} + +TextFormatD2D::~TextFormatD2D() +{ + Dispose(); +} + +void TextFormatD2D::Dispose() +{ + if (m_TextFormat) + { + m_TextFormat->Release(); + m_TextFormat = nullptr; + } + + if (m_InlineEllipsis) + { + m_InlineEllipsis->Release(); + m_InlineEllipsis = nullptr; + } +} + +void TextFormatD2D::SetProperties(const WCHAR* fontFamily, int size, bool bold, bool italic) +{ + Dispose(); + + HRESULT hr = CanvasD2D::c_DW->CreateTextFormat( + fontFamily, + nullptr, + bold ? DWRITE_FONT_WEIGHT_BOLD : DWRITE_FONT_WEIGHT_REGULAR, + italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, + DWRITE_FONT_STRETCH_NORMAL, + size * (4.0f / 3.0f), + L"", + &m_TextFormat); + + if (SUCCEEDED(hr)) + { + CanvasD2D::c_DW->CreateEllipsisTrimmingSign(m_TextFormat, &m_InlineEllipsis); + + SetHorizontalAlignment(GetHorizontalAlignment()); + SetVerticalAlignment(GetVerticalAlignment()); + } + else + { + Dispose(); + } +} + +void TextFormatD2D::SetTrimming(bool trim) +{ + IDWriteInlineObject* inlineObject = nullptr; + DWRITE_TRIMMING trimming = {}; + DWRITE_WORD_WRAPPING wordWrapping = DWRITE_WORD_WRAPPING_NO_WRAP; + if (trim) + { + inlineObject = m_InlineEllipsis; + trimming.granularity = DWRITE_TRIMMING_GRANULARITY_CHARACTER; + wordWrapping = DWRITE_WORD_WRAPPING_WRAP; + } + + m_TextFormat->SetTrimming(&trimming, inlineObject); + m_TextFormat->SetWordWrapping(wordWrapping); +} + +void TextFormatD2D::SetHorizontalAlignment(HorizontalAlignment alignment) +{ + __super::SetHorizontalAlignment(alignment); + + if (m_TextFormat) + { + m_TextFormat->SetTextAlignment( + (alignment == HorizontalAlignment::Left) ? DWRITE_TEXT_ALIGNMENT_LEADING : + (alignment == HorizontalAlignment::Center) ? DWRITE_TEXT_ALIGNMENT_CENTER : + DWRITE_TEXT_ALIGNMENT_TRAILING); + } +} + +void TextFormatD2D::SetVerticalAlignment(VerticalAlignment alignment) +{ + __super::SetVerticalAlignment(alignment); + + if (m_TextFormat) + { + m_TextFormat->SetParagraphAlignment( + (alignment == VerticalAlignment::Top) ? DWRITE_PARAGRAPH_ALIGNMENT_NEAR : + (alignment == VerticalAlignment::Center) ? DWRITE_PARAGRAPH_ALIGNMENT_CENTER : + DWRITE_PARAGRAPH_ALIGNMENT_FAR); + } +} + +} // namespace Gfx \ No newline at end of file diff --git a/Common/Gfx/TextFormatD2D.h b/Common/Gfx/TextFormatD2D.h new file mode 100644 index 00000000..a57b993e --- /dev/null +++ b/Common/Gfx/TextFormatD2D.h @@ -0,0 +1,53 @@ +/* + Copyright (C) 2013 Birunthan Mohanathas + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef RM_GFX_TEXTFORMATD2D_H_ +#define RM_GFX_TEXTFORMATD2D_H_ + +#include "TextFormat.h" +#include + +namespace Gfx { + +class TextFormatD2D : public TextFormat +{ +public: + TextFormatD2D(); + virtual ~TextFormatD2D(); + + virtual bool IsInitialized() { return m_TextFormat != nullptr; } + virtual void SetProperties(const WCHAR* fontFamily, int size, bool bold, bool italic); + + virtual void SetTrimming(bool trim) override; + virtual void SetHorizontalAlignment(HorizontalAlignment alignment) override; + virtual void SetVerticalAlignment(VerticalAlignment alignment) override; + +private: + friend class CanvasD2D; + + TextFormatD2D(const TextFormatD2D& other) {} + + void Dispose(); + + IDWriteTextFormat* m_TextFormat; + IDWriteInlineObject* m_InlineEllipsis; +}; + +} // namespace Gfx + +#endif \ No newline at end of file diff --git a/Common/Gfx/TextFormatGDIP.cpp b/Common/Gfx/TextFormatGDIP.cpp new file mode 100644 index 00000000..538e0350 --- /dev/null +++ b/Common/Gfx/TextFormatGDIP.cpp @@ -0,0 +1,133 @@ +/* + Copyright (C) 2013 Birunthan Mohanathas + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "TextFormatGDIP.h" + +namespace Gfx { + +TextFormatGDIP::TextFormatGDIP() : + m_Font(), + m_FontFamily() +{ +} + +TextFormatGDIP::~TextFormatGDIP() +{ + Dispose(); +} + +void TextFormatGDIP::Dispose() +{ + delete m_FontFamily; + m_FontFamily = nullptr; + + delete m_Font; + m_Font = nullptr; +} + +void TextFormatGDIP::SetProperties(const WCHAR* fontFamily, int size, bool bold, bool italic) +{ + Dispose(); + + m_FontFamily = new Gdiplus::FontFamily(fontFamily); + if (m_FontFamily->GetLastStatus() != Gdiplus::Ok) + { + delete m_FontFamily; + m_FontFamily = nullptr; + } + + Gdiplus::FontStyle style = Gdiplus::FontStyleRegular; + if (bold && italic) + { + style = Gdiplus::FontStyleBoldItalic; + } + else if (bold) + { + style = Gdiplus::FontStyleBold; + } + else if (italic) + { + style = Gdiplus::FontStyleItalic; + } + + if (size != 0) + { + // Adjust the font size with screen DPI. + HDC dc = GetDC(0); + const int dpi = GetDeviceCaps(dc, LOGPIXELSX); + ReleaseDC(0, dc); + const Gdiplus::REAL fontSize = (Gdiplus::REAL)size * (96.0f / dpi); + + if (m_FontFamily) + { + m_Font = new Gdiplus::Font(m_FontFamily, fontSize, style); + if (m_Font->GetLastStatus() != Gdiplus::Ok) + { + delete m_Font; + m_Font = nullptr; + } + } + + if (!m_Font) + { + // Use default font ("Arial" or GenericSansSerif). + m_Font = new Gdiplus::Font(L"Arial", fontSize, style); + if (m_Font->GetLastStatus() != Gdiplus::Ok) + { + delete m_Font; + m_Font = nullptr; + } + } + } +} + +void TextFormatGDIP::SetTrimming(bool trim) +{ + if (trim) + { + m_StringFormat.SetTrimming(Gdiplus::StringTrimmingEllipsisCharacter); + m_StringFormat.SetFormatFlags(0x0); + } + else + { + m_StringFormat.SetTrimming(Gdiplus::StringTrimmingNone); + m_StringFormat.SetFormatFlags(Gdiplus::StringFormatFlagsNoClip | Gdiplus::StringFormatFlagsNoWrap); + } +} + +void TextFormatGDIP::SetHorizontalAlignment(HorizontalAlignment alignment) +{ + static_assert(Gdiplus::StringAlignmentNear == (int)HorizontalAlignment::Left, "Enum mismatch"); + static_assert(Gdiplus::StringAlignmentCenter == (int)HorizontalAlignment::Center, "Enum mismatch"); + static_assert(Gdiplus::StringAlignmentFar == (int)HorizontalAlignment::Right, "Enum mismatch"); + + __super::SetHorizontalAlignment(alignment); + m_StringFormat.SetAlignment((Gdiplus::StringAlignment)alignment); +} + +void TextFormatGDIP::SetVerticalAlignment(VerticalAlignment alignment) +{ + static_assert(Gdiplus::StringAlignmentNear == (int)VerticalAlignment::Top, "Enum mismatch"); + static_assert(Gdiplus::StringAlignmentCenter == (int)VerticalAlignment::Center, "Enum mismatch"); + static_assert(Gdiplus::StringAlignmentFar == (int)VerticalAlignment::Bottom, "Enum mismatch"); + + __super::SetVerticalAlignment(alignment); + m_StringFormat.SetLineAlignment((Gdiplus::StringAlignment)alignment); +} + +} // namespace Gfx \ No newline at end of file diff --git a/Common/Gfx/TextFormatGDIP.h b/Common/Gfx/TextFormatGDIP.h new file mode 100644 index 00000000..2d2536bd --- /dev/null +++ b/Common/Gfx/TextFormatGDIP.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2013 Birunthan Mohanathas + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef RM_GFX_TEXTFORMATGDI_H_ +#define RM_GFX_TEXTFORMATGDI_H_ + +#include "TextFormat.h" +#include + +namespace Gfx { + +class TextFormatGDIP : public TextFormat +{ +public: + TextFormatGDIP(); + virtual ~TextFormatGDIP(); + + virtual bool IsInitialized() { return m_Font != nullptr; } + virtual void SetProperties(const WCHAR* fontFamily, int size, bool bold, bool italic); + + virtual void SetTrimming(bool trim) override; + virtual void SetHorizontalAlignment(HorizontalAlignment alignment) override; + virtual void SetVerticalAlignment(VerticalAlignment alignment) override; + +private: + friend class CanvasGDIP; + + TextFormatGDIP(const TextFormatGDIP& other) {} + + void Dispose(); + + Gdiplus::Font* m_Font; + Gdiplus::FontFamily* m_FontFamily; + Gdiplus::StringFormat m_StringFormat; +}; + +} // namespace Gfx + +#endif \ No newline at end of file diff --git a/Common/Gfx/WICBitmapLockGDIP.cpp b/Common/Gfx/WICBitmapLockGDIP.cpp new file mode 100644 index 00000000..38deb5b2 --- /dev/null +++ b/Common/Gfx/WICBitmapLockGDIP.cpp @@ -0,0 +1,75 @@ +/* + Copyright (C) 2013 Birunthan Mohanathas + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "WICBitmapLockGDIP.h" +#include + +namespace Gfx { + +IFACEMETHODIMP WICBitmapLockGDIP::QueryInterface(REFIID riid, void** ppvObject) +{ + return E_NOTIMPL; +} + +IFACEMETHODIMP_(ULONG) WICBitmapLockGDIP::AddRef() +{ + ++m_RefCount; + return m_RefCount; +} + +IFACEMETHODIMP_(ULONG) WICBitmapLockGDIP::Release() +{ + --m_RefCount; + if (m_RefCount == 0) + { + delete this; + return 0; + } + + return m_RefCount; +} + +IFACEMETHODIMP WICBitmapLockGDIP::GetSize(UINT* puiWidth, UINT* puiHeight) +{ + *puiWidth = m_BitmapData.Width; + *puiHeight = m_BitmapData.Height; + return S_OK; +} + +IFACEMETHODIMP WICBitmapLockGDIP::GetStride(UINT* pcbStride) +{ + *pcbStride = m_BitmapData.Stride; + return S_OK; +} + +IFACEMETHODIMP WICBitmapLockGDIP::GetDataPointer(UINT* pcbBufferSize, BYTE** ppbData) +{ + assert(m_BitmapData.PixelFormat == PixelFormat32bppPARGB); + *pcbBufferSize = m_BitmapData.Stride * m_BitmapData.Height; + *ppbData = (BYTE*)m_BitmapData.Scan0; + return S_OK; +} + +IFACEMETHODIMP WICBitmapLockGDIP::GetPixelFormat(WICPixelFormatGUID* pPixelFormat) +{ + assert(m_BitmapData.PixelFormat == PixelFormat32bppPARGB); + *pPixelFormat = GUID_WICPixelFormat32bppPBGRA; + return S_OK; +} + +} // namespace Gfx \ No newline at end of file diff --git a/Common/Gfx/WICBitmapLockGDIP.h b/Common/Gfx/WICBitmapLockGDIP.h new file mode 100644 index 00000000..a2096b73 --- /dev/null +++ b/Common/Gfx/WICBitmapLockGDIP.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2013 Birunthan Mohanathas + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef RM_GFX_BITMAPLOCKGDI_H_ +#define RM_GFX_BITMAPLOCKGDI_H_ + +#include +#include +#include + +namespace Gfx { + +// Allows the creation of a shared ID2D1Bitmap using pixel data in a Gdiplus::Bitmap. It is +// assumed that this class is used only with 32bpp PARGB bitmaps and using a sigle thread. +class WICBitmapLockGDIP : public IWICBitmapLock +{ +public: + WICBitmapLockGDIP() : m_RefCount(0) {} + + // IUnknown + IFACEMETHOD(QueryInterface)(REFIID riid, void** ppvObject); + IFACEMETHOD_(ULONG, AddRef)(); + IFACEMETHOD_(ULONG, Release)(); + + // IWICBitmapLock + IFACEMETHOD(GetSize)(UINT* puiWidth, UINT* puiHeight); + IFACEMETHOD(GetStride)(UINT* pcbStride); + IFACEMETHOD(GetDataPointer)(UINT* pcbBufferSize, BYTE** ppbData); + IFACEMETHOD(GetPixelFormat)(WICPixelFormatGUID* pPixelFormat); + + Gdiplus::BitmapData* GetBitmapData() { return &m_BitmapData; } + +private: + Gdiplus::BitmapData m_BitmapData; + UINT m_RefCount; +}; + +} // namespace Gfx + +#endif \ No newline at end of file diff --git a/Library/Library.vcxproj b/Library/Library.vcxproj index 1189ad3e..7948e8d5 100644 --- a/Library/Library.vcxproj +++ b/Library/Library.vcxproj @@ -21,8 +21,8 @@ 4018;4090;4114;4267;4334;4351;4786;4800;4996 - comctl32.lib;Wininet.lib;UxTheme.lib;Winmm.lib;gdiplus.lib;Iphlpapi.lib;shlwapi.lib;Version.lib;%(AdditionalDependencies) - Winmm.dll;Version.dll + comctl32.lib;Wininet.lib;UxTheme.lib;Winmm.lib;gdiplus.lib;Iphlpapi.lib;shlwapi.lib;d2d1.lib;dwrite.lib;windowscodecs.lib;Version.lib;%(AdditionalDependencies) + Winmm.dll;Version.dll;d2d1.dll;dwrite.dll Exports.def @@ -33,8 +33,8 @@ 4018;4090;4114;4267;4334;4351;4786;4800;4996 - comctl32.lib;Wininet.lib;UxTheme.lib;Winmm.lib;gdiplus.lib;Iphlpapi.lib;shlwapi.lib;Version.lib;%(AdditionalDependencies) - Winmm.dll;Version.dll + comctl32.lib;Wininet.lib;UxTheme.lib;Winmm.lib;gdiplus.lib;Iphlpapi.lib;shlwapi.lib;d2d1.lib;dwrite.lib;windowscodecs.lib;Version.lib;%(AdditionalDependencies) + Winmm.dll;Version.dll;d2d1.dll;dwrite.dll Exports.def @@ -45,8 +45,8 @@ 4018;4090;4114;4267;4334;4351;4786;4800;4996 - comctl32.lib;Wininet.lib;UxTheme.lib;Winmm.lib;gdiplus.lib;Iphlpapi.lib;shlwapi.lib;Version.lib;%(AdditionalDependencies) - Winmm.dll;Version.dll + comctl32.lib;Wininet.lib;UxTheme.lib;Winmm.lib;gdiplus.lib;Iphlpapi.lib;shlwapi.lib;d2d1.lib;dwrite.lib;windowscodecs.lib;Version.lib;%(AdditionalDependencies) + Winmm.dll;Version.dll;d2d1.dll;dwrite.dll Exports.def @@ -57,14 +57,21 @@ 4018;4090;4114;4267;4334;4351;4786;4800;4996 - comctl32.lib;Wininet.lib;UxTheme.lib;Winmm.lib;gdiplus.lib;Iphlpapi.lib;shlwapi.lib;Version.lib;%(AdditionalDependencies) - Winmm.dll;Version.dll + comctl32.lib;Wininet.lib;UxTheme.lib;Winmm.lib;gdiplus.lib;Iphlpapi.lib;shlwapi.lib;d2d1.lib;dwrite.lib;windowscodecs.lib;Version.lib;%(AdditionalDependencies) + Winmm.dll;Version.dll;d2d1.dll;dwrite.dll Exports.def + + + + + + + @@ -275,6 +282,13 @@ + + + + + + + diff --git a/Library/Library.vcxproj.filters b/Library/Library.vcxproj.filters index 11b25381..4fb027b0 100644 --- a/Library/Library.vcxproj.filters +++ b/Library/Library.vcxproj.filters @@ -28,6 +28,9 @@ {3fcdd272-ad7a-4e06-a1bc-ff114498ccee} + + {26d9c191-5857-45c2-9e73-b0b88964728f} + @@ -339,6 +342,27 @@ Common + + Common\Gfx + + + Common\Gfx + + + Common\Gfx + + + Common\Gfx + + + Common\Gfx + + + Common\Gfx + + + Common\Gfx + @@ -584,6 +608,27 @@ Common + + Common\Gfx + + + Common\Gfx + + + Common\Gfx + + + Common\Gfx + + + Common\Gfx + + + Common\Gfx + + + Common\Gfx +