|
|
(не показаны 20 промежуточные версии 4 участников) |
Строка 1: |
Строка 1: |
− | '''Формат разобрал excid'''
| |
− |
| |
| == О формате == | | == О формате == |
| Формат *.object используется в качестве основного формата хранения моделей на этапе редактирования (включая экспорт из Maya или 3ds Max и хранение моделей до компиляции уровня) | | Формат *.object используется в качестве основного формата хранения моделей на этапе редактирования (включая экспорт из Maya или 3ds Max и хранение моделей до компиляции уровня) |
| | | |
− | == Описание структуры == | + | == Описание формата(из кода xrFSL) == |
− | Формат бинарный. Файл состоит из вложенных друг в друга блоков. Весь файл представляет собой единый блок.
| + | |
| + | const uint16 ''EOBJ_VERSION'' = 0x10; |
| + | |
| + | '''EObjectChunkIDs:''' |
| + | |
| + | ''EOBJ_CHUNK_MAIN'' = 0x7777, |
| + | |
| + | ''EOBJ_CHUNK_VERSION'' = 0x0900, |
| + | |
| + | ''EOBJ_CHUNK_FLAGS'' = 0x0903, |
| + | |
| + | ''EOBJ_CHUNK_SURFACES_0'' = 0x0905, // old format |
| + | |
| + | ''EOBJ_CHUNK_SURFACES_1'' = 0x0906, // old format |
| + | |
| + | ''EOBJ_CHUNK_SURFACES_2'' = 0x0907, |
| + | |
| + | ''EOBJ_CHUNK_MESHES'' = 0x0910, |
| + | |
| + | ''EOBJ_CHUNK_0911'' = 0x0911, // '''ignored by AE(Actor Editor)''' |
| + | |
| + | ''EOBJ_CHUNK_USERDATA'' = 0x0912, |
| + | |
| + | ''EOBJ_CHUNK_BONES_0'' = 0x0913, // old format |
| | | |
− | === Структура блока === | + | ''EOBJ_CHUNK_MOTIONS'' = 0x0916, |
− | Блок имеет 3 обязательные части:
| + | |
− | {| class="standard"
| + | |
− | |-
| + | |
− | !Часть||Тип(размер)||Подробнее
| + | |
− | |-
| + | |
− | |Идентификатор типа блока||(4)||2 байта идентификатора и 2 нулевых байта<br />
| + | |
− | |-
| + | |
− | |Размер блока||uint(4)||без учета этих частей — только то, что идет дальше
| + | |
− | |-
| + | |
− | |Данные||(Размер блока)||Данные могут быть представлены вложенными блоками
| + | |
− | |}
| + | |
| | | |
− | === Типы данных === | + | ''EOBJ_CHUNK_SHADERS_0'' = 0x0918, // old format |
− | Особое внимание стоит обратить на то, как хранятся строки: они нуль-терминальные, то есть в конце обязательно содержат нулевой байт.
| + | |
| | | |
− | == Структура == | + | ''EOBJ_CHUNK_PARTITIONS_0'' = 0x0919, // old format |
− | В заголовке последующих пунктов в скобках содержатся идентификаторы типа блока в шестнадцатиричной форме, при этом байты представлены в обратном порядке (то есть так, как числа задаются в исходниках), поэтому идентификатор 0x0912 в файле будет выглядеть как 09 12 00 00.
| + | |
| | | |
− | == Файл (0x7777) == | + | ''EOBJ_CHUNK_TRANSFORM'' = 0x0920, |
− | === Неизвестные данные (0x0900) ===
| + | |
− | Возможно, это версия.
| + | |
− | {| class="standard"
| + | |
− | |-
| + | |
− | !Название||Тип(размер)||Значение||Подробнее
| + | |
− | |-
| + | |
− | |Неизвестно||(2)||0x10 0x00||
| + | |
− | |}
| + | |
| | | |
− | === Пользовательские информация — User Data (0x0912) === | + | ''EOBJ_CHUNK_BONES_1'' = 0x0921, |
− | В редакторе Game options > User Data.
| + | |
− | {| class="standard"
| + | |
− | |-
| + | |
− | !Название||Тип(размер)||Значение||Подробнее
| + | |
− | |-
| + | |
− | |Данные||строка||||Произвольная строка
| + | |
− | |}
| + | |
| | | |
− | === Уровень детализации — LOD (0x0925) === | + | ''EOBJ_CHUNK_REVISION'' = 0x0922, // file revision |
− | В редакторе LOD > Reference.
| + | |
− | {| class="standard"
| + | |
− | |-
| + | |
− | !Название||Тип(размер)||Значение||Подробнее
| + | |
− | |-
| + | |
− | |Ссылка||строка||||Путь к модели, содержащей следующий уровень детализации
| + | |
− | |}
| + | |
| | | |
− | === Тип объекта — Object Type (0x0903) === | + | ''EOBJ_CHUNK_PARTITIONS_1'' = 0x0923, |
− | В редакторе Object Type.
| + | |
− | {| class="standard"
| + | |
− | |-
| + | |
− | !Название||Тип(размер)||Значение||Подробнее
| + | |
− | |-
| + | |
− | |Тип||(4)||||Значение 0x00 для статической модели (тип Static)
| + | |
− | |}
| + | |
| | | |
− | === Данные о геометрии — Geometry (0x0910) === | + | ''EOBJ_CHUNK_MOTION_REFS'' = 0x0924, |
− | В редакторе Geometry.
| + | |
− | Все представленные ниже данные описывают 1 подобъект.
| + | |
| | | |
− | ==== Неизвестные данные (0x1000) ==== | + | ''EOBJ_CHUNK_LOD_REF'' = 0x0925 // '''LOD\Reference''' |
− | {| class="standard"
| + | |
− | |-
| + | |
− | !Название||Тип(размер)||Значение||Подробнее
| + | |
− | |-
| + | |
− | |Неизвестно||(2)||0x11 0x00||
| + | |
− | |}
| + | |
| | | |
− | ==== Название подобъекта — Name (0x1000) ====
| + | '''EObjectClipChunkIDs:''' |
− | {| class="standard"
| + | |
− | |-
| + | |
− | !Название||Тип(размер)||Значение||Подробнее
| + | |
− | |-
| + | |
− | |Название||строка||||
| + | |
− | |}
| + | |
| | | |
− | ==== Ограничивающий параллелепипед — Bounding Box (0x1004) ==== | + | ''EOBJ_CLIP_VERSION_CHUNK'' = 0x9000, |
− | В редакторе Transform > BBox Min/Max
| + | |
− | {| class="standard"
| + | |
− | |-
| + | |
− | !Название||Тип(размер)||Значение||Подробнее
| + | |
− | |-
| + | |
− | |Минимум||float(4)[3]||||Минимальные значения вершин по x, y, z
| + | |
− | |-
| + | |
− | |Максимум||float(4)[3]||||Максимальные значения вершин по x, y, z
| + | |
− | |}
| + | |
| | | |
− | ==== Неизвестные данные (0x1002) ==== | + | ''EOBJ_CLIP_DATA_CHUNK'' = 0x9001 |
− | {| class="standard"
| + | |
− | |-
| + | |
− | !Название||Тип(размер)||Значение||Подробнее
| + | |
− | |-
| + | |
− | |Неизвестно||(1)||0x05||
| + | |
− | |}
| + | |
| | | |
− | ==== Неизвестные данные (0x1010) ==== | + | const uint16 ''EMESH_VERSION'' = 0x11; |
− | {| class="standard"
| + | |
− | |-
| + | |
− | !Название||Тип(размер)||Значение||Подробнее
| + | |
− | |-
| + | |
− | |Неизвестно||(8)||0x00||Все нули
| + | |
− | |}
| + | |
| | | |
− | ==== Вершины — Vertices (0x1005) ====
| + | '''EMeshChunkID:''' |
− | {| class="standard"
| + | |
− | |-
| + | |
− | !Название||Тип(размер)||Значение||Подробнее
| + | |
− | |-
| + | |
− | |Количество вершин n||uint(4)||||
| + | |
− | |-
| + | |
− | |Координаты||float(4)[n * 3]||||Координаты x, y, z для каждой вершины
| + | |
− | |}
| + | |
| | | |
− | ==== Грани — Faces (0x1006) ==== | + | ''EMESH_CHUNK_VERSION'' = 0x1000, |
− | {| class="standard"
| + | |
− | |-
| + | |
− | !Название||Тип(размер)||Значение||Подробнее
| + | |
− | |-
| + | |
− | |Количество граней m||uint(4)||||
| + | |
− | |-
| + | |
− | |Координаты||uint(4)[m * 6]||||Троки пар индекс вершины + индекс текстурной координаты
| + | |
− | |}
| + | |
| | | |
− | ==== Группы сглаживания — Smoothing Groups (0x1013) ==== | + | ''EMESH_CHUNK_MESHNAME'' = 0x1001, |
− | {| class="standard"
| + | |
− | |-
| + | |
− | !Название||Тип(размер)||Значение||Подробнее
| + | |
− | |-
| + | |
− | |Группы||uint(4)[m]||||32-битная маска групп сглаживания для каждой грани
| + | |
− | |}
| + | |
| | | |
− | ==== Словарь текстурных координат — UVs map (0x1008) ==== | + | ''EMESH_CHUNK_FLAGS'' = 0x1002, |
− | Логика формирования и назначение этого и блока «Текстурные координаты» доконца не понятна.
| + | |
− | Предположительный вариант представлен ниже.
| + | |
− | {| class="standard"
| + | |
− | |-
| + | |
− | !Название||Тип(размер)||Значение||Подробнее
| + | |
− | |-
| + | |
− | |Количество записей k||uint(4)||||
| + | |
− | |-
| + | |
− | |Данные||(9)[k]||||Предположительная структура в следующей таблице
| + | |
− | |}
| + | |
− | <br />
| + | |
− | {| class="standard"
| + | |
− | |-
| + | |
− | !Название||Тип(размер)||Значение||Подробнее
| + | |
− | |-
| + | |
− | |Неизвестно||byte(1)||0x1||
| + | |
− | |-
| + | |
− | |Индекс таблицы текстурных координат||uint(4)||0x0 или 0x1||Возможно, только первый байт содержит эти данные,<br /> остальные выполняют другие функции<br />Встречались «некорректные» данные (например, 0x1 0x90 0xdb 0x11 0x7), но они не использовались
| + | |
− | |-
| + | |
− | |Индекс текстурных координаты||uint(4)||0x0 или 0x1||Индекс в таблице, определяемой предыдущим значением.
| + | |
− | |}
| + | |
| | | |
− | ==== Материалы объекта — Object Materials (0x1009) ==== | + | ''EMESH_CHUNK_BBOX'' = 0x1004, |
− | {| class="standard"
| + | |
− | |-
| + | |
− | !Название||Тип(размер)||Значение||Подробнее
| + | |
− | |-
| + | |
− | |Количество материалов p||ushort(2)||||
| + | |
− | |-
| + | |
− | |Материалы||[p]||||Cтруктура в следующей таблице
| + | |
− | |}
| + | |
| | | |
− | <br />
| + | ''EMESH_CHUNK_VERTS'' = 0x1005, |
− | {| class="standard"
| + | |
− | |-
| + | |
− | !Название||Тип(размер)||Значение||Подробнее
| + | |
− | |-
| + | |
− | |Название материала||строка||||
| + | |
− | |-
| + | |
− | |Количество граней q||uint(4)||||Количество граней, имеющих этот материал
| + | |
− | |-
| + | |
− | |Индексы граней||uint(4)[q]||||
| + | |
− | |}
| + | |
| | | |
− | ==== Текстурные координаты — UVs (0x1008) ==== | + | ''EMESH_CHUNK_FACES'' = 0x1006, |
− | Количество таблиц, которое встречалось в тестовых файлах — 2.
| + | |
− | {| class="standard"
| + | |
− | |-
| + | |
− | !Название||Тип(размер)||Значение||Подробнее
| + | |
− | |-
| + | |
− | |Количество таблиц t||uint(4)||0x2||
| + | |
− | |-
| + | |
− | |Таблицы||[t]||||Структура в следующей таблице
| + | |
− | |}
| + | |
| | | |
− | <br />
| + | ''EMESH_CHUNK_VMAPS_0'' = 0x1007, |
− | {| class="standard"
| + | |
− | |-
| + | |
− | !Название||Тип(размер)||Значение||Подробнее
| + | |
− | |-
| + | |
− | |Неизвестно||строка||Texture||
| + | |
− | |-
| + | |
− | |Неизвестно||ubyte(1)||0x2||Возможно, количество компонентов в текс. координате?
| + | |
− | |-
| + | |
− | |Номер таблицы||ushort(1)||||
| + | |
− | |-
| + | |
− | |Количество текстурных координат s||uint(4)||||
| + | |
− | |-
| + | |
− | |Текстурные координаты||float(4)[s * 2]||||Пары значения текстурных координат u и v
| + | |
− | |-
| + | |
− | |Неизвестно||uint(4)[s]||||Какие-то индексы, не превышающие s
| + | |
− | |-
| + | |
− | |Неизвестно<br />(только для второй таблицы)||uint(4)[s]||||Какие-то индексы, не превышающие s, отсорированные по возрастанию
| + | |
− | |}
| + | |
| | | |
| + | ''EMESH_CHUNK_VMREFS'' = 0x1008, |
| | | |
− | === Материалы — Materials (0x0907) === | + | ''EMESH_CHUNK_SFACE'' = 0x1009, |
− | {| class="standard"
| + | |
− | |-
| + | |
− | !Название||Тип(размер)||Значение||Подробнее
| + | |
− | |-
| + | |
− | |Количество материалов r||uint(4)||||
| + | |
− | |-
| + | |
− | |Материалы||[r]||||Структура в следующей таблице
| + | |
− | |}
| + | |
| | | |
− | <br />
| + | ''EMESH_CHUNK_OPTIONS'' = 0x1010, |
− | {| class="standard"
| + | |
− | |-
| + | |
− | !Название||Тип(размер)||Значение||Подробнее
| + | |
− | |-
| + | |
− | |Название||строка||||
| + | |
− | |-
| + | |
− | |Характеристика для движка||строка||||Например, default
| + | |
− | |-
| + | |
− | |Характеристика для компилятора||строка||||Например, default
| + | |
− | |-
| + | |
− | |Характеристика для игры||строка||||Например, default
| + | |
− | |-
| + | |
− | |Путь к текстуре||строка||||
| + | |
− | |-
| + | |
− | |Неизвестно||строка||Texture||Значение Texture используется в блоке <br />Текстурные координаты — UVs (0x1008)
| + | |
− | |-
| + | |
− | |Флаги||uint(4)||||0x1, если материал двустронний, иначе 0x0
| + | |
− | |-
| + | |
− | |Неизвестно||(4)||0x12 0x1 0x0 0x0 0x1 0x0 0x0 0x0||
| + | |
− | |}
| + | |
| | | |
| + | ''EMESH_CHUNK_VMAPS_1'' = 0x1011, |
| | | |
− | === Автор — Author (0x0907) === | + | ''EMESH_CHUNK_VMAPS_2'' = 0x1012, |
− | {| class="standard"
| + | |
− | |-
| + | |
− | !Название||Тип(размер)||Значение||Подробнее
| + | |
− | |-
| + | |
− | |Создатель||строка||||Вид \\компьютер\пользователь (например, \\NAPALI\excid)
| + | |
− | |-
| + | |
− | |Дата создания||(4)||||
| + | |
− | |-
| + | |
− | |Последний модифицирующий||строка||||Вид \\компьютер\пользователь (например, \\NAPALI\excid)
| + | |
− | |-
| + | |
− | |Дата модификации||(4)||||
| + | |
− | |}
| + | |
| | | |
| + | ''EMESH_CHUNK_SG'' = 0x1013 |
| | | |
− | == Скрипт разбора файла == | + | const uint16 ''BONE_VERSION_1'' = 0x1; |
− | Написан на Python. Не реализован полностью, завершение не планируется, так как свою миссию он выполнил.<br />
| + | |
− | Если запускать из Blender, то импортирует объект (без материалов).<br />
| + | |
− | Не рекомендуется запускать для больших файлов, так как выводится вся информация из файла.
| + | |
| | | |
− | === Код ===
| + | const uint16 ''BONE_VERSION_2'' = 0x2; |
− | <code python>
| + | |
− | # #
| + | |
− | # XRay Engine (S.T.A.L.K.E.R.) object #
| + | |
− | # test import plugin for Blender #
| + | |
− | # #
| + | |
− | # Anton 'excid' Gorenko #
| + | |
− | # excid@mail.ru #
| + | |
− | # #
| + | |
− | # (2007 June) #
| + | |
− | # #
| + | |
| | | |
− | from struct import *
| + | const uint16 ''BONE_VERSION'' = ''BONE_VERSION_2''; |
− | import datetime
| + | |
| | | |
− | useBlender = True
| + | '''EboneChunkID:''' |
− | try:
| + | |
− | from Blender import *
| + | |
− | from Blender.Mathutils import *
| + | |
− | except:
| + | |
− | useBlender = False
| + | |
| | | |
| + | ''BONE_CHUNK_VERSION'' = 0x0001, |
| | | |
− | f = open('X:\\rawdata\\objects\\detail\\det_list_05.object', 'rb')
| + | ''BONE_CHUNK_DEF'' = 0x0002, |
− | s = f.read()
| + | |
− | f.close()
| + | |
| | | |
| + | ''BONE_CHUNK_BIND_POSE''= 0x0003, |
| | | |
− | def parseMeshData(s):
| + | ''BONE_CHUNK_MATERIAL'' = 0x0004, |
− |
| + | |
− | p = 0
| + | |
− | print '\nunknown block =', hex(int(unpack('I', s[p : p + 4])[0]))
| + | |
− | p += 4
| + | |
− | size = unpack('I', s[p : p + 4])[0]
| + | |
− | print 'unknown block size =', size
| + | |
− | p += 4
| + | |
− | print 'unknown data =', map(hex, unpack('%dB' % (size,), s[p : p + size]))
| + | |
− | p += size
| + | |
− |
| + | |
− | print '\nname block =', hex(int(unpack('I', s[p : p + 4])[0]))
| + | |
− | p += 4
| + | |
− | nameSize = unpack('I', s[p : p + 4])[0]
| + | |
− | print 'name block size =', nameSize
| + | |
− | p += 4
| + | |
− | name = unpack('%ds' % (nameSize,), s[p : p + nameSize])[0][:-1]
| + | |
− | p += int(nameSize)
| + | |
− | print 'name =', name
| + | |
− |
| + | |
− | if useBlender:
| + | |
− | obj = Object.New('Mesh', name)
| + | |
− | mesh = Mesh.New(name)
| + | |
− | obj.link(mesh)
| + | |
− | scene = Scene.GetCurrent()
| + | |
− | scene.objects.link(obj)
| + | |
− |
| + | |
− | print '\nbbox block =', hex(int(unpack('I', s[p : p + 4])[0]))
| + | |
− | p += 4
| + | |
− | print 'bbox block size =', unpack('I', s[p : p + 4])[0]
| + | |
− | p += 4
| + | |
− | print 'bbox min = ', unpack('3f', s[p : p + 12])
| + | |
− | p += 12
| + | |
− | print 'bbox max = ', unpack('3f', s[p : p + 12])
| + | |
− | p += 12
| + | |
− |
| + | |
− | print '\nunknown block =', hex(int(unpack('I', s[p : p + 4])[0]))
| + | |
− | p += 4
| + | |
− | size = unpack('I', s[p : p + 4])[0]
| + | |
− | print 'unknown block size =', size
| + | |
− | p += 4
| + | |
− | print 'unknown data =', map(hex, unpack('%dB' % (size,), s[p : p + size]))
| + | |
− | p += size
| + | |
− |
| + | |
− | print '\nunknown block =', hex(int(unpack('I', s[p : p + 4])[0]))
| + | |
− | p += 4
| + | |
− | size = unpack('I', s[p : p + 4])[0]
| + | |
− | print 'unknown block size =', size
| + | |
− | p += 4
| + | |
− | print 'unknown data =', map(hex, unpack('%dB' % (size,), s[p : p + size]))
| + | |
− | p += size
| + | |
− |
| + | |
− | print '\nvertices block =', hex(int(unpack('I', s[p : p + 4])[0]))
| + | |
− | p += 4
| + | |
− | print 'vertices block size =', unpack('I', s[p : p + 4])[0]
| + | |
− | p += 4
| + | |
− | verticesCount = unpack('I', s[p : p + 4])[0]
| + | |
− | p += 4
| + | |
− | print 'vertices count =', verticesCount
| + | |
− | for i in range(verticesCount):
| + | |
− | coords = unpack('3f', s[p : p + 12])
| + | |
− | print 'vertex%d =' % (i,), coords
| + | |
− | p += 12
| + | |
− |
| + | |
− | if useBlender:
| + | |
− | mesh.verts.extend([coords])
| + | |
− |
| + | |
− | print '\ntriangles block =', hex(int(unpack('I', s[p : p + 4])[0]))
| + | |
− | p += 4
| + | |
− | print 'triangles block size =', unpack('I', s[p : p + 4])[0]
| + | |
− | p += 4
| + | |
− |
| + | |
− | trianglesCount = unpack('I', s[p : p + 4])[0]
| + | |
− | p += 4
| + | |
− | print 'triangles count =', trianglesCount
| + | |
− |
| + | |
− | faces = []
| + | |
− | for i in range(trianglesCount):
| + | |
− | vertices = unpack('6I', s[p : p + 24])
| + | |
− | print 'triangle%d =' % (i,), vertices
| + | |
− | p += 24
| + | |
− |
| + | |
− | faces.append(vertices)
| + | |
− |
| + | |
− | print '\nsmoothgroups block =', hex(int(unpack('I', s[p : p + 4])[0]))
| + | |
− | p += 4
| + | |
− | size = unpack('I', s[p : p + 4])[0]
| + | |
− | p += 4
| + | |
− | print 'smoothgroups block size =', size
| + | |
− | for i in range(size / 4):
| + | |
− | x = unpack('I', s[p : p + 4])[0]
| + | |
− | print 'triangle%d =' % (i,), hex(int(x))
| + | |
− | p += 4
| + | |
− |
| + | |
− | print '\nuv map block =', hex(int(unpack('I', s[p : p + 4])[0]))
| + | |
− | p += 4
| + | |
− | size = unpack('I', s[p : p + 4])[0]
| + | |
− | p += 4
| + | |
− | print 'uv map block size =', size
| + | |
− | count = unpack('I', s[p : p + 4])[0]
| + | |
− | p += 4
| + | |
− | print 'count =', count
| + | |
− |
| + | |
− | layerIndices = []
| + | |
− | uvIndices = []
| + | |
− | for i in range(count):
| + | |
− | unknown = unpack('5B', s[p : p + 5])
| + | |
− | p += 5
| + | |
− |
| + | |
− | uvIndex = int(unpack('I', s[p : p + 4])[0])
| + | |
− | p += 4
| + | |
− |
| + | |
− | print 'uv index =', map(hex, unknown), uvIndex
| + | |
− |
| + | |
− | layerIndices.append(unknown[1])
| + | |
− | uvIndices.append(uvIndex)
| + | |
− |
| + | |
− |
| + | |
− | print '\nmaterials block =', hex(int(unpack('I', s[p : p + 4])[0]))
| + | |
− | p += 4
| + | |
− | size = unpack('I', s[p : p + 4])[0]
| + | |
− | p += 4
| + | |
− | print 'materials block size =', size
| + | |
− | materialsCount = unpack('H', s[p : p + 2])[0]
| + | |
− | p += 2
| + | |
− | print 'materials count =', materialsCount
| + | |
− |
| + | |
− | for i in range(materialsCount):
| + | |
− | materialName = ''
| + | |
− | b = unpack('B', s[p : p + 1])[0]
| + | |
− | p += 1
| + | |
− | while b != 0:
| + | |
− | materialName = materialName + chr(b)
| + | |
− | b = unpack('B', s[p : p + 1])[0]
| + | |
− | p += 1
| + | |
− | print 'material%d name =' % (i,), materialName
| + | |
− |
| + | |
− | trianglesCount = unpack('I', s[p : p + 4])[0]
| + | |
− | p += 4
| + | |
− | print 'triangles count =', trianglesCount
| + | |
− |
| + | |
− | print 'triangles indices =', map(int, unpack('%dI' % (trianglesCount,), s[p : p + 4 * trianglesCount]))
| + | |
− | p += 4 * trianglesCount
| + | |
− |
| + | |
− | print '\ntexcoords block =', hex(int(unpack('I', s[p : p + 4])[0]))
| + | |
− | p += 4
| + | |
− | size = unpack('I', s[p : p + 4])[0]
| + | |
− | p += 4
| + | |
− | print 'texcoords block size =', size
| + | |
− | uvTablesCount = unpack('I', s[p : p + 4])[0]
| + | |
− | p += 4
| + | |
− | print 'uv tables count =', uvTablesCount
| + | |
− |
| + | |
− |
| + | |
− | uvs = []
| + | |
− | for i in range(uvTablesCount):
| + | |
− | currentUv = []
| + | |
− | chanelName = ''
| + | |
− | b = unpack('B', s[p : p + 1])[0]
| + | |
− | p += 1
| + | |
− | while b != 0:
| + | |
− | chanelName = chanelName + chr(b)
| + | |
− | b = unpack('B', s[p : p + 1])[0]
| + | |
− | p += 1
| + | |
− | print 'name =', chanelName
| + | |
− |
| + | |
− | x = unpack('B', s[p : p + 1])[0]
| + | |
− | p += 1
| + | |
− | print 'unknown =', x
| + | |
− | layerIndex = unpack('H', s[p : p + 2])[0]
| + | |
− | p += 2
| + | |
− | print 'layer index =', layerIndex
| + | |
− | count = unpack('I', s[p : p + 4])[0]
| + | |
− | p += 4
| + | |
− | print 'uvs count =', count
| + | |
− |
| + | |
− | for j in range(count):
| + | |
− | uv = unpack('2f', s[p : p + 8])
| + | |
− | print 'uv%d =' % (j,), uv
| + | |
− | p += 8
| + | |
− |
| + | |
− | currentUv.append(uv)
| + | |
− | uvs.append(currentUv)
| + | |
− |
| + | |
− | for j in range(count):
| + | |
− | x = unpack('I', s[p : p + 4])[0]
| + | |
− | print 'index%d =' % (j,), int(x)
| + | |
− | p += 4
| + | |
| | | |
− | i = 0
| + | ''BONE_CHUNK_SHAPE'' = 0x0005, |
− | while len(s) > p:
| + | |
− | x = unpack('I', s[p : p + 4])[0]
| + | |
− | print 'unknown index%d =' % (i,), int(x)
| + | |
− | p += 4
| + | |
− | i += 1
| + | |
− |
| + | |
− | if useBlender:
| + | |
− | faceIndex = 0
| + | |
− | for faceInfo in faces:
| + | |
− | if faceInfo[4] == 0:
| + | |
− | faceInfo = faceInfo[2:] + faceInfo[:2]
| + | |
− | mesh.faces.extend(faceInfo[::2])
| + | |
− | face = mesh.faces[-1]
| + | |
| | | |
− | faceUvs = []
| + | ''BONE_CHUNK_IK_JOINT'' = 0x0006, |
− | for i in faceInfo[1::2]:
| + | |
− | faceUvs.append(Vector(uvs[layerIndices[i]][uvIndices[i]]))
| + | |
− | face.uv = faceUvs
| + | |
− |
| + | |
− | def parseString(s, p):
| + | |
− | string = ''
| + | |
− | b = unpack('B', s[p : p + 1])[0]
| + | |
− | p += 1
| + | |
− | while b != 0:
| + | |
− | string = string + chr(b)
| + | |
− | b = unpack('B', s[p : p + 1])[0]
| + | |
− | p += 1
| + | |
− | return string, p
| + | |
− |
| + | |
| | | |
− |
| + | ''BONE_CHUNK_MASS_PARAMS'' = 0x0007, |
− | def parseGeometryBlock(s):
| + | |
− | print '\ngeometry\n'
| + | |
− | p = 0
| + | |
− | while p < len(s):
| + | |
− | i = unpack('I', s[p : p + 4])[0]
| + | |
− | p += 4
| + | |
− | dataSize = unpack('I', s[p : p + 4])[0]
| + | |
− | print 'mesh%d data size = %d' % (i, dataSize)
| + | |
− | p += 4
| + | |
− | parseMeshData(s[p : p + dataSize])
| + | |
− | p += dataSize
| + | |
| | | |
| + | ''BONE_CHUNK_IK_FLAGS'' = 0x0008, |
| | | |
− | def parseMaterialBlock(s):
| + | ''BONE_CHUNK_BREAK_PARAMS'' = 0x0009, |
− | print '\nmaterials\n'
| + | |
− | p = 0
| + | |
− | materialsCount = unpack('I', s[p : p + 4])[0]
| + | |
− | p += 4
| + | |
− | print 'materials count =', materialsCount
| + | |
| | | |
− | for i in range(materialsCount):
| + | ''BONE_CHUNK_FRICTION'' = 0x0010 |
− | print '\n'
| + | |
− | materialName, p = parseString(s, p)
| + | |
− | print 'material%d name =' % (i,), materialName
| + | |
− |
| + | |
− | engineShader, p = parseString(s, p)
| + | |
− | print 'engine shader =', engineShader
| + | |
− |
| + | |
− | compilerShader, p = parseString(s, p)
| + | |
− | print 'compiler shader =', compilerShader
| + | |
| | | |
− | gameMaterial, p = parseString(s, p)
| + | ==Game Materials Library(из кода xrFSL)== |
− | print 'game material =', gameMaterial
| + | |
− |
| + | |
− | texturePath, p = parseString(s, p)
| + | |
− | print 'texture path =', texturePath
| + | |
− |
| + | |
− | texture, p = parseString(s, p)
| + | |
− | print 'texture =', texture
| + | |
| | | |
− | print 'flags (2 sided, etc) =', hex(int(unpack('I', s[p : p + 4])[0]))
| + | const uint16 ''GAMEMTLS_VERSION'' = 1; |
− | p += 4
| + | |
− |
| + | |
− | size = 8
| + | |
− | print 'unknown data =', map(hex, unpack('%dB' % (size,), s[p : p + size]))
| + | |
− | p += size
| + | |
− |
| + | |
− |
| + | |
− | def parseAuthorBlock(s):
| + | |
− | print '\nauthor\n'
| + | |
− | p = 0
| + | |
− | authorName, p = parseString(s, p)
| + | |
− | print 'author name =', authorName
| + | |
− |
| + | |
− | size = 4
| + | |
− | print 'creation date =', map(hex, unpack('%dB' % (size,), s[p : p + size]))
| + | |
− | p += size
| + | |
| | | |
− |
| + | ''GAMEMTLS_CHUNK_VERSION'' = 0x1000, |
− | modifierName, p = parseString(s, p)
| + | |
− | print 'modifier name =', modifierName
| + | |
− |
| + | |
− | print 'modification date =', map(hex, unpack('%dB' % (size,), s[p : p + size]))
| + | |
− | p += size
| + | |
− |
| + | |
− |
| + | |
− | def parseUserDataBlock(s):
| + | |
− | print '\nuser data\n'
| + | |
− | p = 0
| + | |
− | userData, p = parseString(s, p)
| + | |
− | print 'user data =', userData
| + | |
| | | |
− |
| + | ''GAMEMTLS_CHUNK_AUTOINC'' = 0x1001, |
− | def parseLODBlock(s):
| + | |
− | print '\nlod\n'
| + | |
− | p = 0
| + | |
− | reference, p = parseString(s, p)
| + | |
− | print 'lod reference =', reference
| + | |
− |
| + | |
| | | |
− | def parseFlagsBlock(s):
| + | GAMEMTLS_CHUNK_MATERIALS'' = 0x1002, |
− | print '\nflags (model type)\n'
| + | |
− | p = 0
| + | |
− | flags = unpack('I', s[p : p + 4])[0]
| + | |
− | print 'model type =', hex(int(flags))
| + | |
| | | |
− |
| + | ''GAMEMTLS_CHUNK_MATERIAL_PAIRS'' = 0x1003, |
− | print '\n' * 3
| + | |
| | | |
− | p = 0
| + | ''GAMEMTL_CHUNK_MAIN'' = 0x1000, |
− | header = unpack('I', s[p : p + 4])[0]
| + | |
− | print 'header =', hex(int(header))
| + | |
− | p += 4
| + | |
| | | |
− | dataSize = unpack('I', s[p : p + 4])[0]
| + | ''GAMEMTL_CHUNK_FLAGS'' = 0x1001, |
− | print 'data size =', dataSize
| + | |
− | p += 4
| + | |
| | | |
− | while p < len(s):
| + | ''GAMEMTL_CHUNK_PHYSICS'' = 0x1002, |
− | print '\n'
| + | |
− | print '=' * 79
| + | |
− | block = unpack('I', s[p : p + 4])[0]
| + | |
− | print 'block =', hex(int(block))
| + | |
− | p += 4
| + | |
− |
| + | |
− | blockSize = unpack('I', s[p : p + 4])[0]
| + | |
− | print 'block size =', blockSize
| + | |
− | p += 4
| + | |
| | | |
− | if block == 0x0910:
| + | ''GAMEMTL_CHUNK_FACTORS'' = 0x1003, |
− | parseGeometryBlock(s[p : p + blockSize])
| + | |
− | elif block == 0x0907:
| + | |
− | parseMaterialBlock(s[p : p + blockSize])
| + | |
− | elif block == 0x0922:
| + | |
− | parseAuthorBlock(s[p : p + blockSize])
| + | |
− | elif block == 0x0912:
| + | |
− | parseUserDataBlock(s[p : p + blockSize])
| + | |
− | elif block == 0x0925:
| + | |
− | parseLODBlock(s[p : p + blockSize])
| + | |
− | elif block == 0x0903:
| + | |
− | parseFlagsBlock(s[p : p + blockSize])
| + | |
− | else:
| + | |
− | print 'unknown data =', map(hex, unpack('%dB' % (blockSize,), s[p : p + blockSize]))
| + | |
− | p += blockSize
| + | |
− | </code>
| + | |
| | | |
− | === Результат === | + | ''GAMEMTL_CHUNK_FLOTATION'' = 0x1004, |
− | <code>
| + | |
− | header = 0x7777
| + | |
− | data size = 1113
| + | |
| | | |
| + | ''GAMEMTL_CHUNK_DESC'' = 0x1005, |
| | | |
− | ===============================================================================
| + | ''GAMEMTL_CHUNK_INJURY'' = 0x1006, |
− | block = 0x900
| + | |
− | block size = 2
| + | |
− | unknown data = ['0x10', '0x0']
| + | |
| | | |
| | | |
− | =============================================================================== | + | ''GAMEMTLPAIR_CHUNK_PAIR'' = 0x1000, |
− | block = 0x912
| + | |
− | block size = 1
| + | |
| | | |
− | user data
| + | ''GAMEMTLPAIR_CHUNK_BREAKING'' = 0x1002, |
| | | |
− | user data =
| + | ''GAMEMTLPAIR_CHUNK_STEP'' = 0x1003, |
| | | |
| + | ''GAMEMTLPAIR_CHUNK_COLLIDE'' = 0x1005, |
| | | |
− | ===============================================================================
| |
− | block = 0x925
| |
− | block size = 1
| |
| | | |
− | lod
| + | '''SGameMaterial:''' |
| | | |
− | lod reference =
| + | ''MF_BREAKABLE'' = 0x00000001, |
| | | |
| + | ''MF_BOUNCEABLE'' = 0x00000004, |
| | | |
− | =============================================================================== | + | ''MF_SKIDMARK'' = 0x00000008, |
− | block = 0x903
| + | |
− | block size = 4
| + | |
| | | |
− | flags (model type)
| + | ''MF_BLOODMARK'' = 0x00000010, |
| | | |
− | model type = 0x0
| + | ''MF_CLIMABLE'' = 0x00000020, |
| | | |
| + | ''MF_PASSABLE'' = 0x00000080, |
| | | |
− | =============================================================================== | + | ''MF_DYNAMIC'' = 0x00000100, |
− | block = 0x910
| + | |
− | block size = 929
| + | |
| | | |
− | geometry
| + | ''MF_LIQUID'' = 0x00000200, |
| | | |
− | mesh0 data size = 921
| + | ''MF_SUPPRESS_SHADOWS'' = 0x00000400, |
| | | |
− | unknown block = 0x1000
| + | ''MF_SUPPRESS_WALLMARKS'' = 0x00000800, |
− | unknown block size = 2
| + | |
− | unknown data = ['0x11', '0x0']
| + | |
| | | |
− | name block = 0x1001
| + | ''MF_ACTOR_OBSTACLE'' = 0x00001000, |
− | name block size = 8
| + | |
− | name = Plane10
| + | |
| | | |
− | bbox block = 0x1004
| + | ''MF_INJURIOUS'' = 0x10000000, |
− | bbox block size = 24
| + | |
− | bbox min = (-0.089013084769248962, 0.00091872771736234426, -0.05408264324069023
| + | |
− | 1)
| + | |
− | bbox max = (0.064492635428905487, 0.017687048763036728, 0.050194162875413895)
| + | |
| | | |
− | unknown block = 0x1002
| + | ''MF_SHOOTABLE'' = 0x20000000, |
− | unknown block size = 1
| + | |
− | unknown data = ['0x5']
| + | |
| | | |
− | unknown block = 0x1010
| + | ''MF_TRANSPARENT'' = 0x40000000, |
− | unknown block size = 8
| + | |
− | unknown data = ['0x0', '0x0', '0x0', '0x0', '0x0', '0x0', '0x0', '0x0']
| + | |
| | | |
− | vertices block = 0x1005
| + | ''MF_SLOW_DOWN'' = 0x80000000, |
− | vertices block size = 88
| + | |
− | vertices count = 7
| + | |
− | vertex0 = (-0.0019903033971786499, 0.001169001217931509, 0.0068940594792366028)
| + | |
− | vertex1 = (-0.089013084769248962, 0.00091872771736234426, 0.045723527669906616)
| + | |
− | vertex2 = (0.006468137726187706, 0.0094316964969038963, 0.050194162875413895)
| + | |
− | vertex3 = (-0.039456427097320557, 0.0043633054010570049, -0.039133470505475998)
| + | |
− | vertex4 = (0.023728765547275543, 0.0064991358667612076, -0.054082643240690231)
| + | |
− | vertex5 = (0.031571760773658752, 0.0060988827608525753, 0.0041843997314572334)
| + | |
− | vertex6 = (0.064492635428905487, 0.017687048763036728, -0.038134712725877762)
| + | |
| | | |
− | triangles block = 0x1006
| |
− | triangles block size = 148
| |
− | triangles count = 6
| |
− | triangle0 = (0, 2, 1, 1, 2, 0)
| |
− | triangle1 = (0, 8, 3, 7, 1, 6)
| |
− | triangle2 = (0, 11, 4, 10, 3, 9)
| |
− | triangle3 = (5, 14, 6, 13, 4, 12)
| |
− | triangle4 = (0, 17, 2, 16, 5, 15)
| |
− | triangle5 = (0, 20, 5, 19, 4, 18)
| |
| | | |
− | smoothgroups block = 0x1013
| + | '''SGameMaterialPair:''' |
− | smoothgroups block size = 24
| + | |
− | triangle0 = 0x1
| + | |
− | triangle1 = 0x1
| + | |
− | triangle2 = 0x1
| + | |
− | triangle3 = 0x1
| + | |
− | triangle4 = 0x1
| + | |
− | triangle5 = 0x1
| + | |
| | | |
− | uv map block = 0x1008
| + | ''MPF_BREAKING_SOUNDS'' = 0x02, |
− | uv map block size = 193
| + | |
− | count = 21
| + | |
− | uv index = ['0x1', '0x0', '0x0', '0x0', '0x0'] 2
| + | |
− | uv index = ['0x1', '0x0', '0x0', '0x0', '0x0'] 1
| + | |
− | uv index = ['0x1', '0x0', '0x0', '0x0', '0x0'] 0
| + | |
− | uv index = ['0x1', '0x90', '0xdb', '0x11', '0x7'] 12
| + | |
− | uv index = ['0x1', '0x18', '0x87', '0x10', '0x7'] 12
| + | |
− | uv index = ['0x1', '0x80', '0x8c', '0x10', '0x7'] 12
| + | |
− | uv index = ['0x1', '0x1', '0x0', '0x0', '0x0'] 1
| + | |
− | uv index = ['0x1', '0x0', '0x0', '0x0', '0x0'] 3
| + | |
− | uv index = ['0x1', '0x1', '0x0', '0x0', '0x0'] 0
| + | |
− | uv index = ['0x1', '0x1', '0x0', '0x0', '0x0'] 3
| + | |
− | uv index = ['0x1', '0x0', '0x0', '0x0', '0x0'] 4
| + | |
− | uv index = ['0x1', '0x1', '0x0', '0x0', '0x0'] 2
| + | |
− | uv index = ['0x1', '0x1', '0x0', '0x0', '0x0'] 4
| + | |
− | uv index = ['0x1', '0x0', '0x0', '0x0', '0x0'] 6
| + | |
− | uv index = ['0x1', '0x0', '0x0', '0x0', '0x0'] 5
| + | |
− | uv index = ['0x1', '0x1', '0x0', '0x0', '0x0'] 7
| + | |
− | uv index = ['0x1', '0x1', '0x0', '0x0', '0x0'] 6
| + | |
− | uv index = ['0x1', '0x1', '0x0', '0x0', '0x0'] 5
| + | |
− | uv index = ['0x1', '0x1', '0x0', '0x0', '0x0'] 10
| + | |
− | uv index = ['0x1', '0x1', '0x0', '0x0', '0x0'] 9
| + | |
− | uv index = ['0x1', '0x1', '0x0', '0x0', '0x0'] 8
| + | |
| | | |
− | materials block = 0x1009
| + | ''MPF_STEP_SOUNDS'' = 0x04, |
− | materials block size = 43
| + | |
− | materials count = 1
| + | |
− | material0 name = 01 - Default
| + | |
− | triangles count = 6
| + | |
− | triangles indices = [0, 1, 2, 3, 4, 5]
| + | |
| | | |
− | texcoords block = 0x1012
| + | ''MPF_COLLIDE_SOUNDS'' = 0x10, |
− | texcoords block size = 294
| + | |
− | uv tables count = 2
| + | |
− | name = Texture
| + | |
− | unknown = 2
| + | |
− | layer index = 0
| + | |
− | uvs count = 7
| + | |
− | uv0 = (0.72911489009857178, 0.70259565114974976)
| + | |
− | uv1 = (0.4648970365524292, 0.95080757141113281)
| + | |
− | uv2 = (0.55649280548095703, 0.58906811475753784)
| + | |
− | uv3 = (0.97081756591796875, 0.88250058889389038)
| + | |
− | uv4 = (0.97814416885375977, 0.69620668888092041)
| + | |
− | uv5 = (0.75604760646820068, 0.52614188194274902)
| + | |
− | uv6 = (0.98893237113952637, 0.51763355731964111)
| + | |
− | index0 = 0
| + | |
− | index1 = 1
| + | |
− | index2 = 2
| + | |
− | index3 = 3
| + | |
− | index4 = 4
| + | |
− | index5 = 5
| + | |
− | index6 = 6
| + | |
− | name = Texture
| + | |
− | unknown = 2
| + | |
− | layer index = 1
| + | |
− | uvs count = 11
| + | |
− | uv0 = (0.72911489009857178, 0.70259565114974976)
| + | |
− | uv1 = (0.4648970365524292, 0.95080757141113281)
| + | |
− | uv2 = (0.72911489009857178, 0.70259565114974976)
| + | |
− | uv3 = (0.97081756591796875, 0.88250058889389038)
| + | |
− | uv4 = (0.97814416885375977, 0.69620668888092041)
| + | |
− | uv5 = (0.72911489009857178, 0.70259565114974976)
| + | |
− | uv6 = (0.5510140061378479, 0.58371180295944214)
| + | |
− | uv7 = (0.75604760646820068, 0.52614188194274902)
| + | |
− | uv8 = (0.72911489009857178, 0.70259565114974976)
| + | |
− | uv9 = (0.75604760646820068, 0.52614188194274902)
| + | |
− | uv10 = (0.97814416885375977, 0.69620668888092041)
| + | |
− | index0 = 0
| + | |
− | index1 = 1
| + | |
− | index2 = 0
| + | |
− | index3 = 3
| + | |
− | index4 = 4
| + | |
− | index5 = 0
| + | |
− | index6 = 2
| + | |
− | index7 = 5
| + | |
− | index8 = 0
| + | |
− | index9 = 5
| + | |
− | index10 = 4
| + | |
− | unknown index0 = 1
| + | |
− | unknown index1 = 1
| + | |
− | unknown index2 = 2
| + | |
− | unknown index3 = 2
| + | |
− | unknown index4 = 3
| + | |
− | unknown index5 = 4
| + | |
− | unknown index6 = 4
| + | |
− | unknown index7 = 4
| + | |
− | unknown index8 = 5
| + | |
− | unknown index9 = 5
| + | |
− | unknown index10 = 5
| + | |
| | | |
| + | ''MPF_COLLIDE_PARTICLES'' = 0x20, |
| | | |
− | =============================================================================== | + | ''MPF_COLLIDE_MARKS'' = 0x40, |
− | block = 0x907
| + | |
− | block size = 82
| + | |
| | | |
− | materials
| + | ==Engine Shader Library== |
| + | |
| + | // guessed names |
| | | |
− | materials count = 1
| + | ''SHADERS_CHUNK_CONSTANTS'' = 0, |
| | | |
| + | ''SHADERS_CHUNK_MATRICES'' = 1, |
| | | |
− | material0 name = 01 - Default
| + | ''SHADERS_CHUNK_BLENDERS'' = 2, |
− | engine shader = details\blend
| + | |
− | compiler shader = default
| + | |
− | game material = default
| + | |
− | texture path = det\det_listya
| + | |
− | texture = Texture
| + | |
− | flags (2 sided, etc) = 0x0
| + | |
− | unknown data = ['0x12', '0x1', '0x0', '0x0', '0x1', '0x0', '0x0', '0x0']
| + | |
| | | |
| + | ''SHADERS_CHUNK_NAMES'' = 3 |
| | | |
− | =============================================================================== | + | ====Разобрал bardak, Neo==== |
− | block = 0x922
| + | |
− | block size = 38
| + | |
| | | |
− | author
| + | ===[[Попытка #1 от excid]]=== |
| | | |
− | author name = \\SUSHKA\cy-27
| + | ===Ссылки=== |
− | creation date = ['0xf', '0x28', '0x98', '0x43']
| + | Утилиты так или иначе связанные с импортом\экспортом object: |
− | modifier name = \\SUSHKA\cy-27
| + | *[http://stalkerin.gameru.net/modules.php?name=Downloads&d_op=getit&lid=318 xrFSL MaxTools 0.1.1] от '''Neo][''' |
− | modification date = ['0xf', '0x28', '0x98', '0x43']
| + | *[http://stalkerin.gameru.net/modules.php?name=Downloads&d_op=getit&lid=350 X-RAY Max Tools export beta 2] от '''bardak''' |
− | </code>
| + | *[http://stalkerin.gameru.net/modules.php?name=Downloads&d_op=getit&lid=287 X-RAY Tools src] от '''bardak''' |
| + | *[http://stalkerin.gameru.net/modules.php?name=Downloads&d_op=getit&lid=348 X-RAY Tools update 2.0] от '''bardak''' |
| + | *[http://stalkerin.gameru.net/modules.php?name=Downloads&d_op=getit&lid=288 X-RAY Tools] от '''bardak''' |
| + | *[http://stalkerin.gameru.net/modules.php?name=Downloads&d_op=getit&lid=349 Maya 2009 plugin import/export] от '''bardak''' |
| + | *[http://stalkerin.gameru.net/modules.php?name=Downloads&d_op=getit&lid=347 Maya 2008 plugin import/export] от '''bardak''' |
| + | *[http://stalkerin.gameru.net/modules.php?name=Downloads&d_op=getit&lid=330 Object Format] от '''Neo][, bardak''' |
| + | *[http://stalkerin.gameru.net/modules.php?name=Downloads&d_op=getit&lid=100 3DSMax 7 plugin export v.1.1] от '''GSC''' |
| + | *[http://stalkerin.gameru.net/modules.php?name=Downloads&d_op=getit&lid=98 3DSMax 8 plugin export v.2.0] от '''GSC''' |
| + | *[https://github.com/igelbox/blender-xray/releases Blender X-Ray Engine Tools] от '''igelbox''' |
| + | *[https://github.com/PavelBlend/Blender_Stalker_Object Blender Import Object] от '''Pavel_Blend''' |
| [[Категория:Форматы файлов]] | | [[Категория:Форматы файлов]] |
Формат *.object используется в качестве основного формата хранения моделей на этапе редактирования (включая экспорт из Maya или 3ds Max и хранение моделей до компиляции уровня)