mirror of https://github.com/AxioDL/metaforce.git
Added fast mode for mesh cooking
This commit is contained in:
parent
87b86b7553
commit
bcee8aa897
|
@ -17,6 +17,19 @@
|
|||
#include <fcntl.h>
|
||||
#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
|
||||
{
|
||||
|
||||
|
@ -219,7 +232,7 @@ BlenderConnection::BlenderConnection(int verbosityLevel)
|
|||
wchar_t cmdLine[2048];
|
||||
_snwprintf(cmdLine, 2048, L" --background -P \"%s\" -- %" PRIuPTR " %" PRIuPTR " %d \"%s\"",
|
||||
blenderShellPath.c_str(), uintptr_t(writehandle), uintptr_t(readhandle),
|
||||
verbosityLevel > 1 ? 1 : 0, blenderAddonPath.c_str());
|
||||
verbosityLevel, blenderAddonPath.c_str());
|
||||
|
||||
STARTUPINFO sinfo = {sizeof(STARTUPINFO)};
|
||||
HANDLE nulHandle = NULL;
|
||||
|
@ -266,15 +279,15 @@ BlenderConnection::BlenderConnection(int verbosityLevel)
|
|||
snprintf(readfds, 32, "%d", m_writepipe[0]);
|
||||
char writefds[32];
|
||||
snprintf(writefds, 32, "%d", m_readpipe[1]);
|
||||
char dverbose[32];
|
||||
snprintf(dverbose, 32, "%d", verbosityLevel > 1 ? 1 : 0);
|
||||
char vLevel[32];
|
||||
snprintf(vLevel, 32, "%d", verbosityLevel);
|
||||
|
||||
/* Try user-specified blender first */
|
||||
if (blenderBin)
|
||||
{
|
||||
execlp(blenderBin, blenderBin,
|
||||
"--background", "-P", blenderShellPath.c_str(),
|
||||
"--", readfds, writefds, dverbose, blenderAddonPath.c_str(), NULL);
|
||||
"--", readfds, writefds, vLevel, blenderAddonPath.c_str(), NULL);
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
snprintf(errbuf, 256, "NOLAUNCH %s\n", strerror(errno));
|
||||
|
@ -286,7 +299,7 @@ BlenderConnection::BlenderConnection(int verbosityLevel)
|
|||
/* Otherwise default blender */
|
||||
execlp(DEFAULT_BLENDER_BIN, DEFAULT_BLENDER_BIN,
|
||||
"--background", "-P", blenderShellPath.c_str(),
|
||||
"--", readfds, writefds, dverbose, blenderAddonPath.c_str(), NULL);
|
||||
"--", readfds, writefds, vLevel, blenderAddonPath.c_str(), NULL);
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
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());
|
||||
}
|
||||
|
||||
BlenderConnection::DataStream::Mesh::Mesh(BlenderConnection& conn, int skinSlotCount)
|
||||
: aabbMin(conn), aabbMax(conn)
|
||||
BlenderConnection::DataStream::Mesh::Mesh
|
||||
(BlenderConnection& conn, OutputMode outMode, int skinSlotCount, SurfProgFunc& surfProg)
|
||||
: outputMode(outMode), aabbMin(conn), aabbMax(conn)
|
||||
{
|
||||
uint32_t matSetCount;
|
||||
conn._readBuf(&matSetCount, 4);
|
||||
|
@ -538,9 +552,11 @@ BlenderConnection::DataStream::Mesh::Mesh(BlenderConnection& conn, int skinSlotC
|
|||
surfaces.reserve(materialSets.front().size() * 16);
|
||||
uint8_t isSurf;
|
||||
conn._readBuf(&isSurf, 1);
|
||||
int prog = 0;
|
||||
while (isSurf)
|
||||
{
|
||||
surfaces.emplace_back(conn, *this, skinSlotCount);
|
||||
surfProg(++prog);
|
||||
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& conn)
|
||||
{
|
||||
|
|
|
@ -305,6 +305,12 @@ public:
|
|||
operator const uint32_t&() const {return val;}
|
||||
};
|
||||
|
||||
enum OutputMode
|
||||
{
|
||||
OutputTriangles,
|
||||
OutputTriStrips,
|
||||
} outputMode;
|
||||
|
||||
/* Cumulative AABB */
|
||||
Vector3f aabbMin;
|
||||
Vector3f aabbMax;
|
||||
|
@ -338,6 +344,7 @@ public:
|
|||
SkinBind(BlenderConnection& conn) {conn._readBuf(&boneIdx, 8);}
|
||||
};
|
||||
std::vector<std::vector<SkinBind>> skins;
|
||||
std::vector<size_t> contiguousSkinVertCounts;
|
||||
|
||||
/* Islands of the same material/skinBank are represented here */
|
||||
struct Surface
|
||||
|
@ -380,14 +387,27 @@ public:
|
|||
uint32_t addSurface(const Surface& surf, int skinSlotCount);
|
||||
} 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 */
|
||||
Mesh compileMesh(int skinSlotCount=10)
|
||||
Mesh compileMesh(Mesh::OutputMode outMode, int skinSlotCount=10,
|
||||
Mesh::SurfProgFunc surfProg=[](int){})
|
||||
{
|
||||
char req[128];
|
||||
snprintf(req, 128, "MESHCOMPILE %d", skinSlotCount);
|
||||
snprintf(req, 128, "MESHCOMPILE %s %d",
|
||||
MeshOutputModeString(outMode), skinSlotCount);
|
||||
m_parent->_writeLine(req);
|
||||
|
||||
char readBuf[256];
|
||||
|
@ -395,14 +415,16 @@ public:
|
|||
if (strcmp(readBuf, "OK"))
|
||||
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 */
|
||||
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];
|
||||
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);
|
||||
|
||||
char readBuf[256];
|
||||
|
@ -410,14 +432,17 @@ public:
|
|||
if (strcmp(readBuf, "OK"))
|
||||
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 */
|
||||
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];
|
||||
snprintf(req, 128, "MESHCOMPILEALL %d %f", skinSlotCount, maxOctantLength);
|
||||
snprintf(req, 128, "MESHCOMPILEALL %s %d %f",
|
||||
MeshOutputModeString(outMode),
|
||||
skinSlotCount, maxOctantLength);
|
||||
m_parent->_writeLine(req);
|
||||
|
||||
char readBuf[256];
|
||||
|
@ -425,7 +450,7 @@ public:
|
|||
if (strcmp(readBuf, "OK"))
|
||||
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()
|
||||
|
|
|
@ -226,7 +226,7 @@ def strip_next_loop(prev_loop, out_count):
|
|||
loop = radial_loop.link_loop_next
|
||||
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 = Vector()
|
||||
|
@ -258,57 +258,63 @@ def write_out_surface(writebuf, vert_pool, island_faces, mat_idx):
|
|||
avg_norm.normalize()
|
||||
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))
|
||||
|
||||
# Verts themselves
|
||||
prev_loop_emit = None
|
||||
out_count = 0
|
||||
while len(island_faces):
|
||||
sel_lists_local = []
|
||||
restore_out_count = out_count
|
||||
for start_face in island_faces:
|
||||
for l in start_face.loops:
|
||||
out_count = restore_out_count
|
||||
island_local = list(island_faces)
|
||||
if out_count & 1:
|
||||
prev_loop = l.link_loop_prev
|
||||
loop = prev_loop.link_loop_prev
|
||||
sel_list = [l, prev_loop, loop]
|
||||
prev_loop = loop
|
||||
else:
|
||||
prev_loop = l.link_loop_next
|
||||
loop = prev_loop.link_loop_next
|
||||
sel_list = [l, prev_loop, loop]
|
||||
out_count += 3
|
||||
island_local.remove(start_face)
|
||||
while True:
|
||||
if not prev_loop.edge.is_contiguous or prev_loop.edge.tag:
|
||||
break
|
||||
loop, prev_loop = strip_next_loop(prev_loop, out_count)
|
||||
face = loop.face
|
||||
if face not in island_local:
|
||||
break
|
||||
sel_list.append(loop)
|
||||
island_local.remove(face)
|
||||
out_count += 1
|
||||
sel_lists_local.append((sel_list, island_local, out_count))
|
||||
max_count = 0
|
||||
max_sl = None
|
||||
max_island_faces = None
|
||||
for sl in sel_lists_local:
|
||||
if len(sl[0]) > max_count:
|
||||
max_count = len(sl[0])
|
||||
max_sl = sl[0]
|
||||
max_island_faces = sl[1]
|
||||
out_count = sl[2]
|
||||
island_faces = max_island_faces
|
||||
if prev_loop_emit:
|
||||
vert_pool.loop_out(writebuf, prev_loop_emit)
|
||||
vert_pool.loop_out(writebuf, max_sl[0])
|
||||
for loop in max_sl:
|
||||
vert_pool.loop_out(writebuf, loop)
|
||||
prev_loop_emit = loop
|
||||
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
|
||||
out_count = 0
|
||||
while len(island_faces):
|
||||
sel_lists_local = []
|
||||
restore_out_count = out_count
|
||||
for start_face in island_faces:
|
||||
for l in start_face.loops:
|
||||
out_count = restore_out_count
|
||||
island_local = list(island_faces)
|
||||
if out_count & 1:
|
||||
prev_loop = l.link_loop_prev
|
||||
loop = prev_loop.link_loop_prev
|
||||
sel_list = [l, prev_loop, loop]
|
||||
prev_loop = loop
|
||||
else:
|
||||
prev_loop = l.link_loop_next
|
||||
loop = prev_loop.link_loop_next
|
||||
sel_list = [l, prev_loop, loop]
|
||||
out_count += 3
|
||||
island_local.remove(start_face)
|
||||
while True:
|
||||
if not prev_loop.edge.is_contiguous or prev_loop.edge.tag:
|
||||
break
|
||||
loop, prev_loop = strip_next_loop(prev_loop, out_count)
|
||||
face = loop.face
|
||||
if face not in island_local:
|
||||
break
|
||||
sel_list.append(loop)
|
||||
island_local.remove(face)
|
||||
out_count += 1
|
||||
sel_lists_local.append((sel_list, island_local, out_count))
|
||||
max_count = 0
|
||||
max_sl = None
|
||||
max_island_faces = None
|
||||
for sl in sel_lists_local:
|
||||
if len(sl[0]) > max_count:
|
||||
max_count = len(sl[0])
|
||||
max_sl = sl[0]
|
||||
max_island_faces = sl[1]
|
||||
out_count = sl[2]
|
||||
island_faces = max_island_faces
|
||||
if prev_loop_emit:
|
||||
vert_pool.loop_out(writebuf, prev_loop_emit)
|
||||
vert_pool.loop_out(writebuf, max_sl[0])
|
||||
for loop in max_sl:
|
||||
vert_pool.loop_out(writebuf, loop)
|
||||
prev_loop_emit = loop
|
||||
|
||||
writebuf(struct.pack('B', 0))
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ def write_out_material(writebuf, mat, mesh_obj):
|
|||
# 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(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':
|
||||
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)
|
||||
|
||||
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)
|
||||
|
@ -241,7 +241,7 @@ def cook(writebuf, mesh_obj, max_skin_banks, max_octant_length=None):
|
|||
faces = next_faces
|
||||
|
||||
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
|
||||
writebuf(struct.pack('B', 0))
|
||||
|
|
|
@ -9,7 +9,7 @@ if '--' not in sys.argv:
|
|||
args = sys.argv[sys.argv.index('--')+1:]
|
||||
readfd = int(args[0])
|
||||
writefd = int(args[1])
|
||||
double_verbose = int(args[2])
|
||||
verbosity_level = int(args[2])
|
||||
if sys.platform == "win32":
|
||||
import msvcrt
|
||||
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
|
||||
def exec_compbuf(compbuf, globals):
|
||||
if double_verbose:
|
||||
if verbosity_level >= 3:
|
||||
print('EXEC', compbuf)
|
||||
co = compile(compbuf, '<HECL>', 'exec')
|
||||
exec(co, globals)
|
||||
|
@ -144,7 +144,7 @@ def dataout_loop():
|
|||
writepipeline(meshobj.name.encode())
|
||||
|
||||
elif cmdargs[0] == 'MESHCOMPILE':
|
||||
maxSkinBanks = int(cmdargs[1])
|
||||
maxSkinBanks = int(cmdargs[2])
|
||||
|
||||
meshName = bpy.context.scene.hecl_mesh_obj
|
||||
if meshName not in bpy.data.objects:
|
||||
|
@ -152,22 +152,22 @@ def dataout_loop():
|
|||
continue
|
||||
|
||||
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':
|
||||
meshName = cmdargs[1]
|
||||
maxSkinBanks = int(cmdargs[2])
|
||||
maxSkinBanks = int(cmdargs[3])
|
||||
|
||||
if meshName not in bpy.data.objects:
|
||||
writepipeline(('mesh %s not found' % meshName).encode())
|
||||
continue
|
||||
|
||||
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':
|
||||
maxSkinBanks = int(cmdargs[1])
|
||||
maxOctantLength = float(cmdargs[2])
|
||||
maxSkinBanks = int(cmdargs[2])
|
||||
maxOctantLength = float(cmdargs[3])
|
||||
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
join_mesh = bpy.data.meshes.new('JOIN_MESH')
|
||||
|
@ -178,7 +178,7 @@ def dataout_loop():
|
|||
bpy.ops.object.join()
|
||||
|
||||
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.data.objects.remove(join_obj)
|
||||
|
|
|
@ -10,6 +10,7 @@ class ToolCook final : public ToolBase
|
|||
std::unique_ptr<HECL::Database::Project> m_fallbackProj;
|
||||
HECL::Database::Project* m_useProj;
|
||||
bool m_recursive = false;
|
||||
bool m_fast = false;
|
||||
public:
|
||||
ToolCook(const ToolPassInfo& info)
|
||||
: ToolBase(info), m_useProj(info.project)
|
||||
|
@ -28,6 +29,14 @@ public:
|
|||
{
|
||||
if (arg.empty())
|
||||
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::ProjectRootPath root = HECL::SearchForProject(MakePathArgAbsolute(arg, info.cwd), subPath);
|
||||
if (root)
|
||||
|
@ -70,7 +79,7 @@ public:
|
|||
|
||||
help.secHead(_S("SYNOPSIS"));
|
||||
help.beginWrap();
|
||||
help.wrap(_S("hecl cook [-rf] [<pathspec>...]\n"));
|
||||
help.wrap(_S("hecl cook [-rf] [--fast] [<pathspec>...]\n"));
|
||||
help.endWrap();
|
||||
|
||||
help.secHead(_S("DESCRIPTION"));
|
||||
|
@ -117,6 +126,10 @@ public:
|
|||
help.beginWrap();
|
||||
help.wrap(_S("Forces cooking of all matched files, ignoring timestamp differences.\n"));
|
||||
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");}
|
||||
|
@ -131,7 +144,7 @@ public:
|
|||
const HECL::SystemChar* submessage,
|
||||
int lidx, float factor)
|
||||
{ToolPrintProgress(message, submessage, lidx, factor, lineIdx);},
|
||||
m_recursive, m_info.force);
|
||||
m_recursive, m_info.force, m_fast);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -189,7 +189,7 @@ int main(int argc, const char** argv)
|
|||
for (auto it = args.cbegin() ; it != args.cend() ;)
|
||||
{
|
||||
const HECL::SystemString& arg = *it;
|
||||
if (arg.empty() || arg[0] != _S('-'))
|
||||
if (arg.size() < 2 || arg[0] != _S('-') || arg[1] == _S('-'))
|
||||
{
|
||||
++it;
|
||||
continue;
|
||||
|
|
|
@ -67,6 +67,7 @@ class IDataSpec
|
|||
public:
|
||||
virtual ~IDataSpec() {}
|
||||
using FProgress = FProgress;
|
||||
using FCookProgress = std::function<void(const SystemChar*)>;
|
||||
|
||||
/**
|
||||
* @brief Extract Pass Info
|
||||
|
@ -101,8 +102,9 @@ public:
|
|||
|
||||
virtual bool canCook(const ProjectPath& path)
|
||||
{(void)path;LogModule.report(LogVisor::Error, "not implemented");return false;}
|
||||
virtual void doCook(const ProjectPath& path, const ProjectPath& cookedPath)
|
||||
{(void)path;(void)cookedPath;}
|
||||
virtual void doCook(const ProjectPath& path, const ProjectPath& cookedPath,
|
||||
bool fast, FCookProgress progress)
|
||||
{(void)path;(void)cookedPath;(void)fast;(void)progress;}
|
||||
|
||||
/**
|
||||
* @brief Package Pass Info
|
||||
|
@ -406,13 +408,15 @@ public:
|
|||
* @param path directory of intermediates to cook
|
||||
* @param feedbackCb a callback to run reporting cook-progress
|
||||
* @param recursive traverse subdirectories to cook as well
|
||||
* @param fast enables faster (draft) extraction for supported data types
|
||||
* @return true on success
|
||||
*
|
||||
* Object cooking is generally an expensive process for large projects.
|
||||
* This method blocks execution during the procedure, with periodic
|
||||
* 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)
|
||||
|
|
|
@ -357,12 +357,22 @@ public:
|
|||
submsg += _S(')');
|
||||
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);}
|
||||
};
|
||||
|
||||
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,
|
||||
CookProgress& progress)
|
||||
{
|
||||
|
@ -371,17 +381,24 @@ static void VisitFile(const ProjectPath& path, bool force,
|
|||
if (spec.second->canCook(path))
|
||||
{
|
||||
ProjectPath cooked = path.getCookedPath(*spec.first);
|
||||
if (fast)
|
||||
cooked = cooked.getWithExtension(".fast");
|
||||
if (force || cooked.getPathType() == ProjectPath::PT_NONE ||
|
||||
path.getModtime() > cooked.getModtime())
|
||||
{
|
||||
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,
|
||||
CookProgress& progress)
|
||||
{
|
||||
|
@ -421,7 +438,7 @@ static void VisitDirectory(const ProjectPath& dir, bool recursive, bool force,
|
|||
case ProjectPath::PT_FILE:
|
||||
{
|
||||
progress.changeFile(child.first.c_str(), progNum++/progDenom);
|
||||
VisitFile(child.second, force, specInsts, progress);
|
||||
VisitFile(child.second, force, fast, specInsts, progress);
|
||||
break;
|
||||
}
|
||||
case ProjectPath::PT_LINK:
|
||||
|
@ -430,7 +447,7 @@ static void VisitDirectory(const ProjectPath& dir, bool recursive, bool force,
|
|||
if (target.getPathType() == ProjectPath::PT_FILE)
|
||||
{
|
||||
progress.changeFile(target.getLastComponent(), progNum++/progDenom);
|
||||
VisitFile(target, force, specInsts, progress);
|
||||
VisitFile(target, force, fast, specInsts, progress);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -448,7 +465,7 @@ static void VisitDirectory(const ProjectPath& dir, bool recursive, bool force,
|
|||
{
|
||||
case ProjectPath::PT_DIRECTORY:
|
||||
{
|
||||
VisitDirectory(child.second, recursive, force, specInsts, progress);
|
||||
VisitDirectory(child.second, recursive, force, fast, specInsts, progress);
|
||||
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,
|
||||
CookProgress& progress)
|
||||
{
|
||||
|
@ -497,7 +515,7 @@ static void VisitGlob(const ProjectPath& path, bool recursive, bool force,
|
|||
case ProjectPath::PT_FILE:
|
||||
{
|
||||
progress.changeFile(child.getLastComponent(), progNum++/progDenom);
|
||||
VisitFile(child, force, specInsts, progress);
|
||||
VisitFile(child, force, fast, specInsts, progress);
|
||||
break;
|
||||
}
|
||||
case ProjectPath::PT_LINK:
|
||||
|
@ -506,7 +524,7 @@ static void VisitGlob(const ProjectPath& path, bool recursive, bool force,
|
|||
if (target.getPathType() == ProjectPath::PT_FILE)
|
||||
{
|
||||
progress.changeFile(target.getLastComponent(), progNum++/progDenom);
|
||||
VisitFile(target, force, specInsts, progress);
|
||||
VisitFile(target, force, fast, specInsts, progress);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -524,7 +542,7 @@ static void VisitGlob(const ProjectPath& path, bool recursive, bool force,
|
|||
{
|
||||
case ProjectPath::PT_DIRECTORY:
|
||||
{
|
||||
VisitDirectory(child, recursive, force, specInsts, progress);
|
||||
VisitDirectory(child, recursive, force, fast, specInsts, progress);
|
||||
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 */
|
||||
std::vector<SpecInst> specInsts;
|
||||
|
@ -550,7 +569,7 @@ bool Project::cookPath(const ProjectPath& path, FProgress progress, bool recursi
|
|||
case ProjectPath::PT_FILE:
|
||||
{
|
||||
cookProg.changeFile(path.getLastComponent(), 0.0);
|
||||
VisitFile(path, force, specInsts, cookProg);
|
||||
VisitFile(path, force, fast, specInsts, cookProg);
|
||||
break;
|
||||
}
|
||||
case ProjectPath::PT_LINK:
|
||||
|
@ -559,18 +578,18 @@ bool Project::cookPath(const ProjectPath& path, FProgress progress, bool recursi
|
|||
if (target.getPathType() == ProjectPath::PT_FILE)
|
||||
{
|
||||
cookProg.changeFile(target.getLastComponent(), 0.0);
|
||||
VisitFile(target, force, specInsts, cookProg);
|
||||
VisitFile(target, force, fast, specInsts, cookProg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ProjectPath::PT_DIRECTORY:
|
||||
{
|
||||
VisitDirectory(path, recursive, force, specInsts, cookProg);
|
||||
VisitDirectory(path, recursive, force, fast, specInsts, cookProg);
|
||||
break;
|
||||
}
|
||||
case ProjectPath::PT_GLOB:
|
||||
{
|
||||
VisitGlob(path, recursive, force, specInsts, cookProg);
|
||||
VisitGlob(path, recursive, force, fast, specInsts, cookProg);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
|
|
Loading…
Reference in New Issue