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 <string>
#include <HECL/HECL.hpp> #include <HECL/HECL.hpp>
#include <HECL/Database.hpp>
#include <LogVisor/LogVisor.hpp> #include <LogVisor/LogVisor.hpp>
#include "BlenderConnection.hpp" #include "BlenderConnection.hpp"
@ -351,7 +352,7 @@ static const char* BlendTypeStrs[] =
nullptr nullptr
}; };
bool BlenderConnection::createBlend(const SystemString& path, BlendType type) bool BlenderConnection::createBlend(const ProjectPath& path, BlendType type)
{ {
if (m_lock) if (m_lock)
{ {
@ -359,8 +360,7 @@ bool BlenderConnection::createBlend(const SystemString& path, BlendType type)
"BlenderConnection::createBlend() musn't be called with stream active"); "BlenderConnection::createBlend() musn't be called with stream active");
return false; return false;
} }
HECL::SystemUTF8View pathView(path); _writeLine(("CREATE \"" + path.getAbsolutePathUTF8() + "\" " + BlendTypeStrs[type] + " \"" + m_startupBlend + "\"").c_str());
_writeLine(("CREATE \"" + pathView.str() + "\" " + BlendTypeStrs[type] + " \"" + m_startupBlend + "\"").c_str());
char lineBuf[256]; char lineBuf[256];
_readLine(lineBuf, sizeof(lineBuf)); _readLine(lineBuf, sizeof(lineBuf));
if (!strcmp(lineBuf, "FINISHED")) if (!strcmp(lineBuf, "FINISHED"))
@ -372,7 +372,7 @@ bool BlenderConnection::createBlend(const SystemString& path, BlendType type)
return false; return false;
} }
bool BlenderConnection::openBlend(const SystemString& path) bool BlenderConnection::openBlend(const ProjectPath& path)
{ {
if (m_lock) if (m_lock)
{ {
@ -382,8 +382,7 @@ bool BlenderConnection::openBlend(const SystemString& path)
} }
if (path == m_loadedBlend) if (path == m_loadedBlend)
return true; return true;
HECL::SystemUTF8View pathView(path); _writeLine(("OPEN \"" + path.getAbsolutePathUTF8() + "\"").c_str());
_writeLine(("OPEN \"" + pathView.str() + "\"").c_str());
char lineBuf[256]; char lineBuf[256];
_readLine(lineBuf, sizeof(lineBuf)); _readLine(lineBuf, sizeof(lineBuf));
if (!strcmp(lineBuf, "FINISHED")) if (!strcmp(lineBuf, "FINISHED"))
@ -425,11 +424,11 @@ bool BlenderConnection::saveBlend()
void BlenderConnection::deleteBlend() void BlenderConnection::deleteBlend()
{ {
if (m_loadedBlend.size()) if (m_loadedBlend)
{ {
HECL::Unlink(m_loadedBlend.c_str()); HECL::Unlink(m_loadedBlend.getAbsolutePath().c_str());
BlenderLog.report(LogVisor::Info, _S("Deleted '%s'"), m_loadedBlend.c_str()); BlenderLog.report(LogVisor::Info, _S("Deleted '%s'"), m_loadedBlend.getAbsolutePath().c_str());
m_loadedBlend.clear(); m_loadedBlend = ProjectPath();
} }
} }
@ -568,7 +567,14 @@ BlenderConnection::DataStream::Mesh::Material::Material
for (int i=0 ; i<texCount ; ++i) for (int i=0 ; i<texCount ; ++i)
{ {
conn._readLine(buf, 4096); 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_readpipe[2];
int m_writepipe[2]; int m_writepipe[2];
BlendType m_loadedType = TypeNone; BlendType m_loadedType = TypeNone;
SystemString m_loadedBlend; ProjectPath m_loadedBlend;
std::string m_startupBlend; std::string m_startupBlend;
size_t _readLine(char* buf, size_t bufSz); size_t _readLine(char* buf, size_t bufSz);
size_t _writeLine(const char* buf); size_t _writeLine(const char* buf);
@ -57,9 +57,9 @@ public:
BlenderConnection(int verbosityLevel=1); BlenderConnection(int verbosityLevel=1);
~BlenderConnection(); ~BlenderConnection();
bool createBlend(const SystemString& path, BlendType type); bool createBlend(const ProjectPath& path, BlendType type);
BlendType getBlendType() const {return m_loadedType;} BlendType getBlendType() const {return m_loadedType;}
bool openBlend(const SystemString& path); bool openBlend(const ProjectPath& path);
bool saveBlend(); bool saveBlend();
void deleteBlend(); void deleteBlend();
@ -287,7 +287,7 @@ public:
struct Material struct Material
{ {
std::string source; std::string source;
std::vector<std::string> texs; std::vector<ProjectPath> texs;
Material(BlenderConnection& conn); Material(BlenderConnection& conn);
}; };
@ -400,10 +400,10 @@ public:
} }
/* Compile all meshes into one */ /* Compile all meshes into one */
Mesh compileAllMeshes(int skinSlotCount=10) Mesh compileAllMeshes(int skinSlotCount=10, float maxOctantLength=5.0)
{ {
char req[128]; char req[128];
snprintf(req, 128, "MESHCOMPILEALL %d", skinSlotCount); snprintf(req, 128, "MESHCOMPILEALL %d %f", skinSlotCount, maxOctantLength);
m_parent->_writeLine(req); m_parent->_writeLine(req);
char readBuf[256]; char readBuf[256];

View File

@ -10,7 +10,8 @@ from mathutils import Vector
class VertPool: class VertPool:
# Initialize hash-unique index for each available attribute # 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.pos = {}
self.norm = {} self.norm = {}
self.skin = {} self.skin = {}
@ -40,9 +41,10 @@ class VertPool:
pf = v.co.copy().freeze() pf = v.co.copy().freeze()
if pf not in self.pos: if pf not in self.pos:
self.pos[pf] = len(self.pos) self.pos[pf] = len(self.pos)
nf = v.normal.copy().freeze() if not rna_loops:
if nf not in self.norm: nf = v.normal.copy().freeze()
self.norm[nf] = len(self.norm) if nf not in self.norm:
self.norm[nf] = len(self.norm)
if dlay: if dlay:
sf = tuple(sorted(v[dlay].items())) sf = tuple(sorted(v[dlay].items()))
if sf not in self.skin: if sf not in self.skin:
@ -51,6 +53,10 @@ class VertPool:
# Per-loop pool attributes # Per-loop pool attributes
for f in bm.faces: for f in bm.faces:
for l in f.loops: 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)): for cl in range(len(clays)):
cf = l[clays[cl]].copy().freeze() cf = l[clays[cl]].copy().freeze()
if cf not in self.color: if cf not in self.color:
@ -60,44 +66,47 @@ class VertPool:
if uf not in self.uv: if uf not in self.uv:
self.uv[uf] = len(self.uv) self.uv[uf] = len(self.uv)
def write_out(self, writebuffunc, vert_groups): def write_out(self, writebuf, vert_groups):
writebuffunc(struct.pack('I', len(self.pos))) writebuf(struct.pack('I', len(self.pos)))
for p in sorted(self.pos.items(), key=operator.itemgetter(1)): 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)): 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)): 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)): 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: 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)): for s in sorted(self.skin.items(), key=operator.itemgetter(1)):
entries = s[0] entries = s[0]
writebuffunc(struct.pack('I', len(entries))) writebuf(struct.pack('I', len(entries)))
if len(entries): if len(entries):
total_len = 0.0 total_len = 0.0
for ent in entries: for ent in entries:
total_len += ent[1] total_len += ent[1]
for ent in entries: 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): def get_pos_idx(self, vert):
pf = vert.co.copy().freeze() pf = vert.co.copy().freeze()
return self.pos[pf] return self.pos[pf]
def get_norm_idx(self, vert): def get_norm_idx(self, loop):
nf = vert.normal.copy().freeze() if self.rna_loops:
nf = self.rna_loops[loop.index].normal.copy().freeze()
else:
nf = loop.vert.normal.copy().freeze()
return self.norm[nf] return self.norm[nf]
def get_skin_idx(self, vert): def get_skin_idx(self, vert):
@ -114,19 +123,19 @@ class VertPool:
uf = loop[self.ulays[uidx]].uv.copy().freeze() uf = loop[self.ulays[uidx]].uv.copy().freeze()
return self.uv[uf] return self.uv[uf]
def loop_out(self, writebuffunc, loop): def loop_out(self, writebuf, loop):
writebuffunc(struct.pack('B', 1)) writebuf(struct.pack('B', 1))
writebuffunc(struct.pack('II', self.get_pos_idx(loop.vert), self.get_norm_idx(loop.vert))) writebuf(struct.pack('II', self.get_pos_idx(loop.vert), self.get_norm_idx(loop)))
for cl in range(len(self.clays)): 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)): 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)) 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): def recursive_faces_islands(dlay, list_out, rem_list, skin_slot_set, skin_slot_count, face):
if face not in rem_list: if face not in rem_list:
return None return []
if dlay: if dlay:
for v in face.verts: 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) list_out.append(face)
rem_list.remove(face) rem_list.remove(face)
next_faces = []
for e in face.edges: for e in face.edges:
if not e.is_contiguous: if not e.is_contiguous:
continue continue
for f in e.link_faces: for f in e.link_faces:
if f == face: if f == face:
continue continue
if recursive_faces_islands(dlay, list_out, rem_list, skin_slot_set, skin_slot_count, f) == False: next_faces.append(f)
return False return next_faces
def find_opposite_edge(face, boot_edge, boot_edge2, last_edge, last_edge_2): def find_opposite_edge(face, boot_edge, boot_edge2, last_edge, last_edge_2):
if 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): 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: if face not in rem_list:
return return None, None, None
list_out.append(face) list_out.append(face)
rem_list.remove(face) rem_list.remove(face)
edge = find_opposite_edge(face, boot_edge, boot_edge_2, last_edge, last_edge_2) edge = find_opposite_edge(face, boot_edge, boot_edge_2, last_edge, last_edge_2)
if not edge: if not edge:
return return None, None, None
for f in edge.link_faces: for f in edge.link_faces:
if f == face: if f == face:
continue continue
recursive_faces_strip(list_out, rem_list, f, boot_edge, boot_edge_2, edge, last_edge) return f, edge, last_edge
break return None, None, None
def count_contiguous_edges(face): def count_contiguous_edges(face):
retval = 0 retval = 0
@ -188,42 +198,42 @@ def find_loop_opposite_from_other_face(face, other_face):
continue continue
return l 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: if last_loop:
vert_pool.loop_out(writebuffunc, last_loop) vert_pool.loop_out(writebuf, last_loop)
last_idx += 1 next_idx += 1
if len(prim_faces) == 1: if len(prim_faces) == 1:
loop = prim_faces[0].loops[0] loop = prim_faces[0].loops[0]
if last_loop: if last_loop:
vert_pool.loop_out(writebuffunc, loop) vert_pool.loop_out(writebuf, loop)
last_idx += 1 next_idx += 1
if last_idx & 1: if next_idx & 1:
rev = True rev = True
else: else:
rev = False rev = False
for i in range(3): for i in range(3):
vert_pool.loop_out(writebuffunc, loop) vert_pool.loop_out(writebuf, loop)
last_loop = loop last_loop = loop
last_idx += 1 next_idx += 1
if rev: if rev:
loop = loop.link_loop_prev loop = loop.link_loop_prev
else: else:
loop = loop.link_loop_next 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]) loop = find_loop_opposite_from_other_face(prim_faces[0], prim_faces[1])
if last_loop: if last_loop:
vert_pool.loop_out(writebuffunc, loop) vert_pool.loop_out(writebuf, loop)
last_idx += 1 next_idx += 1
if last_idx & 1: if next_idx & 1:
rev = True rev = True
else: else:
rev = False rev = False
for i in range(3): for i in range(3):
vert_pool.loop_out(writebuffunc, loop) vert_pool.loop_out(writebuf, loop)
last_loop = loop last_loop = loop
last_idx += 1 next_idx += 1
if rev: if rev:
loop = loop.link_loop_prev loop = loop.link_loop_prev
else: 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)): for i in range(1, len(prim_faces)):
loop = find_loop_opposite_from_other_face(prim_faces[i], prim_faces[i-1]) 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_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 of surface
centroid = Vector() centroid = Vector()
for f in island_faces: for f in island_faces:
centroid += f.calc_center_bounds() centroid += f.calc_center_bounds()
centroid /= len(island_faces) 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 # Material index
writebuffunc(struct.pack('I', mat_idx)) writebuf(struct.pack('I', mat_idx))
# AABB of surface # AABB of surface
aabb_min = Vector((9999999, 9999999, 9999999)) 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] aabb_min[c] = v.co[c]
if v.co[c] > aabb_max[c]: if v.co[c] > aabb_max[c]:
aabb_max[c] = v.co[c] aabb_max[c] = v.co[c]
writebuffunc(struct.pack('fff', aabb_min[0], aabb_min[1], aabb_min[2])) writebuf(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_max[0], aabb_max[1], aabb_max[2]))
# Average normal of surface # Average normal of surface
avg_norm = Vector() avg_norm = Vector()
for f in island_faces: for f in island_faces:
avg_norm += f.normal avg_norm += f.normal
avg_norm.normalize() 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 # Count estimate
writebuffunc(struct.pack('I', len(island_faces) * 3)) writebuf(struct.pack('I', len(island_faces) * 3))
# Verts themselves # Verts themselves
last_loop = None last_loop = None
last_idx = 0 next_idx = 0
while len(island_faces): while len(island_faces):
sel_lists_local = [] sel_lists_local = []
for start_face in island_faces: 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: for e2 in next_edges:
island_local = list(island_faces) island_local = list(island_faces)
sel_list = [] sel_list = []
recursive_faces_strip(sel_list, island_local, start_face, e, e2, None, None) next_face = start_face
sel_lists_local.append(sel_list) 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_count = 0
max_sl = None max_sl = None
for sl in sel_lists_local: for sl in sel_lists_local:
@ -304,6 +320,6 @@ def write_out_surface(writebuffunc, vert_pool, island_faces, mat_idx):
max_sl = sl max_sl = sl
for f in max_sl: for f in max_sl:
island_faces.remove(f) island_faces.remove(f)
last_loop, last_idx = stripify_primitive(writebuffunc, vert_pool, max_sl, last_loop, last_idx) last_loop, next_idx = stripify_primitive(writebuf, vert_pool, max_sl, last_loop, next_idx)
writebuffunc(struct.pack('B', 0)) 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) # Takes a Blender 'Mesh' object (not the datablock)
# and performs a one-shot conversion process to HMDL; packaging # and performs a one-shot conversion process to HMDL; packaging
# into the HECL data-pipeline and returning a hash once complete # 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': if mesh_obj.type != 'MESH':
raise RuntimeError("%s is not a mesh" % mesh_obj.name) 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_name = mesh_obj.name + "_hmdltri"
copy_mesh = bpy.data.meshes.new(copy_name) copy_mesh = bpy.data.meshes.new(copy_name)
copy_obj = bpy.data.objects.new(copy_name, copy_mesh) copy_obj = bpy.data.objects.new(copy_name, copy_mesh)
copy_obj.data = mesh_obj.to_mesh(bpy.context.scene, True, 'RENDER') copy_obj.data = mesh_obj.to_mesh(bpy.context.scene, True, 'RENDER')
copy_mesh = copy_obj.data
copy_obj.scale = mesh_obj.scale copy_obj.scale = mesh_obj.scale
bpy.context.scene.objects.link(copy_obj) 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 = bmesh.new()
bm_master.from_mesh(copy_obj.data) bm_master.from_mesh(copy_obj.data)
bmesh.ops.triangulate(bm_master, faces=bm_master.faces) vert_pool = HMDLMesh.VertPool(bm_master, rna_loops)
vert_pool = HMDLMesh.VertPool(bm_master)
# Sort materials by pass index first # Sort materials by pass index first
sorted_material_idxs = [] sorted_material_idxs = []
@ -101,34 +113,34 @@ def cook(writebuffunc, mesh_obj, max_skin_banks):
# Generate shaders # Generate shaders
if mesh_obj.data.hecl_material_count > 0: 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): 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: for mat_idx in sorted_material_idxs:
found = False found = False
for mat in bpy.data.materials: for mat in bpy.data.materials:
if mat.name.endswith('_%u_%u' % (grp_idx, mat_idx)): if mat.name.endswith('_%u_%u' % (grp_idx, mat_idx)):
hecl_str, texs = HMDLShader.shader(mat, mesh_obj) hecl_str, texs = HMDLShader.shader(mat, mesh_obj)
writebuffunc((hecl_str + '\n').encode()) writebuf((hecl_str + '\n').encode())
writebuffunc(struct.pack('I', len(texs))) writebuf(struct.pack('I', len(texs)))
for tex in texs: for tex in texs:
writebuffunc((tex + '\n').encode()) writebuf((tex + '\n').encode())
found = True found = True
break break
if not found: if not found:
raise RuntimeError('uneven material set %d in %s' % (grp_idx, mesh_obj.name)) raise RuntimeError('uneven material set %d in %s' % (grp_idx, mesh_obj.name))
else: 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: for mat_idx in sorted_material_idxs:
mat = mesh_obj.data.materials[mat_idx] mat = mesh_obj.data.materials[mat_idx]
hecl_str, texs = HMDLShader.shader(mat, mesh_obj) hecl_str, texs = HMDLShader.shader(mat, mesh_obj)
writebuffunc((hecl_str + '\n').encode()) writebuf((hecl_str + '\n').encode())
writebuffunc(struct.pack('I', len(texs))) writebuf(struct.pack('I', len(texs)))
for tex in texs: for tex in texs:
writebuffunc((tex + '\n').encode()) writebuf((tex + '\n').encode())
# Output vert pool # Output vert pool
vert_pool.write_out(writebuffunc, mesh_obj.vertex_groups) vert_pool.write_out(writebuf, mesh_obj.vertex_groups)
dlay = None dlay = None
if len(bm_master.verts.layers.deform): if len(bm_master.verts.layers.deform):
@ -143,13 +155,27 @@ def cook(writebuffunc, mesh_obj, max_skin_banks):
while len(mat_faces_rem): while len(mat_faces_rem):
the_list = [] the_list = []
skin_slot_set = set() skin_slot_set = set()
HMDLMesh.recursive_faces_islands(dlay, the_list, mat_faces_rem, skin_slot_set, faces = [mat_faces_rem[0]]
max_skin_banks, mat_faces_rem[0]) while len(faces):
writebuffunc(struct.pack('B', 1)) next_faces = []
HMDLMesh.write_out_surface(writebuffunc, vert_pool, the_list, mat_idx) 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 # No more surfaces
writebuffunc(struct.pack('B', 0)) writebuf(struct.pack('B', 0))
# Filter out useless AABB points and generate data array # Filter out useless AABB points and generate data array
#aabb = bytearray() #aabb = bytearray()

View File

@ -167,6 +167,7 @@ def dataout_loop():
elif cmdargs[0] == 'MESHCOMPILEALL': elif cmdargs[0] == 'MESHCOMPILEALL':
maxSkinBanks = int(cmdargs[1]) maxSkinBanks = int(cmdargs[1])
maxOctantLength = float(cmdargs[2])
bpy.ops.object.select_all(action='DESELECT') bpy.ops.object.select_all(action='DESELECT')
join_mesh = bpy.data.meshes.new('JOIN_MESH') join_mesh = bpy.data.meshes.new('JOIN_MESH')
@ -177,7 +178,7 @@ def dataout_loop():
bpy.ops.object.join() bpy.ops.object.join()
writepipeline(b'OK') 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.context.scene.objects.unlink(join_obj)
bpy.data.objects.remove(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 (submessageLen)
{ {
if (messageLen > half-submessageLen-1) 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 else
{ {
HECL::Printf(_S("%s"), message); HECL::Printf(_S("%s"), message);

View File

@ -469,10 +469,10 @@ public:
/** /**
* @brief Make absolute path project relative * @brief Make absolute path project relative
* @param absPath * @param absPath Absolute path
* @return * @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()) if (absPath.size() > m_projRoot.size())
{ {
@ -780,6 +780,18 @@ public:
relTarget += target.m_relPath; relTarget += target.m_relPath;
MakeLink(relTarget.c_str(), m_absPath.c_str()); 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 * @brief HECL-specific xxhash
* @return unique hash value * @return unique hash value

View File

@ -371,7 +371,8 @@ static void VisitFile(const ProjectPath& path,
if (spec.second->canCook(path)) if (spec.second->canCook(path))
{ {
ProjectPath cooked = path.getCookedPath(*spec.first); 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); progress.reportFile(spec.first);
spec.second->doCook(path, cooked); spec.second->doCook(path, cooked);
@ -398,6 +399,13 @@ static void VisitDirectory(const ProjectPath& dir, bool recursive,
++childFileCount; ++childFileCount;
break; break;
} }
case ProjectPath::PT_LINK:
{
ProjectPath target = child.resolveLink();
if (target.getPathType() == ProjectPath::PT_FILE)
++childFileCount;
break;
}
default: break; default: break;
} }
} }
@ -416,6 +424,16 @@ static void VisitDirectory(const ProjectPath& dir, bool recursive,
VisitFile(child, specInsts, progress); VisitFile(child, specInsts, progress);
break; 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; default: break;
} }
} }
@ -457,6 +475,13 @@ static void VisitGlob(const ProjectPath& path, bool recursive,
++childFileCount; ++childFileCount;
break; break;
} }
case ProjectPath::PT_LINK:
{
ProjectPath target = path.resolveLink();
if (target.getPathType() == ProjectPath::PT_FILE)
++childFileCount;
break;
}
default: break; default: break;
} }
} }
@ -475,6 +500,16 @@ static void VisitGlob(const ProjectPath& path, bool recursive,
VisitFile(child, specInsts, progress); VisitFile(child, specInsts, progress);
break; 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; default: break;
} }
} }
@ -518,6 +553,16 @@ bool Project::cookPath(const ProjectPath& path, FProgress progress, bool recursi
VisitFile(path, specInsts, cookProg); VisitFile(path, specInsts, cookProg);
break; 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: case ProjectPath::PT_DIRECTORY:
{ {
VisitDirectory(path, recursive, specInsts, cookProg); VisitDirectory(path, recursive, specInsts, cookProg);

View File

@ -49,6 +49,9 @@ bool IsPathPNG(const HECL::ProjectPath& path)
bool IsPathBlend(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")); FILE* fp = HECL::Fopen(path.getAbsolutePath().c_str(), _S("rb"));
if (!fp) if (!fp)
return false; 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)); LogModule.report(LogVisor::FatalError, _S("unable to resolve link '%s': %s"), m_absPath.c_str(), strerror(errno));
target[targetSz] = '\0'; target[targetSz] = '\0';
#endif #endif
return ProjectPath(*this, target); return ProjectPath(getParentPath(), target);
} }
static void _recursiveGlob(Database::Project& proj, static void _recursiveGlob(Database::Project& proj,