// t5de-renderer.exe: the renderer process. Started by the adapter (t5deRenderEngine.dll) for each of the client's // 3D views; draws into a child window it places in the client's window, frame by frame as the client draws. // // For now a spike proving the architecture: a small box in the 3D view's corner, its color changing with each frame // the client draws, drawn with Diligent (Direct3D 11) from this 64-bit process. #include #include #include #include #include #include #include "EngineFactoryD3D11.h" #include "RefCntAutoPtr.hpp" #include "t5de/protocol/channel.hpp" namespace { using namespace Diligent; // The box: where in the client's 3D view, and how big. constexpr int boxX = 16; constexpr int boxY = 16; constexpr int boxWidth = 240; constexpr int boxHeight = 80; struct Arguments { std::wstring channel; DWORD parent = 0; }; Arguments parse_arguments() { Arguments arguments; int count = 0; wchar_t** argv = CommandLineToArgvW(GetCommandLineW(), &count); for (int i = 1; i + 1 < count; i += 2) { const std::wstring_view name = argv[i]; if (name == L"--channel") { arguments.channel = argv[i + 1]; } else if (name == L"--parent") { arguments.parent = static_cast(std::wcstoul(argv[i + 1], nullptr, 10)); } } LocalFree(argv); return arguments; } LRESULT CALLBACK window_procedure(HWND window, UINT message, WPARAM wparam, LPARAM lparam) { if (message == WM_ERASEBKGND) { return 1; // we draw all of it } return DefWindowProcW(window, message, wparam, lparam); } // A child of the client's window. Disabled, so mouse input goes to the client's window under it. HWND create_child_window(HWND parent) { WNDCLASSEXW windowClass{.cbSize = sizeof(WNDCLASSEXW), .lpfnWndProc = window_procedure, .hInstance = GetModuleHandleW(nullptr), .hCursor = LoadCursorW(nullptr, IDC_ARROW), .lpszClassName = L"T5DERenderer"}; RegisterClassExW(&windowClass); return CreateWindowExW(0, windowClass.lpszClassName, L"", WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CLIPSIBLINGS, boxX, boxY, boxWidth, boxHeight, parent, nullptr, windowClass.hInstance, nullptr); } } // namespace int WINAPI wWinMain(HINSTANCE, HINSTANCE, PWSTR, int) { const Arguments arguments = parse_arguments(); if (arguments.channel.empty()) { return 2; } HANDLE mapping = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, arguments.channel.c_str()); auto* channel = mapping == nullptr ? nullptr : static_cast(MapViewOfFile( mapping, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(t5de::protocol::Channel))); HANDLE frameEvent = OpenEventW(SYNCHRONIZE, FALSE, (arguments.channel + t5de::protocol::frameEventSuffix).c_str()); HANDLE parent = OpenProcess(SYNCHRONIZE, FALSE, arguments.parent); if (channel == nullptr || frameEvent == nullptr || parent == nullptr || channel->version != t5de::protocol::version) { return 3; } HWND window = create_child_window(reinterpret_cast(static_cast(channel->window))); if (window == nullptr) { return 4; } IEngineFactoryD3D11* factory = GetEngineFactoryD3D11(); RefCntAutoPtr device; RefCntAutoPtr context; EngineD3D11CreateInfo engineInfo; factory->CreateDeviceAndContextsD3D11(engineInfo, &device, &context); if (!device) { return 5; } RefCntAutoPtr swapChain; SwapChainDesc swapChainDesc; factory->CreateSwapChainD3D11(device, context, swapChainDesc, FullScreenModeDesc{}, Win32NativeWindow{window}, &swapChain); if (!swapChain) { return 6; } for (;;) { const HANDLE handles[] = {frameEvent, parent}; const DWORD result = MsgWaitForMultipleObjects(2, handles, FALSE, 1000, QS_ALLINPUT); MSG message; while (PeekMessageW(&message, nullptr, 0, 0, PM_REMOVE)) { DispatchMessageW(&message); } if (result == WAIT_OBJECT_0 + 1 || channel->closing != 0) { break; // the client exited, or the engine is gone } if (result != WAIT_OBJECT_0) { continue; } // T5DE gold, pulsing with the client's frames. const float pulse = 0.5f + 0.5f * std::sin(static_cast(channel->frames) * 0.1f); const float color[] = {1.0f, 0.82f * pulse + 0.1f, 0.0f, 1.0f}; ITextureView* backBuffer = swapChain->GetCurrentBackBufferRTV(); context->SetRenderTargets(1, &backBuffer, nullptr, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); context->ClearRenderTarget(backBuffer, color, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); swapChain->Present(0); } DestroyWindow(window); return 0; }