// CoopMockGame -- a tiny test "game" used to exercise the capture + audio + hook paths. // // coop_mock_game.exe [dx9|dx9ex|dx10|dx11|dx12|gl] [seconds] [rate] [channels] [bits] [pcm|float] // // It opens a normal visible window and renders an animated, frame-numbered pattern (see // render_backend.hpp): a moving bar + per-frame background colour make motion obvious, and // a top-left block encodes the exact frame number so a capture test can decode it and // detect dropped / duplicated / stale frames. With audio args it also plays a configurable // WASAPI tone (the same ToneSource coop_tone uses), so it doubles as an A/V source. seconds // = 0 runs until the window is closed. Console app so it can print its pid + status. #include #include #include #include #include #include #include "render_backend.hpp" #include "tone_source.hpp" namespace { std::atomic g_running{true}; LRESULT CALLBACK wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { if (msg == WM_DESTROY) { PostQuitMessage(0); return 0; } return DefWindowProcW(hwnd, msg, wparam, lparam); } // Spawns the audio render loop on its own thread (WASAPI wants its own COM apartment). void audio_thread(coop::tone::ToneFormat want) { if (FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED))) { return; } coop::tone::ToneSource tone; if (tone.open(want, 440.0)) { std::printf("MOCK_GAME audio: %u Hz %u ch %u-bit %s\n", tone.format().rate, tone.format().channels, tone.format().bits, tone.format().is_float ? "float" : "pcm"); std::fflush(stdout); while (g_running.load(std::memory_order_relaxed)) { tone.render_step(200); } } else { std::printf("MOCK_GAME audio: failed to open requested format\n"); } tone.close(); CoUninitialize(); } } // namespace int main(int argc, char** argv) { const std::string backend_name = argc > 1 ? argv[1] : "dx11"; const double seconds = argc > 2 ? std::strtod(argv[2], nullptr) : 0.0; const bool want_audio = argc > 3; coop::tone::ToneFormat audio_fmt; if (want_audio) { audio_fmt.rate = static_cast(std::strtoul(argv[3], nullptr, 10)); audio_fmt.channels = argc > 4 ? static_cast(std::strtoul(argv[4], nullptr, 10)) : 2; audio_fmt.bits = argc > 5 ? static_cast(std::strtoul(argv[5], nullptr, 10)) : 32; audio_fmt.is_float = argc > 6 ? (std::string(argv[6]) == "float") : (audio_fmt.bits == 32); } constexpr std::uint32_t kW = 640, kH = 480; const HINSTANCE inst = GetModuleHandleW(nullptr); WNDCLASSEXW wc = {}; wc.cbSize = sizeof(wc); wc.style = CS_OWNDC; // a stable private DC, so the OpenGL backend can keep one GL context wc.lpfnWndProc = wnd_proc; wc.hInstance = inst; wc.hCursor = LoadCursorW(nullptr, IDC_ARROW); wc.lpszClassName = L"CoopMockGameWindow"; RegisterClassExW(&wc); RECT r = {0, 0, static_cast(kW), static_cast(kH)}; AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, FALSE); HWND hwnd = CreateWindowExW(0, wc.lpszClassName, L"CoopMockGame", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, r.right - r.left, r.bottom - r.top, nullptr, nullptr, inst, nullptr); if (hwnd == nullptr) { std::printf("MOCK_GAME error: CreateWindow failed\n"); return 1; } auto backend = coop::mock::RenderBackend::create(backend_name); if (!backend || !backend->init(hwnd, kW, kH)) { std::printf("MOCK_GAME error: backend '%s' unavailable\n", backend_name.c_str()); return 2; } std::printf("MOCK_GAME pid=%lu backend=%s w=%u h=%u audio=%s\n", GetCurrentProcessId(), backend->name(), kW, kH, want_audio ? "yes" : "no"); std::fflush(stdout); std::thread audio; if (want_audio) { audio = std::thread(audio_thread, audio_fmt); } const ULONGLONG start = GetTickCount64(); std::uint32_t frame = 0; for (;;) { MSG msg; while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) { g_running.store(false, std::memory_order_relaxed); } TranslateMessage(&msg); DispatchMessageW(&msg); } if (!g_running.load(std::memory_order_relaxed)) { break; } backend->render_and_present(frame++); if (seconds > 0.0 && (GetTickCount64() - start) >= static_cast(seconds * 1000.0)) { break; } } g_running.store(false, std::memory_order_relaxed); if (audio.joinable()) { audio.join(); } std::printf("MOCK_GAME done: %u frames\n", frame); return 0; }