Создан Gist с полным кодом здесь
Это довольно эзотерическое искусство, и есть несколько способов сделать это. Я предпочитаю то, что называется Direct3D Wrapper . Прошло много лет с тех пор, как я это сделал, но однажды я сделал это с игрой. Возможно, я пропустил некоторые детали, но я просто надеюсь проиллюстрировать идею.
Все игры Direct3D9 должны вызывать IDirect3DDevice9 :: EndScene после того, как экран отрендерен и готов к рисованию. Таким образом, теоретически мы можем поместить собственный код внутри EndScene
, который рисует то, что мы хотим в игре. Мы делаем это, создавая в игре класс, который выглядит как IDirect3DDevice9, но на самом деле это просто оболочка, которая перенаправляет все вызовы функций в реальный класс. Итак, теперь в нашем пользовательском классе наша функция-обёртка для EndScene
выглядит следующим образом:
HRESULT IDirect3DDevice9::EndScene()
{
// draw overlays here
realDevice.EndScene();
}
Затем мы скомпилируем ее в DLL-библиотеку d3d9.dll и поместим в каталог исполняемого файла игры. Настоящий d3d9.dll должен находиться в папке / system32, но игра сначала просматривает текущий каталог, а вместо этого загружает наш. Как только игра загружается, она использует нашу DLL для создания экземпляра нашего класса-оболочки. И теперь каждый раз, когда вызывается EndScene
, наш код выполняется для отрисовки того, что мы хотим на экране.
Я думаю, вы можете попробовать тот же принцип с OpenGL. Но, чтобы предотвратить вмешательство, я думаю, что некоторые современные игры пытаются предотвратить это.