Added a Win32 GDI visualizer.

This commit is contained in:
casey langen 2016-12-02 01:12:49 -08:00
parent 02282e4991
commit f672446ebf
9 changed files with 710 additions and 6 deletions

2
.gitignore vendored
View File

@ -7,6 +7,8 @@
**/Makefile
**/cmake_install.cmake
**/install_manifest.txt
**/Release
**/Debug
.vs
.vscode
bin

View File

@ -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

View File

@ -36,16 +36,16 @@
#include "CddaDataStream.h"
#include <string>
#include <set>
#include <boost/thread/mutex.hpp>
#include <mutex>
#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<std::mutex> 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<std::mutex> lock(activeMutex);
if (stream == active) {
active = NULL;

View File

@ -54,7 +54,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../../;../../3rdparty/include;../../../../boost_1_60_0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../;../../3rdparty/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
@ -76,7 +76,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>../../;../../3rdparty/include;../../../../boost_1_60_0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../;../../3rdparty/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader>

View File

@ -0,0 +1,157 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="v140" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="GdiVis.cpp" />
<ClCompile Include="MemoryDC.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="MemoryDC.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<SccProjectName />
<SccLocalPath />
<ProjectGuid>{68AA481E-3CCE-440F-8CCE-69F1B371C89D}</ProjectGuid>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
<ProjectName>win32gdivis</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.Cpp.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.Cpp.UpgradeFromVC60.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)bin\release\</OutDir>
<IntDir>.\Release\</IntDir>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)bin\debug\</OutDir>
<IntDir>.\Debug\</IntDir>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<InlineFunctionExpansion>Default</InlineFunctionExpansion>
<StringPooling>true</StringPooling>
<FunctionLevelLinking>true</FunctionLevelLinking>
<Optimization>MaxSpeed</Optimization>
<SuppressStartupBanner>true</SuppressStartupBanner>
<WarningLevel>Level3</WarningLevel>
<AdditionalIncludeDirectories>.\;..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AssemblerListingLocation>.\Release\</AssemblerListingLocation>
<PrecompiledHeaderOutputFile>.\Release\projectMvis.pch</PrecompiledHeaderOutputFile>
<ObjectFileName>.\Release\</ObjectFileName>
<ProgramDataBaseFileName>.\Release\</ProgramDataBaseFileName>
</ClCompile>
<Midl>
<SuppressStartupBanner>true</SuppressStartupBanner>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<TypeLibraryName>.\Release\projectMvis.tlb</TypeLibraryName>
<MkTypLibCompatible>true</MkTypLibCompatible>
<TargetEnvironment>Win32</TargetEnvironment>
</Midl>
<ResourceCompile>
<Culture>0x0409</Culture>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
<OutputFile>.\Release\projectMvis.bsc</OutputFile>
</Bscmake>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<SubSystem>Windows</SubSystem>
<OutputFile>$(SolutionDir)bin\release\win32gdivis.dll</OutputFile>
<AdditionalLibraryDirectories>$(SolutionDir)bin\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>LIBCMT.LIB;version.lib;winmm.lib;Imm32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>xcopy $(TargetPath) $(SolutionDir)\bin\release\plugins\ /Y
</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<InlineFunctionExpansion>Default</InlineFunctionExpansion>
<Optimization>Disabled</Optimization>
<SuppressStartupBanner>true</SuppressStartupBanner>
<WarningLevel>Level3</WarningLevel>
<MinimalRebuild>true</MinimalRebuild>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<AdditionalIncludeDirectories>.\;..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AssemblerListingLocation>.\Debug\</AssemblerListingLocation>
<PrecompiledHeaderOutputFile>.\Debug\projectMvis.pch</PrecompiledHeaderOutputFile>
<ObjectFileName>.\Debug\</ObjectFileName>
<ProgramDataBaseFileName>.\Debug\</ProgramDataBaseFileName>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
</ClCompile>
<Midl>
<SuppressStartupBanner>true</SuppressStartupBanner>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<TypeLibraryName>.\Debug\projectMvis.tlb</TypeLibraryName>
<MkTypLibCompatible>true</MkTypLibCompatible>
<TargetEnvironment>Win32</TargetEnvironment>
</Midl>
<ResourceCompile>
<Culture>0x0409</Culture>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
<OutputFile>.\Debug\projectMvis.bsc</OutputFile>
</Bscmake>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OutputFile>$(SolutionDir)bin\debug\win32gdivis.dll</OutputFile>
<AdditionalLibraryDirectories>$(SolutionDir)bin\debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>LIBCMTD.LIB;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreSpecificDefaultLibraries>
</IgnoreSpecificDefaultLibraries>
</Link>
<PostBuildEvent>
<Command>xcopy $(TargetPath) $(SolutionDir)\bin\debug\plugins\ /Y
</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4af6aad0-9c71-4dc2-8343-19c467346884}</UniqueIdentifier>
<Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="GdiVis.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MemoryDC.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="MemoryDC.h">
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,311 @@
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <iostream>
#include <algorithm>
#include <shlwapi.h>
#include <core/sdk/ISpectrumVisualizer.h>
#include <core/sdk/IPlugin.h>
#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<bool> quit(false);
static std::atomic<bool> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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

View File

@ -0,0 +1,103 @@
//////////////////////////////////////////////////////////////////////////////
//
// License Agreement:
//
// The following are Copyright <20> 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;
}

View File

@ -0,0 +1,102 @@
//////////////////////////////////////////////////////////////////////////////
//
// License Agreement:
//
// The following are Copyright <20> 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 <Windows.h>
//////////////////////////////////////////////////////////////////////////////
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