> For the complete documentation index, see [llms.txt](https://docs.bestway.com.ua/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.bestway.com.ua/gem-rts-v1-ru/bazovaya-informaciya-o-resursakh-v-gem-rts/binarnye-resursy-v-gem-rts/format-mesha-.ply.md).

# Формат меша (.ply)

Формат `.ply` используется для хранения мешей в движках семейства GEM RTS. Формат является chunk-based контейнером.

{% hint style="warning" icon="ruler-vertical" %}
Размер chunk не хранится и должен вычисляться парсером на основе структуры данных chunk-а.
{% endhint %}

**Файл может содержать информацию:**

* статические меши;
* skinned mesh;
* большие меши карт;
* меши вспомогательных сеток поверхности земли;
* adjacency data;
* shadow data;
* multiple UV channels;
* tangent space;
* skinning;
* материалы и текстуры.

**Структура бинарного файла**

```
EPLY | BPLY | PM01
цикл chunk ID
    INDX | IND4
    VERT
    BAS2
    InfG
    BNDS
    ADJA
    SHDW
    MROR
    MARK
    SKIN
    MESH | SBM1 | SUBM
```

{% hint style="info" %}
Порядок чанков внутри цикла не фиксирован. Чанки могут располагаться в произвольном порядке, а некоторые из них могут отсутствовать. Парсер должен определять тип чанка по его значению FourCC и обрабатывать данные соответствующим образом
{% endhint %}

### Заголовок файла

Файл .ply начинается с одного из следующих FourCC.

<table><thead><tr><th width="113.9375">Название</th><th width="103.4765625">Тип</th><th width="101.56640625">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>EPLY</td><td>uint8[4]</td><td>4</td><td>Обычный меш с 16-битным индексом.</td></tr><tr><td>BPLY</td><td>uint8[4]</td><td>4</td><td>Большой меш с 32-битным индексом. Обычно используется для меша карты.</td></tr><tr><td>PM01</td><td>uint8[4]</td><td>4</td><td>GEM3 формат меша.</td></tr></tbody></table>

Стартовый FourCC является идентификатором формата файла и не является обычным chunk-ом. После чтения стартового FourCC парсер последовательно читает файл как набор chunk-ов.

### Каталог chunk ID

<table><thead><tr><th width="160.7421875">FourCC</th><th>Назначение</th></tr></thead><tbody><tr><td>INDX</td><td>Индексы (16 бит)</td></tr><tr><td>IND4</td><td>Индексы (32 бит)</td></tr><tr><td>VERT</td><td>Данные вертексов</td></tr><tr><td>BAS2</td><td>Базис ландшафтной сетки</td></tr><tr><td>InfG</td><td>Terrain grid</td></tr><tr><td>BNDS</td><td>Bounding box</td></tr><tr><td>ADJA</td><td>Adjacency</td></tr><tr><td>SHDW</td><td>Shadow data</td></tr><tr><td>MROR</td><td>Mirrored mesh flag</td></tr><tr><td>MARK</td><td>Markup data</td></tr><tr><td>SKIN</td><td>Карта костей</td></tr><tr><td>MESH</td><td>Сабмеш GEM2</td></tr><tr><td>SBM1</td><td>Сабмеш GEM RTS 1.1+</td></tr><tr><td>SUBM<br>(GEM RTS)</td><td>Сабмеш GEM3 / GEM RTS</td></tr><tr><td>SUBM<br>(AS2)</td><td>Сабмеш Assault Squad 2</td></tr></tbody></table>

{% hint style="info" %}
Существует два несовместимых варианта чанка `SUBM`. Структура чанка зависит от стартового значения FourCC ресурса. \
Парсер должен выбирать соответствующий вариант `SUBM` в зависимости от значения стартового FourCC.
{% endhint %}

### Chunk `INDX` | `IND4`

**Структура данных**

```
INDX | IND4
    index_count
    indices[index_count]
```

#### Chunk `INDX`

<table><thead><tr><th width="134.05859375">Название</th><th width="173.765625">Тип</th><th width="101.46484375">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>FourCC</td><td>uint8[4]</td><td>4</td><td>INDX.<br>Индексы меша.</td></tr><tr><td>index_count</td><td>int32</td><td>4</td><td>Количество индексов.</td></tr><tr><td>indices</td><td>uint16[index_count]</td><td>2</td><td>Массив индексов. Размер индекса определяется стартовым Chunk ID.</td></tr></tbody></table>

#### Chunk `IND4`

<table><thead><tr><th width="140.61328125">Название</th><th width="175.52734375">Тип</th><th width="98.10546875">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>FourCC</td><td>uint8[4]</td><td>4</td><td>IND4.<br>Индексы меша.</td></tr><tr><td>index_count</td><td>int32</td><td>4</td><td>Количество индексов.</td></tr><tr><td>indices</td><td>uint32[index_count]</td><td>4</td><td>Массив индексов. Размер индекса определяется стартовым Chunk ID.</td></tr></tbody></table>

## Chunk `VERT`

**Структура данных**

```
VERT
    vertex_count
    vertex_size
    vertex_flags
    vertices[vertex_count]
        vertex data
```

<table><thead><tr><th width="124.7578125">Название</th><th width="176.2109375">Тип</th><th width="102">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>FourCC</td><td>uint8[4]</td><td>4</td><td>VERT</td></tr><tr><td>vertex_count</td><td>int32</td><td>4</td><td>Количество вершин</td></tr><tr><td>vertex_size</td><td>uint16</td><td>2</td><td>Размер одной вершины в байтах. Движок ориентируется прежде всего на это значение, даже если вычисленный по флагам размер меньше</td></tr><tr><td>vertex_flags</td><td>uint16</td><td>2</td><td>Битовая маска флагов вершин (FVF)</td></tr><tr><td>vertices</td><td>struct[vertex_count]</td><td></td><td>Массив вершин.<br>Структура вершины зависит от формата сабмеша.</td></tr></tbody></table>

### FVF

Флаги для вертексов собираются по битовой маске.

<table><thead><tr><th width="114.16015625">Bit</th><th>Описание</th></tr></thead><tbody><tr><td>0x0001</td><td>Полный цвет. <br>Если флаг отсутствует, цвет вершин после загрузки умножается на 2</td></tr><tr><td>0x0002</td><td>Оптимизированный порядок вершин. <br>Если флаг отсутствует, движок может попытаться автоматически оптимизировать меш после загрузки.</td></tr><tr><td>0x0004</td><td>Цвет проверен. <br>*)Не используется в GEM RTS</td></tr></tbody></table>

### Vertices (`struct[vertex_count]`)

Реальное наличие полей в файле определяется флагами формата вертексов.

<table><thead><tr><th width="163.96484375">Название</th><th width="98.62109375">Тип</th><th width="107.94921875">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>position</td><td>float[3]</td><td>12</td><td>Позиция вершины в локальной системе координат.</td></tr><tr><td>normal</td><td>float[3]</td><td>12</td><td>Нормаль в локальной системе координат.</td></tr><tr><td>tangent</td><td>float[3]</td><td>12</td><td>Касательная в локальной системе координат. Опционально.</td></tr><tr><td>uv</td><td>float[2]</td><td>8</td><td>UV координаты текстуры. <br>Может быть несколько наборов UV.</td></tr><tr><td>bone_indices</td><td>uint8[4]</td><td>4</td><td>Индексы в локальный bone_remap сабмеша.</td></tr><tr><td>bone_weights</td><td>uint8[4]</td><td>4</td><td>Веса костей в формате UNORM8 (0..1).</td></tr></tbody></table>

## Chunk `BAS2`

Базис сетки для карты

**Структура данных**

```
BAS2
    polygons
        center
        axis_x
        axis_y
    texture
        center
        axis_x
        axis_y
```

<table><thead><tr><th width="156.00390625">Название</th><th width="99.04296875">Тип</th><th width="105.52734375">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>FourCC</td><td>uint8[4]</td><td>4</td><td>BAS2</td></tr><tr><td>polygons.center</td><td>float[2]</td><td>8</td><td>Центр координатной системы генерации треугольников.</td></tr><tr><td>polygons.axis_x</td><td>float[2]</td><td>8</td><td>Ось X координатной системы генерации треугольников.</td></tr><tr><td>polygons.axis_y</td><td>float[2]</td><td>8</td><td>Ось Y координатной системы генерации треугольников.</td></tr><tr><td>texture.center</td><td>float[2]</td><td>8</td><td>Центр координатной системы UV текстуры.</td></tr><tr><td>texture.axis_x</td><td>float[2]</td><td>8</td><td>Ось X UV пространства.</td></tr><tr><td>texture.axis_y</td><td>float[2]</td><td>8</td><td>Ось Y UV пространства.</td></tr></tbody></table>

## Chunk `InfG`

Большая сетка треугольников для ландшафта.

**Структура данных**

```
InfG
    grid_start_xy
    grid_end_xy
    face_count
    faces[face_count]
        submesh : 15
        invalid : 1
```

<table><thead><tr><th width="129.1171875">Название</th><th width="171.484375">Тип</th><th width="103.84375">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>FourCC</td><td>uint8[4]</td><td>4</td><td>InfG. Terrain grid.</td></tr><tr><td>grid_start_xy</td><td>int32[2]</td><td>8</td><td>Начальные координаты сетки</td></tr><tr><td>grid_end_xy</td><td>int32[2]</td><td>8</td><td>Конечные координаты сетки</td></tr><tr><td>face_count</td><td>uint32</td><td>4</td><td>Количество треугольников</td></tr><tr><td>faces</td><td>uint16[face_count]</td><td></td><td><a href="#_yvkcfqf5lj5">Массив данных треугольников</a></td></tr></tbody></table>

#### Битовая структура `faces`

<table><thead><tr><th width="127.37109375">Bit</th><th>Описание / Значение</th></tr></thead><tbody><tr><td>0x7FFF</td><td>Индекс сабмеша (<code>submesh : 15</code>)</td></tr><tr><td>0x8000</td><td>Флаг невалидного треугольника (<code>invalid : 1</code>)</td></tr></tbody></table>

## Chunk `BNDS`

Axis-aligned bounding box меша.

**Структура данных**

```
BNDS
    min
    max
```

<table><thead><tr><th width="117.33984375">Название</th><th width="105.58203125">Тип</th><th width="101.3046875">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>FourCC</td><td>uint8[4]</td><td>4</td><td>BNDS. Bounding box меша</td></tr><tr><td>min</td><td>float[3]</td><td>12</td><td>Минимумы по каждой из осей координат XYZ</td></tr><tr><td>max</td><td>float[3]</td><td>12</td><td>Максимумы по каждой из осей координат</td></tr></tbody></table>

## Chunk `ADJA`

Информация о соседних треугольниках.

\*)Не используется в GEM RTS.

**Структура данных**

```
ADJA
    face_count
    adjacencies[face_count]
        neighbours[3]
```

<table><thead><tr><th width="129.46484375">Название</th><th width="162.50390625">Тип</th><th width="105.7265625">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>FourCC</td><td>uint8[4]</td><td>4</td><td>ADJA. Информация adjacency.</td></tr><tr><td>face_count</td><td>int32</td><td>4</td><td>Количество треугольников.</td></tr><tr><td>adjacencies</td><td>struct[face_count]</td><td></td><td>Информация о соседях треугольников</td></tr></tbody></table>

#### Adjacencies (`struct`)

<table><thead><tr><th width="131.671875">Название</th><th width="101.07421875">Тип</th><th width="110.50390625">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>neighbours</td><td>uint16[3]</td><td>6</td><td>Индексы соседних треугольников. <code>0xFFFF</code> означает отсутствие соседа.</td></tr></tbody></table>

## Chunk `SHDW`

Информация о тенях.

\*)Не используется в GEM RTS.

**Структура данных**

```
SHDW
    face_count
    shadow_info[face_count]
```

<table><thead><tr><th width="131.28125">Название</th><th width="159.23046875">Тип</th><th width="103.23046875">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>FourCC</td><td>uint8[4]</td><td>4</td><td><p><code>SHDW</code></p><p>Информация о тенях.</p></td></tr><tr><td>face_count</td><td>int32</td><td>4</td><td>Количество треугольников.</td></tr><tr><td>shadow_infos</td><td>uint8[face_count]</td><td></td><td><p>Флаги отбрасывания теней:</p><ul><li>0 - не отбрасывает тень</li><li>1 - отбрасывает тень</li></ul></td></tr></tbody></table>

## Chunk `MROR`

Признак отзеркаленного меша.

<table><thead><tr><th width="118.90234375">Название</th><th width="94.17578125">Тип</th><th width="103.83203125">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>FourCC</td><td>uint8[4]</td><td>4</td><td><p><code>MROR</code></p><p>Указывает на отзеркаленный меш</p></td></tr></tbody></table>

## Chunk `MARK`

Разметка треугольников.

\*)Не используется в GEM RTS.

**Структура данных**

```
MARK
    mark_size
    marks[mark_size]
```

<table><thead><tr><th width="113.16796875">Название</th><th width="159.36328125">Тип</th><th width="101.6640625">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>FourCC</td><td>uint8[4]</td><td>4</td><td><code>MARK</code></td></tr><tr><td>mark_size</td><td>uint32</td><td>4</td><td>Размер данных разметки</td></tr><tr><td>marks</td><td>uint8[mark_size]</td><td></td><td>Бинарные данные разметки</td></tr></tbody></table>

## Chunk `SKIN`

Карта костей skin-меша.

**Структура данных**

```
SKIN
    bone_count
    bone_names[bone_count]
        bone_name
```

<table><thead><tr><th width="126.8828125">Название</th><th width="183.9375">Тип</th><th width="110.99609375">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>FourCC</td><td>uint8[4]</td><td>4</td><td><code>SKIN</code></td></tr><tr><td>bone_count</td><td>uint32</td><td>4</td><td>Количество костей</td></tr><tr><td>bone_names</td><td>string8[bone_count]</td><td></td><td>Имена костей</td></tr></tbody></table>

## Чанки сабмешей (`SUBM`, `SBM1`, `MESH`)

{% tabs %}
{% tab title="SUBM (GEM3 / GEM RTS, PM01)" %}

## Chunk `SUBM`

Формат описания сабмеша для моделей GEM3 и GEM RTS.

Используется в файлах **.ply**, если в начале файла указан формат PM01.

**Структура данных**

```
SUBM
    vertex_format
    face_start
    face_count
    vertex_start
    vertex_count
    mesh_flags

    [если mesh_flags содержит skin]
        bone_count
        bone_map[bone_count]
        material_name
```

<table><thead><tr><th width="152.4375">Название</th><th width="106.765625">Тип</th><th width="110.984375">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>FourCC</td><td>uint8[4]</td><td>4</td><td><code>SUBM</code></td></tr><tr><td>vertex_format</td><td>uint16</td><td>2</td><td>Битовая маска формата вершин</td></tr><tr><td>face_start</td><td>uint16</td><td>2</td><td>Индекс первого треугольника в сабмеше</td></tr><tr><td>face_count</td><td>uint16</td><td>2</td><td>Количество треугольников в сабмеше</td></tr><tr><td>vertex_start</td><td>uint16</td><td>2</td><td>Индекс первого вертекса в сабмеше. Не используется в GEM RTS</td></tr><tr><td>vertex_count</td><td>uint16</td><td>2</td><td>Количество вертексов в сабмеше. Не используется в GEM RTS</td></tr><tr><td>mesh_flags</td><td>uint16</td><td>2</td><td>Битовые флаги свойств меша</td></tr><tr><td>material_name</td><td>string8/24</td><td>1+</td><td>Имя материала</td></tr></tbody></table>

#### Битовая маска `vertex_format`

<table><thead><tr><th width="121.19140625">Значение</th><th width="123.49609375">Тип</th><th>Коментарий</th></tr></thead><tbody><tr><td>0x0001</td><td>float[3]</td><td>Позиция</td></tr><tr><td>0x0002</td><td>float[3]</td><td>Нормаль</td></tr><tr><td>0x0004</td><td>uint8[4]</td><td>Цвет 0, rgba</td></tr><tr><td>0x0008</td><td>uint8[4]</td><td>Цвет 1, rgba</td></tr><tr><td>0x0010</td><td>float[2]</td><td>Текстурные координаты 0</td></tr><tr><td>0x0020</td><td>float[2]</td><td>Текстурные координаты 1</td></tr><tr><td>0x0040</td><td>float[2]</td><td>Текстурные координаты 2</td></tr><tr><td>0x0080</td><td>float[2]</td><td>Текстурные координаты 3</td></tr><tr><td>0x0100</td><td>float[4]</td><td>Тангент</td></tr><tr><td>0x0200</td><td>uint8</td><td>Skin с 2 костями</td></tr><tr><td>0x0400</td><td>uint8[2]</td><td>Skin с 3 костями</td></tr><tr><td>0x0600</td><td>uint8[3]</td><td>Skin с 4 костями.<br>Одновременно установлены признаки <code>0x0200</code> и <code>0x0400</code></td></tr><tr><td>0x0800</td><td>float</td><td>Амплитуда ветра</td></tr></tbody></table>

#### Битовая маска `mesh_flags`

<table><thead><tr><th width="117.2265625">Значение</th><th>Описание</th></tr></thead><tbody><tr><td>0x0001</td><td>Двусторонний меш</td></tr><tr><td>0x0002</td><td>skin</td></tr></tbody></table>

#### Skin data

Присутствует только если в `mesh_flags` установлен флаг `0x0002` (`skin`)

**Структура данных**

```
bone_count
bone_map[bone_count]
```

<table><thead><tr><th width="120.05078125">Название</th><th width="163.5234375">Тип</th><th width="113.92578125">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>bone_count</td><td>uint8</td><td>1</td><td>Количество костей в skin-е</td></tr><tr><td>bone_map</td><td>uint8[bone_count]</td><td></td><td>Индексы костей в карте костей</td></tr></tbody></table>
{% endtab %}

{% tab title="SBM1 (GEM RTS 1.1+)" %}

## Chunk `SBM1`

Формат сабмеша GEM RTS 1.1+ для карт.

**Структура данных**

```
SBM1

цикл vertex_elements[]
    type_usage
    usage_index
    stream_index

цикл tags[]
    tag_index
    tag_chunk

face_start
face_count
mesh_flags
material_name
```

| Название         | Тип        | Размер | Описание                              |
| ---------------- | ---------- | ------ | ------------------------------------- |
| FourCC           | uint8\[4]  | 4      | SBM1                                  |
| vertex\_elements | struct\[]  |        | Список элементов vertex info          |
| tags             | struct\[]  |        | Список пользовательских тегов вершины |
| face\_start      | int32      | 4      | Индекс первого треугольника в сабмеше |
| face\_count      | int32      | 4      | Количество треугольников в сабмеше    |
| mesh\_flags      | uint32     | 4      | Битовые флаги меша                    |
| material\_name   | string8/24 | 1+     | Имя материала                         |

### Vertex format elements

Список `vertex_elements[]` содержит описание вертексов.

Список не имеет счетчика элементов и читается последовательно до элемента-терминатора.

Поле `type_usage` одновременно хранит тип элемента и его назначение:

* `(type_usage & 0x0F)` определяет тип элемента
* `(type_usage & 0xF0) >> 4` определяет назначение элемента

Значение `0xFF` используется как терминатор списка и завершает чтение элементов вершинного формата.

#### Структура элемента

| Название      | Тип   | Размер | Описание                      |
| ------------- | ----- | ------ | ----------------------------- |
| type\_usage   | uint8 | 1      | Тип элемента и его назначение |
| usage\_index  | uint8 | 1      | Индекс использования          |
| stream\_index | uint8 | 1      | Индекс потока                 |

#### Тип элемента

Определяется младшими четырьмя битами поля `type_usage`.

| Значение | Название | Тип       | Комментарий    |
| -------- | -------- | --------- | -------------- |
| 0        | FLOAT1   | float     |                |
| 1        | FLOAT2   | float\[2] |                |
| 2        | FLOAT3   | float\[3] |                |
| 3        | FLOAT4   | float\[4] |                |
| 4        | SHORT2   | int16\[2] |                |
| 5        | BYTE4    | uint8\[4] |                |
| 6        | COLOR    | uint8\[4] | RGBA           |
| 7        | HALF4    | float\[4] | half-precision |
| 8        | BYTE4N   | uint8\[4] | unorm8         |

#### Назначение элемента

Определяется старшими четырьмя битами поля `type_usage`.

usage = high nibble of type\_usage

| Значение | Описание      |
| -------- | ------------- |
| 0        | POSITION      |
| 1        | NORMAL        |
| 2        | COLOR         |
| 3        | TEXCOORD      |
| 4        | BLEND WEIGHT  |
| 5        | BLEND INDICES |
| 6        | TANGENT       |

### Vertex tags

Список `tags[]` содержит дополнительные пользовательские теги элементов вершины.

Список не имеет счетчика элементов и читается последовательно до элемента-терминатора.

Значение `0xFF` используется как терминатор списка тегов.

#### Структура тега

| Название   | Тип    | Размер | Описание           |
| ---------- | ------ | ------ | ------------------ |
| tag\_index | uint8  | 1      | Индекс элемента    |
| tag\_chunk | uint32 | 4      | Идентификатор тега |

#### Битовая маска `mesh_flags`

| Значение     | Описание                                          |
| ------------ | ------------------------------------------------- |
| 0x0001       | Two sided mesh (render this mesh without culling) |
| 0x0002       | Use alpha (compatibility mode)                    |
| 0x0004       | Use realtime scene light                          |
| 0x0008       | Use player color light                            |
| 0x0010       | Skinned mesh                                      |
| 0x0020       | Shadow volume mesh                                |
| 0x0040       | Mirrored (has negative scaling)                   |
| 0x0080       | Blend by second texture alpha                     |
| 0x0100       | Bump (compatibility mode)                         |
| 0x0200       | Specular color stored                             |
| 0x0400       | Format with material, not textures                |
| 0x0800       | Sub-skin feature                                  |
| 0x1000       | Two textures with one texcoord                    |
| 0x2000       | Using VD (compatibility mode)                     |
| 0x4000       | Has lightmap                                      |
| {% endtab %} |                                                   |

{% tab title="SUBM (Assault Squad 2)" %}

## Chunk `SUBM`

Формат описания сабмеша для карт из Assault Squad 2.

### Структура данных

```
SUBM

vertex_elements[]

type_usage

face_start

face_count

unknown[2]

mesh_flags

material_name
```

| Название         | Тип        | Размер | Описание                              |
| ---------------- | ---------- | ------ | ------------------------------------- |
| FourCC           | uint8\[4]  | 4      | SUBM                                  |
| vertex\_elements | struct\[]  |        | Список элементов vertex info          |
| face\_start      | uint32     | 4      | Индекс первого треугольника в сабмеше |
| face\_count      | uint32     | 4      | Количество треугольников в сабмеше    |
| unknown\[2]      | uint32\[2] | 8      | Неизвестные данные                    |
| mesh\_flags      | uint32     | 4      | Битовые флаги для меша                |
| material\_name   | string8    | 1+     | Имя материала                         |

#### Vertex elements info

Список `vertex_elements[]` содержит описание вертексов.

Список не имеет счетчика элементов и читается последовательно до элемента-терминатора.

Поле `type_usage` одновременно хранит тип элемента и его назначение.

* `(type_usage & 0x0F)` определяет тип элемента.
* `(type_usage & 0xF0) >> 4` определяет назначение элемента.

Значение `0xFF` используется как терминатор списка и завершает чтение элементов вершинного формата.

#### Структура элемента

| Название    | Тип   | Размер | Описание                      |
| ----------- | ----- | ------ | ----------------------------- |
| type\_usage | uint8 | 1      | Тип элемента и его назначение |

#### Тип элемента

Определяется младшими четырьмя битами поля `type_usage`.

| Значение | Название | Тип       | Комментарий    |
| -------- | -------- | --------- | -------------- |
| 0        | FLOAT1   | float     |                |
| 1        | FLOAT2   | float\[2] |                |
| 2        | FLOAT3   | float\[3] |                |
| 3        | FLOAT4   | float\[4] |                |
| 4        | SHORT2   | int16\[2] |                |
| 5        | BYTE4    | uint8\[4] |                |
| 6        | COLOR    | uint8\[4] | RGBA           |
| 7        | HALF4    | float\[4] | half-precision |
| 8        | BYTE4N   | uint8\[4] | unorm8         |

#### Назначение элемента

Определяется старшими четырьмя битами поля `type_usage`.

| Значение | Описание      |
| -------- | ------------- |
| 0        | POSITION      |
| 1        | NORMAL        |
| 2        | COLOR         |
| 3        | TEXCOORD      |
| 4        | BLEND WEIGHT  |
| 5        | BLEND INDICES |
| 6        | TANGENT       |

#### Битовая маска `mesh_flags`

| Значение     | Описание                                          |
| ------------ | ------------------------------------------------- |
| 0x0001       | Two sided mesh (render this mesh without culling) |
| 0x0002       | Use alpha (compatibility mode)                    |
| 0x0004       | Use realtime scene light                          |
| 0x0008       | Use player color light                            |
| 0x0010       | Skinned mesh                                      |
| 0x0020       | Shadow volume mesh                                |
| 0x0040       | Mirrored (has negative scaling)                   |
| 0x0080       | Blend by second texture alpha                     |
| 0x0100       | Bump (compatibility mode)                         |
| 0x0200       | Specular color stored                             |
| 0x0400       | Format with material, not textures                |
| 0x0800       | Sub-skin feature                                  |
| 0x1000       | Two textures with one texcoord                    |
| 0x2000       | Using VD (compatibility mode)                     |
| 0x4000       | Has lightmap                                      |
| {% endtab %} |                                                   |

{% tab title="MESH (Legacy, Faces of War / Men of War)" %}

## Chunk `MESH`

Legacy формат сабмеша из Faces of War / Men of War.

**Структура данных**

<pre><code>MESH
    fvf
    face_start
    face_count
    mesh_flags

    [если mesh_flags содержит specular]
        specular_color
    [если mesh_flags содержит use material]
        material_name
    [иначе]
<strong>        texture data
</strong>            [если mesh_flags содержит specular | bump]
                diffuse
                [если mesh_flags содержит specular]
                    specular_texture
                [если mesh_flags содержит bump]
                    bump_texture
            [иначе]
                [если uv==2 | mesh_flags содержит флаг two textures with one texcoord]
<strong>                    diffuse_0
</strong>                    diffuse_1
                [иначе]
                    diffuse
    [если mesh_flags содержит флаг skinned mesh]
        bone_map_size
        bone_map[bone_map_size]
</code></pre>

<table><thead><tr><th width="119.10546875">Название</th><th width="108.5078125">Тип</th><th width="104.8203125">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>FourCC</td><td>uint8[4]</td><td>4</td><td><code>MESH</code><br>Legacy формат сабмеша.</td></tr><tr><td>fvf</td><td>uint32</td><td>4</td><td>Битовая маска формата вершин.</td></tr><tr><td>face_start</td><td>int32</td><td>4</td><td>Индекс первого треугольника.</td></tr><tr><td>face_count</td><td>int32</td><td>4</td><td>Количество треугольников.</td></tr><tr><td>mesh_flags</td><td>uint32</td><td>4</td><td>Битовые флаги меша.</td></tr></tbody></table>

### Vertex Format Flags (FVF)

Битовая маска для формата вертексов.\
Поле `fvf` содержит битовую маску типа `uint32`. Значения, приведённые в таблице, описывают варианты состава вершины, встречающиеся в формате. Если в файле встречается значение, отсутствующее в таблице, его следует интерпретировать как комбинацию установленных флагов.

<table><thead><tr><th width="148.140625">Bit</th><th>Описание</th></tr></thead><tbody><tr><td>0x002</td><td>position float[3]</td></tr><tr><td>0x006</td><td>position float[3]<br>blend_weight uint8<br>blend_indices uint8[4]</td></tr><tr><td>0x008</td><td>position float[3]<br>blend_weight uint8[2]<br>blend_indices uint8[4]</td></tr><tr><td>0x00A</td><td>position float[3]<br>blend_weight uint8[3]<br>blend_indices uint8[4]</td></tr><tr><td>0x010</td><td>normal float[3]</td></tr><tr><td>0x040</td><td>diffuse_color uint8[4]</td></tr><tr><td>0x080</td><td>specular_color uint8[4]</td></tr><tr><td>0xN00</td><td>texcoord_mask N*float[2]</td></tr><tr><td>0x8000E000</td><td>tangent float[4]</td></tr></tbody></table>

### Битовая маска `mesh_flags`

<table><thead><tr><th width="136.28125">Значение</th><th>Описание</th></tr></thead><tbody><tr><td>0x0001</td><td>Two sided mesh (render this mesh without culling)</td></tr><tr><td>0x0002</td><td>Use alpha (compatibility mode)</td></tr><tr><td>0x0004</td><td>Use realtime scene light</td></tr><tr><td>0x0008</td><td>Use player color light</td></tr><tr><td>0x0010</td><td>Skinned mesh</td></tr><tr><td>0x0020</td><td>Shadow volume mesh</td></tr><tr><td>0x0040</td><td>Mirrored (has negative scaling)</td></tr><tr><td>0x0080</td><td>Blend by second texture alpha</td></tr><tr><td>0x0100</td><td>Bump (compatibility mode)</td></tr><tr><td>0x0200</td><td>Specular</td></tr><tr><td>0x0400</td><td>Use material</td></tr><tr><td>0x0800</td><td>Sub-skin feature</td></tr><tr><td>0x1000</td><td>Two textures with one texcoord</td></tr><tr><td>0x2000</td><td>Using VD (compatibility mode)</td></tr><tr><td>0x4000</td><td>Has lightmap</td></tr></tbody></table>

#### Specular color

Поле присутствует, если `mesh_flags` содержит `0x0200` (`specular`).

<table><thead><tr><th width="139.3125">Название</th><th width="97.6484375">Тип</th><th width="111.9453125">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>specular_color</td><td>uint8[4]</td><td>4</td><td>Цвет для спекуляра</td></tr></tbody></table>

#### Material name

Поле присутствует, если `mesh_flags` содержит `0x0400` (`use material`).

<table><thead><tr><th width="144.48046875">Название</th><th width="113.17578125">Тип</th><th width="101.76171875">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>material_name</td><td>string8/24</td><td>1+</td><td>Имя материала</td></tr></tbody></table>

#### Texture data

Данные текстур загружаются, если `mesh_flags` не содержит `0x0400` (`use material`). Структура зависит от флагов `specular`, `bump`, количества текстурных координат (UV) и флага `two textures with one texcoord`.

#### Texture data для standard material

Используется, если `mesh_flags` содержит `specular` или `bump`.

<table><thead><tr><th width="152.6328125">Название</th><th width="119.44921875">Тип</th><th width="108.3125">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>diffuse</td><td>string8/24</td><td>1+</td><td>Имя диффузной текстуры</td></tr><tr><td>specular_texture</td><td>string8/24</td><td>1+</td><td>Имя текстуры спекуляра.<br>Поле присутствует, если <code>mesh_flags</code> содержит <code>specular</code></td></tr><tr><td>bump_texture</td><td>string8/24</td><td>1+</td><td>Имя текстуры карты нормалей.<br>Поле присутствует, если <code>mesh_flags</code> содержит <code>bump</code></td></tr></tbody></table>

#### Texture data для материала из двух текстур

Используется, если standard material не загружается и выполняется одно из условий:

* `uv == 2`
* `mesh_flags` содержит `two textures with one texcoord`

<table><thead><tr><th width="116.5078125">Название</th><th width="125.90625">Тип</th><th width="108.828125">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>diffuse_0</td><td>string8/24</td><td>1+</td><td>Имя диффузной текстуры 0</td></tr><tr><td>diffuse_1</td><td>string8/24</td><td>1+</td><td>Имя диффузной текстуры 1</td></tr></tbody></table>

#### Texture data для одной текстуры

Используется, если standard material не загружается и условия для использования двух текстур не выполняются.

<table><thead><tr><th width="119.33203125">Название</th><th width="112.8359375">Тип</th><th width="105.53515625">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>diffuse</td><td>string8/24</td><td>1+</td><td>Имя диффузной текстуры</td></tr></tbody></table>

#### Skin data

Данные skin-а присутствуют, если `mesh_flags` содержит `skinned mesh`.

<table><thead><tr><th width="151.48828125">Название</th><th width="193.546875">Тип</th><th width="101.59375">Размер</th><th>Описание</th></tr></thead><tbody><tr><td>bone_map_size</td><td>uint8</td><td>1</td><td>Размер таблицы локального ремаппинга костей</td></tr><tr><td>bone_map</td><td>uint8[bone_map_size]</td><td></td><td>Таблица локального ремаппинга костей.</td></tr></tbody></table>

Таблица `bone_map` используется для сопоставления костей сабмеша с общей картой костей модели, хранящейся в chunk `SKIN`.

Каждый элемент массива содержит индекс кости из `SKIN`, увеличенный на 1.

Значения `vertex.bone_index` в вершинах ссылаются на элементы массива `bone_map`, а не напрямую на кости в `SKIN`.

Это позволяет сабмешу использовать только необходимые ему кости из общей карты костей модели.

**Значения `bone_map`:**

* `0`: указание использовать общую матрицу меша
* `N > 0`: указание использовать кость `SKIN.bones[N - 1]`
  {% endtab %}
  {% endtabs %}
