1
mirror of https://github.com/sampletext32/ParkanPlayground.git synced 2025-12-11 04:51:21 +04:00
Files
parkan-playground/ParkanPlayground/MSH_FORMAT.md
bird_egop a8536f938d fxid
2025-12-09 02:32:32 +03:00

351 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Документация формата MSH
Формат `.msh` используется игрой Parkan: Железная стратегия (1998) для хранения 3D-мешей.
MSH файлы — это NRes архивы, содержащие несколько типизированных компонентов.
## Обзор
Существует **два варианта** формата MSH:
| Вариант | Применение | Ключевые компоненты | Хранение треугольников |
|---------|------------|---------------------|------------------------|
| **Модель** | Роботы, здания, объекты | 06, 0D, 07 | Индексированные треугольники |
| **Ландшафт** | Террейн | 0B, 15 | Прямые треугольники |
### Автоопределение типа
```
Модель: Есть компонент 06 (индексы) И 0D (батчи)
Ландшафт: Есть компонент 0B (материалы) И НЕТ компонента 06
```
---
## Сводка компонентов
| Тип | Название | Размер элемента | Описание |
|:---:|----------|:---------------:|----------|
| 01 | Pieces | 38 (0x26) | Части меша / тайлы с LOD-ссылками |
| 02 | Submeshes | 68 (0x44) | LOD части с баундинг-боксами |
| 03 | Vertices | 12 (0x0C) | Позиции вершин (Vector3) |
| 04 | неизвестно | 4 | (неизвестно) |
| 05 | неизвестно | 4 | (неизвестно) |
| 06 | Indices | 2 | Индексы вершин треугольников (только Модель) |
| 07 | неизвестно | 16 | (только Модель) |
| 08 | Animations | 4 | Кейфреймы анимации меша |
| 0A | ExternalRefs | переменный | Внешние ссылки на меши (строки) |
| 0B | неизвестно | 4 | неизвестно (только Ландшафт) |
| 0D | неизвестно | 20 (0x14) | неизвестно (только Модель) |
| 0E | неизвестно | 4 | неизвестно (только Ландшафт) |
| 12 | MicrotextureMap | 4 | неизвестно |
| 13 | ShortAnims | 2 | Короткие индексы анимаций |
| 15 | неизвестно | 28 (0x1C) | неизвестно |
---
## Поток данных
### Модель (роботы, здания)
```
Компонент 01 (Pieces - части)
└─► Lod[n] ──► Компонент 02 (индекс сабмеша)
├─► StartIndexIn07 ──► Компонент 07 (данные на треугольник)
└─► StartOffsetIn0d:ByteLengthIn0D ──► Компонент 0D (батчи)
├─► IndexInto06:CountOf06 ──► Компонент 06 (индексы)
│ │
│ └─► Компонент 03 (вершины)
└─► IndexInto03 (базовое смещение вершины)
```
### Ландшафт (террейн)
```
Компонент 01 (Тайлы, обычно 16×16 = 256)
└─► Lod[n] ──► Компонент 02 (индекс сабмеша)
└─► StartIndexIn07:CountIn07 ──► Компонент 15 (треугольники)
└─► Vertex1/2/3Index ──► Компонент 03 (вершины)
└─► StartIndexIn07:CountIn07 ──► Компонент 0B (материалы, параллельно 15)
```
**Важно:** В ландшафтных мешах поля `StartIndexIn07` и `CountIn07` в Компоненте 02
используются для индексации в Компонент 15 (треугольники), а не в Компонент 07.
---
## Структуры компонентов
### Компонент 01 - Pieces (0x26 = 38 байт)
Определяет части меша (для моделей) или тайлы террейна (для ландшафтов).
| Смещение | Размер | Тип | Поле | Описание |
|:--------:|:------:|:---:|------|----------|
| 0x00 | 1 | byte | Type1 | Флаги типа части |
| 0x01 | 1 | byte | Type2 | Дополнительные флаги |
| 0x02 | 2 | int16 | ParentIndex | Индекс родителя (-1 = корень) |
| 0x04 | 2 | int16 | OffsetIntoFile13 | Смещение в короткие анимации |
| 0x06 | 2 | int16 | IndexInFile08 | Индекс в анимации |
| 0x08 | 30 | ushort[15] | Lod | Индексы сабмешей по LOD-уровням (0xFFFF = не используется) |
**Ландшафт:** 256 тайлов в сетке 16×16. Каждый тайл имеет 2 LOD (индексы 0-255 и 256-511).
---
### Компонент 02 - Submeshes (Заголовок: 0x8C = 140 байт, Элемент: 0x44 = 68 байт)
#### Заголовок (140 байт)
| Смещение | Размер | Тип | Поле | Описание |
|:--------:|:------:|:---:|------|----------|
| 0x00 | 96 | Vector3[8] | BoundingBox | 8-точечный баундинг-бокс |
| 0x60 | 12 | Vector3 | Center | Центральная точка |
| 0x6C | 4 | float | CenterW | W-компонента |
| 0x70 | 12 | Vector3 | Bottom | Нижняя точка |
| 0x7C | 12 | Vector3 | Top | Верхняя точка |
| 0x88 | 4 | float | XYRadius | Радиус в плоскости XY |
#### Элемент (68 байт)
| Смещение | Размер | Тип | Поле | Описание |
|:--------:|:------:|:---:|------|----------|
| 0x00 | 2 | ushort | StartIndexIn07 | **Модель:** Начальный индекс в Компоненте 07<br>**Ландшафт:** Начальный индекс треугольника в Компоненте 15 |
| 0x02 | 2 | ushort | CountIn07 | **Модель:** Количество в Компоненте 07<br>**Ландшафт:** Количество треугольников |
| 0x04 | 2 | ushort | StartOffsetIn0d | Начальное смещение в Компоненте 0D (только Модель) |
| 0x06 | 2 | ushort | ByteLengthIn0D | Количество батчей в Компоненте 0D (только Модель) |
| 0x08 | 12 | Vector3 | LocalMinimum | Минимум локального баундинг-бокса |
| 0x14 | 12 | Vector3 | LocalMaximum | Максимум локального баундинг-бокса |
| 0x20 | 12 | Vector3 | Center | Центр сабмеша |
| 0x2C | 12 | Vector3 | Vector4 | Неизвестно |
| 0x38 | 12 | Vector3 | Vector5 | Неизвестно |
---
### Компонент 03 - Vertices (0x0C = 12 байт)
| Смещение | Размер | Тип | Поле | Описание |
|:--------:|:------:|:---:|------|----------|
| 0x00 | 4 | float | X | Координата X |
| 0x04 | 4 | float | Y | Координата Y |
| 0x08 | 4 | float | Z | Координата Z |
---
### Компонент 06 - Indices (2 байта) - Только Модель
Массив `ushort` значений — индексы вершин треугольников.
Используются группами по 3 для каждого треугольника. Ссылки через батчи Компонента 0D.
---
### Компонент 07 - Triangle Data (0x10 = 16 байт) - Только Модель
Данные рендеринга на каждый треугольник.
| Смещение | Размер | Тип | Поле | Описание |
|:--------:|:------:|:---:|------|----------|
| 0x00 | 2 | ushort | Flags | Флаги рендера |
| 0x02 | 2 | ushort | Magic02 | Неизвестно |
| 0x04 | 2 | ushort | Magic04 | Неизвестно |
| 0x06 | 2 | ushort | Magic06 | Неизвестно |
| 0x08 | 2 | int16 | OffsetX | Нормализованный X (÷32767 для -1..1) |
| 0x0A | 2 | int16 | OffsetY | Нормализованный Y (÷32767 для -1..1) |
| 0x0C | 2 | int16 | OffsetZ | Нормализованный Z (÷32767 для -1..1) |
| 0x0E | 2 | ushort | Magic14 | Неизвестно |
---
### Компонент 0B - Material Data (4 байта) - Только Ландшафт
Информация о материале/текстуре на каждый треугольник. Параллельный массив к Компоненту 15.
| Смещение | Размер | Тип | Поле | Описание |
|:--------:|:------:|:---:|------|----------|
| 0x00 | 2 | ushort | HighWord | Индекс материала/текстуры |
| 0x02 | 2 | ushort | LowWord | Индекс треугольника (последовательный) |
---
### Компонент 0D - Draw Batches (0x14 = 20 байт) - Только Модель
Определяет батчи вызовов отрисовки.
| Смещение | Размер | Тип | Поле | Описание |
|:--------:|:------:|:---:|------|----------|
| 0x00 | 2 | ushort | Flags | Флаги батча |
| 0x02 | 2 | - | Padding | - |
| 0x04 | 1 | byte | Magic04 | Неизвестно |
| 0x05 | 1 | byte | Magic05 | Неизвестно |
| 0x06 | 2 | ushort | Magic06 | Неизвестно |
| 0x08 | 2 | ushort | CountOf06 | Количество индексов для отрисовки |
| 0x0A | 4 | int32 | IndexInto06 | Начальный индекс в Компоненте 06 |
| 0x0E | 2 | ushort | CountOf03 | Количество вершин |
| 0x10 | 4 | int32 | IndexInto03 | Базовое смещение вершины в Компоненте 03 |
---
### Компонент 15 - Triangles (0x1C = 28 байт)
Прямые определения треугольников. Используется и Моделью и Ландшафтом,
но только Ландшафт использует их напрямую для рендеринга.
| Смещение | Размер | Тип | Поле | Описание |
|:--------:|:------:|:---:|------|----------|
| 0x00 | 4 | uint32 | Flags | Флаги треугольника (0x20000 = коллизия) |
| 0x04 | 4 | uint32 | MaterialData | Данные материала (см. ниже) |
| 0x08 | 2 | ushort | Vertex1Index | Индекс первой вершины |
| 0x0A | 2 | ushort | Vertex2Index | Индекс второй вершины |
| 0x0C | 2 | ushort | Vertex3Index | Индекс третьей вершины |
| 0x0E | 4 | uint32 | Magic0E | Неизвестно |
| 0x12 | 4 | uint32 | Magic12 | Неизвестно |
| 0x16 | 4 | uint32 | Magic16 | Неизвестно |
| 0x1A | 2 | ushort | Magic1A | Неизвестно |
#### MaterialData (0x04) - Структура материала
```
MaterialData = 0xFFFF_SSPP
│ │└─ PP: Основной материал (byte 0)
│ └─── SS: Вторичный материал для блендинга (byte 1)
└────── Всегда 0xFFFF (байты 2-3)
```
| Значение SS | Описание |
|:-----------:|----------|
| 0xFF | Сплошной материал (без блендинга) |
| 0x01-0xFE | Индекс вторичного материала для блендинга |
Примеры:
- `0xFFFFFF01` = Сплошной материал 1
- `0xFFFF0203` = Материал 3 с блендингом в материал 2
---
### Компонент 0A - External References (переменный размер)
Таблица строк для внешних ссылок на части меша. Формат:
```
[4 байта: длина] [байты строки] [null-терминатор]
...повтор...
```
Длина 0 означает пустую запись. Строки типа `"central"` имеют особое значение (flag |= 1).
---
## Пример: Ландшафт SC_1
```
Land.msh (SC_1):
├── 01: 256 тайлов (сетка 16×16)
├── 02: 512 сабмешей (256 LOD0 + 256 LOD1)
├── 03: 10 530 вершин
├── 04: 10 530 данных на вершину
├── 05: 10 530 данных на вершину
├── 0B: 7 882 записи материалов
├── 0E: 10 530 данных на вершину
├── 12: 10 530 микротекстурный маппинг
└── 15: 7 882 треугольника
├── LOD 0: 4 993 треугольника (тайлы 0-255 → сабмеши 0-255)
└── LOD 1: 2 889 треугольников (тайлы 0-255 → сабмеши 256-511)
```
---
## Использование
```csharp
var converter = new MshConverter();
// Автоопределение типа и конвертация в OBJ
converter.Convert("Land.msh", "terrain.obj", lodLevel: 0);
converter.Convert("robot.msh", "robot.obj", lodLevel: 0);
// Ручное определение типа
var archive = NResParser.ReadFile("mesh.msh").Archive;
var type = MshConverter.DetectMeshType(archive);
// Возвращает: MshType.Model или MshType.Landscape
```
---
## Формат WEA - Файлы материалов ландшафта
Файлы `.wea` — текстовые файлы, определяющие таблицу материалов для ландшафта.
### Формат
```
{count}
{index} {material_name}
{index} {material_name}
...
```
### Связь с Land.msh
Каждая карта имеет два файла материалов:
| Файл | Используется для | Треугольники в Comp15 |
|------|------------------|----------------------|
| `Land1.wea` | LOD0 (высокая детализация) | Первые N (сумма CountIn07 для LOD0) |
| `Land2.wea` | LOD1 (низкая детализация) | Остальные |
### Пример (SC_1)
**Land1.wea:**
```
4
0 B_S0
1 L04
2 L02
3 L00
```
**Land2.wea:**
```
4
0 DEFAULT
1 L05
2 L03
3 L01
```
### Маппинг материалов
Индекс материала в `Comp15.MaterialData & 0xFF` → строка в `.wea` файле.
```
Треугольник с MaterialData = 0xFFFF0102
└─ Основной материал = 02 → Land1.wea[2] = "L02"
└─ Блендинг с материалом = 01 → Land1.wea[1] = "L04"
```
### Типичные имена материалов
| Префикс | Назначение |
|---------|------------|
| L00-L05 | Текстуры ландшафта (grass, dirt, etc.) |
| B_S0 | Базовая текстура |
| DEFAULT | Фолбэк для LOD1 |
| WATER | Вода (поверхность) |
| WATER_BOT | Вода (дно) |
| WATER_M | Вода LOD1 |
---
## Источники
- Реверс-инжиниринг `Terrain.dll` (класс CLandscape)
- Декомпиляция Ghidra: `CLandscape::ctor` и `IMesh2_of_CLandscape::Render`