// 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 #include #include #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 create_imvu_engine(imvu::SharedPtr window) { HMODULE scene_window = GetModuleHandleW(L"SceneWindow.dll"); auto create = scene_window == nullptr ? nullptr : reinterpret_cast(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 right half), full (the default) or compare. // (The renderer process can also be switched while it runs: renderer/main.cpp.) 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"split" ? protocol::View::Split : setting == L"compare" ? protocol::View::Compare : protocol::View::Full; } } // 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 __cdecl createRenderEngine(imvu::SharedPtr window) { try { log::info("createRenderEngine: window {}", static_cast(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(std::make_unique( std::move(inner), std::make_shared(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 {}; } }