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 <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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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))
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue