diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/reference/environment-effects.md | 50 | ||||
| -rw-r--r-- | docs/tomes/04-world.md | 24 | ||||
| -rw-r--r-- | docs/tomes/05-render.md | 54 | ||||
| -rw-r--r-- | docs/tomes/06-behavior.md | 22 |
4 files changed, 137 insertions, 13 deletions
diff --git a/docs/reference/environment-effects.md b/docs/reference/environment-effects.md index 078a222..0435a6a 100644 --- a/docs/reference/environment-effects.md +++ b/docs/reference/environment-effects.md @@ -104,6 +104,10 @@ N = round_even( координаты, и к каждой оси применяется floor-based wrap; 5. после wrap точка снова переводится в мир, а её хвост сбрасывается на голову. +Повторное обновление на том же времени имеет нулевой `dt`: позиция капли и +сохранённое начало хвоста остаются прежними. Хвост продвигается только при +положительном шаге; wrap по-прежнему сбрасывает его на голову. + Скорости не принадлежат системе координат камеры: ```text @@ -143,6 +147,24 @@ slot `+6c`): ширина `RECT` делится на горизонтальныÐ исходную таблицу знаков и минимальный depth fade `0.1`. Renderer сам решает, как загрузить этот квадрат и как смешать его материал. +## Точечный свет из opcode 1 + +Preview вычисляет generic Op1 отдельно от визуальных команд. Переданный +владельцем `command_time` сравнивается с началом и концом интервала из body +opcode 1; обе границы включены, а коэффициент выборки равен +`(command_time - start) / (end - start)`. Заголовочная длительность FXID не +заменяет этот интервал. Для нулевой ширины адаптер не создаёт кадр света, +поскольку у команды нет конечного коэффициента интерполяции. + +Позиция, направление, цвет и range интерполируются по концам команды. +Позиция и направление переводятся через основу родителя; направление после +этого нормализуется, а нулевой вектор остаётся нулевым. Range сохраняет +авторское значение без ограничения снизу. Типы Op1 `1`, `2`, `5`, `6` и `7` +выбирают point-light selector `1`; их native flags сохраняются. Типы `3` и +`4` выбирают другие классы записей LightManager и не попадают в generic список +точечного света. У `LightningEffect` выборка тех же полей использует отдельные +ограничение по длительности FXID и правила безопасной обработки. + ## Молния и звуковые события `decode_env_lightning_fxid` извлекает из FXID длительность, ссылки opcode 3 и @@ -285,6 +307,34 @@ Evaluator типа 2 принимает индекс context явно и учиÑ семена отдельных экземпляров лишь детерминированно заменяют process-global состояние и не воспроизводят общий порядок вызовов. +## Частицы Op8 + +`fparkan-fx::smoke` разбирает body Op8, хранит кольцевой пул команды и выдаёт +quad-ы с ориентацией к камере для активных слотов. Нативная нормализованная +фаза окна ограничивается диапазоном 0–1 и задаёт интервал проверки следующего события; +сравнение строгое (`schedule_base + interval < update_clock`). Все события +catch-up в одном обновлении проверяются по тому же нормализованному интервалу; +после события нативный код продвигает базу расписания интервалом, вычисленным +по сырой фазе эффекта, а возраст слота считает по нормализованному интервалу. +Когда фаза равна единственной границе окна, деление `0/0` даёт NaN, который +нативный unordered-путь сравнения ограничивает нулём. + +Нулевая база расписания служит признаком начального состояния: обновление +сохраняет текущую опору эмиттера и базу времени, не создавая частицу. Если +первое время равно нулю, следующее обновление повторно захватывает опору. При +событии скорость опоры считается от сохранённой позиции до текущей за время +от базы расписания; слот смещает сохранённую опору на `скорость * due_interval`. +Обновление без событий не переносит сохранённую опору к текущему владельцу. +Откат часов корректирует только базу расписания до текущего времени: слоты, +опора и три потока случайных +чисел не сбрасываются. + +Evaluator принимает отдельные начальные состояния для эмиттера, знаковых +отклонений и материала. Переход каждого потока совпадает с общим native LFSR, +но эти локальные seed не воспроизводят порядок process-global вызовов игры. +Предел 100000 событий catch-up — защитная граница evaluator-а; соответствующего +лимита в исследованном native цикле не обнаружено. + ## Что остаётся за владельцем `EnvironmentSystem` не извлекает камеру из renderer, не разрешает материалы diff --git a/docs/tomes/04-world.md b/docs/tomes/04-world.md index f9c0e67..e486e18 100644 --- a/docs/tomes/04-world.md +++ b/docs/tomes/04-world.md @@ -430,6 +430,30 @@ full 00000040 -> compact 2000 full 00200000 -> compact 8000 ``` +Бит `0x400` в маске грани рельефа управляет detail-текстурой. В `Terrain.dll` +метод `CShade` по смещению `+0x10` таблицы `0x10065108` ведёт к `0x10028A50`: +он читает `flags` по смещению `+0x3C` и проверяет бит в `0x10029191`. Ветка для +очищенного бита обнуляет указатель detail-текстуры в `0x10029427`. Затем +`Ngi32` применяет режим 1 или 7: для RGB stage 0 умножает текстуру на diffuse- +цвет, а stage 1 отключён. Alpha режима 1 берётся из texture, режима 7 — из +diffuse; на проверенных непрозрачных полосах основания это различие не меняет +цвет фрагмента. Текущий код сохраняет выбор в каждой полосе отрисовки рельефа: + +```rust +let terrain_base_only = first_face.flags.0 & 0x400 == 0; +``` + +Фрагментный шейдер пропускает умножение на detail-текстуру: + +```glsl +bool terrain_base_only = (mode & 16) != 0; +vec3 base_rgb = terrain_base_only ? base.rgb : 2.0 * base.rgb * detail.rgb; +``` + +В исходных картах бит установлен у всех 275 882 граней рельефа. У полос +основания, которые создаются процедурно при загрузке миссии, бит очищен; +именно поэтому им нужен этот вариант без detail-текстуры. + Для шестибитного material-поля используются full-биты `0x100`, `0x8000`, `0x10000`, `0x40000`, `0x80000` и `0x80`; они переходят соответственно в compact-биты `1`, `2`, `4`, `8`, `0x10`, `0x20`. diff --git a/docs/tomes/05-render.md b/docs/tomes/05-render.md index b04af31..3c4e346 100644 --- a/docs/tomes/05-render.md +++ b/docs/tomes/05-render.md @@ -363,11 +363,17 @@ world[n] = world[parent(n)] * local; ``` Статический Vulkan preview берёт начальный кадр узла из явной ссылки прототипа -на CTLD `.ctl`. Используются только включённые строки, а при повторе node ID -поздняя строка заменяет раннюю. Без `--static-animation-frame` preview применяет -эти настройки узлов; узлы без настройки остаются на кадре `0`. Явный -`--static-animation-frame N` переопределяет их и задаёт `N` всем узлам. -Результат — одна статическая поза, не обновление анимации, Control или AI. +на CTLD `.ctl`. Для поддерживаемых Control timeline и tag 21 он выполняет один +сэмпл при native clock `0`, передавая конечные type-1 значения разрешённых NDP +providers; неподдерживаемый режим/variable mapping и отсутствующий или +неразрешённый gate value возвращают preview к статическим CTLD bindings. +Используются только включённые строки, а при повторе node ID поздняя строка +заменяет раннюю. Без +`--static-animation-frame` preview применяет эти настройки узлов; узлы без +настройки остаются на кадре `0`. Явный `--static-animation-frame N` +переопределяет их и задаёт `N` всем узлам, пропуская Control-сэмпл. +Результат — одна стартовая статическая поза, не обновление анимации, Control +или AI по ходу кадров. MSH sampler выбирает type 19 frame округлением `(time - 0.5)` к ближайшему целому с ties-to-even, затем интерполирует выбранный type 8 key и следующий key в исходном `time`; это portable-вариант native x87 conversion в default @@ -625,15 +631,20 @@ Lightmap не является обычной diffuse texture. WEAR содерж отдельным slot или texture stage. Замена lightmap предварительным умножением в diffuse texture ломает LOD, atlas coordinates и динамическую модуляцию. -Vulkan preview строит projected shadows для выбранных зданий и роботов, -отбрасывает spheres вне шести clip-плоскостей с радиусом `sphere + 100` и +Vulkan preview строит проецируемые тени для объектов, отбрасывающих тени, +отбрасывает сферы вне шести clip-плоскостей с радиусом `sphere + 100` и сохраняет порядок видимых кандидатов; frame builder обрабатывает не более 20 -casters. Текущая реализация выделяет страницы в atlas `256 x 256` с 28 page -slots и использует одну smoothing pass. Вызов preview передаёт `fade = 1.0` и -LOD defaults: minimum LOD `1` и detail multiplier `1.0` отдельно для зданий и -роботов. Rust-путь не загружает `shade.cfg`: эти значения задаются кодом, а -параметры файла пока не влияют на preview. Проекция учитывает вклад -directional и point lights. +объектов. Текущая реализация выделяет страницы в atlas `256 x 256` с 28 page +slots и использует одно сглаживание. Preview применяет native defaults +`RobShadowsOn = true` и `BldShadowsOn = false`: объект kind `4` проверяет +первый флаг, остальные kinds — второй. Поэтому роботы BTLU остаются объектами, +отбрасывающими тени, а объекты FORT и STAT их не создают. Preview пока не +загружает `shade.cfg`, поэтому значения из пользовательского файла не меняют +список объектов, отбрасывающих тени. Проверка действует только на проецируемые +тени: отдельный список объектов для затенения солнца по-прежнему включает +FORT, BTLU и STAT. Вызов preview передаёт `fade = 1.0` и LOD defaults: +minimum LOD `1` и detail multiplier `1.0` отдельно для зданий и роботов. +Проекция учитывает вклад directional и point lights. Receiver projection обрезает projected quad по рёбрам треугольника. Native ray query descriptor в `+0x10` требует наличия всех переданных bits, а descriptor @@ -955,6 +966,23 @@ for (face, assignment) in mesh.faces.iter().zip(assignments.iter()) { } ``` +Подготовка BAS вынесена в `fparkan-terrain::build_basement_foundations`. +Функция получает внешние и внутренние кольца в порядке размещения, строит +упорядоченные пересечения внешней границы с текущей поверхностью и возвращает +исходные фрагменты рельефа вместе с треугольниками отмостки в одном наборе. +`TerrainWorld::with_basement_foundation` принимает этот набор во владение и +устанавливает те же координаты и маски в BVH высотных запросов и пересечений. +Предпросмотр миссии на Vulkan пока строит только LOD0: связывание BAS-записей +с этой подготовкой ещё не подключено, поэтому наличие API не означает, что +геометрия миссии уже обрезана. + +Внешнее кольцо должно лежать на области LOD0, а каждый его сегмент — оставаться +покрытым текущей поверхностью. Непокрытый сегмент или пересекающиеся контуры +дают ошибку; карта не остаётся частично обрезанной. Первичная нормализация +использует исходные грани и соседей LOD0, последующие пересечения и вырезания — +канонические фрагменты после предыдущих размещений. Соответствие динамических +соседей, создаваемых нативным движком, пока не моделируется. + ## Материалы ландшафта Рядом с `Land.msh` лежат `Land1.wea` и `Land2.wea`. Старший байт diff --git a/docs/tomes/06-behavior.md b/docs/tomes/06-behavior.md index e663389..d1af7ba 100644 --- a/docs/tomes/06-behavior.md +++ b/docs/tomes/06-behavior.md @@ -424,6 +424,15 @@ type 4, в том числе четыре `f_smalllight_y` с offsets 104–107 offsets 119–121. В `fr_l_gener.ctl` найдено 35 строк type 4, включая `f_gener_ball` с offset 85. +Control.dll `+0x8B10` передаёт указатель текущей записи диспетчеру `+0x2D4B0`. +Теги 2 и 5 направляются в общий читатель `+0x21D50`: таблица виртуальных методов +тега 2 (`+0x3CBD8`) вызывает его через обёртку `+0x29650`, а таблица тега 5 +(`+0x3CDF8`) указывает прямо на него в позиции `+0x1C`. Читатель потребляет +заголовок размером `0xB0` байт со счётчиком `u32` по `+0xAC`, затем `count` +значений `u32`, слово длины и, при ненулевой длине, строку с завершающим NUL; +указатель возврата указывает на следующую запись. Поэтому для тегов 2 и 5 подтверждён общий +структурный формат; смысл их полей пока не назначен. + Resolver прототипов хранит явную registry-ссылку на `.cpt` отдельно от ссылки на `.ctl`. Если строки type 4 разобраны и явная ссылка на CPT есть, подготовка читает ровно указанные archive/name; имя CPT не выводится из имени CTL. В CPT @@ -445,6 +454,19 @@ C0 равен 0, поэтому найденные offsets 104–107, 119–121 условий, загрузка FX materials, activation, выполнение FX opcodes и видимый рендер эффектов пока не реализованы. +После типизированных записей CTLD хранит 21 ссылку на группу эффектов. В +`fr_l_plant.ctl` первая ссылка равна `8`, остальные 20 содержат `u32::MAX`; за +ними расположены 13 таблиц групп. При разборе по адресу `+0x8B10` к каждой +ссылке, кроме `u32::MAX`, прибавляется число групп, зарегистрированных до +таблиц этого CTL; получившиеся индексы сохраняются в control mapping. При +событии `0x80000020` код по адресу `+0x7830` сразу выходит, если поле дескриптора +`+0xC0` равно нулю. Разбор по адресу `+0x8B10` вызывает диспетчер групп `+0x2800` +с индексом группы по умолчанию только при ненулевом `+0xC0`. Назначение поля +дескриптора и условия его заполнения на стороне producer пока неизвестны. +`initial_effect_group` хранит проверенную ссылку на группу по умолчанию. Это +поле описывает данные CTL и не выполняет activation, загрузку FX materials, +FX opcodes или рендер эффектов. + CPU-only обход `MISSIONS/Autodemo.00/data.tma` подготовил четыре CTL с 80 строками type 4 и четыре явных CPT-списка (всего 322 записи). Среди пар были `fortif.rlb/fr_l_plant.ctl` и `fortif.rlb/fr_l_plant.cpt` (155 точек), а также |
