Files
t5de-renderer/adapter/plugin.cpp
T
dhkatzandClaude Opus 5.5 42fc55cb91 Draw the client's scene in the renderer process
The adapter records everything the client draws (state, transforms, lights, fog, textures and buffers) as a command stream, sent in chunks through the shared memory channel, while IMVU's Direct3D renderer still draws the whole view. The renderer process draws it with Diligent, with shaders reproducing IMVU's Direct3D 9 fixed-function setup, over the right half of the 3D view to compare. It skips to the newest frame when it falls behind, and logs its errors and frame times.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-28 05:52:15 -07:00

73 lines
2.9 KiB
C++

// The renderer plugin's entry points, which SceneWindow.dll's createDLLRenderer looks up by name (exported
// undecorated by plugin.def). The engine is the adapter's (engine.hpp): IMVU's Direct3D engine draws, and the
// renderer process draws over part of it.
#include <windows.h>
#include <exception>
#include <string_view>
#include "log.hpp"
#include "engine.hpp"
#include "recorder.hpp"
#include "renderer_process.hpp"
#include "t5de/imvu/render_engine.hpp"
namespace {
using namespace t5de;
// IMVU's Direct3D 9 engine, made by SceneWindow.dll (already loaded: it's what loads this plugin). Direct3D
// rather than IMVU's OpenGL engine, which needs a real graphics driver: Direct3D also works on Windows' basic
// display driver (virtual machines), and it's what most players use.
imvu::SharedPtr<imvu::PiRenderEngine> create_imvu_engine(imvu::SharedPtr<imvu::INativeWindow> window)
{
HMODULE scene_window = GetModuleHandleW(L"SceneWindow.dll");
auto create = scene_window == nullptr
? nullptr
: reinterpret_cast<imvu::CreateRenderer>(GetProcAddress(scene_window, imvu::createRendererName));
if (create == nullptr) {
log::info("SceneWindow.dll's createRenderer not found");
return {};
}
return create(std::move(window), imvu::RendererType::Direct3D);
}
// What the renderer process draws: T5DE_RENDERER_VIEW=off, split (the default: the right half) or full.
protocol::View view()
{
wchar_t value[16] = {};
GetEnvironmentVariableW(L"T5DE_RENDERER_VIEW", value, 16);
const std::wstring_view setting = value;
return setting == L"off" ? protocol::View::Off : setting == L"full" ? protocol::View::Full : protocol::View::Split;
}
} // namespace
extern "C" int __cdecl isRenderEngineSupported() { return 1; }
// Returns a C++ object from a C-linkage function: fine here, the caller is C++ built for the same ABI.
#pragma warning(suppress : 4190)
extern "C" imvu::SharedPtr<imvu::PiRenderEngine> __cdecl createRenderEngine(imvu::SharedPtr<imvu::INativeWindow> window)
{
try {
log::info("createRenderEngine: window {}", static_cast<void*>(window.get()));
HWND hwnd = window ? window->getPlatformWindow() : nullptr;
auto inner = create_imvu_engine(std::move(window));
if (!inner) {
return {};
}
const protocol::View shown = view();
auto renderer = hwnd != nullptr && shown != protocol::View::Off ? RendererProcess::start(hwnd, shown) : nullptr;
return imvu::SharedPtr<imvu::PiRenderEngine>(std::make_unique<Engine>(
std::move(inner), std::make_shared<Recorder>(std::move(renderer))));
} catch (const std::exception& e) {
// Exceptions mustn't cross into IMVU's code (a different C++ runtime).
log::info("createRenderEngine failed: {}", e.what());
return {};
} catch (...) {
log::info("createRenderEngine failed");
return {};
}
}