From 135a7ced5d5948dedbd43cb197edf9fbd9f64ba6 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Tue, 6 Oct 2015 15:16:54 -1000 Subject: [PATCH] Mesh cooker updates --- hecl/blender/BlenderConnection.cpp | 28 +++--- hecl/blender/BlenderConnection.hpp | 12 +-- hecl/blender/hecl/hmdl/HMDLMesh.py | 140 ++++++++++++++++------------- hecl/blender/hecl/hmdl/__init__.py | 66 +++++++++----- hecl/blender/hecl_blendershell.py | 3 +- hecl/driver/ToolBase.hpp | 2 +- hecl/include/HECL/HECL.hpp | 18 +++- hecl/lib/Database/Project.cpp | 47 +++++++++- hecl/lib/HECL.cpp | 3 + hecl/lib/ProjectPath.cpp | 2 +- 10 files changed, 215 insertions(+), 106 deletions(-) diff --git a/hecl/blender/BlenderConnection.cpp b/hecl/blender/BlenderConnection.cpp index 4c56730d7..30ec96f65 100644 --- a/hecl/blender/BlenderConnection.cpp +++ b/hecl/blender/BlenderConnection.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include "BlenderConnection.hpp" @@ -351,7 +352,7 @@ static const char* BlendTypeStrs[] = nullptr }; -bool BlenderConnection::createBlend(const SystemString& path, BlendType type) +bool BlenderConnection::createBlend(const ProjectPath& path, BlendType type) { if (m_lock) { @@ -359,8 +360,7 @@ bool BlenderConnection::createBlend(const SystemString& path, BlendType type) "BlenderConnection::createBlend() musn't be called with stream active"); return false; } - HECL::SystemUTF8View pathView(path); - _writeLine(("CREATE \"" + pathView.str() + "\" " + BlendTypeStrs[type] + " \"" + m_startupBlend + "\"").c_str()); + _writeLine(("CREATE \"" + path.getAbsolutePathUTF8() + "\" " + BlendTypeStrs[type] + " \"" + m_startupBlend + "\"").c_str()); char lineBuf[256]; _readLine(lineBuf, sizeof(lineBuf)); if (!strcmp(lineBuf, "FINISHED")) @@ -372,7 +372,7 @@ bool BlenderConnection::createBlend(const SystemString& path, BlendType type) return false; } -bool BlenderConnection::openBlend(const SystemString& path) +bool BlenderConnection::openBlend(const ProjectPath& path) { if (m_lock) { @@ -382,8 +382,7 @@ bool BlenderConnection::openBlend(const SystemString& path) } if (path == m_loadedBlend) return true; - HECL::SystemUTF8View pathView(path); - _writeLine(("OPEN \"" + pathView.str() + "\"").c_str()); + _writeLine(("OPEN \"" + path.getAbsolutePathUTF8() + "\"").c_str()); char lineBuf[256]; _readLine(lineBuf, sizeof(lineBuf)); if (!strcmp(lineBuf, "FINISHED")) @@ -425,11 +424,11 @@ bool BlenderConnection::saveBlend() void BlenderConnection::deleteBlend() { - if (m_loadedBlend.size()) + if (m_loadedBlend) { - HECL::Unlink(m_loadedBlend.c_str()); - BlenderLog.report(LogVisor::Info, _S("Deleted '%s'"), m_loadedBlend.c_str()); - m_loadedBlend.clear(); + HECL::Unlink(m_loadedBlend.getAbsolutePath().c_str()); + BlenderLog.report(LogVisor::Info, _S("Deleted '%s'"), m_loadedBlend.getAbsolutePath().c_str()); + m_loadedBlend = ProjectPath(); } } @@ -568,7 +567,14 @@ BlenderConnection::DataStream::Mesh::Material::Material for (int i=0 ; i texs; + std::vector texs; Material(BlenderConnection& conn); }; @@ -400,10 +400,10 @@ public: } /* Compile all meshes into one */ - Mesh compileAllMeshes(int skinSlotCount=10) + Mesh compileAllMeshes(int skinSlotCount=10, float maxOctantLength=5.0) { char req[128]; - snprintf(req, 128, "MESHCOMPILEALL %d", skinSlotCount); + snprintf(req, 128, "MESHCOMPILEALL %d %f", skinSlotCount, maxOctantLength); m_parent->_writeLine(req); char readBuf[256]; diff --git a/hecl/blender/hecl/hmdl/HMDLMesh.py b/hecl/blender/hecl/hmdl/HMDLMesh.py index c3ac02733..3de11d5b9 100644 --- a/hecl/blender/hecl/hmdl/HMDLMesh.py +++ b/hecl/blender/hecl/hmdl/HMDLMesh.py @@ -10,7 +10,8 @@ from mathutils import Vector class VertPool: # Initialize hash-unique index for each available attribute - def __init__(self, bm): + def __init__(self, bm, rna_loops): + self.rna_loops = rna_loops self.pos = {} self.norm = {} self.skin = {} @@ -40,9 +41,10 @@ class VertPool: pf = v.co.copy().freeze() if pf not in self.pos: self.pos[pf] = len(self.pos) - nf = v.normal.copy().freeze() - if nf not in self.norm: - self.norm[nf] = len(self.norm) + if not rna_loops: + nf = v.normal.copy().freeze() + if nf not in self.norm: + self.norm[nf] = len(self.norm) if dlay: sf = tuple(sorted(v[dlay].items())) if sf not in self.skin: @@ -51,6 +53,10 @@ class VertPool: # Per-loop pool attributes for f in bm.faces: for l in f.loops: + if rna_loops: + nf = rna_loops[l.index].normal.copy().freeze() + if nf not in self.norm: + self.norm[nf] = len(self.norm) for cl in range(len(clays)): cf = l[clays[cl]].copy().freeze() if cf not in self.color: @@ -60,44 +66,47 @@ class VertPool: if uf not in self.uv: self.uv[uf] = len(self.uv) - def write_out(self, writebuffunc, vert_groups): - writebuffunc(struct.pack('I', len(self.pos))) + def write_out(self, writebuf, vert_groups): + writebuf(struct.pack('I', len(self.pos))) for p in sorted(self.pos.items(), key=operator.itemgetter(1)): - writebuffunc(struct.pack('fff', p[0][0], p[0][1], p[0][2])) + writebuf(struct.pack('fff', p[0][0], p[0][1], p[0][2])) - writebuffunc(struct.pack('I', len(self.norm))) + writebuf(struct.pack('I', len(self.norm))) for n in sorted(self.norm.items(), key=operator.itemgetter(1)): - writebuffunc(struct.pack('fff', n[0][0], n[0][1], n[0][2])) + writebuf(struct.pack('fff', n[0][0], n[0][1], n[0][2])) - writebuffunc(struct.pack('II', len(self.clays), len(self.color))) + writebuf(struct.pack('II', len(self.clays), len(self.color))) for c in sorted(self.color.items(), key=operator.itemgetter(1)): - writebuffunc(struct.pack('fff', c[0][0], c[0][1], c[0][2])) + writebuf(struct.pack('fff', c[0][0], c[0][1], c[0][2])) - writebuffunc(struct.pack('II', len(self.ulays), len(self.uv))) + writebuf(struct.pack('II', len(self.ulays), len(self.uv))) for u in sorted(self.uv.items(), key=operator.itemgetter(1)): - writebuffunc(struct.pack('ff', u[0][0], u[0][1])) + writebuf(struct.pack('ff', u[0][0], u[0][1])) - writebuffunc(struct.pack('I', len(vert_groups))) + writebuf(struct.pack('I', len(vert_groups))) for vgrp in vert_groups: - writebuffunc((vgrp.name + '\n').encode()) + writebuf((vgrp.name + '\n').encode()) - writebuffunc(struct.pack('I', len(self.skin))) + writebuf(struct.pack('I', len(self.skin))) for s in sorted(self.skin.items(), key=operator.itemgetter(1)): entries = s[0] - writebuffunc(struct.pack('I', len(entries))) + writebuf(struct.pack('I', len(entries))) if len(entries): total_len = 0.0 for ent in entries: total_len += ent[1] for ent in entries: - writebuffunc(struct.pack('If', ent[0], ent[1] / total_len)) + writebuf(struct.pack('If', ent[0], ent[1] / total_len)) def get_pos_idx(self, vert): pf = vert.co.copy().freeze() return self.pos[pf] - def get_norm_idx(self, vert): - nf = vert.normal.copy().freeze() + def get_norm_idx(self, loop): + if self.rna_loops: + nf = self.rna_loops[loop.index].normal.copy().freeze() + else: + nf = loop.vert.normal.copy().freeze() return self.norm[nf] def get_skin_idx(self, vert): @@ -114,19 +123,19 @@ class VertPool: uf = loop[self.ulays[uidx]].uv.copy().freeze() return self.uv[uf] - def loop_out(self, writebuffunc, loop): - writebuffunc(struct.pack('B', 1)) - writebuffunc(struct.pack('II', self.get_pos_idx(loop.vert), self.get_norm_idx(loop.vert))) + def loop_out(self, writebuf, loop): + writebuf(struct.pack('B', 1)) + writebuf(struct.pack('II', self.get_pos_idx(loop.vert), self.get_norm_idx(loop))) for cl in range(len(self.clays)): - writebuffunc(struct.pack('I', self.get_color_idx(loop, cl))) + writebuf(struct.pack('I', self.get_color_idx(loop, cl))) for ul in range(len(self.ulays)): - writebuffunc(struct.pack('I', self.get_uv_idx(loop, ul))) + writebuf(struct.pack('I', self.get_uv_idx(loop, ul))) sp = struct.pack('I', self.get_skin_idx(loop.vert)) - writebuffunc(sp) + writebuf(sp) def recursive_faces_islands(dlay, list_out, rem_list, skin_slot_set, skin_slot_count, face): if face not in rem_list: - return None + return [] if dlay: for v in face.verts: @@ -137,14 +146,15 @@ def recursive_faces_islands(dlay, list_out, rem_list, skin_slot_set, skin_slot_c list_out.append(face) rem_list.remove(face) + next_faces = [] for e in face.edges: if not e.is_contiguous: continue for f in e.link_faces: if f == face: continue - if recursive_faces_islands(dlay, list_out, rem_list, skin_slot_set, skin_slot_count, f) == False: - return False + next_faces.append(f) + return next_faces def find_opposite_edge(face, boot_edge, boot_edge2, last_edge, last_edge_2): if last_edge_2: @@ -159,17 +169,17 @@ def find_opposite_edge(face, boot_edge, boot_edge2, last_edge, last_edge_2): def recursive_faces_strip(list_out, rem_list, face, boot_edge, boot_edge_2, last_edge, last_edge_2): if face not in rem_list: - return + return None, None, None list_out.append(face) rem_list.remove(face) edge = find_opposite_edge(face, boot_edge, boot_edge_2, last_edge, last_edge_2) if not edge: - return + return None, None, None for f in edge.link_faces: if f == face: continue - recursive_faces_strip(list_out, rem_list, f, boot_edge, boot_edge_2, edge, last_edge) - break + return f, edge, last_edge + return None, None, None def count_contiguous_edges(face): retval = 0 @@ -188,42 +198,42 @@ def find_loop_opposite_from_other_face(face, other_face): continue return l -def stripify_primitive(writebuffunc, vert_pool, prim_faces, last_loop, last_idx): +def stripify_primitive(writebuf, vert_pool, prim_faces, last_loop, next_idx): if last_loop: - vert_pool.loop_out(writebuffunc, last_loop) - last_idx += 1 + vert_pool.loop_out(writebuf, last_loop) + next_idx += 1 if len(prim_faces) == 1: loop = prim_faces[0].loops[0] if last_loop: - vert_pool.loop_out(writebuffunc, loop) - last_idx += 1 - if last_idx & 1: + vert_pool.loop_out(writebuf, loop) + next_idx += 1 + if next_idx & 1: rev = True else: rev = False for i in range(3): - vert_pool.loop_out(writebuffunc, loop) + vert_pool.loop_out(writebuf, loop) last_loop = loop - last_idx += 1 + next_idx += 1 if rev: loop = loop.link_loop_prev else: loop = loop.link_loop_next - return last_loop, last_idx + return last_loop, next_idx loop = find_loop_opposite_from_other_face(prim_faces[0], prim_faces[1]) if last_loop: - vert_pool.loop_out(writebuffunc, loop) - last_idx += 1 - if last_idx & 1: + vert_pool.loop_out(writebuf, loop) + next_idx += 1 + if next_idx & 1: rev = True else: rev = False for i in range(3): - vert_pool.loop_out(writebuffunc, loop) + vert_pool.loop_out(writebuf, loop) last_loop = loop - last_idx += 1 + next_idx += 1 if rev: loop = loop.link_loop_prev else: @@ -231,24 +241,24 @@ def stripify_primitive(writebuffunc, vert_pool, prim_faces, last_loop, last_idx) for i in range(1, len(prim_faces)): loop = find_loop_opposite_from_other_face(prim_faces[i], prim_faces[i-1]) - vert_pool.loop_out(writebuffunc, loop) + vert_pool.loop_out(writebuf, loop) last_loop = loop - last_idx += 1 + next_idx += 1 - return last_loop, last_idx + return last_loop, next_idx -def write_out_surface(writebuffunc, vert_pool, island_faces, mat_idx): +def write_out_surface(writebuf, vert_pool, island_faces, mat_idx): # Centroid of surface centroid = Vector() for f in island_faces: centroid += f.calc_center_bounds() centroid /= len(island_faces) - writebuffunc(struct.pack('fff', centroid[0], centroid[1], centroid[2])) + writebuf(struct.pack('fff', centroid[0], centroid[1], centroid[2])) # Material index - writebuffunc(struct.pack('I', mat_idx)) + writebuf(struct.pack('I', mat_idx)) # AABB of surface aabb_min = Vector((9999999, 9999999, 9999999)) @@ -260,22 +270,22 @@ def write_out_surface(writebuffunc, vert_pool, island_faces, mat_idx): aabb_min[c] = v.co[c] if v.co[c] > aabb_max[c]: aabb_max[c] = v.co[c] - writebuffunc(struct.pack('fff', aabb_min[0], aabb_min[1], aabb_min[2])) - writebuffunc(struct.pack('fff', aabb_max[0], aabb_max[1], aabb_max[2])) + writebuf(struct.pack('fff', aabb_min[0], aabb_min[1], aabb_min[2])) + writebuf(struct.pack('fff', aabb_max[0], aabb_max[1], aabb_max[2])) # Average normal of surface avg_norm = Vector() for f in island_faces: avg_norm += f.normal avg_norm.normalize() - writebuffunc(struct.pack('fff', avg_norm[0], avg_norm[1], avg_norm[2])) + writebuf(struct.pack('fff', avg_norm[0], avg_norm[1], avg_norm[2])) # Count estimate - writebuffunc(struct.pack('I', len(island_faces) * 3)) + writebuf(struct.pack('I', len(island_faces) * 3)) # Verts themselves last_loop = None - last_idx = 0 + next_idx = 0 while len(island_faces): sel_lists_local = [] for start_face in island_faces: @@ -294,8 +304,14 @@ def write_out_surface(writebuffunc, vert_pool, island_faces, mat_idx): for e2 in next_edges: island_local = list(island_faces) sel_list = [] - recursive_faces_strip(sel_list, island_local, start_face, e, e2, None, None) - sel_lists_local.append(sel_list) + next_face = start_face + last_edge = None + last_edge_2 = None + while next_face is not None: + next_face, last_edge, last_edge_2 = recursive_faces_strip(sel_list, island_local, next_face, + e, e2, last_edge, last_edge_2) + if len(sel_list): + sel_lists_local.append(sel_list) max_count = 0 max_sl = None for sl in sel_lists_local: @@ -304,6 +320,6 @@ def write_out_surface(writebuffunc, vert_pool, island_faces, mat_idx): max_sl = sl for f in max_sl: island_faces.remove(f) - last_loop, last_idx = stripify_primitive(writebuffunc, vert_pool, max_sl, last_loop, last_idx) - writebuffunc(struct.pack('B', 0)) + last_loop, next_idx = stripify_primitive(writebuf, vert_pool, max_sl, last_loop, next_idx) + writebuf(struct.pack('B', 0)) diff --git a/hecl/blender/hecl/hmdl/__init__.py b/hecl/blender/hecl/hmdl/__init__.py index c6ffa2570..996250581 100644 --- a/hecl/blender/hecl/hmdl/__init__.py +++ b/hecl/blender/hecl/hmdl/__init__.py @@ -69,23 +69,35 @@ def generate_skeleton_info(armature, endian_char='<'): # Takes a Blender 'Mesh' object (not the datablock) # and performs a one-shot conversion process to HMDL; packaging # into the HECL data-pipeline and returning a hash once complete -def cook(writebuffunc, mesh_obj, max_skin_banks): +def cook(writebuf, mesh_obj, max_skin_banks, max_octant_length=None): if mesh_obj.type != 'MESH': raise RuntimeError("%s is not a mesh" % mesh_obj.name) - # Copy mesh (and apply mesh modifiers) + # Copy mesh (and apply mesh modifiers with triangulation) copy_name = mesh_obj.name + "_hmdltri" copy_mesh = bpy.data.meshes.new(copy_name) copy_obj = bpy.data.objects.new(copy_name, copy_mesh) copy_obj.data = mesh_obj.to_mesh(bpy.context.scene, True, 'RENDER') + copy_mesh = copy_obj.data copy_obj.scale = mesh_obj.scale bpy.context.scene.objects.link(copy_obj) + bpy.ops.object.select_all(action='DESELECT') + bpy.context.scene.objects.active = copy_obj + copy_obj.select = True + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.mesh.select_all(action='SELECT') + bpy.ops.mesh.quads_convert_to_tris() + bpy.context.scene.update() + bpy.ops.object.mode_set(mode='OBJECT') + rna_loops = None + if copy_mesh.has_custom_normals: + copy_mesh.calc_normals_split() + rna_loops = copy_mesh.loops - # Create master triangulated BMesh and VertPool + # Create master BMesh and VertPool bm_master = bmesh.new() bm_master.from_mesh(copy_obj.data) - bmesh.ops.triangulate(bm_master, faces=bm_master.faces) - vert_pool = HMDLMesh.VertPool(bm_master) + vert_pool = HMDLMesh.VertPool(bm_master, rna_loops) # Sort materials by pass index first sorted_material_idxs = [] @@ -101,34 +113,34 @@ def cook(writebuffunc, mesh_obj, max_skin_banks): # Generate shaders if mesh_obj.data.hecl_material_count > 0: - writebuffunc(struct.pack('I', mesh_obj.data.hecl_material_count)) + writebuf(struct.pack('I', mesh_obj.data.hecl_material_count)) for grp_idx in range(mesh_obj.data.hecl_material_count): - writebuffunc(struct.pack('I', len(sorted_material_idxs))) + writebuf(struct.pack('I', len(sorted_material_idxs))) for mat_idx in sorted_material_idxs: found = False for mat in bpy.data.materials: if mat.name.endswith('_%u_%u' % (grp_idx, mat_idx)): hecl_str, texs = HMDLShader.shader(mat, mesh_obj) - writebuffunc((hecl_str + '\n').encode()) - writebuffunc(struct.pack('I', len(texs))) + writebuf((hecl_str + '\n').encode()) + writebuf(struct.pack('I', len(texs))) for tex in texs: - writebuffunc((tex + '\n').encode()) + writebuf((tex + '\n').encode()) found = True break if not found: raise RuntimeError('uneven material set %d in %s' % (grp_idx, mesh_obj.name)) else: - writebuffunc(struct.pack('II', 1, len(sorted_material_idxs))) + writebuf(struct.pack('II', 1, len(sorted_material_idxs))) for mat_idx in sorted_material_idxs: mat = mesh_obj.data.materials[mat_idx] hecl_str, texs = HMDLShader.shader(mat, mesh_obj) - writebuffunc((hecl_str + '\n').encode()) - writebuffunc(struct.pack('I', len(texs))) + writebuf((hecl_str + '\n').encode()) + writebuf(struct.pack('I', len(texs))) for tex in texs: - writebuffunc((tex + '\n').encode()) + writebuf((tex + '\n').encode()) # Output vert pool - vert_pool.write_out(writebuffunc, mesh_obj.vertex_groups) + vert_pool.write_out(writebuf, mesh_obj.vertex_groups) dlay = None if len(bm_master.verts.layers.deform): @@ -143,13 +155,27 @@ def cook(writebuffunc, mesh_obj, max_skin_banks): while len(mat_faces_rem): the_list = [] skin_slot_set = set() - HMDLMesh.recursive_faces_islands(dlay, the_list, mat_faces_rem, skin_slot_set, - max_skin_banks, mat_faces_rem[0]) - writebuffunc(struct.pack('B', 1)) - HMDLMesh.write_out_surface(writebuffunc, vert_pool, the_list, mat_idx) + faces = [mat_faces_rem[0]] + while len(faces): + next_faces = [] + ret_faces = None + for f in faces: + ret_faces = HMDLMesh.recursive_faces_islands(dlay, the_list, + mat_faces_rem, + skin_slot_set, + max_skin_banks, f) + if ret_faces == False: + break + next_faces.extend(ret_faces) + if ret_faces == False: + break + faces = next_faces + + writebuf(struct.pack('B', 1)) + HMDLMesh.write_out_surface(writebuf, vert_pool, the_list, mat_idx) # No more surfaces - writebuffunc(struct.pack('B', 0)) + writebuf(struct.pack('B', 0)) # Filter out useless AABB points and generate data array #aabb = bytearray() diff --git a/hecl/blender/hecl_blendershell.py b/hecl/blender/hecl_blendershell.py index 75d4b553f..5b30cd6c9 100644 --- a/hecl/blender/hecl_blendershell.py +++ b/hecl/blender/hecl_blendershell.py @@ -167,6 +167,7 @@ def dataout_loop(): elif cmdargs[0] == 'MESHCOMPILEALL': maxSkinBanks = int(cmdargs[1]) + maxOctantLength = float(cmdargs[2]) bpy.ops.object.select_all(action='DESELECT') join_mesh = bpy.data.meshes.new('JOIN_MESH') @@ -177,7 +178,7 @@ def dataout_loop(): bpy.ops.object.join() writepipeline(b'OK') - hecl.hmdl.cook(writepipebuf, join_obj, maxSkinBanks) + hecl.hmdl.cook(writepipebuf, join_obj, maxSkinBanks, maxOctantLength) bpy.context.scene.objects.unlink(join_obj) bpy.data.objects.remove(join_obj) diff --git a/hecl/driver/ToolBase.hpp b/hecl/driver/ToolBase.hpp index 8361fdd3d..857b1ea68 100644 --- a/hecl/driver/ToolBase.hpp +++ b/hecl/driver/ToolBase.hpp @@ -262,7 +262,7 @@ void ToolPrintProgress(const HECL::SystemChar* message, const HECL::SystemChar* if (submessageLen) { if (messageLen > half-submessageLen-1) - HECL::Printf(_S("%.*s... "), half-int(submessageLen)-4, message); + HECL::Printf(_S("%.*s... %s "), half-int(submessageLen)-4, message, submessage); else { HECL::Printf(_S("%s"), message); diff --git a/hecl/include/HECL/HECL.hpp b/hecl/include/HECL/HECL.hpp index 3e3f4cff3..b993c3b98 100644 --- a/hecl/include/HECL/HECL.hpp +++ b/hecl/include/HECL/HECL.hpp @@ -469,10 +469,10 @@ public: /** * @brief Make absolute path project relative - * @param absPath - * @return + * @param absPath Absolute path + * @return SystemString of path relative to project root */ - const SystemString getProjectRelativeFromAbsolute(const SystemString& absPath) const + SystemString getProjectRelativeFromAbsolute(const SystemString& absPath) const { if (absPath.size() > m_projRoot.size()) { @@ -780,6 +780,18 @@ public: relTarget += target.m_relPath; MakeLink(relTarget.c_str(), m_absPath.c_str()); } + + /** + * @brief Fetch project that contains path + * @return Project + */ + Database::Project& getProject() const + { + if (!m_proj) + LogModule.report(LogVisor::FatalError, "ProjectPath::getProject() called on unqualified path"); + return *m_proj; + } + /** * @brief HECL-specific xxhash * @return unique hash value diff --git a/hecl/lib/Database/Project.cpp b/hecl/lib/Database/Project.cpp index 17c1a8af4..7fd6c852b 100644 --- a/hecl/lib/Database/Project.cpp +++ b/hecl/lib/Database/Project.cpp @@ -371,7 +371,8 @@ static void VisitFile(const ProjectPath& path, if (spec.second->canCook(path)) { ProjectPath cooked = path.getCookedPath(*spec.first); - if (path.getModtime() > cooked.getModtime()) + if (cooked.getPathType() == ProjectPath::PT_NONE || + path.getModtime() > cooked.getModtime()) { progress.reportFile(spec.first); spec.second->doCook(path, cooked); @@ -398,6 +399,13 @@ static void VisitDirectory(const ProjectPath& dir, bool recursive, ++childFileCount; break; } + case ProjectPath::PT_LINK: + { + ProjectPath target = child.resolveLink(); + if (target.getPathType() == ProjectPath::PT_FILE) + ++childFileCount; + break; + } default: break; } } @@ -416,6 +424,16 @@ static void VisitDirectory(const ProjectPath& dir, bool recursive, VisitFile(child, specInsts, progress); break; } + case ProjectPath::PT_LINK: + { + ProjectPath target = child.resolveLink(); + if (target.getPathType() == ProjectPath::PT_FILE) + { + progress.changeFile(target.getLastComponent(), progNum++/progDenom); + VisitFile(target, specInsts, progress); + } + break; + } default: break; } } @@ -457,6 +475,13 @@ static void VisitGlob(const ProjectPath& path, bool recursive, ++childFileCount; break; } + case ProjectPath::PT_LINK: + { + ProjectPath target = path.resolveLink(); + if (target.getPathType() == ProjectPath::PT_FILE) + ++childFileCount; + break; + } default: break; } } @@ -475,6 +500,16 @@ static void VisitGlob(const ProjectPath& path, bool recursive, VisitFile(child, specInsts, progress); break; } + case ProjectPath::PT_LINK: + { + ProjectPath target = path.resolveLink(); + if (target.getPathType() == ProjectPath::PT_FILE) + { + progress.changeFile(target.getLastComponent(), progNum++/progDenom); + VisitFile(target, specInsts, progress); + } + break; + } default: break; } } @@ -518,6 +553,16 @@ bool Project::cookPath(const ProjectPath& path, FProgress progress, bool recursi VisitFile(path, specInsts, cookProg); break; } + case ProjectPath::PT_LINK: + { + ProjectPath target = path.resolveLink(); + if (target.getPathType() == ProjectPath::PT_FILE) + { + cookProg.changeFile(target.getLastComponent(), 0.0); + VisitFile(target, specInsts, cookProg); + } + break; + } case ProjectPath::PT_DIRECTORY: { VisitDirectory(path, recursive, specInsts, cookProg); diff --git a/hecl/lib/HECL.cpp b/hecl/lib/HECL.cpp index 1acd7d4f5..f61434306 100644 --- a/hecl/lib/HECL.cpp +++ b/hecl/lib/HECL.cpp @@ -49,6 +49,9 @@ bool IsPathPNG(const HECL::ProjectPath& path) bool IsPathBlend(const HECL::ProjectPath& path) { + const SystemChar* lastCompExt = path.getLastComponentExt(); + if (!lastCompExt || HECL::StrCmp(lastCompExt, _S("blend"))) + return false; FILE* fp = HECL::Fopen(path.getAbsolutePath().c_str(), _S("rb")); if (!fp) return false; diff --git a/hecl/lib/ProjectPath.cpp b/hecl/lib/ProjectPath.cpp index c4cd77058..be6365eac 100644 --- a/hecl/lib/ProjectPath.cpp +++ b/hecl/lib/ProjectPath.cpp @@ -225,7 +225,7 @@ ProjectPath ProjectPath::resolveLink() const LogModule.report(LogVisor::FatalError, _S("unable to resolve link '%s': %s"), m_absPath.c_str(), strerror(errno)); target[targetSz] = '\0'; #endif - return ProjectPath(*this, target); + return ProjectPath(getParentPath(), target); } static void _recursiveGlob(Database::Project& proj,