HECL Compiler bug fixes

This commit is contained in:
Jack Andersen 2015-10-14 13:06:47 -10:00
parent 2148bc2459
commit a86b5f8c1d
13 changed files with 230 additions and 72 deletions

View File

@ -558,21 +558,25 @@ BlenderConnection::DataStream::Mesh::Mesh(BlenderConnection& conn, int skinSlotC
BlenderConnection::DataStream::Mesh::Material::Material
(BlenderConnection& conn)
{
char buf[4096];
conn._readLine(buf, 4096);
source.assign(buf);
uint32_t bufSz;
conn._readBuf(&bufSz, 4);
name.assign(bufSz, ' ');
conn._readBuf(&name[0], bufSz);
conn._readBuf(&bufSz, 4);
source.assign(bufSz, ' ');
conn._readBuf(&source[0], bufSz);
uint32_t texCount;
conn._readBuf(&texCount, 4);
texs.reserve(texCount);
for (uint32_t i=0 ; i<texCount ; ++i)
{
conn._readLine(buf, 4096);
#if HECL_UCS2
SystemString absolute = HECL::UTF8ToWide(buf);
#else
SystemString absolute(buf);
#endif
conn._readBuf(&bufSz, 4);
std::string readStr(bufSz, ' ');
conn._readBuf(&readStr[0], bufSz);
SystemStringView absolute(readStr);
SystemString relative =
conn.m_loadedBlend.getProject().getProjectRootPath().getProjectRelativeFromAbsolute(absolute);
texs.emplace_back(conn.m_loadedBlend.getProject().getProjectWorkingPath(), relative);

View File

@ -308,6 +308,7 @@ public:
/* HECL source of each material */
struct Material
{
std::string name;
std::string source;
std::vector<ProjectPath> texs;

View File

@ -354,7 +354,7 @@ def shader(mat_obj, mesh_obj):
tex_paths = [get_texture_path(name) for name in tex_list]
if mat_obj.game_settings.alpha_blend == 'ALPHA' or mat_obj.game_settings.alpha_blend == 'ALPHA_SORT':
return "HECLBlend(%s, %s)" % (color_trace_result, alpha_trace_result), tex_paths
return "HECLAlpha(%s, %s)" % (color_trace_result, alpha_trace_result), tex_paths
elif mat_obj.game_settings.alpha_blend == 'ADD':
return "HECLAdditive(%s, %s)" % (color_trace_result, alpha_trace_result), tex_paths
else:

View File

@ -95,11 +95,10 @@ def cook(writebuf, mesh_obj, max_skin_banks, max_octant_length=None):
rna_loops = copy_mesh.loops
# Filter out useless AABB points and send data
aabb = bytearray()
for comp in copy_obj.bound_box[0]:
writebuf(struct.pack('f', comp))
for comp in copy_obj.bound_box[6]:
writebuf(struct.pack('f', comp))
pt = copy_obj.bound_box[0]
writebuf(struct.pack('fff', pt[0], pt[1], pt[2]))
pt = copy_obj.bound_box[6]
writebuf(struct.pack('fff', pt[0], pt[1], pt[2]))
# Create master BMesh and VertPool
bm_master = bmesh.new()
@ -128,10 +127,14 @@ def cook(writebuf, mesh_obj, max_skin_banks, max_octant_length=None):
for mat in bpy.data.materials:
if mat.name.endswith('_%u_%u' % (grp_idx, mat_idx)):
hecl_str, texs = HMDLShader.shader(mat, mesh_obj)
writebuf((hecl_str + '\n').encode())
writebuf(struct.pack('I', len(mat.name)))
writebuf(mat.name.encode())
writebuf(struct.pack('I', len(hecl_str)))
writebuf(hecl_str.encode())
writebuf(struct.pack('I', len(texs)))
for tex in texs:
writebuf((tex + '\n').encode())
writebuf(struct.pack('I', len(tex)))
writebuf(tex.encode())
found = True
break
if not found:
@ -141,10 +144,14 @@ def cook(writebuf, mesh_obj, max_skin_banks, max_octant_length=None):
for mat_idx in sorted_material_idxs:
mat = mesh_obj.data.materials[mat_idx]
hecl_str, texs = HMDLShader.shader(mat, mesh_obj)
writebuf((hecl_str + '\n').encode())
writebuf(struct.pack('I', len(mat.name)))
writebuf(mat.name.encode())
writebuf(struct.pack('I', len(hecl_str)))
writebuf(hecl_str.encode())
writebuf(struct.pack('I', len(texs)))
for tex in texs:
writebuf((tex + '\n').encode())
writebuf(struct.pack('I', len(tex)))
writebuf(tex.encode())
# Output vert pool
vert_pool.write_out(writebuf, mesh_obj.vertex_groups)

View File

@ -26,5 +26,5 @@ endif()
target_link_libraries(hecl
${DATA_SPEC_LIBS}
HECLDatabase HECLBlender HECLCommon AthenaCore NOD
HECLDatabase HECLBackend HECLFrontend HECLBlender HECLCommon AthenaCore NOD
LogVisor AthenaLibYaml ${PNG_LIB} squish xxhash ${ZLIB_LIBRARIES} ${LZO_LIB} ${PLAT_LIBS})

View File

@ -201,8 +201,8 @@ struct GX : IBackend
struct TEVStage
{
TevOp m_op = TEV_ADD;
TevColorArg m_color[4] = {CC_ZERO, CC_ZERO, CC_ZERO, CC_CPREV};
TevAlphaArg m_alpha[4] = {CA_ZERO, CA_ZERO, CA_ZERO, CA_APREV};
TevColorArg m_color[4] = {CC_ZERO, CC_ZERO, CC_ZERO, CC_ZERO};
TevAlphaArg m_alpha[4] = {CA_ZERO, CA_ZERO, CA_ZERO, CA_ZERO};
TevKColorSel m_kColor = TEV_KCSEL_1;
TevKAlphaSel m_kAlpha = TEV_KASEL_1;
TevRegID m_regOut = TEVPREV;

View File

@ -23,12 +23,17 @@ struct SourceLocation
class Diagnostics
{
std::string m_name;
std::string m_source;
std::string sourceDiagString(const SourceLocation& l, bool ansi=false) const;
public:
void setName(const std::string& name) {m_name = name;}
void reset(const std::string& name, const std::string& source) {m_name = name; m_source = source;}
void reportParserErr(const SourceLocation& l, const char* format, ...);
void reportLexerErr(const SourceLocation& l, const char* format, ...);
void reportCompileErr(const SourceLocation& l, const char* format, ...);
void reportBackendErr(const SourceLocation& l, const char* format, ...);
const std::string& getName() const {return m_name;}
const std::string& getSource() const {return m_source;}
};
class Parser
@ -65,6 +70,36 @@ public:
float m_tokenFloat = 0.0;
Token() : m_type(TokenNone) {}
Token(TokenType type, SourceLocation loc) : m_type(type), m_location(loc) {}
const char* typeString() const
{
switch (m_type)
{
case TokenNone:
return "None";
case TokenSourceBegin:
return "SourceBegin";
case TokenSourceEnd:
return "SourceEnd";
case TokenNumLiteral:
return "NumLiteral";
case TokenVectorSwizzle:
return "VectorSwizzle";
case TokenEvalGroupStart:
return "EvalGroupStart";
case TokenEvalGroupEnd:
return "EvalGroupEnd";
case TokenFunctionStart:
return "FunctionStart";
case TokenFunctionEnd:
return "FunctionEnd";
case TokenFunctionArgDelim:
return "FunctionArgDelim";
case TokenArithmeticOp:
return "ArithmeticOp";
default: break;
}
return nullptr;
}
};
void reset(const std::string& source);
Token consumeToken();
@ -120,7 +155,7 @@ struct IR
struct
{
int m_idxs[4] = {-1};
int m_idxs[4] = {-1, -1, -1, -1};
size_t m_instIdx;
} m_swizzle;
@ -208,6 +243,9 @@ class Lexer
void EmitArithmetic(IR& ir, const Lexer::OperationNode* arithNode, IR::RegID target) const;
void EmitVectorSwizzle(IR& ir, const Lexer::OperationNode* swizNode, IR::RegID target) const;
static void PrintChain(const Lexer::OperationNode* begin, const Lexer::OperationNode* end);
static void PrintTree(const Lexer::OperationNode* node, int indent=0);
public:
void reset();
void consumeAllTokens(Parser& parser);
@ -224,7 +262,7 @@ class Frontend
public:
IR compileSource(const std::string& source, const std::string& diagName)
{
m_diag.setName(diagName);
m_diag.reset(diagName, source);
m_parser.reset(source);
m_lexer.consumeAllTokens(m_parser);
return m_lexer.compileIR();

View File

@ -30,6 +30,7 @@
#include <algorithm>
#include <regex>
#include <list>
#include <map>
#include <LogVisor/LogVisor.hpp>
#include "../extern/xxhash/xxhash.h"
@ -658,6 +659,19 @@ public:
return m_relPath.c_str() + m_relPath.size();
return m_relPath.c_str() + pos + 1;
}
const char* getLastComponentUTF8() const
{
size_t pos = m_relPath.rfind(_S('/'));
#if HECL_UCS2
if (pos == SystemString::npos)
return m_utf8RelPath.c_str() + m_utf8RelPath.size();
return m_utf8RelPath.c_str() + pos + 1;
#else
if (pos == SystemString::npos)
return m_relPath.c_str() + m_relPath.size();
return m_relPath.c_str() + pos + 1;
#endif
}
/**
* @brief Obtain c-string of extension of final path component (stored within relative path)
@ -738,7 +752,7 @@ public:
* @brief Insert directory children into list
* @param outPaths list to append children to
*/
void getDirChildren(std::vector<ProjectPath>& outPaths) const;
void getDirChildren(std::map<SystemString, ProjectPath>& outPaths) const;
/**
* @brief Insert glob matches into existing vector

View File

@ -169,6 +169,7 @@ GX::TraceResult GX::RecursiveTraceColor(const IR& ir, Diagnostics& diag, const I
TEVStage* b = bTrace.tevStage;
if (b->m_prev != a)
diag.reportBackendErr(inst.m_loc, "TEV stages must have monotonic progression");
b->m_color[3] = CC_CPREV;
return TraceResult(b);
}
break;
@ -183,6 +184,7 @@ GX::TraceResult GX::RecursiveTraceColor(const IR& ir, Diagnostics& diag, const I
if (b->m_prev != a)
diag.reportBackendErr(inst.m_loc, "TEV stages must have monotonic progression");
b->m_op = TEV_SUB;
b->m_color[3] = CC_CPREV;
return TraceResult(b);
}
break;
@ -204,6 +206,14 @@ GX::TraceResult GX::RecursiveTraceColor(const IR& ir, Diagnostics& diag, const I
b->m_color[3] = CC_ZERO;
return TraceResult(b);
}
else if (aTrace.type == TraceResult::TraceTEVColorArg &&
bTrace.type == TraceResult::TraceTEVColorArg)
{
TEVStage& stage = addTEVStage(diag, inst.m_loc);
stage.m_color[1] = aTrace.tevColorArg;
stage.m_color[2] = bTrace.tevColorArg;
return TraceResult(&stage);
}
else if (aTrace.type == TraceResult::TraceTEVStage &&
bTrace.type == TraceResult::TraceTEVColorArg)
{
@ -262,6 +272,19 @@ GX::TraceResult GX::RecursiveTraceColor(const IR& ir, Diagnostics& diag, const I
diag.reportBackendErr(inst.m_loc, "unable to convert arithmetic to TEV stage");
}
case IR::OpSwizzle:
{
if (inst.m_swizzle.m_idxs[0] == 3 && inst.m_swizzle.m_idxs[1] == -1 &&
inst.m_swizzle.m_idxs[2] == -1 && inst.m_swizzle.m_idxs[3] == -1)
{
const IR::Instruction& cInst = inst.getChildInst(ir, 0);
if (cInst.m_op != IR::OpCall || cInst.m_call.m_name.compare("Texture"))
diag.reportBackendErr(inst.m_loc, "only Texture() accepted for alpha swizzle");
return TraceResult(CC_TEXA);
}
else
diag.reportBackendErr(inst.m_loc, "only alpha extract may be performed with swizzle operation");
}
default:
diag.reportBackendErr(inst.m_loc, "invalid color op");
}
@ -305,6 +328,7 @@ GX::TraceResult GX::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const I
}
TEVStage& newStage = addTEVStage(diag, inst.m_loc);
newStage.m_color[3] = CC_CPREV;
newStage.m_texMapIdx = mapIdx;
newStage.m_alpha[0] = CA_TEXA;
@ -355,6 +379,7 @@ GX::TraceResult GX::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const I
TEVStage* b = bTrace.tevStage;
if (b->m_prev != a)
diag.reportBackendErr(inst.m_loc, "TEV stages must have monotonic progression");
b->m_alpha[3] = CA_APREV;
return TraceResult(b);
}
break;
@ -370,6 +395,7 @@ GX::TraceResult GX::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const I
diag.reportBackendErr(inst.m_loc, "TEV stages must have monotonic progression");
if (b->m_op != TEV_SUB)
diag.reportBackendErr(inst.m_loc, "unable to integrate alpha subtraction into stage chain");
b->m_alpha[3] = CA_APREV;
return TraceResult(b);
}
break;
@ -391,6 +417,15 @@ GX::TraceResult GX::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const I
b->m_alpha[3] = CA_ZERO;
return TraceResult(b);
}
else if (aTrace.type == TraceResult::TraceTEVAlphaArg &&
bTrace.type == TraceResult::TraceTEVAlphaArg)
{
TEVStage& stage = addTEVStage(diag, inst.m_loc);
stage.m_color[3] = CC_CPREV;
stage.m_alpha[1] = aTrace.tevAlphaArg;
stage.m_alpha[2] = bTrace.tevAlphaArg;
return TraceResult(&stage);
}
else if (aTrace.type == TraceResult::TraceTEVStage &&
bTrace.type == TraceResult::TraceTEVColorArg)
{
@ -484,6 +519,12 @@ void GX::reset(const IR& ir, Diagnostics& diag)
m_blendDst = BL_ONE;
doAlpha = true;
}
else
{
diag.reportBackendErr(rootCall.m_loc, "GX backend doesn't handle '%s' root",
rootCall.m_call.m_name.c_str());
return;
}
/* Follow Color Chain */
const IR::Instruction& colorRoot =
@ -496,6 +537,11 @@ void GX::reset(const IR& ir, Diagnostics& diag)
const IR::Instruction& alphaRoot =
ir.m_instructions.at(rootCall.m_call.m_argInstIdxs.at(1));
RecursiveTraceAlpha(ir, diag, alphaRoot);
/* Ensure Alpha reaches end of chain */
if (m_alphaTraceStage >= 0)
for (int i=m_alphaTraceStage+1 ; i<m_tevCount ; ++i)
m_tevs[i].m_alpha[3] = CA_APREV;
}
}

View File

@ -385,14 +385,14 @@ static void VisitDirectory(const ProjectPath& dir, bool recursive,
std::vector<SpecInst>& specInsts,
CookProgress& progress)
{
std::vector<ProjectPath> children;
std::map<SystemString, ProjectPath> children;
dir.getDirChildren(children);
/* Pass 1: child file count */
int childFileCount = 0;
for (ProjectPath& child : children)
for (auto& child : children)
{
switch (child.getPathType())
switch (child.second.getPathType())
{
case ProjectPath::PT_FILE:
{
@ -401,7 +401,7 @@ static void VisitDirectory(const ProjectPath& dir, bool recursive,
}
case ProjectPath::PT_LINK:
{
ProjectPath target = child.resolveLink();
ProjectPath target = child.second.resolveLink();
if (target.getPathType() == ProjectPath::PT_FILE)
++childFileCount;
break;
@ -414,19 +414,19 @@ static void VisitDirectory(const ProjectPath& dir, bool recursive,
int progNum = 0;
float progDenom = childFileCount;
progress.changeDir(dir.getLastComponent());
for (ProjectPath& child : children)
for (auto& child : children)
{
switch (child.getPathType())
switch (child.second.getPathType())
{
case ProjectPath::PT_FILE:
{
progress.changeFile(child.getLastComponent(), progNum++/progDenom);
VisitFile(child, specInsts, progress);
progress.changeFile(child.first.c_str(), progNum++/progDenom);
VisitFile(child.second, specInsts, progress);
break;
}
case ProjectPath::PT_LINK:
{
ProjectPath target = child.resolveLink();
ProjectPath target = child.second.resolveLink();
if (target.getPathType() == ProjectPath::PT_FILE)
{
progress.changeFile(target.getLastComponent(), progNum++/progDenom);
@ -442,13 +442,13 @@ static void VisitDirectory(const ProjectPath& dir, bool recursive,
/* Pass 3: child directories */
if (recursive)
{
for (ProjectPath& child : children)
for (auto& child : children)
{
switch (child.getPathType())
switch (child.second.getPathType())
{
case ProjectPath::PT_DIRECTORY:
{
VisitDirectory(child, recursive, specInsts, progress);
VisitDirectory(child.second, recursive, specInsts, progress);
break;
}
default: break;

View File

@ -17,6 +17,32 @@ namespace HECL
namespace Frontend
{
std::string Diagnostics::sourceDiagString(const SourceLocation& l, bool ansi) const
{
std::string::const_iterator it = m_source.begin();
for (int i=1 ; i<l.line ; ++i)
{
while (*it != '\n' && it != m_source.end())
++it;
if (*it == '\n')
++it;
}
std::string::const_iterator begin = it;
while (*it != '\n' && it != m_source.end())
++it;
std::string::const_iterator end = it;
std::string retval(begin, end);
retval += '\n';
for (int i=1 ; i<l.col ; ++i)
retval += ' ';
if (ansi)
retval += GREEN "^" NORMAL;
else
retval += '^';
return retval;
}
void Diagnostics::reportParserErr(const SourceLocation& l, const char* fmt, ...)
{
va_list ap;
@ -31,11 +57,11 @@ void Diagnostics::reportParserErr(const SourceLocation& l, const char* fmt, ...)
#endif
va_end(ap);
if (LogVisor::XtermColor)
LogModule.report(LogVisor::FatalError, RED "Error parsing" NORMAL " '%s' " YELLOW "@%d:%d " NORMAL "\n%s",
m_name.c_str(), l.line, l.col, result);
LogModule.report(LogVisor::FatalError, CYAN "[Parser]" NORMAL " %s " YELLOW "@%d:%d " NORMAL "\n%s\n%s",
m_name.c_str(), l.line, l.col, result, sourceDiagString(l, true).c_str());
else
LogModule.report(LogVisor::FatalError, "Error parsing '%s' @%d:%d\n%s",
m_name.c_str(), l.line, l.col, result);
LogModule.report(LogVisor::FatalError, "[Parser] %s @%d:%d\n%s\n%s",
m_name.c_str(), l.line, l.col, result, sourceDiagString(l, false).c_str());
free(result);
}
@ -53,11 +79,11 @@ void Diagnostics::reportLexerErr(const SourceLocation& l, const char* fmt, ...)
#endif
va_end(ap);
if (LogVisor::XtermColor)
LogModule.report(LogVisor::FatalError, RED "Error lexing" NORMAL " '%s' " YELLOW "@%d:%d " NORMAL "\n%s",
m_name.c_str(), l.line, l.col, result);
LogModule.report(LogVisor::FatalError, CYAN "[Lexer]" NORMAL " %s " YELLOW "@%d:%d " NORMAL "\n%s\n%s",
m_name.c_str(), l.line, l.col, result, sourceDiagString(l, true).c_str());
else
LogModule.report(LogVisor::FatalError, "Error lexing '%s' @%d:%d\n%s",
m_name.c_str(), l.line, l.col, result);
LogModule.report(LogVisor::FatalError, "[Lexer] %s @%d:%d\n%s\n%s",
m_name.c_str(), l.line, l.col, result, sourceDiagString(l, false).c_str());
free(result);
}
@ -75,11 +101,11 @@ void Diagnostics::reportCompileErr(const SourceLocation& l, const char* fmt, ...
#endif
va_end(ap);
if (LogVisor::XtermColor)
LogModule.report(LogVisor::FatalError, RED "Error compiling" NORMAL " '%s' " YELLOW "@%d:%d " NORMAL "\n%s",
m_name.c_str(), l.line, l.col, result);
LogModule.report(LogVisor::FatalError, CYAN "[Compiler]" NORMAL " %s " YELLOW "@%d:%d " NORMAL "\n%s\n%s",
m_name.c_str(), l.line, l.col, result, sourceDiagString(l, true).c_str());
else
LogModule.report(LogVisor::FatalError, "Error compiling '%s' @%d:%d\n%s",
m_name.c_str(), l.line, l.col, result);
LogModule.report(LogVisor::FatalError, "[Compiler] %s @%d:%d\n%s\n%s",
m_name.c_str(), l.line, l.col, result, sourceDiagString(l, false).c_str());
free(result);
}
@ -97,11 +123,11 @@ void Diagnostics::reportBackendErr(const SourceLocation& l, const char* fmt, ...
#endif
va_end(ap);
if (LogVisor::XtermColor)
LogModule.report(LogVisor::FatalError, RED "Backend error" NORMAL " in '%s' " YELLOW "@%d:%d " NORMAL "\n%s",
m_name.c_str(), l.line, l.col, result);
LogModule.report(LogVisor::FatalError, CYAN "[Backend]" NORMAL " %s " YELLOW "@%d:%d " NORMAL "\n%s\n%s",
m_name.c_str(), l.line, l.col, result, sourceDiagString(l, true).c_str());
else
LogModule.report(LogVisor::FatalError, "Backend error in '%s' @%d:%d\n%s",
m_name.c_str(), l.line, l.col, result);
LogModule.report(LogVisor::FatalError, "[Backend] %s @%d:%d\n%s\n%s",
m_name.c_str(), l.line, l.col, result, sourceDiagString(l, false).c_str());
free(result);
}

View File

@ -47,6 +47,28 @@ void Lexer::ReconnectArithmetic(OperationNode* sn, OperationNode** lastSub, Oper
*newSub = sn;
}
void Lexer::PrintChain(const Lexer::OperationNode* begin, const Lexer::OperationNode* end)
{
for (const Lexer::OperationNode* n = begin ; n != end ; n = n->m_next)
{
printf("%3d %s %s\n", n->m_tok.m_location.col, n->m_tok.typeString(),
n->m_tok.m_tokenString.c_str());
}
}
void Lexer::PrintTree(const Lexer::OperationNode* node, int indent)
{
for (const Lexer::OperationNode* n = node ; n ; n = n->m_next)
{
for (int i=0 ; i<indent ; ++i)
printf(" ");
printf("%3d %s %s\n", n->m_tok.m_location.col, n->m_tok.typeString(),
n->m_tok.m_tokenString.c_str());
if (n->m_sub)
PrintTree(n->m_sub, indent + 1);
}
}
void Lexer::reset()
{
m_root = nullptr;
@ -157,7 +179,7 @@ void Lexer::consumeAllTokens(Parser& parser)
}
else if (n->m_tok.m_type == Parser::TokenFunctionEnd)
{
if (n->m_prev->m_tok.m_type != Parser::TokenEvalGroupStart)
if (n->m_prev->m_tok.m_type != Parser::TokenFunctionStart)
{
m_pool.emplace_front(std::move(
Parser::Token(Parser::TokenEvalGroupEnd, n->m_tok.m_location)));
@ -230,9 +252,14 @@ void Lexer::consumeAllTokens(Parser& parser)
if (sn->m_tok.m_type == Parser::TokenFunctionEnd)
{
n.m_sub = n.m_next;
if (n.m_next == sn)
n.m_sub = nullptr;
n.m_next = sn->m_next;
if (sn->m_next)
sn->m_next->m_prev = &n;
if (n.m_sub)
n.m_sub->m_prev = nullptr;
if (sn->m_prev)
sn->m_prev->m_next = nullptr;
break;
}
@ -310,6 +337,13 @@ void Lexer::consumeAllTokens(Parser& parser)
}
}
if (HECL::VerbosityLevel)
{
printf("%s\n", m_diag.getSource().c_str());
PrintTree(firstNode);
printf("\n");
}
/* Done! */
m_root = firstNode->m_next;
}

View File

@ -286,7 +286,7 @@ static void _recursiveGlob(Database::Project& proj,
#endif
}
void ProjectPath::getDirChildren(std::vector<ProjectPath>& outPaths) const
void ProjectPath::getDirChildren(std::map<SystemString, ProjectPath>& outPaths) const
{
#if _WIN32
#else
@ -298,18 +298,6 @@ void ProjectPath::getDirChildren(std::vector<ProjectPath>& outPaths) const
return;
}
/* Count elements */
size_t count = 0;
while ((de = readdir(dir)))
{
if (!strcmp(de->d_name, "."))
continue;
if (!strcmp(de->d_name, ".."))
continue;
++count;
}
outPaths.reserve(outPaths.size() + count);
/* Add elements */
rewinddir(dir);
while ((de = readdir(dir)))
@ -318,7 +306,7 @@ void ProjectPath::getDirChildren(std::vector<ProjectPath>& outPaths) const
continue;
if (!strcmp(de->d_name, ".."))
continue;
outPaths.emplace_back(*this, de->d_name);
outPaths[de->d_name] = ProjectPath(*this, de->d_name);
}
closedir(dir);