...
 
Commits (2)
......@@ -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
......
# 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):
......
......@@ -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)
......
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')
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)
......
......@@ -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")
......
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())
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))
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('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)
......
......@@ -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)
......
......@@ -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="))) {
......
......@@ -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="))) {
......
......@@ -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;
}
......
Subproject commit a9039e04e64e913b1cee1df271739d8234c9bd3a
Subproject commit 42581c922a4574f4f34df134a454effa9f9cc8d0
Subproject commit e342ea5754a078dec32d238593aa7d136b886e73
Subproject commit 922fcbb3c23677b3ccc53737fd23ada165ccf9f3
......@@ -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 <typename S, typename... Args, typename Char = fmt::char_t<S>>
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<Vector3f> verts;
std::vector<Index> indices;
std::vector<uint32_t> indices;
struct Surface {
Vector3f normal;
Vector3f centerOfMass;
Index start;
Index count;
std::vector<std::pair<Index, Index>> borders;
uint32_t start;
uint32_t count;
std::vector<std::pair<uint32_t, uint32_t>> borders;
Surface(Connection& conn);
};
std::vector<Surface> surfaces;
......@@ -547,7 +550,6 @@ struct Bone {
/** Intermediate armature representation used in Actor */
struct Armature {
std::string name;
std::vector<Bone> 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<Armature> armatures;
struct ActorArmature {
std::string name;
ProjectPath path;
std::optional<Armature> armature;
ActorArmature(Connection& conn);
};
std::vector<ActorArmature> armatures;
struct Subtype {
std::string name;
std::string cskrId;
ProjectPath mesh;
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);
};
std::vector<Subtype> 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<std::string> getArmatureNames();
std::vector<std::string> getSubtypeNames();
std::vector<std::string> getActionNames();
std::vector<std::string> getSubtypeOverlayNames(std::string_view name);
std::vector<std::string> getAttachmentNames();
std::vector<std::pair<std::string, std::string>> getSubtypeNames();
std::vector<std::pair<std::string, std::string>> getActionNames();
std::vector<std::pair<std::string, std::string>> getSubtypeOverlayNames(std::string_view name);
std::vector<std::pair<std::string, std::string>> getAttachmentNames();
std::unordered_map<std::string, Matrix3f> 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<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 _blenderDied();
......@@ -764,8 +856,7 @@ public:
};
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)
BlenderLog.report(logvisor::Fatal, fmt("lock not held for PyOutStream::format()"));
fmt::print(*this, format, std::forward<Args>(args)...);
......
......@@ -13,8 +13,6 @@
#include <logvisor/logvisor.hpp>
#define RUNTIME_ORIGINAL_IDS 0
namespace hecl {
class ClientProcess;
......
......@@ -74,12 +74,12 @@ inline void DNAFourCC::Enumerate<BigDNA::Write>(Write::StreamT& w) {
}
template <>
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));
}
template <>
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 <>
inline void DNAFourCC::Enumerate<BigDNA::BinarySize>(BinarySize::StreamT& s) {
......
......@@ -208,7 +208,7 @@ private:
inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<athena::Endian::Big>::Read>( \
typename Read::StreamT & r) { \
EnumType variant_type = {}; \
Do<athena::io::DNA<athena::Endian::Big>::Read>(athena::io::PropId("variant_type"), variant_type, r); \
Do<athena::io::DNA<athena::Endian::Big>::Read>(athena::io::PropId("variant_type"sv), variant_type, r); \
static_cast<TypedVariant<__VA_ARGS__>&>(*this) = Build(variant_type); \
visit([&](auto& var) { var.read(r); }); \
} \
......@@ -220,7 +220,7 @@ private:
visit([&](auto& var) { \
using T = std::decay_t<decltype(var)>; \
EnumType variant_type = T::variant_type(); \
Do<athena::io::DNA<athena::Endian::Big>::Write>(athena::io::PropId("variant_type"), variant_type, w); \
Do<athena::io::DNA<athena::Endian::Big>::Write>(athena::io::PropId("variant_type"sv), variant_type, w); \
var.write(w); \
}); \
} \
......@@ -232,13 +232,13 @@ private:
visit([&](auto& var) { \
using T = std::decay_t<decltype(var)>; \
EnumType variant_type = T::variant_type(); \
Do<athena::io::DNA<athena::Endian::Big>::BinarySize>(athena::io::PropId("variant_type"), variant_type, sz); \
Do<athena::io::DNA<athena::Endian::Big>::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(...) \
......@@ -248,7 +248,7 @@ private:
inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<athena::Endian::Big>::ReadYaml>( \
typename ReadYaml::StreamT & r) { \
EnumType variant_type = {}; \
Do<athena::io::DNA<athena::Endian::Big>::ReadYaml>(athena::io::PropId("variant_type"), variant_type, r); \
Do<athena::io::DNA<athena::Endian::Big>::ReadYaml>(athena::io::PropId("variant_type"sv), variant_type, r); \
static_cast<TypedVariant<__VA_ARGS__>&>(*this) = Build(variant_type); \
visit([&](auto& var) { var.read(r); }); \
} \
......@@ -260,7 +260,7 @@ private:
visit([&](auto& var) { \
using T = std::decay_t<decltype(var)>; \
EnumType variant_type = T::variant_type(); \
Do<athena::io::DNA<athena::Endian::Big>::WriteYaml>(athena::io::PropId("variant_type"), variant_type, w); \
Do<athena::io::DNA<athena::Endian::Big>::WriteYaml>(athena::io::PropId("variant_type"sv), variant_type, w); \
var.write(w); \
}); \
}
......
......@@ -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 ANIMOutStream;
class Connection;
......@@ -138,6 +139,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;
......@@ -172,6 +175,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);
......@@ -424,7 +429,9 @@ class MultiProgressPrinter;
class ProjectRootPath;
using SystemRegex = std::basic_regex<SystemChar>;
using SystemRegexIterator = std::regex_iterator<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>;
/**
......@@ -930,6 +937,36 @@ public:
}
#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
*/
......@@ -1054,6 +1091,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;
};
/**
......@@ -1295,6 +1334,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<hecl::ProjectPath> {
......
This diff is collapsed.
......@@ -47,10 +47,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);
}
......@@ -60,32 +61,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 {
......@@ -380,36 +382,38 @@ void MeshOptimizer::optimize(Mesh& mesh, int max_skin_banks) const {
MeshOptimizer::MeshOptimizer(Connection& conn, const std::vector<Material>& 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)
......@@ -424,15 +428,8 @@ MeshOptimizer::MeshOptimizer(Connection& conn, const std::vector<Material>& 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)
......
......@@ -37,7 +37,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;
......@@ -47,7 +47,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;
}
......
......@@ -182,7 +182,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);
......
......@@ -94,7 +94,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;
}
......@@ -109,7 +109,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;
}
......
......@@ -17,9 +17,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);
......@@ -143,6 +143,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;
......@@ -249,6 +251,43 @@ void ProjectPath::getGlobResults(std::vector<ProjectPath>& outPaths) const {
_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 testRoot(path);
auto begin = testRoot.getAbsolutePath().begin();
......
......@@ -30,11 +30,13 @@
#include <logvisor/logvisor.hpp>
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"<>?\"", 4};
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,
......