mirror of https://github.com/AxioDL/metaforce.git
Mesh cooker updates
This commit is contained in:
parent
f0325f7946
commit
135a7ced5d
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue