diff --git a/Common/Gfx/CanvasD2D.cpp b/Common/Gfx/CanvasD2D.cpp index 332f40c1..ab80c4e2 100644 --- a/Common/Gfx/CanvasD2D.cpp +++ b/Common/Gfx/CanvasD2D.cpp @@ -59,12 +59,10 @@ IWICImagingFactory* CanvasD2D::c_WIC = nullptr; CanvasD2D::CanvasD2D() : Canvas(), m_Target(), - m_InteropTarget(), m_Bitmap(), m_GdipGraphics(), m_GdipBitmap(), - m_BeginDrawCalled(false), - m_TargetBeginDrawCalled(false) + m_TextAntiAliasing(false) { Initialize(); } @@ -122,9 +120,7 @@ void CanvasD2D::Finalize() void CanvasD2D::DiscardDeviceResources() { - SafeRelease(&m_InteropTarget); SafeRelease(&m_Target); - SafeRelease(&m_Bitmap); delete m_GdipGraphics; m_GdipGraphics = nullptr; @@ -139,6 +135,26 @@ void CanvasD2D::Resize(int w, int h) DiscardDeviceResources(); + m_Bitmap.Resize(w, h); + + m_GdipBitmap = new Gdiplus::Bitmap(w, h, w * 4, PixelFormat32bppPARGB, m_Bitmap.GetData()); + m_GdipGraphics = new Gdiplus::Graphics(m_GdipBitmap); +} + +bool CanvasD2D::BeginDraw() +{ + return true; +} + +void CanvasD2D::EndDraw() +{ + EndTargetDraw(); +} + +bool CanvasD2D::BeginTargetDraw() +{ + if (m_Target) return true; + const D2D1_PIXEL_FORMAT format = D2D1::PixelFormat( DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED); @@ -150,115 +166,57 @@ void CanvasD2D::Resize(int w, int h) 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); + // A new Direct2D render target must be created for each sequence of Direct2D draw operations + // since we use GDI+ to render to the same pixel data. Without creating a new render target + // each time, it has been found that Direct2D may overwrite the draws by GDI+ since it is + // unaware of the changes made by GDI+. By creating a new render target and then releasing it + // before the next GDI+ draw operations, we ensure that the pixel data result is as expected + // Once GDI+ drawing is no longer needed, we change to recreate the render target only when the + // bitmap size is changed. + HRESULT hr = c_D2D->CreateWicBitmapRenderTarget(&m_Bitmap, properties, &m_Target); if (SUCCEEDED(hr)) { - hr = m_Target->QueryInterface(&m_InteropTarget); // Always succeeds + SetTextAntiAliasing(m_TextAntiAliasing); - // 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(); + return true; } + + return false; } void CanvasD2D::EndTargetDraw() { - if (m_TargetBeginDrawCalled) + if (m_Target) { - m_TargetBeginDrawCalled = false; - HRESULT hr = m_Target->EndDraw(); - if (hr == D2DERR_RECREATE_TARGET) - { - DiscardDeviceResources(); + m_Target->EndDraw(); - // Attempt to recreate target. - Resize(m_W, m_H); - } + SafeRelease(&m_Target); } } 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; - } - + EndTargetDraw(); return *m_GdipGraphics; } void CanvasD2D::EndGdiplusContext() { - // See BeginGdiplusContext(). - m_TargetBeginDrawCalled = false; } HDC CanvasD2D::GetDC() { - BeginTargetDraw(); + EndTargetDraw(); - HDC dcMemory = nullptr; - m_InteropTarget->GetDC(D2D1_DC_INITIALIZE_MODE_COPY, &dcMemory); + HDC dcMemory = CreateCompatibleDC(nullptr); + SelectObject(dcMemory, m_Bitmap.GetHandle()); return dcMemory; } void CanvasD2D::ReleaseDC(HDC dc) { - // Assume that the DC was not modified. - RECT r = {0, 0, 0, 0}; - m_InteropTarget->ReleaseDC(&r); + DeleteDC(dc); } bool CanvasD2D::IsTransparentPixel(int x, int y) @@ -267,21 +225,11 @@ bool CanvasD2D::IsTransparentPixel(int x, int y) 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)) + DWORD* data = (DWORD*)m_Bitmap.GetData(); + if (data) { - 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(); + DWORD pixel = data[y * m_W + x]; // Top-down DIB. + transparent = (pixel & 0xFF000000) != 0; } return transparent; @@ -299,19 +247,25 @@ void CanvasD2D::SetAntiAliasing(bool enable) 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); + m_TextAntiAliasing = enable; + + if (m_Target) + { + m_Target->SetTextAntialiasMode( + m_TextAntiAliasing ? D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE : D2D1_TEXT_ANTIALIAS_MODE_ALIASED); + } } void CanvasD2D::Clear(const Gdiplus::Color& color) { - BeginTargetDraw(); + if (!BeginTargetDraw()) return; + m_Target->Clear(ToColorF(color)); } void CanvasD2D::DrawTextW(const WCHAR* str, UINT strLen, const TextFormat& format, Gdiplus::RectF& rect, const Gdiplus::SolidBrush& brush) { - BeginTargetDraw(); + if (!BeginTargetDraw()) return; Gdiplus::Color color; brush.GetColor(&color); @@ -391,10 +345,11 @@ bool CanvasD2D::MeasureTextLinesW(const WCHAR* str, UINT strLen, const TextForma void CanvasD2D::DrawBitmap(Gdiplus::Bitmap* bitmap, const Gdiplus::Rect& dstRect, const Gdiplus::Rect& srcRect) { + if (!BeginTargetDraw()) return; + // 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()); @@ -406,12 +361,9 @@ void CanvasD2D::DrawBitmap(Gdiplus::Bitmap* bitmap, const Gdiplus::Rect& dstRect 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(); } @@ -420,15 +372,12 @@ void CanvasD2D::DrawBitmap(Gdiplus::Bitmap* bitmap, const Gdiplus::Rect& dstRect bitmap->UnlockBits(bitmapLock->GetBitmapData()); } - if (!draw) - { - delete bitmapLock; - } + bitmapLock->Release(); } void CanvasD2D::FillRectangle(Gdiplus::Rect& rect, const Gdiplus::SolidBrush& brush) { - BeginTargetDraw(); + if (!BeginTargetDraw()) return; Gdiplus::Color color; brush.GetColor(&color); diff --git a/Common/Gfx/CanvasD2D.h b/Common/Gfx/CanvasD2D.h index 84da9f3d..a4ae4dfb 100644 --- a/Common/Gfx/CanvasD2D.h +++ b/Common/Gfx/CanvasD2D.h @@ -21,6 +21,7 @@ #include "Canvas.h" #include "TextFormatD2D.h" +#include "WICBitmapDIB.h" #include #include #include @@ -75,24 +76,17 @@ private: void DiscardDeviceResources(); - void BeginTargetDraw(); + bool BeginTargetDraw(); void EndTargetDraw(); ID2D1RenderTarget* m_Target; - ID2D1GdiInteropRenderTarget* m_InteropTarget; - IWICBitmap* m_Bitmap; + WICBitmapDIB 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; + bool m_TextAntiAliasing; static UINT c_Instances; static ID2D1Factory* c_D2D; diff --git a/Common/Gfx/WICBitmapDIB.cpp b/Common/Gfx/WICBitmapDIB.cpp new file mode 100644 index 00000000..d92d8194 --- /dev/null +++ b/Common/Gfx/WICBitmapDIB.cpp @@ -0,0 +1,134 @@ +/* + 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 "WICBitmapDIB.h" +#include "WICBitmapLockDIB.h" +#include + +namespace Gfx { + +WICBitmapDIB::WICBitmapDIB() : + m_DIBSectionBuffer(), + m_DIBSectionBufferPixels(), + m_W(0), + m_H(0) +{ +} + +WICBitmapDIB::~WICBitmapDIB() +{ + if (m_DIBSectionBuffer) + { + DeleteObject(m_DIBSectionBuffer); + m_DIBSectionBufferPixels = nullptr; + } +} + +void WICBitmapDIB::Resize(UINT w, UINT h) +{ + if (m_DIBSectionBuffer) + { + DeleteObject(m_DIBSectionBuffer); + m_DIBSectionBufferPixels = nullptr; + } + + m_W = w; + m_H = h; + + BITMAPV4HEADER bh = {sizeof(BITMAPV4HEADER)}; + bh.bV4Width = (LONG)m_W; + bh.bV4Height = -(LONG)m_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); + + assert(m_DIBSectionBufferPixels); +} + +IFACEMETHODIMP WICBitmapDIB::QueryInterface(REFIID riid, void** ppvObject) +{ + return E_NOTIMPL; +} + +IFACEMETHODIMP_(ULONG) WICBitmapDIB::AddRef() +{ + return 0; +} + +IFACEMETHODIMP_(ULONG) WICBitmapDIB::Release() +{ + return 0; +} + +IFACEMETHODIMP WICBitmapDIB::GetSize(UINT* puiWidth, UINT* puiHeight) +{ + if (puiWidth) *puiWidth = m_W; + if (puiHeight) *puiHeight = m_H; + return S_OK; +} + +IFACEMETHODIMP WICBitmapDIB::GetPixelFormat(WICPixelFormatGUID* pPixelFormat) +{ + *pPixelFormat = GUID_WICPixelFormat32bppPBGRA; + return S_OK; +} + +IFACEMETHODIMP WICBitmapDIB::GetResolution(double* pDpiX, double* pDpiY) +{ + return E_NOTIMPL; +} + +IFACEMETHODIMP WICBitmapDIB::CopyPalette(IWICPalette* pIPalette) +{ + return E_NOTIMPL; +} + +IFACEMETHODIMP WICBitmapDIB::CopyPixels(const WICRect* prc, UINT cbStride, UINT cbBufferSize, BYTE* pbBuffer) +{ + return E_NOTIMPL; +} + +IFACEMETHODIMP WICBitmapDIB::Lock(const WICRect* prcLock, DWORD flags, IWICBitmapLock** ppILock) +{ + if (ppILock) *ppILock = (IWICBitmapLock*)new WICBitmapLockDIB(this, prcLock); + return S_OK; +} + +IFACEMETHODIMP WICBitmapDIB::SetPalette(IWICPalette* pIPalette) +{ + return E_NOTIMPL; +} + +IFACEMETHODIMP WICBitmapDIB::SetResolution(double dpiX, double dpiY) +{ + return E_NOTIMPL; +} + +} // namespace Gfx \ No newline at end of file diff --git a/Common/Gfx/WICBitmapDIB.h b/Common/Gfx/WICBitmapDIB.h new file mode 100644 index 00000000..1afc44ab --- /dev/null +++ b/Common/Gfx/WICBitmapDIB.h @@ -0,0 +1,73 @@ +/* + 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_WICBITMAPDIB_H_ +#define RM_GFX_WICBITMAPDIB_H_ + +#include +#include +#include + +namespace Gfx { + +// Allows the use of a DIB section (HBITMAP) in Direct2D as a WIC bitmap. It is assumed that this +// class is used only with 32bpp PARGB bitmaps and using a sigle thread. +// +// This class does not follow the COM reference count model. RTTI is used instead. This class +// implements only the bare essentials in order to use a DIB section as a Direct2D render target. +class WICBitmapDIB : public IWICBitmap +{ +public: + WICBitmapDIB(); + ~WICBitmapDIB(); + + void Resize(UINT w, UINT h); + + HBITMAP GetHandle() const { return m_DIBSectionBuffer; } + BYTE* GetData() const { return (BYTE*)m_DIBSectionBufferPixels; } + + // IUnknown + IFACEMETHOD(QueryInterface)(REFIID riid, void** ppvObject); + IFACEMETHOD_(ULONG, AddRef)(); + IFACEMETHOD_(ULONG, Release)(); + + // IWICBitmapSource + IFACEMETHOD(GetSize)(UINT* puiWidth, UINT* puiHeight); + IFACEMETHOD(GetPixelFormat)(WICPixelFormatGUID* pPixelFormat); + IFACEMETHOD(GetResolution)(double* pDpiX, double* pDpiY); + IFACEMETHOD(CopyPalette)(IWICPalette* pIPalette); + IFACEMETHOD(CopyPixels)(const WICRect* prc, UINT cbStride, UINT cbBufferSize, BYTE* pbBuffer); + + // IWICBitmap + IFACEMETHOD(Lock)(const WICRect* prcLock, DWORD flags, IWICBitmapLock** ppILock); + IFACEMETHOD(SetPalette)(IWICPalette* pIPalette); + IFACEMETHOD(SetResolution)(double dpiX, double dpiY); + +private: + friend class WICBitmapLockDIB; + + HBITMAP m_DIBSectionBuffer; + LPDWORD m_DIBSectionBufferPixels; + UINT m_W; + UINT m_H; +}; + + +} // namespace Gfx + +#endif \ No newline at end of file diff --git a/Common/Gfx/WICBitmapLockDIB.cpp b/Common/Gfx/WICBitmapLockDIB.cpp new file mode 100644 index 00000000..232c1f34 --- /dev/null +++ b/Common/Gfx/WICBitmapLockDIB.cpp @@ -0,0 +1,91 @@ +/* + 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 "WICBitmapLockDIB.h" +#include +#include "../../Library/Litestep.h" + +namespace Gfx { + +WICBitmapLockDIB::WICBitmapLockDIB(WICBitmapDIB* bitmap, const WICRect* lockRect) : + m_Bitmap(bitmap), + m_Rect(lockRect), + m_RefCount(1) +{ +} + +WICBitmapLockDIB::~WICBitmapLockDIB() +{ +} + +IFACEMETHODIMP WICBitmapLockDIB::QueryInterface(REFIID riid, void** ppvObject) +{ + return E_NOTIMPL; +} + +IFACEMETHODIMP_(ULONG) WICBitmapLockDIB::AddRef() +{ + ++m_RefCount; + return m_RefCount; +} + +IFACEMETHODIMP_(ULONG) WICBitmapLockDIB::Release() +{ + --m_RefCount; + if (m_RefCount == 0) + { + delete this; + return 0; + } + + return m_RefCount; +} + +IFACEMETHODIMP WICBitmapLockDIB::GetSize(UINT* puiWidth, UINT* puiHeight) +{ + return m_Bitmap->GetSize(puiWidth, puiHeight); +} + +IFACEMETHODIMP WICBitmapLockDIB::GetStride(UINT* pcbStride) +{ + UINT width = 0; + m_Bitmap->GetSize(&width, nullptr); + + if (pcbStride) *pcbStride = (width * 32 + 31) / 32 * 4; + + return S_OK; +} + +IFACEMETHODIMP WICBitmapLockDIB::GetDataPointer(UINT* pcbBufferSize, BYTE** ppbData) +{ + UINT stride = 0; + GetStride(&stride); + + if (pcbBufferSize) *pcbBufferSize = stride * m_Rect->Height; + if (ppbData) *ppbData = (BYTE*)&m_Bitmap->m_DIBSectionBufferPixels[m_Rect->Y * m_Rect->Width + m_Rect->X]; + + return S_OK; +} + + +IFACEMETHODIMP WICBitmapLockDIB::GetPixelFormat(WICPixelFormatGUID* pPixelFormat) +{ + return m_Bitmap->GetPixelFormat(pPixelFormat); +} + +} // namespace Gfx \ No newline at end of file diff --git a/Common/Gfx/WICBitmapLockDIB.h b/Common/Gfx/WICBitmapLockDIB.h new file mode 100644 index 00000000..24130d49 --- /dev/null +++ b/Common/Gfx/WICBitmapLockDIB.h @@ -0,0 +1,59 @@ +/* + 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_WICBITMAPLOCKDIB_H_ +#define RM_GFX_WICBITMAPLOCKDIB_H_ + +#include +#include +#include +#include "WICBitmapDIB.h" + +namespace Gfx { + +// Implements the IWICBitmapLock interface for use with WICBitmapDIB. It is assumed that this +// class is used only with 32bpp PARGB bitmaps and using a sigle thread. +class WICBitmapLockDIB : public IWICBitmapLock +{ +public: + WICBitmapLockDIB(WICBitmapDIB* bitmap, const WICRect* lockRect); + virtual ~WICBitmapLockDIB(); + + void Resize(UINT w, UINT h); + + // 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); + +private: + WICBitmapDIB* m_Bitmap; + const WICRect* m_Rect; + UINT m_RefCount; +}; + + +} // namespace Gfx + +#endif \ No newline at end of file diff --git a/Library/Library.vcxproj b/Library/Library.vcxproj index 7948e8d5..4330307e 100644 --- a/Library/Library.vcxproj +++ b/Library/Library.vcxproj @@ -71,6 +71,8 @@ + + @@ -288,6 +290,8 @@ + + diff --git a/Library/Library.vcxproj.filters b/Library/Library.vcxproj.filters index 4fb027b0..47ca06ab 100644 --- a/Library/Library.vcxproj.filters +++ b/Library/Library.vcxproj.filters @@ -363,6 +363,12 @@ Common\Gfx + + Common\Gfx + + + Common\Gfx + @@ -629,6 +635,12 @@ Common\Gfx + + Common\Gfx + + + Common\Gfx +