mirror of
https://github.com/AxioDL/metaforce.git
synced 2025-07-07 14:45:51 +00:00
Added fast mode for mesh cooking
This commit is contained in:
parent
87b86b7553
commit
bcee8aa897
@ -17,6 +17,19 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
template <> struct hash<std::pair<uint32_t,uint32_t>>
|
||||||
|
{
|
||||||
|
size_t operator()(const std::pair<uint32_t,uint32_t>& val) const NOEXCEPT
|
||||||
|
{
|
||||||
|
/* this will potentially truncate the second value if 32-bit size_t,
|
||||||
|
* however, its application here is intended to operate in 16-bit indices */
|
||||||
|
return val.first | (val.second << 16);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
namespace HECL
|
namespace HECL
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -219,7 +232,7 @@ BlenderConnection::BlenderConnection(int verbosityLevel)
|
|||||||
wchar_t cmdLine[2048];
|
wchar_t cmdLine[2048];
|
||||||
_snwprintf(cmdLine, 2048, L" --background -P \"%s\" -- %" PRIuPTR " %" PRIuPTR " %d \"%s\"",
|
_snwprintf(cmdLine, 2048, L" --background -P \"%s\" -- %" PRIuPTR " %" PRIuPTR " %d \"%s\"",
|
||||||
blenderShellPath.c_str(), uintptr_t(writehandle), uintptr_t(readhandle),
|
blenderShellPath.c_str(), uintptr_t(writehandle), uintptr_t(readhandle),
|
||||||
verbosityLevel > 1 ? 1 : 0, blenderAddonPath.c_str());
|
verbosityLevel, blenderAddonPath.c_str());
|
||||||
|
|
||||||
STARTUPINFO sinfo = {sizeof(STARTUPINFO)};
|
STARTUPINFO sinfo = {sizeof(STARTUPINFO)};
|
||||||
HANDLE nulHandle = NULL;
|
HANDLE nulHandle = NULL;
|
||||||
@ -266,15 +279,15 @@ BlenderConnection::BlenderConnection(int verbosityLevel)
|
|||||||
snprintf(readfds, 32, "%d", m_writepipe[0]);
|
snprintf(readfds, 32, "%d", m_writepipe[0]);
|
||||||
char writefds[32];
|
char writefds[32];
|
||||||
snprintf(writefds, 32, "%d", m_readpipe[1]);
|
snprintf(writefds, 32, "%d", m_readpipe[1]);
|
||||||
char dverbose[32];
|
char vLevel[32];
|
||||||
snprintf(dverbose, 32, "%d", verbosityLevel > 1 ? 1 : 0);
|
snprintf(vLevel, 32, "%d", verbosityLevel);
|
||||||
|
|
||||||
/* Try user-specified blender first */
|
/* Try user-specified blender first */
|
||||||
if (blenderBin)
|
if (blenderBin)
|
||||||
{
|
{
|
||||||
execlp(blenderBin, blenderBin,
|
execlp(blenderBin, blenderBin,
|
||||||
"--background", "-P", blenderShellPath.c_str(),
|
"--background", "-P", blenderShellPath.c_str(),
|
||||||
"--", readfds, writefds, dverbose, blenderAddonPath.c_str(), NULL);
|
"--", readfds, writefds, vLevel, blenderAddonPath.c_str(), NULL);
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
{
|
{
|
||||||
snprintf(errbuf, 256, "NOLAUNCH %s\n", strerror(errno));
|
snprintf(errbuf, 256, "NOLAUNCH %s\n", strerror(errno));
|
||||||
@ -286,7 +299,7 @@ BlenderConnection::BlenderConnection(int verbosityLevel)
|
|||||||
/* Otherwise default blender */
|
/* Otherwise default blender */
|
||||||
execlp(DEFAULT_BLENDER_BIN, DEFAULT_BLENDER_BIN,
|
execlp(DEFAULT_BLENDER_BIN, DEFAULT_BLENDER_BIN,
|
||||||
"--background", "-P", blenderShellPath.c_str(),
|
"--background", "-P", blenderShellPath.c_str(),
|
||||||
"--", readfds, writefds, dverbose, blenderAddonPath.c_str(), NULL);
|
"--", readfds, writefds, vLevel, blenderAddonPath.c_str(), NULL);
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
{
|
{
|
||||||
snprintf(errbuf, 256, "NOLAUNCH %s\n", strerror(errno));
|
snprintf(errbuf, 256, "NOLAUNCH %s\n", strerror(errno));
|
||||||
@ -467,8 +480,9 @@ void BlenderConnection::PyOutStream::linkBlend(const std::string& target,
|
|||||||
objName.c_str(), objName.c_str(), target.c_str(), objName.c_str());
|
objName.c_str(), objName.c_str(), target.c_str(), objName.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
BlenderConnection::DataStream::Mesh::Mesh(BlenderConnection& conn, int skinSlotCount)
|
BlenderConnection::DataStream::Mesh::Mesh
|
||||||
: aabbMin(conn), aabbMax(conn)
|
(BlenderConnection& conn, OutputMode outMode, int skinSlotCount, SurfProgFunc& surfProg)
|
||||||
|
: outputMode(outMode), aabbMin(conn), aabbMax(conn)
|
||||||
{
|
{
|
||||||
uint32_t matSetCount;
|
uint32_t matSetCount;
|
||||||
conn._readBuf(&matSetCount, 4);
|
conn._readBuf(&matSetCount, 4);
|
||||||
@ -538,9 +552,11 @@ BlenderConnection::DataStream::Mesh::Mesh(BlenderConnection& conn, int skinSlotC
|
|||||||
surfaces.reserve(materialSets.front().size() * 16);
|
surfaces.reserve(materialSets.front().size() * 16);
|
||||||
uint8_t isSurf;
|
uint8_t isSurf;
|
||||||
conn._readBuf(&isSurf, 1);
|
conn._readBuf(&isSurf, 1);
|
||||||
|
int prog = 0;
|
||||||
while (isSurf)
|
while (isSurf)
|
||||||
{
|
{
|
||||||
surfaces.emplace_back(conn, *this, skinSlotCount);
|
surfaces.emplace_back(conn, *this, skinSlotCount);
|
||||||
|
surfProg(++prog);
|
||||||
conn._readBuf(&isSurf, 1);
|
conn._readBuf(&isSurf, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -565,6 +581,48 @@ BlenderConnection::DataStream::Mesh::Mesh(BlenderConnection& conn, int skinSlotC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BlenderConnection::DataStream::Mesh
|
||||||
|
BlenderConnection::DataStream::Mesh::getContiguousSkinningVersion() const
|
||||||
|
{
|
||||||
|
Mesh newMesh = *this;
|
||||||
|
newMesh.pos.clear();
|
||||||
|
newMesh.norm.clear();
|
||||||
|
newMesh.contiguousSkinVertCounts.reserve(skins.size());
|
||||||
|
for (size_t i=0 ; i<skins.size() ; ++i)
|
||||||
|
{
|
||||||
|
std::unordered_map<std::pair<uint32_t,uint32_t>, uint32_t> contigMap;
|
||||||
|
size_t vertCount = 0;
|
||||||
|
for (Surface& surf : newMesh.surfaces)
|
||||||
|
{
|
||||||
|
for (Surface::Vert& vert : surf.verts)
|
||||||
|
{
|
||||||
|
if (vert.iSkin == i)
|
||||||
|
{
|
||||||
|
auto key = std::make_pair(vert.iPos, vert.iNorm);
|
||||||
|
auto search = contigMap.find(key);
|
||||||
|
if (search != contigMap.end())
|
||||||
|
{
|
||||||
|
vert.iPos = search->second;
|
||||||
|
vert.iNorm = search->second;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint32_t newIdx = newMesh.pos.size();
|
||||||
|
contigMap[key] = newIdx;
|
||||||
|
newMesh.pos.push_back(pos.at(vert.iPos));
|
||||||
|
newMesh.norm.push_back(norm.at(vert.iNorm));
|
||||||
|
vert.iPos = newIdx;
|
||||||
|
vert.iNorm = newIdx;
|
||||||
|
++vertCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newMesh.contiguousSkinVertCounts.push_back(vertCount);
|
||||||
|
}
|
||||||
|
return newMesh;
|
||||||
|
}
|
||||||
|
|
||||||
BlenderConnection::DataStream::Mesh::Material::Material
|
BlenderConnection::DataStream::Mesh::Material::Material
|
||||||
(BlenderConnection& conn)
|
(BlenderConnection& conn)
|
||||||
{
|
{
|
||||||
|
@ -305,6 +305,12 @@ public:
|
|||||||
operator const uint32_t&() const {return val;}
|
operator const uint32_t&() const {return val;}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum OutputMode
|
||||||
|
{
|
||||||
|
OutputTriangles,
|
||||||
|
OutputTriStrips,
|
||||||
|
} outputMode;
|
||||||
|
|
||||||
/* Cumulative AABB */
|
/* Cumulative AABB */
|
||||||
Vector3f aabbMin;
|
Vector3f aabbMin;
|
||||||
Vector3f aabbMax;
|
Vector3f aabbMax;
|
||||||
@ -338,6 +344,7 @@ public:
|
|||||||
SkinBind(BlenderConnection& conn) {conn._readBuf(&boneIdx, 8);}
|
SkinBind(BlenderConnection& conn) {conn._readBuf(&boneIdx, 8);}
|
||||||
};
|
};
|
||||||
std::vector<std::vector<SkinBind>> skins;
|
std::vector<std::vector<SkinBind>> skins;
|
||||||
|
std::vector<size_t> contiguousSkinVertCounts;
|
||||||
|
|
||||||
/* Islands of the same material/skinBank are represented here */
|
/* Islands of the same material/skinBank are represented here */
|
||||||
struct Surface
|
struct Surface
|
||||||
@ -380,14 +387,27 @@ public:
|
|||||||
uint32_t addSurface(const Surface& surf, int skinSlotCount);
|
uint32_t addSurface(const Surface& surf, int skinSlotCount);
|
||||||
} skinBanks;
|
} skinBanks;
|
||||||
|
|
||||||
Mesh(BlenderConnection& conn, int skinSlotCount);
|
using SurfProgFunc = std::function<void(int)>;
|
||||||
|
Mesh(BlenderConnection& conn, OutputMode outMode, int skinSlotCount, SurfProgFunc& surfProg);
|
||||||
|
|
||||||
|
Mesh getContiguousSkinningVersion() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static const char* MeshOutputModeString(Mesh::OutputMode mode)
|
||||||
|
{
|
||||||
|
static const char* STRS[] = {"TRIANGLES", "TRISTRIPS"};
|
||||||
|
return STRS[mode];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Compile mesh by context */
|
/* Compile mesh by context */
|
||||||
Mesh compileMesh(int skinSlotCount=10)
|
Mesh compileMesh(Mesh::OutputMode outMode, int skinSlotCount=10,
|
||||||
|
Mesh::SurfProgFunc surfProg=[](int){})
|
||||||
{
|
{
|
||||||
char req[128];
|
char req[128];
|
||||||
snprintf(req, 128, "MESHCOMPILE %d", skinSlotCount);
|
snprintf(req, 128, "MESHCOMPILE %s %d",
|
||||||
|
MeshOutputModeString(outMode), skinSlotCount);
|
||||||
m_parent->_writeLine(req);
|
m_parent->_writeLine(req);
|
||||||
|
|
||||||
char readBuf[256];
|
char readBuf[256];
|
||||||
@ -395,14 +415,16 @@ public:
|
|||||||
if (strcmp(readBuf, "OK"))
|
if (strcmp(readBuf, "OK"))
|
||||||
BlenderLog.report(LogVisor::FatalError, "unable to cook mesh: %s", readBuf);
|
BlenderLog.report(LogVisor::FatalError, "unable to cook mesh: %s", readBuf);
|
||||||
|
|
||||||
return Mesh(*m_parent, skinSlotCount);
|
return Mesh(*m_parent, outMode, skinSlotCount, surfProg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compile mesh by name */
|
/* Compile mesh by name */
|
||||||
Mesh compileMesh(const std::string& name, int skinSlotCount=10)
|
Mesh compileMesh(const std::string& name, Mesh::OutputMode outMode, int skinSlotCount=10,
|
||||||
|
Mesh::SurfProgFunc surfProg=[](int){})
|
||||||
{
|
{
|
||||||
char req[128];
|
char req[128];
|
||||||
snprintf(req, 128, "MESHCOMPILENAME %s %d", name.c_str(), skinSlotCount);
|
snprintf(req, 128, "MESHCOMPILENAME %s %s %d", name.c_str(),
|
||||||
|
MeshOutputModeString(outMode), skinSlotCount);
|
||||||
m_parent->_writeLine(req);
|
m_parent->_writeLine(req);
|
||||||
|
|
||||||
char readBuf[256];
|
char readBuf[256];
|
||||||
@ -410,14 +432,17 @@ public:
|
|||||||
if (strcmp(readBuf, "OK"))
|
if (strcmp(readBuf, "OK"))
|
||||||
BlenderLog.report(LogVisor::FatalError, "unable to cook mesh '%s': %s", name.c_str(), readBuf);
|
BlenderLog.report(LogVisor::FatalError, "unable to cook mesh '%s': %s", name.c_str(), readBuf);
|
||||||
|
|
||||||
return Mesh(*m_parent, skinSlotCount);
|
return Mesh(*m_parent, outMode, skinSlotCount, surfProg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compile all meshes into one */
|
/* Compile all meshes into one */
|
||||||
Mesh compileAllMeshes(int skinSlotCount=10, float maxOctantLength=5.0)
|
Mesh compileAllMeshes(Mesh::OutputMode outMode, int skinSlotCount=10, float maxOctantLength=5.0,
|
||||||
|
Mesh::SurfProgFunc surfProg=[](int){})
|
||||||
{
|
{
|
||||||
char req[128];
|
char req[128];
|
||||||
snprintf(req, 128, "MESHCOMPILEALL %d %f", skinSlotCount, maxOctantLength);
|
snprintf(req, 128, "MESHCOMPILEALL %s %d %f",
|
||||||
|
MeshOutputModeString(outMode),
|
||||||
|
skinSlotCount, maxOctantLength);
|
||||||
m_parent->_writeLine(req);
|
m_parent->_writeLine(req);
|
||||||
|
|
||||||
char readBuf[256];
|
char readBuf[256];
|
||||||
@ -425,7 +450,7 @@ public:
|
|||||||
if (strcmp(readBuf, "OK"))
|
if (strcmp(readBuf, "OK"))
|
||||||
BlenderLog.report(LogVisor::FatalError, "unable to cook all meshes: %s", readBuf);
|
BlenderLog.report(LogVisor::FatalError, "unable to cook all meshes: %s", readBuf);
|
||||||
|
|
||||||
return Mesh(*m_parent, skinSlotCount);
|
return Mesh(*m_parent, outMode, skinSlotCount, surfProg);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
DataStream beginData()
|
DataStream beginData()
|
||||||
|
@ -226,7 +226,7 @@ def strip_next_loop(prev_loop, out_count):
|
|||||||
loop = radial_loop.link_loop_next
|
loop = radial_loop.link_loop_next
|
||||||
return loop.link_loop_next, loop
|
return loop.link_loop_next, loop
|
||||||
|
|
||||||
def write_out_surface(writebuf, vert_pool, island_faces, mat_idx):
|
def write_out_surface(writebuf, output_mode, vert_pool, island_faces, mat_idx):
|
||||||
|
|
||||||
# Centroid of surface
|
# Centroid of surface
|
||||||
centroid = Vector()
|
centroid = Vector()
|
||||||
@ -258,10 +258,16 @@ def write_out_surface(writebuf, vert_pool, island_faces, mat_idx):
|
|||||||
avg_norm.normalize()
|
avg_norm.normalize()
|
||||||
writebuf(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 (as raw triangles)
|
||||||
writebuf(struct.pack('I', len(island_faces) * 3))
|
writebuf(struct.pack('I', len(island_faces) * 3))
|
||||||
|
|
||||||
# Verts themselves
|
# Verts themselves
|
||||||
|
if output_mode == 'TRIANGLES':
|
||||||
|
for f in island_faces:
|
||||||
|
for l in f.loops:
|
||||||
|
vert_pool.loop_out(writebuf, l)
|
||||||
|
|
||||||
|
elif output_mode == 'TRISTRIPS':
|
||||||
prev_loop_emit = None
|
prev_loop_emit = None
|
||||||
out_count = 0
|
out_count = 0
|
||||||
while len(island_faces):
|
while len(island_faces):
|
||||||
|
@ -91,7 +91,7 @@ def write_out_material(writebuf, mat, mesh_obj):
|
|||||||
# 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(writebuf, mesh_obj, max_skin_banks, max_octant_length=None):
|
def cook(writebuf, mesh_obj, output_mode, 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)
|
||||||
|
|
||||||
@ -207,7 +207,7 @@ def cook(writebuf, mesh_obj, max_skin_banks, max_octant_length=None):
|
|||||||
mat_faces_rem.remove(f)
|
mat_faces_rem.remove(f)
|
||||||
|
|
||||||
writebuf(struct.pack('B', 1))
|
writebuf(struct.pack('B', 1))
|
||||||
HMDLMesh.write_out_surface(writebuf, vert_pool, the_list, mat_idx)
|
HMDLMesh.write_out_surface(writebuf, output_mode, vert_pool, the_list, mat_idx)
|
||||||
|
|
||||||
|
|
||||||
# Generate island meshes (if transparent)
|
# Generate island meshes (if transparent)
|
||||||
@ -241,7 +241,7 @@ def cook(writebuf, mesh_obj, max_skin_banks, max_octant_length=None):
|
|||||||
faces = next_faces
|
faces = next_faces
|
||||||
|
|
||||||
writebuf(struct.pack('B', 1))
|
writebuf(struct.pack('B', 1))
|
||||||
HMDLMesh.write_out_surface(writebuf, vert_pool, the_list, mat_idx)
|
HMDLMesh.write_out_surface(writebuf, output_mode, vert_pool, the_list, mat_idx)
|
||||||
|
|
||||||
# No more surfaces
|
# No more surfaces
|
||||||
writebuf(struct.pack('B', 0))
|
writebuf(struct.pack('B', 0))
|
||||||
|
@ -9,7 +9,7 @@ if '--' not in sys.argv:
|
|||||||
args = sys.argv[sys.argv.index('--')+1:]
|
args = sys.argv[sys.argv.index('--')+1:]
|
||||||
readfd = int(args[0])
|
readfd = int(args[0])
|
||||||
writefd = int(args[1])
|
writefd = int(args[1])
|
||||||
double_verbose = int(args[2])
|
verbosity_level = int(args[2])
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
import msvcrt
|
import msvcrt
|
||||||
readfd = msvcrt.open_osfhandle(readfd, os.O_RDONLY | os.O_BINARY)
|
readfd = msvcrt.open_osfhandle(readfd, os.O_RDONLY | os.O_BINARY)
|
||||||
@ -89,7 +89,7 @@ def read_cmdargs():
|
|||||||
|
|
||||||
# Complete sequences of statements compiled/executed here
|
# Complete sequences of statements compiled/executed here
|
||||||
def exec_compbuf(compbuf, globals):
|
def exec_compbuf(compbuf, globals):
|
||||||
if double_verbose:
|
if verbosity_level >= 3:
|
||||||
print('EXEC', compbuf)
|
print('EXEC', compbuf)
|
||||||
co = compile(compbuf, '<HECL>', 'exec')
|
co = compile(compbuf, '<HECL>', 'exec')
|
||||||
exec(co, globals)
|
exec(co, globals)
|
||||||
@ -144,7 +144,7 @@ def dataout_loop():
|
|||||||
writepipeline(meshobj.name.encode())
|
writepipeline(meshobj.name.encode())
|
||||||
|
|
||||||
elif cmdargs[0] == 'MESHCOMPILE':
|
elif cmdargs[0] == 'MESHCOMPILE':
|
||||||
maxSkinBanks = int(cmdargs[1])
|
maxSkinBanks = int(cmdargs[2])
|
||||||
|
|
||||||
meshName = bpy.context.scene.hecl_mesh_obj
|
meshName = bpy.context.scene.hecl_mesh_obj
|
||||||
if meshName not in bpy.data.objects:
|
if meshName not in bpy.data.objects:
|
||||||
@ -152,22 +152,22 @@ def dataout_loop():
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
writepipeline(b'OK')
|
writepipeline(b'OK')
|
||||||
hecl.hmdl.cook(writepipebuf, bpy.data.objects[meshName], maxSkinBanks)
|
hecl.hmdl.cook(writepipebuf, bpy.data.objects[meshName], cmdargs[1], maxSkinBanks)
|
||||||
|
|
||||||
elif cmdargs[0] == 'MESHCOMPILENAME':
|
elif cmdargs[0] == 'MESHCOMPILENAME':
|
||||||
meshName = cmdargs[1]
|
meshName = cmdargs[1]
|
||||||
maxSkinBanks = int(cmdargs[2])
|
maxSkinBanks = int(cmdargs[3])
|
||||||
|
|
||||||
if meshName not in bpy.data.objects:
|
if meshName not in bpy.data.objects:
|
||||||
writepipeline(('mesh %s not found' % meshName).encode())
|
writepipeline(('mesh %s not found' % meshName).encode())
|
||||||
continue
|
continue
|
||||||
|
|
||||||
writepipeline(b'OK')
|
writepipeline(b'OK')
|
||||||
hecl.hmdl.cook(writepipebuf, bpy.data.objects[meshName], maxSkinBanks)
|
hecl.hmdl.cook(writepipebuf, bpy.data.objects[meshName], cmdargs[2], maxSkinBanks)
|
||||||
|
|
||||||
elif cmdargs[0] == 'MESHCOMPILEALL':
|
elif cmdargs[0] == 'MESHCOMPILEALL':
|
||||||
maxSkinBanks = int(cmdargs[1])
|
maxSkinBanks = int(cmdargs[2])
|
||||||
maxOctantLength = float(cmdargs[2])
|
maxOctantLength = float(cmdargs[3])
|
||||||
|
|
||||||
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')
|
||||||
@ -178,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, maxOctantLength)
|
hecl.hmdl.cook(writepipebuf, join_obj, cmdargs[1], 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)
|
||||||
|
@ -10,6 +10,7 @@ class ToolCook final : public ToolBase
|
|||||||
std::unique_ptr<HECL::Database::Project> m_fallbackProj;
|
std::unique_ptr<HECL::Database::Project> m_fallbackProj;
|
||||||
HECL::Database::Project* m_useProj;
|
HECL::Database::Project* m_useProj;
|
||||||
bool m_recursive = false;
|
bool m_recursive = false;
|
||||||
|
bool m_fast = false;
|
||||||
public:
|
public:
|
||||||
ToolCook(const ToolPassInfo& info)
|
ToolCook(const ToolPassInfo& info)
|
||||||
: ToolBase(info), m_useProj(info.project)
|
: ToolBase(info), m_useProj(info.project)
|
||||||
@ -28,6 +29,14 @@ public:
|
|||||||
{
|
{
|
||||||
if (arg.empty())
|
if (arg.empty())
|
||||||
continue;
|
continue;
|
||||||
|
else if (!arg.compare("--fast"))
|
||||||
|
{
|
||||||
|
m_fast = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (arg.size() >= 2 && arg[0] == _S('-') && arg[1] == _S('-'))
|
||||||
|
continue;
|
||||||
|
|
||||||
HECL::SystemString subPath;
|
HECL::SystemString subPath;
|
||||||
HECL::ProjectRootPath root = HECL::SearchForProject(MakePathArgAbsolute(arg, info.cwd), subPath);
|
HECL::ProjectRootPath root = HECL::SearchForProject(MakePathArgAbsolute(arg, info.cwd), subPath);
|
||||||
if (root)
|
if (root)
|
||||||
@ -70,7 +79,7 @@ public:
|
|||||||
|
|
||||||
help.secHead(_S("SYNOPSIS"));
|
help.secHead(_S("SYNOPSIS"));
|
||||||
help.beginWrap();
|
help.beginWrap();
|
||||||
help.wrap(_S("hecl cook [-rf] [<pathspec>...]\n"));
|
help.wrap(_S("hecl cook [-rf] [--fast] [<pathspec>...]\n"));
|
||||||
help.endWrap();
|
help.endWrap();
|
||||||
|
|
||||||
help.secHead(_S("DESCRIPTION"));
|
help.secHead(_S("DESCRIPTION"));
|
||||||
@ -117,6 +126,10 @@ public:
|
|||||||
help.beginWrap();
|
help.beginWrap();
|
||||||
help.wrap(_S("Forces cooking of all matched files, ignoring timestamp differences.\n"));
|
help.wrap(_S("Forces cooking of all matched files, ignoring timestamp differences.\n"));
|
||||||
help.endWrap();
|
help.endWrap();
|
||||||
|
help.optionHead(_S("--fast"), _S("fast cook"));
|
||||||
|
help.beginWrap();
|
||||||
|
help.wrap(_S("Performs draft-optimization cooking for supported data types.\n"));
|
||||||
|
help.endWrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
HECL::SystemString toolName() const {return _S("cook");}
|
HECL::SystemString toolName() const {return _S("cook");}
|
||||||
@ -131,7 +144,7 @@ public:
|
|||||||
const HECL::SystemChar* submessage,
|
const HECL::SystemChar* submessage,
|
||||||
int lidx, float factor)
|
int lidx, float factor)
|
||||||
{ToolPrintProgress(message, submessage, lidx, factor, lineIdx);},
|
{ToolPrintProgress(message, submessage, lidx, factor, lineIdx);},
|
||||||
m_recursive, m_info.force);
|
m_recursive, m_info.force, m_fast);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -189,7 +189,7 @@ int main(int argc, const char** argv)
|
|||||||
for (auto it = args.cbegin() ; it != args.cend() ;)
|
for (auto it = args.cbegin() ; it != args.cend() ;)
|
||||||
{
|
{
|
||||||
const HECL::SystemString& arg = *it;
|
const HECL::SystemString& arg = *it;
|
||||||
if (arg.empty() || arg[0] != _S('-'))
|
if (arg.size() < 2 || arg[0] != _S('-') || arg[1] == _S('-'))
|
||||||
{
|
{
|
||||||
++it;
|
++it;
|
||||||
continue;
|
continue;
|
||||||
|
@ -67,6 +67,7 @@ class IDataSpec
|
|||||||
public:
|
public:
|
||||||
virtual ~IDataSpec() {}
|
virtual ~IDataSpec() {}
|
||||||
using FProgress = FProgress;
|
using FProgress = FProgress;
|
||||||
|
using FCookProgress = std::function<void(const SystemChar*)>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Extract Pass Info
|
* @brief Extract Pass Info
|
||||||
@ -101,8 +102,9 @@ public:
|
|||||||
|
|
||||||
virtual bool canCook(const ProjectPath& path)
|
virtual bool canCook(const ProjectPath& path)
|
||||||
{(void)path;LogModule.report(LogVisor::Error, "not implemented");return false;}
|
{(void)path;LogModule.report(LogVisor::Error, "not implemented");return false;}
|
||||||
virtual void doCook(const ProjectPath& path, const ProjectPath& cookedPath)
|
virtual void doCook(const ProjectPath& path, const ProjectPath& cookedPath,
|
||||||
{(void)path;(void)cookedPath;}
|
bool fast, FCookProgress progress)
|
||||||
|
{(void)path;(void)cookedPath;(void)fast;(void)progress;}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Package Pass Info
|
* @brief Package Pass Info
|
||||||
@ -406,13 +408,15 @@ public:
|
|||||||
* @param path directory of intermediates to cook
|
* @param path directory of intermediates to cook
|
||||||
* @param feedbackCb a callback to run reporting cook-progress
|
* @param feedbackCb a callback to run reporting cook-progress
|
||||||
* @param recursive traverse subdirectories to cook as well
|
* @param recursive traverse subdirectories to cook as well
|
||||||
|
* @param fast enables faster (draft) extraction for supported data types
|
||||||
* @return true on success
|
* @return true on success
|
||||||
*
|
*
|
||||||
* Object cooking is generally an expensive process for large projects.
|
* Object cooking is generally an expensive process for large projects.
|
||||||
* This method blocks execution during the procedure, with periodic
|
* This method blocks execution during the procedure, with periodic
|
||||||
* feedback delivered via feedbackCb.
|
* feedback delivered via feedbackCb.
|
||||||
*/
|
*/
|
||||||
bool cookPath(const ProjectPath& path, FProgress feedbackCb, bool recursive=false, bool force=false);
|
bool cookPath(const ProjectPath& path, FProgress feedbackCb,
|
||||||
|
bool recursive=false, bool force=false, bool fast=false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Interrupts a cook in progress (call from SIGINT handler)
|
* @brief Interrupts a cook in progress (call from SIGINT handler)
|
||||||
|
@ -357,12 +357,22 @@ public:
|
|||||||
submsg += _S(')');
|
submsg += _S(')');
|
||||||
m_progFunc(m_dir, submsg.c_str(), lidx, m_prog);
|
m_progFunc(m_dir, submsg.c_str(), lidx, m_prog);
|
||||||
}
|
}
|
||||||
|
void reportFile(const DataSpecEntry* specEnt, const SystemChar* extra)
|
||||||
|
{
|
||||||
|
SystemString submsg(m_file);
|
||||||
|
submsg += _S(" (");
|
||||||
|
submsg += specEnt->m_name;
|
||||||
|
submsg += _S(", ");
|
||||||
|
submsg += extra;
|
||||||
|
submsg += _S(')');
|
||||||
|
m_progFunc(m_dir, submsg.c_str(), lidx, m_prog);
|
||||||
|
}
|
||||||
void reportDirComplete() {m_progFunc(m_dir, nullptr, lidx, 1.0);}
|
void reportDirComplete() {m_progFunc(m_dir, nullptr, lidx, 1.0);}
|
||||||
};
|
};
|
||||||
|
|
||||||
using SpecInst = std::pair<const DataSpecEntry*, std::unique_ptr<IDataSpec>>;
|
using SpecInst = std::pair<const DataSpecEntry*, std::unique_ptr<IDataSpec>>;
|
||||||
|
|
||||||
static void VisitFile(const ProjectPath& path, bool force,
|
static void VisitFile(const ProjectPath& path, bool force, bool fast,
|
||||||
std::vector<SpecInst>& specInsts,
|
std::vector<SpecInst>& specInsts,
|
||||||
CookProgress& progress)
|
CookProgress& progress)
|
||||||
{
|
{
|
||||||
@ -371,17 +381,24 @@ static void VisitFile(const ProjectPath& path, bool force,
|
|||||||
if (spec.second->canCook(path))
|
if (spec.second->canCook(path))
|
||||||
{
|
{
|
||||||
ProjectPath cooked = path.getCookedPath(*spec.first);
|
ProjectPath cooked = path.getCookedPath(*spec.first);
|
||||||
|
if (fast)
|
||||||
|
cooked = cooked.getWithExtension(".fast");
|
||||||
if (force || cooked.getPathType() == ProjectPath::PT_NONE ||
|
if (force || cooked.getPathType() == ProjectPath::PT_NONE ||
|
||||||
path.getModtime() > cooked.getModtime())
|
path.getModtime() > cooked.getModtime())
|
||||||
{
|
{
|
||||||
progress.reportFile(spec.first);
|
progress.reportFile(spec.first);
|
||||||
spec.second->doCook(path, cooked);
|
spec.second->doCook(path, cooked, fast,
|
||||||
|
[&](const SystemChar* extra)
|
||||||
|
{
|
||||||
|
progress.reportFile(spec.first, extra);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void VisitDirectory(const ProjectPath& dir, bool recursive, bool force,
|
static void VisitDirectory(const ProjectPath& dir,
|
||||||
|
bool recursive, bool force, bool fast,
|
||||||
std::vector<SpecInst>& specInsts,
|
std::vector<SpecInst>& specInsts,
|
||||||
CookProgress& progress)
|
CookProgress& progress)
|
||||||
{
|
{
|
||||||
@ -421,7 +438,7 @@ static void VisitDirectory(const ProjectPath& dir, bool recursive, bool force,
|
|||||||
case ProjectPath::PT_FILE:
|
case ProjectPath::PT_FILE:
|
||||||
{
|
{
|
||||||
progress.changeFile(child.first.c_str(), progNum++/progDenom);
|
progress.changeFile(child.first.c_str(), progNum++/progDenom);
|
||||||
VisitFile(child.second, force, specInsts, progress);
|
VisitFile(child.second, force, fast, specInsts, progress);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ProjectPath::PT_LINK:
|
case ProjectPath::PT_LINK:
|
||||||
@ -430,7 +447,7 @@ static void VisitDirectory(const ProjectPath& dir, bool recursive, bool force,
|
|||||||
if (target.getPathType() == ProjectPath::PT_FILE)
|
if (target.getPathType() == ProjectPath::PT_FILE)
|
||||||
{
|
{
|
||||||
progress.changeFile(target.getLastComponent(), progNum++/progDenom);
|
progress.changeFile(target.getLastComponent(), progNum++/progDenom);
|
||||||
VisitFile(target, force, specInsts, progress);
|
VisitFile(target, force, fast, specInsts, progress);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -448,7 +465,7 @@ static void VisitDirectory(const ProjectPath& dir, bool recursive, bool force,
|
|||||||
{
|
{
|
||||||
case ProjectPath::PT_DIRECTORY:
|
case ProjectPath::PT_DIRECTORY:
|
||||||
{
|
{
|
||||||
VisitDirectory(child.second, recursive, force, specInsts, progress);
|
VisitDirectory(child.second, recursive, force, fast, specInsts, progress);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: break;
|
default: break;
|
||||||
@ -457,7 +474,8 @@ static void VisitDirectory(const ProjectPath& dir, bool recursive, bool force,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void VisitGlob(const ProjectPath& path, bool recursive, bool force,
|
static void VisitGlob(const ProjectPath& path,
|
||||||
|
bool recursive, bool force, bool fast,
|
||||||
std::vector<SpecInst>& specInsts,
|
std::vector<SpecInst>& specInsts,
|
||||||
CookProgress& progress)
|
CookProgress& progress)
|
||||||
{
|
{
|
||||||
@ -497,7 +515,7 @@ static void VisitGlob(const ProjectPath& path, bool recursive, bool force,
|
|||||||
case ProjectPath::PT_FILE:
|
case ProjectPath::PT_FILE:
|
||||||
{
|
{
|
||||||
progress.changeFile(child.getLastComponent(), progNum++/progDenom);
|
progress.changeFile(child.getLastComponent(), progNum++/progDenom);
|
||||||
VisitFile(child, force, specInsts, progress);
|
VisitFile(child, force, fast, specInsts, progress);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ProjectPath::PT_LINK:
|
case ProjectPath::PT_LINK:
|
||||||
@ -506,7 +524,7 @@ static void VisitGlob(const ProjectPath& path, bool recursive, bool force,
|
|||||||
if (target.getPathType() == ProjectPath::PT_FILE)
|
if (target.getPathType() == ProjectPath::PT_FILE)
|
||||||
{
|
{
|
||||||
progress.changeFile(target.getLastComponent(), progNum++/progDenom);
|
progress.changeFile(target.getLastComponent(), progNum++/progDenom);
|
||||||
VisitFile(target, force, specInsts, progress);
|
VisitFile(target, force, fast, specInsts, progress);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -524,7 +542,7 @@ static void VisitGlob(const ProjectPath& path, bool recursive, bool force,
|
|||||||
{
|
{
|
||||||
case ProjectPath::PT_DIRECTORY:
|
case ProjectPath::PT_DIRECTORY:
|
||||||
{
|
{
|
||||||
VisitDirectory(child, recursive, force, specInsts, progress);
|
VisitDirectory(child, recursive, force, fast, specInsts, progress);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: break;
|
default: break;
|
||||||
@ -533,7 +551,8 @@ static void VisitGlob(const ProjectPath& path, bool recursive, bool force,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Project::cookPath(const ProjectPath& path, FProgress progress, bool recursive, bool force)
|
bool Project::cookPath(const ProjectPath& path, FProgress progress,
|
||||||
|
bool recursive, bool force, bool fast)
|
||||||
{
|
{
|
||||||
/* Construct DataSpec instances for cooking */
|
/* Construct DataSpec instances for cooking */
|
||||||
std::vector<SpecInst> specInsts;
|
std::vector<SpecInst> specInsts;
|
||||||
@ -550,7 +569,7 @@ bool Project::cookPath(const ProjectPath& path, FProgress progress, bool recursi
|
|||||||
case ProjectPath::PT_FILE:
|
case ProjectPath::PT_FILE:
|
||||||
{
|
{
|
||||||
cookProg.changeFile(path.getLastComponent(), 0.0);
|
cookProg.changeFile(path.getLastComponent(), 0.0);
|
||||||
VisitFile(path, force, specInsts, cookProg);
|
VisitFile(path, force, fast, specInsts, cookProg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ProjectPath::PT_LINK:
|
case ProjectPath::PT_LINK:
|
||||||
@ -559,18 +578,18 @@ bool Project::cookPath(const ProjectPath& path, FProgress progress, bool recursi
|
|||||||
if (target.getPathType() == ProjectPath::PT_FILE)
|
if (target.getPathType() == ProjectPath::PT_FILE)
|
||||||
{
|
{
|
||||||
cookProg.changeFile(target.getLastComponent(), 0.0);
|
cookProg.changeFile(target.getLastComponent(), 0.0);
|
||||||
VisitFile(target, force, specInsts, cookProg);
|
VisitFile(target, force, fast, specInsts, cookProg);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ProjectPath::PT_DIRECTORY:
|
case ProjectPath::PT_DIRECTORY:
|
||||||
{
|
{
|
||||||
VisitDirectory(path, recursive, force, specInsts, cookProg);
|
VisitDirectory(path, recursive, force, fast, specInsts, cookProg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ProjectPath::PT_GLOB:
|
case ProjectPath::PT_GLOB:
|
||||||
{
|
{
|
||||||
VisitGlob(path, recursive, force, specInsts, cookProg);
|
VisitGlob(path, recursive, force, fast, specInsts, cookProg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: break;
|
default: break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user