mirror of
https://github.com/sampletext32/ParkanPlayground.git
synced 2025-12-11 04:51:21 +04:00
feat: Add landscape mesh support to MshConverter
- Auto-detect Model vs Landscape mesh types - Model: uses indexed triangles (06, 0D, 07) - Landscape: uses direct triangles (0B, 15) - Add MSH_FORMAT.md documentation (Russian) - Add Ghidra decompiled code for CLandscape
This commit is contained in:
267
ParkanPlayground/MSH_FORMAT.md
Normal file
267
ParkanPlayground/MSH_FORMAT.md
Normal file
@@ -0,0 +1,267 @@
|
||||
# Документация формата 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) | Сабмеши с баундинг-боксами |
|
||||
| 03 | Vertices | 12 (0x0C) | Позиции вершин (Vector3) |
|
||||
| 04 | VertexData1 | 4 | Данные на вершину (неизвестно) |
|
||||
| 05 | VertexData2 | 4 | Данные на вершину (неизвестно) |
|
||||
| 06 | Indices | 2 | Индексы вершин треугольников (только Модель) |
|
||||
| 07 | TriangleData | 16 | Данные рендера на треугольник (только Модель) |
|
||||
| 08 | Animations | 4 | Кейфреймы анимации меша |
|
||||
| 0A | ExternalRefs | переменный | Внешние ссылки на меши (строки) |
|
||||
| 0B | MaterialData | 4 | Материалы на треугольник (только Ландшафт) |
|
||||
| 0D | DrawBatches | 20 (0x14) | Батчи отрисовки (только Модель) |
|
||||
| 0E | VertexData3 | 4 | Данные на вершину (только Ландшафт) |
|
||||
| 12 | MicrotextureMap | 4 | Микротекстурный маппинг на вершину |
|
||||
| 13 | ShortAnims | 2 | Короткие индексы анимаций |
|
||||
| 15 | Triangles | 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 | Magic04 | Неизвестно (часто 0xFFFFFF01) |
|
||||
| 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 | Неизвестно |
|
||||
|
||||
---
|
||||
|
||||
### Компонент 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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Источники
|
||||
|
||||
- Реверс-инжиниринг `Terrain.dll` (класс CLandscape)
|
||||
- Декомпиляция Ghidra: `CLandscape::ctor` и `IMesh2_of_CLandscape::Render`
|
||||
Reference in New Issue
Block a user