Code style improvements

This commit is contained in:
Jack Andersen 2019-09-30 21:23:35 -10:00
parent 0b30fedef5
commit 8a73a8ee48
26 changed files with 719 additions and 833 deletions

View File

@ -10,6 +10,7 @@ list(APPEND PY_SOURCES
hecl/sact/SACTSubtype.py hecl/sact/SACTSubtype.py
hecl/srea/__init__.py hecl/srea/__init__.py
hecl/swld/__init__.py hecl/swld/__init__.py
hecl/armature.py
hecl/mapa.py hecl/mapa.py
hecl/mapu.py hecl/mapu.py
hecl/frme.py hecl/frme.py

View File

@ -1,11 +1,11 @@
# Node Grid Arranger Class # Node Grid Arranger Class
NODE_PADDING = 80 NODE_PADDING = 80
FRAME_NAMES = ['Textures','Output'] FRAME_NAMES = ['Textures','Output','Blend']
FRAME_WIDTHS = [400, 180] FRAME_WIDTHS = [400, 180, 180]
TOTAL_WIDTH = 0.0 TOTAL_WIDTH = 0.0
for width in FRAME_WIDTHS: for width in FRAME_WIDTHS:
TOTAL_WIDTH += width + NODE_PADDING 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: class Nodegrid:
def __init__(self, nodetree, cycles=False): def __init__(self, nodetree, cycles=False):

View File

@ -9,7 +9,7 @@ bl_info = {
"category": "System"} "category": "System"}
# Package import # 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 Nodegrid = Nodegrid.Nodegrid
parent_armature = sact.SACTSubtype.parent_armature parent_armature = sact.SACTSubtype.parent_armature
import bpy, os, sys, struct, math import bpy, os, sys, struct, math
@ -20,6 +20,7 @@ hecl_typeS = [
('NONE', "None", "Active scene not using HECL", None), ('NONE', "None", "Active scene not using HECL", None),
('MESH', "Mesh", "Active scene represents an HMDL Mesh", hmdl.draw), ('MESH', "Mesh", "Active scene represents an HMDL Mesh", hmdl.draw),
('CMESH', "Collision Mesh", "Active scene represents a Collision Mesh", None), ('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), ('ACTOR', "Actor", "Active scene represents a HECL Actor", sact.draw),
('AREA', "Area", "Active scene represents a HECL Area", srea.draw), ('AREA', "Area", "Active scene represents a HECL Area", srea.draw),
('WORLD', "World", "Active scene represents a HECL World", swld.draw), ('WORLD', "World", "Active scene represents a HECL World", swld.draw),
@ -141,9 +142,10 @@ from bpy.app.handlers import persistent
@persistent @persistent
def scene_loaded(dummy): def scene_loaded(dummy):
# Hide everything from an external library # Hide everything from an external library
for o in bpy.context.scene.objects: if bpy.context.scene.hecl_type != 'FRAME':
if o.library: for o in bpy.context.scene.objects:
o.hide_set(True) if o.library or (o.data and o.data.library):
o.hide_set(True)
# Show PATH library objects as wireframes # Show PATH library objects as wireframes
if bpy.context.scene.hecl_type == 'PATH': if bpy.context.scene.hecl_type == 'PATH':
@ -208,6 +210,7 @@ def register():
mapa.register() mapa.register()
mapu.register() mapu.register()
path.register() path.register()
armature.register()
bpy.utils.register_class(hecl_scene_panel) bpy.utils.register_class(hecl_scene_panel)
bpy.utils.register_class(hecl_light_panel) bpy.utils.register_class(hecl_light_panel)
bpy.types.Scene.hecl_auto_select = bpy.props.BoolProperty(name='HECL Auto Select', default=True) bpy.types.Scene.hecl_auto_select = bpy.props.BoolProperty(name='HECL Auto Select', default=True)

View File

@ -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')

View File

@ -1,6 +1,12 @@
import struct, bpy, bmesh import struct, bpy, bmesh
from . import HMDLShader, HMDLMesh from . import HMDLShader, HMDLMesh
BLEND_TYPES = {
'HECLAdditiveOutput': 2,
'HECLBlendOutput': 1,
'HECLOpaqueOutput': 0,
}
def write_out_material(writebuf, mat, mesh_obj): def write_out_material(writebuf, mat, mesh_obj):
writebuf(struct.pack('I', len(mat.name))) writebuf(struct.pack('I', len(mat.name)))
writebuf(mat.name.encode()) writebuf(mat.name.encode())
@ -20,12 +26,10 @@ def write_out_material(writebuf, mat, mesh_obj):
writebuf(prop[0].encode()) writebuf(prop[0].encode())
writebuf(struct.pack('i', prop[1])) writebuf(struct.pack('i', prop[1]))
blend = 0 blend_node = mat.node_tree.nodes['Blend']
if mat.blend_method == 'BLEND': if blend_node.node_tree.name not in BLEND_TYPES:
blend = 1 raise RuntimeError("HMDL *requires* one of the HMDL*Output group nodes for the 'Blend' node")
elif mat.blend_method == 'ADD': writebuf(struct.pack('I', BLEND_TYPES[blend_node.node_tree.name]))
blend = 2
writebuf(struct.pack('I', blend))
# Takes a Blender 'Mesh' object (not the datablock) # Takes a Blender 'Mesh' object (not the datablock)
# and performs a one-shot conversion process to HMDL # 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] obj = context.scene.objects[context.scene.hecl_mesh_obj]
if obj.type != 'MESH': if obj.type != 'MESH':
layout.label(text="'"+context.scene.hecl_mesh_obj+"' not a 'MESH'", icon='ERROR') 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_active_material')
layout.prop(obj.data, 'hecl_material_count') layout.prop(obj.data, 'hecl_material_count')
@ -297,6 +302,7 @@ def register():
bpy.types.Scene.hecl_actor_obj = bpy.props.StringProperty( bpy.types.Scene.hecl_actor_obj = bpy.props.StringProperty(
name='HECL Actor Object', name='HECL Actor Object',
description='Blender Empty Object to export during HECL\'s cook process') 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_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.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) bpy.utils.register_class(hecl_mesh_operator)

View File

@ -52,6 +52,7 @@ def draw(layout, context):
else: else:
#layout.prop(linked_action, 'hecl_index', text="Index") #layout.prop(linked_action, 'hecl_index', text="Index")
#layout.prop(linked_action, 'hecl_anim_props', text="Props") #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") layout.prop(linked_action, 'hecl_fps', text="Frame Rate")
row = layout.row() row = layout.row()
row.prop(context.scene, 'hecl_auto_remap', text="60-fps Remap") row.prop(context.scene, 'hecl_auto_remap', text="60-fps Remap")

View File

@ -1,4 +1,5 @@
from . import SACTSubtype, SACTAction, ANIM from . import SACTSubtype, SACTAction, ANIM
from .. import armature
import bpy import bpy
import bpy.path import bpy.path
@ -207,21 +208,14 @@ def _out_armatures(sact_data, writebuf):
writebuf(struct.pack('I', len(arm.name))) writebuf(struct.pack('I', len(arm.name)))
writebuf(arm.name.encode()) writebuf(arm.name.encode())
writebuf(struct.pack('I', len(arm.bones))) if arm.library:
for bone in arm.bones: arm_path = bpy.path.abspath(arm.library.filepath)
writebuf(struct.pack('I', len(bone.name))) writebuf(struct.pack('I', len(arm_path)))
writebuf(bone.name.encode()) 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])) armature.cook(writebuf, arm)
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 _out_subtypes(sact_data, writebuf): def _out_subtypes(sact_data, writebuf):
writebuf(struct.pack('I', len(sact_data.subtypes))) writebuf(struct.pack('I', len(sact_data.subtypes)))
@ -232,9 +226,14 @@ def _out_subtypes(sact_data, writebuf):
mesh = None mesh = None
if subtype.linked_mesh in bpy.data.objects: if subtype.linked_mesh in bpy.data.objects:
mesh = bpy.data.objects[subtype.linked_mesh] 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: if mesh and mesh.data.library:
mesh_path = bpy.path.abspath(mesh.library.filepath) mesh_path = bpy.path.abspath(mesh.data.library.filepath)
writebuf(struct.pack('I', len(mesh_path))) writebuf(struct.pack('I', len(mesh_path)))
writebuf(mesh_path.encode()) writebuf(mesh_path.encode())
else: else:
@ -257,9 +256,14 @@ def _out_subtypes(sact_data, writebuf):
mesh = None mesh = None
if overlay.linked_mesh in bpy.data.objects: if overlay.linked_mesh in bpy.data.objects:
mesh = bpy.data.objects[overlay.linked_mesh] 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: if mesh and mesh.data.library:
mesh_path = bpy.path.abspath(mesh.library.filepath) mesh_path = bpy.path.abspath(mesh.data.library.filepath)
writebuf(struct.pack('I', len(mesh_path))) writebuf(struct.pack('I', len(mesh_path)))
writebuf(mesh_path.encode()) writebuf(mesh_path.encode())
else: else:
@ -274,9 +278,14 @@ def _out_attachments(sact_data, writebuf):
mesh = None mesh = None
if attachment.linked_mesh in bpy.data.objects: if attachment.linked_mesh in bpy.data.objects:
mesh = bpy.data.objects[attachment.linked_mesh] 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: if mesh and mesh.data.library:
mesh_path = bpy.path.abspath(mesh.library.filepath) mesh_path = bpy.path.abspath(mesh.data.library.filepath)
writebuf(struct.pack('I', len(mesh_path))) writebuf(struct.pack('I', len(mesh_path)))
writebuf(mesh_path.encode()) writebuf(mesh_path.encode())
else: else:
@ -302,6 +311,9 @@ def _out_actions(sact_data, writebuf):
bact = None bact = None
if action.name in bpy.data.actions: if action.name in bpy.data.actions:
bact = bpy.data.actions[action.name] 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: if not bact:
raise RuntimeError('action %s not found' % action.name) raise RuntimeError('action %s not found' % action.name)
@ -334,6 +346,9 @@ def _out_action_no_subtypes(sact_data, writebuf, action_name):
bact = None bact = None
if action.name in bpy.data.actions: if action.name in bpy.data.actions:
bact = bpy.data.actions[action.name] 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: if not bact:
raise RuntimeError('action %s not found' % action.name) raise RuntimeError('action %s not found' % action.name)
@ -386,14 +401,6 @@ def cook_action_channels_only(writebuf, action_name):
# Output action without AABBs # Output action without AABBs
_out_action_no_subtypes(sact_data, writebuf, action_name) _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 # Access actor's contained subtype names
def get_subtype_names(writebuf): def get_subtype_names(writebuf):
sact_data = bpy.context.scene.hecl_sact_data sact_data = bpy.context.scene.hecl_sact_data
@ -402,6 +409,10 @@ def get_subtype_names(writebuf):
subtype = sact_data.subtypes[sub_idx] subtype = sact_data.subtypes[sub_idx]
writebuf(struct.pack('I', len(subtype.name))) writebuf(struct.pack('I', len(subtype.name)))
writebuf(subtype.name.encode()) 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 # Access subtype's contained overlay names
def get_subtype_overlay_names(writebuf, subtypeName): def get_subtype_overlay_names(writebuf, subtypeName):
@ -413,6 +424,10 @@ def get_subtype_overlay_names(writebuf, subtypeName):
for overlay in subtype.overlays: for overlay in subtype.overlays:
writebuf(struct.pack('I', len(overlay.name))) writebuf(struct.pack('I', len(overlay.name)))
writebuf(overlay.name.encode()) 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 return
writebuf(struct.pack('I', 0)) writebuf(struct.pack('I', 0))
@ -424,6 +439,10 @@ def get_attachment_names(writebuf):
attachment = sact_data.attachments[att_idx] attachment = sact_data.attachments[att_idx]
writebuf(struct.pack('I', len(attachment.name))) writebuf(struct.pack('I', len(attachment.name)))
writebuf(attachment.name.encode()) 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 # Access actor's contained action names
def get_action_names(writebuf): def get_action_names(writebuf):
@ -433,6 +452,9 @@ def get_action_names(writebuf):
action = sact_data.actions[action_idx] action = sact_data.actions[action_idx]
writebuf(struct.pack('I', len(action.name))) writebuf(struct.pack('I', len(action.name)))
writebuf(action.name.encode()) 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 # Panel draw
def draw(layout, context): def draw(layout, context):
@ -452,6 +474,7 @@ def register():
SACTAction.register() SACTAction.register()
bpy.utils.register_class(SACTData) bpy.utils.register_class(SACTData)
bpy.types.Scene.hecl_sact_data = bpy.props.PointerProperty(type=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_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_additive = bpy.props.BoolProperty(name='HECL Additive Action', default=False)
bpy.types.Action.hecl_looping = bpy.props.BoolProperty(name='HECL Looping Action', default=False) bpy.types.Action.hecl_looping = bpy.props.BoolProperty(name='HECL Looping Action', default=False)

View File

@ -55,17 +55,7 @@ class PathHasher:
def hashpath32(self, path): def hashpath32(self, path):
writepipestr(path.encode()) writepipestr(path.encode())
read_str = readpipestr() read_str = readpipestr()
if len(read_str) >= 16: return int(read_str[0:8], 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
# Ensure Blender 2.8 is being used # Ensure Blender 2.8 is being used
if bpy.app.version < (2, 80, 0): if bpy.app.version < (2, 80, 0):
@ -226,21 +216,21 @@ def dataout_loop():
elif cmdargs[0] == 'MESHLIST': elif cmdargs[0] == 'MESHLIST':
meshCount = 0 meshCount = 0
for meshobj in bpy.data.objects: 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 meshCount += 1
writepipebuf(struct.pack('I', meshCount)) writepipebuf(struct.pack('I', meshCount))
for meshobj in bpy.data.objects: 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()) writepipestr(meshobj.name.encode())
elif cmdargs[0] == 'LIGHTLIST': elif cmdargs[0] == 'LIGHTLIST':
lightCount = 0 lightCount = 0
for obj in bpy.context.scene.objects: 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 lightCount += 1
writepipebuf(struct.pack('I', lightCount)) writepipebuf(struct.pack('I', lightCount))
for obj in bpy.context.scene.objects: 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()) writepipestr(obj.name.encode())
elif cmdargs[0] == 'MESHAABB': elif cmdargs[0] == 'MESHAABB':
@ -256,6 +246,15 @@ def dataout_loop():
writepipestr(b'OK') writepipestr(b'OK')
hecl.hmdl.cook(writepipebuf, bpy.data.objects[meshName]) 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': elif cmdargs[0] == 'MESHCOMPILENAME':
meshName = cmdargs[1] meshName = cmdargs[1]
useLuv = int(cmdargs[2]) useLuv = int(cmdargs[2])
@ -281,13 +280,13 @@ def dataout_loop():
writepipestr(b'OK') writepipestr(b'OK')
colCount = 0 colCount = 0
for obj in bpy.context.scene.objects: 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 colCount += 1
writepipebuf(struct.pack('I', colCount)) writepipebuf(struct.pack('I', colCount))
for obj in bpy.context.scene.objects: 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) hecl.hmdl.cookcol(writepipebuf, obj)
elif cmdargs[0] == 'MESHCOMPILEPATH': elif cmdargs[0] == 'MESHCOMPILEPATH':
@ -384,10 +383,6 @@ def dataout_loop():
writepipestr(b'OK') writepipestr(b'OK')
hecl.sact.cook_action_channels_only(writepipebuf, actionName) 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': elif cmdargs[0] == 'GETSUBTYPENAMES':
writepipestr(b'OK') writepipestr(b'OK')
hecl.sact.get_subtype_names(writepipebuf) hecl.sact.get_subtype_names(writepipebuf)

View File

@ -26,7 +26,7 @@ public:
for (const hecl::SystemString& arg : info.args) { for (const hecl::SystemString& arg : info.args) {
if (arg.empty()) if (arg.empty())
continue; continue;
else if (!arg.compare(_SYS_STR("--fast"))) { else if (arg == _SYS_STR("--fast")) {
m_fast = true; m_fast = true;
continue; continue;
} else if (arg.size() >= 8 && !arg.compare(0, 7, _SYS_STR("--spec="))) { } else if (arg.size() >= 8 && !arg.compare(0, 7, _SYS_STR("--spec="))) {

View File

@ -20,15 +20,10 @@ class ToolPackage final : public ToolBase {
} }
void CheckFile(const hecl::ProjectPath& path) { 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); 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) { void FindSelectedItems(const hecl::ProjectPath& path, bool checkGeneral) {
@ -70,7 +65,7 @@ public:
for (const hecl::SystemString& arg : info.args) { for (const hecl::SystemString& arg : info.args) {
if (arg.empty()) if (arg.empty())
continue; continue;
else if (!arg.compare(_SYS_STR("--fast"))) { else if (arg == _SYS_STR("--fast")) {
m_fast = true; m_fast = true;
continue; continue;
} else if (arg.size() >= 8 && !arg.compare(0, 7, _SYS_STR("--spec="))) { } else if (arg.size() >= 8 && !arg.compare(0, 7, _SYS_STR("--spec="))) {

View File

@ -19,9 +19,9 @@ public:
hecl::SystemString firstArg = info.args.front(); hecl::SystemString firstArg = info.args.front();
hecl::ToLower(firstArg); hecl::ToLower(firstArg);
if (!firstArg.compare(_SYS_STR("enable"))) if (firstArg == _SYS_STR("enable"))
mode = MENABLE; mode = MENABLE;
else if (!firstArg.compare(_SYS_STR("disable"))) else if (firstArg == _SYS_STR("disable"))
mode = MDISABLE; mode = MDISABLE;
else else
return; return;
@ -112,7 +112,7 @@ public:
for (auto& spec : specs) { for (auto& spec : specs) {
hecl::SystemString compName(spec.spec.m_name); hecl::SystemString compName(spec.spec.m_name);
hecl::ToLower(compName); hecl::ToLower(compName);
if (!itName.compare(compName)) { if (itName == compName) {
opSpecs.emplace_back(spec.spec.m_name); opSpecs.emplace_back(spec.spec.m_name);
break; break;
} }

2
hecl/extern/athena vendored

@ -1 +1 @@
Subproject commit 132c7def65a78f5915e199de805abb672c291d98 Subproject commit 42581c922a4574f4f34df134a454effa9f9cc8d0

2
hecl/extern/boo vendored

@ -1 +1 @@
Subproject commit 9b8ef4695f3f1d07b29580241fc266abc17dc29c Subproject commit 922fcbb3c23677b3ccc53737fd23ada165ccf9f3

View File

@ -81,7 +81,8 @@ class PyOutStream : public std::ostream {
StreamBuf(PyOutStream& parent, bool deleteOnError) : m_parent(parent), m_deleteOnError(deleteOnError) {} StreamBuf(PyOutStream& parent, bool deleteOnError) : m_parent(parent), m_deleteOnError(deleteOnError) {}
StreamBuf(const StreamBuf& other) = delete; StreamBuf(const StreamBuf& other) = delete;
StreamBuf(StreamBuf&& other) = default; 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; } m_sbuf;
PyOutStream(Connection* parent, bool deleteOnError); PyOutStream(Connection* parent, bool deleteOnError);
@ -94,8 +95,10 @@ public:
void close(); void close();
template <typename S, typename... Args, typename Char = fmt::char_t<S>> template <typename S, typename... Args, typename Char = fmt::char_t<S>>
void format(const S& format, Args&&... args); void format(const S& format, Args&&... args);
void linkBlend(const char* target, const char* objName, bool link = true); void linkBlend(std::string_view target, std::string_view objName, bool link = true);
void linkBackground(const char* target, const char* sceneName = nullptr); 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 AABBToBMesh(const atVec3f& min, const atVec3f& max);
void centerView(); void centerView();
@ -498,15 +501,15 @@ struct Light {
/** Intermediate MapArea representation */ /** Intermediate MapArea representation */
struct MapArea { struct MapArea {
Index visType; uint32_t visType;
std::vector<Vector3f> verts; std::vector<Vector3f> verts;
std::vector<Index> indices; std::vector<uint32_t> indices;
struct Surface { struct Surface {
Vector3f normal; Vector3f normal;
Vector3f centerOfMass; Vector3f centerOfMass;
Index start; uint32_t start;
Index count; uint32_t count;
std::vector<std::pair<Index, Index>> borders; std::vector<std::pair<uint32_t, uint32_t>> borders;
Surface(Connection& conn); Surface(Connection& conn);
}; };
std::vector<Surface> surfaces; std::vector<Surface> surfaces;
@ -547,7 +550,6 @@ struct Bone {
/** Intermediate armature representation used in Actor */ /** Intermediate armature representation used in Actor */
struct Armature { struct Armature {
std::string name;
std::vector<Bone> bones; std::vector<Bone> bones;
const Bone* lookupBone(const char* name) const; const Bone* lookupBone(const char* name) const;
const Bone* getParent(const Bone* bone) const; const Bone* getParent(const Bone* bone) const;
@ -559,6 +561,7 @@ struct Armature {
/** Intermediate action representation used in Actor */ /** Intermediate action representation used in Actor */
struct Action { struct Action {
std::string name; std::string name;
std::string animId;
float interval; float interval;
bool additive; bool additive;
bool looping; bool looping;
@ -582,18 +585,32 @@ struct Action {
/** Intermediate actor representation prepared by blender from a single HECL actor blend */ /** Intermediate actor representation prepared by blender from a single HECL actor blend */
struct Actor { struct Actor {
std::vector<Armature> armatures; struct ActorArmature {
std::string name;
ProjectPath path;
std::optional<Armature> armature;
ActorArmature(Connection& conn);
};
std::vector<ActorArmature> armatures;
struct Subtype { struct Subtype {
std::string name; std::string name;
std::string cskrId;
ProjectPath mesh; ProjectPath mesh;
int32_t armature = -1; int32_t armature = -1;
std::vector<std::pair<std::string, ProjectPath>> overlayMeshes; struct OverlayMesh {
std::string name;
std::string cskrId;
ProjectPath mesh;
OverlayMesh(Connection& conn);
};
std::vector<OverlayMesh> overlayMeshes;
Subtype(Connection& conn); Subtype(Connection& conn);
}; };
std::vector<Subtype> subtypes; std::vector<Subtype> subtypes;
struct Attachment { struct Attachment {
std::string name; std::string name;
std::string cskrId;
ProjectPath mesh; ProjectPath mesh;
int32_t armature = -1; int32_t armature = -1;
Attachment(Connection& conn); Attachment(Connection& conn);
@ -654,12 +671,12 @@ public:
Actor compileActor(); Actor compileActor();
Actor compileActorCharacterOnly(); Actor compileActorCharacterOnly();
Armature compileArmature();
Action compileActionChannelsOnly(std::string_view name); Action compileActionChannelsOnly(std::string_view name);
std::vector<std::string> getArmatureNames(); std::vector<std::pair<std::string, std::string>> getSubtypeNames();
std::vector<std::string> getSubtypeNames(); std::vector<std::pair<std::string, std::string>> getActionNames();
std::vector<std::string> getActionNames(); std::vector<std::pair<std::string, std::string>> getSubtypeOverlayNames(std::string_view name);
std::vector<std::string> getSubtypeOverlayNames(std::string_view name); std::vector<std::pair<std::string, std::string>> getAttachmentNames();
std::vector<std::string> getAttachmentNames();
std::unordered_map<std::string, Matrix3f> getBoneMatrices(std::string_view name); std::unordered_map<std::string, Matrix3f> getBoneMatrices(std::string_view name);
@ -695,6 +712,7 @@ class Connection {
friend struct Vector3f; friend struct Vector3f;
friend struct Vector4f; friend struct Vector4f;
friend struct World; friend struct World;
friend class MeshOptimizer;
std::atomic_bool m_lock = {false}; std::atomic_bool m_lock = {false};
bool m_pyStreamActive = false; bool m_pyStreamActive = false;
@ -718,6 +736,80 @@ class Connection {
uint32_t _writeStr(std::string_view view) { return _writeStr(view.data(), view.size()); } uint32_t _writeStr(std::string_view view) { return _writeStr(view.data(), view.size()); }
size_t _readBuf(void* buf, size_t len); size_t _readBuf(void* buf, size_t len);
size_t _writeBuf(const 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<typename T, std::enable_if_t<std::disjunction_v<std::is_arithmetic<T>, std::is_enum<T>>, int> = 0>
void _readValue(T& v) { _readBuf(&v, sizeof(T)); }
template<typename T>
void _readItems(T enumerator) {
uint32_t nItems;
_readBuf(&nItems, 4);
for (uint32_t i = 0; i < nItems; ++i)
enumerator(*this);
}
template<typename T, typename... Args, std::enable_if_t<
!std::disjunction_v<std::is_arithmetic<T>, std::is_enum<T>, std::is_same<T, std::string>>, int> = 0>
void _readVector(std::vector<T>& 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>(args)...);
}
template<typename T, std::enable_if_t<std::disjunction_v<std::is_arithmetic<T>, std::is_enum<T>>, int> = 0>
void _readVector(std::vector<T>& container) {
uint32_t nItems;
_readBuf(&nItems, 4);
container.clear();
container.resize(nItems);
_readBuf(&container[0], sizeof(T) * nItems);
}
void _readVector(std::vector<std::string>& 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<typename T, typename F>
void _readVectorFunc(std::vector<T>& 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 _closePipe();
void _blenderDied(); void _blenderDied();
@ -764,8 +856,7 @@ public:
}; };
template <typename S, typename... Args, typename Char> template <typename S, typename... Args, typename Char>
void PyOutStream::format(const S& format, Args&&... args) void PyOutStream::format(const S& format, Args&&... args) {
{
if (!m_parent || !m_parent->m_lock) if (!m_parent || !m_parent->m_lock)
BlenderLog.report(logvisor::Fatal, fmt("lock not held for PyOutStream::format()")); BlenderLog.report(logvisor::Fatal, fmt("lock not held for PyOutStream::format()"));
fmt::print(*this, format, std::forward<Args>(args)...); fmt::print(*this, format, std::forward<Args>(args)...);

View File

@ -15,8 +15,6 @@
#include "hecl.hpp" #include "hecl.hpp"
#define RUNTIME_ORIGINAL_IDS 0
namespace hecl { namespace hecl {
class ClientProcess; class ClientProcess;

View File

@ -72,12 +72,12 @@ inline void DNAFourCC::Enumerate<BigDNA::Write>(Write::StreamT& w) {
} }
template <> template <>
inline void DNAFourCC::Enumerate<BigDNA::ReadYaml>(ReadYaml::StreamT& r) { inline void DNAFourCC::Enumerate<BigDNA::ReadYaml>(ReadYaml::StreamT& r) {
const std::string rs = r.readString(nullptr); const std::string rs = r.readString();
rs.copy(fcc, std::size(fcc)); rs.copy(fcc, std::size(fcc));
} }
template <> template <>
inline void DNAFourCC::Enumerate<BigDNA::WriteYaml>(WriteYaml::StreamT& w) { inline void DNAFourCC::Enumerate<BigDNA::WriteYaml>(WriteYaml::StreamT& w) {
w.writeString(nullptr, std::string_view{fcc, std::size(fcc)}); w.writeString(std::string_view{fcc, std::size(fcc)});
} }
template <> template <>
inline void DNAFourCC::Enumerate<BigDNA::BinarySize>(BinarySize::StreamT& s) { inline void DNAFourCC::Enumerate<BigDNA::BinarySize>(BinarySize::StreamT& s) {

View File

@ -204,7 +204,7 @@ template <> \
template <> \ template <> \
inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<athena::Big>::Read>(typename Read::StreamT & r) { \ inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<athena::Big>::Read>(typename Read::StreamT & r) { \
EnumType variant_type = {}; \ EnumType variant_type = {}; \
Do<athena::io::DNA<athena::Big>::Read>(athena::io::PropId("variant_type"), variant_type, r); \ Do<athena::io::DNA<athena::Big>::Read>(athena::io::PropId("variant_type"sv), variant_type, r); \
static_cast<TypedVariant<__VA_ARGS__>&>(*this) = Build(variant_type); \ static_cast<TypedVariant<__VA_ARGS__>&>(*this) = Build(variant_type); \
visit([&](auto& var) { var.read(r); }); \ visit([&](auto& var) { var.read(r); }); \
} \ } \
@ -215,7 +215,7 @@ inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<ath
visit([&](auto& var) { \ visit([&](auto& var) { \
using T = std::decay_t<decltype(var)>; \ using T = std::decay_t<decltype(var)>; \
EnumType variant_type = T::variant_type(); \ EnumType variant_type = T::variant_type(); \
Do<athena::io::DNA<athena::Big>::Write>(athena::io::PropId("variant_type"), variant_type, w); \ Do<athena::io::DNA<athena::Big>::Write>(athena::io::PropId("variant_type"sv), variant_type, w); \
var.write(w); \ var.write(w); \
}); \ }); \
} \ } \
@ -226,13 +226,13 @@ inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<ath
visit([&](auto& var) { \ visit([&](auto& var) { \
using T = std::decay_t<decltype(var)>; \ using T = std::decay_t<decltype(var)>; \
EnumType variant_type = T::variant_type(); \ EnumType variant_type = T::variant_type(); \
Do<athena::io::DNA<athena::Big>::BinarySize>(athena::io::PropId("variant_type"), variant_type, sz); \ Do<athena::io::DNA<athena::Big>::BinarySize>(athena::io::PropId("variant_type"sv), variant_type, sz); \
var.binarySize(sz); \ var.binarySize(sz); \
}); \ }); \
} \ } \
template <> \ template <> \
inline const char* hecl::TypedVariantBigDNA<__VA_ARGS__>::DNAType() { \ inline std::string_view hecl::TypedVariantBigDNA<__VA_ARGS__>::DNAType() { \
return "hecl::TypedVariantBigDNA<" #__VA_ARGS__ ">"; \ return "hecl::TypedVariantBigDNA<" #__VA_ARGS__ ">"sv; \
} }
#define AT_SPECIALIZE_TYPED_VARIANT_BIGDNA_YAML(...) \ #define AT_SPECIALIZE_TYPED_VARIANT_BIGDNA_YAML(...) \
@ -241,7 +241,7 @@ template <> \
template <> \ template <> \
inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<athena::Big>::ReadYaml>(typename ReadYaml::StreamT & r) { \ inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<athena::Big>::ReadYaml>(typename ReadYaml::StreamT & r) { \
EnumType variant_type = {}; \ EnumType variant_type = {}; \
Do<athena::io::DNA<athena::Big>::ReadYaml>(athena::io::PropId("variant_type"), variant_type, r); \ Do<athena::io::DNA<athena::Big>::ReadYaml>(athena::io::PropId("variant_type"sv), variant_type, r); \
static_cast<TypedVariant<__VA_ARGS__>&>(*this) = Build(variant_type); \ static_cast<TypedVariant<__VA_ARGS__>&>(*this) = Build(variant_type); \
visit([&](auto& var) { var.read(r); }); \ visit([&](auto& var) { var.read(r); }); \
} \ } \
@ -252,7 +252,7 @@ inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<ath
visit([&](auto& var) { \ visit([&](auto& var) { \
using T = std::decay_t<decltype(var)>; \ using T = std::decay_t<decltype(var)>; \
EnumType variant_type = T::variant_type(); \ EnumType variant_type = T::variant_type(); \
Do<athena::io::DNA<athena::Big>::WriteYaml>(athena::io::PropId("variant_type"), variant_type, w); \ Do<athena::io::DNA<athena::Big>::WriteYaml>(athena::io::PropId("variant_type"sv), variant_type, w); \
var.write(w); \ var.write(w); \
}); \ }); \
} }

View File

@ -60,7 +60,8 @@ struct DataSpecEntry;
} // namespace Database } // namespace Database
namespace blender { 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 Connection;
class Token; class Token;
@ -137,6 +138,8 @@ public:
return std::wstring(lhs).append(rhs.m_sys); return std::wstring(lhs).append(rhs.m_sys);
} }
}; };
inline hecl::SystemString UTF8StringToSysString(std::string_view src) { return UTF8ToWide(src); }
#else #else
class SystemUTF8Conv { class SystemUTF8Conv {
std::string_view m_utf8; std::string_view m_utf8;
@ -171,6 +174,8 @@ public:
return std::string(lhs).append(rhs.m_sys); return std::string(lhs).append(rhs.m_sys);
} }
}; };
inline hecl::SystemString UTF8StringToSysString(std::string src) { return src; }
#endif #endif
void SanitizePath(std::string& path); void SanitizePath(std::string& path);
@ -423,7 +428,9 @@ class MultiProgressPrinter;
class ProjectRootPath; class ProjectRootPath;
using SystemRegex = std::basic_regex<SystemChar>; using SystemRegex = std::basic_regex<SystemChar>;
using SystemRegexIterator = std::regex_iterator<SystemString::const_iterator>;
using SystemRegexMatch = std::match_results<SystemString::const_iterator>; using SystemRegexMatch = std::match_results<SystemString::const_iterator>;
using SystemViewRegexMatch = std::match_results<SystemStringView::const_iterator>;
using SystemRegexTokenIterator = std::regex_token_iterator<SystemString::const_iterator>; using SystemRegexTokenIterator = std::regex_token_iterator<SystemString::const_iterator>;
/** /**
@ -929,6 +936,36 @@ public:
} }
#endif #endif
template<typename StringT>
class EncodableString {
friend class ProjectPath;
using EncStringView = std::basic_string_view<typename StringT::value_type>;
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<SystemString> getEncodableString() const {
if (!getAuxInfo().empty())
return {SystemString(getRelativePath()) + _SYS_STR('|') + getAuxInfo().data()};
else
return {getRelativePath()};
}
EncodableString<std::string> getEncodableStringUTF8() const {
if (!getAuxInfo().empty())
return {std::string(getRelativePathUTF8()) + '|' + getAuxInfoUTF8().data()};
else
return {getRelativePathUTF8()};
}
/** /**
* @brief Type of path * @brief Type of path
*/ */
@ -1053,6 +1090,8 @@ public:
Hash hash() const noexcept { return m_hash; } 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 m_hash == other.m_hash; }
bool operator!=(const ProjectPath& other) const noexcept { return !operator==(other); } 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 } // 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 { namespace std {
template <> template <>
struct hash<hecl::ProjectPath> { struct hash<hecl::ProjectPath> {

File diff suppressed because it is too large Load Diff

View File

@ -43,10 +43,11 @@ static bool material_is_lightmapped(const Material& mat) {
MeshOptimizer::Vertex::Vertex(Connection& conn) { MeshOptimizer::Vertex::Vertex(Connection& conn) {
co.read(conn); co.read(conn);
Index skin_count(conn); uint32_t skin_count;
if (skin_count.val > MaxSkinEntries) conn._readValue(skin_count);
Log.report(logvisor::Fatal, fmt("Skin entry overflow {}/{}"), skin_count.val, MaxSkinEntries); if (skin_count > MaxSkinEntries)
for (uint32_t i = 0; i < skin_count.val; ++i) 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); 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); colors[i].read(conn);
for (uint32_t i = 0; i < uv_count; ++i) for (uint32_t i = 0; i < uv_count; ++i)
uvs[i].read(conn); uvs[i].read(conn);
vert = Index(conn).val; conn._readValue(vert);
edge = Index(conn).val; conn._readValue(edge);
face = Index(conn).val; conn._readValue(face);
link_loop_next = Index(conn).val; conn._readValue(link_loop_next);
link_loop_prev = Index(conn).val; conn._readValue(link_loop_prev);
link_loop_radial_next = Index(conn).val; conn._readValue(link_loop_radial_next);
link_loop_radial_prev = Index(conn).val; conn._readValue(link_loop_radial_prev);
} }
MeshOptimizer::Edge::Edge(Connection& conn) { MeshOptimizer::Edge::Edge(Connection& conn) {
for (uint32_t i = 0; i < 2; ++i) for (uint32_t i = 0; i < 2; ++i)
verts[i] = Index(conn).val; conn._readValue(verts[i]);
Index face_count(conn); uint32_t face_count;
conn._readValue(face_count);
if (face_count > MaxLinkFaces) if (face_count > MaxLinkFaces)
Log.report(logvisor::Fatal, fmt("Face overflow {}/{}"), face_count.val, MaxLinkFaces); Log.report(logvisor::Fatal, fmt("Face overflow {}/{}"), face_count, MaxLinkFaces);
for (uint32_t i = 0; i < face_count.val; ++i) for (uint32_t i = 0; i < face_count; ++i)
link_faces[i] = Index(conn).val; conn._readValue(link_faces[i]);
is_contiguous = Boolean(conn).val; conn._readValue(is_contiguous);
} }
MeshOptimizer::Face::Face(Connection& conn) { MeshOptimizer::Face::Face(Connection& conn) {
normal.read(conn); normal.read(conn);
centroid.read(conn); centroid.read(conn);
material_index = Index(conn).val; conn._readValue(material_index);
for (uint32_t i = 0; i < 3; ++i) 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 { 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<Material>& materials, bool use_luvs) MeshOptimizer::MeshOptimizer(Connection& conn, const std::vector<Material>& materials, bool use_luvs)
: materials(materials), use_luvs(use_luvs) { : materials(materials), use_luvs(use_luvs) {
color_count = Index(conn).val; conn._readValue(color_count);
if (color_count > MaxColorLayers) if (color_count > MaxColorLayers)
Log.report(logvisor::Fatal, fmt("Color layer overflow {}/{}"), 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) if (uv_count > MaxUVLayers)
Log.report(logvisor::Fatal, fmt("UV layer overflow {}/{}"), uv_count, MaxUVLayers); Log.report(logvisor::Fatal, fmt("UV layer overflow {}/{}"), uv_count, MaxUVLayers);
/* Simultaneously load topology objects and build unique mapping indices */ /* Simultaneously load topology objects and build unique mapping indices */
Index vert_count(conn); uint32_t vert_count;
verts.reserve(vert_count.val); conn._readValue(vert_count);
b_pos.reserve(vert_count.val); verts.reserve(vert_count);
b_skin.reserve(vert_count.val * 4); b_pos.reserve(vert_count);
for (uint32_t i = 0; i < vert_count.val; ++i) { b_skin.reserve(vert_count * 4);
for (uint32_t i = 0; i < vert_count; ++i) {
verts.emplace_back(conn); verts.emplace_back(conn);
insert_unique_attr(b_pos, verts.back().co); insert_unique_attr(b_pos, verts.back().co);
if (verts.back().skin_ents[0].valid()) if (verts.back().skin_ents[0].valid())
insert_unique_attr(b_skin, verts.back().skin_ents); insert_unique_attr(b_skin, verts.back().skin_ents);
} }
Index loop_count(conn); uint32_t loop_count;
loops.reserve(loop_count.val); conn._readValue(loop_count);
b_norm.reserve(loop_count.val); loops.reserve(loop_count);
b_norm.reserve(loop_count);
if (use_luvs) { if (use_luvs) {
b_uv.reserve(std::max(int(loop_count.val) - 1, 0) * uv_count); b_uv.reserve(std::max(int(loop_count) - 1, 0) * uv_count);
b_luv.reserve(loop_count.val); b_luv.reserve(loop_count);
} else { } 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); loops.emplace_back(conn, color_count, uv_count);
insert_unique_attr(b_norm, loops.back().normal); insert_unique_attr(b_norm, loops.back().normal);
for (const auto& c : loops.back().colors) for (const auto& c : loops.back().colors)
@ -420,15 +424,8 @@ MeshOptimizer::MeshOptimizer(Connection& conn, const std::vector<Material>& mate
} }
} }
Index edge_count(conn); conn._readVector(edges);
edges.reserve(edge_count.val); conn._readVector(faces);
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);
/* Cache edges that should block tristrip traversal */ /* Cache edges that should block tristrip traversal */
for (auto& e : edges) for (auto& e : edges)

View File

@ -29,7 +29,7 @@ const SDNABlock::SDNAStruct::SDNAField* SDNABlock::SDNAStruct::lookupField(const
if (bracket != std::string::npos) { if (bracket != std::string::npos) {
if (!name.compare(0, bracket, n)) if (!name.compare(0, bracket, n))
return &field; return &field;
} else if (!name.compare(n)) } else if (name == n)
return &field; return &field;
} }
return nullptr; return nullptr;
@ -39,7 +39,7 @@ const SDNABlock::SDNAStruct* SDNABlock::lookupStruct(const char* n, atUint32& id
idx = 0; idx = 0;
for (const SDNAStruct& strc : strcs) { for (const SDNAStruct& strc : strcs) {
const auto& name = types[strc.type]; const auto& name = types[strc.type];
if (!name.compare(n)) if (name == n)
return &strc; return &strc;
++idx; ++idx;
} }

View File

@ -165,11 +165,11 @@ bool CVar::toBoolean(bool* isValid) const {
std::string tmp = m_value; std::string tmp = m_value;
athena::utility::tolower(tmp); athena::utility::tolower(tmp);
if (!tmp.compare("yes") || !tmp.compare("true") || !tmp.compare("1")) { if (tmp == "yes" || tmp == "true" || tmp == "1") {
if (isValid) if (isValid)
*isValid = true; *isValid = true;
return true; return true;
} else if (!tmp.compare("no") || !tmp.compare("false") || !tmp.compare("0")) { } else if (tmp == "no" || tmp == "false" || tmp == "0") {
if (isValid) if (isValid)
*isValid = true; *isValid = true;
return false; return false;

View File

@ -181,7 +181,7 @@ void CVarManager::serialize() {
filename += _SYS_STR(".yaml"); filename += _SYS_STR(".yaml");
athena::io::FileReader r(filename); athena::io::FileReader r(filename);
athena::io::YAMLDocWriter docWriter(nullptr, r.isOpen() ? &r : nullptr); athena::io::YAMLDocWriter docWriter(r.isOpen() ? &r : nullptr);
r.close(); r.close();
docWriter.setStyle(athena::io::YAMLNodeStyle::Block); docWriter.setStyle(athena::io::YAMLNodeStyle::Block);

View File

@ -91,7 +91,7 @@ void Project::ConfigFile::removeLine(std::string_view refLine) {
} }
for (auto it = m_lines.begin(); it != m_lines.end();) { for (auto it = m_lines.begin(); it != m_lines.end();) {
if (!(*it).compare(refLine)) { if (*it == refLine) {
it = m_lines.erase(it); it = m_lines.erase(it);
continue; continue;
} }
@ -106,7 +106,7 @@ bool Project::ConfigFile::checkForLine(std::string_view refLine) {
} }
for (const std::string& line : m_lines) for (const std::string& line : m_lines)
if (!line.compare(refLine)) if (line == refLine)
return true; return true;
return false; return false;
} }

View File

@ -14,9 +14,9 @@ static SystemString CanonRelPath(SystemStringView path) {
SanitizePath(in); SanitizePath(in);
for (; std::regex_search(in, matches, regPATHCOMP); in = matches.suffix().str()) { for (; std::regex_search(in, matches, regPATHCOMP); in = matches.suffix().str()) {
hecl::SystemRegexMatch::const_reference match = matches[1]; hecl::SystemRegexMatch::const_reference match = matches[1];
if (!match.compare(_SYS_STR("."))) if (match == _SYS_STR("."))
continue; continue;
else if (!match.compare(_SYS_STR(".."))) { else if (match == _SYS_STR("..")) {
if (comps.empty()) { if (comps.empty()) {
/* Unable to resolve outside project */ /* Unable to resolve outside project */
LogModule.report(logvisor::Fatal, fmt(_SYS_STR("Unable to resolve outside project root in {}")), path); 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 { ProjectPath::Type ProjectPath::getPathType() const {
if (m_absPath.empty())
return Type::None;
if (m_absPath.find(_SYS_STR('*')) != SystemString::npos) if (m_absPath.find(_SYS_STR('*')) != SystemString::npos)
return Type::Glob; return Type::Glob;
Sstat theStat; Sstat theStat;
@ -246,6 +248,43 @@ void ProjectPath::getGlobResults(std::vector<ProjectPath>& outPaths) const {
_recursiveGlob(*m_proj, outPaths, m_relPath, rootPath.data(), rootPath.back() != _SYS_STR('/')); _recursiveGlob(*m_proj, outPaths, m_relPath, rootPath.data(), rootPath.back() != _SYS_STR('/'));
} }
template <typename T>
static bool RegexSearchLast(const T& str, std::match_results<typename T::const_iterator>& m,
const std::basic_regex<typename T::value_type>& reg) {
using Iterator = std::regex_iterator<typename T::const_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 SearchForProject(SystemStringView path) {
ProjectRootPath testRoot(path); ProjectRootPath testRoot(path);
auto begin = testRoot.getAbsolutePath().begin(); auto begin = testRoot.getAbsolutePath().begin();

View File

@ -30,11 +30,13 @@
#include <logvisor/logvisor.hpp> #include <logvisor/logvisor.hpp>
using namespace std::literals;
namespace hecl { namespace hecl {
unsigned VerbosityLevel = 0; unsigned VerbosityLevel = 0;
bool GuiMode = false; bool GuiMode = false;
logvisor::Module LogModule("hecl"); logvisor::Module LogModule("hecl");
constexpr std::string_view Illegals{"<>?\""}; constexpr std::string_view Illegals = "<>?\""sv;
void SanitizePath(std::string& path) { void SanitizePath(std::string& path) {
if (path.empty()) if (path.empty())
@ -64,7 +66,7 @@ void SanitizePath(std::string& path) {
path.pop_back(); path.pop_back();
} }
constexpr std::wstring_view WIllegals{L"<>?\""}; constexpr std::wstring_view WIllegals = L"<>?\""sv;
void SanitizePath(std::wstring& path) { void SanitizePath(std::wstring& path) {
if (path.empty()) if (path.empty())
@ -174,9 +176,8 @@ bool IsPathPNG(const hecl::ProjectPath& path) {
bool IsPathBlend(const hecl::ProjectPath& path) { bool IsPathBlend(const hecl::ProjectPath& path) {
const auto lastCompExt = path.getLastComponentExt(); const auto lastCompExt = path.getLastComponentExt();
if (lastCompExt.empty() || hecl::StrCmp(lastCompExt.data(), _SYS_STR("blend"))) { if (lastCompExt.empty() || lastCompExt != _SYS_STR("blend"))
return false; return false;
}
const auto fp = hecl::FopenUnique(path.getAbsolutePath().data(), _SYS_STR("rb")); const auto fp = hecl::FopenUnique(path.getAbsolutePath().data(), _SYS_STR("rb"));
if (fp == nullptr) { if (fp == nullptr) {
@ -193,14 +194,15 @@ bool IsPathBlend(const hecl::ProjectPath& path) {
} }
bool IsPathYAML(const hecl::ProjectPath& path) { bool IsPathYAML(const hecl::ProjectPath& path) {
if (!hecl::StrCmp(path.getLastComponent().data(), _SYS_STR("!catalog.yaml"))) auto lastComp = path.getLastComponent();
return false; /* !catalog.yaml is exempt from general use */ 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(); auto lastCompExt = path.getLastComponentExt();
if (lastCompExt.empty()) if (lastCompExt.empty())
return false; return false;
if (!hecl::StrCmp(lastCompExt.data(), _SYS_STR("yaml")) || !hecl::StrCmp(lastCompExt.data(), _SYS_STR("yml"))) return lastCompExt == _SYS_STR("yaml") || lastCompExt == _SYS_STR("yml");
return true;
return false;
} }
hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode, bool sizeSort, bool reverse, hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode, bool sizeSort, bool reverse,