From df2c43b689d9a181fee8737ec7d7a31d07631126 Mon Sep 17 00:00:00 2001 From: Hunter Kvalevog Date: Thu, 21 May 2026 13:43:03 -0500 Subject: --- win-resize-mt/build.sh | 3 + win-resize-mt/win-resize-mt.c | 277 ++++++++++++++++++++++++++++++++++++++++++ win-resize-st/build.bat | 3 + win-resize-st/build.sh | 3 + win-resize-st/win-resize-st.c | 228 ++++++++++++++++++++++++++++++++++ win-resize/build.bat | 3 - win-resize/build.sh | 3 - win-resize/win-resize.c | 229 ---------------------------------- 8 files changed, 514 insertions(+), 235 deletions(-) create mode 100644 win-resize-mt/build.sh create mode 100644 win-resize-mt/win-resize-mt.c create mode 100644 win-resize-st/build.bat create mode 100644 win-resize-st/build.sh create mode 100644 win-resize-st/win-resize-st.c delete mode 100644 win-resize/build.bat delete mode 100755 win-resize/build.sh delete mode 100644 win-resize/win-resize.c diff --git a/win-resize-mt/build.sh b/win-resize-mt/build.sh new file mode 100644 index 0000000..c7c4423 --- /dev/null +++ b/win-resize-mt/build.sh @@ -0,0 +1,3 @@ +#!/bin/bash +mkdir -p bin +cc -o bin/win-resize-mt -Wall -Wextra -Wpedantic -O0 -g ./win-resize-mt.c -ldwmapi -lgdi32 diff --git a/win-resize-mt/win-resize-mt.c b/win-resize-mt/win-resize-mt.c new file mode 100644 index 0000000..2f9dd4e --- /dev/null +++ b/win-resize-mt/win-resize-mt.c @@ -0,0 +1,277 @@ +// ================================================================================================ +// Example of how to draw while resizing / moving a window on Windows in C. +// +// This demo uses a dedicated render thread with basic synchronization with the event loop. There +// is a single-threaded version called win-resize/ if that's more your style. +// +// Build (MSVC): +// > cl /W4 /Od /Zi win-resize-mt.c /Fe:win-resize-mt.exe +// Build (GCC/clang): +// $ cc -o win-resize-mt.exe -Wall -Wextra -Wpedantic -O0 -g win-resize-mt.c -ldwmapi -lgdi32 +// +// Changelog: +// XX/XX/XXXX: Initial release +// +// License: +// Copyright (c) 2026 Hunter Kvalevog +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE. +// ================================================================================================ + +#define WIN32_LEAN_AND_MEAN +#include +#include + +#include +#include +#include + +#ifdef _MSC_VER +# pragma comment(lib, "dwmapi.lib") +# pragma comment(lib, "gdi32.lib") +# pragma comment(lib, "user32.lib") +#endif + +#define UNUSED(Var) ((void)(Var)) + +static void GfxInit(HWND wnd); +static void GfxResize(UINT vpw, UINT vph); +static void GfxDraw(void); + +#define THREAD_BIT_QUIT (1 << 0) +#define THREAD_BIT_SIZE (1 << 1) +#define THREAD_BIT_SYNC (1 << 2) + +typedef struct ThreadData ThreadData; +struct ThreadData +{ + HWND wnd; + HANDLE init_sig; + HANDLE sync_sig; + volatile LONG bits; + volatile LONG size_w; + volatile LONG size_h; +}; + +// +static DWORD WINAPI RenderThread(LPVOID opaque) +{ + ThreadData *td = opaque; + GfxInit(td->wnd); + GfxDraw(); + + SetEvent(td->init_sig); + + while (TRUE) { + const LONG bits = InterlockedOr(&td->bits, 0); + + if (bits & THREAD_BIT_QUIT) { + break; + } + + if (bits & THREAD_BIT_SIZE) { + const LONG size_w = InterlockedOr(&td->size_w, 0); + const LONG size_h = InterlockedOr(&td->size_h, 0); + GfxResize(size_w, size_h); + InterlockedAnd(&td->bits, ~THREAD_BIT_SIZE); + } + + GfxDraw(); + + if (bits & THREAD_BIT_SYNC) { + SetEvent(td->sync_sig); + InterlockedAnd(&td->bits, ~THREAD_BIT_SYNC); + } + } + + return 0; +} + +// +static LRESULT CALLBACK WndProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + ThreadData *td = (ThreadData *)GetWindowLongPtrW(wnd, GWLP_USERDATA); + switch (msg) + { + case WM_DESTROY: + PostQuitMessage(0); + return 0; + case WM_SIZE: + // Resize + InterlockedExchange(&td->size_w, LOWORD(lparam)); + InterlockedExchange(&td->size_h, HIWORD(lparam)); + InterlockedOr(&td->bits, THREAD_BIT_SIZE); + + // Sync + InterlockedOr(&td->bits, THREAD_BIT_SYNC); + WaitForSingleObject(td->sync_sig, INFINITE); + ResetEvent(td->sync_sig); + break; + } + return DefWindowProcW(wnd, msg, wparam, lparam); +} + +// +int WinMain(HINSTANCE instance, HINSTANCE previnstance, LPSTR cmdline, int cmdshow) +{ + UNUSED(previnstance); UNUSED(cmdline); + + // Register window class + WNDCLASSEXW wc = { 0 }; + wc.cbSize = sizeof(wc); + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hInstance = instance; + wc.lpfnWndProc = WndProc; + wc.lpszClassName = L"win-resize-mt"; + + ATOM atom = RegisterClassExW(&wc); + assert(atom && "Failed to register window class"); + + // Create window + HWND wnd = CreateWindowExW(WS_EX_APPWINDOW, wc.lpszClassName, wc.lpszClassName, + WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, 0, 0, wc.hInstance, 0); + assert(wnd && "Failed to create window"); + + // + ThreadData td = { 0 }; + td.wnd = wnd; + td.init_sig = CreateEvent(0, TRUE, FALSE, 0); + td.sync_sig = CreateEvent(0, TRUE, FALSE, 0); + + // + HANDLE th = CreateThread(0, 0, RenderThread, &td, 0, 0); + assert(th && "Failed to create render thread"); + + // + SetWindowLongPtrW(wnd, GWLP_USERDATA, (LONG_PTR)&td); + WaitForSingleObject(td.init_sig, INFINITE); + + // + ShowWindow(wnd, cmdshow); + + // + MSG msg; + while (GetMessageW(&msg, 0, 0, 0) > 0) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + // + InterlockedOr(&td.bits, THREAD_BIT_QUIT); + WaitForSingleObject(th, INFINITE); + + return 0; +} + +// ================================================================================================ + +static UINT g_vpw = 0; +static UINT g_vph = 0; +static HDC g_hdc = 0; +static HDC g_hdc_back = 0; +static HBITMAP g_bmp = 0; +static HBRUSH g_bgbr = 0; +static HBRUSH g_fgbr = 0; +static HPEN g_pen = 0; + +static void GfxInit(HWND wnd) +{ + g_hdc = GetDC(wnd); + g_hdc_back = CreateCompatibleDC(g_hdc); + g_bgbr = CreateSolidBrush(RGB(0x00, 0x20, 0x20)); + g_fgbr = CreateSolidBrush(RGB(0xE0, 0xE0, 0xE0)); + g_pen = CreatePen(PS_SOLID, 2, RGB(0xFF, 0x10, 0x10)); + + RECT rc; + GetClientRect(wnd, &rc); + + GfxResize(rc.right, rc.bottom); +} + +static void GfxResize(UINT vpw, UINT vph) +{ + if (g_bmp) + { + DeleteObject(g_bmp); + g_bmp = 0; + } + + if (vpw > 0 && vph > 0) + { + g_bmp = CreateCompatibleBitmap(g_hdc, vpw, vph); + SelectObject(g_hdc_back, g_bmp); + } + + g_vpw = vpw; + g_vph = vph; +} + +static void GfxDraw(void) +{ + static UINT frame = 0; + ++frame; + + if (g_bmp && g_vpw > 0 && g_vph > 0) + { + HDC hdc = g_hdc_back; + + // Clear + { + RECT rc = { 0, 0, g_vpw, g_vph }; + FillRect(hdc, &rc, g_bgbr); + } + + // Draw X + { + SelectObject(hdc, g_pen); + MoveToEx(hdc, 0, 0, 0); + LineTo(hdc, g_vpw, g_vph); + MoveToEx(hdc, 0, g_vph, 0); + LineTo(hdc, g_vpw, 0); + } + + // Draw rotating triangle + { + int cx = g_vpw / 2; + int cy = g_vph / 2; + int r = (g_vpw < g_vph ? g_vpw : g_vph) / 3; + + POINT verts[3]; + for (int i = 0; i < 3; ++i) + { + float ang = ((float)frame / 100.0f) + (float)i * (2.0f * 3.14159265f / 3.0f); + verts[i].x = cx + (int)(cosf(ang) * r); + verts[i].y = cy + (int)(sinf(ang) * r); + } + + SelectObject(hdc, g_pen); + SelectObject(hdc, g_fgbr); + Polygon(hdc, verts, ARRAYSIZE(verts)); + } + + // Draw text + { + WCHAR txtbuf[256]; + _snwprintf_s(txtbuf, ARRAYSIZE(txtbuf), _TRUNCATE, L"win-resize-mt (frame %u)", frame); + + SIZE sz; + GetTextExtentPoint32W(hdc, txtbuf, (int)wcslen(txtbuf), &sz); + + SetBkMode(hdc, TRANSPARENT); + SetTextColor(hdc, RGB(0xE0, 0xE0, 0xE0)); + TextOutW(hdc, (g_vpw - sz.cx) / 2, 19, txtbuf, (int)wcslen(txtbuf)); + } + + // Present + BitBlt(g_hdc, 0, 0, g_vpw, g_vph, g_hdc_back, 0, 0, SRCCOPY); + + // Wait for dwm to display a frame + DwmFlush(); + } +} + diff --git a/win-resize-st/build.bat b/win-resize-st/build.bat new file mode 100644 index 0000000..8568ca2 --- /dev/null +++ b/win-resize-st/build.bat @@ -0,0 +1,3 @@ +@echo off +if not exist bin mkdir bin +cl /W4 /Od /Zi /Fe:bin\win-resize-st.exe win-resize-st.c /Fd:bin\ /Fo:bin\ diff --git a/win-resize-st/build.sh b/win-resize-st/build.sh new file mode 100644 index 0000000..d644837 --- /dev/null +++ b/win-resize-st/build.sh @@ -0,0 +1,3 @@ +#!/bin/bash +mkdir -p bin +cc -o bin/win-resize-st -Wall -Wextra -Wpedantic -O0 -g ./win-resize-st.c -ldwmapi -lgdi32 diff --git a/win-resize-st/win-resize-st.c b/win-resize-st/win-resize-st.c new file mode 100644 index 0000000..5aace81 --- /dev/null +++ b/win-resize-st/win-resize-st.c @@ -0,0 +1,228 @@ +// ================================================================================================ +// Example of how to draw while resizing / moving a window on Windows in C. +// +// Window contents are rendered via GDI, but the behavior is the same no matter what graphics API +// you use. The original version of this demo (on old-20260427 branch) used D3D11. +// +// Pretty much all modern Direct3D Windows apps use a render thread and therefore don't have to +// deal with this problem. That strategy doesn't work with APIs that have weird thread affinity +// issues (OpenGL), so this is one way of doing it without multithreading. +// +// Build (MSVC): +// > cl /W4 /Od /Zi win-resize-st.c /Fe:win-resize-st.exe +// Build (GCC/clang): +// $ cc -o win-resize-st.exe -Wall -Wextra -Wpedantic -O0 -g win-resize-st.c -ldwmapi -lgdi32 +// +// Changelog: +// 5/15/2026: Initial release +// +// License: +// Copyright (c) 2026 Hunter Kvalevog +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE. +// ================================================================================================ + +#define WIN32_LEAN_AND_MEAN +#include +#include + +#include +#include +#include + +#ifdef _MSC_VER +# pragma comment(lib, "dwmapi.lib") +# pragma comment(lib, "gdi32.lib") +# pragma comment(lib, "user32.lib") +#endif + +#define UNUSED(Var) ((void)(Var)) + +static void GfxInit(HWND wnd); +static void GfxResize(UINT vpw, UINT vph); +static void GfxDraw(void); + +// +static LRESULT CALLBACK WndProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch (msg) + { + case WM_DESTROY: + PostQuitMessage(0); + return 0; + case WM_SIZE: + GfxResize(LOWORD(lparam), HIWORD(lparam)); + GfxDraw(); + break; + case WM_ENTERSIZEMOVE: + SetTimer(wnd, 1, USER_TIMER_MINIMUM, 0); + break; + case WM_EXITSIZEMOVE: + KillTimer(wnd, 1); + break; + case WM_TIMER: + GfxDraw(); + break; + } + return DefWindowProcW(wnd, msg, wparam, lparam); +} + +// +int WinMain(HINSTANCE instance, HINSTANCE previnstance, LPSTR cmdline, int cmdshow) +{ + UNUSED(previnstance); UNUSED(cmdline); + + // Register window class + WNDCLASSEXW wc = { 0 }; + wc.cbSize = sizeof(wc); + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hInstance = instance; + wc.lpfnWndProc = WndProc; + wc.lpszClassName = L"win-resize-st"; + + ATOM atom = RegisterClassExW(&wc); + assert(atom && "Failed to register window class"); + + // Create window + HWND wnd = CreateWindowExW(WS_EX_APPWINDOW, wc.lpszClassName, wc.lpszClassName, + WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, 0, 0, wc.hInstance, 0); + assert(wnd && "Failed to create window"); + + // + GfxInit(wnd); + + // + ShowWindow(wnd, cmdshow); + + // Run a typical D3D-style window loop + BOOL quit = FALSE; + while (!quit) + { + // Pump the message loop + MSG msg; + while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) + { + quit |= (msg.message == WM_QUIT); + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + + // Update the screen + GfxDraw(); + } + + return 0; +} + +// ================================================================================================ + +static UINT g_vpw = 0; +static UINT g_vph = 0; +static HDC g_hdc = 0; +static HDC g_hdc_back = 0; +static HBITMAP g_bmp = 0; +static HBRUSH g_bgbr = 0; +static HBRUSH g_fgbr = 0; +static HPEN g_pen = 0; + +static void GfxInit(HWND wnd) +{ + g_hdc = GetDC(wnd); + g_hdc_back = CreateCompatibleDC(g_hdc); + g_bgbr = CreateSolidBrush(RGB(0x00, 0x20, 0x20)); + g_fgbr = CreateSolidBrush(RGB(0xE0, 0xE0, 0xE0)); + g_pen = CreatePen(PS_SOLID, 2, RGB(0xFF, 0x10, 0x10)); + + RECT rc; + GetClientRect(wnd, &rc); + + GfxResize(rc.right, rc.bottom); +} + +static void GfxResize(UINT vpw, UINT vph) +{ + if (g_bmp) + { + DeleteObject(g_bmp); + g_bmp = 0; + } + + if (vpw > 0 && vph > 0) + { + g_bmp = CreateCompatibleBitmap(g_hdc, vpw, vph); + SelectObject(g_hdc_back, g_bmp); + } + + g_vpw = vpw; + g_vph = vph; +} + +static void GfxDraw(void) +{ + static UINT frame = 0; + ++frame; + + if (g_bmp && g_vpw > 0 && g_vph > 0) + { + HDC hdc = g_hdc_back; + + // Clear + { + RECT rc = { 0, 0, g_vpw, g_vph }; + FillRect(hdc, &rc, g_bgbr); + } + + // Draw X + { + SelectObject(hdc, g_pen); + MoveToEx(hdc, 0, 0, 0); + LineTo(hdc, g_vpw, g_vph); + MoveToEx(hdc, 0, g_vph, 0); + LineTo(hdc, g_vpw, 0); + } + + // Draw rotating triangle + { + int cx = g_vpw / 2; + int cy = g_vph / 2; + int r = (g_vpw < g_vph ? g_vpw : g_vph) / 3; + + POINT verts[3]; + for (int i = 0; i < 3; ++i) + { + float ang = ((float)frame / 100.0f) + (float)i * (2.0f * 3.14159265f / 3.0f); + verts[i].x = cx + (int)(cosf(ang) * r); + verts[i].y = cy + (int)(sinf(ang) * r); + } + + SelectObject(hdc, g_pen); + SelectObject(hdc, g_fgbr); + Polygon(hdc, verts, ARRAYSIZE(verts)); + } + + // Draw text + { + WCHAR txtbuf[256]; + _snwprintf_s(txtbuf, ARRAYSIZE(txtbuf), _TRUNCATE, L"win-resize-st (frame %u)", frame); + + SIZE sz; + GetTextExtentPoint32W(hdc, txtbuf, (int)wcslen(txtbuf), &sz); + + SetBkMode(hdc, TRANSPARENT); + SetTextColor(hdc, RGB(0xE0, 0xE0, 0xE0)); + TextOutW(hdc, (g_vpw - sz.cx) / 2, 19, txtbuf, (int)wcslen(txtbuf)); + } + + // Present + BitBlt(g_hdc, 0, 0, g_vpw, g_vph, g_hdc_back, 0, 0, SRCCOPY); + + // Wait for dwm to display a frame + DwmFlush(); + } +} + diff --git a/win-resize/build.bat b/win-resize/build.bat deleted file mode 100644 index 14ca49c..0000000 --- a/win-resize/build.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -if not exist bin mkdir bin -cl /W4 /Od /Zi /Fe:bin\win-resize.exe win-resize.c /Fd:bin\ /Fo:bin\ diff --git a/win-resize/build.sh b/win-resize/build.sh deleted file mode 100755 index 4d3a4ab..0000000 --- a/win-resize/build.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -mkdir -p bin -cc -o bin/win-resize -Wall -Wextra -Wpedantic -O0 -g ./win-resize.c -ldwmapi -lgdi32 diff --git a/win-resize/win-resize.c b/win-resize/win-resize.c deleted file mode 100644 index 275760e..0000000 --- a/win-resize/win-resize.c +++ /dev/null @@ -1,229 +0,0 @@ -// ================================================================================================ -// Example of how to draw while resizing / moving a window on Windows in C. -// -// Window contents are rendered via GDI, but the behavior is the same no matter what graphics API -// you use. The original version of this demo (on old-20260427 branch) used D3D11. -// -// Pretty much all modern Direct3D Windows apps use a render thread and therefore don't have to -// deal with this problem. That strategy doesn't work with APIs that have weird thread affinity -// issues (OpenGL), so this is one way of doing it without multithreading. -// -// Build (MSVC): -// > cl /W4 /Od /Zi win-resize.c /Fe:win-resize.exe -// Build (GCC/clang): -// $ cc -o win-resize.exe -Wall -Wextra -Wpedantic -O0 -g win-resize.c -ldwmapi -lgdi32 -// -// Changelog: -// 5/15/2026: Initial release -// -// License: -// SPDX-License-Identifier: 0BSD -// Copyright (c) 2026 Hunter Kvalevog -// -// Permission to use, copy, modify, and/or distribute this software for any -// purpose with or without fee is hereby granted. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -// WITH REGARD TO THIS SOFTWARE. -// ================================================================================================ - -#define WIN32_LEAN_AND_MEAN -#include -#include - -#include -#include -#include - -#ifdef _MSC_VER -# pragma comment(lib, "dwmapi.lib") -# pragma comment(lib, "gdi32.lib") -# pragma comment(lib, "user32.lib") -#endif - -#define UNUSED(Var) ((void)(Var)) - -static void GfxInit(HWND wnd); -static void GfxResize(UINT vpw, UINT vph); -static void GfxDraw(void); - -// -static LRESULT CALLBACK WndProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) -{ - switch (msg) - { - case WM_DESTROY: - PostQuitMessage(0); - return 0; - case WM_SIZE: - GfxResize(LOWORD(lparam), HIWORD(lparam)); - GfxDraw(); - break; - case WM_ENTERSIZEMOVE: - SetTimer(wnd, 1, USER_TIMER_MINIMUM, 0); - break; - case WM_EXITSIZEMOVE: - KillTimer(wnd, 1); - break; - case WM_TIMER: - GfxDraw(); - break; - } - return DefWindowProcW(wnd, msg, wparam, lparam); -} - -// -int WinMain(HINSTANCE instance, HINSTANCE previnstance, LPSTR cmdline, int cmdshow) -{ - UNUSED(previnstance); UNUSED(cmdline); - - // Register window class - WNDCLASSEXW wc = { }; - wc.cbSize = sizeof(wc); - wc.hCursor = LoadCursor(0, IDC_ARROW); - wc.hInstance = instance; - wc.lpfnWndProc = WndProc; - wc.lpszClassName = L"win-resize"; - - ATOM atom = RegisterClassExW(&wc); - assert(atom && "Failed to register window class"); - - // Create window - HWND wnd = CreateWindowExW(WS_EX_APPWINDOW, wc.lpszClassName, wc.lpszClassName, - WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, 0, 0, wc.hInstance, 0); - assert(wnd && "Failed to create window"); - - // - GfxInit(wnd); - - // - ShowWindow(wnd, cmdshow); - - // Run a typical D3D-style window loop - BOOL quit = FALSE; - while (!quit) - { - // Pump the message loop - MSG msg; - while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) - { - quit |= (msg.message == WM_QUIT); - TranslateMessage(&msg); - DispatchMessageW(&msg); - } - - // Update the screen - GfxDraw(); - } - - return 0; -} - -// ================================================================================================ - -static UINT g_vpw = 0; -static UINT g_vph = 0; -static HDC g_hdc = 0; -static HDC g_hdc_back = 0; -static HBITMAP g_bmp = 0; -static HBRUSH g_bgbr = 0; -static HBRUSH g_fgbr = 0; -static HPEN g_pen = 0; - -static void GfxInit(HWND wnd) -{ - g_hdc = GetDC(wnd); - g_hdc_back = CreateCompatibleDC(g_hdc); - g_bgbr = CreateSolidBrush(RGB(0x00, 0x20, 0x20)); - g_fgbr = CreateSolidBrush(RGB(0xE0, 0xE0, 0xE0)); - g_pen = CreatePen(PS_SOLID, 2, RGB(0xFF, 0x10, 0x10)); - - RECT rc; - GetClientRect(wnd, &rc); - - GfxResize(rc.right, rc.bottom); -} - -static void GfxResize(UINT vpw, UINT vph) -{ - if (g_bmp) - { - DeleteObject(g_bmp); - g_bmp = 0; - } - - if (vpw > 0 && vph > 0) - { - g_bmp = CreateCompatibleBitmap(g_hdc, vpw, vph); - SelectObject(g_hdc_back, g_bmp); - } - - g_vpw = vpw; - g_vph = vph; -} - -static void GfxDraw(void) -{ - static UINT frame = 0; - ++frame; - - if (g_bmp && g_vpw > 0 && g_vph > 0) - { - HDC hdc = g_hdc_back; - - // Clear - { - RECT rc = { 0, 0, g_vpw, g_vph }; - FillRect(hdc, &rc, g_bgbr); - } - - // Draw X - { - SelectObject(hdc, g_pen); - MoveToEx(hdc, 0, 0, 0); - LineTo(hdc, g_vpw, g_vph); - MoveToEx(hdc, 0, g_vph, 0); - LineTo(hdc, g_vpw, 0); - } - - // Draw rotating triangle - { - int cx = g_vpw / 2; - int cy = g_vph / 2; - int r = (g_vpw < g_vph ? g_vpw : g_vph) / 3; - - POINT verts[3]; - for (int i = 0; i < 3; ++i) - { - float ang = ((float)frame / 100.0f) + (float)i * (2.0f * 3.14159265f / 3.0f); - verts[i].x = cx + (int)(cosf(ang) * r); - verts[i].y = cy + (int)(sinf(ang) * r); - } - - SelectObject(hdc, g_pen); - SelectObject(hdc, g_fgbr); - Polygon(hdc, verts, ARRAYSIZE(verts)); - } - - // Draw text - { - WCHAR txtbuf[256]; - _snwprintf_s(txtbuf, ARRAYSIZE(txtbuf), _TRUNCATE, L"win-resize (frame %u)", frame); - - SIZE sz; - GetTextExtentPoint32W(hdc, txtbuf, (int)wcslen(txtbuf), &sz); - - SetBkMode(hdc, TRANSPARENT); - SetTextColor(hdc, RGB(0xE0, 0xE0, 0xE0)); - TextOutW(hdc, (g_vpw - sz.cx) / 2, 19, txtbuf, (int)wcslen(txtbuf)); - } - - // Present - BitBlt(g_hdc, 0, 0, g_vpw, g_vph, g_hdc_back, 0, 0, SRCCOPY); - - // Wait for dwm to display a frame - DwmFlush(); - } -} - -- cgit v1.2.3