Сразу признаюсь: в этой статье нет ни одной строчки кода, которую написал бы я. Я написал промпт. Пять строчек, с матом и с ошибками.
Всё остальное сделал Claude, пока я ходил на кухню и обратно: 7 300 новых строк на C, C++ и HLSL, порт на 64 бита, рендер на DirectX 12 с нуля, звук, мышь и даже тестовый прогон на моём ноутбуке. Ушло на это полтора часа, с 21:28 до 22:55.
UPD: дозалил футажик сравнение, где отчетливо видно разницу, того, с чем я стартовал (софтвер + досбокс для аутентичности). и что получил на выходе.
Зачем вообще это понадобилось
Последний месяц я гоняю DLSS 5 через ReShade и RenoDX по всему, что шевелится. Pong, Lada Racing Club, Heretic, Свитч... Схема со старыми играми всегда одна, и она мерзкая. Игра рисует через DX8-9, OpenGL или вообще процессором в DOS, сверху dgVoodoo2 переводит это в DX11, сверху фидер, сверху RenoDX, а уже сверху нейросеть. Пять слоёв костылей, и каждый норовит отвалиться при первом alt‑tab.
А ещё DLSS 5 хочет векторы движения и глубину. Старая игра их не отдаёт, поэтому их достраивают шейдерами по готовой картинке, то есть, по сути, угадывают. Отсюда добрая половина галлюцинаций, над которыми я ржал в прошлой статье про Pong.
И вот сижу я вечером, смотрю на папку с досовской демкой Quake (она у меня почему‑то живёт внутри папки Heroes 2, не спрашивайте) и думаю: а что если не надевать на игру очередной враппер, а просто... переписать ей рендер?
Сам я этого, понятно, не умею.
Промпт
Целиком приводить не буду, Хабр такие слова не одобрит.
Что он сделал. В переводе на человеческий
Начал он не с кода. Сначала поднял себе Linux в облаке, поставил mingw‑w64 (это компилятор, который на Linux собирает обычные виндовые экзешники), Wine и vkd3d, чтобы DirectX 12 можно было запускать прямо там, без видеокарты. Проверил на одном разноцветном прямоугольнике, и прямоугольник нарисовался.
Потом выкачал с GitHub исходники Quake, те самые, которые id Software открыла по лицензии GPL в 1999 году.
Шаг 1. 64 бита
Quake писали под 32-битные машины, и там есть тонкое место. Вся игровая логика (монстры, двери, оружие) написана на скриптовом QuakeC, а он хранит каждую строку как 4-байтовое смещение от начала таблицы. На x64 часть строк лежит в памяти так далеко, что в 4 байта отступ не влезает, и игра либо падает, либо показывает мусор вместо названия карты.
Claude завёл отдельную таблицу «движковых» строк с отрицательными номерами и переписал под неё около 30 мест в коде.
Заодно всплыли две старые ошибки самого id. Загрузчик карт писал 8 чисел в массив на 4, и точно такой же выход за границу был в частицах у светящихся предметов. Компилятор 1996 года это молча прощал, а современный GCC вполне может превратить такое в «оптимизацию», после которой карта грузится криво.
Шаг 2. Выкинуть старьё
OpenGL, DirectDraw, DirectSound, DirectInput, сеть IPX, модем, музыку с CD‑диска и ассемблер под Pentium. Минус 8 000 строк. Игра от этого ничего не потеряла, кроме возможности поиграть по нуль‑модемному кабелю.
Шаг 3. Рендер на DirectX 12 с нуля
На этом месте его отчёта я честно перестал понимать слова уже к третьему абзацу, поэтому коротко и как я это понял:
Вся геометрия карты один раз при загрузке заливается в видеопамять. Дальше каждый кадр процессор по родному BSP только решает, какие стены видно, и отдаёт видеокарте список номеров.
Свет на стенах упакован в атлас 1024×1024 из 4 слоёв, а мигание факелов и ламп считает шейдер, ничего не перезаливается.
Вспышки от выстрелов и ракет считаются для каждого пикселя.
Все кадры анимации монстров лежат в видеопамяти, и шейдер плавно смешивает соседние, так что огры наконец перестали дёргаться 10 раз в секунду.
Небо и вода «плывут» прямо в шейдере по формулам софтверного Quake, без нарезки на полигоны, как это было в GLQuake.
Больше всего меня порадовала одна деталь. Яркость он сверил с таблицей цветов colormap из PAK0 и выставил пересвет как в DOS‑версии, до 1.94 от нормы. GLQuake обрезал свет на единице, поэтому и выглядел таким плоским. Я об этом даже не знал.

Шаг 4. То, ради чего всё затевалось
Для DLSS 5 игра теперь сама отдаёт три буфера, и у каждого человеческое имя, которое видно в RenderDoc, Nsight и аддонах:
Буфер | Формат | Что внутри |
SceneColor | RGBA16F | 3D‑сцена без HUD, меню и консоли |
MotionVectors | RG16F | настоящие векторы: камера, двери, лифты, анимация монстров и ствол в руках |
SceneDepth | D32 | глубина в reverse‑Z, без дальней плоскости |
Плюс r_jitter (субпиксельный сдвиг камеры каждый кадр), r_scale (внутреннее разрешение, чтобы апскейлеру было что апскейлить) и r_debugview, который выводит векторы движения прямо на экран.
Векторы, кстати, он проверил глазами. При движении вперёд картинка правильно «разбегается» от центра, а у грунта с ружьём свои векторы, отдельно от стен.

Шаг 5. Всё остальное
Звук через XAudio2, мышь через Raw Input, клавиатура по скан‑кодам (WASD работает даже на русской раскладке), геймпад через XInput. Окно ровно 1600×1200 настоящих пикселей, Windows его при масштабе 150% не растягивает.
Подводные камни. Их было больше, чем у меня со Свитчем
Первый же запуск в облаке... и сразу ошибка внутри Wine: встроенный компилятор шейдеров упал на его HLSL. Переписывать шейдеры под Wine он не стал. Вместо этого скачал Electron (да, тот самый, на котором сделан Discord), вытащил оттуда настоящий d3dcompiler_47.dll от Microsoft и дальше тестировал уже с ним. Логика простая: у меня в Windows стоит ровно этот же файл, а я бы до такого не додумался и за сто лет.
Потом он часами... ну ладно, минутами гонял игру на программном рендере (от 5 до 40 FPS на двух ядрах) и разглядывал скриншоты демок. И нашёл у себя три бага:
Ствол при взгляде вниз превращался в красную призму, потому что у моделей был перевёрнут знак наклона.
Консоль и меню оказались невидимыми: шрифт создавался раньше, чем грузилась палитра, и получался прозрачным.
Окно открылось на втором мониторе, а он у меня сам 1600×1200, и окно 1600×1200 с заголовком туда физически не влезает. Теперь игра открывается на основном экране.
И последний, уже на моём железе. Я написал ему, что игра рендерится на встройке. Он полез в лог, а там чёрным по белому Direct3D 12 on NVIDIA GeForce RTX 5090 Laptop GPU... Просто второй монитор у меня подключён к встроенной графике, и готовый кадр копируется туда. На всякий случай он вшил в экзешник флаги NvOptimusEnablement и AmdPowerXpressRequestHighPerformance, по которым драйвер ноутбука сразу отдаёт игру дискретке.
Как он тестировал на моём компе
Вот тут я немного напрягся. Он сам положил в папку игры скрипт, сам открыл Проводник и сам дважды кликнул по exe. Игра прогнала демку (60 FPS, упёрлась в VSync), сделала два скриншота и вышла, а он прочитал лог. Меня в этой цепочке не было вообще. Ну, кроме момента, когда он попросил закрыть игру, потому что я её запустил сам и exe был занят.
Что в итоге
quake_dx12.exe весит около мегабайта, тянет только системные библиотеки Windows и рисует напрямую через DirectX 12. Никаких dgVoodoo, никаких обёрток. Рядом лежат pak0.pak из досовской демки, исходники (GPL требует).
Сделал ли я что‑то сам? Нашёл папку, написал промпт с ошибками и один раз закрыл игру.
Ну и прикрутил длсс 5. но об этом можно почитать в старых публикациях
P. S. Файлы на пощупать, сложил в свой домашний сайт. Т.к. не знаю можно ли класть ссылки на файлопомойки. А ради одного вайбкод проекта заводить гит — ну такое:‑)