aboutsummaryrefslogtreecommitdiff
path: root/docs/specs/material.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/specs/material.md')
-rw-r--r--docs/specs/material.md130
1 files changed, 130 insertions, 0 deletions
diff --git a/docs/specs/material.md b/docs/specs/material.md
new file mode 100644
index 0000000..cd7eea5
--- /dev/null
+++ b/docs/specs/material.md
@@ -0,0 +1,130 @@
+# Material (`MAT0`)
+
+`MAT0` описывает материал и его фазовую анимацию.
+
+Связанные страницы:
+
+- [Wear table (`WEAR`)](wear.md)
+- [Texture (`Texm`)](texture.md)
+- [Render pipeline](render.md)
+
+## 1. Контейнер
+
+- Тип ресурса: `0x3054414D` (`MAT0`).
+- Обычно хранится в `Material.lib`.
+- `attr1` используется как битовое поле runtime-флагов материала.
+- `attr2` задаёт версию заголовка payload.
+
+## 2. Бинарный layout
+
+```c
+struct Mat0Payload {
+ uint16_t phaseCount;
+ uint16_t animBlockCount; // должно быть < 20
+
+ // если attr2 >= 2
+ uint8_t metaA8;
+ uint8_t metaB8;
+ // если attr2 >= 3
+ uint32_t metaC32;
+ // если attr2 >= 4
+ uint32_t metaD32;
+
+ PhaseRecord34 phases[phaseCount];
+ AnimBlockRaw anim[animBlockCount];
+};
+```
+
+Если `attr2 < 2`, используются runtime-значения по умолчанию:
+
+- `metaA = 255`
+- `metaB = 255`
+- `metaC = 1.0f`
+- `metaD = 0`
+
+## 3. Фазы материала
+
+```c
+struct PhaseRecord34 {
+ uint8_t params[18];
+ char textureName[16];
+};
+```
+
+В рантайме запись разворачивается в структуру ~76 байт:
+
+- набор коэффициентов цвета/освещения/прозрачности;
+- индекс слота текстуры;
+- дополнительные целочисленные поля.
+
+`textureName`:
+
+- пустая строка -> фаза без текстуры (`texSlot = -1`);
+- непустая строка -> загрузка текстуры по имени.
+
+## 4. Анимационные блоки
+
+```c
+struct AnimBlockRaw {
+ uint32_t headerRaw; // mode = low 3 bits, interpMask = остальные
+ uint16_t keyCount;
+ KeyRaw keys[keyCount];
+};
+
+struct KeyRaw {
+ uint16_t k0;
+ uint16_t k1;
+ uint16_t k2; // opaque, сохранять 1:1
+};
+```
+
+`k2` нельзя удалять или нормализовать: это часть бинарного контракта.
+
+## 5. Выбор текущей фазы
+
+Материал выбирает фазу по времени и по режиму анимации блока:
+
+- loop;
+- ping-pong;
+- one-shot с clamp;
+- random-offset.
+
+При смешивании интерполируется только часть полей, остальные копируются из активной фазы.
+Для 1:1 совместимости важно сохранить эту выборочную интерполяцию.
+
+## 6. Загрузка и fallback
+
+При запросе материала по имени:
+
+1. Точный поиск по имени.
+2. Если не найдено — fallback на `DEFAULT`.
+3. Если `DEFAULT` отсутствует — используется запись с индексом `0`.
+
+## 7. Атрибуты и флаги
+
+Практически важные биты `attr1`:
+
+- бит загрузки текстурной фазы с расширенными флагами;
+- флаги аппаратного профиля;
+- 4-битный режим (`nibbleMode`);
+- дополнительный флаг material-поведения.
+
+Неизвестные биты должны сохраняться без изменений.
+
+## 8. Ограничения
+
+- `animBlockCount < 20`
+- `phaseCount` и фактический размер секции фаз должны совпадать
+- `textureName` должен быть NUL-terminated и укладываться в 16 байт
+
+## 9. Правила writer/editor
+
+1. Сохранять `attr1/attr2/attr3`.
+2. Не менять `metaA/B/C/D` без явного запроса.
+3. Сохранять opaque-поля анимации (включая `k2`) 1:1.
+4. Проверять выход за границы payload при парсинге.
+
+## 10. Статус валидации
+
+- Инварианты MAT0 зафиксированы в текущем toolchain проекта (`docs/specs` + `tools`).
+- В этом окружении нет полного игрового корпуса, поэтому статистика по всем материалам не пересчитывалась.