From f672446ebf8ad084b027f9b4acd29c723784c7a8 Mon Sep 17 00:00:00 2001 From: casey langen Date: Fri, 2 Dec 2016 01:12:49 -0800 Subject: [PATCH] Added a Win32 GDI visualizer. --- .gitignore | 2 + musikcube.sln | 7 + src/contrib/cddadecoder/CddaDataStream.cpp | 8 +- src/contrib/cddadecoder/cddadecoder.vcxproj | 4 +- .../win32gdivis/GdiVis-musikcube.vcxproj | 157 +++++++++ .../GdiVis-musikcube.vcxproj.filters | 22 ++ src/contrib/win32gdivis/GdiVis.cpp | 311 ++++++++++++++++++ src/contrib/win32gdivis/MemoryDC.cpp | 103 ++++++ src/contrib/win32gdivis/MemoryDC.h | 102 ++++++ 9 files changed, 710 insertions(+), 6 deletions(-) create mode 100644 src/contrib/win32gdivis/GdiVis-musikcube.vcxproj create mode 100644 src/contrib/win32gdivis/GdiVis-musikcube.vcxproj.filters create mode 100644 src/contrib/win32gdivis/GdiVis.cpp create mode 100644 src/contrib/win32gdivis/MemoryDC.cpp create mode 100644 src/contrib/win32gdivis/MemoryDC.h diff --git a/.gitignore b/.gitignore index ce3b7e235..eb69b2036 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ **/Makefile **/cmake_install.cmake **/install_manifest.txt +**/Release +**/Debug .vs .vscode bin diff --git a/musikcube.sln b/musikcube.sln index a1c5337ba..66ef73760 100644 --- a/musikcube.sln +++ b/musikcube.sln @@ -4,6 +4,7 @@ VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "musikbox", "src\musikbox\musikbox.vcxproj", "{C7102EB1-7311-4B36-A7FF-89DD7F077FF9}" ProjectSection(ProjectDependencies) = postProject + {68AA481E-3CCE-440F-8CCE-69F1B371C89D} = {68AA481E-3CCE-440F-8CCE-69F1B371C89D} {3E30064E-B9C4-4690-8AC2-2C694176A319} = {3E30064E-B9C4-4690-8AC2-2C694176A319} {54764854-5A73-4329-9BAD-9AF22C72D9E2} = {54764854-5A73-4329-9BAD-9AF22C72D9E2} {465EF178-91C1-4068-BE1D-F9616ECCB6DE} = {465EF178-91C1-4068-BE1D-F9616ECCB6DE} @@ -34,6 +35,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "m4adecoder", "src\contrib\m EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win32globalhotkeys", "src\contrib\win32globalhotkeys\win32globalhotkeys.vcxproj", "{3E30064E-B9C4-4690-8AC2-2C694176A319}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win32gdivis", "src\contrib\win32gdivis\GdiVis-musikcube.vcxproj", "{68AA481E-3CCE-440F-8CCE-69F1B371C89D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -84,6 +87,10 @@ Global {3E30064E-B9C4-4690-8AC2-2C694176A319}.Debug|Win32.Build.0 = Debug|Win32 {3E30064E-B9C4-4690-8AC2-2C694176A319}.Release|Win32.ActiveCfg = Release|Win32 {3E30064E-B9C4-4690-8AC2-2C694176A319}.Release|Win32.Build.0 = Release|Win32 + {68AA481E-3CCE-440F-8CCE-69F1B371C89D}.Debug|Win32.ActiveCfg = Debug|Win32 + {68AA481E-3CCE-440F-8CCE-69F1B371C89D}.Debug|Win32.Build.0 = Debug|Win32 + {68AA481E-3CCE-440F-8CCE-69F1B371C89D}.Release|Win32.ActiveCfg = Release|Win32 + {68AA481E-3CCE-440F-8CCE-69F1B371C89D}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/contrib/cddadecoder/CddaDataStream.cpp b/src/contrib/cddadecoder/CddaDataStream.cpp index 919bded4d..243474eba 100755 --- a/src/contrib/cddadecoder/CddaDataStream.cpp +++ b/src/contrib/cddadecoder/CddaDataStream.cpp @@ -36,16 +36,16 @@ #include "CddaDataStream.h" #include #include -#include +#include #define RAW_SECTOR_SIZE 2352 #define MSF2UINT(hgs) ((hgs[1]*4500) + (hgs[2]*75) + (hgs[3])) static CddaDataStream* active = NULL; -static boost::mutex activeMutex; +static std::mutex activeMutex; static void setActive(CddaDataStream* stream) { - boost::mutex::scoped_lock lock(activeMutex); + std::unique_lock lock(activeMutex); if (active != NULL) { active->Close(); @@ -56,7 +56,7 @@ static void setActive(CddaDataStream* stream) { } static void resetIfActive(CddaDataStream* stream) { - boost::mutex::scoped_lock lock(activeMutex); + std::unique_lock lock(activeMutex); if (stream == active) { active = NULL; diff --git a/src/contrib/cddadecoder/cddadecoder.vcxproj b/src/contrib/cddadecoder/cddadecoder.vcxproj index 06976df32..b8a103330 100755 --- a/src/contrib/cddadecoder/cddadecoder.vcxproj +++ b/src/contrib/cddadecoder/cddadecoder.vcxproj @@ -54,7 +54,7 @@ Disabled - ../../;../../3rdparty/include;../../../../boost_1_60_0;%(AdditionalIncludeDirectories) + ../../;../../3rdparty/include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) true EnableFastChecks @@ -76,7 +76,7 @@ - ../../;../../3rdparty/include;../../../../boost_1_60_0;%(AdditionalIncludeDirectories) + ../../;../../3rdparty/include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) MultiThreaded diff --git a/src/contrib/win32gdivis/GdiVis-musikcube.vcxproj b/src/contrib/win32gdivis/GdiVis-musikcube.vcxproj new file mode 100644 index 000000000..9a81f7852 --- /dev/null +++ b/src/contrib/win32gdivis/GdiVis-musikcube.vcxproj @@ -0,0 +1,157 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + + + {68AA481E-3CCE-440F-8CCE-69F1B371C89D} + 8.1 + win32gdivis + + + + DynamicLibrary + v140 + false + Unicode + + + DynamicLibrary + v140 + false + Unicode + + + + + + + + + + + + + + + $(SolutionDir)bin\release\ + .\Release\ + false + + + $(SolutionDir)bin\debug\ + .\Debug\ + true + + + + MultiThreaded + Default + true + true + MaxSpeed + true + Level3 + .\;..\..\;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + .\Release\ + .\Release\projectMvis.pch + .\Release\ + .\Release\ + + + true + NDEBUG;%(PreprocessorDefinitions) + .\Release\projectMvis.tlb + true + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Release\projectMvis.bsc + + + true + Windows + $(SolutionDir)bin\release\win32gdivis.dll + $(SolutionDir)bin\release;%(AdditionalLibraryDirectories) + LIBCMT.LIB;version.lib;winmm.lib;Imm32.lib;shlwapi.lib;%(AdditionalDependencies) + + + xcopy $(TargetPath) $(SolutionDir)\bin\release\plugins\ /Y + + + + + + + MultiThreadedDebug + Default + Disabled + true + Level3 + true + EditAndContinue + .\;..\..\;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;DEBUG;%(PreprocessorDefinitions) + .\Debug\ + .\Debug\projectMvis.pch + .\Debug\ + .\Debug\ + EnableFastChecks + + + true + _DEBUG;%(PreprocessorDefinitions) + .\Debug\projectMvis.tlb + true + Win32 + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\projectMvis.bsc + + + true + true + Windows + $(SolutionDir)bin\debug\win32gdivis.dll + $(SolutionDir)bin\debug;%(AdditionalLibraryDirectories) + LIBCMTD.LIB;%(AdditionalDependencies) + + + + + xcopy $(TargetPath) $(SolutionDir)\bin\debug\plugins\ /Y + + + + + + + + \ No newline at end of file diff --git a/src/contrib/win32gdivis/GdiVis-musikcube.vcxproj.filters b/src/contrib/win32gdivis/GdiVis-musikcube.vcxproj.filters new file mode 100644 index 000000000..ad8c63fd2 --- /dev/null +++ b/src/contrib/win32gdivis/GdiVis-musikcube.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4af6aad0-9c71-4dc2-8343-19c467346884} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + + + Source Files + + + Source Files + + + + + Source Files + + + \ No newline at end of file diff --git a/src/contrib/win32gdivis/GdiVis.cpp b/src/contrib/win32gdivis/GdiVis.cpp new file mode 100644 index 000000000..5a200bac1 --- /dev/null +++ b/src/contrib/win32gdivis/GdiVis.cpp @@ -0,0 +1,311 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "MemoryDC.h" + +#define DLL_EXPORT __declspec(dllexport) +#define MAX_FPS 10LL +#define MILLIS_PER_FRAME (1000LL / MAX_FPS) +#define WINDOW_CLASS_NAME L"GdiVis-musikcube" +#define DEFAULT_WIDTH 550 +#define DEFAULT_HEIGHT 120 +#define TEXTURE_WIDTH 90 +#define TEXTURE_HEIGHT 80 + +using namespace std::chrono; + +static std::atomic quit(false); +static std::atomic thread(false); +static std::mutex pcmMutex, threadMutex; +static std::condition_variable threadCondition; +static HINSTANCE instance; +static HBITMAP texture = nullptr; +static COLORREF *textureBits = nullptr; +static HBRUSH fg = CreateSolidBrush(RGB(255, 0, 0)); +static COLORREF bg = RGB(24, 24, 24); + +static int spectrumSize = 0; +static float* spectrumIn = nullptr; +static float* spectrumOut = nullptr; + +static void renderFrame(HWND hwnd) { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + RECT& r = ps.rcPaint; + + { + /* copy to the output buffer so we can write the input buffer + immediately if we want to. */ + std::unique_lock lock(pcmMutex); + memcpy(::spectrumOut, ::spectrumIn, ::spectrumSize * sizeof(float)); + } + + if (::spectrumOut && ::spectrumSize) { + + win32cpp::MemoryDC memDc(hdc, ps.rcPaint); + + for (int n = 0; n < TEXTURE_WIDTH * TEXTURE_HEIGHT - 1; n++) { + textureBits[n] = bg; + } + + RECT rect; + + int barHeight; + const int barWidth = 7; + const int barY = 100; + + int x = 20; + int n = spectrumSize / 4; + for (int bar = 0; bar < n; bar++) { + barHeight = 4 + (int)(spectrumOut[bar]); + rect.left = x; + rect.right = rect.left + barWidth; + + int dstY = barY - barHeight; + for (int y = barY; y > dstY; y-=2) { + rect.top = y; + rect.bottom = rect.top - 1; + FillRect(memDc, &rect, fg); + } + + x += barWidth + 1; + } + } + + EndPaint(hwnd, &ps); +} + +LRESULT CALLBACK staticWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch (uMsg) { + case WM_CLOSE: { + DestroyWindow(hwnd); + UnregisterClass(WINDOW_CLASS_NAME, NULL); + return 0; + } + + case WM_DESTROY: { + PostQuitMessage(0); + break; + + case WM_CHAR: + if (wParam == 0x1B) { /* esc */ + PostQuitMessage(0); + } + break; + + case WM_PAINT: + renderFrame(hwnd); + break; + } + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +static void threadProc() { +#ifdef DEBUG + _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); + _CrtSetBreakAlloc(60); +#endif + + // Register the windows class + WNDCLASSW wndClass; + wndClass.style = CS_DBLCLKS; + wndClass.lpfnWndProc = staticWndProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = 0; + wndClass.hInstance = instance; + wndClass.hIcon = NULL; + wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndClass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH); + wndClass.lpszMenuName = NULL; + wndClass.lpszClassName = WINDOW_CLASS_NAME; + + if (!RegisterClass(&wndClass)) { + DWORD dwError = GetLastError(); + if (dwError != ERROR_CLASS_ALREADY_EXISTS) { + return; + } + } + + int windowWidth = DEFAULT_WIDTH; + int windowHeight = DEFAULT_HEIGHT; + + RECT rc; + SetRect(&rc, 0, 0, windowWidth, windowHeight); + AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, false); + + // Create the render window + HWND hwnd = CreateWindow( + WINDOW_CLASS_NAME, + L"GdiVis-musikcube", + WS_EX_TOOLWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + (rc.right - rc.left), + (rc.bottom - rc.top), + 0, + NULL, + instance, + 0); + + if (!hwnd) { + DWORD dwError = GetLastError(); + return; + } + + BITMAPINFO bminfo; + ZeroMemory(&bminfo, sizeof(BITMAPINFO)); + bminfo.bmiHeader.biWidth = TEXTURE_WIDTH; + bminfo.bmiHeader.biHeight = TEXTURE_HEIGHT; + bminfo.bmiHeader.biPlanes = 1; + bminfo.bmiHeader.biBitCount = 32; + bminfo.bmiHeader.biCompression = BI_RGB; + bminfo.bmiHeader.biXPelsPerMeter = 0; + bminfo.bmiHeader.biYPelsPerMeter = 0; + bminfo.bmiHeader.biClrUsed = 0; + bminfo.bmiHeader.biClrImportant = 0; + bminfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bminfo.bmiHeader.biSizeImage = TEXTURE_WIDTH * TEXTURE_HEIGHT * 4; + + texture = CreateDIBSection(NULL, &bminfo, DIB_RGB_COLORS, (void **)&textureBits, NULL, NULL); + + ShowWindow(hwnd, SW_SHOW); + + MSG msg; + msg.message = WM_NULL; + + PeekMessage(&msg, NULL, 0U, 0U, PM_NOREMOVE); + while (WM_QUIT != msg.message) { + if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE) != 0) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + else { + if (quit) { + PostQuitMessage(0); + } + else { + DWORD start = GetTickCount(); + InvalidateRect(hwnd, 0, false); + UpdateWindow(hwnd); + DWORD delta = (GetTickCount() - start); + if (MILLIS_PER_FRAME > delta) { + Sleep(MILLIS_PER_FRAME - delta); + } + } + } + } + + DeleteObject(texture); + texture = nullptr; + textureBits = nullptr; + + thread.store(false); + + { + std::unique_lock lock(threadMutex); + threadCondition.notify_all(); + } +} + +#ifdef COMPILE_AS_EXE + int main(int argc, char *argv[]) { + SetProjectMDataDirectory(util::getModuleDirectory()); + +#ifndef WIN32 + std::thread background(pipeReadProc); + background.detach(); +#endif + + quit.store(false); + thread.store(true); + windowProc(); + + return 0; + } +#else + #ifdef WIN32 + BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpReserved) { + instance = hModule; + return true; + } + #endif +#endif + +#ifdef WIN32 + class Visualizer : public musik::core::sdk::ISpectrumVisualizer { + public: + virtual const char* Name() { + return "GdiVis"; + }; + + virtual const char* Version() { + return "0.1.0"; + }; + + virtual const char* Author() { + return "clangen"; + }; + + virtual void Destroy() { + this->Hide(); + delete this; + } + + virtual void Write(float *spectrum, int size) { + std::unique_lock lock(pcmMutex); + + if (::spectrumSize != size) { + delete ::spectrumIn; + delete ::spectrumOut; + ::spectrumSize = size; + ::spectrumIn = new float[size]; + ::spectrumOut = new float[size]; + } + + memcpy(::spectrumIn, spectrum, size * sizeof(float)); + } + + virtual void Show() { + if (!Visible()) { + quit.store(false); + thread.store(true); + std::thread background(threadProc); + background.detach(); + } + } + + virtual void Hide() { + if (Visible()) { + quit.store(true); + + while (thread.load()) { + std::unique_lock lock(threadMutex); + threadCondition.wait(lock); + } + } + } + + virtual bool Visible() { + return thread.load(); + } + }; + + extern "C" DLL_EXPORT musik::core::sdk::IPlugin* GetPlugin() { + return new Visualizer(); + } + + extern "C" DLL_EXPORT musik::core::sdk::ISpectrumVisualizer* GetSpectrumVisualizer() { + return new Visualizer(); + } +#endif diff --git a/src/contrib/win32gdivis/MemoryDC.cpp b/src/contrib/win32gdivis/MemoryDC.cpp new file mode 100644 index 000000000..1c2f3268b --- /dev/null +++ b/src/contrib/win32gdivis/MemoryDC.cpp @@ -0,0 +1,103 @@ +////////////////////////////////////////////////////////////////////////////// +// +// License Agreement: +// +// The following are Copyright � 2007, Casey Langen +// +// Sources and Binaries of: win32cpp +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + +#include "MemoryDC.h" + +////////////////////////////////////////////////////////////////////////////// + +using namespace win32cpp; + +////////////////////////////////////////////////////////////////////////////// +// MemoryDC +////////////////////////////////////////////////////////////////////////////// + +///\brief +///Constructor. +/// +///\param hdc +///The destination HDC. The final contents of the memory buffer will +///be copied here upon destruction. +/// +///\param rect +///The Rectangle that represents the drawable area of the HDC. +/*ctor*/ MemoryDC::MemoryDC(HDC hdc, const RECT& rect) +: rectIsValid(false) +, screenDC(hdc) +, memoryBitmap(NULL) +, memoryDC(NULL) +, clientRect(rect) +{ + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; + + this->memoryDC = ::CreateCompatibleDC(this->screenDC); + // + this->memoryBitmap = ::CreateCompatibleBitmap(this->screenDC, width, height); + this->oldObject = ::SelectObject(this->memoryDC, this->memoryBitmap); + + this->rectIsValid = ((width > 0) && (height > 0)); +} + +/*dtor*/ MemoryDC::~MemoryDC() +{ + if (this->rectIsValid) + { + ::BitBlt( + this->screenDC, + this->clientRect.left, + this->clientRect.top, + this->clientRect.right - this->clientRect.left, + this->clientRect.bottom - this->clientRect.top, + this->memoryDC, + 0, + 0, + SRCCOPY); + } + + ::SelectObject(this->memoryDC, this->oldObject); + + ::DeleteObject(this->memoryBitmap); + ::DeleteObject(this->memoryDC); +} + +///\brief +///Returns a handle to the offscreen device context. +MemoryDC::operator HDC() +{ + return this->memoryDC; +} \ No newline at end of file diff --git a/src/contrib/win32gdivis/MemoryDC.h b/src/contrib/win32gdivis/MemoryDC.h new file mode 100644 index 000000000..1bbec1f0d --- /dev/null +++ b/src/contrib/win32gdivis/MemoryDC.h @@ -0,0 +1,102 @@ +////////////////////////////////////////////////////////////////////////////// +// +// License Agreement: +// +// The following are Copyright � 2007, Casey Langen +// +// Sources and Binaries of: win32cpp +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include + +////////////////////////////////////////////////////////////////////////////// + +namespace win32cpp { + +////////////////////////////////////////////////////////////////////////////// + +///\brief +///A memory device context. MemoryDC is used internally by various classes, +///including Window, for flicker free drawing. +/// +///When performing graphics operations on a Window's DC, changes are drawn +///directly to screen; this leads to flickering. MemoryDC creates an offscreen +///buffer that "accumulates" changes, which are copied to a desination DC +///when all drawing has finished. +/// +///MemoryDC is constructed with an HDC and a Rect as parameters, and provides +///an implicit HDC cast operator that returns a handle to the offscreen buffer. +///This means that regular Win32 drawing routines, such as DrawLine, FillRect, +///etc, can transparently use a MemoryDC as if it were a regular HDC. +/// +///When a MemoryDC's destructor is called the contents of the offscren buffer +///are automatically copied to to the HDC it was constructed with, resulting +///in flicker-free drawing. +/// +///\code +///PAINTSTRUCT paintStruct; +///HDC hdc = ::BeginPaint(this->Handle(), &paintStruct); +///{ +/// MemoryDC memDC(hdc, paintStruct.rcPaint); +/// +/// //... +/// //draw to memDC as if you were drawing to hdc +/// //... +/// +///} // when the MemoryDC destructor is called, the contents will be copied to hdc +///::EndPaint(this->Handle(), &paintStruct); +///\endcode +/// +///\see +///RedrawLock +class MemoryDC +{ +public: // constructors, destructor + /*ctor*/ MemoryDC(HDC hdc, const RECT& rect); + /*dtor*/ ~MemoryDC(); + +public: // operators + operator HDC(); + +private: // instance data + HBITMAP memoryBitmap; + HDC memoryDC, screenDC; + HANDLE oldObject; + RECT clientRect; + bool rectIsValid; +}; + +////////////////////////////////////////////////////////////////////////////// + +} // win32cpp \ No newline at end of file