EBLAN_ENGINE/TODO_ARTEM.md
Artvasil09 a1d1baa869 feat: complete engine and editor subsystems (Stages 1-5 from TODO_ARTEM)
- Stage 1: Eliminate fish-eye distortion with precomputed tangential ray offset table and fractional DDA depth
- Stage 2: Full asset management in EblanStudio (stb_image/stb_image_write, 128x128 BGRA texture packaging, WAV sound manager)
- Stage 3: Multi-level room streaming, LevelTransition/CELL_PORTAL trigger system, 16-frame screen fade to black
- Stage 4: 60Hz cutscene engine in pure x86 ASM (v4 binary track, waypoint camera motion, shortest-arc pan, CP1251 Russian subtitles, letterbox overlay, audio)
- Stage 5: EblanStudio cutscene timeline (F6) and windowless Live ASM Viewport over shared-memory IPC directly rendered into DX11
- Tooling & Tests: comprehensive regression test suite (94 editor + 107 engine tests), IPC tests, and cutscene demo
2026-10-22 16:24:22 +03:00

24 KiB
Raw Blame History

ТЕХНИЧЕСКОЕ ЗАДАНИЕ ДЛЯ АРТЕМА: EBLAN ENGINE 3D & EBLANSTUDIO

Назначение документа: Детальный план разработки следующих ключевых подсистем игрового 2.5D движка на ассемблере (EBLAN ENGINE 3D) и сопутствующего C++ визуального редактора (EblanStudio).
Целевой стек: x86 MASM32 (движок), C++17 + Dear ImGui + DirectX 11 (редактор).


Проверка реализации этапов 1–3 — 21.10.2026

  • Этап 1: тангенциальные углы лучей, единственная косинусная коррекция, DDA с 8 дробными битами до проекции. В регрессионной сцене прямая стена имеет одинаковую глубину во всех 320 столбцах.
  • Этап 2: PNG/JPG/BMP, BGRA и хромакей, безопасное создание и обновление пакета, стандартные слоты при первом импорте, WAV и манифесты. Портал не использует слот фонаря.
  • Этап 3: EBLN v3 с чтением v1/v2, полная проверка перед заменой комнаты, обработка ошибочного перехода, спавны, затемнение и защита от повторного срабатывания при появлении в портале. F5 работает с временной копией карт и ресурсов.
  • Регрессионные проверки: python tools/test_regressions.py. Ручная проверка интерфейса и длительный игровой прогон остаются отдельной проверкой качества.
  • Этапы 4 и 5 реализованы следующим изменением, см. статус ниже.

Реализация этапов 4–5 — 22.10.2026

  • Этап 4: бинарный трек EBLN v4, чистый ASM, линейные пролёты по точкам, повороты по кратчайшей дуге, паузы, русские субтитры CP1251, letterbox 2.35:1, WAV, затемнения и переходы. Автозапуск при входе, C для повтора и Tab для пропуска; управление игроком блокируется на время сцены. Старые карты v1/v2/v3 читаются.
  • Этап 5: F6 открывает таймлайн с дорожками, перетаскиванием ключей, списком команд, инспектором, установкой точек на карте, автозапуском, Undo/Redo и сохранением. Предпросмотр и перемотка показывают сцену глазами камеры во встроенном игровом виде, а на карте — траекторию. F5 запускает полную игру и связанные комнаты с проверкой WAV.
  • Пример examples/cutscene_demo/run_demo.bat показывает пролёт, текст, звук и переход во вторую комнату; основные карты проекта он не меняет.
  • Регрессионный набор расширен проверками формата v4, проигрывателей ASM/C++, оверлея, переходов, редактора и покадрового совпадения состояния.
  • Уточнения исходного ТЗ: сериализуемый dataPtr заменён на dataId, строки хранятся в отдельном пуле; движение задаётся длительностью. Использованы линейные waypoints, камера во время пролёта не сталкивается со стенами. WAV воспроизводится одним каналом PlaySoundA без внешних библиотек.

Завершение редактора и исправление F5 — 22.10.2026

  • Встроен игровой вид, который получает кадры от настоящего ASM-рендерера. Доступны режимы «Рядом», «Игровой вид», «Карта», свободный осмотр и камера таймлайна. Изменения стен, цветов, спрайтов и текстур видны без сохранения.
  • Исправлена блокировка F5/F6 при захвате клавиатуры интерфейсом ImGui. Ошибки запуска показываются отдельным диалогом. Начальная карта открывается относительно расположения редактора, независимо от рабочей папки.
  • Автопроверки проверяют горячие клавиши с фокусом в интерфейсе, реальную передачу кадров из x86 ASM в x64 редактор и DX11, обновление геометрии, перемотку кат-сцены, точное совпадение пикселей с отдельным движком и освобождение процесса рендерера.
  • Все пять этапов реализованы. Предпросмотр редактора останавливается на команде перехода между комнатами; полный сценарий переходов и игровой ввод доступны через F5. Это ограничение предпросмотра, а не отсутствие переходов в движке.
  • Итоговая проверка: 94/94 сценария редактора и 107/107 сценариев ASM, совпадение всех 320 углов лучей, покадровое совпадение проигрывателей и точное совпадение пикселей встроенного вида с движком. Обе программы пересобраны. Исходные ресурсы проекта при проверках остались без изменений. Ручное управление окнами было остановлено пользователем через Esc; полный визуальный прогон интерфейса не завершён.

Разделы ниже сохраняют исходное ТЗ и описание прежних проблем как историю требований. Актуальные формат и поведение описаны в AGENTS.md и docs/ENGINE_ARCHITECTURE.md.


📋 Оглавление

  1. Задача 1: Устранение Fish-Eye эффекта и фикс рендера
  2. Задача 2: Полноценный импорт ассетов в EblanStudio
  3. Задача 3: Многоуровневые локации и стриминг подуровней
  4. Задача 4: Система кат-сцен и скриптовых последовательностей
  5. Чек-лист готовности и порядок реализации

Задача 1: Устранение Fish-Eye эффекта и фикс рендера [ВЫПОЛНЕНО / DONE]

1.1. Суть проблемы в текущем коде

В файле include/engine_raycaster.inc лучи выпускаются с равномерным шагом угла:

; Линейное распределение углов по ширине экрана:
rayAngle = playerAngle - FOV_HALF + (screenX * FOV_ANGLES / SCREEN_W)
  • Геометрическое искажение: когда экран плоский, равные интервалы пикселей по оси X соответствуют разным угловым приращениям (\tan \theta \ne \theta). Лучи, выпущенные с постоянным шагом угла, проецируются на изогнутую цилиндрическую поверхность.
  • Артефакт "рыбьего глаза": стены по краям экрана кажутся вздутыми, а при повороте камеры прямые стены начинают "плавать" и изгибаться волной.
  • Ошибки DDA: в секции apply_fisheye_fix расстояние повторно умножается на косинус, что при некоторых углах дает артефакт двойного искажения.

1.2. Решение: Тангенциальная коррекция углов лучей

Сохраняя радиальную архитектуру лучей (512 дискретных углов), пересчитать угол каждого столбца x \in [0..319] через тангенс:

\theta_x = \text{playerAngle} + \arctan\left(\left(\frac{2x}{\text{SCREEN\_W}} - 1\right) \cdot \tan\left(\frac{\text{FOV}}{2}\right)\right)

Что нужно сделать:

  1. Таблица предвычисленных смещений лучей (tableRayAngleOffset):
    • В include/engine_math.inc при вызове InitMathTables сгенерировать через FPU таблицу из 320 значений DWORD.
    • Для каждого столбца x:
      float cameraX = (2.0f * x / 320.0f) - 1.0f;
      float radOffset = atanf(cameraX * tanf(FOV_RAD / 2.0f));
      int angleOffset = (int)roundf(radOffset * 512.0f / (2.0f * M_PI));
      tableRayAngleOffset[x] = angleOffset;
      
  2. Использование в цикле лучей (include/engine_raycaster.inc):
    • Заменить линейный расчет угла на быстрый табличный:
      mov eax, screenX
      mov edx, [tableRayAngleOffset + eax*4]
      add edx, playerAngle
      and edx, ANGLE_MASK
      mov rayAngle, edx
      
  3. Коррекция перпендикулярного расстояния:
    • Перпендикулярная дистанция:
      \text{perpWallDist} = \text{rawDist} \cdot \cos(\text{rayAngle} - \text{playerAngle})
    • Убедиться, что sideDistX и deltaDistX не накапливают масштабирующий множитель 64 дважды при вычислении текстурных координат (texX).

Задача 2: Полноценный импорт ассетов в EblanStudio [ВЫПОЛНЕНО / DONE]

2.1. Требования

У Артема и дизайнеров уровней должна быть возможность в пару кликов мыши в редакторе загружать свои изображения (PNG) и звуки (WAV) без ручного запуска сторонних питоновских скриптов.

2.2. Архитектура Asset Manager в C++ (editor/)

  1. Библиотека декодирования картинок:
    • Подключить stb_image.h (однофайловая C++ библиотека без внешних зависимостей) в папку editor/src/stb_image.h.
    • Загрузка любого PNG, JPG, BMP в 32-битный массив пикселей:
      int w, h, channels;
      unsigned char* data = stbi_load(filename, &w, &h, &channels, 4); // RGBA32
      
  2. Диалоговые окна выбора файлов Win32:
    • Использовать стандартный GetOpenFileNameA для выбора PNG/WAV файлов.
  3. Конвертация и упаковка текстур (Wall Textures & Sprites):
    • Входное изображение ресемплится/обрезается до стандарта движка: 128x128 пикселей.
    • Цветовые каналы конвертируются из RGBA в BGRA (00RRGGBBh), где для прозрачных спрайтов альфа = 0 заменяется на ключевой цвет мадженты 0x00FF00FF (COLOR_CHROMA_KEY).
    • Автоматическая перезапись и сохранение в assets/textures/texturepack.bin (заголовок EBTX + 16 слотов по 65536 байт).
  4. Интерфейс в EblanStudio:
    • Вкладка меню: Ассеты -> Импорт текстуры стены... (выбор слота 1..15).
    • Вкладка меню: Ассеты -> Импорт спрайта... (добавление в список доступных спрайтов).
    • Вкладка меню: Ассеты -> Импорт аудио (WAV)... (копирование звука в assets/sounds/ с автоматической генерацией алиаса MCI).
    • Превью текстуры прямо в палитре тайлов в левой панели редактора.


Задача 3: Многоуровневые локации и стриминг подуровней [ВЫПОЛНЕНО / DONE]

3.1. Секторно-комнатная модель уровней

Вместо одной изолированной сетки 32 \times 32 мир организуется как граф связанных секторов (комнат).

  • Каждый сектор — это отдельный бинарный файл подуровня (например, map.dat, sublevel_02.dat) со своей сеткой 32 \times 32, цветами пола/потолка и локальными спрайтами.
  • Сектора соединяются Порталами / Дверями перехода (Sector Portals).

3.2. Структура данных перехода (Portal Transition)

В заголовок и сущности карты добавлен тип CELL_PORTAL = 10 и структура:

// Структура перехода между подуровнями (42 байта packed)
struct LevelTransition {
    uint8_t  triggerCellX;       // Координата X двери/триггера в текущем секторе
    uint8_t  triggerCellY;       // Координата Y двери/триггера в текущем секторе
    char     targetMap[32];      // Имя целевого файла: "sublevel_02.dat"
    uint16_t targetSpawnX;       // Точка появления в новом секторе (X)
    uint16_t targetSpawnY;       // Точка появления в новом секторе (Y)
    uint16_t targetAngle;        // Направление взгляда после перехода
    uint8_t  fadeEffect;         // 0 = мгновенно, 1 = затемнение экрана (Fade to Black)
    uint8_t  reserved;           // Выравнивание
};

3.3. Логика динамической подгрузки и выгрузки в Ассемблере

В include/engine_map.inc:

  1. Процедура перехода SwitchSublevel(szNextMap, spawnX, spawnY, spawnAngle, fadeEffect):
    • Шаг 1 (Fade Out): Плавное затемнение буфера экрана screenBuffer за 16 кадров с помощью целочисленного масштабирования цветовых каналов RGB.
    • Шаг 2 (Unload): Очистка текущих спрайтов (mov spriteCount, 0), сброс флагов и переходных триггеров.
    • Шаг 3 (Load): Чтение нового файла карты через LoadSublevelBinary в gameMap, обновление цветов неба/пола (mapCeilingColor, mapFloorColor), загрузка массива спрайтов нового сектора.
    • Шаг 4 (Spawn): Установка новых координат игрока playerX = spawnX * 64 + 32, playerY = spawnY * 64 + 32, playerAngle = spawnAngle.
    • Шаг 5 (Fade In): Плавное 16-кадровое осветление экрана.
  2. Память и производительность:
    • Постоянный объем оперативной памяти (~1-2 МБ), буферы очищаются и заполняются новым сектором на лету, позволяя создавать бесконечные цепочки и комплексы комнат.
    • Во время обычного геймплея оверхед пост-процесса затемнения равен нулю (cmp fadeState, 0; je fade_done).
  3. Интеграция в EblanStudio:
    • Добавлен тайл 10. Портал перехода с неоново-фиолетовой палитрой и меткой портала на 2D-сетке.
    • Инспектор свойств перехода: выбор файла целевого подуровня (.dat), кнопка обзора файловой системы, слайдеры целевого спавна и угла, переключатель Fade to Black, быстрое удаление и кнопка мгновенного перехода к подуровню в редакторе.
    • Поддержка сериализации и десериализации переходов в бинарный формат с сохранением 100% обратной совместимости.

Задача 4: Система кат-сцен и скриптовых последовательностей [ВЫПОЛНЕНО / DONE]

4.1. Архитектура: Бинарный трек событий (Keyframe Track)

Кат-сцена представляет собой упорядоченный во времени список событий (Action Track). Во время кат-сцены управление игрока блокируется, а виртуальный режиссер интерполирует камеру, спавнит звуки и выводит диалоговые субтитры.

4.2. Формат команд кат-сцены

Каждая команда — это фиксированная 16-байтовая структура:

enum CutsceneOpCode : uint8_t {
    OP_END = 0,             // Конец кат-сцены, возврат управления
    OP_WAIT,                // Ждать N кадров/тиков
    OP_MOVE_CAM_TO,         // Плавное перемещение камеры в (X, Y) со скоростью V
    OP_PAN_CAM_TO,          // Плавный поворот камеры на угол Angle
    OP_SHOW_SUBTITLE,       // Вывести текст субтитра на экране (ID строки)
    OP_HIDE_SUBTITLE,       // Скрыть субтитры
    OP_PLAY_SOUND,          // Проиграть звук (WAV алиас)
    OP_FADE_SCREEN,         // Затемнить / осветлить экран
    OP_CHANGE_SUBLEVEL      // Инициировать переход на другой подуровень
};

struct CutsceneEvent {
    uint16_t tickTimestamp;  // Кадр запуска от старта сцены
    uint8_t  opCode;         // Тип команды (CutsceneOpCode)
    uint8_t  param8;         // Доп. байт параметров (напр. флаг fade)
    int32_t  paramA;         // Целевой X / угол / длительность
    int32_t  paramB;         // Целевой Y / скорость
    int32_t  dataPtr;        // Указатель на текст / имя звука
};

4.3. Реализация в движке (MASM32)

  1. Флаг состояния isCutsceneActive:DWORD:
    • Когда isCutsceneActive == 1, в PollInput игнорируются клавиши WASD и стрелочки.
  2. Интерполятор камеры UpdateCutscene:
    • Вызывается в UpdatePlayer.
    • Если задано targetCamX, плавно сдвигает playerX к цели:
      ; Движение playerX -> targetCamX
      mov eax, targetCamX
      sub eax, playerX
      ; нормализация шага и добавление скорости
      
    • Аналогично для угла поворота playerAngle по кратчайшей дуге окружности 512.
  3. Отрисовка 2D-субтитров:
    • В include/engine_render2d.inc использовать существующий DrawString8x8 для вывода полупрозрачной плашки внизу экрана (Letterbox 2.35:1) и текста диалогов с центрированием.

4.4. Инструментарий в EblanStudio

  • Добавить в редактор панель "Cutscene Timeline":
    • Горизонтальная шкала времени (в секундах / кадрах).
    • Кнопки добавления ключевых точек: [+ Камера], [+ Текст], [+ Звук], [+ Переход].
    • Возможность кликом по карте расставить контрольные точки пролета камеры (Spline/Waypoints).
    • Кнопка предпросмотра пролета прямо в окне редактора.

Чек-лист готовности и порядок реализации

Этап Задача Затронутые файлы Ожидаемый результат
Этап 1 — готово Исправление Fish-Eye и угла лучей include/engine_math.inc, include/engine_raycaster.inc Стены остаются ровными по краям экрана, нет искажения при вращении камеры.
Этап 2 — готово Импорт текстур и спрайтов в редакторе editor/src/stb_image.h, editor/src/editor_app.cpp Кнопка импорта в GUI загружает PNG и обновляет assets/textures/texturepack.bin.
Этап 3 — готово Система связанных секторов (комнат) editor/src/level_format.h, include/engine_map.inc Переход между комнатами по триггеру с выгрузкой старой карты и загрузкой новой.
Этап 4 — готово Движок кат-сцен и диалогов include/engine_cutscene.inc, include/engine_data.inc, main.asm Пролёт камеры по ключевым точкам, субтитры, звук, затемнения, переходы, блокировка инпута.
Этап 5 — готово Визуальный таймлайн в EblanStudio editor/src/editor_cutscene.inl, editor/src/editor_viewport.inl, editor/src/cutscene_preview.h Редактирование траектории и сценария, предпросмотр игрового вида внутри редактора, Undo/Redo, F5 для полной игры.

Файл подготовлен и структурирован для передачи в работу Артему.