From 8a73a8ee48a1d05265455e589a4cb90588b7a985 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Mon, 30 Sep 2019 21:23:35 -1000 Subject: [PATCH] Code style improvements --- hecl/blender/CMakeLists.txt | 1 + hecl/blender/hecl/Nodegrid.py | 6 +- hecl/blender/hecl/__init__.py | 11 +- hecl/blender/hecl/armature.py | 35 + hecl/blender/hecl/hmdl/__init__.py | 18 +- hecl/blender/hecl/sact/SACTAction.py | 1 + hecl/blender/hecl/sact/__init__.py | 79 +- hecl/blender/hecl_blendershell.py | 37 +- hecl/driver/ToolCook.hpp | 2 +- hecl/driver/ToolPackage.hpp | 13 +- hecl/driver/ToolSpec.hpp | 6 +- hecl/extern/athena | 2 +- hecl/extern/boo | 2 +- hecl/include/hecl/Blender/Connection.hpp | 127 ++- hecl/include/hecl/Database.hpp | 2 - hecl/include/hecl/FourCC.hpp | 4 +- hecl/include/hecl/TypedVariant.hpp | 14 +- hecl/include/hecl/hecl.hpp | 85 +- hecl/lib/Blender/Connection.cpp | 949 +++++++---------------- hecl/lib/Blender/MeshOptimizer.cpp | 81 +- hecl/lib/Blender/SDNARead.cpp | 4 +- hecl/lib/CVar.cpp | 4 +- hecl/lib/CVarManager.cpp | 2 +- hecl/lib/Project.cpp | 4 +- hecl/lib/ProjectPath.cpp | 43 +- hecl/lib/hecl.cpp | 20 +- 26 files changed, 719 insertions(+), 833 deletions(-) create mode 100644 hecl/blender/hecl/armature.py diff --git a/hecl/blender/CMakeLists.txt b/hecl/blender/CMakeLists.txt index 0cc337007..f1a6ef2a9 100644 --- a/hecl/blender/CMakeLists.txt +++ b/hecl/blender/CMakeLists.txt @@ -10,6 +10,7 @@ list(APPEND PY_SOURCES hecl/sact/SACTSubtype.py hecl/srea/__init__.py hecl/swld/__init__.py + hecl/armature.py hecl/mapa.py hecl/mapu.py hecl/frme.py diff --git a/hecl/blender/hecl/Nodegrid.py b/hecl/blender/hecl/Nodegrid.py index 4dfe25d0f..b7d7049eb 100644 --- a/hecl/blender/hecl/Nodegrid.py +++ b/hecl/blender/hecl/Nodegrid.py @@ -1,11 +1,11 @@ # Node Grid Arranger Class NODE_PADDING = 80 -FRAME_NAMES = ['Textures','Output'] -FRAME_WIDTHS = [400, 180] +FRAME_NAMES = ['Textures','Output','Blend'] +FRAME_WIDTHS = [400, 180, 180] TOTAL_WIDTH = 0.0 for width in FRAME_WIDTHS: TOTAL_WIDTH += width + NODE_PADDING -FRAME_COLORS = [(0.6,0.48,0.44),(0.53,0.6,0.47)] +FRAME_COLORS = [(0.6,0.48,0.44),(0.53,0.6,0.47),(0.56,0.46,0.90)] class Nodegrid: def __init__(self, nodetree, cycles=False): diff --git a/hecl/blender/hecl/__init__.py b/hecl/blender/hecl/__init__.py index 318182944..8b33937c9 100644 --- a/hecl/blender/hecl/__init__.py +++ b/hecl/blender/hecl/__init__.py @@ -9,7 +9,7 @@ bl_info = { "category": "System"} # Package import -from . import hmdl, sact, srea, swld, mapa, mapu, frme, path, Nodegrid, Patching +from . import hmdl, sact, srea, swld, armature, mapa, mapu, frme, path, Nodegrid, Patching Nodegrid = Nodegrid.Nodegrid parent_armature = sact.SACTSubtype.parent_armature import bpy, os, sys, struct, math @@ -20,6 +20,7 @@ hecl_typeS = [ ('NONE', "None", "Active scene not using HECL", None), ('MESH', "Mesh", "Active scene represents an HMDL Mesh", hmdl.draw), ('CMESH', "Collision Mesh", "Active scene represents a Collision Mesh", None), +('ARMATURE', "Armature", "Active scene represents an Armature", armature.draw), ('ACTOR', "Actor", "Active scene represents a HECL Actor", sact.draw), ('AREA', "Area", "Active scene represents a HECL Area", srea.draw), ('WORLD', "World", "Active scene represents a HECL World", swld.draw), @@ -141,9 +142,10 @@ from bpy.app.handlers import persistent @persistent def scene_loaded(dummy): # Hide everything from an external library - for o in bpy.context.scene.objects: - if o.library: - o.hide_set(True) + if bpy.context.scene.hecl_type != 'FRAME': + for o in bpy.context.scene.objects: + if o.library or (o.data and o.data.library): + o.hide_set(True) # Show PATH library objects as wireframes if bpy.context.scene.hecl_type == 'PATH': @@ -208,6 +210,7 @@ def register(): mapa.register() mapu.register() path.register() + armature.register() bpy.utils.register_class(hecl_scene_panel) bpy.utils.register_class(hecl_light_panel) bpy.types.Scene.hecl_auto_select = bpy.props.BoolProperty(name='HECL Auto Select', default=True) diff --git a/hecl/blender/hecl/armature.py b/hecl/blender/hecl/armature.py new file mode 100644 index 000000000..91477a9ce --- /dev/null +++ b/hecl/blender/hecl/armature.py @@ -0,0 +1,35 @@ +import struct + +def cook(writebuf, arm): + writebuf(struct.pack('I', len(arm.bones))) + for bone in arm.bones: + writebuf(struct.pack('I', len(bone.name))) + writebuf(bone.name.encode()) + + writebuf(struct.pack('fff', bone.head_local[0], bone.head_local[1], bone.head_local[2])) + + if bone.parent: + writebuf(struct.pack('i', arm.bones.find(bone.parent.name))) + else: + writebuf(struct.pack('i', -1)) + + writebuf(struct.pack('I', len(bone.children))) + for child in bone.children: + writebuf(struct.pack('i', arm.bones.find(child.name))) + +def draw(layout, context): + layout.prop_search(context.scene, 'hecl_arm_obj', context.scene, 'objects') + if not len(context.scene.hecl_arm_obj): + layout.label(text="Armature not specified", icon='ERROR') + elif context.scene.hecl_arm_obj not in context.scene.objects: + layout.label(text="'"+context.scene.hecl_arm_obj+"' not in scene", icon='ERROR') + else: + obj = context.scene.objects[context.scene.hecl_arm_obj] + if obj.type != 'ARMATURE': + layout.label(text="'"+context.scene.hecl_arm_obj+"' not an 'ARMATURE'", icon='ERROR') + +import bpy +def register(): + bpy.types.Scene.hecl_arm_obj = bpy.props.StringProperty( + name='HECL Armature Object', + description='Blender Armature Object to export during HECL\'s cook process') diff --git a/hecl/blender/hecl/hmdl/__init__.py b/hecl/blender/hecl/hmdl/__init__.py index 4eaaf46b3..ae765b416 100644 --- a/hecl/blender/hecl/hmdl/__init__.py +++ b/hecl/blender/hecl/hmdl/__init__.py @@ -1,6 +1,12 @@ import struct, bpy, bmesh from . import HMDLShader, HMDLMesh +BLEND_TYPES = { + 'HECLAdditiveOutput': 2, + 'HECLBlendOutput': 1, + 'HECLOpaqueOutput': 0, +} + def write_out_material(writebuf, mat, mesh_obj): writebuf(struct.pack('I', len(mat.name))) writebuf(mat.name.encode()) @@ -20,12 +26,10 @@ def write_out_material(writebuf, mat, mesh_obj): writebuf(prop[0].encode()) writebuf(struct.pack('i', prop[1])) - blend = 0 - if mat.blend_method == 'BLEND': - blend = 1 - elif mat.blend_method == 'ADD': - blend = 2 - writebuf(struct.pack('I', blend)) + blend_node = mat.node_tree.nodes['Blend'] + if blend_node.node_tree.name not in BLEND_TYPES: + raise RuntimeError("HMDL *requires* one of the HMDL*Output group nodes for the 'Blend' node") + writebuf(struct.pack('I', BLEND_TYPES[blend_node.node_tree.name])) # Takes a Blender 'Mesh' object (not the datablock) # and performs a one-shot conversion process to HMDL @@ -256,6 +260,7 @@ def draw(layout, context): obj = context.scene.objects[context.scene.hecl_mesh_obj] if obj.type != 'MESH': layout.label(text="'"+context.scene.hecl_mesh_obj+"' not a 'MESH'", icon='ERROR') + layout.prop(obj.data, 'cskr_id') layout.prop(obj.data, 'hecl_active_material') layout.prop(obj.data, 'hecl_material_count') @@ -297,6 +302,7 @@ def register(): bpy.types.Scene.hecl_actor_obj = bpy.props.StringProperty( name='HECL Actor Object', description='Blender Empty Object to export during HECL\'s cook process') + bpy.types.Mesh.cskr_id = bpy.props.StringProperty(name='Original CSKR ID') bpy.types.Mesh.hecl_material_count = bpy.props.IntProperty(name='HECL Material Count', default=0, min=0) bpy.types.Mesh.hecl_active_material = bpy.props.IntProperty(name='HECL Active Material', default=0, min=0, update=material_update) bpy.utils.register_class(hecl_mesh_operator) diff --git a/hecl/blender/hecl/sact/SACTAction.py b/hecl/blender/hecl/sact/SACTAction.py index e2d5bd951..1a25ce9a9 100644 --- a/hecl/blender/hecl/sact/SACTAction.py +++ b/hecl/blender/hecl/sact/SACTAction.py @@ -52,6 +52,7 @@ def draw(layout, context): else: #layout.prop(linked_action, 'hecl_index', text="Index") #layout.prop(linked_action, 'hecl_anim_props', text="Props") + layout.prop(linked_action, 'anim_id', text="ANIM ID") layout.prop(linked_action, 'hecl_fps', text="Frame Rate") row = layout.row() row.prop(context.scene, 'hecl_auto_remap', text="60-fps Remap") diff --git a/hecl/blender/hecl/sact/__init__.py b/hecl/blender/hecl/sact/__init__.py index d2ce45bc2..636156242 100644 --- a/hecl/blender/hecl/sact/__init__.py +++ b/hecl/blender/hecl/sact/__init__.py @@ -1,4 +1,5 @@ from . import SACTSubtype, SACTAction, ANIM +from .. import armature import bpy import bpy.path @@ -207,21 +208,14 @@ def _out_armatures(sact_data, writebuf): writebuf(struct.pack('I', len(arm.name))) writebuf(arm.name.encode()) - writebuf(struct.pack('I', len(arm.bones))) - for bone in arm.bones: - writebuf(struct.pack('I', len(bone.name))) - writebuf(bone.name.encode()) + if arm.library: + arm_path = bpy.path.abspath(arm.library.filepath) + writebuf(struct.pack('I', len(arm_path))) + writebuf(arm_path.encode()) + else: + writebuf(struct.pack('I', 0)) - writebuf(struct.pack('fff', bone.head_local[0], bone.head_local[1], bone.head_local[2])) - - if bone.parent: - writebuf(struct.pack('i', arm.bones.find(bone.parent.name))) - else: - writebuf(struct.pack('i', -1)) - - writebuf(struct.pack('I', len(bone.children))) - for child in bone.children: - writebuf(struct.pack('i', arm.bones.find(child.name))) + armature.cook(writebuf, arm) def _out_subtypes(sact_data, writebuf): writebuf(struct.pack('I', len(sact_data.subtypes))) @@ -232,9 +226,14 @@ def _out_subtypes(sact_data, writebuf): mesh = None if subtype.linked_mesh in bpy.data.objects: mesh = bpy.data.objects[subtype.linked_mesh] + cskr_id = mesh.data.cskr_id + writebuf(struct.pack('I', len(cskr_id))) + writebuf(cskr_id.encode()) + else: + writebuf(struct.pack('I', 0)) - if mesh and mesh.library: - mesh_path = bpy.path.abspath(mesh.library.filepath) + if mesh and mesh.data.library: + mesh_path = bpy.path.abspath(mesh.data.library.filepath) writebuf(struct.pack('I', len(mesh_path))) writebuf(mesh_path.encode()) else: @@ -257,9 +256,14 @@ def _out_subtypes(sact_data, writebuf): mesh = None if overlay.linked_mesh in bpy.data.objects: mesh = bpy.data.objects[overlay.linked_mesh] + cskr_id = mesh.data.cskr_id + writebuf(struct.pack('I', len(cskr_id))) + writebuf(cskr_id.encode()) + else: + writebuf(struct.pack('I', 0)) - if mesh and mesh.library: - mesh_path = bpy.path.abspath(mesh.library.filepath) + if mesh and mesh.data.library: + mesh_path = bpy.path.abspath(mesh.data.library.filepath) writebuf(struct.pack('I', len(mesh_path))) writebuf(mesh_path.encode()) else: @@ -274,9 +278,14 @@ def _out_attachments(sact_data, writebuf): mesh = None if attachment.linked_mesh in bpy.data.objects: mesh = bpy.data.objects[attachment.linked_mesh] + cskr_id = mesh.data.cskr_id + writebuf(struct.pack('I', len(cskr_id))) + writebuf(cskr_id.encode()) + else: + writebuf(struct.pack('I', 0)) - if mesh and mesh.library: - mesh_path = bpy.path.abspath(mesh.library.filepath) + if mesh and mesh.data.library: + mesh_path = bpy.path.abspath(mesh.data.library.filepath) writebuf(struct.pack('I', len(mesh_path))) writebuf(mesh_path.encode()) else: @@ -302,6 +311,9 @@ def _out_actions(sact_data, writebuf): bact = None if action.name in bpy.data.actions: bact = bpy.data.actions[action.name] + anim_id = bact.anim_id + writebuf(struct.pack('I', len(anim_id))) + writebuf(anim_id.encode()) if not bact: raise RuntimeError('action %s not found' % action.name) @@ -334,6 +346,9 @@ def _out_action_no_subtypes(sact_data, writebuf, action_name): bact = None if action.name in bpy.data.actions: bact = bpy.data.actions[action.name] + anim_id = bact.anim_id + writebuf(struct.pack('I', len(anim_id))) + writebuf(anim_id.encode()) if not bact: raise RuntimeError('action %s not found' % action.name) @@ -386,14 +401,6 @@ def cook_action_channels_only(writebuf, action_name): # Output action without AABBs _out_action_no_subtypes(sact_data, writebuf, action_name) - -# Access actor's contained armature names -def get_armature_names(writebuf): - writebuf(struct.pack('I', len(bpy.data.armatures))) - for arm in bpy.data.armatures: - writebuf(struct.pack('I', len(arm.name))) - writebuf(arm.name.encode()) - # Access actor's contained subtype names def get_subtype_names(writebuf): sact_data = bpy.context.scene.hecl_sact_data @@ -402,6 +409,10 @@ def get_subtype_names(writebuf): subtype = sact_data.subtypes[sub_idx] writebuf(struct.pack('I', len(subtype.name))) writebuf(subtype.name.encode()) + obj = bpy.data.objects[subtype.linked_mesh] + cskr_id = obj.data.cskr_id + writebuf(struct.pack('I', len(cskr_id))) + writebuf(cskr_id.encode()) # Access subtype's contained overlay names def get_subtype_overlay_names(writebuf, subtypeName): @@ -413,6 +424,10 @@ def get_subtype_overlay_names(writebuf, subtypeName): for overlay in subtype.overlays: writebuf(struct.pack('I', len(overlay.name))) writebuf(overlay.name.encode()) + obj = bpy.data.objects[overlay.linked_mesh] + cskr_id = obj.data.cskr_id + writebuf(struct.pack('I', len(cskr_id))) + writebuf(cskr_id.encode()) return writebuf(struct.pack('I', 0)) @@ -424,6 +439,10 @@ def get_attachment_names(writebuf): attachment = sact_data.attachments[att_idx] writebuf(struct.pack('I', len(attachment.name))) writebuf(attachment.name.encode()) + obj = bpy.data.objects[attachment.linked_mesh] + cskr_id = obj.data.cskr_id + writebuf(struct.pack('I', len(cskr_id))) + writebuf(cskr_id.encode()) # Access actor's contained action names def get_action_names(writebuf): @@ -433,6 +452,9 @@ def get_action_names(writebuf): action = sact_data.actions[action_idx] writebuf(struct.pack('I', len(action.name))) writebuf(action.name.encode()) + anim_id = bpy.data.actions[action.name].anim_id + writebuf(struct.pack('I', len(anim_id))) + writebuf(anim_id.encode()) # Panel draw def draw(layout, context): @@ -452,6 +474,7 @@ def register(): SACTAction.register() bpy.utils.register_class(SACTData) bpy.types.Scene.hecl_sact_data = bpy.props.PointerProperty(type=SACTData) + bpy.types.Action.anim_id = bpy.props.StringProperty(name='Original ANIM ID') bpy.types.Action.hecl_fps = bpy.props.IntProperty(name='HECL Action FPS', default=30) bpy.types.Action.hecl_additive = bpy.props.BoolProperty(name='HECL Additive Action', default=False) bpy.types.Action.hecl_looping = bpy.props.BoolProperty(name='HECL Looping Action', default=False) diff --git a/hecl/blender/hecl_blendershell.py b/hecl/blender/hecl_blendershell.py index 93817204f..ba459d909 100644 --- a/hecl/blender/hecl_blendershell.py +++ b/hecl/blender/hecl_blendershell.py @@ -55,17 +55,7 @@ class PathHasher: def hashpath32(self, path): writepipestr(path.encode()) read_str = readpipestr() - if len(read_str) >= 16: - hash = int(read_str[0:16], 16) - return (hash & 0xffffffff) ^ ((hash >> 32) & 0xffffffff) - return 0 - - def hashpath64(self, path): - writepipestr(path.encode()) - read_str = readpipestr() - if len(read_str) >= 16: - return int(read_str[0:16], 16) - return 0 + return int(read_str[0:8], 16) # Ensure Blender 2.8 is being used if bpy.app.version < (2, 80, 0): @@ -226,21 +216,21 @@ def dataout_loop(): elif cmdargs[0] == 'MESHLIST': meshCount = 0 for meshobj in bpy.data.objects: - if meshobj.type == 'MESH' and not meshobj.library: + if meshobj.type == 'MESH' and not meshobj.data.library: meshCount += 1 writepipebuf(struct.pack('I', meshCount)) for meshobj in bpy.data.objects: - if meshobj.type == 'MESH' and not meshobj.library: + if meshobj.type == 'MESH' and not meshobj.data.library: writepipestr(meshobj.name.encode()) elif cmdargs[0] == 'LIGHTLIST': lightCount = 0 for obj in bpy.context.scene.objects: - if obj.type == 'LIGHT' and not obj.library: + if obj.type == 'LIGHT' and not obj.data.library: lightCount += 1 writepipebuf(struct.pack('I', lightCount)) for obj in bpy.context.scene.objects: - if obj.type == 'LIGHT' and not obj.library: + if obj.type == 'LIGHT' and not obj.data.library: writepipestr(obj.name.encode()) elif cmdargs[0] == 'MESHAABB': @@ -256,6 +246,15 @@ def dataout_loop(): writepipestr(b'OK') hecl.hmdl.cook(writepipebuf, bpy.data.objects[meshName]) + elif cmdargs[0] == 'ARMATURECOMPILE': + armName = bpy.context.scene.hecl_arm_obj + if armName not in bpy.data.objects: + writepipestr(('armature %s not found' % armName).encode()) + continue + + writepipestr(b'OK') + hecl.armature.cook(writepipebuf, bpy.data.objects[armName].data) + elif cmdargs[0] == 'MESHCOMPILENAME': meshName = cmdargs[1] useLuv = int(cmdargs[2]) @@ -281,13 +280,13 @@ def dataout_loop(): writepipestr(b'OK') colCount = 0 for obj in bpy.context.scene.objects: - if obj.type == 'MESH' and not obj.library: + if obj.type == 'MESH' and not obj.data.library: colCount += 1 writepipebuf(struct.pack('I', colCount)) for obj in bpy.context.scene.objects: - if obj.type == 'MESH' and not obj.library: + if obj.type == 'MESH' and not obj.data.library: hecl.hmdl.cookcol(writepipebuf, obj) elif cmdargs[0] == 'MESHCOMPILEPATH': @@ -384,10 +383,6 @@ def dataout_loop(): writepipestr(b'OK') hecl.sact.cook_action_channels_only(writepipebuf, actionName) - elif cmdargs[0] == 'GETARMATURENAMES': - writepipestr(b'OK') - hecl.sact.get_armature_names(writepipebuf) - elif cmdargs[0] == 'GETSUBTYPENAMES': writepipestr(b'OK') hecl.sact.get_subtype_names(writepipebuf) diff --git a/hecl/driver/ToolCook.hpp b/hecl/driver/ToolCook.hpp index 1f3e83702..93f96a723 100644 --- a/hecl/driver/ToolCook.hpp +++ b/hecl/driver/ToolCook.hpp @@ -26,7 +26,7 @@ public: for (const hecl::SystemString& arg : info.args) { if (arg.empty()) continue; - else if (!arg.compare(_SYS_STR("--fast"))) { + else if (arg == _SYS_STR("--fast")) { m_fast = true; continue; } else if (arg.size() >= 8 && !arg.compare(0, 7, _SYS_STR("--spec="))) { diff --git a/hecl/driver/ToolPackage.hpp b/hecl/driver/ToolPackage.hpp index ebbb20f2d..108b03aca 100644 --- a/hecl/driver/ToolPackage.hpp +++ b/hecl/driver/ToolPackage.hpp @@ -20,15 +20,10 @@ class ToolPackage final : public ToolBase { } void CheckFile(const hecl::ProjectPath& path) { - if (!hecl::StrCmp(path.getLastComponent().data(), _SYS_STR("!world.blend"))) + auto lastComp = path.getLastComponent(); + if (hecl::StringUtils::BeginsWith(lastComp, _SYS_STR("!world_")) && + hecl::StringUtils::EndsWith(lastComp, _SYS_STR(".blend"))) AddSelectedItem(path); -#if RUNTIME_ORIGINAL_IDS - else if (!hecl::StrCmp(path.getLastComponent().data(), _SYS_STR("!original_ids.yaml"))) { - auto pathComps = path.getPathComponents(); - if (pathComps.size() == 2 && pathComps[0] != _SYS_STR("out")) - AddSelectedItem(path); - } -#endif } void FindSelectedItems(const hecl::ProjectPath& path, bool checkGeneral) { @@ -70,7 +65,7 @@ public: for (const hecl::SystemString& arg : info.args) { if (arg.empty()) continue; - else if (!arg.compare(_SYS_STR("--fast"))) { + else if (arg == _SYS_STR("--fast")) { m_fast = true; continue; } else if (arg.size() >= 8 && !arg.compare(0, 7, _SYS_STR("--spec="))) { diff --git a/hecl/driver/ToolSpec.hpp b/hecl/driver/ToolSpec.hpp index ec96a4f25..3a927614b 100644 --- a/hecl/driver/ToolSpec.hpp +++ b/hecl/driver/ToolSpec.hpp @@ -19,9 +19,9 @@ public: hecl::SystemString firstArg = info.args.front(); hecl::ToLower(firstArg); - if (!firstArg.compare(_SYS_STR("enable"))) + if (firstArg == _SYS_STR("enable")) mode = MENABLE; - else if (!firstArg.compare(_SYS_STR("disable"))) + else if (firstArg == _SYS_STR("disable")) mode = MDISABLE; else return; @@ -112,7 +112,7 @@ public: for (auto& spec : specs) { hecl::SystemString compName(spec.spec.m_name); hecl::ToLower(compName); - if (!itName.compare(compName)) { + if (itName == compName) { opSpecs.emplace_back(spec.spec.m_name); break; } diff --git a/hecl/extern/athena b/hecl/extern/athena index 132c7def6..42581c922 160000 --- a/hecl/extern/athena +++ b/hecl/extern/athena @@ -1 +1 @@ -Subproject commit 132c7def65a78f5915e199de805abb672c291d98 +Subproject commit 42581c922a4574f4f34df134a454effa9f9cc8d0 diff --git a/hecl/extern/boo b/hecl/extern/boo index 9b8ef4695..922fcbb3c 160000 --- a/hecl/extern/boo +++ b/hecl/extern/boo @@ -1 +1 @@ -Subproject commit 9b8ef4695f3f1d07b29580241fc266abc17dc29c +Subproject commit 922fcbb3c23677b3ccc53737fd23ada165ccf9f3 diff --git a/hecl/include/hecl/Blender/Connection.hpp b/hecl/include/hecl/Blender/Connection.hpp index 82f66d3b7..1e4432141 100644 --- a/hecl/include/hecl/Blender/Connection.hpp +++ b/hecl/include/hecl/Blender/Connection.hpp @@ -81,7 +81,8 @@ class PyOutStream : public std::ostream { StreamBuf(PyOutStream& parent, bool deleteOnError) : m_parent(parent), m_deleteOnError(deleteOnError) {} StreamBuf(const StreamBuf& other) = delete; StreamBuf(StreamBuf&& other) = default; - int_type overflow(int_type ch) override; + bool sendLine(std::string_view line); + std::streamsize xsputn(const char_type* __s, std::streamsize __n) override; } m_sbuf; PyOutStream(Connection* parent, bool deleteOnError); @@ -94,8 +95,10 @@ public: void close(); template > void format(const S& format, Args&&... args); - void linkBlend(const char* target, const char* objName, bool link = true); - void linkBackground(const char* target, const char* sceneName = nullptr); + void linkBlend(std::string_view target, std::string_view objName, bool link = true); + void linkArmature(std::string_view target, std::string_view armName); + void linkMesh(std::string_view target, std::string_view meshName); + void linkBackground(std::string_view target, std::string_view sceneName = {}); void AABBToBMesh(const atVec3f& min, const atVec3f& max); void centerView(); @@ -498,15 +501,15 @@ struct Light { /** Intermediate MapArea representation */ struct MapArea { - Index visType; + uint32_t visType; std::vector verts; - std::vector indices; + std::vector indices; struct Surface { Vector3f normal; Vector3f centerOfMass; - Index start; - Index count; - std::vector> borders; + uint32_t start; + uint32_t count; + std::vector> borders; Surface(Connection& conn); }; std::vector surfaces; @@ -547,7 +550,6 @@ struct Bone { /** Intermediate armature representation used in Actor */ struct Armature { - std::string name; std::vector bones; const Bone* lookupBone(const char* name) const; const Bone* getParent(const Bone* bone) const; @@ -559,6 +561,7 @@ struct Armature { /** Intermediate action representation used in Actor */ struct Action { std::string name; + std::string animId; float interval; bool additive; bool looping; @@ -582,18 +585,32 @@ struct Action { /** Intermediate actor representation prepared by blender from a single HECL actor blend */ struct Actor { - std::vector armatures; + struct ActorArmature { + std::string name; + ProjectPath path; + std::optional armature; + ActorArmature(Connection& conn); + }; + std::vector armatures; struct Subtype { std::string name; + std::string cskrId; ProjectPath mesh; int32_t armature = -1; - std::vector> overlayMeshes; + struct OverlayMesh { + std::string name; + std::string cskrId; + ProjectPath mesh; + OverlayMesh(Connection& conn); + }; + std::vector overlayMeshes; Subtype(Connection& conn); }; std::vector subtypes; struct Attachment { std::string name; + std::string cskrId; ProjectPath mesh; int32_t armature = -1; Attachment(Connection& conn); @@ -654,12 +671,12 @@ public: Actor compileActor(); Actor compileActorCharacterOnly(); + Armature compileArmature(); Action compileActionChannelsOnly(std::string_view name); - std::vector getArmatureNames(); - std::vector getSubtypeNames(); - std::vector getActionNames(); - std::vector getSubtypeOverlayNames(std::string_view name); - std::vector getAttachmentNames(); + std::vector> getSubtypeNames(); + std::vector> getActionNames(); + std::vector> getSubtypeOverlayNames(std::string_view name); + std::vector> getAttachmentNames(); std::unordered_map getBoneMatrices(std::string_view name); @@ -695,6 +712,7 @@ class Connection { friend struct Vector3f; friend struct Vector4f; friend struct World; + friend class MeshOptimizer; std::atomic_bool m_lock = {false}; bool m_pyStreamActive = false; @@ -718,6 +736,80 @@ class Connection { uint32_t _writeStr(std::string_view view) { return _writeStr(view.data(), view.size()); } size_t _readBuf(void* buf, size_t len); size_t _writeBuf(const void* buf, size_t len); + std::string _readStdString() { + uint32_t bufSz; + _readBuf(&bufSz, 4); + std::string ret(bufSz, ' '); + _readBuf(&ret[0], bufSz); + return ret; + } + template, std::is_enum>, int> = 0> + void _readValue(T& v) { _readBuf(&v, sizeof(T)); } + template + void _readItems(T enumerator) { + uint32_t nItems; + _readBuf(&nItems, 4); + for (uint32_t i = 0; i < nItems; ++i) + enumerator(*this); + } + template, std::is_enum, std::is_same>, int> = 0> + void _readVector(std::vector& container, Args&&... args) { + uint32_t nItems; + _readBuf(&nItems, 4); + container.clear(); + container.reserve(nItems); + for (uint32_t i = 0; i < nItems; ++i) + container.emplace_back(*this, std::forward(args)...); + } + template, std::is_enum>, int> = 0> + void _readVector(std::vector& container) { + uint32_t nItems; + _readBuf(&nItems, 4); + container.clear(); + container.resize(nItems); + _readBuf(&container[0], sizeof(T) * nItems); + } + void _readVector(std::vector& container) { + uint32_t nItems; + _readBuf(&nItems, 4); + container.clear(); + container.reserve(nItems); + for (uint32_t i = 0; i < nItems; ++i) { + uint32_t strSize; + _readBuf(&strSize, 4); + _readBuf(&container.emplace_back(strSize, ' ')[0], strSize); + } + } + template + void _readVectorFunc(std::vector& container, F func) { + uint32_t nItems; + _readBuf(&nItems, 4); + container.clear(); + container.reserve(nItems); + for (uint32_t i = 0; i < nItems; ++i) + func(); + } + ProjectPath _readPath(); + bool _isStatus(const char* status) { + char readBuf[16]; + _readStr(readBuf, 16); + return std::strcmp(readBuf, status) == 0; + } + bool _isOk() { return _isStatus("OK"); } + bool _isFinished() { return _isStatus("FINISHED"); } + bool _isTrue() { return _isStatus("TRUE"); } + void _checkStatus(std::string_view action, std::string_view status) { + char readBuf[16]; + _readStr(readBuf, 16); + if (status != readBuf) + BlenderLog.report(logvisor::Fatal, fmt("{}: {}: {}"), m_loadedBlend.getRelativePathUTF8(), action, readBuf); + } + void _checkReady(std::string_view action) { _checkStatus(action, "READY"sv); } + void _checkDone(std::string_view action) { _checkStatus(action, "DONE"sv); } + void _checkOk(std::string_view action) { _checkStatus(action, "OK"sv); } + void _checkAnimReady(std::string_view action) { _checkStatus(action, "ANIMREADY"sv); } + void _checkAnimDone(std::string_view action) { _checkStatus(action, "ANIMDONE"sv); } void _closePipe(); void _blenderDied(); @@ -764,8 +856,7 @@ public: }; template -void PyOutStream::format(const S& format, Args&&... args) -{ +void PyOutStream::format(const S& format, Args&&... args) { if (!m_parent || !m_parent->m_lock) BlenderLog.report(logvisor::Fatal, fmt("lock not held for PyOutStream::format()")); fmt::print(*this, format, std::forward(args)...); diff --git a/hecl/include/hecl/Database.hpp b/hecl/include/hecl/Database.hpp index 5f7dee115..0baafe856 100644 --- a/hecl/include/hecl/Database.hpp +++ b/hecl/include/hecl/Database.hpp @@ -15,8 +15,6 @@ #include "hecl.hpp" -#define RUNTIME_ORIGINAL_IDS 0 - namespace hecl { class ClientProcess; diff --git a/hecl/include/hecl/FourCC.hpp b/hecl/include/hecl/FourCC.hpp index 26ba12ad6..d772205fa 100644 --- a/hecl/include/hecl/FourCC.hpp +++ b/hecl/include/hecl/FourCC.hpp @@ -72,12 +72,12 @@ inline void DNAFourCC::Enumerate(Write::StreamT& w) { } template <> inline void DNAFourCC::Enumerate(ReadYaml::StreamT& r) { - const std::string rs = r.readString(nullptr); + const std::string rs = r.readString(); rs.copy(fcc, std::size(fcc)); } template <> inline void DNAFourCC::Enumerate(WriteYaml::StreamT& w) { - w.writeString(nullptr, std::string_view{fcc, std::size(fcc)}); + w.writeString(std::string_view{fcc, std::size(fcc)}); } template <> inline void DNAFourCC::Enumerate(BinarySize::StreamT& s) { diff --git a/hecl/include/hecl/TypedVariant.hpp b/hecl/include/hecl/TypedVariant.hpp index 5eae4b1a8..69d6f0bdb 100644 --- a/hecl/include/hecl/TypedVariant.hpp +++ b/hecl/include/hecl/TypedVariant.hpp @@ -204,7 +204,7 @@ template <> \ template <> \ inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate::Read>(typename Read::StreamT & r) { \ EnumType variant_type = {}; \ - Do::Read>(athena::io::PropId("variant_type"), variant_type, r); \ + Do::Read>(athena::io::PropId("variant_type"sv), variant_type, r); \ static_cast&>(*this) = Build(variant_type); \ visit([&](auto& var) { var.read(r); }); \ } \ @@ -215,7 +215,7 @@ inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate; \ EnumType variant_type = T::variant_type(); \ - Do::Write>(athena::io::PropId("variant_type"), variant_type, w); \ + Do::Write>(athena::io::PropId("variant_type"sv), variant_type, w); \ var.write(w); \ }); \ } \ @@ -226,13 +226,13 @@ inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate; \ EnumType variant_type = T::variant_type(); \ - Do::BinarySize>(athena::io::PropId("variant_type"), variant_type, sz); \ + Do::BinarySize>(athena::io::PropId("variant_type"sv), variant_type, sz); \ var.binarySize(sz); \ }); \ } \ template <> \ -inline const char* hecl::TypedVariantBigDNA<__VA_ARGS__>::DNAType() { \ - return "hecl::TypedVariantBigDNA<" #__VA_ARGS__ ">"; \ +inline std::string_view hecl::TypedVariantBigDNA<__VA_ARGS__>::DNAType() { \ + return "hecl::TypedVariantBigDNA<" #__VA_ARGS__ ">"sv; \ } #define AT_SPECIALIZE_TYPED_VARIANT_BIGDNA_YAML(...) \ @@ -241,7 +241,7 @@ template <> \ template <> \ inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate::ReadYaml>(typename ReadYaml::StreamT & r) { \ EnumType variant_type = {}; \ - Do::ReadYaml>(athena::io::PropId("variant_type"), variant_type, r); \ + Do::ReadYaml>(athena::io::PropId("variant_type"sv), variant_type, r); \ static_cast&>(*this) = Build(variant_type); \ visit([&](auto& var) { var.read(r); }); \ } \ @@ -252,7 +252,7 @@ inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate; \ EnumType variant_type = T::variant_type(); \ - Do::WriteYaml>(athena::io::PropId("variant_type"), variant_type, w); \ + Do::WriteYaml>(athena::io::PropId("variant_type"sv), variant_type, w); \ var.write(w); \ }); \ } diff --git a/hecl/include/hecl/hecl.hpp b/hecl/include/hecl/hecl.hpp index 28a0ba3c8..5cb44c142 100644 --- a/hecl/include/hecl/hecl.hpp +++ b/hecl/include/hecl/hecl.hpp @@ -60,7 +60,8 @@ struct DataSpecEntry; } // namespace Database namespace blender { -enum class BlendType { None, Mesh, ColMesh, Actor, Area, World, MapArea, MapUniverse, Frame, PathMesh }; +enum class BlendType { None, Mesh, ColMesh, Armature, Actor, Area, + World, MapArea, MapUniverse, Frame, PathMesh }; class Connection; class Token; @@ -137,6 +138,8 @@ public: return std::wstring(lhs).append(rhs.m_sys); } }; + +inline hecl::SystemString UTF8StringToSysString(std::string_view src) { return UTF8ToWide(src); } #else class SystemUTF8Conv { std::string_view m_utf8; @@ -171,6 +174,8 @@ public: return std::string(lhs).append(rhs.m_sys); } }; + +inline hecl::SystemString UTF8StringToSysString(std::string src) { return src; } #endif void SanitizePath(std::string& path); @@ -423,7 +428,9 @@ class MultiProgressPrinter; class ProjectRootPath; using SystemRegex = std::basic_regex; +using SystemRegexIterator = std::regex_iterator; using SystemRegexMatch = std::match_results; +using SystemViewRegexMatch = std::match_results; using SystemRegexTokenIterator = std::regex_token_iterator; /** @@ -929,6 +936,36 @@ public: } #endif + template + class EncodableString { + friend class ProjectPath; + using EncStringView = std::basic_string_view; + StringT m_ownedString; + EncStringView m_stringView; + EncodableString(StringT s) : m_ownedString(std::move(s)), m_stringView(m_ownedString) {} + EncodableString(EncStringView sv) : m_stringView(sv) {} + EncodableString(const EncodableString&) = delete; + EncodableString& operator=(const EncodableString&) = delete; + EncodableString(EncodableString&&) = delete; + EncodableString& operator=(EncodableString&&) = delete; + public: + operator EncStringView() const { return m_stringView; } + }; + + EncodableString getEncodableString() const { + if (!getAuxInfo().empty()) + return {SystemString(getRelativePath()) + _SYS_STR('|') + getAuxInfo().data()}; + else + return {getRelativePath()}; + } + + EncodableString getEncodableStringUTF8() const { + if (!getAuxInfo().empty()) + return {std::string(getRelativePathUTF8()) + '|' + getAuxInfoUTF8().data()}; + else + return {getRelativePathUTF8()}; + } + /** * @brief Type of path */ @@ -1053,6 +1090,8 @@ public: Hash hash() const noexcept { return m_hash; } bool operator==(const ProjectPath& other) const noexcept { return m_hash == other.m_hash; } bool operator!=(const ProjectPath& other) const noexcept { return !operator==(other); } + + uint32_t parsedHash32() const; }; /** @@ -1294,6 +1333,50 @@ constexpr void hash_combine_impl(SizeT& seed, SizeT value) noexcept { } // namespace hecl +#define CHAINED_SIGNAL_HANDLER(name, signal) \ +class ChainedSignalHandler_##name { \ + typedef void(*sighandler_t)(int); \ + typedef void(*sigaction_t)(int, siginfo_t*, void*); \ + static std::atomic_bool m_isSetup; \ + static sighandler_t m_nextsh; \ + static sigaction_t m_nextsa; \ + static void my_sig_action(int sig, siginfo_t* si, void* ctx); \ + static void sig_action(int sig, siginfo_t* si, void* ctx) { \ + my_sig_action(sig, si, ctx); \ + if (m_nextsa) \ + m_nextsa(sig, si, ctx); \ + else if (m_nextsh) \ + m_nextsh(sig); \ + } \ +public: \ + static void setup() { \ + if (ChainedSignalHandler_##name::m_isSetup.exchange(true) == true) \ + return; \ + { \ + struct sigaction sold; \ + if (sigaction(signal, nullptr, &sold) == 0) { \ + if (sold.sa_flags & SA_SIGINFO) \ + m_nextsa = sold.sa_sigaction; \ + else \ + m_nextsh = sold.sa_handler; \ + } \ + } \ + { \ + struct sigaction snew = {}; \ + snew.sa_sigaction = sig_action; \ + snew.sa_flags = SA_RESTART | SA_NOCLDSTOP | SA_SIGINFO; \ + sigaction(signal, &snew, nullptr); \ + } \ + } \ +}; \ +std::atomic_bool ChainedSignalHandler_##name::m_isSetup = {false}; \ +ChainedSignalHandler_##name::sighandler_t ChainedSignalHandler_##name::m_nextsh = {}; \ +ChainedSignalHandler_##name::sigaction_t ChainedSignalHandler_##name::m_nextsa = {}; \ +inline void ChainedSignalHandler_##name::my_sig_action + +#define SETUP_CHAINED_SIGNAL_HANDLER(name) \ +ChainedSignalHandler_##name::setup() + namespace std { template <> struct hash { diff --git a/hecl/lib/Blender/Connection.cpp b/hecl/lib/Blender/Connection.cpp index 9e63544d9..d2c75f158 100644 --- a/hecl/lib/Blender/Connection.cpp +++ b/hecl/lib/Blender/Connection.cpp @@ -26,6 +26,8 @@ #if _WIN32 #include #include +#else +#include #endif #undef min @@ -52,7 +54,7 @@ Token SharedBlenderToken; #ifdef __APPLE__ #define DEFAULT_BLENDER_BIN "/Applications/Blender.app/Contents/MacOS/blender" #else -#define DEFAULT_BLENDER_BIN "blender-2.8" +#define DEFAULT_BLENDER_BIN "blender" #endif extern "C" uint8_t HECL_BLENDERSHELL[]; @@ -219,6 +221,17 @@ size_t Connection::_writeBuf(const void* buf, size_t len) { return writeLen; } +ProjectPath Connection::_readPath() { + std::string path = _readStdString(); + if (!path.empty()) { + SystemStringConv pathAbs(path); + SystemString meshPathRel = + getBlendPath().getProject().getProjectRootPath().getProjectRelativeFromAbsolute(pathAbs.sys_str()); + return ProjectPath(getBlendPath().getProject().getProjectWorkingPath(), meshPathRel); + } + return {}; +} + void Connection::_closePipe() { close(m_readpipe[0]); close(m_writepipe[1]); @@ -488,13 +501,12 @@ Connection::Connection(int verbosityLevel) { hecl::Unlink(m_errPath.c_str()); /* Handle first response */ - char lineBuf[256]; - _readStr(lineBuf, sizeof(lineBuf)); + std::string lineStr = _readStdString(); - if (!strncmp(lineBuf, "NOLAUNCH", 8)) { + if (!lineStr.compare(0, 8, "NOLAUNCH")) { _closePipe(); - BlenderLog.report(logvisor::Fatal, fmt("Unable to launch blender: {}"), lineBuf + 9); - } else if (!strncmp(lineBuf, "NOBLENDER", 9)) { + BlenderLog.report(logvisor::Fatal, fmt("Unable to launch blender: {}"), lineStr.c_str() + 9); + } else if (!lineStr.compare(0, 9, "NOBLENDER")) { _closePipe(); #if _WIN32 BlenderLog.report(logvisor::Fatal, fmt(_SYS_STR("Unable to find blender at '{}'")), blenderBin); @@ -505,10 +517,10 @@ Connection::Connection(int verbosityLevel) { else BlenderLog.report(logvisor::Fatal, fmt(_SYS_STR("Unable to find blender at '{}'")), DEFAULT_BLENDER_BIN); #endif - } else if (!strcmp(lineBuf, "NOT280")) { + } else if (lineStr == "NOT280") { _closePipe(); BlenderLog.report(logvisor::Fatal, fmt(_SYS_STR("Installed blender version must be >= 2.80"))); - } else if (!strcmp(lineBuf, "NOADDON")) { + } else if (lineStr == "NOADDON") { _closePipe(); if (blenderAddonPath != _SYS_STR("SKIPINSTALL")) InstallAddon(blenderAddonPath.c_str()); @@ -516,14 +528,20 @@ Connection::Connection(int verbosityLevel) { if (installAttempt >= 2) BlenderLog.report(logvisor::Fatal, fmt(_SYS_STR("unable to install blender addon using '{}'")), blenderAddonPath.c_str()); +#ifndef _WIN32 + waitpid(pid, nullptr, 0); +#endif continue; - } else if (!strcmp(lineBuf, "ADDONINSTALLED")) { + } else if (lineStr == "ADDONINSTALLED") { _closePipe(); blenderAddonPath = _SYS_STR("SKIPINSTALL"); +#ifndef _WIN32 + waitpid(pid, nullptr, 0); +#endif continue; - } else if (strcmp(lineBuf, "READY")) { + } else if (lineStr != "READY") { _closePipe(); - BlenderLog.report(logvisor::Fatal, fmt("read '{}' from blender; expected 'READY'"), lineBuf); + BlenderLog.report(logvisor::Fatal, fmt("read '{}' from blender; expected 'READY'"), lineStr); } _writeStr("ACK"); @@ -544,28 +562,48 @@ void Index::read(Connection& conn) { conn._readBuf(&val, 4); } void Float::read(Connection& conn) { conn._readBuf(&val, 4); } void Boolean::read(Connection& conn) { conn._readBuf(&val, 1); } -std::streambuf::int_type PyOutStream::StreamBuf::overflow(int_type ch) { - if (!m_parent.m_parent || !m_parent.m_parent->m_lock) - BlenderLog.report(logvisor::Fatal, fmt("lock not held for PyOutStream writing")); - if (ch != traits_type::eof() && ch != '\n' && ch != '\0') { - m_lineBuf += char_type(ch); - return ch; - } - // printf("FLUSHING %s\n", m_lineBuf.c_str()); - m_parent.m_parent->_writeStr(m_lineBuf); - char readBuf[16]; - m_parent.m_parent->_readStr(readBuf, 16); - if (strcmp(readBuf, "OK")) { +bool PyOutStream::StreamBuf::sendLine(std::string_view line) { + m_parent.m_parent->_writeStr(line); + if (!m_parent.m_parent->_isOk()) { if (m_deleteOnError) m_parent.m_parent->deleteBlend(); m_parent.m_parent->_blenderDied(); + return false; } - m_lineBuf.clear(); - return ch; + return true; } -constexpr std::array BlendTypeStrs{ - "NONE", "MESH", "CMESH", "ACTOR", "AREA", "WORLD", "MAPAREA", "MAPUNIVERSE", "FRAME", "PATH", nullptr, +std::streamsize PyOutStream::StreamBuf::xsputn(const char_type* __first, std::streamsize __n) { + if (!m_parent.m_parent || !m_parent.m_parent->m_lock) + BlenderLog.report(logvisor::Fatal, fmt("lock not held for PyOutStream writing")); + const char_type* __last = __first + __n; + const char_type* __s = __first; + for (const char_type* __e = __first; __e != __last; ++__e) { + if (*__e == '\n' || *__e == traits_type::eof()) { + std::string_view line(__s, __e - __s); + bool result; + if (!m_lineBuf.empty()) { + /* Complete line with incomplete line from previous call */ + m_lineBuf += line; + result = sendLine(m_lineBuf); + m_lineBuf.clear(); + } else { + /* Complete line (optimal case) */ + result = sendLine(line); + } + if (!result || *__e == traits_type::eof()) + return __e - __first; /* Error or eof, end now */ + __s += line.size() + 1; + } + } + if (__s != __last) /* String ended with incomplete line (ideally this shouldn't happen for zero buffer overhead) */ + m_lineBuf += std::string_view(__s, __last - __s); + return __n; +} + +constexpr std::array BlendTypeStrs{ + "NONE"sv, "MESH"sv, "CMESH"sv, "ARMATURE"sv, "ACTOR"sv, "AREA"sv, + "WORLD"sv, "MAPAREA"sv, "MAPUNIVERSE"sv, "FRAME"sv, "PATH"sv }; bool Connection::createBlend(const ProjectPath& path, BlendType type) { @@ -574,9 +612,7 @@ bool Connection::createBlend(const ProjectPath& path, BlendType type) { return false; } _writeStr(fmt::format(fmt("CREATE \"{}\" {}"), path.getAbsolutePathUTF8(), BlendTypeStrs[int(type)])); - char lineBuf[256]; - _readStr(lineBuf, sizeof(lineBuf)); - if (!strcmp(lineBuf, "FINISHED")) { + if (_isFinished()) { /* Delete immediately in case save doesn't occur */ hecl::Unlink(path.getAbsolutePath().data()); m_loadedBlend = path; @@ -594,16 +630,14 @@ bool Connection::openBlend(const ProjectPath& path, bool force) { if (!force && path == m_loadedBlend) return true; _writeStr(fmt::format(fmt("OPEN \"{}\""), path.getAbsolutePathUTF8())); - char lineBuf[256]; - _readStr(lineBuf, sizeof(lineBuf)); - if (!strcmp(lineBuf, "FINISHED")) { + if (_isFinished()) { m_loadedBlend = path; _writeStr("GETTYPE"); - _readStr(lineBuf, sizeof(lineBuf)); + std::string typeStr = _readStdString(); m_loadedType = BlendType::None; unsigned idx = 0; - while (BlendTypeStrs[idx]) { - if (!strcmp(BlendTypeStrs[idx], lineBuf)) { + for (const auto& type : BlendTypeStrs) { + if (type == typeStr) { m_loadedType = BlendType(idx); break; } @@ -612,8 +646,7 @@ bool Connection::openBlend(const ProjectPath& path, bool force) { m_loadedRigged = false; if (m_loadedType == BlendType::Mesh) { _writeStr("GETMESHRIGGED"); - _readStr(lineBuf, sizeof(lineBuf)); - if (!strcmp("TRUE", lineBuf)) + if (_isTrue()) m_loadedRigged = true; } return true; @@ -627,11 +660,7 @@ bool Connection::saveBlend() { return false; } _writeStr("SAVE"); - char lineBuf[256]; - _readStr(lineBuf, sizeof(lineBuf)); - if (!strcmp(lineBuf, "FINISHED")) - return true; - return false; + return _isFinished(); } void Connection::deleteBlend() { @@ -646,25 +675,19 @@ PyOutStream::PyOutStream(Connection* parent, bool deleteOnError) : std::ostream(&m_sbuf), m_parent(parent), m_sbuf(*this, deleteOnError) { m_parent->m_pyStreamActive = true; m_parent->_writeStr("PYBEGIN"); - char readBuf[16]; - m_parent->_readStr(readBuf, 16); - if (strcmp(readBuf, "READY")) - BlenderLog.report(logvisor::Fatal, fmt("unable to open PyOutStream with blender")); + m_parent->_checkReady("unable to open PyOutStream with blender"sv); } void PyOutStream::close() { if (m_parent && m_parent->m_lock) { m_parent->_writeStr("PYEND"); - char readBuf[16]; - m_parent->_readStr(readBuf, 16); - if (strcmp(readBuf, "DONE")) - BlenderLog.report(logvisor::Fatal, fmt("unable to close PyOutStream with blender")); + m_parent->_checkDone("unable to close PyOutStream with blender"sv); m_parent->m_pyStreamActive = false; m_parent->m_lock = false; } } -void PyOutStream::linkBlend(const char* target, const char* objName, bool link) { +void PyOutStream::linkBlend(std::string_view target, std::string_view objName, bool link) { format(fmt("if '{}' not in bpy.data.scenes:\n" " with bpy.data.libraries.load('''{}''', link={}, relative=True) as (data_from, data_to):\n" " data_to.scenes = data_from.scenes\n" @@ -685,8 +708,34 @@ void PyOutStream::linkBlend(const char* target, const char* objName, bool link) objName, target, link ? "True" : "False", objName, objName, target, objName); } -void PyOutStream::linkBackground(const char* target, const char* sceneName) { - if (!sceneName) { +void PyOutStream::linkArmature(std::string_view target, std::string_view armName) { + format(fmt("target_arm_name = '{}'\n" + "if target_arm_name not in bpy.data.armatures:\n" + " with bpy.data.libraries.load('''{}''', link=True, relative=True) as (data_from, data_to):\n" + " if target_arm_name not in data_from.armatures:\n" + " raise RuntimeError('''unable to find {} in {}. try deleting it and restart the extract.''')\n" + " data_to.armatures.append(target_arm_name)\n" + " obj = bpy.data.objects.new(target_arm_name, bpy.data.armatures[target_arm_name])\n" + "else:\n" + " obj = bpy.data.objects[target_arm_name]\n" + "\n"), + armName, target, armName, target); +} + +void PyOutStream::linkMesh(std::string_view target, std::string_view meshName) { + format(fmt("target_mesh_name = '{}'\n" + "if target_mesh_name not in bpy.data.objects:\n" + " with bpy.data.libraries.load('''{}''', link=True, relative=True) as (data_from, data_to):\n" + " if target_mesh_name not in data_from.objects:\n" + " raise RuntimeError('''unable to find {} in {}. try deleting it and restart the extract.''')\n" + " data_to.objects.append(target_mesh_name)\n" + "obj = bpy.data.objects[target_mesh_name]\n" + "\n"), + meshName, target, meshName, target); +} + +void PyOutStream::linkBackground(std::string_view target, std::string_view sceneName) { + if (sceneName.empty()) { format(fmt("with bpy.data.libraries.load('''{}''', link=True, relative=True) as (data_from, data_to):\n" " data_to.scenes = data_from.scenes\n" "obj_scene = None\n" @@ -770,19 +819,13 @@ void PyOutStream::centerView() { ANIMOutStream::ANIMOutStream(Connection* parent) : m_parent(parent) { m_parent->_writeStr("PYANIM"); - char readBuf[16]; - m_parent->_readStr(readBuf, 16); - if (strcmp(readBuf, "ANIMREADY")) - BlenderLog.report(logvisor::Fatal, fmt("unable to open ANIMOutStream")); + m_parent->_checkAnimReady("unable to open ANIMOutStream"sv); } ANIMOutStream::~ANIMOutStream() { char tp = -1; m_parent->_writeBuf(&tp, 1); - char readBuf[16]; - m_parent->_readStr(readBuf, 16); - if (strcmp(readBuf, "ANIMDONE")) - BlenderLog.report(logvisor::Fatal, fmt("unable to close ANIMOutStream")); + m_parent->_checkAnimDone("unable to close ANIMOutStream"sv); } void ANIMOutStream::changeCurve(CurveType type, unsigned crvIdx, unsigned keyCount) { @@ -815,8 +858,8 @@ void ANIMOutStream::write(unsigned frame, float val) { } Mesh::SkinBind::SkinBind(Connection& conn) { - vg_idx = Index(conn).val; - weight = Float(conn).val; + conn._readValue(vg_idx); + conn._readValue(weight); } void Mesh::normalizeSkinBinds() { @@ -835,44 +878,26 @@ void Mesh::normalizeSkinBinds() { Mesh::Mesh(Connection& conn, HMDLTopology topologyIn, int skinSlotCount, bool useLuvs) : topology(topologyIn), sceneXf(conn), aabbMin(conn), aabbMax(conn) { - Index matSetCount(conn); - materialSets.reserve(matSetCount.val); - for (uint32_t i = 0; i < matSetCount.val; ++i) { - std::vector& materials = materialSets.emplace_back(); - Index matCount(conn); - materials.reserve(matCount.val); - for (uint32_t j = 0; j < matCount.val; ++j) - materials.emplace_back(conn); - } + conn._readVectorFunc(materialSets, [&]() { + conn._readVector(materialSets.emplace_back()); + }); MeshOptimizer opt(conn, materialSets[0], useLuvs); opt.optimize(*this, skinSlotCount); - Index count(conn); - boneNames.reserve(count.val); - for (uint32_t i = 0; i < count; ++i) { - char name[128]; - conn._readStr(name, 128); - boneNames.emplace_back(name); - } - + conn._readVector(boneNames); if (boneNames.size()) for (Surface& s : surfaces) s.skinBankIdx = skinBanks.addSurface(*this, s, skinSlotCount); /* Custom properties */ - Index propCount(conn); + uint32_t propCount; + conn._readValue(propCount); std::string keyBuf; std::string valBuf; - for (uint32_t i = 0; i < propCount.val; ++i) { - Index kLen(conn); - keyBuf.assign(kLen.val, '\0'); - conn._readBuf(&keyBuf[0], kLen.val); - - Index vLen(conn); - valBuf.assign(vLen.val, '\0'); - conn._readBuf(&valBuf[0], vLen.val); - + for (uint32_t i = 0; i < propCount; ++i) { + keyBuf = conn._readStdString(); + valBuf = conn._readStdString(); customProps[keyBuf] = valBuf; } @@ -936,68 +961,48 @@ static T SwapFourCC(T fcc) { } Material::PASS::PASS(Connection& conn) { - conn._readBuf(&type, 4); + conn._readValue(type); type = SwapFourCC(type); + tex = conn._readPath(); - uint32_t bufSz; - conn._readBuf(&bufSz, 4); - std::string readStr(bufSz, ' '); - conn._readBuf(&readStr[0], bufSz); - SystemStringConv absolute(readStr); - - SystemString relative = - conn.getBlendPath().getProject().getProjectRootPath().getProjectRelativeFromAbsolute(absolute.sys_str()); - tex.assign(conn.getBlendPath().getProject().getProjectWorkingPath(), relative); - - conn._readBuf(&source, 1); - conn._readBuf(&uvAnimType, 1); + conn._readValue(source); + conn._readValue(uvAnimType); uint32_t argCount; - conn._readBuf(&argCount, 4); + conn._readValue(argCount); for (uint32_t i = 0; i < argCount; ++i) - conn._readBuf(&uvAnimParms[i], 4); - conn._readBuf(&alpha, 1); + conn._readValue(uvAnimParms[i]); + conn._readValue(alpha); } Material::CLR::CLR(Connection& conn) { - conn._readBuf(&type, 4); + conn._readValue(type); type = SwapFourCC(type); color.read(conn); } Material::Material(Connection& conn) { - uint32_t bufSz; - conn._readBuf(&bufSz, 4); - name.assign(bufSz, ' '); - conn._readBuf(&name[0], bufSz); + name = conn._readStdString(); - conn._readBuf(&passIndex, 4); - conn._readBuf(&shaderType, 4); + conn._readValue(passIndex); + conn._readValue(shaderType); shaderType = SwapFourCC(shaderType); - uint32_t chunkCount; - conn._readBuf(&chunkCount, 4); - chunks.reserve(chunkCount); - for (uint32_t i = 0; i < chunkCount; ++i) { + conn._readVectorFunc(chunks, [&]() { ChunkType type; - conn._readBuf(&type, 4); + conn._readValue(type); type = SwapFourCC(type); chunks.push_back(Chunk::Build(type, conn)); - } + }); uint32_t iPropCount; - conn._readBuf(&iPropCount, 4); + conn._readValue(iPropCount); iprops.reserve(iPropCount); for (uint32_t i = 0; i < iPropCount; ++i) { - conn._readBuf(&bufSz, 4); - std::string readStr(bufSz, ' '); - conn._readBuf(&readStr[0], bufSz); - - int32_t val; - conn._readBuf(&val, 4); - iprops[readStr] = val; + std::string readStr = conn._readStdString(); + conn._readValue(iprops[readStr]); } - conn._readBuf(&blendMode, 4); + conn._readValue(blendMode); } bool Mesh::Surface::Vert::operator==(const Vert& other) const { @@ -1076,36 +1081,14 @@ uint32_t Mesh::SkinBanks::addSurface(const Mesh& mesh, const Surface& surf, int } ColMesh::ColMesh(Connection& conn) { - uint32_t matCount; - conn._readBuf(&matCount, 4); - materials.reserve(matCount); - for (uint32_t i = 0; i < matCount; ++i) - materials.emplace_back(conn); - - uint32_t count; - conn._readBuf(&count, 4); - verts.reserve(count); - for (uint32_t i = 0; i < count; ++i) - verts.emplace_back(conn); - - conn._readBuf(&count, 4); - edges.reserve(count); - for (uint32_t i = 0; i < count; ++i) - edges.emplace_back(conn); - - conn._readBuf(&count, 4); - trianges.reserve(count); - for (uint32_t i = 0; i < count; ++i) - trianges.emplace_back(conn); + conn._readVector(materials); + conn._readVector(verts); + conn._readVector(edges); + conn._readVector(trianges); } ColMesh::Material::Material(Connection& conn) { - uint32_t nameLen; - conn._readBuf(&nameLen, 4); - if (nameLen) { - name.assign(nameLen, '\0'); - conn._readBuf(&name[0], nameLen); - } + name = conn._readStdString(); conn._readBuf(&unknown, 42); } @@ -1123,57 +1106,29 @@ World::Area::Dock::Dock(Connection& conn) { } World::Area::Area(Connection& conn) { - std::string name; - uint32_t nameLen; - conn._readBuf(&nameLen, 4); - if (nameLen) { - name.assign(nameLen, '\0'); - conn._readBuf(&name[0], nameLen); - } + std::string name = conn._readStdString(); path.assign(conn.getBlendPath().getParentPath(), name); aabb[0].read(conn); aabb[1].read(conn); transform.read(conn); - - uint32_t dockCount; - conn._readBuf(&dockCount, 4); - docks.reserve(dockCount); - for (uint32_t i = 0; i < dockCount; ++i) - docks.emplace_back(conn); + conn._readVector(docks); } World::World(Connection& conn) { - uint32_t areaCount; - conn._readBuf(&areaCount, 4); - areas.reserve(areaCount); - for (uint32_t i = 0; i < areaCount; ++i) - areas.emplace_back(conn); + conn._readVector(areas); } Light::Light(Connection& conn) : sceneXf(conn), color(conn) { conn._readBuf(&layer, 29); - - uint32_t nameLen; - conn._readBuf(&nameLen, 4); - if (nameLen) { - name.assign(nameLen, '\0'); - conn._readBuf(&name[0], nameLen); - } + name = conn._readStdString(); } MapArea::Surface::Surface(Connection& conn) { centerOfMass.read(conn); normal.read(conn); conn._readBuf(&start, 8); - - uint32_t borderCount; - conn._readBuf(&borderCount, 4); - borders.reserve(borderCount); - for (uint32_t i = 0; i < borderCount; ++i) { - std::pair& idx = borders.emplace_back(); - conn._readBuf(&idx, 8); - } + conn._readVectorFunc(borders, [&]() { conn._readBuf(&borders.emplace_back(), 8); }); } MapArea::POI::POI(Connection& conn) { @@ -1182,121 +1137,51 @@ MapArea::POI::POI(Connection& conn) { } MapArea::MapArea(Connection& conn) { - visType.read(conn); - - uint32_t vertCount; - conn._readBuf(&vertCount, 4); - verts.reserve(vertCount); - for (uint32_t i = 0; i < vertCount; ++i) - verts.emplace_back(conn); + conn._readValue(visType); + conn._readVector(verts); uint8_t isIdx; - conn._readBuf(&isIdx, 1); + conn._readValue(isIdx); while (isIdx) { - indices.emplace_back(conn); - conn._readBuf(&isIdx, 1); + conn._readValue(indices.emplace_back()); + conn._readValue(isIdx); } - uint32_t surfCount; - conn._readBuf(&surfCount, 4); - surfaces.reserve(surfCount); - for (uint32_t i = 0; i < surfCount; ++i) - surfaces.emplace_back(conn); - - uint32_t poiCount; - conn._readBuf(&poiCount, 4); - pois.reserve(poiCount); - for (uint32_t i = 0; i < poiCount; ++i) - pois.emplace_back(conn); + conn._readVector(surfaces); + conn._readVector(pois); } MapUniverse::World::World(Connection& conn) { - uint32_t nameLen; - conn._readBuf(&nameLen, 4); - if (nameLen) { - name.assign(nameLen, '\0'); - conn._readBuf(&name[0], nameLen); - } - + name = conn._readStdString(); xf.read(conn); - - uint32_t hexCount; - conn._readBuf(&hexCount, 4); - hexagons.reserve(hexCount); - for (uint32_t i = 0; i < hexCount; ++i) - hexagons.emplace_back(conn); - + conn._readVector(hexagons); color.read(conn); - - uint32_t pathLen; - conn._readBuf(&pathLen, 4); - if (pathLen) { - std::string path; - path.assign(pathLen, '\0'); - conn._readBuf(&path[0], pathLen); - + std::string path = conn._readStdString(); + if (!path.empty()) { hecl::SystemStringConv sysPath(path); worldPath.assign(conn.getBlendPath().getProject().getProjectWorkingPath(), sysPath.sys_str()); } } MapUniverse::MapUniverse(Connection& conn) { - uint32_t pathLen; - conn._readBuf(&pathLen, 4); - if (pathLen) { - std::string path; - path.assign(pathLen, '\0'); - conn._readBuf(&path[0], pathLen); - - hecl::SystemStringConv sysPath(path); - SystemString pathRel = - conn.getBlendPath().getProject().getProjectRootPath().getProjectRelativeFromAbsolute(sysPath.sys_str()); - hexagonPath.assign(conn.getBlendPath().getProject().getProjectWorkingPath(), pathRel); - } - - uint32_t worldCount; - conn._readBuf(&worldCount, 4); - worlds.reserve(worldCount); - for (uint32_t i = 0; i < worldCount; ++i) - worlds.emplace_back(conn); + hexagonPath = conn._readPath(); + conn._readVector(worlds); } Actor::Actor(Connection& conn) { - uint32_t armCount; - conn._readBuf(&armCount, 4); - armatures.reserve(armCount); - for (uint32_t i = 0; i < armCount; ++i) - armatures.emplace_back(conn); - - uint32_t subtypeCount; - conn._readBuf(&subtypeCount, 4); - subtypes.reserve(subtypeCount); - for (uint32_t i = 0; i < subtypeCount; ++i) - subtypes.emplace_back(conn); - - uint32_t attachmentCount; - conn._readBuf(&attachmentCount, 4); - attachments.reserve(attachmentCount); - for (uint32_t i = 0; i < attachmentCount; ++i) - attachments.emplace_back(conn); - - uint32_t actionCount; - conn._readBuf(&actionCount, 4); - actions.reserve(actionCount); - for (uint32_t i = 0; i < actionCount; ++i) - actions.emplace_back(conn); + conn._readVector(armatures); + conn._readVector(subtypes); + conn._readVector(attachments); + conn._readVector(actions); } PathMesh::PathMesh(Connection& conn) { - uint32_t dataSize; - conn._readBuf(&dataSize, 4); - data.resize(dataSize); - conn._readBuf(data.data(), dataSize); + conn._readVector(data); } const Bone* Armature::lookupBone(const char* name) const { for (const Bone& b : bones) - if (!b.name.compare(name)) + if (b.name == name) return &b; return nullptr; } @@ -1324,149 +1209,62 @@ const Bone* Armature::getRoot() const { } Armature::Armature(Connection& conn) { - uint32_t bufSz; - conn._readBuf(&bufSz, 4); - name.assign(bufSz, ' '); - conn._readBuf(&name[0], bufSz); - - uint32_t boneCount; - conn._readBuf(&boneCount, 4); - bones.reserve(boneCount); - for (uint32_t i = 0; i < boneCount; ++i) - bones.emplace_back(conn); + conn._readVector(bones); } Bone::Bone(Connection& conn) { - uint32_t bufSz; - conn._readBuf(&bufSz, 4); - name.assign(bufSz, ' '); - conn._readBuf(&name[0], bufSz); - + name = conn._readStdString(); origin.read(conn); + conn._readValue(parent); + conn._readVector(children); +} - conn._readBuf(&parent, 4); +Actor::ActorArmature::ActorArmature(Connection& conn) { + name = conn._readStdString(); + path = conn._readPath(); + armature.emplace(conn); +} - uint32_t childCount; - conn._readBuf(&childCount, 4); - children.reserve(childCount); - for (uint32_t i = 0; i < childCount; ++i) { - children.emplace_back(0); - conn._readBuf(&children.back(), 4); - } +Actor::Subtype::OverlayMesh::OverlayMesh(Connection& conn) { + name = conn._readStdString(); + cskrId = conn._readStdString(); + mesh = conn._readPath(); } Actor::Subtype::Subtype(Connection& conn) { - uint32_t bufSz; - conn._readBuf(&bufSz, 4); - name.assign(bufSz, ' '); - conn._readBuf(&name[0], bufSz); - - conn._readBuf(&bufSz, 4); - if (bufSz != 0) { - std::string meshPath(bufSz, ' '); - conn._readBuf(meshPath.data(), meshPath.size()); - const SystemStringConv meshPathAbs(meshPath); - - const SystemString meshPathRel = - conn.getBlendPath().getProject().getProjectRootPath().getProjectRelativeFromAbsolute(meshPathAbs.sys_str()); - mesh.assign(conn.getBlendPath().getProject().getProjectWorkingPath(), meshPathRel); - } - - conn._readBuf(&armature, 4); - - uint32_t overlayCount; - conn._readBuf(&overlayCount, 4); - overlayMeshes.reserve(overlayCount); - for (uint32_t i = 0; i < overlayCount; ++i) { - std::string overlayName; - conn._readBuf(&bufSz, 4); - overlayName.assign(bufSz, ' '); - conn._readBuf(&overlayName[0], bufSz); - - conn._readBuf(&bufSz, 4); - if (bufSz != 0) { - std::string meshPath(bufSz, ' '); - conn._readBuf(meshPath.data(), meshPath.size()); - const SystemStringConv meshPathAbs(meshPath); - - const SystemString meshPathRel = - conn.getBlendPath().getProject().getProjectRootPath().getProjectRelativeFromAbsolute(meshPathAbs.sys_str()); - overlayMeshes.emplace_back(std::move(overlayName), - ProjectPath(conn.getBlendPath().getProject().getProjectWorkingPath(), meshPathRel)); - } - } + name = conn._readStdString(); + cskrId = conn._readStdString(); + mesh = conn._readPath(); + conn._readValue(armature); + conn._readVector(overlayMeshes); } Actor::Attachment::Attachment(Connection& conn) { - uint32_t bufSz; - conn._readBuf(&bufSz, 4); - name.assign(bufSz, ' '); - conn._readBuf(&name[0], bufSz); - - std::string meshPath; - conn._readBuf(&bufSz, 4); - if (bufSz) { - meshPath.assign(bufSz, ' '); - conn._readBuf(&meshPath[0], bufSz); - SystemStringConv meshPathAbs(meshPath); - - SystemString meshPathRel = - conn.getBlendPath().getProject().getProjectRootPath().getProjectRelativeFromAbsolute(meshPathAbs.sys_str()); - mesh.assign(conn.getBlendPath().getProject().getProjectWorkingPath(), meshPathRel); - } - - conn._readBuf(&armature, 4); + name = conn._readStdString(); + cskrId = conn._readStdString(); + mesh = conn._readPath(); + conn._readValue(armature); } Action::Action(Connection& conn) { - uint32_t bufSz; - conn._readBuf(&bufSz, 4); - name.assign(bufSz, ' '); - conn._readBuf(&name[0], bufSz); - - conn._readBuf(&interval, 4); - conn._readBuf(&additive, 1); - conn._readBuf(&looping, 1); - - uint32_t frameCount; - conn._readBuf(&frameCount, 4); - frames.reserve(frameCount); - for (uint32_t i = 0; i < frameCount; ++i) { - frames.emplace_back(); - conn._readBuf(&frames.back(), 4); - } - - uint32_t chanCount; - conn._readBuf(&chanCount, 4); - channels.reserve(chanCount); - for (uint32_t i = 0; i < chanCount; ++i) - channels.emplace_back(conn); - - uint32_t aabbCount; - conn._readBuf(&aabbCount, 4); - subtypeAABBs.reserve(aabbCount); - for (uint32_t i = 0; i < aabbCount; ++i) { - subtypeAABBs.emplace_back(conn, conn); - // printf("AABB %s %d (%f %f %f) (%f %f %f)\n", name.c_str(), i, - // float(subtypeAABBs.back().first.val.simd[0]), float(subtypeAABBs.back().first.val.simd[1]), - // float(subtypeAABBs.back().first.val.simd[2]), float(subtypeAABBs.back().second.val.simd[0]), - // float(subtypeAABBs.back().second.val.simd[1]), float(subtypeAABBs.back().second.val.simd[2])); - } + name = conn._readStdString(); + animId = conn._readStdString(); + conn._readValue(interval); + conn._readValue(additive); + conn._readValue(looping); + conn._readVector(frames); + conn._readVector(channels); + conn._readVectorFunc(subtypeAABBs, [&]() { + auto& p = subtypeAABBs.emplace_back(); + p.first.read(conn); + p.second.read(conn); + }); } Action::Channel::Channel(Connection& conn) { - uint32_t bufSz; - conn._readBuf(&bufSz, 4); - boneName.assign(bufSz, ' '); - conn._readBuf(&boneName[0], bufSz); - - conn._readBuf(&attrMask, 4); - - uint32_t keyCount; - conn._readBuf(&keyCount, 4); - keys.reserve(keyCount); - for (uint32_t i = 0; i < keyCount; ++i) - keys.emplace_back(conn, attrMask); + boneName = conn._readStdString(); + conn._readValue(attrMask); + conn._readVector(keys, attrMask); } Action::Channel::Key::Key(Connection& conn, uint32_t attrMask) { @@ -1483,19 +1281,13 @@ Action::Channel::Key::Key(Connection& conn, uint32_t attrMask) { DataStream::DataStream(Connection* parent) : m_parent(parent) { m_parent->m_dataStreamActive = true; m_parent->_writeStr("DATABEGIN"); - char readBuf[16]; - m_parent->_readStr(readBuf, 16); - if (strcmp(readBuf, "READY")) - BlenderLog.report(logvisor::Fatal, fmt("unable to open DataStream with blender")); + m_parent->_checkReady("unable to open DataStream with blender"sv); } void DataStream::close() { if (m_parent && m_parent->m_lock) { m_parent->_writeStr("DATAEND"); - char readBuf[16]; - m_parent->_readStr(readBuf, 16); - if (strcmp(readBuf, "DONE")) - BlenderLog.report(logvisor::Fatal, fmt("unable to close DataStream with blender")); + m_parent->_checkDone("unable to close DataStream with blender"sv); m_parent->m_dataStreamActive = false; m_parent->m_lock = false; } @@ -1503,29 +1295,15 @@ void DataStream::close() { std::vector DataStream::getMeshList() { m_parent->_writeStr("MESHLIST"); - uint32_t count; - m_parent->_readBuf(&count, 4); std::vector retval; - retval.reserve(count); - for (uint32_t i = 0; i < count; ++i) { - char name[128]; - m_parent->_readStr(name, 128); - retval.push_back(name); - } + m_parent->_readVector(retval); return retval; } std::vector DataStream::getLightList() { m_parent->_writeStr("LIGHTLIST"); - uint32_t count; - m_parent->_readBuf(&count, 4); std::vector retval; - retval.reserve(count); - for (uint32_t i = 0; i < count; ++i) { - char name[128]; - m_parent->_readStr(name, 128); - retval.push_back(name); - } + m_parent->_readVector(retval); return retval; } @@ -1535,10 +1313,7 @@ std::pair DataStream::getMeshAABB() { m_parent->m_loadedBlend.getAbsolutePath()); m_parent->_writeStr("MESHAABB"); - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable get AABB: {}"), readBuf); + m_parent->_checkOk("unable get AABB"sv); Vector3f minPt(*m_parent); Vector3f maxPt(*m_parent); @@ -1556,11 +1331,7 @@ Mesh DataStream::compileMesh(HMDLTopology topology, int skinSlotCount) { m_parent->getBlendPath().getAbsolutePath()); m_parent->_writeStr("MESHCOMPILE"); - - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable to cook mesh: {}"), readBuf); + m_parent->_checkOk("unable to cook mesh"sv); return Mesh(*m_parent, topology, skinSlotCount); } @@ -1571,11 +1342,7 @@ Mesh DataStream::compileMesh(std::string_view name, HMDLTopology topology, int s m_parent->getBlendPath().getAbsolutePath()); m_parent->_writeStr(fmt::format(fmt("MESHCOMPILENAME {} {}"), name, int(useLuv))); - - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable to cook mesh '{}': {}"), name, readBuf); + m_parent->_checkOk("unable to cook mesh"sv); return Mesh(*m_parent, topology, skinSlotCount, useLuv); } @@ -1586,11 +1353,7 @@ ColMesh DataStream::compileColMesh(std::string_view name) { m_parent->getBlendPath().getAbsolutePath()); m_parent->_writeStr(fmt::format(fmt("MESHCOMPILENAMECOLLISION {}"), name)); - - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable to cook collision mesh '{}': {}"), name, readBuf); + m_parent->_checkOk("unable to cook collision mesh"sv); return ColMesh(*m_parent); } @@ -1601,21 +1364,10 @@ std::vector DataStream::compileColMeshes() { m_parent->getBlendPath().getAbsolutePath()); m_parent->_writeStr("MESHCOMPILECOLLISIONALL"); - - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable to cook collision meshes: {}"), readBuf); - - uint32_t meshCount; - m_parent->_readBuf(&meshCount, 4); + m_parent->_checkOk("unable to cook collision meshes"sv); std::vector ret; - ret.reserve(meshCount); - - for (uint32_t i = 0; i < meshCount; ++i) - ret.emplace_back(*m_parent); - + m_parent->_readVector(ret); return ret; } @@ -1625,21 +1377,10 @@ std::vector DataStream::compileLights() { m_parent->getBlendPath().getAbsolutePath()); m_parent->_writeStr("LIGHTCOMPILEALL"); - - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable to gather all lights: {}"), readBuf); - - uint32_t lightCount; - m_parent->_readBuf(&lightCount, 4); + m_parent->_checkOk("unable to gather all lights"sv); std::vector ret; - ret.reserve(lightCount); - - for (uint32_t i = 0; i < lightCount; ++i) - ret.emplace_back(*m_parent); - + m_parent->_readVector(ret); return ret; } @@ -1649,34 +1390,24 @@ PathMesh DataStream::compilePathMesh() { m_parent->getBlendPath().getAbsolutePath()); m_parent->_writeStr("MESHCOMPILEPATH"); - - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable to path collision mesh: {}"), readBuf); + m_parent->_checkOk("unable to compile path mesh"sv); return PathMesh(*m_parent); } std::vector DataStream::compileGuiFrame(int version) { - std::vector ret; if (m_parent->getBlendType() != BlendType::Frame) BlenderLog.report(logvisor::Fatal, fmt(_SYS_STR("{} is not a FRAME blend")), m_parent->getBlendPath().getAbsolutePath()); m_parent->_writeStr(fmt::format(fmt("FRAMECOMPILE {}"), version)); - - char readBuf[1024]; - m_parent->_readStr(readBuf, 1024); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable to compile frame: {}"), readBuf); + m_parent->_checkOk("unable to compile frame"sv); while (true) { - m_parent->_readStr(readBuf, 1024); - if (!strcmp(readBuf, "FRAMEDONE")) + std::string readStr = m_parent->_readStdString(); + if (readStr == "FRAMEDONE") break; - std::string readStr(readBuf); SystemStringConv absolute(readStr); auto& proj = m_parent->getBlendPath().getProject(); SystemString relative; @@ -1686,39 +1417,22 @@ std::vector DataStream::compileGuiFrame(int version) { relative = proj.getProjectRootPath().getProjectRelativeFromAbsolute(absolute.sys_str()); hecl::ProjectPath path(proj.getProjectWorkingPath(), relative); - m_parent->_writeStr(fmt::format(fmt("{:016X}"), path.hash().val64())); + m_parent->_writeStr(fmt::format(fmt("{:08X}"), path.parsedHash32())); } - uint32_t len; - m_parent->_readBuf(&len, 4); - ret.resize(len); - m_parent->_readBuf(&ret[0], len); + std::vector ret; + m_parent->_readVector(ret); return ret; } std::vector DataStream::getTextures() { m_parent->_writeStr("GETTEXTURES"); + m_parent->_checkOk("unable to get textures"sv); - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable to get textures: {}"), readBuf); - - uint32_t texCount; - m_parent->_readBuf(&texCount, 4); std::vector texs; - texs.reserve(texCount); - for (uint32_t i = 0; i < texCount; ++i) { - uint32_t bufSz; - m_parent->_readBuf(&bufSz, 4); - std::string readStr(bufSz, ' '); - m_parent->_readBuf(&readStr[0], bufSz); - SystemStringConv absolute(readStr); - - SystemString relative = - m_parent->getBlendPath().getProject().getProjectRootPath().getProjectRelativeFromAbsolute(absolute.sys_str()); - texs.emplace_back(m_parent->getBlendPath().getProject().getProjectWorkingPath(), relative); - } + m_parent->_readVectorFunc(texs, [&]() { + texs.push_back(m_parent->_readPath()); + }); return texs; } @@ -1729,11 +1443,7 @@ Actor DataStream::compileActor() { m_parent->getBlendPath().getAbsolutePath()); m_parent->_writeStr("ACTORCOMPILE"); - - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable to compile actor: {}"), readBuf); + m_parent->_checkOk("unable to compile actor"sv); return Actor(*m_parent); } @@ -1744,26 +1454,29 @@ Actor DataStream::compileActorCharacterOnly() { m_parent->getBlendPath().getAbsolutePath()); m_parent->_writeStr("ACTORCOMPILECHARACTERONLY"); - - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable to compile actor: {}"), readBuf); + m_parent->_checkOk("unable to compile actor"sv); return Actor(*m_parent); } +Armature DataStream::compileArmature() { + if (m_parent->getBlendType() != BlendType::Armature) + BlenderLog.report(logvisor::Fatal, fmt(_SYS_STR("{} is not an ARMATURE blend")), + m_parent->getBlendPath().getAbsolutePath()); + + m_parent->_writeStr("ARMATURECOMPILE"); + m_parent->_checkOk("unable to compile armature"sv); + + return Armature(*m_parent); +} + Action DataStream::compileActionChannelsOnly(std::string_view name) { if (m_parent->getBlendType() != BlendType::Actor) BlenderLog.report(logvisor::Fatal, fmt(_SYS_STR("{} is not an ACTOR blend")), m_parent->getBlendPath().getAbsolutePath()); m_parent->_writeStr(fmt::format(fmt("ACTIONCOMPILECHANNELSONLY {}"), name)); - - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable to compile action: {}"), readBuf); + m_parent->_checkOk("unable to compile action"sv); return Action(*m_parent); } @@ -1774,151 +1487,79 @@ World DataStream::compileWorld() { m_parent->getBlendPath().getAbsolutePath()); m_parent->_writeStr("WORLDCOMPILE"); - - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable to compile world: {}"), readBuf); + m_parent->_checkOk("unable to compile world"sv); return World(*m_parent); } -std::vector DataStream::getArmatureNames() { - if (m_parent->getBlendType() != BlendType::Actor) - BlenderLog.report(logvisor::Fatal, fmt(_SYS_STR("{} is not an ACTOR blend")), - m_parent->getBlendPath().getAbsolutePath()); - - m_parent->_writeStr("GETARMATURENAMES"); - - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable to get armatures of actor: {}"), readBuf); - - std::vector ret; - - uint32_t armCount; - m_parent->_readBuf(&armCount, 4); - ret.reserve(armCount); - for (uint32_t i = 0; i < armCount; ++i) { - std::string& name = ret.emplace_back(); - uint32_t bufSz; - m_parent->_readBuf(&bufSz, 4); - name.assign(bufSz, ' '); - m_parent->_readBuf(name.data(), name.size()); - } - - return ret; -} - -std::vector DataStream::getSubtypeNames() { +std::vector> DataStream::getSubtypeNames() { if (m_parent->getBlendType() != BlendType::Actor) BlenderLog.report(logvisor::Fatal, fmt(_SYS_STR("{} is not an ACTOR blend")), m_parent->getBlendPath().getAbsolutePath()); m_parent->_writeStr("GETSUBTYPENAMES"); + m_parent->_checkOk("unable to get subtypes of actor"sv); - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable to get subtypes of actor: {}"), readBuf); - - std::vector ret; - - uint32_t subCount; - m_parent->_readBuf(&subCount, 4); - ret.reserve(subCount); - for (uint32_t i = 0; i < subCount; ++i) { - std::string& name = ret.emplace_back(); - uint32_t bufSz; - m_parent->_readBuf(&bufSz, 4); - name.assign(bufSz, ' '); - m_parent->_readBuf(name.data(), name.size()); - } + std::vector> ret; + m_parent->_readVectorFunc(ret, [&]() { + auto& [name, cskrId] = ret.emplace_back(); + name = m_parent->_readStdString(); + cskrId = m_parent->_readStdString(); + }); return ret; } -std::vector DataStream::getActionNames() { +std::vector> DataStream::getActionNames() { if (m_parent->getBlendType() != BlendType::Actor) BlenderLog.report(logvisor::Fatal, fmt(_SYS_STR("{} is not an ACTOR blend")), m_parent->getBlendPath().getAbsolutePath()); m_parent->_writeStr("GETACTIONNAMES"); + m_parent->_checkOk("unable to get actions of actor"sv); - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable to get actions of actor: {}"), readBuf); - - std::vector ret; - - uint32_t actCount; - m_parent->_readBuf(&actCount, 4); - ret.reserve(actCount); - for (uint32_t i = 0; i < actCount; ++i) { - std::string& name = ret.emplace_back(); - uint32_t bufSz; - m_parent->_readBuf(&bufSz, 4); - name.assign(bufSz, ' '); - m_parent->_readBuf(name.data(), name.size()); - } + std::vector> ret; + m_parent->_readVectorFunc(ret, [&]() { + auto& [name, animId] = ret.emplace_back(); + name = m_parent->_readStdString(); + animId = m_parent->_readStdString(); + }); return ret; } -std::vector DataStream::getSubtypeOverlayNames(std::string_view name) { +std::vector> DataStream::getSubtypeOverlayNames(std::string_view name) { if (m_parent->getBlendType() != BlendType::Actor) BlenderLog.report(logvisor::Fatal, fmt(_SYS_STR("{} is not an ACTOR blend")), m_parent->getBlendPath().getAbsolutePath()); m_parent->_writeStr(fmt::format(fmt("GETSUBTYPEOVERLAYNAMES {}"), name)); + m_parent->_checkOk("unable to get subtype overlays of actor"sv); - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable to get subtype overlays of actor: {}"), readBuf); - - std::vector ret; - - uint32_t subCount; - m_parent->_readBuf(&subCount, 4); - ret.reserve(subCount); - for (uint32_t i = 0; i < subCount; ++i) { - std::string& subtypeName = ret.emplace_back(); - uint32_t bufSz; - m_parent->_readBuf(&bufSz, 4); - subtypeName.assign(bufSz, ' '); - m_parent->_readBuf(subtypeName.data(), subtypeName.size()); - } + std::vector> ret; + m_parent->_readVectorFunc(ret, [&]() { + auto& [subtypeName, cskrId] = ret.emplace_back(); + subtypeName = m_parent->_readStdString(); + cskrId = m_parent->_readStdString(); + }); return ret; } -std::vector DataStream::getAttachmentNames() { +std::vector> DataStream::getAttachmentNames() { if (m_parent->getBlendType() != BlendType::Actor) BlenderLog.report(logvisor::Fatal, fmt(_SYS_STR("{} is not an ACTOR blend")), m_parent->getBlendPath().getAbsolutePath()); m_parent->_writeStr("GETATTACHMENTNAMES"); + m_parent->_checkOk("unable to get attachments of actor"sv); - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable to get attachments of actor: {}"), readBuf); - - std::vector ret; - - uint32_t attCount; - m_parent->_readBuf(&attCount, 4); - ret.reserve(attCount); - for (uint32_t i = 0; i < attCount; ++i) { - std::string& name = ret.emplace_back(); - uint32_t bufSz; - m_parent->_readBuf(&bufSz, 4); - name.assign(bufSz, ' '); - m_parent->_readBuf(name.data(), name.size()); - } + std::vector> ret; + m_parent->_readVectorFunc(ret, [&]() { + auto& [name, cskrId] = ret.emplace_back(); + name = m_parent->_readStdString(); + cskrId = m_parent->_readStdString(); + }); return ret; } @@ -1932,31 +1573,24 @@ std::unordered_map DataStream::getBoneMatrices(std::strin m_parent->getBlendPath().getAbsolutePath()); m_parent->_writeStr(fmt::format(fmt("GETBONEMATRICES {}"), name)); - - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable to get matrices of armature: {}"), readBuf); + m_parent->_checkOk("unable to get matrices of armature"sv); std::unordered_map ret; uint32_t boneCount; - m_parent->_readBuf(&boneCount, 4); + m_parent->_readValue(boneCount); ret.reserve(boneCount); for (uint32_t i = 0; i < boneCount; ++i) { - uint32_t bufSz; - m_parent->_readBuf(&bufSz, 4); - std::string mat_name(bufSz, ' '); - m_parent->_readBuf(mat_name.data(), bufSz); + std::string mat_name = m_parent->_readStdString(); Matrix3f matOut; for (int mat_i = 0; mat_i < 3; ++mat_i) { for (int mat_j = 0; mat_j < 3; ++mat_j) { float val; - m_parent->_readBuf(&val, 4); + m_parent->_readValue(val); matOut[mat_i].simd[mat_j] = val; } - reinterpret_cast(matOut[mat_i]).simd[3] = 0.f; + matOut[mat_i].simd[3] = 0.f; } ret.emplace(std::move(mat_name), std::move(matOut)); @@ -1975,12 +1609,7 @@ bool DataStream::renderPvs(std::string_view path, const atVec3f& location) { athena::simd_floats f(location.simd); m_parent->_writeStr(fmt::format(fmt("RENDERPVS {} {} {} {}"), path, f[0], f[1], f[2])); - - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable to render PVS for: {}; {}"), - m_parent->getBlendPath().getAbsolutePathUTF8(), readBuf); + m_parent->_checkOk("unable to render PVS"sv); return true; } @@ -1994,12 +1623,7 @@ bool DataStream::renderPvsLight(std::string_view path, std::string_view lightNam m_parent->getBlendPath().getAbsolutePath()); m_parent->_writeStr(fmt::format(fmt("RENDERPVSLIGHT {} {}"), path, lightName)); - - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable to render PVS light {} for: {}; {}"), lightName, - m_parent->getBlendPath().getAbsolutePathUTF8(), readBuf); + m_parent->_checkOk("unable to render PVS light"sv); return true; } @@ -2010,12 +1634,7 @@ MapArea DataStream::compileMapArea() { m_parent->getBlendPath().getAbsolutePath()); m_parent->_writeStr("MAPAREACOMPILE"); - - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable to compile map area: {}; {}"), - m_parent->getBlendPath().getAbsolutePathUTF8(), readBuf); + m_parent->_checkOk("unable to compile map area"sv); return {*m_parent}; } @@ -2026,12 +1645,7 @@ MapUniverse DataStream::compileMapUniverse() { m_parent->getBlendPath().getAbsolutePath()); m_parent->_writeStr("MAPUNIVERSECOMPILE"); - - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, fmt("unable to compile map universe: {}; {}"), - m_parent->getBlendPath().getAbsolutePathUTF8(), readBuf); + m_parent->_checkOk("unable to compile map universe"sv); return {*m_parent}; } @@ -2052,6 +1666,9 @@ void Connection::quitBlender() { } _writeStr("QUIT"); _readStr(lineBuf, sizeof(lineBuf)); +#ifndef _WIN32 + waitpid(m_blenderProc, nullptr, 0); +#endif } Connection& Connection::SharedConnection() { return SharedBlenderToken.getBlenderConnection(); } diff --git a/hecl/lib/Blender/MeshOptimizer.cpp b/hecl/lib/Blender/MeshOptimizer.cpp index f14068735..bbb0ddb45 100644 --- a/hecl/lib/Blender/MeshOptimizer.cpp +++ b/hecl/lib/Blender/MeshOptimizer.cpp @@ -43,10 +43,11 @@ static bool material_is_lightmapped(const Material& mat) { MeshOptimizer::Vertex::Vertex(Connection& conn) { co.read(conn); - Index skin_count(conn); - if (skin_count.val > MaxSkinEntries) - Log.report(logvisor::Fatal, fmt("Skin entry overflow {}/{}"), skin_count.val, MaxSkinEntries); - for (uint32_t i = 0; i < skin_count.val; ++i) + uint32_t skin_count; + conn._readValue(skin_count); + if (skin_count > MaxSkinEntries) + Log.report(logvisor::Fatal, fmt("Skin entry overflow {}/{}"), skin_count, MaxSkinEntries); + for (uint32_t i = 0; i < skin_count; ++i) skin_ents[i] = Mesh::SkinBind(conn); } @@ -56,32 +57,33 @@ MeshOptimizer::Loop::Loop(Connection& conn, uint32_t color_count, uint32_t uv_co colors[i].read(conn); for (uint32_t i = 0; i < uv_count; ++i) uvs[i].read(conn); - vert = Index(conn).val; - edge = Index(conn).val; - face = Index(conn).val; - link_loop_next = Index(conn).val; - link_loop_prev = Index(conn).val; - link_loop_radial_next = Index(conn).val; - link_loop_radial_prev = Index(conn).val; + conn._readValue(vert); + conn._readValue(edge); + conn._readValue(face); + conn._readValue(link_loop_next); + conn._readValue(link_loop_prev); + conn._readValue(link_loop_radial_next); + conn._readValue(link_loop_radial_prev); } MeshOptimizer::Edge::Edge(Connection& conn) { for (uint32_t i = 0; i < 2; ++i) - verts[i] = Index(conn).val; - Index face_count(conn); + conn._readValue(verts[i]); + uint32_t face_count; + conn._readValue(face_count); if (face_count > MaxLinkFaces) - Log.report(logvisor::Fatal, fmt("Face overflow {}/{}"), face_count.val, MaxLinkFaces); - for (uint32_t i = 0; i < face_count.val; ++i) - link_faces[i] = Index(conn).val; - is_contiguous = Boolean(conn).val; + Log.report(logvisor::Fatal, fmt("Face overflow {}/{}"), face_count, MaxLinkFaces); + for (uint32_t i = 0; i < face_count; ++i) + conn._readValue(link_faces[i]); + conn._readValue(is_contiguous); } MeshOptimizer::Face::Face(Connection& conn) { normal.read(conn); centroid.read(conn); - material_index = Index(conn).val; + conn._readValue(material_index); for (uint32_t i = 0; i < 3; ++i) - loops[i] = Index(conn).val; + conn._readValue(loops[i]); } uint32_t MeshOptimizer::get_pos_idx(const Vertex& v) const { @@ -376,36 +378,38 @@ void MeshOptimizer::optimize(Mesh& mesh, int max_skin_banks) const { MeshOptimizer::MeshOptimizer(Connection& conn, const std::vector& materials, bool use_luvs) : materials(materials), use_luvs(use_luvs) { - color_count = Index(conn).val; + conn._readValue(color_count); if (color_count > MaxColorLayers) Log.report(logvisor::Fatal, fmt("Color layer overflow {}/{}"), color_count, MaxColorLayers); - uv_count = Index(conn).val; + conn._readValue(uv_count); if (uv_count > MaxUVLayers) Log.report(logvisor::Fatal, fmt("UV layer overflow {}/{}"), uv_count, MaxUVLayers); /* Simultaneously load topology objects and build unique mapping indices */ - Index vert_count(conn); - verts.reserve(vert_count.val); - b_pos.reserve(vert_count.val); - b_skin.reserve(vert_count.val * 4); - for (uint32_t i = 0; i < vert_count.val; ++i) { + uint32_t vert_count; + conn._readValue(vert_count); + verts.reserve(vert_count); + b_pos.reserve(vert_count); + b_skin.reserve(vert_count * 4); + for (uint32_t i = 0; i < vert_count; ++i) { verts.emplace_back(conn); insert_unique_attr(b_pos, verts.back().co); if (verts.back().skin_ents[0].valid()) insert_unique_attr(b_skin, verts.back().skin_ents); } - Index loop_count(conn); - loops.reserve(loop_count.val); - b_norm.reserve(loop_count.val); + uint32_t loop_count; + conn._readValue(loop_count); + loops.reserve(loop_count); + b_norm.reserve(loop_count); if (use_luvs) { - b_uv.reserve(std::max(int(loop_count.val) - 1, 0) * uv_count); - b_luv.reserve(loop_count.val); + b_uv.reserve(std::max(int(loop_count) - 1, 0) * uv_count); + b_luv.reserve(loop_count); } else { - b_uv.reserve(loop_count.val * uv_count); + b_uv.reserve(loop_count * uv_count); } - for (uint32_t i = 0; i < loop_count.val; ++i) { + for (uint32_t i = 0; i < loop_count; ++i) { loops.emplace_back(conn, color_count, uv_count); insert_unique_attr(b_norm, loops.back().normal); for (const auto& c : loops.back().colors) @@ -420,15 +424,8 @@ MeshOptimizer::MeshOptimizer(Connection& conn, const std::vector& mate } } - Index edge_count(conn); - edges.reserve(edge_count.val); - for (uint32_t i = 0; i < edge_count.val; ++i) - edges.emplace_back(conn); - - Index face_count(conn); - faces.reserve(face_count.val); - for (uint32_t i = 0; i < face_count.val; ++i) - faces.emplace_back(conn); + conn._readVector(edges); + conn._readVector(faces); /* Cache edges that should block tristrip traversal */ for (auto& e : edges) diff --git a/hecl/lib/Blender/SDNARead.cpp b/hecl/lib/Blender/SDNARead.cpp index d75d859d9..2b6f0ddba 100644 --- a/hecl/lib/Blender/SDNARead.cpp +++ b/hecl/lib/Blender/SDNARead.cpp @@ -29,7 +29,7 @@ const SDNABlock::SDNAStruct::SDNAField* SDNABlock::SDNAStruct::lookupField(const if (bracket != std::string::npos) { if (!name.compare(0, bracket, n)) return &field; - } else if (!name.compare(n)) + } else if (name == n) return &field; } return nullptr; @@ -39,7 +39,7 @@ const SDNABlock::SDNAStruct* SDNABlock::lookupStruct(const char* n, atUint32& id idx = 0; for (const SDNAStruct& strc : strcs) { const auto& name = types[strc.type]; - if (!name.compare(n)) + if (name == n) return &strc; ++idx; } diff --git a/hecl/lib/CVar.cpp b/hecl/lib/CVar.cpp index 9d2bfc81c..c0731c15c 100644 --- a/hecl/lib/CVar.cpp +++ b/hecl/lib/CVar.cpp @@ -165,11 +165,11 @@ bool CVar::toBoolean(bool* isValid) const { std::string tmp = m_value; athena::utility::tolower(tmp); - if (!tmp.compare("yes") || !tmp.compare("true") || !tmp.compare("1")) { + if (tmp == "yes" || tmp == "true" || tmp == "1") { if (isValid) *isValid = true; return true; - } else if (!tmp.compare("no") || !tmp.compare("false") || !tmp.compare("0")) { + } else if (tmp == "no" || tmp == "false" || tmp == "0") { if (isValid) *isValid = true; return false; diff --git a/hecl/lib/CVarManager.cpp b/hecl/lib/CVarManager.cpp index 94fc0379f..9f1bbdd2d 100644 --- a/hecl/lib/CVarManager.cpp +++ b/hecl/lib/CVarManager.cpp @@ -181,7 +181,7 @@ void CVarManager::serialize() { filename += _SYS_STR(".yaml"); athena::io::FileReader r(filename); - athena::io::YAMLDocWriter docWriter(nullptr, r.isOpen() ? &r : nullptr); + athena::io::YAMLDocWriter docWriter(r.isOpen() ? &r : nullptr); r.close(); docWriter.setStyle(athena::io::YAMLNodeStyle::Block); diff --git a/hecl/lib/Project.cpp b/hecl/lib/Project.cpp index 57b167399..b6e439156 100644 --- a/hecl/lib/Project.cpp +++ b/hecl/lib/Project.cpp @@ -91,7 +91,7 @@ void Project::ConfigFile::removeLine(std::string_view refLine) { } for (auto it = m_lines.begin(); it != m_lines.end();) { - if (!(*it).compare(refLine)) { + if (*it == refLine) { it = m_lines.erase(it); continue; } @@ -106,7 +106,7 @@ bool Project::ConfigFile::checkForLine(std::string_view refLine) { } for (const std::string& line : m_lines) - if (!line.compare(refLine)) + if (line == refLine) return true; return false; } diff --git a/hecl/lib/ProjectPath.cpp b/hecl/lib/ProjectPath.cpp index 0eca7f826..4e999110b 100644 --- a/hecl/lib/ProjectPath.cpp +++ b/hecl/lib/ProjectPath.cpp @@ -14,9 +14,9 @@ static SystemString CanonRelPath(SystemStringView path) { SanitizePath(in); for (; std::regex_search(in, matches, regPATHCOMP); in = matches.suffix().str()) { hecl::SystemRegexMatch::const_reference match = matches[1]; - if (!match.compare(_SYS_STR("."))) + if (match == _SYS_STR(".")) continue; - else if (!match.compare(_SYS_STR(".."))) { + else if (match == _SYS_STR("..")) { if (comps.empty()) { /* Unable to resolve outside project */ LogModule.report(logvisor::Fatal, fmt(_SYS_STR("Unable to resolve outside project root in {}")), path); @@ -140,6 +140,8 @@ ProjectPath ProjectPath::getCookedPath(const Database::DataSpecEntry& spec) cons } ProjectPath::Type ProjectPath::getPathType() const { + if (m_absPath.empty()) + return Type::None; if (m_absPath.find(_SYS_STR('*')) != SystemString::npos) return Type::Glob; Sstat theStat; @@ -246,6 +248,43 @@ void ProjectPath::getGlobResults(std::vector& outPaths) const { _recursiveGlob(*m_proj, outPaths, m_relPath, rootPath.data(), rootPath.back() != _SYS_STR('/')); } +template +static bool RegexSearchLast(const T& str, std::match_results& m, + const std::basic_regex& reg) { + using Iterator = std::regex_iterator; + Iterator begin = Iterator(str.begin(), str.end(), reg); + Iterator end = Iterator(); + if (begin == end) + return false; + Iterator last_it; + for (auto it = begin; it != end; ++it) + last_it = it; + m = *last_it; + return true; +} + +static const hecl::SystemRegex regParsedHash32(_SYS_STR(R"(_([0-9a-fA-F]{8}))"), + std::regex::ECMAScript | std::regex::optimize); +uint32_t ProjectPath::parsedHash32() const { + { + hecl::SystemRegexMatch match; + if (RegexSearchLast(m_auxInfo, match, regParsedHash32)) { + auto hexStr = match[1].str(); + if (auto val = hecl::StrToUl(hexStr.c_str(), nullptr, 16)) + return val; + } + } + { + hecl::SystemViewRegexMatch match; + if (RegexSearchLast(getLastComponent(), match, regParsedHash32)) { + auto hexStr = match[1].str(); + if (auto val = hecl::StrToUl(hexStr.c_str(), nullptr, 16)) + return val; + } + } + return hash().val32(); +} + ProjectRootPath SearchForProject(SystemStringView path) { ProjectRootPath testRoot(path); auto begin = testRoot.getAbsolutePath().begin(); diff --git a/hecl/lib/hecl.cpp b/hecl/lib/hecl.cpp index 27e491986..4a7927994 100644 --- a/hecl/lib/hecl.cpp +++ b/hecl/lib/hecl.cpp @@ -30,11 +30,13 @@ #include +using namespace std::literals; + namespace hecl { unsigned VerbosityLevel = 0; bool GuiMode = false; logvisor::Module LogModule("hecl"); -constexpr std::string_view Illegals{"<>?\""}; +constexpr std::string_view Illegals = "<>?\""sv; void SanitizePath(std::string& path) { if (path.empty()) @@ -64,7 +66,7 @@ void SanitizePath(std::string& path) { path.pop_back(); } -constexpr std::wstring_view WIllegals{L"<>?\""}; +constexpr std::wstring_view WIllegals = L"<>?\""sv; void SanitizePath(std::wstring& path) { if (path.empty()) @@ -174,9 +176,8 @@ bool IsPathPNG(const hecl::ProjectPath& path) { bool IsPathBlend(const hecl::ProjectPath& path) { const auto lastCompExt = path.getLastComponentExt(); - if (lastCompExt.empty() || hecl::StrCmp(lastCompExt.data(), _SYS_STR("blend"))) { + if (lastCompExt.empty() || lastCompExt != _SYS_STR("blend")) return false; - } const auto fp = hecl::FopenUnique(path.getAbsolutePath().data(), _SYS_STR("rb")); if (fp == nullptr) { @@ -193,14 +194,15 @@ bool IsPathBlend(const hecl::ProjectPath& path) { } bool IsPathYAML(const hecl::ProjectPath& path) { - if (!hecl::StrCmp(path.getLastComponent().data(), _SYS_STR("!catalog.yaml"))) - return false; /* !catalog.yaml is exempt from general use */ + auto lastComp = path.getLastComponent(); + if (lastComp == _SYS_STR("!catalog.yaml") || + lastComp == _SYS_STR("!memoryid.yaml") || + lastComp == _SYS_STR("!memoryrelays.yaml")) + return false; /* !catalog.yaml, !memoryid.yaml, !memoryrelays.yaml are exempt from general use */ auto lastCompExt = path.getLastComponentExt(); if (lastCompExt.empty()) return false; - if (!hecl::StrCmp(lastCompExt.data(), _SYS_STR("yaml")) || !hecl::StrCmp(lastCompExt.data(), _SYS_STR("yml"))) - return true; - return false; + return lastCompExt == _SYS_STR("yaml") || lastCompExt == _SYS_STR("yml"); } hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode, bool sizeSort, bool reverse,