aboutsummaryrefslogtreecommitdiff
path: root/docs/reference
diff options
context:
space:
mode:
Diffstat (limited to 'docs/reference')
-rw-r--r--docs/reference/environment-effects.md34
-rw-r--r--docs/reference/render-frame.md57
2 files changed, 75 insertions, 16 deletions
diff --git a/docs/reference/environment-effects.md b/docs/reference/environment-effects.md
index f3ecfb4..0e709d9 100644
--- a/docs/reference/environment-effects.md
+++ b/docs/reference/environment-effects.md
@@ -416,16 +416,38 @@ RVA `0x93D0`, ветка mode 1 с `0x9739`, сборка столбцов `0x97
XY, ненулевой выбирает статические quad/cap координаты. Op4 вычисляет локальное
расстояние камеры тем же component-wise projection, что использует native path.
-FX-команды используют общий preview clock и ограниченный набор time modes:
-mode 0 оставляет фазу равной нулю, mode 1 вычисляет `elapsed / duration` без
-зажатия, mode 2 повторяет цикл. Header flags `0x200` и `0x20` преобразуют эту
-фазу; command path `0x8120` зажимает результат только после преобразований.
+FX-команды одной Control-строки используют общие часы экземпляра
+`fparkan_fx::clock::FxInstanceClock`. Время хранится в миллисекундах `f32`,
+отдельно от длительности документа: mode 0 возвращает постоянную фазу
+(при создании ноль), mode 1 — `(now − origin) / duration`, mode 2 повторяет
+цикл, mode 3 возвращает `1 − (now − origin) / duration`.
+Header flags `0x200` и `0x20` преобразуют незажатую фазу; command path
+`0x8120` зажимает результат только после преобразований.
+Вызов `set_time` меняет начало отсчёта и режим экземпляра, сохраняя режим
+документа. Запрос перезапуска (`Effect.dll` RVA `0x7B40`, instance bit `0x20`)
+срабатывает после конца текущего времени жизни: следующий update начинает
+новый цикл в своём времени и возвращает режим документа. Это отдельный флаг,
+не header `0x20`, складывающий фазу треугольником. Правила режимов, gates
+`0x80/0x100` и установления времени сверены вызовом эталонной DLL с x87 CW
+`0x007F`; отложенный переход закреплён Rust-тестом по ветви update `0x8120`.
+Все экземпляры статического preview пока создаются в момент ноль; геометрия,
+свет и звук получают одну фазу на обновление сцены. Команды Control ещё не
+меняют эти часы, а нативная очередь обновления с шагом 50 ms не моделируется.
+В [эталонной Effect.dll](original-binaries.md) RVA `0x5C60` режимы 4–17
+читают состояние владельца или провайдера; режим 14 тоже входит в эту группу.
+Пропуски при расширении выбранных начальных Control-строк учитываются по
+командам: `control_fx_requires_game_state` для этих режимов и
+`control_fx_unsupported` для остальных непреобразованных команд. Диагностика
+сохраняет причину, ресурс, объект, компонент, строку и номер команды.
+`control_fx_invalid_documents` отдельно считает неразобранные FXID, где число
+команд неизвестно. Счётчики суммируются по компонентам миссии; они не заменяют
+учёт ещё не выбранных Control-групп и условных строк в фазе G.
Effect renderer проверяет header bit `0x800` только при
render selector 0; native AniMesh component path был захвачен с selector 1,
поэтому preview использует selector 1 и не подавляет такие visual commands.
Этот capture также показал `0xD00` FX entries в 53-entry manager. Динамическое
-состояние manager `A8`, связанное с header gate и фактической FX phase, пока не
-моделируется. Header bit `0x10` относится к activation lifecycle и сам по себе
+состояние manager `A8` пока заменено нулём; экземпляры с gates `0x80/0x100`
+считаются в `control_fx_manager_flag_stub`. Header bit `0x10` относится к activation lifecycle и сам по себе
не отключает draw.
Header jitter и random shift хранятся один раз на Control row и совместно
применяются к его sibling-командам; отдельный детерминированный поток каждой
diff --git a/docs/reference/render-frame.md b/docs/reference/render-frame.md
index df3f248..ebe3971 100644
--- a/docs/reference/render-frame.md
+++ b/docs/reference/render-frame.md
@@ -6,6 +6,11 @@
## Порядок кадра
+Сам рельеф образует полноценную графическую сцену: список размещённых объектов
+может быть пустым. Наличие MSH-компонентов объектов не является условием
+отрисовки карты. Проверочные TMA без объектов позволяют отдельно загружать
+карты ресурсов, для которых в установленной игре нет штатной миссии.
+
```text
системные сообщения и ввод
-> расчёт симуляции
@@ -63,13 +68,24 @@ RVA `0x1B0F0`, заменяет diffuse alpha пакета без type 16 с bat
Скаляр камеры в шестом float getter `0x4F5F0` и поле CShade `+0xBB4`
проверены в работающем оригинале: оба содержат текущий горизонтальный FOV.
-`legacy_msh_portal_alpha` хранит кривую в `fparkan-render`. Приложение пока
-берёт первую индексированную вершину своего диапазона и обычный `sqrt`,
-поэтому выбор вершины после native CPU clipping и точность `RSQRTSS` не
-воспроизводятся. Счётчик `render_coverage portal_fade_packet_selection_approx`
-показывает число таких диапазонов. Поток type 16 сохраняет прежний отдельный
-путь и ещё не декодирован. Это ограничивает приёмку на частично отсечённых
-порталах и не позволяет считать интерьер принятой эталонной сценой.
+`legacy_msh_portal_alpha` хранит кривую в `fparkan-render`. Её опорная вершина
+принадлежит входному пакету: выбирать вместо неё первую видимую точку нельзя.
+В живом краевом ракурсе AutoDemo первая вершина окна находится за правой
+границей viewport (`NDC x ≈ 1,048`), а следующая — внутри (`x ≈ 0,815`).
+Оригинал всё равно использует первую: расстояние `106,74783` даёт alpha
+`0,51991343`. Выбор следующей изменил бы alpha примерно на `0,026`.
+Передача пакета renderer-у происходит после записи этой alpha.
+
+Адаптер изолирует инструкцию `RSQRTSS`; на x86-64 расстояние и alpha этого
+ракурса совпадают с оригиналом побитно. Обычный `sqrt` давал alpha
+`0,5196797`: при упаковке прозрачности этого достаточно для отличия отдельных
+пикселей. Прежнее предположение о выборе вершины после clipping и связанный
+счётчик `portal_fade_packet_selection_approx` удалены. На других архитектурах
+сохраняется переносимый корень с явным `packet_distance_native_rsqrt_unsupported`;
+совпадение камеры с вершиной использует нулевую дистанцию и
+`packet_zero_distance_fallback` вместо native `0 × infinity`.
+Поток type 16 ещё не декодирован. Проверка краевого окна не закрывает остальные
+внутренние ракурсы завода.
## Дистанционная кривая тумана
@@ -146,9 +162,8 @@ raw-флаге `Batch20` `0x0008` получает переопределениÐ
материал; alpha `0` временно задаёт число индексов `0`, а при очистке
переопределения исходное число индексов восстанавливается.
-Fade обновляется с камерой каждый кадр. Открыт выбор первой принятой вершины
-после native CPU clipping: приложение пока берёт первую индексированную
-вершину диапазона и считает это приближение в `render_coverage`.
+Fade обновляется с камерой каждый кадр и сохраняет исходную опорную вершину
+диапазона, в том числе когда часть окна выходит за границу экрана.
В превью с фиксированной камерой диапазоны туманности и звёзд, купола и облаков
явно помечаются как прозрачный фон. Непрозрачные диапазоны мира остаются на
@@ -213,6 +228,22 @@ RVA `0x4EBE0` использует соглашение о вызовах `__std
`REFLECTION_SHIFTED`. Это свидетельство ABI фабрики, а не восстановленный
контракт матрицы вида или проекции.
+## Представление готового кадра
+
+Vulkan сохраняет явно выбранный режим, если поверхность его поддерживает.
+Приложение предпочитает MAILBOX: готовый новый кадр заменяет ожидающий,
+а показ остаётся привязан к развёртке. При отсутствии MAILBOX выбирается
+IMMEDIATE, затем FIFO. IMMEDIATE допускает разрывы изображения, зато не
+навязывает ожидание вертикальной развёртки; FIFO остаётся запасным режимом.
+Семантика режимов описана в [спецификации Vulkan](https://docs.vulkan.org/refpages/latest/refpages/source/VkPresentModeKHR.html).
+
+Оконная ветка GOG Ngi32.dll (SHA-256 из [таблицы модулей](original-binaries.md))
+по RVA `0x6E1B` вызывает `IDirectDrawSurface7::Blt` с `DDBLT_WAIT`.
+Эта ветка наблюдалась при нативных захватах. Флаг ждёт готовности блиттера,
+а не задаёт интервал развёртки — см. [описание Microsoft](https://learn.microsoft.com/en-us/windows/win32/api/ddraw/nf-ddraw-idirectdrawsurface7-blt).
+Современный композитор и драйвер всё равно могут влиять на фактический показ;
+это правило выбора API, а не гарантия одинаковой задержки двух движков.
+
## Предпросмотр по захвату камеры D3D7
`fparkan-game --legacy-camera-capture <json>` принимает матрицу камеры
@@ -348,3 +379,9 @@ D3D7 в `fparkan-render`, а затем один раз меняет знак в
каналов не определяет. Последовательность не содержит структурированных ID
видимых объектов, списка элементов отрисовки, ключей конвейера, матриц или
хэшей промежуточных буферов.
+
+При преобразовании кадра в PNG сохраняется исходный RGB, а прозрачность
+выключается: окно показывает готовое непрозрачное изображение. Альфа-канал
+GPU может содержать результат смешивания поверхностей; повторное применение
+его к готовому цвету затемнило бы кадр ещё раз. Поэтому конвертер и сборщик
+сравнительных пар игнорируют эту альфу, а raw-файл сохраняют без изменений.