From bf6afd7ec67df86bc7a20d1128a274f7445ad7ca Mon Sep 17 00:00:00 2001 From: Hunter Kvalevog Date: Fri, 15 May 2026 11:08:06 -0500 Subject: --- win-resize/build.bat | 3 + win-resize/build.sh | 3 + win-resize/win-resize.c | 229 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 235 insertions(+) create mode 100644 win-resize/build.bat create mode 100644 win-resize/build.sh create mode 100644 win-resize/win-resize.c (limited to 'win-resize') diff --git a/win-resize/build.bat b/win-resize/build.bat new file mode 100644 index 0000000..14ca49c --- /dev/null +++ b/win-resize/build.bat @@ -0,0 +1,3 @@ +@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 new file mode 100644 index 0000000..5b87d14 --- /dev/null +++ b/win-resize/build.sh @@ -0,0 +1,3 @@ +#!/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 new file mode 100644 index 0000000..275760e --- /dev/null +++ b/win-resize/win-resize.c @@ -0,0 +1,229 @@ +// ================================================================================================ +// 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