mirror of
https://github.com/YorhaX2P/NieR2Blender2NieR-PS4.git
synced 2026-08-26 19:43:33 +00:00
3.0.0 pre-release
This commit is contained in:
+165
-48
@@ -1,11 +1,11 @@
|
||||
bl_info = {
|
||||
"name": "NieR2Blender (NieR:Automata Model Importer)",
|
||||
"name": "NieR2Blender (NieR:Automata Data Importer)",
|
||||
"author": "Woeful_Wolf (Original by C4nf3ng)",
|
||||
"version": (2, 2),
|
||||
"version": (3, 0),
|
||||
"blender": (2, 80, 0),
|
||||
"api": 38019,
|
||||
"location": "File > Import",
|
||||
"description": "Import Nier:Automata Model Data",
|
||||
"description": "Import Nier:Automata Data",
|
||||
"warning": "",
|
||||
"wiki_url": "",
|
||||
"tracker_url": "",
|
||||
@@ -32,6 +32,45 @@ class ImportNier2blender(bpy.types.Operator, ImportHelper):
|
||||
wmb_importer.reset_blend()
|
||||
return wmb_importer.main(False, self.filepath)
|
||||
|
||||
def importDat(only_extract, filepath):
|
||||
head = os.path.split(filepath)[0]
|
||||
tail = os.path.split(filepath)[1]
|
||||
tailless_tail = tail[:-4]
|
||||
dat_filepath = head + '\\' + tailless_tail + '.dat'
|
||||
extract_dir = head + '\\nier2blender_extracted'
|
||||
from . import dat_unpacker
|
||||
if os.path.isfile(dat_filepath):
|
||||
dat_unpacker.main(dat_filepath, extract_dir + '\\' + tailless_tail + '.dat', dat_filepath) # dat
|
||||
else:
|
||||
print('DAT not found. Only extracting DTT. (No materials, collisions or layouts will automatically be imported)')
|
||||
|
||||
last_filename = dat_unpacker.main(filepath, extract_dir + '\\' + tailless_tail + '.dtt', filepath) # dtt
|
||||
|
||||
wmb_filepath = extract_dir + '\\' + tailless_tail + '.dtt\\' + last_filename[:-4] + '.wmb'
|
||||
if not os.path.exists(wmb_filepath):
|
||||
wmb_filepath = extract_dir + '\\' + tailless_tail + '.dat\\' + last_filename[:-4] + '.wmb' # if not in dtt, then must be in dat
|
||||
|
||||
# WMB
|
||||
from . import wmb_importer
|
||||
wmb_importer.main(only_extract, wmb_filepath)
|
||||
|
||||
if only_extract:
|
||||
return {'FINISHED'}
|
||||
|
||||
# COL
|
||||
col_filepath = extract_dir + '\\' + tailless_tail + '.dat\\' + tailless_tail + '.col'
|
||||
if os.path.isfile(col_filepath):
|
||||
from . import col_importer
|
||||
col_importer.main(col_filepath)
|
||||
|
||||
# LAY
|
||||
lay_filepath = extract_dir + '\\' + tailless_tail + '.dat\\' + 'Layout.lay'
|
||||
if os.path.isfile(lay_filepath):
|
||||
from . import lay_importer
|
||||
lay_importer.main(lay_filepath, __name__)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
class ImportDATNier2blender(bpy.types.Operator, ImportHelper):
|
||||
'''Load a Nier:Automata DTT (and DAT) File.'''
|
||||
bl_idname = "import_scene.dtt_data"
|
||||
@@ -54,69 +93,147 @@ class ImportDATNier2blender(bpy.types.Operator, ImportHelper):
|
||||
if filename[-4:] == '.dtt':
|
||||
try:
|
||||
filepath = folder + '\\' + filename
|
||||
head = os.path.split(filepath)[0]
|
||||
tail = os.path.split(filepath)[1]
|
||||
tailless_tail = tail[:-4]
|
||||
dat_filepath = head + '\\' + tailless_tail + '.dat'
|
||||
extract_dir = head + '\\nier2blender_extracted'
|
||||
from . import dat_unpacker
|
||||
if os.path.isfile(dat_filepath):
|
||||
dat_unpacker.main(dat_filepath, extract_dir + '\\' + tailless_tail + '.dat', dat_filepath) # dat
|
||||
else:
|
||||
print('DAT not found. Only extracting DTT. (No materials will automatically be imported)')
|
||||
|
||||
wtp_filename = dat_unpacker.main(filepath, extract_dir + '\\' + tailless_tail + '.dtt', filepath) # dtt
|
||||
|
||||
wmb_filepath = extract_dir + '\\' + tailless_tail + '.dtt\\' + wtp_filename[:-4] + '.wmb'
|
||||
if not os.path.exists(wmb_filepath):
|
||||
wmb_filepath = extract_dir + '\\' + tailless_tail + '.dat\\' + wtp_filename[:-4] + '.wmb' # if not in dtt, then must be in dat
|
||||
|
||||
wmb_importer.main(self.only_extract, wmb_filepath)
|
||||
importDat(self.only_extract, filepath)
|
||||
except:
|
||||
print('ERROR: FAILED TO IMPORT', filename)
|
||||
return {'FINISHED'}
|
||||
|
||||
else:
|
||||
head = os.path.split(self.filepath)[0]
|
||||
tail = os.path.split(self.filepath)[1]
|
||||
tailless_tail = tail[:-4]
|
||||
dat_filepath = head + '\\' + tailless_tail + '.dat'
|
||||
extract_dir = head + '\\nier2blender_extracted'
|
||||
from . import dat_unpacker
|
||||
if os.path.isfile(dat_filepath):
|
||||
dat_unpacker.main(dat_filepath, extract_dir + '\\' + tailless_tail + '.dat', dat_filepath) # dat
|
||||
else:
|
||||
print('DAT not found. Only extracting DTT. (No materials will automatically be imported)')
|
||||
return importDat(self.only_extract, self.filepath)
|
||||
|
||||
wtp_filename = dat_unpacker.main(self.filepath, extract_dir + '\\' + tailless_tail + '.dtt', self.filepath) # dtt
|
||||
class ImportColNier2Blender(bpy.types.Operator, ImportHelper):
|
||||
'''Load a Nier:Automata Col (Collision) File.'''
|
||||
bl_idname = "import_scene.col_data"
|
||||
bl_label = "Import Col Data"
|
||||
bl_options = {'PRESET'}
|
||||
filename_ext = ".col"
|
||||
filter_glob: StringProperty(default="*.col", options={'HIDDEN'})
|
||||
|
||||
wmb_filepath = extract_dir + '\\' + tailless_tail + '.dtt\\' + wtp_filename[:-4] + '.wmb'
|
||||
if not os.path.exists(wmb_filepath):
|
||||
wmb_filepath = extract_dir + '\\' + tailless_tail + '.dat\\' + wtp_filename[:-4] + '.wmb' # if not in dtt, then must be in dat
|
||||
def execute(self, context):
|
||||
from . import col_importer
|
||||
return col_importer.main(self.filepath)
|
||||
|
||||
from . import wmb_importer
|
||||
return wmb_importer.main(self.only_extract, wmb_filepath)
|
||||
class ImportLayNier2Blender(bpy.types.Operator, ImportHelper):
|
||||
'''Load a Nier:Automata Lay (Layout) File.'''
|
||||
bl_idname = "import_scene.lay_data"
|
||||
bl_label = "Import Lay Data"
|
||||
bl_options = {'PRESET'}
|
||||
filename_ext = ".lay"
|
||||
filter_glob: StringProperty(default="*.lay", options={'HIDDEN'})
|
||||
|
||||
# Registration
|
||||
def execute(self, context):
|
||||
from . import lay_importer
|
||||
return lay_importer.main(self.filepath, __name__)
|
||||
|
||||
class SelectDirectory(bpy.types.Operator, ImportHelper):
|
||||
'''Select Directory'''
|
||||
bl_idname = "n2b.folder_select"
|
||||
bl_label = "Select Directory"
|
||||
filename_ext = ""
|
||||
dirpath : StringProperty(name = "", description="Choose directory:", subtype='DIR_PATH')
|
||||
|
||||
target : bpy.props.StringProperty(options={'HIDDEN'})
|
||||
|
||||
def execute(self, context):
|
||||
directory = os.path.dirname(self.filepath)
|
||||
if self.target == "data005":
|
||||
context.preferences.addons[__name__].preferences.data005_dir = directory
|
||||
elif self.target == "data015":
|
||||
context.preferences.addons[__name__].preferences.data015_dir = directory
|
||||
else:
|
||||
print("Invalid target", self.target)
|
||||
return {"CANCELLED"}
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
class NieR2BlenderPreferences(bpy.types.AddonPreferences):
|
||||
bl_idname = __package__
|
||||
data005_dir : StringProperty(options={'HIDDEN'})
|
||||
data015_dir : StringProperty(options={'HIDDEN'})
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.label(text="Assign Directories Below If You Wish To Enable Bounding Box Visualization With Layout Import:")
|
||||
box = layout.box()
|
||||
box.label(text="Path To Extracted data005.cpk Directory:")
|
||||
row = box.row(align=True)
|
||||
row.prop(self, "data005_dir", text="")
|
||||
row.operator("n2b.folder_select", icon="FILE_FOLDER", text="").target = "data005"
|
||||
|
||||
box.label(text="Path To Extracted data015.cpk Directory:")
|
||||
row = box.row(align=True)
|
||||
row.prop(self, "data015_dir", text="")
|
||||
row.operator("n2b.folder_select", icon="FILE_FOLDER", text="").target = "data015"
|
||||
|
||||
class NieR2BlenderCreateObjBBox(bpy.types.Operator):
|
||||
"""Create Layout Object Bounding Box"""
|
||||
bl_idname = "n2b.create_lay_bb"
|
||||
bl_label = "Create Layout Object Bounding Box"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
def execute(self, context):
|
||||
from .lay_importer import getModelBoundingBox, createBoundingBoxObject
|
||||
for obj in bpy.context.selected_objects:
|
||||
boundingBox = getModelBoundingBox(obj.name.split("_")[0], __name__)
|
||||
createBoundingBoxObject(obj, obj.name + "-BoundingBox", bpy.data.collections.get("lay_layAssets"), boundingBox)
|
||||
return {'FINISHED'}
|
||||
|
||||
class N2BLayoutObjectMenu(bpy.types.Menu):
|
||||
bl_idname = 'OBJECT_MT_n2blayout'
|
||||
bl_label = 'NieR2Blender'
|
||||
def draw(self, context):
|
||||
self.layout.operator(NieR2BlenderCreateObjBBox.bl_idname, icon="CUBE")
|
||||
|
||||
def menu_func_utils(self, context):
|
||||
pcoll = preview_collections["main"]
|
||||
yorha_icon = pcoll["yorha"]
|
||||
self.layout.menu(N2BLayoutObjectMenu.bl_idname, icon_value=yorha_icon.icon_id)
|
||||
|
||||
def menu_func_import(self, context):
|
||||
self.layout.operator(ImportNier2blender.bl_idname, text="WMB File for Nier:Automata (.wmb)")
|
||||
pcoll = preview_collections["main"]
|
||||
yorha_icon = pcoll["yorha"]
|
||||
self.layout.operator(ImportDATNier2blender.bl_idname, text="DTT File for Nier:Automata (.dtt)", icon_value=yorha_icon.icon_id)
|
||||
self.layout.operator(ImportNier2blender.bl_idname, text="WMB File for Nier:Automata (.wmb)", icon_value=yorha_icon.icon_id)
|
||||
self.layout.operator(ImportColNier2Blender.bl_idname, text="Collision File for Nier:Automata (.col)", icon_value=yorha_icon.icon_id)
|
||||
self.layout.operator(ImportLayNier2Blender.bl_idname, text="Layout File for Nier:Automata (.lay)", icon_value=yorha_icon.icon_id)
|
||||
|
||||
def menu_func_import_dat(self, context):
|
||||
self.layout.operator(ImportDATNier2blender.bl_idname, text="DTT File for Nier:Automata (.dtt)")
|
||||
classes = (
|
||||
ImportNier2blender,
|
||||
ImportDATNier2blender,
|
||||
ImportColNier2Blender,
|
||||
ImportLayNier2Blender,
|
||||
SelectDirectory,
|
||||
NieR2BlenderPreferences,
|
||||
NieR2BlenderCreateObjBBox,
|
||||
N2BLayoutObjectMenu
|
||||
)
|
||||
|
||||
preview_collections = {}
|
||||
|
||||
def register():
|
||||
bpy.utils.register_class(ImportNier2blender)
|
||||
bpy.utils.register_class(ImportDATNier2blender)
|
||||
# Custom icons
|
||||
import bpy.utils.previews
|
||||
pcoll = bpy.utils.previews.new()
|
||||
my_icons_dir = os.path.join(os.path.dirname(__file__), "icons")
|
||||
pcoll.load("yorha", os.path.join(my_icons_dir, "yorha-filled.png"), 'IMAGE')
|
||||
preview_collections["main"] = pcoll
|
||||
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
|
||||
bpy.types.TOPBAR_MT_file_import.append(menu_func_import_dat)
|
||||
bpy.types.VIEW3D_MT_object.append(menu_func_utils)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.utils.unregister_class(ImportNier2blender)
|
||||
bpy.utils.unregister_class(ImportDATNier2blender)
|
||||
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
|
||||
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import_dat)
|
||||
for pcoll in preview_collections.values():
|
||||
bpy.utils.previews.remove(pcoll)
|
||||
preview_collections.clear()
|
||||
|
||||
for cls in classes:
|
||||
bpy.utils.unregister_class(cls)
|
||||
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
|
||||
bpy.types.VIEW3D_MT_object.remove(menu_func_utils)
|
||||
|
||||
if __name__ == '__main__':
|
||||
register()
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
# https://github.com/Kerilk/bayonetta_tools/blob/master/binary_templates/Nier%20Automata%20col.bt
|
||||
|
||||
from .util import *
|
||||
|
||||
class Header:
|
||||
def __init__(self, colFile):
|
||||
self.id = colFile.read(4)
|
||||
self.version = "%08x" % (to_uint(colFile.read(4)))
|
||||
|
||||
self.offsetNames = to_uint(colFile.read(4))
|
||||
self.nameCount = to_uint(colFile.read(4))
|
||||
|
||||
self.offsetMeshes = to_uint(colFile.read(4))
|
||||
self.meshCount = to_uint(colFile.read(4))
|
||||
|
||||
self.offsetBoneMap = to_uint(colFile.read(4))
|
||||
self.boneMapCount = to_uint(colFile.read(4))
|
||||
|
||||
self.offsetBoneMap2 = to_uint(colFile.read(4))
|
||||
self.boneMap2Count = to_uint(colFile.read(4))
|
||||
|
||||
self.offsetMeshMap = to_uint(colFile.read(4))
|
||||
self.meshMapCount = to_uint(colFile.read(4))
|
||||
|
||||
self.offsetColTreeNodes = to_uint(colFile.read(4))
|
||||
self.colTreeNodesCount = to_uint(colFile.read(4))
|
||||
|
||||
class NameGroups:
|
||||
def __init__(self, colFile, header):
|
||||
self.offsetNames = []
|
||||
for i in range(header.nameCount):
|
||||
self.offsetNames.append(to_uint(colFile.read(4)))
|
||||
|
||||
self.names = []
|
||||
for offsetName in self.offsetNames:
|
||||
colFile.seek(offsetName)
|
||||
self.names.append(to_string(colFile.read(256)))
|
||||
|
||||
class Batch:
|
||||
def __init__(self, colFile, batchType):
|
||||
if batchType == 2:
|
||||
self.boneIndex = to_int(colFile.read(4))
|
||||
self.offsetVertices = to_uint(colFile.read(4))
|
||||
self.vertexCount = to_uint(colFile.read(4))
|
||||
self.offsetIndices = to_uint(colFile.read(4))
|
||||
self.indexCount = to_uint(colFile.read(4))
|
||||
|
||||
returnPos = colFile.tell()
|
||||
|
||||
colFile.seek(self.offsetVertices)
|
||||
self.vertices = []
|
||||
self.vec4Vertices = []
|
||||
for i in range(self.vertexCount):
|
||||
x = to_float(colFile.read(4))
|
||||
y = to_float(colFile.read(4))
|
||||
z = to_float(colFile.read(4))
|
||||
w = to_float(colFile.read(4))
|
||||
self.vertices.append([x, y, z])
|
||||
self.vec4Vertices.append([x, y, z, w])
|
||||
|
||||
colFile.seek(self.offsetIndices)
|
||||
self.indices = []
|
||||
self.rawIndices = []
|
||||
for i in range(round(self.indexCount / 3)):
|
||||
v0 = to_ushort(colFile.read(2))
|
||||
v1 = to_ushort(colFile.read(2))
|
||||
v2 = to_ushort(colFile.read(2))
|
||||
self.rawIndices.append(v0)
|
||||
self.rawIndices.append(v1)
|
||||
self.rawIndices.append(v2)
|
||||
self.indices.append([v2, v1, v0])
|
||||
|
||||
colFile.seek(returnPos)
|
||||
|
||||
elif batchType == 3:
|
||||
self.offsetVertices = to_uint(colFile.read(4))
|
||||
self.vertexCount = to_uint(colFile.read(4))
|
||||
self.offsetIndices = to_uint(colFile.read(4))
|
||||
self.indexCount = to_uint(colFile.read(4))
|
||||
|
||||
returnPos = colFile.tell()
|
||||
else:
|
||||
print("UNKNOWN BATCH TYPE!")
|
||||
|
||||
class Mesh:
|
||||
def __init__(self, colFile):
|
||||
self.collisionType = to_uint(colFile.read(1))
|
||||
self.slidable = to_uint(colFile.read(1))
|
||||
self.unknownByte = to_uint(colFile.read(1))
|
||||
self.surfaceType = to_uint(colFile.read(1))
|
||||
|
||||
self.nameIndex = to_uint(colFile.read(4))
|
||||
self.batchType = to_uint(colFile.read(4))
|
||||
self.offsetBatches = to_uint(colFile.read(4))
|
||||
self.batchCount = to_uint(colFile.read(4))
|
||||
|
||||
returnPos = colFile.tell()
|
||||
|
||||
colFile.seek(self.offsetBatches)
|
||||
self.batches = []
|
||||
for i in range(self.batchCount):
|
||||
self.batches.append(Batch(colFile, self.batchType))
|
||||
|
||||
colFile.seek(returnPos)
|
||||
|
||||
class ColTreeNode:
|
||||
def __init__(self, colFile):
|
||||
self.p1 = [to_float(colFile.read(4)), to_float(colFile.read(4)), to_float(colFile.read(4))]
|
||||
self.p2 = [to_float(colFile.read(4)), to_float(colFile.read(4)), to_float(colFile.read(4))]
|
||||
|
||||
self.left = to_int(colFile.read(4))
|
||||
self.right = to_int(colFile.read(4))
|
||||
|
||||
self.offsetMeshIndices = to_uint(colFile.read(4))
|
||||
self.meshIndexCount = to_uint(colFile.read(4))
|
||||
|
||||
self.meshIndices = []
|
||||
if self.offsetMeshIndices != 0 and self.meshIndexCount != 0:
|
||||
returnPos = colFile.tell()
|
||||
colFile.seek(self.offsetMeshIndices)
|
||||
for i in range(self.meshIndexCount):
|
||||
self.meshIndices.append(to_uint(colFile.read(4)))
|
||||
colFile.seek(returnPos)
|
||||
|
||||
class Col:
|
||||
def __init__(self, colFile):
|
||||
self.header = Header(colFile)
|
||||
|
||||
colFile.seek(self.header.offsetNames)
|
||||
self.nameGroups = NameGroups(colFile, self.header)
|
||||
|
||||
colFile.seek(self.header.offsetMeshes)
|
||||
self.meshes = []
|
||||
for i in range(self.header.meshCount):
|
||||
self.meshes.append(Mesh(colFile))
|
||||
|
||||
self.meshMaps = []
|
||||
if self.header.meshMapCount > 0:
|
||||
colFile.seek(self.header.offsetMeshMap)
|
||||
for i in range(self.header.meshMapCount):
|
||||
self.meshMaps.append(to_uint(colFile.read(4)))
|
||||
|
||||
self.boneMaps = []
|
||||
if self.header.boneMapCount > 0:
|
||||
colFile.seek(self.header.offsetBoneMap)
|
||||
for i in range(self.header.boneMapCount):
|
||||
self.boneMaps.append(to_uint(colFile.read(4)))
|
||||
|
||||
self.boneMaps2 = []
|
||||
if self.header.boneMap2Count > 0:
|
||||
colFile.seek(self.header.offsetBoneMap2)
|
||||
for i in range(self.header.boneMap2Count):
|
||||
self.boneMaps2.append(to_uint(colFile.read(4)))
|
||||
|
||||
self.colTreeNodes = []
|
||||
if self.header.colTreeNodesCount > 0:
|
||||
colFile.seek(self.header.offsetColTreeNodes)
|
||||
for i in range(self.header.colTreeNodesCount):
|
||||
self.colTreeNodes.append(ColTreeNode(colFile))
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
import bpy, math
|
||||
from .col import Col
|
||||
|
||||
collisionTypes = [
|
||||
("-1", "UNKNOWN", ""),
|
||||
("3", "Block Actors", "If modifier is enabled, this will not block players who are jumping (e.g. to prevent accidentally walking off ledges)."),
|
||||
("88", "Water", ""),
|
||||
("127", "Grabbable Block All", ""),
|
||||
("255", "Block All", "")
|
||||
]
|
||||
|
||||
# Identified by NSA Cloud
|
||||
surfaceTypes = [
|
||||
("-1", "UNKNOWN", ""),
|
||||
("0", "Concrete1", ""),
|
||||
("1", "Dirt", ""),
|
||||
("2", "Concrete2", ""),
|
||||
("3", "Metal Floor", ""),
|
||||
("4", "Rubble", ""),
|
||||
("5", "Metal Grate", ""),
|
||||
("6", "Gravel", ""),
|
||||
("7", "Rope Bridge", ""),
|
||||
("8", "Grass", ""),
|
||||
("9", "Wood Plank", ""),
|
||||
("11", "Water", ""),
|
||||
("12", "Sand", ""),
|
||||
("13", "Rocky Gravel 1", ""),
|
||||
("15", "Mud", ""),
|
||||
("16", "Rocky Gravel 2", ""),
|
||||
("17", "Concrete 3", ""),
|
||||
("18", "Bunker Floor", ""),
|
||||
("22", "Concrete 4", ""),
|
||||
("23", "Car", ""),
|
||||
("24", "Flowers", "")
|
||||
]
|
||||
|
||||
def setColourByCollisionType(obj):
|
||||
opacity = 0.95
|
||||
collisionType = int(obj.collisionType)
|
||||
if collisionType == 127:
|
||||
obj.color = [0.0, 1.0, 0.0, opacity]
|
||||
elif collisionType == 88:
|
||||
obj.color = [0.0, 0.5, 1.0, opacity]
|
||||
elif collisionType == 3:
|
||||
obj.color = [1.0, 0.5, 0.0, opacity]
|
||||
elif collisionType == 255:
|
||||
obj.color = [1.0, 0.0, 0.0, opacity]
|
||||
else:
|
||||
obj.color = [1.0, 0.45, 1.0, opacity]
|
||||
|
||||
def updateCollisionType(self, context):
|
||||
setColourByCollisionType(self)
|
||||
|
||||
def main(colFilePath):
|
||||
bpy.types.Object.collisionType = bpy.props.EnumProperty(name="Collision Type", items=collisionTypes, update=updateCollisionType)
|
||||
bpy.types.Object.slidable = bpy.props.BoolProperty(name="Slidable/Modifier")
|
||||
bpy.types.Object.surfaceType = bpy.props.EnumProperty(name="Surface Type", items=surfaceTypes)
|
||||
|
||||
# Setup Viewport
|
||||
for window in bpy.context.window_manager.windows:
|
||||
for area in window.screen.areas:
|
||||
if area.type == 'VIEW_3D':
|
||||
for space in area.spaces:
|
||||
if space.type == 'VIEW_3D':
|
||||
space.shading.type = "SOLID"
|
||||
space.shading.color_type = "OBJECT"
|
||||
space.shading.show_backface_culling = True
|
||||
|
||||
colFile = open(colFilePath, "rb")
|
||||
print("Parsing Col file...", colFilePath)
|
||||
col = Col(colFile)
|
||||
colFile.close()
|
||||
|
||||
# Create COL Collection
|
||||
colCollection = bpy.data.collections.get("COL")
|
||||
if not colCollection:
|
||||
colCollection = bpy.data.collections.new("COL")
|
||||
bpy.context.scene.collection.children.link(colCollection)
|
||||
|
||||
# Create meshes
|
||||
for meshIdx, mesh in enumerate(col.meshes):
|
||||
meshName = col.nameGroups.names[mesh.nameIndex]
|
||||
|
||||
# Create batches
|
||||
for batchIdx, batch in enumerate(mesh.batches):
|
||||
objName = str(meshIdx) + "-" + meshName + "-" + str(batchIdx)
|
||||
objMesh = bpy.data.meshes.new(objName)
|
||||
obj = bpy.data.objects.new(objName, objMesh)
|
||||
colCollection.objects.link(obj)
|
||||
#obj.display_type = 'WIRE'
|
||||
obj.show_wire = True
|
||||
objMesh.from_pydata(batch.vertices, [], batch.indices)
|
||||
objMesh.update(calc_edges=True)
|
||||
|
||||
try:
|
||||
obj.collisionType = str(mesh.collisionType)
|
||||
except:
|
||||
print("[!] Collision mesh flagged with unknown collsionType:", mesh.collisionType)
|
||||
obj.collisionType = "-1"
|
||||
obj["UNKNOWN_collisionType"] = mesh.collisionType
|
||||
|
||||
obj.slidable = bool(mesh.slidable)
|
||||
obj["unknownByte"] = mesh.unknownByte
|
||||
|
||||
try:
|
||||
obj.surfaceType = str(mesh.surfaceType)
|
||||
except:
|
||||
print("[!] Collision mesh flagged with unknown surfaceType:", mesh.surfaceType)
|
||||
obj.surfaceType = "-1"
|
||||
obj["UNKNOWN_surfaceType"] = mesh.surfaceType
|
||||
|
||||
obj.rotation_euler = (math.radians(90),0,0)
|
||||
|
||||
# Create colTreeNodes Sub-Collection
|
||||
colTreeNodesCollection = bpy.data.collections.get("col_colTreeNodes")
|
||||
if not colTreeNodesCollection:
|
||||
colTreeNodesCollection = bpy.data.collections.new("col_colTreeNodes")
|
||||
colCollection.children.link(colTreeNodesCollection)
|
||||
|
||||
bpy.context.view_layer.active_layer_collection.children["COL"].children["col_colTreeNodes"].hide_viewport = True
|
||||
|
||||
# Create colTreeNodes
|
||||
rootNode = bpy.data.objects.new("Root_col", None)
|
||||
rootNode.hide_viewport = True
|
||||
colTreeNodesCollection.objects.link(rootNode)
|
||||
rootNode.rotation_euler = (math.radians(90),0,0)
|
||||
for nodeIdx, node in enumerate(col.colTreeNodes):
|
||||
objName = str(nodeIdx) + "_" + str(node.left) + "_" + str(node.right) + "_col"
|
||||
obj = bpy.data.objects.new(objName, None)
|
||||
colTreeNodesCollection.objects.link(obj)
|
||||
obj.parent = rootNode
|
||||
obj.empty_display_type = 'CUBE'
|
||||
|
||||
obj.location = node.p1
|
||||
obj.scale = node.p2
|
||||
|
||||
if len(node.meshIndices) > 0:
|
||||
obj["meshIndices"] = node.meshIndices
|
||||
|
||||
print('Importing finished. ;)')
|
||||
return {'FINISHED'}
|
||||
+7
-7
@@ -2,7 +2,7 @@
|
||||
import os
|
||||
import sys
|
||||
import struct
|
||||
from .util import to_int
|
||||
from .util import to_uint
|
||||
|
||||
def little_endian_to_float(bs):
|
||||
return struct.unpack("<f", bs)[0]
|
||||
@@ -120,16 +120,16 @@ def extract_hashes(fp, extract_dir, FileCount, hashMapOffset, fileNamesOffset):
|
||||
# hash_data.metadata
|
||||
# Header
|
||||
fp.seek(hashMapOffset)
|
||||
preHashShift = to_int(fp.read(4))
|
||||
bucketOffsetsOffset = to_int(fp.read(4))
|
||||
hashesOffset = to_int(fp.read(4))
|
||||
fileIndicesOffset = to_int(fp.read(4))
|
||||
preHashShift = to_uint(fp.read(4))
|
||||
bucketOffsetsOffset = to_uint(fp.read(4))
|
||||
hashesOffset = to_uint(fp.read(4))
|
||||
fileIndicesOffset = to_uint(fp.read(4))
|
||||
|
||||
# Bucket Offsets
|
||||
fp.seek(hashMapOffset + bucketOffsetsOffset)
|
||||
bucketOffsets = []
|
||||
while fp.tell() < (hashMapOffset + hashesOffset):
|
||||
bucketOffsets.append(to_int(fp.read(2)))
|
||||
bucketOffsets.append(to_uint(fp.read(2)))
|
||||
|
||||
# Hashes
|
||||
fp.seek(hashMapOffset + hashesOffset)
|
||||
@@ -141,7 +141,7 @@ def extract_hashes(fp, extract_dir, FileCount, hashMapOffset, fileNamesOffset):
|
||||
fp.seek(hashMapOffset + fileIndicesOffset)
|
||||
fileIndices = []
|
||||
for i in range(FileCount):
|
||||
fileIndices.append(to_int(fp.read(2)))
|
||||
fileIndices.append(to_uint(fp.read(2)))
|
||||
|
||||
# Extraction
|
||||
filename = 'hash_data.metadata'
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 95 KiB |
@@ -0,0 +1,69 @@
|
||||
from .util import *
|
||||
|
||||
# Based on binary template by NSA Cloud
|
||||
|
||||
class Header:
|
||||
def __init__(self, layFile):
|
||||
self.id = layFile.read(4)
|
||||
self.unknownVer = to_float(layFile.read(4))
|
||||
|
||||
self.modelListOffset = to_uint(layFile.read(4))
|
||||
self.modelListCount = to_uint(layFile.read(4))
|
||||
|
||||
self.assetsOffset = to_uint(layFile.read(4))
|
||||
self.assetsCount = to_uint(layFile.read(4))
|
||||
|
||||
self.instancesOffset = to_uint(layFile.read(4))
|
||||
self.instancesCount = to_uint(layFile.read(4))
|
||||
|
||||
class ModelEntry:
|
||||
def __init__(self, layFile):
|
||||
self.dir = layFile.read(2)
|
||||
self.id = layFile.read(2)
|
||||
|
||||
class Asset:
|
||||
def __init__(self, layFile):
|
||||
self.name = to_string(layFile.read(32))
|
||||
|
||||
self.position = [to_float(layFile.read(4)) for val in range(3)]
|
||||
self.rotation = [to_float(layFile.read(4)) for val in range(3)]
|
||||
self.scale = [to_float(layFile.read(4)) for val in range(3)]
|
||||
|
||||
self.null0 = to_uint(layFile.read(4))
|
||||
self.unknownIndex = to_uint(layFile.read(4))
|
||||
self.null1 = [to_uint(layFile.read(4)) for val in range(8)]
|
||||
|
||||
self.instanceCount = to_uint(layFile.read(4))
|
||||
|
||||
self.instances = []
|
||||
|
||||
class Instance:
|
||||
def __init__(self, layFile):
|
||||
self.position = [to_float(layFile.read(4)) for val in range(3)]
|
||||
self.rotation = [to_float(layFile.read(4)) for val in range(3)]
|
||||
self.scale = [to_float(layFile.read(4)) for val in range(3)]
|
||||
|
||||
class Lay:
|
||||
def __init__(self, layFile):
|
||||
self.header = Header(layFile)
|
||||
|
||||
layFile.seek(self.header.modelListOffset)
|
||||
self.modelList = []
|
||||
for i in range(self.header.modelListCount):
|
||||
self.modelList.append(ModelEntry(layFile))
|
||||
|
||||
layFile.seek(self.header.assetsOffset)
|
||||
self.assets = []
|
||||
for i in range(self.header.assetsCount):
|
||||
self.assets.append(Asset(layFile))
|
||||
|
||||
layFile.seek(self.header.instancesOffset)
|
||||
self.instances = []
|
||||
for i in range(self.header.instancesCount):
|
||||
self.instances.append(Instance(layFile))
|
||||
|
||||
currentInstanceIndx = 0
|
||||
for asset in self.assets:
|
||||
for i in range(asset.instanceCount):
|
||||
asset.instances.append(self.instances[currentInstanceIndx])
|
||||
currentInstanceIndx = currentInstanceIndx + 1
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
import bpy, math, os
|
||||
from .lay import Lay
|
||||
from .util import *
|
||||
|
||||
def main(layFilePath, addonName):
|
||||
layFile = open(layFilePath, "rb")
|
||||
print("Parsing Lay file...", layFilePath)
|
||||
lay = Lay(layFile)
|
||||
layFile.close()
|
||||
|
||||
# Create LAY Collection
|
||||
layCollection = bpy.data.collections.get("LAY")
|
||||
if not layCollection:
|
||||
layCollection = bpy.data.collections.new("LAY")
|
||||
bpy.context.scene.collection.children.link(layCollection)
|
||||
|
||||
# Create layAssets Sub-Collection
|
||||
layAssetsCollection = bpy.data.collections.get("lay_layAssets")
|
||||
if not layAssetsCollection:
|
||||
layAssetsCollection = bpy.data.collections.new("lay_layAssets")
|
||||
layCollection.children.link(layAssetsCollection)
|
||||
|
||||
# Create layInstances Sub-Collection
|
||||
layInstancesCollection = bpy.data.collections.get("lay_layInstances")
|
||||
if not layInstancesCollection:
|
||||
layInstancesCollection = bpy.data.collections.new("lay_layInstances")
|
||||
layCollection.children.link(layInstancesCollection)
|
||||
|
||||
# Create layAssets and layInstances
|
||||
assetRootNode = bpy.data.objects.new("Root_layAsset", None)
|
||||
assetRootNode.hide_viewport = True
|
||||
layAssetsCollection.objects.link(assetRootNode)
|
||||
assetRootNode.rotation_euler = (math.radians(90),0,0)
|
||||
|
||||
instanceRootNode = bpy.data.objects.new("Root_layInstance", None)
|
||||
instanceRootNode.hide_viewport = True
|
||||
layInstancesCollection.objects.link(instanceRootNode)
|
||||
instanceRootNode.rotation_euler = (math.radians(90),0,0)
|
||||
|
||||
for asset in lay.assets:
|
||||
assetName = asset.name
|
||||
print("Placing asset", assetName)
|
||||
boundingBox = getModelBoundingBox(assetName.split("_")[0], addonName)
|
||||
assetObj = createLayObject(assetName, layAssetsCollection, assetRootNode, asset.position, asset.rotation, asset.scale, boundingBox)
|
||||
assetObj["unknownIndex"] = asset.unknownIndex
|
||||
for instance in asset.instances:
|
||||
instanceName = assetName + "-Instance"
|
||||
createLayObject(instanceName, layInstancesCollection, instanceRootNode, instance.position, instance.rotation, instance.scale, boundingBox)
|
||||
|
||||
print('Importing finished. ;)')
|
||||
return {'FINISHED'}
|
||||
|
||||
def createLayObject(name, collection, parent, pos, rot, scale, boundingBox):
|
||||
obj = bpy.data.objects.new(name, None)
|
||||
collection.objects.link(obj)
|
||||
obj.parent = parent
|
||||
obj.empty_display_type = 'SPHERE'
|
||||
obj.empty_display_size = 0.5
|
||||
|
||||
obj.location = pos
|
||||
obj.rotation_euler = rot
|
||||
obj.scale = scale
|
||||
|
||||
obj.show_axis = True
|
||||
|
||||
if boundingBox != None:
|
||||
createBoundingBoxObject(obj, name + "-BoundingBox", collection, boundingBox)
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
def createBoundingBoxObject(obj, name, collection, boundingBox):
|
||||
boundingBoxObj = bpy.data.objects.new(name, None)
|
||||
collection.objects.link(boundingBoxObj)
|
||||
boundingBoxObj.parent = obj
|
||||
boundingBoxObj.empty_display_type = 'CUBE'
|
||||
|
||||
boundingBoxObj.location = boundingBox[:3]
|
||||
boundingBoxObj.scale = boundingBox[-3:]
|
||||
|
||||
boundingBoxObj.hide_select = True
|
||||
|
||||
def getModelBoundingBox(modelName, addonName):
|
||||
data005_dir = bpy.context.preferences.addons[addonName].preferences.data005_dir
|
||||
data015_dir = bpy.context.preferences.addons[addonName].preferences.data015_dir
|
||||
|
||||
if not os.path.isdir(data005_dir) or not os.path.isdir(data015_dir):
|
||||
return None
|
||||
|
||||
#print("Model To Find", modelName)
|
||||
|
||||
fileFound = False
|
||||
filePath = ""
|
||||
# Search data005.cpk
|
||||
for pathName in os.listdir(data005_dir):
|
||||
if fileFound:
|
||||
break
|
||||
fullPathName = os.path.join(data005_dir, pathName)
|
||||
if os.path.isdir(fullPathName):
|
||||
for file in os.listdir(fullPathName):
|
||||
if file == (modelName + ".dtt"):
|
||||
filePath = fullPathName + "\\" + file
|
||||
fileFound = True
|
||||
break
|
||||
else:
|
||||
if pathName == (modelName + ".dtt"):
|
||||
filePath = fullPathName + "\\" + pathName
|
||||
fileFound = True
|
||||
break
|
||||
|
||||
# Search data015.cpk
|
||||
for pathName in os.listdir(data015_dir):
|
||||
if fileFound:
|
||||
break
|
||||
fullPathName = os.path.join(data015_dir, pathName)
|
||||
if os.path.isdir(fullPathName):
|
||||
for file in os.listdir(fullPathName):
|
||||
if file == (modelName + ".dtt"):
|
||||
filePath = fullPathName + "\\" + file
|
||||
fileFound = True
|
||||
break
|
||||
else:
|
||||
if pathName == (modelName + ".dtt"):
|
||||
filePath = fullPathName + "\\" + pathName
|
||||
fileFound = True
|
||||
break
|
||||
|
||||
if not fileFound:
|
||||
return None
|
||||
|
||||
modelDTTFile = open(filePath, "rb")
|
||||
id = modelDTTFile.read(4)
|
||||
numFiles = to_uint(modelDTTFile.read(4))
|
||||
fileOffsetsOffset = to_uint(modelDTTFile.read(4))
|
||||
fileExtensionsOffset = to_uint(modelDTTFile.read(4))
|
||||
|
||||
fileOffsets = []
|
||||
modelDTTFile.seek(fileOffsetsOffset)
|
||||
for i in range(numFiles):
|
||||
fileOffsets.append(to_uint(modelDTTFile.read(4)))
|
||||
|
||||
fileExtensions = []
|
||||
modelDTTFile.seek(fileExtensionsOffset)
|
||||
for i in range(numFiles):
|
||||
fileExtensions.append(to_string(modelDTTFile.read(4)))
|
||||
|
||||
for i, ext in enumerate(fileExtensions):
|
||||
if ext == "wmb":
|
||||
modelDTTFile.seek(fileOffsets[i] + 16)
|
||||
boundingBox = [to_float(modelDTTFile.read(4)) for val in range(6)]
|
||||
modelDTTFile.close()
|
||||
return boundingBox
|
||||
@@ -10,12 +10,17 @@ def to_float(bs):
|
||||
def to_float16(bs):
|
||||
return float(np.frombuffer(bs, np.float16)[0])
|
||||
|
||||
def to_uint(bs):
|
||||
return (int.from_bytes(bs, byteorder='little', signed=False))
|
||||
|
||||
def to_int(bs):
|
||||
return (int.from_bytes(bs, byteorder='little'))
|
||||
return (int.from_bytes(bs, byteorder='little', signed=True))
|
||||
|
||||
def to_string(bs, encoding = 'utf8'):
|
||||
return bs.split(b'\x00')[0].decode(encoding)
|
||||
|
||||
def to_ushort(bs):
|
||||
return struct.unpack("<H", bs)[0]
|
||||
|
||||
def create_dir(dirpath):
|
||||
if not os.path.exists(dirpath):
|
||||
|
||||
@@ -9,57 +9,57 @@ class WMB_Header(object):
|
||||
super(WMB_Header, self).__init__()
|
||||
self.magicNumber = wmb_fp.read(4) # ID
|
||||
if self.magicNumber == b'WMB3':
|
||||
self.version = "%08x" % (to_int(wmb_fp.read(4))) # Version
|
||||
self.unknown08 = to_int(wmb_fp.read(4)) # UnknownA
|
||||
self.flags = to_int(wmb_fp.read(4)) # flags & referenceBone
|
||||
self.version = "%08x" % (to_uint(wmb_fp.read(4))) # Version
|
||||
self.unknown08 = to_uint(wmb_fp.read(4)) # UnknownA
|
||||
self.flags = to_uint(wmb_fp.read(4)) # flags & referenceBone
|
||||
self.bounding_box1 = to_float(wmb_fp.read(4)) # bounding_box
|
||||
self.bounding_box2 = to_float(wmb_fp.read(4))
|
||||
self.bounding_box3 = to_float(wmb_fp.read(4))
|
||||
self.bounding_box4 = to_float(wmb_fp.read(4))
|
||||
self.bounding_box5 = to_float(wmb_fp.read(4))
|
||||
self.bounding_box6 = to_float(wmb_fp.read(4))
|
||||
self.boneArrayOffset = to_int(wmb_fp.read(4)) # offsetBones
|
||||
self.boneCount = to_int(wmb_fp.read(4)) # numBones
|
||||
self.offsetBoneIndexTranslateTable = to_int(wmb_fp.read(4)) # offsetBoneIndexTranslateTable
|
||||
self.boneIndexTranslateTableSize = to_int(wmb_fp.read(4)) # boneIndexTranslateTableSize
|
||||
self.vertexGroupArrayOffset = to_int(wmb_fp.read(4)) # offsetVertexGroups
|
||||
self.vertexGroupCount = to_int(wmb_fp.read(4)) # numVertexGroups
|
||||
self.meshArrayOffset = to_int(wmb_fp.read(4)) # offsetBatches
|
||||
self.meshCount = to_int(wmb_fp.read(4)) # numBatches
|
||||
self.meshGroupInfoArrayHeaderOffset = to_int(wmb_fp.read(4)) # offsetLODS
|
||||
self.meshGroupInfoArrayCount = to_int(wmb_fp.read(4)) # numLODS
|
||||
self.colTreeNodesOffset = to_int(wmb_fp.read(4)) # offsetColTreeNodes
|
||||
self.colTreeNodesCount = to_int(wmb_fp.read(4)) # numColTreeNodes
|
||||
self.boneMapOffset = to_int(wmb_fp.read(4)) # offsetBoneMap
|
||||
self.boneMapCount = to_int(wmb_fp.read(4)) # numBoneMap
|
||||
self.bonesetOffset = to_int(wmb_fp.read(4)) # offsetBoneSets
|
||||
self.bonesetCount = to_int(wmb_fp.read(4)) # numBoneSets
|
||||
self.materialArrayOffset = to_int(wmb_fp.read(4)) # offsetMaterials
|
||||
self.materialCount = to_int(wmb_fp.read(4)) # numMaterials
|
||||
self.meshGroupOffset = to_int(wmb_fp.read(4)) # offsetMeshes
|
||||
self.meshGroupCount = to_int(wmb_fp.read(4)) # numMeshes
|
||||
self.offsetMeshMaterials = to_int(wmb_fp.read(4)) # offsetMeshMaterials
|
||||
self.numMeshMaterials = to_int(wmb_fp.read(4)) # numMeshMaterials
|
||||
self.unknownWorldDataArrayOffset = to_int(wmb_fp.read(4)) # offsetUnknown0 World Model Stuff
|
||||
self.unknownWorldDataArrayCount = to_int(wmb_fp.read(4)) # numUnknown0 World Model Stuff
|
||||
self.unknown8C = to_int(wmb_fp.read(4))
|
||||
self.boneArrayOffset = to_uint(wmb_fp.read(4)) # offsetBones
|
||||
self.boneCount = to_uint(wmb_fp.read(4)) # numBones
|
||||
self.offsetBoneIndexTranslateTable = to_uint(wmb_fp.read(4)) # offsetBoneIndexTranslateTable
|
||||
self.boneIndexTranslateTableSize = to_uint(wmb_fp.read(4)) # boneIndexTranslateTableSize
|
||||
self.vertexGroupArrayOffset = to_uint(wmb_fp.read(4)) # offsetVertexGroups
|
||||
self.vertexGroupCount = to_uint(wmb_fp.read(4)) # numVertexGroups
|
||||
self.meshArrayOffset = to_uint(wmb_fp.read(4)) # offsetBatches
|
||||
self.meshCount = to_uint(wmb_fp.read(4)) # numBatches
|
||||
self.meshGroupInfoArrayHeaderOffset = to_uint(wmb_fp.read(4)) # offsetLODS
|
||||
self.meshGroupInfoArrayCount = to_uint(wmb_fp.read(4)) # numLODS
|
||||
self.colTreeNodesOffset = to_uint(wmb_fp.read(4)) # offsetColTreeNodes
|
||||
self.colTreeNodesCount = to_uint(wmb_fp.read(4)) # numColTreeNodes
|
||||
self.boneMapOffset = to_uint(wmb_fp.read(4)) # offsetBoneMap
|
||||
self.boneMapCount = to_uint(wmb_fp.read(4)) # numBoneMap
|
||||
self.bonesetOffset = to_uint(wmb_fp.read(4)) # offsetBoneSets
|
||||
self.bonesetCount = to_uint(wmb_fp.read(4)) # numBoneSets
|
||||
self.materialArrayOffset = to_uint(wmb_fp.read(4)) # offsetMaterials
|
||||
self.materialCount = to_uint(wmb_fp.read(4)) # numMaterials
|
||||
self.meshGroupOffset = to_uint(wmb_fp.read(4)) # offsetMeshes
|
||||
self.meshGroupCount = to_uint(wmb_fp.read(4)) # numMeshes
|
||||
self.offsetMeshMaterials = to_uint(wmb_fp.read(4)) # offsetMeshMaterials
|
||||
self.numMeshMaterials = to_uint(wmb_fp.read(4)) # numMeshMaterials
|
||||
self.unknownWorldDataArrayOffset = to_uint(wmb_fp.read(4)) # offsetUnknown0 World Model Stuff
|
||||
self.unknownWorldDataArrayCount = to_uint(wmb_fp.read(4)) # numUnknown0 World Model Stuff
|
||||
self.unknown8C = to_uint(wmb_fp.read(4))
|
||||
|
||||
class wmb3_vertexHeader(object):
|
||||
"""docstring for wmb3_vertexHeader"""
|
||||
def __init__(self, wmb_fp):
|
||||
super(wmb3_vertexHeader, self).__init__()
|
||||
self.vertexArrayOffset = to_int(wmb_fp.read(4))
|
||||
self.vertexExDataArrayOffset = to_int(wmb_fp.read(4))
|
||||
self.unknown08 = to_int(wmb_fp.read(4))
|
||||
self.unknown0C = to_int(wmb_fp.read(4))
|
||||
self.vertexStride = to_int(wmb_fp.read(4))
|
||||
self.vertexExDataStride = to_int(wmb_fp.read(4))
|
||||
self.unknown18 = to_int(wmb_fp.read(4))
|
||||
self.unknown1C = to_int(wmb_fp.read(4))
|
||||
self.vertexCount = to_int(wmb_fp.read(4))
|
||||
self.vertexFlags = to_int(wmb_fp.read(4))
|
||||
self.faceArrayOffset = to_int(wmb_fp.read(4))
|
||||
self.faceCount = to_int(wmb_fp.read(4))
|
||||
self.vertexArrayOffset = to_uint(wmb_fp.read(4))
|
||||
self.vertexExDataArrayOffset = to_uint(wmb_fp.read(4))
|
||||
self.unknown08 = to_uint(wmb_fp.read(4))
|
||||
self.unknown0C = to_uint(wmb_fp.read(4))
|
||||
self.vertexStride = to_uint(wmb_fp.read(4))
|
||||
self.vertexExDataStride = to_uint(wmb_fp.read(4))
|
||||
self.unknown18 = to_uint(wmb_fp.read(4))
|
||||
self.unknown1C = to_uint(wmb_fp.read(4))
|
||||
self.vertexCount = to_uint(wmb_fp.read(4))
|
||||
self.vertexFlags = to_uint(wmb_fp.read(4))
|
||||
self.faceArrayOffset = to_uint(wmb_fp.read(4))
|
||||
self.faceCount = to_uint(wmb_fp.read(4))
|
||||
|
||||
class wmb3_vertex(object):
|
||||
"""docstring for wmb3_vertex"""
|
||||
@@ -68,22 +68,22 @@ class wmb3_vertex(object):
|
||||
self.positionX = to_float(wmb_fp.read(4))
|
||||
self.positionY = to_float(wmb_fp.read(4))
|
||||
self.positionZ = to_float(wmb_fp.read(4))
|
||||
self.normalX = to_int(wmb_fp.read(1)) * 2 / 255
|
||||
self.normalY = to_int(wmb_fp.read(1)) * 2 / 255
|
||||
self.normalZ = to_int(wmb_fp.read(1)) * 2 / 255
|
||||
self.normalX = to_uint(wmb_fp.read(1)) * 2 / 255
|
||||
self.normalY = to_uint(wmb_fp.read(1)) * 2 / 255
|
||||
self.normalZ = to_uint(wmb_fp.read(1)) * 2 / 255
|
||||
wmb_fp.read(1)
|
||||
self.textureU = to_float16(wmb_fp.read(2))
|
||||
self.textureV = to_float16(wmb_fp.read(2))
|
||||
if vertex_flags in [0]:
|
||||
self.normal = hex(to_int(wmb_fp.read(8)))
|
||||
self.normal = hex(to_uint(wmb_fp.read(8)))
|
||||
if vertex_flags in [1, 4, 5, 12, 14]:
|
||||
self.textureU2 = to_float16(wmb_fp.read(2))
|
||||
self.textureV2 = to_float16(wmb_fp.read(2))
|
||||
if vertex_flags in [7, 10, 11]:
|
||||
self.boneIndices = [to_int(wmb_fp.read(1)) for i in range(4)]
|
||||
self.boneWeights = [to_int(wmb_fp.read(1))/255 for i in range(4)]
|
||||
self.boneIndices = [to_uint(wmb_fp.read(1)) for i in range(4)]
|
||||
self.boneWeights = [to_uint(wmb_fp.read(1))/255 for i in range(4)]
|
||||
if vertex_flags in [4, 5, 12, 14]:
|
||||
self.color = [to_int(wmb_fp.read(1)) for i in range(4)]
|
||||
self.color = [to_uint(wmb_fp.read(1)) for i in range(4)]
|
||||
|
||||
class wmb3_vertexExData(object):
|
||||
"""docstring for wmb3_vertexExData"""
|
||||
@@ -93,34 +93,34 @@ class wmb3_vertexExData(object):
|
||||
#0x0 has no ExVertexData
|
||||
|
||||
if vertex_flags in [1, 4]: #0x1, 0x4
|
||||
self.normal = hex(to_int(wmb_fp.read(8)))
|
||||
self.normal = hex(to_uint(wmb_fp.read(8)))
|
||||
|
||||
elif vertex_flags in [5]: #0x5
|
||||
self.normal = hex(to_int(wmb_fp.read(8)))
|
||||
self.normal = hex(to_uint(wmb_fp.read(8)))
|
||||
self.textureU3 = to_float16(wmb_fp.read(2))
|
||||
self.textureV3 = to_float16(wmb_fp.read(2))
|
||||
|
||||
elif vertex_flags in [7]: #0x7
|
||||
self.textureU2 = to_float16(wmb_fp.read(2))
|
||||
self.textureV2 = to_float16(wmb_fp.read(2))
|
||||
self.normal = hex(to_int(wmb_fp.read(8)))
|
||||
self.normal = hex(to_uint(wmb_fp.read(8)))
|
||||
|
||||
elif vertex_flags in [10]: #0xa
|
||||
self.textureU2 = to_float16(wmb_fp.read(2))
|
||||
self.textureV2 = to_float16(wmb_fp.read(2))
|
||||
self.color = [to_int(wmb_fp.read(1)) for i in range(4)]
|
||||
self.normal = hex(to_int(wmb_fp.read(8)))
|
||||
self.color = [to_uint(wmb_fp.read(1)) for i in range(4)]
|
||||
self.normal = hex(to_uint(wmb_fp.read(8)))
|
||||
|
||||
elif vertex_flags in [11]: #0xb
|
||||
self.textureU2 = to_float16(wmb_fp.read(2))
|
||||
self.textureV2 = to_float16(wmb_fp.read(2))
|
||||
self.color = [to_int(wmb_fp.read(1)) for i in range(4)]
|
||||
self.normal = hex(to_int(wmb_fp.read(8)))
|
||||
self.color = [to_uint(wmb_fp.read(1)) for i in range(4)]
|
||||
self.normal = hex(to_uint(wmb_fp.read(8)))
|
||||
self.textureU3 = to_float16(wmb_fp.read(2))
|
||||
self.textureV3 = to_float16(wmb_fp.read(2))
|
||||
|
||||
elif vertex_flags in [12]: #0xc
|
||||
self.normal = hex(to_int(wmb_fp.read(8)))
|
||||
self.normal = hex(to_uint(wmb_fp.read(8)))
|
||||
self.textureU3 = to_float16(wmb_fp.read(2))
|
||||
self.textureV3 = to_float16(wmb_fp.read(2))
|
||||
self.textureU4 = to_float16(wmb_fp.read(2))
|
||||
@@ -129,7 +129,7 @@ class wmb3_vertexExData(object):
|
||||
self.textureV5 = to_float16(wmb_fp.read(2))
|
||||
|
||||
elif vertex_flags in [14]: #0xe
|
||||
self.normal = hex(to_int(wmb_fp.read(8)))
|
||||
self.normal = hex(to_uint(wmb_fp.read(8)))
|
||||
self.textureU3 = to_float16(wmb_fp.read(2))
|
||||
self.textureV3 = to_float16(wmb_fp.read(2))
|
||||
self.textureU4 = to_float16(wmb_fp.read(2))
|
||||
@@ -159,29 +159,29 @@ class wmb3_vertexGroup(object):
|
||||
wmb_fp.seek(self.vertexGroupHeader.faceArrayOffset)
|
||||
for face_index in range(self.vertexGroupHeader.faceCount):
|
||||
if faceSize == 2:
|
||||
self.faceRawArray.append(to_int(wmb_fp.read(2)) + 1)
|
||||
self.faceRawArray.append(to_uint(wmb_fp.read(2)) + 1)
|
||||
else:
|
||||
self.faceRawArray.append(to_int(wmb_fp.read(4)) + 1)
|
||||
self.faceRawArray.append(to_uint(wmb_fp.read(4)) + 1)
|
||||
|
||||
class wmb3_mesh(object):
|
||||
"""docstring for wmb3_mesh"""
|
||||
def __init__(self, wmb_fp):
|
||||
super(wmb3_mesh, self).__init__()
|
||||
self.vertexGroupIndex = to_int(wmb_fp.read(4))
|
||||
self.bonesetIndex = to_int(wmb_fp.read(4))
|
||||
self.vertexStart = to_int(wmb_fp.read(4))
|
||||
self.faceStart = to_int(wmb_fp.read(4))
|
||||
self.vertexCount = to_int(wmb_fp.read(4))
|
||||
self.faceCount = to_int(wmb_fp.read(4))
|
||||
self.unknown18 = to_int(wmb_fp.read(4))
|
||||
self.vertexGroupIndex = to_uint(wmb_fp.read(4))
|
||||
self.bonesetIndex = to_uint(wmb_fp.read(4))
|
||||
self.vertexStart = to_uint(wmb_fp.read(4))
|
||||
self.faceStart = to_uint(wmb_fp.read(4))
|
||||
self.vertexCount = to_uint(wmb_fp.read(4))
|
||||
self.faceCount = to_uint(wmb_fp.read(4))
|
||||
self.unknown18 = to_uint(wmb_fp.read(4))
|
||||
|
||||
class wmb3_bone(object):
|
||||
"""docstring for wmb3_bone"""
|
||||
def __init__(self, wmb_fp,index):
|
||||
super(wmb3_bone, self).__init__()
|
||||
self.boneIndex = index
|
||||
self.boneNumber = to_int(wmb_fp.read(2))
|
||||
self.parentIndex = to_int(wmb_fp.read(2))
|
||||
self.boneNumber = to_uint(wmb_fp.read(2))
|
||||
self.parentIndex = to_uint(wmb_fp.read(2))
|
||||
|
||||
local_positionX = to_float(wmb_fp.read(4))
|
||||
local_positionY = to_float(wmb_fp.read(4))
|
||||
@@ -223,8 +223,8 @@ class wmb3_boneMap(object):
|
||||
"""docstring for wmb3_boneMap"""
|
||||
def __init__(self, wmb_fp):
|
||||
super(wmb3_boneMap, self).__init__()
|
||||
self.boneMapOffset = to_int(wmb_fp.read(4))
|
||||
self.boneMapCount = to_int(wmb_fp.read(4))
|
||||
self.boneMapOffset = to_uint(wmb_fp.read(4))
|
||||
self.boneMapCount = to_uint(wmb_fp.read(4))
|
||||
|
||||
class wmb3_boneSet(object):
|
||||
"""docstring for wmb3_boneSet"""
|
||||
@@ -234,34 +234,34 @@ class wmb3_boneSet(object):
|
||||
self.boneSetCount = boneSetCount
|
||||
boneSetInfoArray = []
|
||||
for index in range(boneSetCount):
|
||||
offset = to_int(wmb_fp.read(4))
|
||||
count = to_int(wmb_fp.read(4))
|
||||
offset = to_uint(wmb_fp.read(4))
|
||||
count = to_uint(wmb_fp.read(4))
|
||||
boneSetInfoArray.append([offset, count])
|
||||
for boneSetInfo in boneSetInfoArray:
|
||||
wmb_fp.seek(boneSetInfo[0])
|
||||
boneSet = []
|
||||
for index in range(boneSetInfo[1]):
|
||||
boneSet.append(to_int(wmb_fp.read(2)))
|
||||
boneSet.append(to_uint(wmb_fp.read(2)))
|
||||
self.boneSetArray.append(boneSet)
|
||||
|
||||
class wmb3_material(object):
|
||||
"""docstring for wmb3_material"""
|
||||
def __init__(self, wmb_fp):
|
||||
super(wmb3_material, self).__init__()
|
||||
to_int(wmb_fp.read(2))
|
||||
to_int(wmb_fp.read(2))
|
||||
to_int(wmb_fp.read(2))
|
||||
to_int(wmb_fp.read(2))
|
||||
materialNameOffset = to_int(wmb_fp.read(4))
|
||||
effectNameOffset = to_int(wmb_fp.read(4))
|
||||
techniqueNameOffset = to_int(wmb_fp.read(4))
|
||||
to_int(wmb_fp.read(4))
|
||||
textureOffset = to_int(wmb_fp.read(4))
|
||||
textureNum = to_int(wmb_fp.read(4))
|
||||
paramterGroupsOffset = to_int(wmb_fp.read(4))
|
||||
numParameterGroups = to_int(wmb_fp.read(4))
|
||||
varOffset = to_int(wmb_fp.read(4))
|
||||
varNum = to_int(wmb_fp.read(4))
|
||||
to_uint(wmb_fp.read(2))
|
||||
to_uint(wmb_fp.read(2))
|
||||
to_uint(wmb_fp.read(2))
|
||||
to_uint(wmb_fp.read(2))
|
||||
materialNameOffset = to_uint(wmb_fp.read(4))
|
||||
effectNameOffset = to_uint(wmb_fp.read(4))
|
||||
techniqueNameOffset = to_uint(wmb_fp.read(4))
|
||||
to_uint(wmb_fp.read(4))
|
||||
textureOffset = to_uint(wmb_fp.read(4))
|
||||
textureNum = to_uint(wmb_fp.read(4))
|
||||
paramterGroupsOffset = to_uint(wmb_fp.read(4))
|
||||
numParameterGroups = to_uint(wmb_fp.read(4))
|
||||
varOffset = to_uint(wmb_fp.read(4))
|
||||
varNum = to_uint(wmb_fp.read(4))
|
||||
wmb_fp.seek(materialNameOffset)
|
||||
self.materialName = to_string(wmb_fp.read(256))
|
||||
wmb_fp.seek(effectNameOffset)
|
||||
@@ -288,8 +288,8 @@ class wmb3_material(object):
|
||||
# Append textures to materials in the dictionary
|
||||
for i in range(textureNum):
|
||||
wmb_fp.seek(textureOffset + i * 8)
|
||||
offset = to_int(wmb_fp.read(4))
|
||||
identifier = "%08x"%to_int(wmb_fp.read(4))
|
||||
offset = to_uint(wmb_fp.read(4))
|
||||
identifier = "%08x"%to_uint(wmb_fp.read(4))
|
||||
wmb_fp.seek(offset)
|
||||
textureTypeName = to_string(wmb_fp.read(256))
|
||||
self.textureArray[textureTypeName] = identifier
|
||||
@@ -305,9 +305,9 @@ class wmb3_material(object):
|
||||
for i in range(numParameterGroups):
|
||||
wmb_fp.seek(paramterGroupsOffset + i * 12)
|
||||
parameters = []
|
||||
index = to_int(wmb_fp.read(4))
|
||||
offset = to_int(wmb_fp.read(4))
|
||||
num = to_int(wmb_fp.read(4))
|
||||
index = to_uint(wmb_fp.read(4))
|
||||
offset = to_uint(wmb_fp.read(4))
|
||||
num = to_uint(wmb_fp.read(4))
|
||||
wmb_fp.seek(offset)
|
||||
for k in range(num):
|
||||
param = to_float(wmb_fp.read(4))
|
||||
@@ -318,7 +318,7 @@ class wmb3_material(object):
|
||||
self.uniformArray = {}
|
||||
for i in range(varNum):
|
||||
wmb_fp.seek(varOffset + i * 8)
|
||||
offset = to_int(wmb_fp.read(4))
|
||||
offset = to_uint(wmb_fp.read(4))
|
||||
value = to_float(wmb_fp.read(4))
|
||||
wmb_fp.seek(offset)
|
||||
self.uniformArray [to_string(wmb_fp.read(256))] = value
|
||||
@@ -328,38 +328,38 @@ class wmb3_meshGroup(object):
|
||||
"""docstring for wmb3_meshGroupInfo"""
|
||||
def __init__(self, wmb_fp):
|
||||
super(wmb3_meshGroup, self).__init__()
|
||||
nameOffset = to_int(wmb_fp.read(4))
|
||||
nameOffset = to_uint(wmb_fp.read(4))
|
||||
self.boundingBox = []
|
||||
for i in range(6):
|
||||
self.boundingBox.append(to_float(wmb_fp.read(4)))
|
||||
materialIndexArrayOffset = to_int(wmb_fp.read(4))
|
||||
materialIndexArrayCount = to_int(wmb_fp.read(4))
|
||||
boneIndexArrayOffset =to_int(wmb_fp.read(4))
|
||||
boneIndexArrayCount = to_int(wmb_fp.read(4))
|
||||
materialIndexArrayOffset = to_uint(wmb_fp.read(4))
|
||||
materialIndexArrayCount = to_uint(wmb_fp.read(4))
|
||||
boneIndexArrayOffset =to_uint(wmb_fp.read(4))
|
||||
boneIndexArrayCount = to_uint(wmb_fp.read(4))
|
||||
wmb_fp.seek(nameOffset)
|
||||
self.meshGroupname = to_string(wmb_fp.read(256))
|
||||
self.materialIndexArray = []
|
||||
self.boneIndexArray = []
|
||||
wmb_fp.seek(materialIndexArrayOffset)
|
||||
for i in range(materialIndexArrayCount):
|
||||
self.materialIndexArray.append(to_int(wmb_fp.read(2)))
|
||||
self.materialIndexArray.append(to_uint(wmb_fp.read(2)))
|
||||
wmb_fp.seek(boneIndexArrayOffset)
|
||||
for i in range(boneIndexArrayCount):
|
||||
self.boneIndexArray.append(to_int(wmb_fp.read(2)))
|
||||
self.boneIndexArray.append(to_uint(wmb_fp.read(2)))
|
||||
|
||||
|
||||
class wmb3_groupedMesh(object):
|
||||
"""docstring for wmb3_groupedMesh"""
|
||||
def __init__(self, wmb_fp):
|
||||
super(wmb3_groupedMesh, self).__init__()
|
||||
self.vertexGroupIndex = to_int(wmb_fp.read(4))
|
||||
self.meshGroupIndex = to_int(wmb_fp.read(4))
|
||||
self.materialIndex = to_int(wmb_fp.read(4))
|
||||
self.colTreeNodeIndex = to_int(wmb_fp.read(4))
|
||||
self.vertexGroupIndex = to_uint(wmb_fp.read(4))
|
||||
self.meshGroupIndex = to_uint(wmb_fp.read(4))
|
||||
self.materialIndex = to_uint(wmb_fp.read(4))
|
||||
self.colTreeNodeIndex = to_uint(wmb_fp.read(4))
|
||||
if self.colTreeNodeIndex == 4294967295:
|
||||
self.colTreeNodeIndex = -1
|
||||
self.meshGroupInfoMaterialPair = to_int(wmb_fp.read(4))
|
||||
self.unknownWorldDataIndex = to_int(wmb_fp.read(4))
|
||||
self.meshGroupInfoMaterialPair = to_uint(wmb_fp.read(4))
|
||||
self.unknownWorldDataIndex = to_uint(wmb_fp.read(4))
|
||||
if self.unknownWorldDataIndex == 4294967295:
|
||||
self.unknownWorldDataIndex = -1
|
||||
|
||||
@@ -368,13 +368,13 @@ class wmb3_meshGroupInfo(object):
|
||||
"""docstring for wmb3_meshGroupInfo"""
|
||||
def __init__(self, wmb_fp):
|
||||
super(wmb3_meshGroupInfo, self).__init__()
|
||||
self.nameOffset = to_int(wmb_fp.read(4))
|
||||
self.lodLevel = to_int(wmb_fp.read(4))
|
||||
self.nameOffset = to_uint(wmb_fp.read(4))
|
||||
self.lodLevel = to_uint(wmb_fp.read(4))
|
||||
if self.lodLevel == 4294967295:
|
||||
self.lodLevel = -1
|
||||
self.meshStart = to_int(wmb_fp.read(4))
|
||||
meshGroupInfoOffset = to_int(wmb_fp.read(4))
|
||||
self.meshCount = to_int(wmb_fp.read(4))
|
||||
self.meshStart = to_uint(wmb_fp.read(4))
|
||||
meshGroupInfoOffset = to_uint(wmb_fp.read(4))
|
||||
self.meshCount = to_uint(wmb_fp.read(4))
|
||||
wmb_fp.seek(self.nameOffset)
|
||||
self.meshGroupInfoname = to_string(wmb_fp.read(256))
|
||||
wmb_fp.seek(meshGroupInfoOffset)
|
||||
@@ -396,11 +396,11 @@ class wmb3_colTreeNode(object):
|
||||
p2_z = to_float(wmb_fp.read(4))
|
||||
self.p2 = (p2_x, p2_y, p2_z)
|
||||
|
||||
self.left = to_int(wmb_fp.read(4))
|
||||
self.left = to_uint(wmb_fp.read(4))
|
||||
if self.left == 4294967295:
|
||||
self.left = -1
|
||||
|
||||
self.right = to_int(wmb_fp.read(4))
|
||||
self.right = to_uint(wmb_fp.read(4))
|
||||
if self.right == 4294967295:
|
||||
self.right = -1
|
||||
|
||||
@@ -459,7 +459,7 @@ class WMB3(object):
|
||||
wmb_fp.seek(self.wmb3_header.offsetBoneIndexTranslateTable)
|
||||
self.firstLevel = []
|
||||
for entry in range(16):
|
||||
self.firstLevel.append(to_int(wmb_fp.read(2)))
|
||||
self.firstLevel.append(to_uint(wmb_fp.read(2)))
|
||||
if self.firstLevel[-1] == 65535:
|
||||
self.firstLevel[-1] = -1
|
||||
|
||||
@@ -470,7 +470,7 @@ class WMB3(object):
|
||||
|
||||
self.secondLevel = []
|
||||
for entry in range(firstLevel_Entry_Count * 16):
|
||||
self.secondLevel.append(to_int(wmb_fp.read(2)))
|
||||
self.secondLevel.append(to_uint(wmb_fp.read(2)))
|
||||
if self.secondLevel[-1] == 65535:
|
||||
self.secondLevel[-1] = -1
|
||||
|
||||
@@ -481,7 +481,7 @@ class WMB3(object):
|
||||
|
||||
self.thirdLevel = []
|
||||
for entry in range(secondLevel_Entry_Count * 16):
|
||||
self.thirdLevel.append(to_int(wmb_fp.read(2)))
|
||||
self.thirdLevel.append(to_uint(wmb_fp.read(2)))
|
||||
if self.thirdLevel[-1] == 65535:
|
||||
self.thirdLevel[-1] = -1
|
||||
|
||||
@@ -489,7 +489,7 @@ class WMB3(object):
|
||||
wmb_fp.seek(self.wmb3_header.offsetBoneIndexTranslateTable)
|
||||
unknownData1Array = []
|
||||
for i in range(self.wmb3_header.boneIndexTranslateTableSize):
|
||||
unknownData1Array.append(to_int(wmb_fp.read(1)))
|
||||
unknownData1Array.append(to_uint(wmb_fp.read(1)))
|
||||
|
||||
self.vertexGroupArray = []
|
||||
for vertexGroupIndex in range(self.wmb3_header.vertexGroupCount):
|
||||
@@ -526,7 +526,7 @@ class WMB3(object):
|
||||
wmb_fp.seek(self.wmb3_header.boneMapOffset)
|
||||
self.boneMap = []
|
||||
for index in range(self.wmb3_header.boneMapCount):
|
||||
self.boneMap.append(to_int(wmb_fp.read(4)))
|
||||
self.boneMap.append(to_uint(wmb_fp.read(4)))
|
||||
wmb_fp.seek(self.wmb3_header.bonesetOffset)
|
||||
self.boneSetArray = wmb3_boneSet(wmb_fp, self.wmb3_header.bonesetCount).boneSetArray
|
||||
|
||||
|
||||
+47
-34
@@ -25,17 +25,17 @@ def reset_blend():
|
||||
bpy.data.objects.remove(obj)
|
||||
obj.user_clear()
|
||||
|
||||
def construct_armature(name, bone_data_array, firstLevel, secondLevel, thirdLevel, boneMap, boneSetArray): # bone_data =[boneIndex, boneName, parentIndex, parentName, bone_pos, optional, boneNumber, localPos, local_rotation, world_rotation, world_position_tpose]
|
||||
def construct_armature(name, bone_data_array, firstLevel, secondLevel, thirdLevel, boneMap, boneSetArray, collection_name): # bone_data =[boneIndex, boneName, parentIndex, parentName, bone_pos, optional, boneNumber, localPos, local_rotation, world_rotation, world_position_tpose]
|
||||
print('[+] importing armature')
|
||||
bpy.ops.object.add(
|
||||
type='ARMATURE',
|
||||
enter_editmode=True,
|
||||
location=(0,0,0))
|
||||
ob = bpy.context.active_object
|
||||
amt = bpy.data.armatures.new(name +'Amt')
|
||||
ob = bpy.data.objects.new(name, amt)
|
||||
#ob = bpy.context.active_object
|
||||
ob.show_in_front = False
|
||||
ob.name = name
|
||||
amt = ob.data
|
||||
amt.name = name +'Amt'
|
||||
bpy.data.collections.get(collection_name).objects.link(ob)
|
||||
|
||||
bpy.context.view_layer.objects.active = ob
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
amt['firstLevel'] = firstLevel
|
||||
amt['secondLevel'] = secondLevel
|
||||
@@ -119,7 +119,7 @@ def construct_mesh(mesh_data, collection_name): # [meshName, vertices, faces,
|
||||
else:
|
||||
obj = bpy.data.objects[name]
|
||||
obj.location = Vector((0,0,0))
|
||||
bpy.context.collection.objects.link(obj)
|
||||
bpy.data.collections.get(collection_name).objects.link(obj)
|
||||
objmesh.from_pydata(vertices, [], faces)
|
||||
objmesh.update(calc_edges=True)
|
||||
|
||||
@@ -155,8 +155,6 @@ def construct_mesh(mesh_data, collection_name): # [meshName, vertices, faces,
|
||||
obj['LOD_Level'] = mesh_data[9]
|
||||
obj['colTreeNodeIndex'] = mesh_data[10]
|
||||
obj['unknownWorldDataIndex'] = mesh_data[11]
|
||||
obj['boundingBoxXYZ'] = [mesh_data[12][0], mesh_data[12][1], mesh_data[12][2]]
|
||||
obj['boundingBoxUVW'] = [mesh_data[12][3], mesh_data[12][4], mesh_data[12][5]]
|
||||
|
||||
obj.data.flip_normals()
|
||||
return obj
|
||||
@@ -559,22 +557,39 @@ def import_colTreeNodes(wmb, collection):
|
||||
colTreeNodesDict = {}
|
||||
#collision_col = bpy.data.collections.new("CollisionNodes")
|
||||
#collection.children.link(collision_col)
|
||||
for index, node in enumerate(wmb.colTreeNodes):
|
||||
colTreeNodeName = 'colTreeNode' + str(index)
|
||||
|
||||
colTreeNodesCollection = bpy.data.collections.get("wmb_colTreeNodes")
|
||||
if not colTreeNodesCollection:
|
||||
colTreeNodesCollection = bpy.data.collections.new("wmb_colTreeNodes")
|
||||
collection.children.link(colTreeNodesCollection)
|
||||
|
||||
bpy.context.view_layer.active_layer_collection.children["WMB"].children[collection.name].children["wmb_colTreeNodes"].hide_viewport = True
|
||||
|
||||
rootNode = bpy.data.objects.new("Root_wmb", None)
|
||||
rootNode.hide_viewport = True
|
||||
colTreeNodesCollection.objects.link(rootNode)
|
||||
rootNode.rotation_euler = (math.radians(90),0,0)
|
||||
for nodeIdx, node in enumerate(wmb.colTreeNodes):
|
||||
colTreeNodeName = 'colTreeNode' + str(nodeIdx)
|
||||
objName = str(nodeIdx) + "_" + str(node.left) + "_" + str(node.right) + "_wmb"
|
||||
obj = bpy.data.objects.new(objName, None)
|
||||
colTreeNodesCollection.objects.link(obj)
|
||||
obj.parent = rootNode
|
||||
obj.empty_display_type = 'CUBE'
|
||||
|
||||
obj.location = node.p1
|
||||
obj.scale = node.p2
|
||||
meshIndices = []
|
||||
for bObj in (x for x in bpy.data.collections['WMB'].all_objects if x.type == "MESH"):
|
||||
if bObj["colTreeNodeIndex"] == nodeIdx:
|
||||
idx = int(bObj.name.split("-")[0])
|
||||
meshIndices.append(idx)
|
||||
|
||||
if len(meshIndices) > 0:
|
||||
obj["meshIndices"] = meshIndices
|
||||
colTreeNode = [node.p1[0], node.p1[1], node.p1[2], node.p2[0], node.p2[1], node.p2[2], node.left, node.right]
|
||||
colTreeNodesDict[colTreeNodeName] = colTreeNode
|
||||
|
||||
"""
|
||||
bpy.ops.mesh.primitive_cube_add(enter_editmode=False, align='WORLD', location=(node.p1[0], node.p1[1], node.p1[2]))
|
||||
col_Bound = bpy.context.active_object
|
||||
col_Bound.name = str(index) + "-" + str(node.left) + "-" + str(node.right)
|
||||
bpy.ops.transform.resize(value=(node.p2[0], node.p2[1], node.p2[2]))
|
||||
bpy.ops.transform.rotate(value=math.radians(-90), orient_axis='X', center_override=(0, 0, 0))
|
||||
bpy.context.object.display_type = 'BOUNDS'
|
||||
collision_col.objects.link(col_Bound)
|
||||
collection.objects.unlink(col_Bound)
|
||||
"""
|
||||
|
||||
bpy.context.scene['colTreeNodes'] = colTreeNodesDict
|
||||
|
||||
def import_unknowWorldDataArray(wmb):
|
||||
@@ -584,12 +599,6 @@ def import_unknowWorldDataArray(wmb):
|
||||
unknownWorldDataDict[unknownWorldDataName] = unknownWorldData.unknownWorldData
|
||||
bpy.context.scene['unknownWorldData'] = unknownWorldDataDict
|
||||
|
||||
def import_wmb_boundingbox(wmb):
|
||||
boundingBoxXYZ = [wmb.wmb3_header.bounding_box1, wmb.wmb3_header.bounding_box2, wmb.wmb3_header.bounding_box3]
|
||||
boundingBoxUVW = [wmb.wmb3_header.bounding_box4, wmb.wmb3_header.bounding_box5, wmb.wmb3_header.bounding_box6]
|
||||
bpy.context.scene['boundingBoxXYZ'] = boundingBoxXYZ
|
||||
bpy.context.scene['boundingBoxUVW'] = boundingBoxUVW
|
||||
|
||||
def main(only_extract = False, wmb_file = os.path.split(os.path.realpath(__file__))[0] + '\\test\\pl0000.dtt\\pl0000.wmb'):
|
||||
#reset_blend()
|
||||
wmb = WMB3(wmb_file)
|
||||
@@ -601,19 +610,23 @@ def main(only_extract = False, wmb_file = os.path.split(os.path.realpath(__file_
|
||||
print('Extraction finished. ;)')
|
||||
return {'FINISHED'}
|
||||
|
||||
wmbCollection = bpy.data.collections.get("WMB")
|
||||
if not wmbCollection:
|
||||
wmbCollection = bpy.data.collections.new("WMB")
|
||||
bpy.context.scene.collection.children.link(wmbCollection)
|
||||
|
||||
collection_name = wmbname[:-4]
|
||||
|
||||
col = bpy.data.collections.new(collection_name)
|
||||
bpy.context.scene.collection.children.link(col)
|
||||
bpy.context.view_layer.active_layer_collection = bpy.context.view_layer.layer_collection.children[-1]
|
||||
wmbCollection.children.link(col)
|
||||
#bpy.context.view_layer.active_layer_collection = bpy.context.view_layer.layer_collection.children[-1]
|
||||
texture_dir = wmb_file.replace(wmbname, '\\textures\\')
|
||||
import_wmb_boundingbox(wmb)
|
||||
if wmb.hasBone:
|
||||
boneArray = [[bone.boneIndex, "bone%d"%bone.boneIndex, bone.parentIndex,"bone%d"%bone.parentIndex, bone.world_position, bone.world_rotation, bone.boneNumber, bone.local_position, bone.local_rotation, bone.world_rotation, bone.world_position_tpose] for bone in wmb.boneArray]
|
||||
armature_no_wmb = wmbname.replace('.wmb','')
|
||||
armature_name_split = armature_no_wmb.split('/')
|
||||
armature_name = armature_name_split[len(armature_name_split)-1] # THIS IS SPAGHETT I KNOW. I WAS TIRED
|
||||
construct_armature(armature_name, boneArray, wmb.firstLevel, wmb.secondLevel, wmb.thirdLevel, wmb.boneMap, wmb.boneSetArray)
|
||||
construct_armature(armature_name, boneArray, wmb.firstLevel, wmb.secondLevel, wmb.thirdLevel, wmb.boneMap, wmb.boneSetArray, collection_name)
|
||||
meshes, uvs, usedVerticeIndexArrays = format_wmb_mesh(wmb, collection_name)
|
||||
wmb_materials = get_wmb_material(wmb, texture_dir)
|
||||
materials = []
|
||||
|
||||
@@ -7,13 +7,13 @@ class WTA(object):
|
||||
super(WTA, self).__init__()
|
||||
self.magicNumber = wta_fp.read(4)
|
||||
if self.magicNumber == b'WTB\x00':
|
||||
self.unknown04 = to_int(wta_fp.read(4))
|
||||
self.textureCount = to_int(wta_fp.read(4))
|
||||
self.textureOffsetArrayOffset = to_int(wta_fp.read(4))
|
||||
self.textureSizeArrayOffset = to_int(wta_fp.read(4))
|
||||
self.unknownArrayOffset1 = to_int(wta_fp.read(4))
|
||||
self.textureIdentifierArrayOffset = to_int(wta_fp.read(4))
|
||||
self.unknownArrayOffset2 = to_int(wta_fp.read(4))
|
||||
self.unknown04 = to_uint(wta_fp.read(4))
|
||||
self.textureCount = to_uint(wta_fp.read(4))
|
||||
self.textureOffsetArrayOffset = to_uint(wta_fp.read(4))
|
||||
self.textureSizeArrayOffset = to_uint(wta_fp.read(4))
|
||||
self.unknownArrayOffset1 = to_uint(wta_fp.read(4))
|
||||
self.textureIdentifierArrayOffset = to_uint(wta_fp.read(4))
|
||||
self.unknownArrayOffset2 = to_uint(wta_fp.read(4))
|
||||
self.wtaTextureOffset = [0] * self.textureCount
|
||||
self.wtaTextureSize = [0] * self.textureCount
|
||||
self.wtaTextureIdentifier = [0] * self.textureCount
|
||||
@@ -21,17 +21,17 @@ class WTA(object):
|
||||
self.unknownArray2 = []
|
||||
for i in range(self.textureCount):
|
||||
wta_fp.seek(self.textureOffsetArrayOffset + i * 4)
|
||||
self.wtaTextureOffset[i] = to_int(wta_fp.read(4))
|
||||
self.wtaTextureOffset[i] = to_uint(wta_fp.read(4))
|
||||
wta_fp.seek(self.textureSizeArrayOffset + i * 4)
|
||||
self.wtaTextureSize[i] = to_int(wta_fp.read(4))
|
||||
self.wtaTextureSize[i] = to_uint(wta_fp.read(4))
|
||||
wta_fp.seek(self.textureIdentifierArrayOffset + i * 4)
|
||||
self.wtaTextureIdentifier[i] = "%08x"%to_int(wta_fp.read(4))
|
||||
self.wtaTextureIdentifier[i] = "%08x"%to_uint(wta_fp.read(4))
|
||||
wta_fp.seek(self.unknownArrayOffset1 + i * 4)
|
||||
self.unknownArray1[i] = "%08x"%to_int(wta_fp.read(4))
|
||||
self.unknownArray1[i] = "%08x"%to_uint(wta_fp.read(4))
|
||||
wta_fp.seek(self.unknownArrayOffset2 )
|
||||
unknownval = (wta_fp.read(4))
|
||||
while unknownval:
|
||||
self.unknownArray2.append(to_int(unknownval))
|
||||
self.unknownArray2.append(to_uint(unknownval))
|
||||
unknownval = (wta_fp.read(4))
|
||||
self.pointer2 = hex(wta_fp.tell())
|
||||
def getTextureByIndex(self, texture_index, texture_fp):
|
||||
|
||||
Reference in New Issue
Block a user