2
0
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:
Jack Andersen 2015-10-21 16:01:08 -10:00
parent 87b86b7553
commit bcee8aa897
9 changed files with 224 additions and 99 deletions

View File

@ -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)
{ {

View File

@ -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()

View File

@ -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):

View File

@ -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))

View File

@ -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)

View File

@ -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;
} }

View File

@ -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;

View File

@ -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)

View File

@ -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;