Mesh cooker updates

This commit is contained in:
Jack Andersen 2015-10-06 15:16:54 -10:00
parent f0325f7946
commit 135a7ced5d
10 changed files with 215 additions and 106 deletions

View File

@ -7,6 +7,7 @@
#include <string>
#include <HECL/HECL.hpp>
#include <HECL/Database.hpp>
#include <LogVisor/LogVisor.hpp>
#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<texCount ; ++i)
{
conn._readLine(buf, 4096);
texs.emplace_back(buf);
#if HECL_UCS2
SystemString absolute = HECL::UTF8ToWide(buf);
#else
SystemString absolute(buf);
#endif
SystemString relative =
conn.m_loadedBlend.getProject().getProjectRootPath().getProjectRelativeFromAbsolute(absolute);
texs.emplace_back(conn.m_loadedBlend.getProject().getProjectWorkingPath(), relative);
}
}

View File

@ -46,7 +46,7 @@ private:
int m_readpipe[2];
int m_writepipe[2];
BlendType m_loadedType = TypeNone;
SystemString m_loadedBlend;
ProjectPath m_loadedBlend;
std::string m_startupBlend;
size_t _readLine(char* buf, size_t bufSz);
size_t _writeLine(const char* buf);
@ -57,9 +57,9 @@ public:
BlenderConnection(int verbosityLevel=1);
~BlenderConnection();
bool createBlend(const SystemString& path, BlendType type);
bool createBlend(const ProjectPath& path, BlendType type);
BlendType getBlendType() const {return m_loadedType;}
bool openBlend(const SystemString& path);
bool openBlend(const ProjectPath& path);
bool saveBlend();
void deleteBlend();
@ -287,7 +287,7 @@ public:
struct Material
{
std::string source;
std::vector<std::string> texs;
std::vector<ProjectPath> 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];

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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;

View File

@ -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,