Add bounds checks to the parsing utilities. (#5421)
* Add bounds checks to the parsing utilities. * Fix merge conflicts in ACLoader. * Fix loaders * Fix unittest of AC-Loader. * Remove dead code. * Md5Parser fixes * Fix md5-parsing * Fix Merge conflict * Fix merge conflicts. * Md5: Fix warning: missing return statement.pull/5446/head
parent
d5f35582d4
commit
c08e3b4abb
|
@ -77,8 +77,8 @@ static constexpr aiImporterDesc desc = {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// skip to the next token
|
// skip to the next token
|
||||||
inline const char *AcSkipToNextToken(const char *buffer) {
|
inline const char *AcSkipToNextToken(const char *buffer, const char *end) {
|
||||||
if (!SkipSpaces(&buffer)) {
|
if (!SkipSpaces(&buffer, end)) {
|
||||||
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL");
|
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL");
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
|
@ -86,13 +86,13 @@ inline const char *AcSkipToNextToken(const char *buffer) {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// read a string (may be enclosed in double quotation marks). buffer must point to "
|
// read a string (may be enclosed in double quotation marks). buffer must point to "
|
||||||
inline const char *AcGetString(const char *buffer, std::string &out) {
|
inline const char *AcGetString(const char *buffer, const char *end, std::string &out) {
|
||||||
if (*buffer == '\0') {
|
if (*buffer == '\0') {
|
||||||
throw DeadlyImportError("AC3D: Unexpected EOF in string");
|
throw DeadlyImportError("AC3D: Unexpected EOF in string");
|
||||||
}
|
}
|
||||||
++buffer;
|
++buffer;
|
||||||
const char *sz = buffer;
|
const char *sz = buffer;
|
||||||
while ('\"' != *buffer) {
|
while ('\"' != *buffer && buffer != end) {
|
||||||
if (IsLineEnd(*buffer)) {
|
if (IsLineEnd(*buffer)) {
|
||||||
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL in string");
|
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL in string");
|
||||||
out = "ERROR";
|
out = "ERROR";
|
||||||
|
@ -112,8 +112,8 @@ inline const char *AcGetString(const char *buffer, std::string &out) {
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// read 1 to n floats prefixed with an optional predefined identifier
|
// read 1 to n floats prefixed with an optional predefined identifier
|
||||||
template <class T>
|
template <class T>
|
||||||
inline const char *TAcCheckedLoadFloatArray(const char *buffer, const char *name, size_t name_length, size_t num, T *out) {
|
inline const char *TAcCheckedLoadFloatArray(const char *buffer, const char *end, const char *name, size_t name_length, size_t num, T *out) {
|
||||||
buffer = AcSkipToNextToken(buffer);
|
buffer = AcSkipToNextToken(buffer, end);
|
||||||
if (0 != name_length) {
|
if (0 != name_length) {
|
||||||
if (0 != strncmp(buffer, name, name_length) || !IsSpace(buffer[name_length])) {
|
if (0 != strncmp(buffer, name, name_length) || !IsSpace(buffer[name_length])) {
|
||||||
ASSIMP_LOG_ERROR("AC3D: Unexpected token. ", name, " was expected.");
|
ASSIMP_LOG_ERROR("AC3D: Unexpected token. ", name, " was expected.");
|
||||||
|
@ -122,7 +122,7 @@ inline const char *TAcCheckedLoadFloatArray(const char *buffer, const char *name
|
||||||
buffer += name_length + 1;
|
buffer += name_length + 1;
|
||||||
}
|
}
|
||||||
for (unsigned int _i = 0; _i < num; ++_i) {
|
for (unsigned int _i = 0; _i < num; ++_i) {
|
||||||
buffer = AcSkipToNextToken(buffer);
|
buffer = AcSkipToNextToken(buffer, end);
|
||||||
buffer = fast_atoreal_move<float>(buffer, ((float *)out)[_i]);
|
buffer = fast_atoreal_move<float>(buffer, ((float *)out)[_i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ inline const char *TAcCheckedLoadFloatArray(const char *buffer, const char *name
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructor to be privately used by Importer
|
// Constructor to be privately used by Importer
|
||||||
AC3DImporter::AC3DImporter() :
|
AC3DImporter::AC3DImporter() :
|
||||||
buffer(),
|
mBuffer(),
|
||||||
configSplitBFCull(),
|
configSplitBFCull(),
|
||||||
configEvalSubdivision(),
|
configEvalSubdivision(),
|
||||||
mNumMeshes(),
|
mNumMeshes(),
|
||||||
|
@ -164,17 +164,17 @@ const aiImporterDesc *AC3DImporter::GetInfo() const {
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Get a pointer to the next line from the file
|
// Get a pointer to the next line from the file
|
||||||
bool AC3DImporter::GetNextLine() {
|
bool AC3DImporter::GetNextLine() {
|
||||||
SkipLine(&buffer);
|
SkipLine(&mBuffer.data, mBuffer.end);
|
||||||
return SkipSpaces(&buffer);
|
return SkipSpaces(&mBuffer.data, mBuffer.end);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Parse an object section in an AC file
|
// Parse an object section in an AC file
|
||||||
bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
|
bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
|
||||||
if (!TokenMatch(buffer, "OBJECT", 6))
|
if (!TokenMatch(mBuffer.data, "OBJECT", 6))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&mBuffer.data, mBuffer.end);
|
||||||
|
|
||||||
++mNumMeshes;
|
++mNumMeshes;
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
|
||||||
Object &obj = objects.back();
|
Object &obj = objects.back();
|
||||||
|
|
||||||
aiLight *light = nullptr;
|
aiLight *light = nullptr;
|
||||||
if (!ASSIMP_strincmp(buffer, "light", 5)) {
|
if (!ASSIMP_strincmp(mBuffer.data, "light", 5)) {
|
||||||
// This is a light source. Add it to the list
|
// This is a light source. Add it to the list
|
||||||
mLights->push_back(light = new aiLight());
|
mLights->push_back(light = new aiLight());
|
||||||
|
|
||||||
|
@ -198,16 +198,16 @@ bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
|
||||||
|
|
||||||
ASSIMP_LOG_VERBOSE_DEBUG("AC3D: Light source encountered");
|
ASSIMP_LOG_VERBOSE_DEBUG("AC3D: Light source encountered");
|
||||||
obj.type = Object::Light;
|
obj.type = Object::Light;
|
||||||
} else if (!ASSIMP_strincmp(buffer, "group", 5)) {
|
} else if (!ASSIMP_strincmp(mBuffer.data, "group", 5)) {
|
||||||
obj.type = Object::Group;
|
obj.type = Object::Group;
|
||||||
} else if (!ASSIMP_strincmp(buffer, "world", 5)) {
|
} else if (!ASSIMP_strincmp(mBuffer.data, "world", 5)) {
|
||||||
obj.type = Object::World;
|
obj.type = Object::World;
|
||||||
} else
|
} else
|
||||||
obj.type = Object::Poly;
|
obj.type = Object::Poly;
|
||||||
while (GetNextLine()) {
|
while (GetNextLine()) {
|
||||||
if (TokenMatch(buffer, "kids", 4)) {
|
if (TokenMatch(mBuffer.data, "kids", 4)) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&mBuffer.data, mBuffer.end);
|
||||||
unsigned int num = strtoul10(buffer, &buffer);
|
unsigned int num = strtoul10(mBuffer.data, &mBuffer.data);
|
||||||
GetNextLine();
|
GetNextLine();
|
||||||
if (num) {
|
if (num) {
|
||||||
// load the children of this object recursively
|
// load the children of this object recursively
|
||||||
|
@ -220,51 +220,44 @@ bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else if (TokenMatch(buffer, "name", 4)) {
|
} else if (TokenMatch(mBuffer.data, "name", 4)) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&mBuffer.data, mBuffer.data);
|
||||||
buffer = AcGetString(buffer, obj.name);
|
mBuffer.data = AcGetString(mBuffer.data, mBuffer.end, obj.name);
|
||||||
|
|
||||||
// If this is a light source, we'll also need to store
|
// If this is a light source, we'll also need to store
|
||||||
// the name of the node in it.
|
// the name of the node in it.
|
||||||
if (light) {
|
if (light) {
|
||||||
light->mName.Set(obj.name);
|
light->mName.Set(obj.name);
|
||||||
}
|
}
|
||||||
} else if (TokenMatch(buffer, "texture", 7)) {
|
} else if (TokenMatch(mBuffer.data, "texture", 7)) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&mBuffer.data, mBuffer.end);
|
||||||
// skip empty acc texture
|
|
||||||
if (*buffer != '\"') {
|
|
||||||
if (!TokenMatch(buffer, "empty_texture_no_mapping", 24)) {
|
|
||||||
ASSIMP_LOG_ERROR("AC3D: Unquoted texture string");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
std::string texture;
|
std::string texture;
|
||||||
buffer = AcGetString(buffer, texture);
|
mBuffer.data = AcGetString(mBuffer.data, mBuffer.end, texture);
|
||||||
obj.textures.push_back(texture);
|
obj.textures.push_back(texture);
|
||||||
}
|
} else if (TokenMatch(mBuffer.data, "texrep", 6)) {
|
||||||
} else if (TokenMatch(buffer, "texrep", 6)) {
|
SkipSpaces(&mBuffer.data, mBuffer.end);
|
||||||
SkipSpaces(&buffer);
|
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 2, &obj.texRepeat);
|
||||||
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &obj.texRepeat);
|
|
||||||
if (!obj.texRepeat.x || !obj.texRepeat.y)
|
if (!obj.texRepeat.x || !obj.texRepeat.y)
|
||||||
obj.texRepeat = aiVector2D(1.f, 1.f);
|
obj.texRepeat = aiVector2D(1.f, 1.f);
|
||||||
} else if (TokenMatch(buffer, "texoff", 6)) {
|
} else if (TokenMatch(mBuffer.data, "texoff", 6)) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&mBuffer.data, mBuffer.end);
|
||||||
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &obj.texOffset);
|
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 2, &obj.texOffset);
|
||||||
} else if (TokenMatch(buffer, "rot", 3)) {
|
} else if (TokenMatch(mBuffer.data, "rot", 3)) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&mBuffer.data, mBuffer.end);
|
||||||
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 9, &obj.rotation);
|
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 9, &obj.rotation);
|
||||||
} else if (TokenMatch(buffer, "loc", 3)) {
|
} else if (TokenMatch(mBuffer.data, "loc", 3)) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&mBuffer.data, mBuffer.end);
|
||||||
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 3, &obj.translation);
|
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 3, &obj.translation);
|
||||||
} else if (TokenMatch(buffer, "subdiv", 6)) {
|
} else if (TokenMatch(mBuffer.data, "subdiv", 6)) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&mBuffer.data, mBuffer.end);
|
||||||
obj.subDiv = strtoul10(buffer, &buffer);
|
obj.subDiv = strtoul10(mBuffer.data, &mBuffer.data);
|
||||||
} else if (TokenMatch(buffer, "crease", 6)) {
|
} else if (TokenMatch(mBuffer.data, "crease", 6)) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&mBuffer.data, mBuffer.end);
|
||||||
obj.crease = fast_atof(buffer);
|
obj.crease = fast_atof(mBuffer.data);
|
||||||
} else if (TokenMatch(buffer, "numvert", 7)) {
|
} else if (TokenMatch(mBuffer.data, "numvert", 7)) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&mBuffer.data, mBuffer.end);
|
||||||
|
|
||||||
unsigned int t = strtoul10(buffer, &buffer);
|
unsigned int t = strtoul10(mBuffer.data, &mBuffer.data);
|
||||||
if (t >= AI_MAX_ALLOC(aiVector3D)) {
|
if (t >= AI_MAX_ALLOC(aiVector3D)) {
|
||||||
throw DeadlyImportError("AC3D: Too many vertices, would run out of memory");
|
throw DeadlyImportError("AC3D: Too many vertices, would run out of memory");
|
||||||
}
|
}
|
||||||
|
@ -273,59 +266,59 @@ bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
|
||||||
if (!GetNextLine()) {
|
if (!GetNextLine()) {
|
||||||
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: not all vertices have been parsed yet");
|
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: not all vertices have been parsed yet");
|
||||||
break;
|
break;
|
||||||
} else if (!IsNumeric(*buffer)) {
|
} else if (!IsNumeric(*mBuffer.data)) {
|
||||||
ASSIMP_LOG_ERROR("AC3D: Unexpected token: not all vertices have been parsed yet");
|
ASSIMP_LOG_ERROR("AC3D: Unexpected token: not all vertices have been parsed yet");
|
||||||
--buffer; // make sure the line is processed a second time
|
--mBuffer.data; // make sure the line is processed a second time
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
obj.vertices.emplace_back();
|
obj.vertices.emplace_back();
|
||||||
aiVector3D &v = obj.vertices.back();
|
aiVector3D &v = obj.vertices.back();
|
||||||
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 3, &v.x);
|
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 3, &v.x);
|
||||||
}
|
}
|
||||||
} else if (TokenMatch(buffer, "numsurf", 7)) {
|
} else if (TokenMatch(mBuffer.data, "numsurf", 7)) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&mBuffer.data, mBuffer.end);
|
||||||
|
|
||||||
bool Q3DWorkAround = false;
|
bool Q3DWorkAround = false;
|
||||||
|
|
||||||
const unsigned int t = strtoul10(buffer, &buffer);
|
const unsigned int t = strtoul10(mBuffer.data, &mBuffer.data);
|
||||||
obj.surfaces.reserve(t);
|
obj.surfaces.reserve(t);
|
||||||
for (unsigned int i = 0; i < t; ++i) {
|
for (unsigned int i = 0; i < t; ++i) {
|
||||||
GetNextLine();
|
GetNextLine();
|
||||||
if (!TokenMatch(buffer, "SURF", 4)) {
|
if (!TokenMatch(mBuffer.data, "SURF", 4)) {
|
||||||
// FIX: this can occur for some files - Quick 3D for
|
// FIX: this can occur for some files - Quick 3D for
|
||||||
// example writes no surf chunks
|
// example writes no surf chunks
|
||||||
if (!Q3DWorkAround) {
|
if (!Q3DWorkAround) {
|
||||||
ASSIMP_LOG_WARN("AC3D: SURF token was expected");
|
ASSIMP_LOG_WARN("AC3D: SURF token was expected");
|
||||||
ASSIMP_LOG_VERBOSE_DEBUG("Continuing with Quick3D Workaround enabled");
|
ASSIMP_LOG_VERBOSE_DEBUG("Continuing with Quick3D Workaround enabled");
|
||||||
}
|
}
|
||||||
--buffer; // make sure the line is processed a second time
|
--mBuffer.data; // make sure the line is processed a second time
|
||||||
// break; --- see fix notes above
|
// break; --- see fix notes above
|
||||||
|
|
||||||
Q3DWorkAround = true;
|
Q3DWorkAround = true;
|
||||||
}
|
}
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&mBuffer.data, mBuffer.end);
|
||||||
obj.surfaces.emplace_back();
|
obj.surfaces.emplace_back();
|
||||||
Surface &surf = obj.surfaces.back();
|
Surface &surf = obj.surfaces.back();
|
||||||
surf.flags = strtoul_cppstyle(buffer);
|
surf.flags = strtoul_cppstyle(mBuffer.data);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!GetNextLine()) {
|
if (!GetNextLine()) {
|
||||||
throw DeadlyImportError("AC3D: Unexpected EOF: surface is incomplete");
|
throw DeadlyImportError("AC3D: Unexpected EOF: surface is incomplete");
|
||||||
}
|
}
|
||||||
if (TokenMatch(buffer, "mat", 3)) {
|
if (TokenMatch(mBuffer.data, "mat", 3)) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&mBuffer.data, mBuffer.end);
|
||||||
surf.mat = strtoul10(buffer);
|
surf.mat = strtoul10(mBuffer.data);
|
||||||
} else if (TokenMatch(buffer, "refs", 4)) {
|
} else if (TokenMatch(mBuffer.data, "refs", 4)) {
|
||||||
// --- see fix notes above
|
// --- see fix notes above
|
||||||
if (Q3DWorkAround) {
|
if (Q3DWorkAround) {
|
||||||
if (!surf.entries.empty()) {
|
if (!surf.entries.empty()) {
|
||||||
buffer -= 6;
|
mBuffer.data -= 6;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&mBuffer.data, mBuffer.end);
|
||||||
const unsigned int m = strtoul10(buffer);
|
const unsigned int m = strtoul10(mBuffer.data);
|
||||||
surf.entries.reserve(m);
|
surf.entries.reserve(m);
|
||||||
|
|
||||||
obj.numRefs += m;
|
obj.numRefs += m;
|
||||||
|
@ -338,12 +331,12 @@ bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
|
||||||
surf.entries.emplace_back();
|
surf.entries.emplace_back();
|
||||||
Surface::SurfaceEntry &entry = surf.entries.back();
|
Surface::SurfaceEntry &entry = surf.entries.back();
|
||||||
|
|
||||||
entry.first = strtoul10(buffer, &buffer);
|
entry.first = strtoul10(mBuffer.data, &mBuffer.data);
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&mBuffer.data, mBuffer.end);
|
||||||
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &entry.second);
|
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 2, &entry.second);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
--buffer; // make sure the line is processed a second time
|
--mBuffer.data; // make sure the line is processed a second time
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -475,16 +468,15 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ((*it).GetType()) {
|
switch ((*it).GetType()) {
|
||||||
// closed line
|
case Surface::ClosedLine: // closed line
|
||||||
case Surface::ClosedLine:
|
needMat[idx].first += static_cast<unsigned int>((*it).entries.size());
|
||||||
needMat[idx].first += (unsigned int)(*it).entries.size();
|
needMat[idx].second += static_cast<unsigned int>((*it).entries.size() << 1u);
|
||||||
needMat[idx].second += (unsigned int)(*it).entries.size() << 1u;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// unclosed line
|
// unclosed line
|
||||||
case Surface::OpenLine:
|
case Surface::OpenLine:
|
||||||
needMat[idx].first += (unsigned int)(*it).entries.size() - 1;
|
needMat[idx].first += static_cast<unsigned int>((*it).entries.size() - 1);
|
||||||
needMat[idx].second += ((unsigned int)(*it).entries.size() - 1) << 1u;
|
needMat[idx].second += static_cast<unsigned int>(((*it).entries.size() - 1) << 1u);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// triangle strip
|
// triangle strip
|
||||||
|
@ -763,17 +755,18 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
|
||||||
std::vector<char> mBuffer2;
|
std::vector<char> mBuffer2;
|
||||||
TextFileToBuffer(file.get(), mBuffer2);
|
TextFileToBuffer(file.get(), mBuffer2);
|
||||||
|
|
||||||
buffer = &mBuffer2[0];
|
mBuffer.data = &mBuffer2[0];
|
||||||
|
mBuffer.end = &mBuffer2[0] + mBuffer2.size();
|
||||||
mNumMeshes = 0;
|
mNumMeshes = 0;
|
||||||
|
|
||||||
mLightsCounter = mPolysCounter = mWorldsCounter = mGroupsCounter = 0;
|
mLightsCounter = mPolysCounter = mWorldsCounter = mGroupsCounter = 0;
|
||||||
|
|
||||||
if (::strncmp(buffer, "AC3D", 4)) {
|
if (::strncmp(mBuffer.data, "AC3D", 4)) {
|
||||||
throw DeadlyImportError("AC3D: No valid AC3D file, magic sequence not found");
|
throw DeadlyImportError("AC3D: No valid AC3D file, magic sequence not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
// print the file format version to the console
|
// print the file format version to the console
|
||||||
unsigned int version = HexDigitToDecimal(buffer[4]);
|
unsigned int version = HexDigitToDecimal(mBuffer.data[4]);
|
||||||
char msg[3];
|
char msg[3];
|
||||||
ASSIMP_itoa10(msg, 3, version);
|
ASSIMP_itoa10(msg, 3, version);
|
||||||
ASSIMP_LOG_INFO("AC3D file format version: ", msg);
|
ASSIMP_LOG_INFO("AC3D file format version: ", msg);
|
||||||
|
@ -788,31 +781,31 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
|
||||||
mLights = &lights;
|
mLights = &lights;
|
||||||
|
|
||||||
while (GetNextLine()) {
|
while (GetNextLine()) {
|
||||||
if (TokenMatch(buffer, "MATERIAL", 8)) {
|
if (TokenMatch(mBuffer.data, "MATERIAL", 8)) {
|
||||||
materials.emplace_back();
|
materials.emplace_back();
|
||||||
Material &mat = materials.back();
|
Material &mat = materials.back();
|
||||||
|
|
||||||
// manually parse the material ... sscanf would use the buldin atof ...
|
// manually parse the material ... sscanf would use the buldin atof ...
|
||||||
// Format: (name) rgb %f %f %f amb %f %f %f emis %f %f %f spec %f %f %f shi %d trans %f
|
// Format: (name) rgb %f %f %f amb %f %f %f emis %f %f %f spec %f %f %f shi %d trans %f
|
||||||
|
|
||||||
buffer = AcSkipToNextToken(buffer);
|
mBuffer.data = AcSkipToNextToken(mBuffer.data, mBuffer.end);
|
||||||
if ('\"' == *buffer) {
|
if ('\"' == *mBuffer.data) {
|
||||||
buffer = AcGetString(buffer, mat.name);
|
mBuffer.data = AcGetString(mBuffer.data, mBuffer.end, mat.name);
|
||||||
buffer = AcSkipToNextToken(buffer);
|
mBuffer.data = AcSkipToNextToken(mBuffer.data, mBuffer.end);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer = TAcCheckedLoadFloatArray(buffer, "rgb", 3, 3, &mat.rgb);
|
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "rgb", 3, 3, &mat.rgb);
|
||||||
buffer = TAcCheckedLoadFloatArray(buffer, "amb", 3, 3, &mat.amb);
|
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "amb", 3, 3, &mat.amb);
|
||||||
buffer = TAcCheckedLoadFloatArray(buffer, "emis", 4, 3, &mat.emis);
|
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "emis", 4, 3, &mat.emis);
|
||||||
buffer = TAcCheckedLoadFloatArray(buffer, "spec", 4, 3, &mat.spec);
|
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "spec", 4, 3, &mat.spec);
|
||||||
buffer = TAcCheckedLoadFloatArray(buffer, "shi", 3, 1, &mat.shin);
|
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "shi", 3, 1, &mat.shin);
|
||||||
buffer = TAcCheckedLoadFloatArray(buffer, "trans", 5, 1, &mat.trans);
|
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "trans", 5, 1, &mat.trans);
|
||||||
} else {
|
} else {
|
||||||
LoadObjectSection(rootObjects);
|
LoadObjectSection(rootObjects);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rootObjects.empty() || !mNumMeshes) {
|
if (rootObjects.empty() || mNumMeshes == 0u) {
|
||||||
throw DeadlyImportError("AC3D: No meshes have been loaded");
|
throw DeadlyImportError("AC3D: No meshes have been loaded");
|
||||||
}
|
}
|
||||||
if (materials.empty()) {
|
if (materials.empty()) {
|
||||||
|
@ -828,7 +821,7 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
|
||||||
materials.reserve(mNumMeshes);
|
materials.reserve(mNumMeshes);
|
||||||
|
|
||||||
// generate a dummy root if there are multiple objects on the top layer
|
// generate a dummy root if there are multiple objects on the top layer
|
||||||
Object *root;
|
Object *root = nullptr;
|
||||||
if (1 == rootObjects.size())
|
if (1 == rootObjects.size())
|
||||||
root = &rootObjects[0];
|
root = &rootObjects[0];
|
||||||
else {
|
else {
|
||||||
|
@ -841,7 +834,7 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
|
||||||
delete root;
|
delete root;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!::strncmp(pScene->mRootNode->mName.data, "Node", 4)) {
|
if (::strncmp(pScene->mRootNode->mName.data, "Node", 4) == 0) {
|
||||||
pScene->mRootNode->mName.Set("<AC3DWorld>");
|
pScene->mRootNode->mName.Set("<AC3DWorld>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -860,7 +853,7 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
|
||||||
|
|
||||||
// copy lights
|
// copy lights
|
||||||
pScene->mNumLights = (unsigned int)lights.size();
|
pScene->mNumLights = (unsigned int)lights.size();
|
||||||
if (lights.size()) {
|
if (!lights.empty()) {
|
||||||
pScene->mLights = new aiLight *[lights.size()];
|
pScene->mLights = new aiLight *[lights.size()];
|
||||||
::memcpy(pScene->mLights, &lights[0], lights.size() * sizeof(void *));
|
::memcpy(pScene->mLights, &lights[0], lights.size() * sizeof(void *));
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Open Asset Import Library (assimp)
|
Open Asset Import Library (assimp)
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
Copyright (c) 2006-2022, assimp team
|
Copyright (c) 2006-2024, assimp team
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
|
@ -242,7 +242,7 @@ private:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// points to the next data line
|
// points to the next data line
|
||||||
const char *buffer;
|
aiBuffer mBuffer;
|
||||||
|
|
||||||
// Configuration option: if enabled, up to two meshes
|
// Configuration option: if enabled, up to two meshes
|
||||||
// are generated per material: those faces who have
|
// are generated per material: those faces who have
|
||||||
|
|
|
@ -110,10 +110,12 @@ using namespace Assimp::ASE;
|
||||||
++filePtr;
|
++filePtr;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Parser::Parser(const char *szFile, unsigned int fileFormatDefault) {
|
Parser::Parser(const char *szFile, unsigned int fileFormatDefault) :
|
||||||
|
filePtr(nullptr), mEnd (nullptr) {
|
||||||
ai_assert(nullptr != szFile);
|
ai_assert(nullptr != szFile);
|
||||||
|
|
||||||
filePtr = szFile;
|
filePtr = szFile;
|
||||||
|
mEnd = filePtr + std::strlen(filePtr);
|
||||||
iFileFormat = fileFormatDefault;
|
iFileFormat = fileFormatDefault;
|
||||||
|
|
||||||
// make sure that the color values are invalid
|
// make sure that the color values are invalid
|
||||||
|
@ -179,14 +181,22 @@ bool Parser::SkipToNextToken() {
|
||||||
while (true) {
|
while (true) {
|
||||||
char me = *filePtr;
|
char me = *filePtr;
|
||||||
|
|
||||||
|
if (filePtr == mEnd) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// increase the line number counter if necessary
|
// increase the line number counter if necessary
|
||||||
if (IsLineEnd(me) && !bLastWasEndLine) {
|
if (IsLineEnd(me) && !bLastWasEndLine) {
|
||||||
++iLineNumber;
|
++iLineNumber;
|
||||||
bLastWasEndLine = true;
|
bLastWasEndLine = true;
|
||||||
} else
|
} else
|
||||||
bLastWasEndLine = false;
|
bLastWasEndLine = false;
|
||||||
if ('*' == me || '}' == me || '{' == me) return true;
|
if ('*' == me || '}' == me || '{' == me) {
|
||||||
if ('\0' == me) return false;
|
return true;
|
||||||
|
}
|
||||||
|
if ('\0' == me) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
++filePtr;
|
++filePtr;
|
||||||
}
|
}
|
||||||
|
@ -344,8 +354,9 @@ void Parser::ParseLV1SoftSkinBlock() {
|
||||||
unsigned int numVerts = 0;
|
unsigned int numVerts = 0;
|
||||||
|
|
||||||
const char *sz = filePtr;
|
const char *sz = filePtr;
|
||||||
while (!IsSpaceOrNewLine(*filePtr))
|
while (!IsSpaceOrNewLine(*filePtr)) {
|
||||||
++filePtr;
|
++filePtr;
|
||||||
|
}
|
||||||
|
|
||||||
const unsigned int diff = (unsigned int)(filePtr - sz);
|
const unsigned int diff = (unsigned int)(filePtr - sz);
|
||||||
if (diff) {
|
if (diff) {
|
||||||
|
@ -363,24 +374,24 @@ void Parser::ParseLV1SoftSkinBlock() {
|
||||||
// Skip the mesh data - until we find a new mesh
|
// Skip the mesh data - until we find a new mesh
|
||||||
// or the end of the *MESH_SOFTSKINVERTS section
|
// or the end of the *MESH_SOFTSKINVERTS section
|
||||||
while (true) {
|
while (true) {
|
||||||
SkipSpacesAndLineEnd(&filePtr);
|
SkipSpacesAndLineEnd(&filePtr, mEnd);
|
||||||
if (*filePtr == '}') {
|
if (*filePtr == '}') {
|
||||||
++filePtr;
|
++filePtr;
|
||||||
return;
|
return;
|
||||||
} else if (!IsNumeric(*filePtr))
|
} else if (!IsNumeric(*filePtr))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
SkipLine(&filePtr);
|
SkipLine(&filePtr, mEnd);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SkipSpacesAndLineEnd(&filePtr);
|
SkipSpacesAndLineEnd(&filePtr, mEnd);
|
||||||
ParseLV4MeshLong(numVerts);
|
ParseLV4MeshLong(numVerts);
|
||||||
|
|
||||||
// Reserve enough storage
|
// Reserve enough storage
|
||||||
curMesh->mBoneVertices.reserve(numVerts);
|
curMesh->mBoneVertices.reserve(numVerts);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < numVerts; ++i) {
|
for (unsigned int i = 0; i < numVerts; ++i) {
|
||||||
SkipSpacesAndLineEnd(&filePtr);
|
SkipSpacesAndLineEnd(&filePtr, mEnd);
|
||||||
unsigned int numWeights;
|
unsigned int numWeights;
|
||||||
ParseLV4MeshLong(numWeights);
|
ParseLV4MeshLong(numWeights);
|
||||||
|
|
||||||
|
@ -422,7 +433,7 @@ void Parser::ParseLV1SoftSkinBlock() {
|
||||||
if (*filePtr == '\0')
|
if (*filePtr == '\0')
|
||||||
return;
|
return;
|
||||||
++filePtr;
|
++filePtr;
|
||||||
SkipSpacesAndLineEnd(&filePtr);
|
SkipSpacesAndLineEnd(&filePtr, mEnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -743,7 +754,7 @@ void Parser::ParseLV3MapBlock(Texture &map) {
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool Parser::ParseString(std::string &out, const char *szName) {
|
bool Parser::ParseString(std::string &out, const char *szName) {
|
||||||
char szBuffer[1024];
|
char szBuffer[1024];
|
||||||
if (!SkipSpaces(&filePtr)) {
|
if (!SkipSpaces(&filePtr, mEnd)) {
|
||||||
|
|
||||||
ai_snprintf(szBuffer, 1024, "Unable to parse %s block: Unexpected EOL", szName);
|
ai_snprintf(szBuffer, 1024, "Unable to parse %s block: Unexpected EOL", szName);
|
||||||
LogWarning(szBuffer);
|
LogWarning(szBuffer);
|
||||||
|
@ -1355,7 +1366,7 @@ void Parser::ParseLV4MeshBones(unsigned int iNumBones, ASE::Mesh &mesh) {
|
||||||
// Mesh bone with name ...
|
// Mesh bone with name ...
|
||||||
if (TokenMatch(filePtr, "MESH_BONE_NAME", 14)) {
|
if (TokenMatch(filePtr, "MESH_BONE_NAME", 14)) {
|
||||||
// parse an index ...
|
// parse an index ...
|
||||||
if (SkipSpaces(&filePtr)) {
|
if (SkipSpaces(&filePtr, mEnd)) {
|
||||||
unsigned int iIndex = strtoul10(filePtr, &filePtr);
|
unsigned int iIndex = strtoul10(filePtr, &filePtr);
|
||||||
if (iIndex >= iNumBones) {
|
if (iIndex >= iNumBones) {
|
||||||
LogWarning("Bone index is out of bounds");
|
LogWarning("Bone index is out of bounds");
|
||||||
|
@ -1395,11 +1406,11 @@ void Parser::ParseLV4MeshBonesVertices(unsigned int iNumVertices, ASE::Mesh &mes
|
||||||
std::pair<int, float> pairOut;
|
std::pair<int, float> pairOut;
|
||||||
while (true) {
|
while (true) {
|
||||||
// first parse the bone index ...
|
// first parse the bone index ...
|
||||||
if (!SkipSpaces(&filePtr)) break;
|
if (!SkipSpaces(&filePtr, mEnd)) break;
|
||||||
pairOut.first = strtoul10(filePtr, &filePtr);
|
pairOut.first = strtoul10(filePtr, &filePtr);
|
||||||
|
|
||||||
// then parse the vertex weight
|
// then parse the vertex weight
|
||||||
if (!SkipSpaces(&filePtr)) break;
|
if (!SkipSpaces(&filePtr, mEnd)) break;
|
||||||
filePtr = fast_atoreal_move<float>(filePtr, pairOut.second);
|
filePtr = fast_atoreal_move<float>(filePtr, pairOut.second);
|
||||||
|
|
||||||
// -1 marks unused entries
|
// -1 marks unused entries
|
||||||
|
@ -1675,7 +1686,7 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh &sMesh) {
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Parser::ParseLV4MeshFace(ASE::Face &out) {
|
void Parser::ParseLV4MeshFace(ASE::Face &out) {
|
||||||
// skip spaces and tabs
|
// skip spaces and tabs
|
||||||
if (!SkipSpaces(&filePtr)) {
|
if (!SkipSpaces(&filePtr, mEnd)) {
|
||||||
LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL [#1]");
|
LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL [#1]");
|
||||||
SkipToNextToken();
|
SkipToNextToken();
|
||||||
return;
|
return;
|
||||||
|
@ -1685,7 +1696,7 @@ void Parser::ParseLV4MeshFace(ASE::Face &out) {
|
||||||
out.iFace = strtoul10(filePtr, &filePtr);
|
out.iFace = strtoul10(filePtr, &filePtr);
|
||||||
|
|
||||||
// next character should be ':'
|
// next character should be ':'
|
||||||
if (!SkipSpaces(&filePtr)) {
|
if (!SkipSpaces(&filePtr, mEnd)) {
|
||||||
// FIX: there are some ASE files which haven't got : here ....
|
// FIX: there are some ASE files which haven't got : here ....
|
||||||
LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. \':\' expected [#2]");
|
LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. \':\' expected [#2]");
|
||||||
SkipToNextToken();
|
SkipToNextToken();
|
||||||
|
@ -1697,7 +1708,7 @@ void Parser::ParseLV4MeshFace(ASE::Face &out) {
|
||||||
// Parse all mesh indices
|
// Parse all mesh indices
|
||||||
for (unsigned int i = 0; i < 3; ++i) {
|
for (unsigned int i = 0; i < 3; ++i) {
|
||||||
unsigned int iIndex = 0;
|
unsigned int iIndex = 0;
|
||||||
if (!SkipSpaces(&filePtr)) {
|
if (!SkipSpaces(&filePtr, mEnd)) {
|
||||||
LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL");
|
LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL");
|
||||||
SkipToNextToken();
|
SkipToNextToken();
|
||||||
return;
|
return;
|
||||||
|
@ -1723,7 +1734,7 @@ void Parser::ParseLV4MeshFace(ASE::Face &out) {
|
||||||
++filePtr;
|
++filePtr;
|
||||||
|
|
||||||
// next character should be ':'
|
// next character should be ':'
|
||||||
if (!SkipSpaces(&filePtr) || ':' != *filePtr) {
|
if (!SkipSpaces(&filePtr, mEnd) || ':' != *filePtr) {
|
||||||
LogWarning("Unable to parse *MESH_FACE Element: "
|
LogWarning("Unable to parse *MESH_FACE Element: "
|
||||||
"Unexpected EOL. \':\' expected [#2]");
|
"Unexpected EOL. \':\' expected [#2]");
|
||||||
SkipToNextToken();
|
SkipToNextToken();
|
||||||
|
@ -1731,9 +1742,9 @@ void Parser::ParseLV4MeshFace(ASE::Face &out) {
|
||||||
}
|
}
|
||||||
|
|
||||||
++filePtr;
|
++filePtr;
|
||||||
if (!SkipSpaces(&filePtr)) {
|
if (!SkipSpaces(&filePtr, mEnd)) {
|
||||||
LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. "
|
LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. "
|
||||||
"Vertex index ecpected [#4]");
|
"Vertex index expected [#4]");
|
||||||
SkipToNextToken();
|
SkipToNextToken();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1752,7 +1763,7 @@ void Parser::ParseLV4MeshFace(ASE::Face &out) {
|
||||||
|
|
||||||
// parse the smoothing group of the face
|
// parse the smoothing group of the face
|
||||||
if (TokenMatch(filePtr, "*MESH_SMOOTHING", 15)) {
|
if (TokenMatch(filePtr, "*MESH_SMOOTHING", 15)) {
|
||||||
if (!SkipSpaces(&filePtr)) {
|
if (!SkipSpaces(&filePtr, mEnd)) {
|
||||||
LogWarning("Unable to parse *MESH_SMOOTHING Element: "
|
LogWarning("Unable to parse *MESH_SMOOTHING Element: "
|
||||||
"Unexpected EOL. Smoothing group(s) expected [#5]");
|
"Unexpected EOL. Smoothing group(s) expected [#5]");
|
||||||
SkipToNextToken();
|
SkipToNextToken();
|
||||||
|
@ -1771,12 +1782,12 @@ void Parser::ParseLV4MeshFace(ASE::Face &out) {
|
||||||
LogWarning(message.c_str());
|
LogWarning(message.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SkipSpaces(&filePtr);
|
SkipSpaces(&filePtr, mEnd);
|
||||||
if (',' != *filePtr) {
|
if (',' != *filePtr) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
++filePtr;
|
++filePtr;
|
||||||
SkipSpaces(&filePtr);
|
SkipSpaces(&filePtr, mEnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1792,7 +1803,7 @@ void Parser::ParseLV4MeshFace(ASE::Face &out) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TokenMatch(filePtr, "*MESH_MTLID", 11)) {
|
if (TokenMatch(filePtr, "*MESH_MTLID", 11)) {
|
||||||
if (!SkipSpaces(&filePtr)) {
|
if (!SkipSpaces(&filePtr, mEnd)) {
|
||||||
LogWarning("Unable to parse *MESH_MTLID Element: Unexpected EOL. "
|
LogWarning("Unable to parse *MESH_MTLID Element: Unexpected EOL. "
|
||||||
"Material index expected [#6]");
|
"Material index expected [#6]");
|
||||||
SkipToNextToken();
|
SkipToNextToken();
|
||||||
|
@ -1840,7 +1851,7 @@ void Parser::ParseLV4MeshFloatTriple(ai_real *apOut) {
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Parser::ParseLV4MeshFloat(ai_real &fOut) {
|
void Parser::ParseLV4MeshFloat(ai_real &fOut) {
|
||||||
// skip spaces and tabs
|
// skip spaces and tabs
|
||||||
if (!SkipSpaces(&filePtr)) {
|
if (!SkipSpaces(&filePtr, mEnd)) {
|
||||||
// LOG
|
// LOG
|
||||||
LogWarning("Unable to parse float: unexpected EOL [#1]");
|
LogWarning("Unable to parse float: unexpected EOL [#1]");
|
||||||
fOut = 0.0;
|
fOut = 0.0;
|
||||||
|
@ -1853,7 +1864,7 @@ void Parser::ParseLV4MeshFloat(ai_real &fOut) {
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Parser::ParseLV4MeshLong(unsigned int &iOut) {
|
void Parser::ParseLV4MeshLong(unsigned int &iOut) {
|
||||||
// Skip spaces and tabs
|
// Skip spaces and tabs
|
||||||
if (!SkipSpaces(&filePtr)) {
|
if (!SkipSpaces(&filePtr, mEnd)) {
|
||||||
// LOG
|
// LOG
|
||||||
LogWarning("Unable to parse long: unexpected EOL [#1]");
|
LogWarning("Unable to parse long: unexpected EOL [#1]");
|
||||||
iOut = 0;
|
iOut = 0;
|
||||||
|
|
|
@ -620,6 +620,9 @@ public:
|
||||||
//! Pointer to current data
|
//! Pointer to current data
|
||||||
const char *filePtr;
|
const char *filePtr;
|
||||||
|
|
||||||
|
/// The end pointer of the file data
|
||||||
|
const char *mEnd;
|
||||||
|
|
||||||
//! background color to be passed to the viewer
|
//! background color to be passed to the viewer
|
||||||
//! QNAN if none was found
|
//! QNAN if none was found
|
||||||
aiColor3D m_clrBackground;
|
aiColor3D m_clrBackground;
|
||||||
|
|
|
@ -473,8 +473,9 @@ void COBImporter::ReadBasicNodeInfo_Ascii(Node &msh, LineSplitter &splitter, con
|
||||||
} else if (splitter.match_start("Transform")) {
|
} else if (splitter.match_start("Transform")) {
|
||||||
for (unsigned int y = 0; y < 4 && ++splitter; ++y) {
|
for (unsigned int y = 0; y < 4 && ++splitter; ++y) {
|
||||||
const char *s = splitter->c_str();
|
const char *s = splitter->c_str();
|
||||||
|
const char *end = s + splitter->size();
|
||||||
for (unsigned int x = 0; x < 4; ++x) {
|
for (unsigned int x = 0; x < 4; ++x) {
|
||||||
SkipSpaces(&s);
|
SkipSpaces(&s, end);
|
||||||
msh.transform[y][x] = fast_atof(&s);
|
msh.transform[y][x] = fast_atof(&s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -486,12 +487,12 @@ void COBImporter::ReadBasicNodeInfo_Ascii(Node &msh, LineSplitter &splitter, con
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void COBImporter::ReadFloat3Tuple_Ascii(T &fill, const char **in) {
|
void COBImporter::ReadFloat3Tuple_Ascii(T &fill, const char **in, const char *end) {
|
||||||
const char *rgb = *in;
|
const char *rgb = *in;
|
||||||
for (unsigned int i = 0; i < 3; ++i) {
|
for (unsigned int i = 0; i < 3; ++i) {
|
||||||
SkipSpaces(&rgb);
|
SkipSpaces(&rgb, end);
|
||||||
if (*rgb == ',') ++rgb;
|
if (*rgb == ',') ++rgb;
|
||||||
SkipSpaces(&rgb);
|
SkipSpaces(&rgb, end);
|
||||||
|
|
||||||
fill[i] = fast_atof(&rgb);
|
fill[i] = fast_atof(&rgb);
|
||||||
}
|
}
|
||||||
|
@ -538,7 +539,7 @@ void COBImporter::ReadMat1_Ascii(Scene &out, LineSplitter &splitter, const Chunk
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *rgb = splitter[1];
|
const char *rgb = splitter[1];
|
||||||
ReadFloat3Tuple_Ascii(mat.rgb, &rgb);
|
ReadFloat3Tuple_Ascii(mat.rgb, &rgb, splitter.getEnd());
|
||||||
|
|
||||||
++splitter;
|
++splitter;
|
||||||
if (!splitter.match_start("alpha ")) {
|
if (!splitter.match_start("alpha ")) {
|
||||||
|
@ -617,20 +618,21 @@ void COBImporter::ReadLght_Ascii(Scene &out, LineSplitter &splitter, const Chunk
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *rgb = splitter[1];
|
const char *rgb = splitter[1];
|
||||||
ReadFloat3Tuple_Ascii(msh.color, &rgb);
|
const char *end = splitter.getEnd();
|
||||||
|
ReadFloat3Tuple_Ascii(msh.color, &rgb, end);
|
||||||
|
|
||||||
SkipSpaces(&rgb);
|
SkipSpaces(&rgb, end);
|
||||||
if (strncmp(rgb, "cone angle", 10) != 0) {
|
if (strncmp(rgb, "cone angle", 10) != 0) {
|
||||||
ASSIMP_LOG_WARN("Expected `cone angle` entity in `color` line in `Lght` chunk ", nfo.id);
|
ASSIMP_LOG_WARN("Expected `cone angle` entity in `color` line in `Lght` chunk ", nfo.id);
|
||||||
}
|
}
|
||||||
SkipSpaces(rgb + 10, &rgb);
|
SkipSpaces(rgb + 10, &rgb, end);
|
||||||
msh.angle = fast_atof(&rgb);
|
msh.angle = fast_atof(&rgb);
|
||||||
|
|
||||||
SkipSpaces(&rgb);
|
SkipSpaces(&rgb, end);
|
||||||
if (strncmp(rgb, "inner angle", 11) != 0) {
|
if (strncmp(rgb, "inner angle", 11) != 0) {
|
||||||
ASSIMP_LOG_WARN("Expected `inner angle` entity in `color` line in `Lght` chunk ", nfo.id);
|
ASSIMP_LOG_WARN("Expected `inner angle` entity in `color` line in `Lght` chunk ", nfo.id);
|
||||||
}
|
}
|
||||||
SkipSpaces(rgb + 11, &rgb);
|
SkipSpaces(rgb + 11, &rgb, end);
|
||||||
msh.inner_angle = fast_atof(&rgb);
|
msh.inner_angle = fast_atof(&rgb);
|
||||||
|
|
||||||
// skip the rest for we can't handle this kind of physically-based lighting information.
|
// skip the rest for we can't handle this kind of physically-based lighting information.
|
||||||
|
@ -703,14 +705,14 @@ void COBImporter::ReadPolH_Ascii(Scene &out, LineSplitter &splitter, const Chunk
|
||||||
|
|
||||||
for (unsigned int cur = 0; cur < cnt && ++splitter; ++cur) {
|
for (unsigned int cur = 0; cur < cnt && ++splitter; ++cur) {
|
||||||
const char *s = splitter->c_str();
|
const char *s = splitter->c_str();
|
||||||
|
const char *end = splitter.getEnd();
|
||||||
aiVector3D &v = msh.vertex_positions[cur];
|
aiVector3D &v = msh.vertex_positions[cur];
|
||||||
|
|
||||||
SkipSpaces(&s);
|
SkipSpaces(&s, end);
|
||||||
v.x = fast_atof(&s);
|
v.x = fast_atof(&s);
|
||||||
SkipSpaces(&s);
|
SkipSpaces(&s, end);
|
||||||
v.y = fast_atof(&s);
|
v.y = fast_atof(&s);
|
||||||
SkipSpaces(&s);
|
SkipSpaces(&s, end);
|
||||||
v.z = fast_atof(&s);
|
v.z = fast_atof(&s);
|
||||||
}
|
}
|
||||||
} else if (splitter.match_start("Texture Vertices")) {
|
} else if (splitter.match_start("Texture Vertices")) {
|
||||||
|
@ -719,12 +721,13 @@ void COBImporter::ReadPolH_Ascii(Scene &out, LineSplitter &splitter, const Chunk
|
||||||
|
|
||||||
for (unsigned int cur = 0; cur < cnt && ++splitter; ++cur) {
|
for (unsigned int cur = 0; cur < cnt && ++splitter; ++cur) {
|
||||||
const char *s = splitter->c_str();
|
const char *s = splitter->c_str();
|
||||||
|
const char *end = splitter.getEnd();
|
||||||
|
|
||||||
aiVector2D &v = msh.texture_coords[cur];
|
aiVector2D &v = msh.texture_coords[cur];
|
||||||
|
|
||||||
SkipSpaces(&s);
|
SkipSpaces(&s, end);
|
||||||
v.x = fast_atof(&s);
|
v.x = fast_atof(&s);
|
||||||
SkipSpaces(&s);
|
SkipSpaces(&s, end);
|
||||||
v.y = fast_atof(&s);
|
v.y = fast_atof(&s);
|
||||||
}
|
}
|
||||||
} else if (splitter.match_start("Faces")) {
|
} else if (splitter.match_start("Faces")) {
|
||||||
|
@ -749,8 +752,9 @@ void COBImporter::ReadPolH_Ascii(Scene &out, LineSplitter &splitter, const Chunk
|
||||||
face.material = strtoul10(splitter[6]);
|
face.material = strtoul10(splitter[6]);
|
||||||
|
|
||||||
const char *s = (++splitter)->c_str();
|
const char *s = (++splitter)->c_str();
|
||||||
|
const char *end = splitter.getEnd();
|
||||||
for (size_t i = 0; i < face.indices.size(); ++i) {
|
for (size_t i = 0; i < face.indices.size(); ++i) {
|
||||||
if (!SkipSpaces(&s)) {
|
if (!SkipSpaces(&s, end)) {
|
||||||
ThrowException("Expected EOL token in Face entry");
|
ThrowException("Expected EOL token in Face entry");
|
||||||
}
|
}
|
||||||
if ('<' != *s++) {
|
if ('<' != *s++) {
|
||||||
|
|
|
@ -120,7 +120,7 @@ private:
|
||||||
void ReadChunkInfo_Ascii(COB::ChunkInfo &out, const LineSplitter &splitter);
|
void ReadChunkInfo_Ascii(COB::ChunkInfo &out, const LineSplitter &splitter);
|
||||||
void ReadBasicNodeInfo_Ascii(COB::Node &msh, LineSplitter &splitter, const COB::ChunkInfo &nfo);
|
void ReadBasicNodeInfo_Ascii(COB::Node &msh, LineSplitter &splitter, const COB::ChunkInfo &nfo);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void ReadFloat3Tuple_Ascii(T &fill, const char **in);
|
void ReadFloat3Tuple_Ascii(T &fill, const char **in, const char *end);
|
||||||
|
|
||||||
void ReadPolH_Ascii(COB::Scene &out, LineSplitter &splitter, const COB::ChunkInfo &nfo);
|
void ReadPolH_Ascii(COB::Scene &out, LineSplitter &splitter, const COB::ChunkInfo &nfo);
|
||||||
void ReadBitM_Ascii(COB::Scene &out, LineSplitter &splitter, const COB::ChunkInfo &nfo);
|
void ReadBitM_Ascii(COB::Scene &out, LineSplitter &splitter, const COB::ChunkInfo &nfo);
|
||||||
|
|
|
@ -82,23 +82,20 @@ CSMImporter::CSMImporter() : noSkeletonMesh(){
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Returns whether the class can handle the format of the given file.
|
// Returns whether the class can handle the format of the given file.
|
||||||
bool CSMImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const
|
bool CSMImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const {
|
||||||
{
|
|
||||||
static const char* tokens[] = {"$Filename"};
|
static const char* tokens[] = {"$Filename"};
|
||||||
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,AI_COUNT_OF(tokens));
|
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,AI_COUNT_OF(tokens));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Build a string of all file extensions supported
|
// Build a string of all file extensions supported
|
||||||
const aiImporterDesc* CSMImporter::GetInfo () const
|
const aiImporterDesc* CSMImporter::GetInfo () const {
|
||||||
{
|
|
||||||
return &desc;
|
return &desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Setup configuration properties for the loader
|
// Setup configuration properties for the loader
|
||||||
void CSMImporter::SetupProperties(const Importer* pImp)
|
void CSMImporter::SetupProperties(const Importer* pImp) {
|
||||||
{
|
|
||||||
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
|
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,29 +115,29 @@ void CSMImporter::InternReadFile( const std::string& pFile,
|
||||||
std::vector<char> mBuffer2;
|
std::vector<char> mBuffer2;
|
||||||
TextFileToBuffer(file.get(),mBuffer2);
|
TextFileToBuffer(file.get(),mBuffer2);
|
||||||
const char* buffer = &mBuffer2[0];
|
const char* buffer = &mBuffer2[0];
|
||||||
|
const char *end = &mBuffer2[mBuffer2.size() - 1] + 1;
|
||||||
std::unique_ptr<aiAnimation> anim(new aiAnimation());
|
std::unique_ptr<aiAnimation> anim(new aiAnimation());
|
||||||
int first = 0, last = 0x00ffffff;
|
int first = 0, last = 0x00ffffff;
|
||||||
|
|
||||||
// now process the file and look out for '$' sections
|
// now process the file and look out for '$' sections
|
||||||
while (true) {
|
while (true) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&buffer, end);
|
||||||
if ('\0' == *buffer)
|
if ('\0' == *buffer)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if ('$' == *buffer) {
|
if ('$' == *buffer) {
|
||||||
++buffer;
|
++buffer;
|
||||||
if (TokenMatchI(buffer,"firstframe",10)) {
|
if (TokenMatchI(buffer,"firstframe",10)) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&buffer, end);
|
||||||
first = strtol10(buffer,&buffer);
|
first = strtol10(buffer,&buffer);
|
||||||
}
|
}
|
||||||
else if (TokenMatchI(buffer,"lastframe",9)) {
|
else if (TokenMatchI(buffer,"lastframe",9)) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&buffer, end);
|
||||||
last = strtol10(buffer,&buffer);
|
last = strtol10(buffer,&buffer);
|
||||||
}
|
}
|
||||||
else if (TokenMatchI(buffer,"rate",4)) {
|
else if (TokenMatchI(buffer,"rate",4)) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&buffer, end);
|
||||||
float d;
|
float d = { 0.0f };
|
||||||
buffer = fast_atoreal_move<float>(buffer,d);
|
buffer = fast_atoreal_move<float>(buffer,d);
|
||||||
anim->mTicksPerSecond = d;
|
anim->mTicksPerSecond = d;
|
||||||
}
|
}
|
||||||
|
@ -148,8 +145,8 @@ void CSMImporter::InternReadFile( const std::string& pFile,
|
||||||
std::vector< aiNodeAnim* > anims_temp;
|
std::vector< aiNodeAnim* > anims_temp;
|
||||||
anims_temp.reserve(30);
|
anims_temp.reserve(30);
|
||||||
while (true) {
|
while (true) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&buffer, end);
|
||||||
if (IsLineEnd(*buffer) && SkipSpacesAndLineEnd(&buffer) && *buffer == '$')
|
if (IsLineEnd(*buffer) && SkipSpacesAndLineEnd(&buffer, end) && *buffer == '$')
|
||||||
break; // next section
|
break; // next section
|
||||||
|
|
||||||
// Construct a new node animation channel and setup its name
|
// Construct a new node animation channel and setup its name
|
||||||
|
@ -157,41 +154,43 @@ void CSMImporter::InternReadFile( const std::string& pFile,
|
||||||
aiNodeAnim* nda = anims_temp.back();
|
aiNodeAnim* nda = anims_temp.back();
|
||||||
|
|
||||||
char* ot = nda->mNodeName.data;
|
char* ot = nda->mNodeName.data;
|
||||||
while (!IsSpaceOrNewLine(*buffer))
|
while (!IsSpaceOrNewLine(*buffer)) {
|
||||||
*ot++ = *buffer++;
|
*ot++ = *buffer++;
|
||||||
|
}
|
||||||
|
|
||||||
*ot = '\0';
|
*ot = '\0';
|
||||||
nda->mNodeName.length = static_cast<ai_uint32>(ot-nda->mNodeName.data);
|
nda->mNodeName.length = static_cast<ai_uint32>(ot-nda->mNodeName.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
anim->mNumChannels = static_cast<unsigned int>(anims_temp.size());
|
anim->mNumChannels = static_cast<unsigned int>(anims_temp.size());
|
||||||
if (!anim->mNumChannels)
|
if (!anim->mNumChannels) {
|
||||||
throw DeadlyImportError("CSM: Empty $order section");
|
throw DeadlyImportError("CSM: Empty $order section");
|
||||||
|
}
|
||||||
|
|
||||||
// copy over to the output animation
|
// copy over to the output animation
|
||||||
anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
|
anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
|
||||||
::memcpy(anim->mChannels,&anims_temp[0],sizeof(aiNodeAnim*)*anim->mNumChannels);
|
::memcpy(anim->mChannels,&anims_temp[0],sizeof(aiNodeAnim*)*anim->mNumChannels);
|
||||||
}
|
} else if (TokenMatchI(buffer,"points",6)) {
|
||||||
else if (TokenMatchI(buffer,"points",6)) {
|
if (!anim->mNumChannels) {
|
||||||
if (!anim->mNumChannels)
|
|
||||||
throw DeadlyImportError("CSM: \'$order\' section is required to appear prior to \'$points\'");
|
throw DeadlyImportError("CSM: \'$order\' section is required to appear prior to \'$points\'");
|
||||||
|
}
|
||||||
|
|
||||||
// If we know how many frames we'll read, we can preallocate some storage
|
// If we know how many frames we'll read, we can preallocate some storage
|
||||||
unsigned int alloc = 100;
|
unsigned int alloc = 100;
|
||||||
if (last != 0x00ffffff)
|
if (last != 0x00ffffff) {
|
||||||
{
|
|
||||||
alloc = last-first;
|
alloc = last-first;
|
||||||
alloc += alloc>>2u; // + 25%
|
alloc += alloc>>2u; // + 25%
|
||||||
for (unsigned int i = 0; i < anim->mNumChannels;++i)
|
for (unsigned int i = 0; i < anim->mNumChannels; ++i) {
|
||||||
anim->mChannels[i]->mPositionKeys = new aiVectorKey[alloc];
|
anim->mChannels[i]->mPositionKeys = new aiVectorKey[alloc];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int filled = 0;
|
unsigned int filled = 0;
|
||||||
|
|
||||||
// Now read all point data.
|
// Now read all point data.
|
||||||
while (true) {
|
while (true) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&buffer, end);
|
||||||
if (IsLineEnd(*buffer) && (!SkipSpacesAndLineEnd(&buffer) || *buffer == '$')) {
|
if (IsLineEnd(*buffer) && (!SkipSpacesAndLineEnd(&buffer, end) || *buffer == '$')) {
|
||||||
break; // next section
|
break; // next section
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,8 +201,8 @@ void CSMImporter::InternReadFile( const std::string& pFile,
|
||||||
for (unsigned int i = 0; i < anim->mNumChannels;++i) {
|
for (unsigned int i = 0; i < anim->mNumChannels;++i) {
|
||||||
|
|
||||||
aiNodeAnim* s = anim->mChannels[i];
|
aiNodeAnim* s = anim->mChannels[i];
|
||||||
if (s->mNumPositionKeys == alloc) { /* need to reallocate? */
|
if (s->mNumPositionKeys == alloc) {
|
||||||
|
// need to reallocate?
|
||||||
aiVectorKey* old = s->mPositionKeys;
|
aiVectorKey* old = s->mPositionKeys;
|
||||||
s->mPositionKeys = new aiVectorKey[s->mNumPositionKeys = alloc*2];
|
s->mPositionKeys = new aiVectorKey[s->mNumPositionKeys = alloc*2];
|
||||||
::memcpy(s->mPositionKeys,old,sizeof(aiVectorKey)*alloc);
|
::memcpy(s->mPositionKeys,old,sizeof(aiVectorKey)*alloc);
|
||||||
|
@ -211,24 +210,26 @@ void CSMImporter::InternReadFile( const std::string& pFile,
|
||||||
}
|
}
|
||||||
|
|
||||||
// read x,y,z
|
// read x,y,z
|
||||||
if(!SkipSpacesAndLineEnd(&buffer))
|
if (!SkipSpacesAndLineEnd(&buffer, end)) {
|
||||||
throw DeadlyImportError("CSM: Unexpected EOF occurred reading sample x coord");
|
throw DeadlyImportError("CSM: Unexpected EOF occurred reading sample x coord");
|
||||||
|
}
|
||||||
|
|
||||||
if (TokenMatchI(buffer, "DROPOUT", 7)) {
|
if (TokenMatchI(buffer, "DROPOUT", 7)) {
|
||||||
// seems this is invalid marker data; at least the doc says it's possible
|
// seems this is invalid marker data; at least the doc says it's possible
|
||||||
ASSIMP_LOG_WARN("CSM: Encountered invalid marker data (DROPOUT)");
|
ASSIMP_LOG_WARN("CSM: Encountered invalid marker data (DROPOUT)");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
aiVectorKey* sub = s->mPositionKeys + s->mNumPositionKeys;
|
aiVectorKey* sub = s->mPositionKeys + s->mNumPositionKeys;
|
||||||
sub->mTime = (double)frame;
|
sub->mTime = (double)frame;
|
||||||
buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.x);
|
buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.x);
|
||||||
|
|
||||||
if(!SkipSpacesAndLineEnd(&buffer))
|
if (!SkipSpacesAndLineEnd(&buffer, end)) {
|
||||||
throw DeadlyImportError("CSM: Unexpected EOF occurred reading sample y coord");
|
throw DeadlyImportError("CSM: Unexpected EOF occurred reading sample y coord");
|
||||||
|
}
|
||||||
buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.y);
|
buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.y);
|
||||||
|
|
||||||
if(!SkipSpacesAndLineEnd(&buffer))
|
if (!SkipSpacesAndLineEnd(&buffer, end)) {
|
||||||
throw DeadlyImportError("CSM: Unexpected EOF occurred reading sample z coord");
|
throw DeadlyImportError("CSM: Unexpected EOF occurred reading sample z coord");
|
||||||
|
}
|
||||||
buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.z);
|
buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.z);
|
||||||
|
|
||||||
++s->mNumPositionKeys;
|
++s->mNumPositionKeys;
|
||||||
|
@ -236,22 +237,22 @@ void CSMImporter::InternReadFile( const std::string& pFile,
|
||||||
}
|
}
|
||||||
|
|
||||||
// update allocation granularity
|
// update allocation granularity
|
||||||
if (filled == alloc)
|
if (filled == alloc) {
|
||||||
alloc *= 2;
|
alloc *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
++filled;
|
++filled;
|
||||||
}
|
}
|
||||||
// all channels must be complete in order to continue safely.
|
// all channels must be complete in order to continue safely.
|
||||||
for (unsigned int i = 0; i < anim->mNumChannels;++i) {
|
for (unsigned int i = 0; i < anim->mNumChannels;++i) {
|
||||||
|
if (!anim->mChannels[i]->mNumPositionKeys) {
|
||||||
if (!anim->mChannels[i]->mNumPositionKeys)
|
|
||||||
throw DeadlyImportError("CSM: Invalid marker track");
|
throw DeadlyImportError("CSM: Invalid marker track");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
} else {
|
||||||
// advance to the next line
|
// advance to the next line
|
||||||
SkipLine(&buffer);
|
SkipLine(&buffer, end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -654,12 +654,13 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &controlle
|
||||||
std::string v;
|
std::string v;
|
||||||
XmlParser::getValueAsString(currentNode, v);
|
XmlParser::getValueAsString(currentNode, v);
|
||||||
const char *content = v.c_str();
|
const char *content = v.c_str();
|
||||||
|
const char *end = content + v.size();
|
||||||
for (unsigned int a = 0; a < 16; a++) {
|
for (unsigned int a = 0; a < 16; a++) {
|
||||||
SkipSpacesAndLineEnd(&content);
|
SkipSpacesAndLineEnd(&content, end);
|
||||||
// read a number
|
// read a number
|
||||||
content = fast_atoreal_move<ai_real>(content, controller.mBindShapeMatrix[a]);
|
content = fast_atoreal_move<ai_real>(content, controller.mBindShapeMatrix[a]);
|
||||||
// skip whitespace after it
|
// skip whitespace after it
|
||||||
SkipSpacesAndLineEnd(&content);
|
SkipSpacesAndLineEnd(&content, end);
|
||||||
}
|
}
|
||||||
} else if (currentName == "source") {
|
} else if (currentName == "source") {
|
||||||
ReadSource(currentNode);
|
ReadSource(currentNode);
|
||||||
|
@ -740,7 +741,9 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
|
||||||
throw DeadlyImportError("Unknown semantic \"", attrSemantic, "\" in <vertex_weights> data <input> element");
|
throw DeadlyImportError("Unknown semantic \"", attrSemantic, "\" in <vertex_weights> data <input> element");
|
||||||
}
|
}
|
||||||
} else if (currentName == "vcount" && vertexCount > 0) {
|
} else if (currentName == "vcount" && vertexCount > 0) {
|
||||||
const char *text = currentNode.text().as_string();
|
const std::string stdText = currentNode.text().as_string();
|
||||||
|
const char *text = stdText.c_str();
|
||||||
|
const char *end = text + stdText.size();
|
||||||
size_t numWeights = 0;
|
size_t numWeights = 0;
|
||||||
for (std::vector<size_t>::iterator it = pController.mWeightCounts.begin(); it != pController.mWeightCounts.end(); ++it) {
|
for (std::vector<size_t>::iterator it = pController.mWeightCounts.begin(); it != pController.mWeightCounts.end(); ++it) {
|
||||||
if (*text == 0) {
|
if (*text == 0) {
|
||||||
|
@ -749,7 +752,7 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
|
||||||
|
|
||||||
*it = strtoul10(text, &text);
|
*it = strtoul10(text, &text);
|
||||||
numWeights += *it;
|
numWeights += *it;
|
||||||
SkipSpacesAndLineEnd(&text);
|
SkipSpacesAndLineEnd(&text, end);
|
||||||
}
|
}
|
||||||
// reserve weight count
|
// reserve weight count
|
||||||
pController.mWeights.resize(numWeights);
|
pController.mWeights.resize(numWeights);
|
||||||
|
@ -758,18 +761,19 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
|
||||||
std::string stdText;
|
std::string stdText;
|
||||||
XmlParser::getValueAsString(currentNode, stdText);
|
XmlParser::getValueAsString(currentNode, stdText);
|
||||||
const char *text = stdText.c_str();
|
const char *text = stdText.c_str();
|
||||||
|
const char *end = text + stdText.size();
|
||||||
for (std::vector<std::pair<size_t, size_t>>::iterator it = pController.mWeights.begin(); it != pController.mWeights.end(); ++it) {
|
for (std::vector<std::pair<size_t, size_t>>::iterator it = pController.mWeights.begin(); it != pController.mWeights.end(); ++it) {
|
||||||
if (text == nullptr) {
|
if (text == nullptr) {
|
||||||
throw DeadlyImportError("Out of data while reading <vertex_weights>");
|
throw DeadlyImportError("Out of data while reading <vertex_weights>");
|
||||||
}
|
}
|
||||||
SkipSpacesAndLineEnd(&text);
|
SkipSpacesAndLineEnd(&text, end);
|
||||||
it->first = strtoul10(text, &text);
|
it->first = strtoul10(text, &text);
|
||||||
SkipSpacesAndLineEnd(&text);
|
SkipSpacesAndLineEnd(&text, end);
|
||||||
if (*text == 0) {
|
if (*text == 0) {
|
||||||
throw DeadlyImportError("Out of data while reading <vertex_weights>");
|
throw DeadlyImportError("Out of data while reading <vertex_weights>");
|
||||||
}
|
}
|
||||||
it->second = strtoul10(text, &text);
|
it->second = strtoul10(text, &text);
|
||||||
SkipSpacesAndLineEnd(&text);
|
SkipSpacesAndLineEnd(&text, end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -952,15 +956,16 @@ void ColladaParser::ReadLight(XmlNode &node, Collada::Light &pLight) {
|
||||||
std::string v;
|
std::string v;
|
||||||
XmlParser::getValueAsString(currentNode, v);
|
XmlParser::getValueAsString(currentNode, v);
|
||||||
const char *content = v.c_str();
|
const char *content = v.c_str();
|
||||||
|
const char *end = content + v.size();
|
||||||
|
|
||||||
content = fast_atoreal_move<ai_real>(content, (ai_real &)pLight.mColor.r);
|
content = fast_atoreal_move<ai_real>(content, (ai_real &)pLight.mColor.r);
|
||||||
SkipSpacesAndLineEnd(&content);
|
SkipSpacesAndLineEnd(&content, end);
|
||||||
|
|
||||||
content = fast_atoreal_move<ai_real>(content, (ai_real &)pLight.mColor.g);
|
content = fast_atoreal_move<ai_real>(content, (ai_real &)pLight.mColor.g);
|
||||||
SkipSpacesAndLineEnd(&content);
|
SkipSpacesAndLineEnd(&content, end);
|
||||||
|
|
||||||
content = fast_atoreal_move<ai_real>(content, (ai_real &)pLight.mColor.b);
|
content = fast_atoreal_move<ai_real>(content, (ai_real &)pLight.mColor.b);
|
||||||
SkipSpacesAndLineEnd(&content);
|
SkipSpacesAndLineEnd(&content, end);
|
||||||
} else if (currentName == "constant_attenuation") {
|
} else if (currentName == "constant_attenuation") {
|
||||||
XmlParser::getValueAsFloat(currentNode, pLight.mAttConstant);
|
XmlParser::getValueAsFloat(currentNode, pLight.mAttConstant);
|
||||||
} else if (currentName == "linear_attenuation") {
|
} else if (currentName == "linear_attenuation") {
|
||||||
|
@ -1220,18 +1225,19 @@ void ColladaParser::ReadEffectColor(XmlNode &node, aiColor4D &pColor, Sampler &p
|
||||||
std::string v;
|
std::string v;
|
||||||
XmlParser::getValueAsString(currentNode, v);
|
XmlParser::getValueAsString(currentNode, v);
|
||||||
const char *content = v.c_str();
|
const char *content = v.c_str();
|
||||||
|
const char *end = v.c_str() + v.size() + 1;
|
||||||
|
|
||||||
content = fast_atoreal_move<ai_real>(content, (ai_real &)pColor.r);
|
content = fast_atoreal_move<ai_real>(content, (ai_real &)pColor.r);
|
||||||
SkipSpacesAndLineEnd(&content);
|
SkipSpacesAndLineEnd(&content, end);
|
||||||
|
|
||||||
content = fast_atoreal_move<ai_real>(content, (ai_real &)pColor.g);
|
content = fast_atoreal_move<ai_real>(content, (ai_real &)pColor.g);
|
||||||
SkipSpacesAndLineEnd(&content);
|
SkipSpacesAndLineEnd(&content, end);
|
||||||
|
|
||||||
content = fast_atoreal_move<ai_real>(content, (ai_real &)pColor.b);
|
content = fast_atoreal_move<ai_real>(content, (ai_real &)pColor.b);
|
||||||
SkipSpacesAndLineEnd(&content);
|
SkipSpacesAndLineEnd(&content, end);
|
||||||
|
|
||||||
content = fast_atoreal_move<ai_real>(content, (ai_real &)pColor.a);
|
content = fast_atoreal_move<ai_real>(content, (ai_real &)pColor.a);
|
||||||
SkipSpacesAndLineEnd(&content);
|
SkipSpacesAndLineEnd(&content, end);
|
||||||
} else if (currentName == "texture") {
|
} else if (currentName == "texture") {
|
||||||
// get name of source texture/sampler
|
// get name of source texture/sampler
|
||||||
XmlParser::getStdStrAttribute(currentNode, "texture", pSampler.mName);
|
XmlParser::getStdStrAttribute(currentNode, "texture", pSampler.mName);
|
||||||
|
@ -1345,6 +1351,7 @@ void ColladaParser::ReadGeometry(XmlNode &node, Collada::Mesh &pMesh) {
|
||||||
if (node.empty()) {
|
if (node.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (XmlNode ¤tNode : node.children()) {
|
for (XmlNode ¤tNode : node.children()) {
|
||||||
const std::string ¤tName = currentNode.name();
|
const std::string ¤tName = currentNode.name();
|
||||||
if (currentName == "mesh") {
|
if (currentName == "mesh") {
|
||||||
|
@ -1415,6 +1422,7 @@ void ColladaParser::ReadDataArray(XmlNode &node) {
|
||||||
XmlParser::getValueAsString(node, v);
|
XmlParser::getValueAsString(node, v);
|
||||||
v = ai_trim(v);
|
v = ai_trim(v);
|
||||||
const char *content = v.c_str();
|
const char *content = v.c_str();
|
||||||
|
const char *end = content + v.size();
|
||||||
|
|
||||||
// read values and store inside an array in the data library
|
// read values and store inside an array in the data library
|
||||||
mDataLibrary[id] = Data();
|
mDataLibrary[id] = Data();
|
||||||
|
@ -1433,11 +1441,13 @@ void ColladaParser::ReadDataArray(XmlNode &node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
s.clear();
|
s.clear();
|
||||||
while (!IsSpaceOrNewLine(*content))
|
while (!IsSpaceOrNewLine(*content)) {
|
||||||
s += *content++;
|
s += *content;
|
||||||
|
content++;
|
||||||
|
}
|
||||||
data.mStrings.push_back(s);
|
data.mStrings.push_back(s);
|
||||||
|
|
||||||
SkipSpacesAndLineEnd(&content);
|
SkipSpacesAndLineEnd(&content, end);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
data.mValues.reserve(count);
|
data.mValues.reserve(count);
|
||||||
|
@ -1452,7 +1462,7 @@ void ColladaParser::ReadDataArray(XmlNode &node) {
|
||||||
content = fast_atoreal_move<ai_real>(content, value);
|
content = fast_atoreal_move<ai_real>(content, value);
|
||||||
data.mValues.push_back(value);
|
data.mValues.push_back(value);
|
||||||
// skip whitespace after it
|
// skip whitespace after it
|
||||||
SkipSpacesAndLineEnd(&content);
|
SkipSpacesAndLineEnd(&content, end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1617,8 +1627,10 @@ void ColladaParser::ReadIndexData(XmlNode &node, Mesh &pMesh) {
|
||||||
std::string v;
|
std::string v;
|
||||||
XmlParser::getValueAsString(currentNode, v);
|
XmlParser::getValueAsString(currentNode, v);
|
||||||
const char *content = v.c_str();
|
const char *content = v.c_str();
|
||||||
|
const char *end = content + v.size();
|
||||||
|
|
||||||
vcount.reserve(numPrimitives);
|
vcount.reserve(numPrimitives);
|
||||||
SkipSpacesAndLineEnd(&content);
|
SkipSpacesAndLineEnd(&content, end);
|
||||||
for (unsigned int a = 0; a < numPrimitives; a++) {
|
for (unsigned int a = 0; a < numPrimitives; a++) {
|
||||||
if (*content == 0) {
|
if (*content == 0) {
|
||||||
throw DeadlyImportError("Expected more values while reading <vcount> contents.");
|
throw DeadlyImportError("Expected more values while reading <vcount> contents.");
|
||||||
|
@ -1626,7 +1638,7 @@ void ColladaParser::ReadIndexData(XmlNode &node, Mesh &pMesh) {
|
||||||
// read a number
|
// read a number
|
||||||
vcount.push_back((size_t)strtoul10(content, &content));
|
vcount.push_back((size_t)strtoul10(content, &content));
|
||||||
// skip whitespace after it
|
// skip whitespace after it
|
||||||
SkipSpacesAndLineEnd(&content);
|
SkipSpacesAndLineEnd(&content, end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1735,14 +1747,16 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector<Inp
|
||||||
std::string v;
|
std::string v;
|
||||||
XmlParser::getValueAsString(node, v);
|
XmlParser::getValueAsString(node, v);
|
||||||
const char *content = v.c_str();
|
const char *content = v.c_str();
|
||||||
SkipSpacesAndLineEnd(&content);
|
const char *end = content + v.size();
|
||||||
|
|
||||||
|
SkipSpacesAndLineEnd(&content, end);
|
||||||
while (*content != 0) {
|
while (*content != 0) {
|
||||||
// read a value.
|
// read a value.
|
||||||
// Hack: (thom) Some exporters put negative indices sometimes. We just try to carry on anyways.
|
// Hack: (thom) Some exporters put negative indices sometimes. We just try to carry on anyways.
|
||||||
int value = std::max(0, strtol10(content, &content));
|
int value = std::max(0, strtol10(content, &content));
|
||||||
indices.push_back(size_t(value));
|
indices.push_back(size_t(value));
|
||||||
// skip whitespace after it
|
// skip whitespace after it
|
||||||
SkipSpacesAndLineEnd(&content);
|
SkipSpacesAndLineEnd(&content, end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1801,8 +1815,10 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector<Inp
|
||||||
|
|
||||||
// For continued primitives, the given count does not come all in one <p>, but only one primitive per <p>
|
// For continued primitives, the given count does not come all in one <p>, but only one primitive per <p>
|
||||||
size_t numPrimitives = pNumPrimitives;
|
size_t numPrimitives = pNumPrimitives;
|
||||||
if (pPrimType == Prim_TriFans || pPrimType == Prim_Polygon)
|
if (pPrimType == Prim_TriFans || pPrimType == Prim_Polygon) {
|
||||||
numPrimitives = 1;
|
numPrimitives = 1;
|
||||||
|
}
|
||||||
|
|
||||||
// For continued primitives, the given count is actually the number of <p>'s inside the parent tag
|
// For continued primitives, the given count is actually the number of <p>'s inside the parent tag
|
||||||
if (pPrimType == Prim_TriStrips) {
|
if (pPrimType == Prim_TriStrips) {
|
||||||
size_t numberOfVertices = indices.size() / numOffsets;
|
size_t numberOfVertices = indices.size() / numOffsets;
|
||||||
|
@ -2166,15 +2182,15 @@ void ColladaParser::ReadNodeTransformation(XmlNode &node, Node *pNode, Transform
|
||||||
}
|
}
|
||||||
|
|
||||||
// how many parameters to read per transformation type
|
// how many parameters to read per transformation type
|
||||||
static const unsigned int sNumParameters[] = { 9, 4, 3, 3, 7, 16 };
|
static constexpr unsigned int sNumParameters[] = { 9, 4, 3, 3, 7, 16 };
|
||||||
std::string value;
|
std::string value;
|
||||||
XmlParser::getValueAsString(node, value);
|
XmlParser::getValueAsString(node, value);
|
||||||
const char *content = value.c_str();
|
const char *content = value.c_str();
|
||||||
|
const char *end = value.c_str() + value.size();
|
||||||
// read as many parameters and store in the transformation
|
// read as many parameters and store in the transformation
|
||||||
for (unsigned int a = 0; a < sNumParameters[pType]; a++) {
|
for (unsigned int a = 0; a < sNumParameters[pType]; a++) {
|
||||||
// skip whitespace before the number
|
// skip whitespace before the number
|
||||||
SkipSpacesAndLineEnd(&content);
|
SkipSpacesAndLineEnd(&content, end);
|
||||||
// read a number
|
// read a number
|
||||||
content = fast_atoreal_move<ai_real>(content, tf.f[a]);
|
content = fast_atoreal_move<ai_real>(content, tf.f[a]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -250,7 +250,9 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
|
||||||
};
|
};
|
||||||
|
|
||||||
// We know what format buffer is, collect numbers
|
// We know what format buffer is, collect numbers
|
||||||
ParseBufferVertices(verticesNode.text().get(), vertexFormat,
|
std::string v = verticesNode.text().get();
|
||||||
|
const char *end = v.c_str() + v.size();
|
||||||
|
ParseBufferVertices(v.c_str(), end, vertexFormat,
|
||||||
curVertices, curNormals,
|
curVertices, curNormals,
|
||||||
curTangents, curBitangents,
|
curTangents, curBitangents,
|
||||||
curUVs, curUV2s, curColors, useColors);
|
curUVs, curUV2s, curColors, useColors);
|
||||||
|
@ -329,8 +331,9 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
|
||||||
|
|
||||||
// NOTE this might explode for UTF-16 and wchars
|
// NOTE this might explode for UTF-16 and wchars
|
||||||
const char *sz = indicesNode.text().get();
|
const char *sz = indicesNode.text().get();
|
||||||
|
const char *end = sz + std::strlen(sz) + 1;
|
||||||
// For each index loop over aiMesh faces
|
// For each index loop over aiMesh faces
|
||||||
while (SkipSpacesAndLineEnd(&sz)) {
|
while (SkipSpacesAndLineEnd(&sz, end)) {
|
||||||
if (curFace >= faceEnd) {
|
if (curFace >= faceEnd) {
|
||||||
ASSIMP_LOG_ERROR("IRRMESH: Too many indices");
|
ASSIMP_LOG_ERROR("IRRMESH: Too many indices");
|
||||||
break;
|
break;
|
||||||
|
@ -354,12 +357,18 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
|
||||||
|
|
||||||
// Copy over data to aiMesh
|
// Copy over data to aiMesh
|
||||||
*pcV++ = curVertices[idx];
|
*pcV++ = curVertices[idx];
|
||||||
if (pcN) *pcN++ = curNormals[idx];
|
if (pcN)
|
||||||
if (pcT) *pcT++ = curTangents[idx];
|
*pcN++ = curNormals[idx];
|
||||||
if (pcB) *pcB++ = curBitangents[idx];
|
if (pcT)
|
||||||
if (pcC0) *pcC0++ = curColors[idx];
|
*pcT++ = curTangents[idx];
|
||||||
if (pcT0) *pcT0++ = curUVs[idx];
|
if (pcB)
|
||||||
if (pcT1) *pcT1++ = curUV2s[idx];
|
*pcB++ = curBitangents[idx];
|
||||||
|
if (pcC0)
|
||||||
|
*pcC0++ = curColors[idx];
|
||||||
|
if (pcT0)
|
||||||
|
*pcT0++ = curUVs[idx];
|
||||||
|
if (pcT1)
|
||||||
|
*pcT1++ = curUV2s[idx];
|
||||||
|
|
||||||
// start new face
|
// start new face
|
||||||
if (++curIdx == 3) {
|
if (++curIdx == 3) {
|
||||||
|
@ -421,37 +430,37 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRRMeshImporter::ParseBufferVertices(const char *sz, VertexFormat vertexFormat,
|
void IRRMeshImporter::ParseBufferVertices(const char *sz, const char *end, VertexFormat vertexFormat,
|
||||||
std::vector<aiVector3D> &vertices, std::vector<aiVector3D> &normals,
|
std::vector<aiVector3D> &vertices, std::vector<aiVector3D> &normals,
|
||||||
std::vector<aiVector3D> &tangents, std::vector<aiVector3D> &bitangents,
|
std::vector<aiVector3D> &tangents, std::vector<aiVector3D> &bitangents,
|
||||||
std::vector<aiVector3D> &UVs, std::vector<aiVector3D> &UV2s,
|
std::vector<aiVector3D> &UVs, std::vector<aiVector3D> &UV2s,
|
||||||
std::vector<aiColor4D> &colors, bool &useColors) {
|
std::vector<aiColor4D> &colors, bool &useColors) {
|
||||||
// read vertices
|
// read vertices
|
||||||
do {
|
do {
|
||||||
SkipSpacesAndLineEnd(&sz);
|
SkipSpacesAndLineEnd(&sz, end);
|
||||||
aiVector3D temp;
|
aiVector3D temp;
|
||||||
aiColor4D c;
|
aiColor4D c;
|
||||||
|
|
||||||
// Read the vertex position
|
// Read the vertex position
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, end);
|
||||||
|
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, end);
|
||||||
|
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, end);
|
||||||
vertices.push_back(temp);
|
vertices.push_back(temp);
|
||||||
|
|
||||||
// Read the vertex normals
|
// Read the vertex normals
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, end);
|
||||||
|
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, end);
|
||||||
|
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, end);
|
||||||
normals.push_back(temp);
|
normals.push_back(temp);
|
||||||
|
|
||||||
// read the vertex colors
|
// read the vertex colors
|
||||||
|
@ -463,14 +472,14 @@ void IRRMeshImporter::ParseBufferVertices(const char *sz, VertexFormat vertexFor
|
||||||
useColors = true;
|
useColors = true;
|
||||||
|
|
||||||
colors.push_back(c);
|
colors.push_back(c);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, end);
|
||||||
|
|
||||||
// read the first UV coordinate set
|
// read the first UV coordinate set
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, end);
|
||||||
|
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, end);
|
||||||
temp.z = 0.f;
|
temp.z = 0.f;
|
||||||
temp.y = 1.f - temp.y; // DX to OGL
|
temp.y = 1.f - temp.y; // DX to OGL
|
||||||
UVs.push_back(temp);
|
UVs.push_back(temp);
|
||||||
|
@ -480,7 +489,7 @@ void IRRMeshImporter::ParseBufferVertices(const char *sz, VertexFormat vertexFor
|
||||||
// read the (optional) second UV coordinate set
|
// read the (optional) second UV coordinate set
|
||||||
if (vertexFormat == VertexFormat::t2coord) {
|
if (vertexFormat == VertexFormat::t2coord) {
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, end);
|
||||||
|
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
||||||
temp.y = 1.f - temp.y; // DX to OGL
|
temp.y = 1.f - temp.y; // DX to OGL
|
||||||
|
@ -490,33 +499,32 @@ void IRRMeshImporter::ParseBufferVertices(const char *sz, VertexFormat vertexFor
|
||||||
else if (vertexFormat == VertexFormat::tangent) {
|
else if (vertexFormat == VertexFormat::tangent) {
|
||||||
// tangents
|
// tangents
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, end);
|
||||||
|
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, end);
|
||||||
|
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, end);
|
||||||
temp.y *= -1.0f;
|
temp.y *= -1.0f;
|
||||||
tangents.push_back(temp);
|
tangents.push_back(temp);
|
||||||
|
|
||||||
// bitangents
|
// bitangents
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, end);
|
||||||
|
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, end);
|
||||||
|
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, end);
|
||||||
temp.y *= -1.0f;
|
temp.y *= -1.0f;
|
||||||
bitangents.push_back(temp);
|
bitangents.push_back(temp);
|
||||||
}
|
}
|
||||||
} while (SkipLine(&sz));
|
} while (SkipLine(&sz, end));
|
||||||
/* IMPORTANT: We assume that each vertex is specified in one
|
// IMPORTANT: We assume that each vertex is specified in one
|
||||||
line. So we can skip the rest of the line - unknown vertex
|
// line. So we can skip the rest of the line - unknown vertex
|
||||||
elements are ignored.
|
// elements are ignored.
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // !! ASSIMP_BUILD_NO_IRRMESH_IMPORTER
|
#endif // !! ASSIMP_BUILD_NO_IRRMESH_IMPORTER
|
||||||
|
|
|
@ -93,7 +93,7 @@ private:
|
||||||
tangent = 2, // "tangents" - standard + tangents and bitangents
|
tangent = 2, // "tangents" - standard + tangents and bitangents
|
||||||
};
|
};
|
||||||
|
|
||||||
void ParseBufferVertices(const char *sz, VertexFormat vertexFormat,
|
void ParseBufferVertices(const char *sz, const char *end, VertexFormat vertexFormat,
|
||||||
std::vector<aiVector3D> &vertices, std::vector<aiVector3D> &normals,
|
std::vector<aiVector3D> &vertices, std::vector<aiVector3D> &normals,
|
||||||
std::vector<aiVector3D> &tangents, std::vector<aiVector3D> &bitangents,
|
std::vector<aiVector3D> &tangents, std::vector<aiVector3D> &bitangents,
|
||||||
std::vector<aiVector3D> &UVs, std::vector<aiVector3D> &UV2s,
|
std::vector<aiVector3D> &UVs, std::vector<aiVector3D> &UV2s,
|
||||||
|
|
|
@ -135,21 +135,23 @@ void IrrlichtBase::ReadVectorProperty(VectorProperty &out, pugi::xml_node& vecto
|
||||||
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||||
// three floats, separated with commas
|
// three floats, separated with commas
|
||||||
const char *ptr = attrib.value();
|
const char *ptr = attrib.value();
|
||||||
|
size_t len = std::strlen(ptr);
|
||||||
|
const char *end = ptr + len;
|
||||||
|
|
||||||
SkipSpaces(&ptr);
|
SkipSpaces(&ptr, end);
|
||||||
ptr = fast_atoreal_move<float>(ptr, (float &)out.value.x);
|
ptr = fast_atoreal_move<float>(ptr, (float &)out.value.x);
|
||||||
SkipSpaces(&ptr);
|
SkipSpaces(&ptr, end);
|
||||||
if (',' != *ptr) {
|
if (',' != *ptr) {
|
||||||
ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
|
ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
|
||||||
} else {
|
} else {
|
||||||
SkipSpaces(ptr + 1, &ptr);
|
SkipSpaces(ptr + 1, &ptr, end);
|
||||||
}
|
}
|
||||||
ptr = fast_atoreal_move<float>(ptr, (float &)out.value.y);
|
ptr = fast_atoreal_move<float>(ptr, (float &)out.value.y);
|
||||||
SkipSpaces(&ptr);
|
SkipSpaces(&ptr, end);
|
||||||
if (',' != *ptr) {
|
if (',' != *ptr) {
|
||||||
ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
|
ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
|
||||||
} else {
|
} else {
|
||||||
SkipSpaces(ptr + 1, &ptr);
|
SkipSpaces(ptr + 1, &ptr, end);
|
||||||
}
|
}
|
||||||
ptr = fast_atoreal_move<float>(ptr, (float &)out.value.z);
|
ptr = fast_atoreal_move<float>(ptr, (float &)out.value.z);
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,14 +78,14 @@ static constexpr aiImporterDesc desc = {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Recursive parsing of LWS files
|
// Recursive parsing of LWS files
|
||||||
void LWS::Element::Parse(const char *&buffer) {
|
void LWS::Element::Parse(const char *&buffer, const char *end) {
|
||||||
for (; SkipSpacesAndLineEnd(&buffer); SkipLine(&buffer)) {
|
for (; SkipSpacesAndLineEnd(&buffer, end); SkipLine(&buffer, end)) {
|
||||||
|
|
||||||
// begin of a new element with children
|
// begin of a new element with children
|
||||||
bool sub = false;
|
bool sub = false;
|
||||||
if (*buffer == '{') {
|
if (*buffer == '{') {
|
||||||
++buffer;
|
++buffer;
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&buffer, end);
|
||||||
sub = true;
|
sub = true;
|
||||||
} else if (*buffer == '}')
|
} else if (*buffer == '}')
|
||||||
return;
|
return;
|
||||||
|
@ -98,16 +98,15 @@ void LWS::Element::Parse(const char *&buffer) {
|
||||||
while (!IsSpaceOrNewLine(*buffer))
|
while (!IsSpaceOrNewLine(*buffer))
|
||||||
++buffer;
|
++buffer;
|
||||||
children.back().tokens[0] = std::string(cur, (size_t)(buffer - cur));
|
children.back().tokens[0] = std::string(cur, (size_t)(buffer - cur));
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&buffer, end);
|
||||||
|
|
||||||
if (children.back().tokens[0] == "Plugin") {
|
if (children.back().tokens[0] == "Plugin") {
|
||||||
ASSIMP_LOG_VERBOSE_DEBUG("LWS: Skipping over plugin-specific data");
|
ASSIMP_LOG_VERBOSE_DEBUG("LWS: Skipping over plugin-specific data");
|
||||||
|
|
||||||
// strange stuff inside Plugin/Endplugin blocks. Needn't
|
// strange stuff inside Plugin/Endplugin blocks. Needn't
|
||||||
// follow LWS syntax, so we skip over it
|
// follow LWS syntax, so we skip over it
|
||||||
for (; SkipSpacesAndLineEnd(&buffer); SkipLine(&buffer)) {
|
for (; SkipSpacesAndLineEnd(&buffer, end); SkipLine(&buffer, end)) {
|
||||||
if (!::strncmp(buffer, "EndPlugin", 9)) {
|
if (!::strncmp(buffer, "EndPlugin", 9)) {
|
||||||
//SkipLine(&buffer);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,7 +121,7 @@ void LWS::Element::Parse(const char *&buffer) {
|
||||||
|
|
||||||
// parse more elements recursively
|
// parse more elements recursively
|
||||||
if (sub) {
|
if (sub) {
|
||||||
children.back().Parse(buffer);
|
children.back().Parse(buffer, end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,6 +154,7 @@ const aiImporterDesc *LWSImporter::GetInfo() const {
|
||||||
return &desc;
|
return &desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr int MagicHackNo = 150392;
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Setup configuration properties
|
// Setup configuration properties
|
||||||
void LWSImporter::SetupProperties(const Importer *pImp) {
|
void LWSImporter::SetupProperties(const Importer *pImp) {
|
||||||
|
@ -163,11 +163,11 @@ void LWSImporter::SetupProperties(const Importer *pImp) {
|
||||||
|
|
||||||
// AI_CONFIG_IMPORT_LWS_ANIM_START
|
// AI_CONFIG_IMPORT_LWS_ANIM_START
|
||||||
first = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWS_ANIM_START,
|
first = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWS_ANIM_START,
|
||||||
150392 /* magic hack */);
|
MagicHackNo /* magic hack */);
|
||||||
|
|
||||||
// AI_CONFIG_IMPORT_LWS_ANIM_END
|
// AI_CONFIG_IMPORT_LWS_ANIM_END
|
||||||
last = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWS_ANIM_END,
|
last = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWS_ANIM_END,
|
||||||
150392 /* magic hack */);
|
MagicHackNo /* magic hack */);
|
||||||
|
|
||||||
if (last < first) {
|
if (last < first) {
|
||||||
std::swap(last, first);
|
std::swap(last, first);
|
||||||
|
@ -191,15 +191,16 @@ void LWSImporter::ReadEnvelope(const LWS::Element &dad, LWO::Envelope &fill) {
|
||||||
|
|
||||||
for (++it; it != dad.children.end(); ++it) {
|
for (++it; it != dad.children.end(); ++it) {
|
||||||
const char *c = (*it).tokens[1].c_str();
|
const char *c = (*it).tokens[1].c_str();
|
||||||
|
const char *end = c + (*it).tokens[1].size();
|
||||||
|
|
||||||
if ((*it).tokens[0] == "Key") {
|
if ((*it).tokens[0] == "Key") {
|
||||||
fill.keys.emplace_back();
|
fill.keys.emplace_back();
|
||||||
LWO::Key &key = fill.keys.back();
|
LWO::Key &key = fill.keys.back();
|
||||||
|
|
||||||
float f;
|
float f;
|
||||||
SkipSpaces(&c);
|
SkipSpaces(&c, end);
|
||||||
c = fast_atoreal_move<float>(c, key.value);
|
c = fast_atoreal_move<float>(c, key.value);
|
||||||
SkipSpaces(&c);
|
SkipSpaces(&c, end);
|
||||||
c = fast_atoreal_move<float>(c, f);
|
c = fast_atoreal_move<float>(c, f);
|
||||||
|
|
||||||
key.time = f;
|
key.time = f;
|
||||||
|
@ -231,13 +232,13 @@ void LWSImporter::ReadEnvelope(const LWS::Element &dad, LWO::Envelope &fill) {
|
||||||
ASSIMP_LOG_ERROR("LWS: Unknown span type");
|
ASSIMP_LOG_ERROR("LWS: Unknown span type");
|
||||||
}
|
}
|
||||||
for (unsigned int i = 0; i < num; ++i) {
|
for (unsigned int i = 0; i < num; ++i) {
|
||||||
SkipSpaces(&c);
|
SkipSpaces(&c, end);
|
||||||
c = fast_atoreal_move<float>(c, key.params[i]);
|
c = fast_atoreal_move<float>(c, key.params[i]);
|
||||||
}
|
}
|
||||||
} else if ((*it).tokens[0] == "Behaviors") {
|
} else if ((*it).tokens[0] == "Behaviors") {
|
||||||
SkipSpaces(&c);
|
SkipSpaces(&c, end);
|
||||||
fill.pre = (LWO::PrePostBehaviour)strtoul10(c, &c);
|
fill.pre = (LWO::PrePostBehaviour)strtoul10(c, &c);
|
||||||
SkipSpaces(&c);
|
SkipSpaces(&c, end);
|
||||||
fill.post = (LWO::PrePostBehaviour)strtoul10(c, &c);
|
fill.post = (LWO::PrePostBehaviour)strtoul10(c, &c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,36 +246,39 @@ void LWSImporter::ReadEnvelope(const LWS::Element &dad, LWO::Envelope &fill) {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Read animation channels in the old LightWave animation format
|
// Read animation channels in the old LightWave animation format
|
||||||
void LWSImporter::ReadEnvelope_Old(
|
void LWSImporter::ReadEnvelope_Old(std::list<LWS::Element>::const_iterator &it,const std::list<LWS::Element>::const_iterator &endIt,
|
||||||
std::list<LWS::Element>::const_iterator &it,
|
LWS::NodeDesc &nodes, unsigned int) {
|
||||||
const std::list<LWS::Element>::const_iterator &end,
|
unsigned int num=0, sub_num=0;
|
||||||
LWS::NodeDesc &nodes,
|
if (++it == endIt) {
|
||||||
unsigned int /*version*/) {
|
ASSIMP_LOG_ERROR("LWS: Encountered unexpected end of file while parsing object motion");
|
||||||
unsigned int num, sub_num;
|
return;
|
||||||
if (++it == end) goto unexpected_end;
|
}
|
||||||
|
|
||||||
num = strtoul10((*it).tokens[0].c_str());
|
num = strtoul10((*it).tokens[0].c_str());
|
||||||
for (unsigned int i = 0; i < num; ++i) {
|
for (unsigned int i = 0; i < num; ++i) {
|
||||||
|
|
||||||
nodes.channels.emplace_back();
|
nodes.channels.emplace_back();
|
||||||
LWO::Envelope &envl = nodes.channels.back();
|
LWO::Envelope &envl = nodes.channels.back();
|
||||||
|
|
||||||
envl.index = i;
|
envl.index = i;
|
||||||
envl.type = (LWO::EnvelopeType)(i + 1);
|
envl.type = (LWO::EnvelopeType)(i + 1);
|
||||||
|
|
||||||
if (++it == end) {
|
if (++it == endIt) {
|
||||||
goto unexpected_end;
|
ASSIMP_LOG_ERROR("LWS: Encountered unexpected end of file while parsing object motion");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
sub_num = strtoul10((*it).tokens[0].c_str());
|
sub_num = strtoul10((*it).tokens[0].c_str());
|
||||||
|
|
||||||
for (unsigned int n = 0; n < sub_num; ++n) {
|
for (unsigned int n = 0; n < sub_num; ++n) {
|
||||||
|
if (++it == endIt) {
|
||||||
if (++it == end) goto unexpected_end;
|
ASSIMP_LOG_ERROR("LWS: Encountered unexpected end of file while parsing object motion");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// parse value and time, skip the rest for the moment.
|
// parse value and time, skip the rest for the moment.
|
||||||
LWO::Key key;
|
LWO::Key key;
|
||||||
const char *c = fast_atoreal_move<float>((*it).tokens[0].c_str(), key.value);
|
const char *c = fast_atoreal_move<float>((*it).tokens[0].c_str(), key.value);
|
||||||
SkipSpaces(&c);
|
const char *end = c + (*it).tokens[0].size();
|
||||||
|
SkipSpaces(&c, end);
|
||||||
float f;
|
float f;
|
||||||
fast_atoreal_move<float>((*it).tokens[0].c_str(), f);
|
fast_atoreal_move<float>((*it).tokens[0].c_str(), f);
|
||||||
key.time = f;
|
key.time = f;
|
||||||
|
@ -282,10 +286,6 @@ void LWSImporter::ReadEnvelope_Old(
|
||||||
envl.keys.push_back(key);
|
envl.keys.push_back(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
|
|
||||||
unexpected_end:
|
|
||||||
ASSIMP_LOG_ERROR("LWS: Encountered unexpected end of file while parsing object motion");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -296,7 +296,6 @@ void LWSImporter::SetupNodeName(aiNode *nd, LWS::NodeDesc &src) {
|
||||||
// the name depends on the type. We break LWS's strange naming convention
|
// the name depends on the type. We break LWS's strange naming convention
|
||||||
// and return human-readable, but still machine-parsable and unique, strings.
|
// and return human-readable, but still machine-parsable and unique, strings.
|
||||||
if (src.type == LWS::NodeDesc::OBJECT) {
|
if (src.type == LWS::NodeDesc::OBJECT) {
|
||||||
|
|
||||||
if (src.path.length()) {
|
if (src.path.length()) {
|
||||||
std::string::size_type s = src.path.find_last_of("\\/");
|
std::string::size_type s = src.path.find_last_of("\\/");
|
||||||
if (s == std::string::npos) {
|
if (s == std::string::npos) {
|
||||||
|
@ -501,7 +500,8 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
// Parse the file structure
|
// Parse the file structure
|
||||||
LWS::Element root;
|
LWS::Element root;
|
||||||
const char *dummy = &mBuffer[0];
|
const char *dummy = &mBuffer[0];
|
||||||
root.Parse(dummy);
|
const char *dummyEnd = dummy + mBuffer.size();
|
||||||
|
root.Parse(dummy, dummyEnd);
|
||||||
|
|
||||||
// Construct a Batch-importer to read more files recursively
|
// Construct a Batch-importer to read more files recursively
|
||||||
BatchLoader batch(pIOHandler);
|
BatchLoader batch(pIOHandler);
|
||||||
|
@ -540,6 +540,7 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
// Now read all elements in a very straightforward manner
|
// Now read all elements in a very straightforward manner
|
||||||
for (; it != root.children.end(); ++it) {
|
for (; it != root.children.end(); ++it) {
|
||||||
const char *c = (*it).tokens[1].c_str();
|
const char *c = (*it).tokens[1].c_str();
|
||||||
|
const char *end = c + (*it).tokens[1].size();
|
||||||
|
|
||||||
// 'FirstFrame': begin of animation slice
|
// 'FirstFrame': begin of animation slice
|
||||||
if ((*it).tokens[0] == "FirstFrame") {
|
if ((*it).tokens[0] == "FirstFrame") {
|
||||||
|
@ -567,14 +568,14 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
LWS::NodeDesc d;
|
LWS::NodeDesc d;
|
||||||
d.type = LWS::NodeDesc::OBJECT;
|
d.type = LWS::NodeDesc::OBJECT;
|
||||||
if (version >= 4) { // handle LWSC 4 explicit ID
|
if (version >= 4) { // handle LWSC 4 explicit ID
|
||||||
SkipSpaces(&c);
|
SkipSpaces(&c, end);
|
||||||
d.number = strtoul16(c, &c) & AI_LWS_MASK;
|
d.number = strtoul16(c, &c) & AI_LWS_MASK;
|
||||||
} else {
|
} else {
|
||||||
d.number = cur_object++;
|
d.number = cur_object++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// and add the file to the import list
|
// and add the file to the import list
|
||||||
SkipSpaces(&c);
|
SkipSpaces(&c, end);
|
||||||
std::string path = FindLWOFile(c);
|
std::string path = FindLWOFile(c);
|
||||||
d.path = path;
|
d.path = path;
|
||||||
d.id = batch.AddLoadRequest(path, 0, &props);
|
d.id = batch.AddLoadRequest(path, 0, &props);
|
||||||
|
@ -588,7 +589,7 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
|
|
||||||
if (version >= 4) { // handle LWSC 4 explicit ID
|
if (version >= 4) { // handle LWSC 4 explicit ID
|
||||||
d.number = strtoul16(c, &c) & AI_LWS_MASK;
|
d.number = strtoul16(c, &c) & AI_LWS_MASK;
|
||||||
SkipSpaces(&c);
|
SkipSpaces(&c, end);
|
||||||
} else {
|
} else {
|
||||||
d.number = cur_object++;
|
d.number = cur_object++;
|
||||||
}
|
}
|
||||||
|
@ -604,7 +605,7 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
d.type = LWS::NodeDesc::OBJECT;
|
d.type = LWS::NodeDesc::OBJECT;
|
||||||
if (version >= 4) { // handle LWSC 4 explicit ID
|
if (version >= 4) { // handle LWSC 4 explicit ID
|
||||||
d.number = strtoul16(c, &c) & AI_LWS_MASK;
|
d.number = strtoul16(c, &c) & AI_LWS_MASK;
|
||||||
SkipSpaces(&c);
|
SkipSpaces(&c, end);
|
||||||
} else {
|
} else {
|
||||||
d.number = cur_object++;
|
d.number = cur_object++;
|
||||||
}
|
}
|
||||||
|
@ -668,26 +669,25 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
// two ints per envelope
|
// two ints per envelope
|
||||||
LWO::Envelope &env = *envelopeIt;
|
LWO::Envelope &env = *envelopeIt;
|
||||||
env.pre = (LWO::PrePostBehaviour)strtoul10(c, &c);
|
env.pre = (LWO::PrePostBehaviour)strtoul10(c, &c);
|
||||||
SkipSpaces(&c);
|
SkipSpaces(&c, end);
|
||||||
env.post = (LWO::PrePostBehaviour)strtoul10(c, &c);
|
env.post = (LWO::PrePostBehaviour)strtoul10(c, &c);
|
||||||
SkipSpaces(&c);
|
SkipSpaces(&c, end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 'ParentItem': specifies the parent of the current element
|
// 'ParentItem': specifies the parent of the current element
|
||||||
else if ((*it).tokens[0] == "ParentItem") {
|
else if ((*it).tokens[0] == "ParentItem") {
|
||||||
if (nodes.empty())
|
if (nodes.empty()) {
|
||||||
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'ParentItem\'");
|
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'ParentItem\'");
|
||||||
|
} else {
|
||||||
else
|
|
||||||
nodes.back().parent = strtoul16(c, &c);
|
nodes.back().parent = strtoul16(c, &c);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// 'ParentObject': deprecated one for older formats
|
// 'ParentObject': deprecated one for older formats
|
||||||
else if (version < 3 && (*it).tokens[0] == "ParentObject") {
|
else if (version < 3 && (*it).tokens[0] == "ParentObject") {
|
||||||
if (nodes.empty())
|
if (nodes.empty()) {
|
||||||
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'ParentObject\'");
|
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'ParentObject\'");
|
||||||
|
} else {
|
||||||
else {
|
|
||||||
nodes.back().parent = strtoul10(c, &c) | (1u << 28u);
|
nodes.back().parent = strtoul10(c, &c) | (1u << 28u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -700,20 +700,21 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
|
|
||||||
if (version >= 4) { // handle LWSC 4 explicit ID
|
if (version >= 4) { // handle LWSC 4 explicit ID
|
||||||
d.number = strtoul16(c, &c) & AI_LWS_MASK;
|
d.number = strtoul16(c, &c) & AI_LWS_MASK;
|
||||||
} else
|
} else {
|
||||||
d.number = cur_camera++;
|
d.number = cur_camera++;
|
||||||
|
}
|
||||||
nodes.push_back(d);
|
nodes.push_back(d);
|
||||||
|
|
||||||
num_camera++;
|
num_camera++;
|
||||||
}
|
}
|
||||||
// 'CameraName': set name of currently active camera
|
// 'CameraName': set name of currently active camera
|
||||||
else if ((*it).tokens[0] == "CameraName") {
|
else if ((*it).tokens[0] == "CameraName") {
|
||||||
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::CAMERA)
|
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::CAMERA) {
|
||||||
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'CameraName\'");
|
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'CameraName\'");
|
||||||
|
} else {
|
||||||
else
|
|
||||||
nodes.back().name = c;
|
nodes.back().name = c;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// 'AddLight': add a light to the scenegraph
|
// 'AddLight': add a light to the scenegraph
|
||||||
else if ((*it).tokens[0] == "AddLight") {
|
else if ((*it).tokens[0] == "AddLight") {
|
||||||
|
|
||||||
|
@ -723,20 +724,21 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
|
|
||||||
if (version >= 4) { // handle LWSC 4 explicit ID
|
if (version >= 4) { // handle LWSC 4 explicit ID
|
||||||
d.number = strtoul16(c, &c) & AI_LWS_MASK;
|
d.number = strtoul16(c, &c) & AI_LWS_MASK;
|
||||||
} else
|
} else {
|
||||||
d.number = cur_light++;
|
d.number = cur_light++;
|
||||||
|
}
|
||||||
nodes.push_back(d);
|
nodes.push_back(d);
|
||||||
|
|
||||||
num_light++;
|
num_light++;
|
||||||
}
|
}
|
||||||
// 'LightName': set name of currently active light
|
// 'LightName': set name of currently active light
|
||||||
else if ((*it).tokens[0] == "LightName") {
|
else if ((*it).tokens[0] == "LightName") {
|
||||||
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
|
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
|
||||||
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightName\'");
|
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightName\'");
|
||||||
|
} else {
|
||||||
else
|
|
||||||
nodes.back().name = c;
|
nodes.back().name = c;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// 'LightIntensity': set intensity of currently active light
|
// 'LightIntensity': set intensity of currently active light
|
||||||
else if ((*it).tokens[0] == "LightIntensity" || (*it).tokens[0] == "LgtIntensity") {
|
else if ((*it).tokens[0] == "LightIntensity" || (*it).tokens[0] == "LgtIntensity") {
|
||||||
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
|
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
|
||||||
|
@ -753,62 +755,58 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
}
|
}
|
||||||
// 'LightType': set type of currently active light
|
// 'LightType': set type of currently active light
|
||||||
else if ((*it).tokens[0] == "LightType") {
|
else if ((*it).tokens[0] == "LightType") {
|
||||||
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
|
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
|
||||||
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightType\'");
|
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightType\'");
|
||||||
|
} else {
|
||||||
else
|
|
||||||
nodes.back().lightType = strtoul10(c);
|
nodes.back().lightType = strtoul10(c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 'LightFalloffType': set falloff type of currently active light
|
// 'LightFalloffType': set falloff type of currently active light
|
||||||
else if ((*it).tokens[0] == "LightFalloffType") {
|
else if ((*it).tokens[0] == "LightFalloffType") {
|
||||||
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
|
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
|
||||||
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightFalloffType\'");
|
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightFalloffType\'");
|
||||||
else
|
} else {
|
||||||
nodes.back().lightFalloffType = strtoul10(c);
|
nodes.back().lightFalloffType = strtoul10(c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 'LightConeAngle': set cone angle of currently active light
|
// 'LightConeAngle': set cone angle of currently active light
|
||||||
else if ((*it).tokens[0] == "LightConeAngle") {
|
else if ((*it).tokens[0] == "LightConeAngle") {
|
||||||
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
|
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
|
||||||
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightConeAngle\'");
|
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightConeAngle\'");
|
||||||
|
} else {
|
||||||
else
|
|
||||||
nodes.back().lightConeAngle = fast_atof(c);
|
nodes.back().lightConeAngle = fast_atof(c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 'LightEdgeAngle': set area where we're smoothing from min to max intensity
|
// 'LightEdgeAngle': set area where we're smoothing from min to max intensity
|
||||||
else if ((*it).tokens[0] == "LightEdgeAngle") {
|
else if ((*it).tokens[0] == "LightEdgeAngle") {
|
||||||
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
|
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
|
||||||
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightEdgeAngle\'");
|
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightEdgeAngle\'");
|
||||||
|
} else {
|
||||||
else
|
|
||||||
nodes.back().lightEdgeAngle = fast_atof(c);
|
nodes.back().lightEdgeAngle = fast_atof(c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 'LightColor': set color of currently active light
|
// 'LightColor': set color of currently active light
|
||||||
else if ((*it).tokens[0] == "LightColor") {
|
else if ((*it).tokens[0] == "LightColor") {
|
||||||
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
|
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
|
||||||
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightColor\'");
|
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightColor\'");
|
||||||
|
} else {
|
||||||
else {
|
|
||||||
c = fast_atoreal_move<float>(c, (float &)nodes.back().lightColor.r);
|
c = fast_atoreal_move<float>(c, (float &)nodes.back().lightColor.r);
|
||||||
SkipSpaces(&c);
|
SkipSpaces(&c, end);
|
||||||
c = fast_atoreal_move<float>(c, (float &)nodes.back().lightColor.g);
|
c = fast_atoreal_move<float>(c, (float &)nodes.back().lightColor.g);
|
||||||
SkipSpaces(&c);
|
SkipSpaces(&c, end);
|
||||||
c = fast_atoreal_move<float>(c, (float &)nodes.back().lightColor.b);
|
c = fast_atoreal_move<float>(c, (float &)nodes.back().lightColor.b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'PivotPosition': position of local transformation origin
|
// 'PivotPosition': position of local transformation origin
|
||||||
else if ((*it).tokens[0] == "PivotPosition" || (*it).tokens[0] == "PivotPoint") {
|
else if ((*it).tokens[0] == "PivotPosition" || (*it).tokens[0] == "PivotPoint") {
|
||||||
if (nodes.empty())
|
if (nodes.empty()) {
|
||||||
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'PivotPosition\'");
|
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'PivotPosition\'");
|
||||||
else {
|
} else {
|
||||||
c = fast_atoreal_move<float>(c, (float &)nodes.back().pivotPos.x);
|
c = fast_atoreal_move<float>(c, (float &)nodes.back().pivotPos.x);
|
||||||
SkipSpaces(&c);
|
SkipSpaces(&c, end);
|
||||||
c = fast_atoreal_move<float>(c, (float &)nodes.back().pivotPos.y);
|
c = fast_atoreal_move<float>(c, (float &)nodes.back().pivotPos.y);
|
||||||
SkipSpaces(&c);
|
SkipSpaces(&c, end);
|
||||||
c = fast_atoreal_move<float>(c, (float &)nodes.back().pivotPos.z);
|
c = fast_atoreal_move<float>(c, (float &)nodes.back().pivotPos.z);
|
||||||
// Mark pivotPos as set
|
// Mark pivotPos as set
|
||||||
nodes.back().isPivotSet = true;
|
nodes.back().isPivotSet = true;
|
||||||
|
@ -818,7 +816,6 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
|
|
||||||
// resolve parenting
|
// resolve parenting
|
||||||
for (std::list<LWS::NodeDesc>::iterator ndIt = nodes.begin(); ndIt != nodes.end(); ++ndIt) {
|
for (std::list<LWS::NodeDesc>::iterator ndIt = nodes.begin(); ndIt != nodes.end(); ++ndIt) {
|
||||||
|
|
||||||
// check whether there is another node which calls us a parent
|
// check whether there is another node which calls us a parent
|
||||||
for (std::list<LWS::NodeDesc>::iterator dit = nodes.begin(); dit != nodes.end(); ++dit) {
|
for (std::list<LWS::NodeDesc>::iterator dit = nodes.begin(); dit != nodes.end(); ++dit) {
|
||||||
if (dit != ndIt && *ndIt == (*dit).parent) {
|
if (dit != ndIt && *ndIt == (*dit).parent) {
|
||||||
|
@ -854,7 +851,7 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
aiNode *nd = master->mRootNode = new aiNode();
|
aiNode *nd = master->mRootNode = new aiNode();
|
||||||
|
|
||||||
// allocate storage for cameras&lights
|
// allocate storage for cameras&lights
|
||||||
if (num_camera) {
|
if (num_camera > 0u) {
|
||||||
master->mCameras = new aiCamera *[master->mNumCameras = num_camera];
|
master->mCameras = new aiCamera *[master->mNumCameras = num_camera];
|
||||||
}
|
}
|
||||||
aiCamera **cams = master->mCameras;
|
aiCamera **cams = master->mCameras;
|
||||||
|
|
|
@ -76,7 +76,7 @@ public:
|
||||||
std::list<Element> children;
|
std::list<Element> children;
|
||||||
|
|
||||||
//! Recursive parsing function
|
//! Recursive parsing function
|
||||||
void Parse(const char *&buffer);
|
void Parse(const char *&buffer, const char *end);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define AI_LWS_MASK (0xffffffff >> 4u)
|
#define AI_LWS_MASK (0xffffffff >> 4u)
|
||||||
|
|
|
@ -123,12 +123,12 @@ bool Q3Shader::LoadShader(ShaderData &fill, const std::string &pFile, IOSystem *
|
||||||
// remove comments from it (C++ style)
|
// remove comments from it (C++ style)
|
||||||
CommentRemover::RemoveLineComments("//", &_buff[0]);
|
CommentRemover::RemoveLineComments("//", &_buff[0]);
|
||||||
const char *buff = &_buff[0];
|
const char *buff = &_buff[0];
|
||||||
|
const char *end = buff + _buff.size();
|
||||||
Q3Shader::ShaderDataBlock *curData = nullptr;
|
Q3Shader::ShaderDataBlock *curData = nullptr;
|
||||||
Q3Shader::ShaderMapBlock *curMap = nullptr;
|
Q3Shader::ShaderMapBlock *curMap = nullptr;
|
||||||
|
|
||||||
// read line per line
|
// read line per line
|
||||||
for (; SkipSpacesAndLineEnd(&buff); SkipLine(&buff)) {
|
for (; SkipSpacesAndLineEnd(&buff, end); SkipLine(&buff, end)) {
|
||||||
|
|
||||||
if (*buff == '{') {
|
if (*buff == '{') {
|
||||||
++buff;
|
++buff;
|
||||||
|
@ -140,21 +140,21 @@ bool Q3Shader::LoadShader(ShaderData &fill, const std::string &pFile, IOSystem *
|
||||||
}
|
}
|
||||||
|
|
||||||
// read this data section
|
// read this data section
|
||||||
for (; SkipSpacesAndLineEnd(&buff); SkipLine(&buff)) {
|
for (; SkipSpacesAndLineEnd(&buff, end); SkipLine(&buff, end)) {
|
||||||
if (*buff == '{') {
|
if (*buff == '{') {
|
||||||
++buff;
|
++buff;
|
||||||
// add new map section
|
// add new map section
|
||||||
curData->maps.emplace_back();
|
curData->maps.emplace_back();
|
||||||
curMap = &curData->maps.back();
|
curMap = &curData->maps.back();
|
||||||
|
|
||||||
for (; SkipSpacesAndLineEnd(&buff); SkipLine(&buff)) {
|
for (; SkipSpacesAndLineEnd(&buff, end); SkipLine(&buff, end)) {
|
||||||
// 'map' - Specifies texture file name
|
// 'map' - Specifies texture file name
|
||||||
if (TokenMatchI(buff, "map", 3) || TokenMatchI(buff, "clampmap", 8)) {
|
if (TokenMatchI(buff, "map", 3) || TokenMatchI(buff, "clampmap", 8)) {
|
||||||
curMap->name = GetNextToken(buff);
|
curMap->name = GetNextToken(buff, end);
|
||||||
}
|
}
|
||||||
// 'blendfunc' - Alpha blending mode
|
// 'blendfunc' - Alpha blending mode
|
||||||
else if (TokenMatchI(buff, "blendfunc", 9)) {
|
else if (TokenMatchI(buff, "blendfunc", 9)) {
|
||||||
const std::string blend_src = GetNextToken(buff);
|
const std::string blend_src = GetNextToken(buff, end);
|
||||||
if (blend_src == "add") {
|
if (blend_src == "add") {
|
||||||
curMap->blend_src = Q3Shader::BLEND_GL_ONE;
|
curMap->blend_src = Q3Shader::BLEND_GL_ONE;
|
||||||
curMap->blend_dest = Q3Shader::BLEND_GL_ONE;
|
curMap->blend_dest = Q3Shader::BLEND_GL_ONE;
|
||||||
|
@ -166,12 +166,12 @@ bool Q3Shader::LoadShader(ShaderData &fill, const std::string &pFile, IOSystem *
|
||||||
curMap->blend_dest = Q3Shader::BLEND_GL_ONE_MINUS_SRC_ALPHA;
|
curMap->blend_dest = Q3Shader::BLEND_GL_ONE_MINUS_SRC_ALPHA;
|
||||||
} else {
|
} else {
|
||||||
curMap->blend_src = StringToBlendFunc(blend_src);
|
curMap->blend_src = StringToBlendFunc(blend_src);
|
||||||
curMap->blend_dest = StringToBlendFunc(GetNextToken(buff));
|
curMap->blend_dest = StringToBlendFunc(GetNextToken(buff, end));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 'alphafunc' - Alpha testing mode
|
// 'alphafunc' - Alpha testing mode
|
||||||
else if (TokenMatchI(buff, "alphafunc", 9)) {
|
else if (TokenMatchI(buff, "alphafunc", 9)) {
|
||||||
const std::string at = GetNextToken(buff);
|
const std::string at = GetNextToken(buff, end);
|
||||||
if (at == "GT0") {
|
if (at == "GT0") {
|
||||||
curMap->alpha_test = Q3Shader::AT_GT0;
|
curMap->alpha_test = Q3Shader::AT_GT0;
|
||||||
} else if (at == "LT128") {
|
} else if (at == "LT128") {
|
||||||
|
@ -186,7 +186,6 @@ bool Q3Shader::LoadShader(ShaderData &fill, const std::string &pFile, IOSystem *
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (*buff == '}') {
|
} else if (*buff == '}') {
|
||||||
++buff;
|
++buff;
|
||||||
curData = nullptr;
|
curData = nullptr;
|
||||||
|
@ -195,7 +194,7 @@ bool Q3Shader::LoadShader(ShaderData &fill, const std::string &pFile, IOSystem *
|
||||||
|
|
||||||
// 'cull' specifies culling behaviour for the model
|
// 'cull' specifies culling behaviour for the model
|
||||||
else if (TokenMatchI(buff, "cull", 4)) {
|
else if (TokenMatchI(buff, "cull", 4)) {
|
||||||
SkipSpaces(&buff);
|
SkipSpaces(&buff, end);
|
||||||
if (!ASSIMP_strincmp(buff, "back", 4)) { // render face's backside, does not function in Q3 engine (bug)
|
if (!ASSIMP_strincmp(buff, "back", 4)) { // render face's backside, does not function in Q3 engine (bug)
|
||||||
curData->cull = Q3Shader::CULL_CCW;
|
curData->cull = Q3Shader::CULL_CCW;
|
||||||
} else if (!ASSIMP_strincmp(buff, "front", 5)) { // is not valid keyword in Q3, but occurs in shaders
|
} else if (!ASSIMP_strincmp(buff, "front", 5)) { // is not valid keyword in Q3, but occurs in shaders
|
||||||
|
@ -213,9 +212,10 @@ bool Q3Shader::LoadShader(ShaderData &fill, const std::string &pFile, IOSystem *
|
||||||
curData = &fill.blocks.back();
|
curData = &fill.blocks.back();
|
||||||
|
|
||||||
// get the name of this section
|
// get the name of this section
|
||||||
curData->name = GetNextToken(buff);
|
curData->name = GetNextToken(buff, end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,6 +232,7 @@ bool Q3Shader::LoadSkin(SkinData &fill, const std::string &pFile, IOSystem *io)
|
||||||
const size_t s = file->FileSize();
|
const size_t s = file->FileSize();
|
||||||
std::vector<char> _buff(s + 1);
|
std::vector<char> _buff(s + 1);
|
||||||
const char *buff = &_buff[0];
|
const char *buff = &_buff[0];
|
||||||
|
const char *end = buff + _buff.size();
|
||||||
file->Read(&_buff[0], s, 1);
|
file->Read(&_buff[0], s, 1);
|
||||||
_buff[s] = 0;
|
_buff[s] = 0;
|
||||||
|
|
||||||
|
@ -240,10 +241,10 @@ bool Q3Shader::LoadSkin(SkinData &fill, const std::string &pFile, IOSystem *io)
|
||||||
|
|
||||||
// read token by token and fill output table
|
// read token by token and fill output table
|
||||||
for (; *buff;) {
|
for (; *buff;) {
|
||||||
SkipSpacesAndLineEnd(&buff);
|
SkipSpacesAndLineEnd(&buff, end);
|
||||||
|
|
||||||
// get first identifier
|
// get first identifier
|
||||||
std::string ss = GetNextToken(buff);
|
std::string ss = GetNextToken(buff, end);
|
||||||
|
|
||||||
// ignore tokens starting with tag_
|
// ignore tokens starting with tag_
|
||||||
if (!::strncmp(&ss[0], "tag_", std::min((size_t)4, ss.length())))
|
if (!::strncmp(&ss[0], "tag_", std::min((size_t)4, ss.length())))
|
||||||
|
@ -253,8 +254,9 @@ bool Q3Shader::LoadSkin(SkinData &fill, const std::string &pFile, IOSystem *io)
|
||||||
SkinData::TextureEntry &entry = fill.textures.back();
|
SkinData::TextureEntry &entry = fill.textures.back();
|
||||||
|
|
||||||
entry.first = ss;
|
entry.first = ss;
|
||||||
entry.second = GetNextToken(buff);
|
entry.second = GetNextToken(buff, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,7 +295,7 @@ void Q3Shader::ConvertShaderToMaterial(aiMaterial *out, const ShaderDataBlock &s
|
||||||
// - in any case: set it as diffuse texture
|
// - in any case: set it as diffuse texture
|
||||||
//
|
//
|
||||||
// If the texture is using 'filter' blending
|
// If the texture is using 'filter' blending
|
||||||
// - take as lightmap
|
// - take as light-map
|
||||||
//
|
//
|
||||||
// Textures with alpha funcs
|
// Textures with alpha funcs
|
||||||
// - aiTextureFlags_UseAlpha is set (otherwise aiTextureFlags_NoAlpha is explicitly set)
|
// - aiTextureFlags_UseAlpha is set (otherwise aiTextureFlags_NoAlpha is explicitly set)
|
||||||
|
|
|
@ -210,7 +210,7 @@ void MD5Importer::MakeDataUnique(MD5::MeshDesc &meshSrc) {
|
||||||
const unsigned int guess = (unsigned int)(fWeightsPerVert * iNewNum);
|
const unsigned int guess = (unsigned int)(fWeightsPerVert * iNewNum);
|
||||||
meshSrc.mWeights.reserve(guess + (guess >> 3)); // + 12.5% as buffer
|
meshSrc.mWeights.reserve(guess + (guess >> 3)); // + 12.5% as buffer
|
||||||
|
|
||||||
for (FaceList::const_iterator iter = meshSrc.mFaces.begin(), iterEnd = meshSrc.mFaces.end(); iter != iterEnd; ++iter) {
|
for (FaceArray::const_iterator iter = meshSrc.mFaces.begin(), iterEnd = meshSrc.mFaces.end(); iter != iterEnd; ++iter) {
|
||||||
const aiFace &face = *iter;
|
const aiFace &face = *iter;
|
||||||
for (unsigned int i = 0; i < 3; ++i) {
|
for (unsigned int i = 0; i < 3; ++i) {
|
||||||
if (face.mIndices[0] >= meshSrc.mVertices.size()) {
|
if (face.mIndices[0] >= meshSrc.mVertices.size()) {
|
||||||
|
@ -231,7 +231,7 @@ void MD5Importer::MakeDataUnique(MD5::MeshDesc &meshSrc) {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Recursive node graph construction from a MD5MESH
|
// Recursive node graph construction from a MD5MESH
|
||||||
void MD5Importer::AttachChilds_Mesh(int iParentID, aiNode *piParent, BoneList &bones) {
|
void MD5Importer::AttachChilds_Mesh(int iParentID, aiNode *piParent, BoneArray &bones) {
|
||||||
ai_assert(nullptr != piParent);
|
ai_assert(nullptr != piParent);
|
||||||
ai_assert(!piParent->mNumChildren);
|
ai_assert(!piParent->mNumChildren);
|
||||||
|
|
||||||
|
@ -282,7 +282,7 @@ void MD5Importer::AttachChilds_Mesh(int iParentID, aiNode *piParent, BoneList &b
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Recursive node graph construction from a MD5ANIM
|
// Recursive node graph construction from a MD5ANIM
|
||||||
void MD5Importer::AttachChilds_Anim(int iParentID, aiNode *piParent, AnimBoneList &bones, const aiNodeAnim **node_anims) {
|
void MD5Importer::AttachChilds_Anim(int iParentID, aiNode *piParent, AnimBoneArray &bones, const aiNodeAnim **node_anims) {
|
||||||
ai_assert(nullptr != piParent);
|
ai_assert(nullptr != piParent);
|
||||||
ai_assert(!piParent->mNumChildren);
|
ai_assert(!piParent->mNumChildren);
|
||||||
|
|
||||||
|
@ -402,7 +402,7 @@ void MD5Importer::LoadMD5MeshFile() {
|
||||||
|
|
||||||
// copy texture coordinates
|
// copy texture coordinates
|
||||||
aiVector3D *pv = mesh->mTextureCoords[0];
|
aiVector3D *pv = mesh->mTextureCoords[0];
|
||||||
for (MD5::VertexList::const_iterator iter = meshSrc.mVertices.begin(); iter != meshSrc.mVertices.end(); ++iter, ++pv) {
|
for (MD5::VertexArray::const_iterator iter = meshSrc.mVertices.begin(); iter != meshSrc.mVertices.end(); ++iter, ++pv) {
|
||||||
pv->x = (*iter).mUV.x;
|
pv->x = (*iter).mUV.x;
|
||||||
pv->y = 1.0f - (*iter).mUV.y; // D3D to OpenGL
|
pv->y = 1.0f - (*iter).mUV.y; // D3D to OpenGL
|
||||||
pv->z = 0.0f;
|
pv->z = 0.0f;
|
||||||
|
@ -412,7 +412,7 @@ void MD5Importer::LoadMD5MeshFile() {
|
||||||
unsigned int *piCount = new unsigned int[meshParser.mJoints.size()];
|
unsigned int *piCount = new unsigned int[meshParser.mJoints.size()];
|
||||||
::memset(piCount, 0, sizeof(unsigned int) * meshParser.mJoints.size());
|
::memset(piCount, 0, sizeof(unsigned int) * meshParser.mJoints.size());
|
||||||
|
|
||||||
for (MD5::VertexList::const_iterator iter = meshSrc.mVertices.begin(); iter != meshSrc.mVertices.end(); ++iter, ++pv) {
|
for (MD5::VertexArray::const_iterator iter = meshSrc.mVertices.begin(); iter != meshSrc.mVertices.end(); ++iter, ++pv) {
|
||||||
for (unsigned int jub = (*iter).mFirstWeight, w = jub; w < jub + (*iter).mNumWeights; ++w) {
|
for (unsigned int jub = (*iter).mFirstWeight, w = jub; w < jub + (*iter).mNumWeights; ++w) {
|
||||||
MD5::WeightDesc &weightDesc = meshSrc.mWeights[w];
|
MD5::WeightDesc &weightDesc = meshSrc.mWeights[w];
|
||||||
/* FIX for some invalid exporters */
|
/* FIX for some invalid exporters */
|
||||||
|
@ -447,7 +447,7 @@ void MD5Importer::LoadMD5MeshFile() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pv = mesh->mVertices;
|
pv = mesh->mVertices;
|
||||||
for (MD5::VertexList::const_iterator iter = meshSrc.mVertices.begin(); iter != meshSrc.mVertices.end(); ++iter, ++pv) {
|
for (MD5::VertexArray::const_iterator iter = meshSrc.mVertices.begin(); iter != meshSrc.mVertices.end(); ++iter, ++pv) {
|
||||||
// compute the final vertex position from all single weights
|
// compute the final vertex position from all single weights
|
||||||
*pv = aiVector3D();
|
*pv = aiVector3D();
|
||||||
|
|
||||||
|
@ -585,14 +585,14 @@ void MD5Importer::LoadMD5AnimFile() {
|
||||||
// 1 tick == 1 frame
|
// 1 tick == 1 frame
|
||||||
anim->mTicksPerSecond = animParser.fFrameRate;
|
anim->mTicksPerSecond = animParser.fFrameRate;
|
||||||
|
|
||||||
for (FrameList::const_iterator iter = animParser.mFrames.begin(), iterEnd = animParser.mFrames.end(); iter != iterEnd; ++iter) {
|
for (FrameArray::const_iterator iter = animParser.mFrames.begin(), iterEnd = animParser.mFrames.end(); iter != iterEnd; ++iter) {
|
||||||
double dTime = (double)(*iter).iIndex;
|
double dTime = (double)(*iter).iIndex;
|
||||||
aiNodeAnim **pcAnimNode = anim->mChannels;
|
aiNodeAnim **pcAnimNode = anim->mChannels;
|
||||||
if (!(*iter).mValues.empty() || iter == animParser.mFrames.begin()) /* be sure we have at least one frame */
|
if (!(*iter).mValues.empty() || iter == animParser.mFrames.begin()) /* be sure we have at least one frame */
|
||||||
{
|
{
|
||||||
// now process all values in there ... read all joints
|
// now process all values in there ... read all joints
|
||||||
MD5::BaseFrameDesc *pcBaseFrame = &animParser.mBaseFrames[0];
|
MD5::BaseFrameDesc *pcBaseFrame = &animParser.mBaseFrames[0];
|
||||||
for (AnimBoneList::const_iterator iter2 = animParser.mAnimatedBones.begin(); iter2 != animParser.mAnimatedBones.end(); ++iter2,
|
for (AnimBoneArray::const_iterator iter2 = animParser.mAnimatedBones.begin(); iter2 != animParser.mAnimatedBones.end(); ++iter2,
|
||||||
++pcAnimNode, ++pcBaseFrame) {
|
++pcAnimNode, ++pcBaseFrame) {
|
||||||
if ((*iter2).iFirstKeyIndex >= (*iter).mValues.size()) {
|
if ((*iter2).iFirstKeyIndex >= (*iter).mValues.size()) {
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Open Asset Import Library (assimp)
|
Open Asset Import Library (assimp)
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
Copyright (c) 2006-2022, assimp team
|
Copyright (c) 2006-2024, assimp team
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ protected:
|
||||||
* @param node_anims Generated node animations
|
* @param node_anims Generated node animations
|
||||||
*/
|
*/
|
||||||
void AttachChilds_Anim(int iParentID, aiNode *piParent,
|
void AttachChilds_Anim(int iParentID, aiNode *piParent,
|
||||||
AnimBoneList &bones, const aiNodeAnim **node_anims);
|
AnimBoneArray &bones, const aiNodeAnim **node_anims);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Construct node hierarchy from a given MD5MESH
|
/** Construct node hierarchy from a given MD5MESH
|
||||||
|
@ -126,7 +126,7 @@ protected:
|
||||||
* @param piParent Parent node to attach to
|
* @param piParent Parent node to attach to
|
||||||
* @param bones Input bones
|
* @param bones Input bones
|
||||||
*/
|
*/
|
||||||
void AttachChilds_Mesh(int iParentID, aiNode *piParent, BoneList &bones);
|
void AttachChilds_Mesh(int iParentID, aiNode *piParent, BoneArray &bones);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Build unique vertex buffers from a given MD5ANIM
|
/** Build unique vertex buffers from a given MD5ANIM
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
Open Asset Import Library (assimp)
|
Open Asset Import Library (assimp)
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
Copyright (c) 2006-2023, assimp team
|
Copyright (c) 2006-2024, assimp team
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
|
@ -138,30 +138,34 @@ bool MD5Parser::ParseSection(Section &out) {
|
||||||
char *sz = buffer;
|
char *sz = buffer;
|
||||||
while (!IsSpaceOrNewLine(*buffer)) {
|
while (!IsSpaceOrNewLine(*buffer)) {
|
||||||
++buffer;
|
++buffer;
|
||||||
if (buffer == bufferEnd)
|
if (buffer == bufferEnd) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
out.mName = std::string(sz, (uintptr_t)(buffer - sz));
|
out.mName = std::string(sz, (uintptr_t)(buffer - sz));
|
||||||
while (IsSpace(*buffer)) {
|
while (IsSpace(*buffer)) {
|
||||||
++buffer;
|
++buffer;
|
||||||
if (buffer == bufferEnd)
|
if (buffer == bufferEnd) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool running = true;
|
bool running = true;
|
||||||
while (running) {
|
while (running) {
|
||||||
if ('{' == *buffer) {
|
if ('{' == *buffer) {
|
||||||
// it is a normal section so read all lines
|
// it is a normal section so read all lines
|
||||||
++buffer;
|
++buffer;
|
||||||
if (buffer == bufferEnd)
|
if (buffer == bufferEnd) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
bool run = true;
|
bool run = true;
|
||||||
while (run) {
|
while (run) {
|
||||||
while (IsSpaceOrNewLine(*buffer)) {
|
while (IsSpaceOrNewLine(*buffer)) {
|
||||||
++buffer;
|
++buffer;
|
||||||
if (buffer == bufferEnd)
|
if (buffer == bufferEnd) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if ('\0' == *buffer) {
|
if ('\0' == *buffer) {
|
||||||
return false; // seems this was the last section
|
return false; // seems this was the last section
|
||||||
}
|
}
|
||||||
|
@ -175,108 +179,129 @@ bool MD5Parser::ParseSection(Section &out) {
|
||||||
|
|
||||||
elem.iLineNumber = lineNumber;
|
elem.iLineNumber = lineNumber;
|
||||||
elem.szStart = buffer;
|
elem.szStart = buffer;
|
||||||
|
elem.end = bufferEnd;
|
||||||
|
|
||||||
// terminate the line with zero
|
// terminate the line with zero
|
||||||
while (!IsLineEnd(*buffer)) {
|
while (!IsLineEnd(*buffer)) {
|
||||||
++buffer;
|
++buffer;
|
||||||
if (buffer == bufferEnd)
|
if (buffer == bufferEnd) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (*buffer) {
|
if (*buffer) {
|
||||||
++lineNumber;
|
++lineNumber;
|
||||||
*buffer++ = '\0';
|
*buffer++ = '\0';
|
||||||
if (buffer == bufferEnd)
|
if (buffer == bufferEnd) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
} else if (!IsSpaceOrNewLine(*buffer)) {
|
} else if (!IsSpaceOrNewLine(*buffer)) {
|
||||||
// it is an element at global scope. Parse its value and go on
|
// it is an element at global scope. Parse its value and go on
|
||||||
sz = buffer;
|
sz = buffer;
|
||||||
while (!IsSpaceOrNewLine(*buffer++)) {
|
while (!IsSpaceOrNewLine(*buffer++)) {
|
||||||
if (buffer == bufferEnd)
|
if (buffer == bufferEnd) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
out.mGlobalValue = std::string(sz, (uintptr_t)(buffer - sz));
|
out.mGlobalValue = std::string(sz, (uintptr_t)(buffer - sz));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (buffer == bufferEnd)
|
if (buffer == bufferEnd) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
while (IsSpaceOrNewLine(*buffer)) {
|
while (IsSpaceOrNewLine(*buffer)) {
|
||||||
|
if (buffer == bufferEnd) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
++buffer;
|
++buffer;
|
||||||
if (buffer == bufferEnd)
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return '\0' != *buffer;
|
return '\0' != *buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// Some dirty macros just because they're so funny and easy to debug
|
|
||||||
|
|
||||||
// skip all spaces ... handle EOL correctly
|
// skip all spaces ... handle EOL correctly
|
||||||
#define AI_MD5_SKIP_SPACES() \
|
inline void AI_MD5_SKIP_SPACES(const char **sz, const char *bufferEnd, int linenumber) {
|
||||||
if (!SkipSpaces(&sz)) \
|
if (!SkipSpaces(sz, bufferEnd)) {
|
||||||
MD5Parser::ReportWarning("Unexpected end of line", elem.iLineNumber);
|
MD5Parser::ReportWarning("Unexpected end of line", linenumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// read a triple float in brackets: (1.0 1.0 1.0)
|
// read a triple float in brackets: (1.0 1.0 1.0)
|
||||||
#define AI_MD5_READ_TRIPLE(vec) \
|
inline void AI_MD5_READ_TRIPLE(aiVector3D &vec, const char **sz, const char *bufferEnd, int linenumber) {
|
||||||
AI_MD5_SKIP_SPACES(); \
|
AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber);
|
||||||
if ('(' != *sz++) \
|
if ('(' != **sz) {
|
||||||
MD5Parser::ReportWarning("Unexpected token: ( was expected", elem.iLineNumber); \
|
MD5Parser::ReportWarning("Unexpected token: ( was expected", linenumber);
|
||||||
AI_MD5_SKIP_SPACES(); \
|
++*sz;
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)vec.x); \
|
}
|
||||||
AI_MD5_SKIP_SPACES(); \
|
++*sz;
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)vec.y); \
|
AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber);
|
||||||
AI_MD5_SKIP_SPACES(); \
|
*sz = fast_atoreal_move<float>(*sz, (float &)vec.x);
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)vec.z); \
|
AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber);
|
||||||
AI_MD5_SKIP_SPACES(); \
|
*sz = fast_atoreal_move<float>(*sz, (float &)vec.y);
|
||||||
if (')' != *sz++) \
|
AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber);
|
||||||
MD5Parser::ReportWarning("Unexpected token: ) was expected", elem.iLineNumber);
|
*sz = fast_atoreal_move<float>(*sz, (float &)vec.z);
|
||||||
|
AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber);
|
||||||
|
if (')' != **sz) {
|
||||||
|
MD5Parser::ReportWarning("Unexpected token: ) was expected", linenumber);
|
||||||
|
}
|
||||||
|
++*sz;
|
||||||
|
}
|
||||||
|
|
||||||
// parse a string, enclosed in quotation marks or not
|
// parse a string, enclosed in quotation marks or not
|
||||||
#define AI_MD5_PARSE_STRING(out) \
|
inline bool AI_MD5_PARSE_STRING(const char **sz, const char *bufferEnd, aiString &out, int linenumber) {
|
||||||
bool bQuota = (*sz == '\"'); \
|
bool bQuota = (**sz == '\"');
|
||||||
const char *szStart = sz; \
|
const char *szStart = *sz;
|
||||||
while (!IsSpaceOrNewLine(*sz)) \
|
while (!IsSpaceOrNewLine(**sz)) {
|
||||||
++sz; \
|
++*sz;
|
||||||
const char *szEnd = sz; \
|
if (*sz == bufferEnd) break;
|
||||||
if (bQuota) { \
|
}
|
||||||
szStart++; \
|
const char *szEnd = *sz;
|
||||||
if ('\"' != *(szEnd -= 1)) { \
|
if (bQuota) {
|
||||||
MD5Parser::ReportWarning("Expected closing quotation marks in string", \
|
szStart++;
|
||||||
elem.iLineNumber); \
|
if ('\"' != *(szEnd -= 1)) {
|
||||||
continue; \
|
MD5Parser::ReportWarning("Expected closing quotation marks in string", linenumber);
|
||||||
} \
|
++*sz;
|
||||||
} \
|
}
|
||||||
out.length = (size_t)(szEnd - szStart); \
|
}
|
||||||
::memcpy(out.data, szStart, out.length); \
|
out.length = (ai_uint32)(szEnd - szStart);
|
||||||
|
::memcpy(out.data, szStart, out.length);
|
||||||
out.data[out.length] = '\0';
|
out.data[out.length] = '\0';
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// parse a string, enclosed in quotation marks
|
// parse a string, enclosed in quotation marks
|
||||||
#define AI_MD5_PARSE_STRING_IN_QUOTATION(out) \
|
inline void AI_MD5_PARSE_STRING_IN_QUOTATION(const char **sz, const char *bufferEnd, aiString &out) {
|
||||||
out.length = 0; \
|
out.length = 0u;
|
||||||
while ('\"' != *sz && '\0' != *sz) \
|
while (('\"' != **sz && '\0' != **sz) && *sz != bufferEnd) {
|
||||||
++sz; \
|
++*sz;
|
||||||
if ('\0' != *sz) { \
|
}
|
||||||
const char *szStart = ++sz; \
|
if ('\0' != **sz) {
|
||||||
while ('\"' != *sz && '\0' != *sz) \
|
const char *szStart = ++(*sz);
|
||||||
++sz; \
|
|
||||||
if ('\0' != *sz) { \
|
while (('\"' != **sz && '\0' != **sz) && *sz != bufferEnd) {
|
||||||
const char *szEnd = (sz++); \
|
++*sz;
|
||||||
out.length = (ai_uint32)(szEnd - szStart); \
|
}
|
||||||
::memcpy(out.data, szStart, out.length); \
|
if ('\0' != **sz) {
|
||||||
} \
|
const char *szEnd = *sz;
|
||||||
} \
|
++*sz;
|
||||||
|
out.length = (ai_uint32)(szEnd - szStart);
|
||||||
|
::memcpy(out.data, szStart, out.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
out.data[out.length] = '\0';
|
out.data[out.length] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// .MD5MESH parsing function
|
// .MD5MESH parsing function
|
||||||
MD5MeshParser::MD5MeshParser(SectionList &mSections) {
|
MD5MeshParser::MD5MeshParser(SectionArray &mSections) {
|
||||||
ASSIMP_LOG_DEBUG("MD5MeshParser begin");
|
ASSIMP_LOG_DEBUG("MD5MeshParser begin");
|
||||||
|
|
||||||
// now parse all sections
|
// now parse all sections
|
||||||
for (SectionList::const_iterator iter = mSections.begin(), iterEnd = mSections.end(); iter != iterEnd; ++iter) {
|
for (SectionArray::const_iterator iter = mSections.begin(), iterEnd = mSections.end(); iter != iterEnd; ++iter) {
|
||||||
if ((*iter).mName == "numMeshes") {
|
if ((*iter).mName == "numMeshes") {
|
||||||
mMeshes.reserve(::strtoul10((*iter).mGlobalValue.c_str()));
|
mMeshes.reserve(::strtoul10((*iter).mGlobalValue.c_str()));
|
||||||
} else if ((*iter).mName == "numJoints") {
|
} else if ((*iter).mName == "numJoints") {
|
||||||
|
@ -288,14 +313,15 @@ MD5MeshParser::MD5MeshParser(SectionList &mSections) {
|
||||||
BoneDesc &desc = mJoints.back();
|
BoneDesc &desc = mJoints.back();
|
||||||
|
|
||||||
const char *sz = elem.szStart;
|
const char *sz = elem.szStart;
|
||||||
AI_MD5_PARSE_STRING_IN_QUOTATION(desc.mName);
|
AI_MD5_PARSE_STRING_IN_QUOTATION(&sz, elem.end, desc.mName);
|
||||||
AI_MD5_SKIP_SPACES();
|
|
||||||
|
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
|
||||||
|
|
||||||
// negative values, at least -1, is allowed here
|
// negative values, at least -1, is allowed here
|
||||||
desc.mParentIndex = (int)strtol10(sz, &sz);
|
desc.mParentIndex = (int)strtol10(sz, &sz);
|
||||||
|
|
||||||
AI_MD5_READ_TRIPLE(desc.mPositionXYZ);
|
AI_MD5_READ_TRIPLE(desc.mPositionXYZ, &sz, elem.end, elem.iLineNumber);
|
||||||
AI_MD5_READ_TRIPLE(desc.mRotationQuat); // normalized quaternion, so w is not there
|
AI_MD5_READ_TRIPLE(desc.mRotationQuat, &sz, elem.end, elem.iLineNumber); // normalized quaternion, so w is not there
|
||||||
}
|
}
|
||||||
} else if ((*iter).mName == "mesh") {
|
} else if ((*iter).mName == "mesh") {
|
||||||
mMeshes.emplace_back();
|
mMeshes.emplace_back();
|
||||||
|
@ -306,52 +332,52 @@ MD5MeshParser::MD5MeshParser(SectionList &mSections) {
|
||||||
|
|
||||||
// shader attribute
|
// shader attribute
|
||||||
if (TokenMatch(sz, "shader", 6)) {
|
if (TokenMatch(sz, "shader", 6)) {
|
||||||
AI_MD5_SKIP_SPACES();
|
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
|
||||||
AI_MD5_PARSE_STRING_IN_QUOTATION(desc.mShader);
|
AI_MD5_PARSE_STRING_IN_QUOTATION(&sz, elem.end, desc.mShader);
|
||||||
}
|
}
|
||||||
// numverts attribute
|
// numverts attribute
|
||||||
else if (TokenMatch(sz, "numverts", 8)) {
|
else if (TokenMatch(sz, "numverts", 8)) {
|
||||||
AI_MD5_SKIP_SPACES();
|
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
|
||||||
desc.mVertices.resize(strtoul10(sz));
|
desc.mVertices.resize(strtoul10(sz));
|
||||||
}
|
}
|
||||||
// numtris attribute
|
// numtris attribute
|
||||||
else if (TokenMatch(sz, "numtris", 7)) {
|
else if (TokenMatch(sz, "numtris", 7)) {
|
||||||
AI_MD5_SKIP_SPACES();
|
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
|
||||||
desc.mFaces.resize(strtoul10(sz));
|
desc.mFaces.resize(strtoul10(sz));
|
||||||
}
|
}
|
||||||
// numweights attribute
|
// numweights attribute
|
||||||
else if (TokenMatch(sz, "numweights", 10)) {
|
else if (TokenMatch(sz, "numweights", 10)) {
|
||||||
AI_MD5_SKIP_SPACES();
|
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
|
||||||
desc.mWeights.resize(strtoul10(sz));
|
desc.mWeights.resize(strtoul10(sz));
|
||||||
}
|
}
|
||||||
// vert attribute
|
// vert attribute
|
||||||
// "vert 0 ( 0.394531 0.513672 ) 0 1"
|
// "vert 0 ( 0.394531 0.513672 ) 0 1"
|
||||||
else if (TokenMatch(sz, "vert", 4)) {
|
else if (TokenMatch(sz, "vert", 4)) {
|
||||||
AI_MD5_SKIP_SPACES();
|
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
|
||||||
const unsigned int idx = ::strtoul10(sz, &sz);
|
const unsigned int idx = ::strtoul10(sz, &sz);
|
||||||
AI_MD5_SKIP_SPACES();
|
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
|
||||||
if (idx >= desc.mVertices.size())
|
if (idx >= desc.mVertices.size())
|
||||||
desc.mVertices.resize(idx + 1);
|
desc.mVertices.resize(idx + 1);
|
||||||
|
|
||||||
VertexDesc &vert = desc.mVertices[idx];
|
VertexDesc &vert = desc.mVertices[idx];
|
||||||
if ('(' != *sz++)
|
if ('(' != *sz++)
|
||||||
MD5Parser::ReportWarning("Unexpected token: ( was expected", elem.iLineNumber);
|
MD5Parser::ReportWarning("Unexpected token: ( was expected", elem.iLineNumber);
|
||||||
AI_MD5_SKIP_SPACES();
|
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)vert.mUV.x);
|
sz = fast_atoreal_move<float>(sz, (float &)vert.mUV.x);
|
||||||
AI_MD5_SKIP_SPACES();
|
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)vert.mUV.y);
|
sz = fast_atoreal_move<float>(sz, (float &)vert.mUV.y);
|
||||||
AI_MD5_SKIP_SPACES();
|
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
|
||||||
if (')' != *sz++)
|
if (')' != *sz++)
|
||||||
MD5Parser::ReportWarning("Unexpected token: ) was expected", elem.iLineNumber);
|
MD5Parser::ReportWarning("Unexpected token: ) was expected", elem.iLineNumber);
|
||||||
AI_MD5_SKIP_SPACES();
|
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
|
||||||
vert.mFirstWeight = ::strtoul10(sz, &sz);
|
vert.mFirstWeight = ::strtoul10(sz, &sz);
|
||||||
AI_MD5_SKIP_SPACES();
|
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
|
||||||
vert.mNumWeights = ::strtoul10(sz, &sz);
|
vert.mNumWeights = ::strtoul10(sz, &sz);
|
||||||
}
|
}
|
||||||
// tri attribute
|
// tri attribute
|
||||||
// "tri 0 15 13 12"
|
// "tri 0 15 13 12"
|
||||||
else if (TokenMatch(sz, "tri", 3)) {
|
else if (TokenMatch(sz, "tri", 3)) {
|
||||||
AI_MD5_SKIP_SPACES();
|
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
|
||||||
const unsigned int idx = strtoul10(sz, &sz);
|
const unsigned int idx = strtoul10(sz, &sz);
|
||||||
if (idx >= desc.mFaces.size())
|
if (idx >= desc.mFaces.size())
|
||||||
desc.mFaces.resize(idx + 1);
|
desc.mFaces.resize(idx + 1);
|
||||||
|
@ -359,24 +385,24 @@ MD5MeshParser::MD5MeshParser(SectionList &mSections) {
|
||||||
aiFace &face = desc.mFaces[idx];
|
aiFace &face = desc.mFaces[idx];
|
||||||
face.mIndices = new unsigned int[face.mNumIndices = 3];
|
face.mIndices = new unsigned int[face.mNumIndices = 3];
|
||||||
for (unsigned int i = 0; i < 3; ++i) {
|
for (unsigned int i = 0; i < 3; ++i) {
|
||||||
AI_MD5_SKIP_SPACES();
|
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
|
||||||
face.mIndices[i] = strtoul10(sz, &sz);
|
face.mIndices[i] = strtoul10(sz, &sz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// weight attribute
|
// weight attribute
|
||||||
// "weight 362 5 0.500000 ( -3.553583 11.893474 9.719339 )"
|
// "weight 362 5 0.500000 ( -3.553583 11.893474 9.719339 )"
|
||||||
else if (TokenMatch(sz, "weight", 6)) {
|
else if (TokenMatch(sz, "weight", 6)) {
|
||||||
AI_MD5_SKIP_SPACES();
|
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
|
||||||
const unsigned int idx = strtoul10(sz, &sz);
|
const unsigned int idx = strtoul10(sz, &sz);
|
||||||
AI_MD5_SKIP_SPACES();
|
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
|
||||||
if (idx >= desc.mWeights.size())
|
if (idx >= desc.mWeights.size())
|
||||||
desc.mWeights.resize(idx + 1);
|
desc.mWeights.resize(idx + 1);
|
||||||
|
|
||||||
WeightDesc &weight = desc.mWeights[idx];
|
WeightDesc &weight = desc.mWeights[idx];
|
||||||
weight.mBone = strtoul10(sz, &sz);
|
weight.mBone = strtoul10(sz, &sz);
|
||||||
AI_MD5_SKIP_SPACES();
|
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
|
||||||
sz = fast_atoreal_move<float>(sz, weight.mWeight);
|
sz = fast_atoreal_move<float>(sz, weight.mWeight);
|
||||||
AI_MD5_READ_TRIPLE(weight.vOffsetPosition);
|
AI_MD5_READ_TRIPLE(weight.vOffsetPosition, &sz, elem.end, elem.iLineNumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -386,12 +412,12 @@ MD5MeshParser::MD5MeshParser(SectionList &mSections) {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// .MD5ANIM parsing function
|
// .MD5ANIM parsing function
|
||||||
MD5AnimParser::MD5AnimParser(SectionList &mSections) {
|
MD5AnimParser::MD5AnimParser(SectionArray &mSections) {
|
||||||
ASSIMP_LOG_DEBUG("MD5AnimParser begin");
|
ASSIMP_LOG_DEBUG("MD5AnimParser begin");
|
||||||
|
|
||||||
fFrameRate = 24.0f;
|
fFrameRate = 24.0f;
|
||||||
mNumAnimatedComponents = UINT_MAX;
|
mNumAnimatedComponents = UINT_MAX;
|
||||||
for (SectionList::const_iterator iter = mSections.begin(), iterEnd = mSections.end(); iter != iterEnd; ++iter) {
|
for (SectionArray::const_iterator iter = mSections.begin(), iterEnd = mSections.end(); iter != iterEnd; ++iter) {
|
||||||
if ((*iter).mName == "hierarchy") {
|
if ((*iter).mName == "hierarchy") {
|
||||||
// "sheath" 0 63 6
|
// "sheath" 0 63 6
|
||||||
for (const auto &elem : (*iter).mElements) {
|
for (const auto &elem : (*iter).mElements) {
|
||||||
|
@ -399,18 +425,18 @@ MD5AnimParser::MD5AnimParser(SectionList &mSections) {
|
||||||
AnimBoneDesc &desc = mAnimatedBones.back();
|
AnimBoneDesc &desc = mAnimatedBones.back();
|
||||||
|
|
||||||
const char *sz = elem.szStart;
|
const char *sz = elem.szStart;
|
||||||
AI_MD5_PARSE_STRING_IN_QUOTATION(desc.mName);
|
AI_MD5_PARSE_STRING_IN_QUOTATION(&sz, elem.end, desc.mName);
|
||||||
AI_MD5_SKIP_SPACES();
|
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
|
||||||
|
|
||||||
// parent index - negative values are allowed (at least -1)
|
// parent index - negative values are allowed (at least -1)
|
||||||
desc.mParentIndex = ::strtol10(sz, &sz);
|
desc.mParentIndex = ::strtol10(sz, &sz);
|
||||||
|
|
||||||
// flags (highest is 2^6-1)
|
// flags (highest is 2^6-1)
|
||||||
AI_MD5_SKIP_SPACES();
|
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
|
||||||
if (63 < (desc.iFlags = ::strtoul10(sz, &sz))) {
|
if (63 < (desc.iFlags = ::strtoul10(sz, &sz))) {
|
||||||
MD5Parser::ReportWarning("Invalid flag combination in hierarchy section", elem.iLineNumber);
|
MD5Parser::ReportWarning("Invalid flag combination in hierarchy section", elem.iLineNumber);
|
||||||
}
|
}
|
||||||
AI_MD5_SKIP_SPACES();
|
AI_MD5_SKIP_SPACES(& sz, elem.end, elem.iLineNumber);
|
||||||
|
|
||||||
// index of the first animation keyframe component for this joint
|
// index of the first animation keyframe component for this joint
|
||||||
desc.iFirstKeyIndex = ::strtoul10(sz, &sz);
|
desc.iFirstKeyIndex = ::strtoul10(sz, &sz);
|
||||||
|
@ -423,8 +449,8 @@ MD5AnimParser::MD5AnimParser(SectionList &mSections) {
|
||||||
mBaseFrames.emplace_back();
|
mBaseFrames.emplace_back();
|
||||||
BaseFrameDesc &desc = mBaseFrames.back();
|
BaseFrameDesc &desc = mBaseFrames.back();
|
||||||
|
|
||||||
AI_MD5_READ_TRIPLE(desc.vPositionXYZ);
|
AI_MD5_READ_TRIPLE(desc.vPositionXYZ, &sz, elem.end, elem.iLineNumber);
|
||||||
AI_MD5_READ_TRIPLE(desc.vRotationQuat);
|
AI_MD5_READ_TRIPLE(desc.vRotationQuat, &sz, elem.end, elem.iLineNumber);
|
||||||
}
|
}
|
||||||
} else if ((*iter).mName == "frame") {
|
} else if ((*iter).mName == "frame") {
|
||||||
if (!(*iter).mGlobalValue.length()) {
|
if (!(*iter).mGlobalValue.length()) {
|
||||||
|
@ -444,7 +470,7 @@ MD5AnimParser::MD5AnimParser(SectionList &mSections) {
|
||||||
// now read all elements (continuous list of floats)
|
// now read all elements (continuous list of floats)
|
||||||
for (const auto &elem : (*iter).mElements) {
|
for (const auto &elem : (*iter).mElements) {
|
||||||
const char *sz = elem.szStart;
|
const char *sz = elem.szStart;
|
||||||
while (SkipSpacesAndLineEnd(&sz)) {
|
while (SkipSpacesAndLineEnd(&sz, elem.end)) {
|
||||||
float f;
|
float f;
|
||||||
sz = fast_atoreal_move<float>(sz, f);
|
sz = fast_atoreal_move<float>(sz, f);
|
||||||
desc.mValues.push_back(f);
|
desc.mValues.push_back(f);
|
||||||
|
@ -471,11 +497,11 @@ MD5AnimParser::MD5AnimParser(SectionList &mSections) {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// .MD5CAMERA parsing function
|
// .MD5CAMERA parsing function
|
||||||
MD5CameraParser::MD5CameraParser(SectionList &mSections) {
|
MD5CameraParser::MD5CameraParser(SectionArray &mSections) {
|
||||||
ASSIMP_LOG_DEBUG("MD5CameraParser begin");
|
ASSIMP_LOG_DEBUG("MD5CameraParser begin");
|
||||||
fFrameRate = 24.0f;
|
fFrameRate = 24.0f;
|
||||||
|
|
||||||
for (SectionList::const_iterator iter = mSections.begin(), iterEnd = mSections.end(); iter != iterEnd; ++iter) {
|
for (SectionArray::const_iterator iter = mSections.begin(), iterEnd = mSections.end(); iter != iterEnd; ++iter) {
|
||||||
if ((*iter).mName == "numFrames") {
|
if ((*iter).mName == "numFrames") {
|
||||||
frames.reserve(strtoul10((*iter).mGlobalValue.c_str()));
|
frames.reserve(strtoul10((*iter).mGlobalValue.c_str()));
|
||||||
} else if ((*iter).mName == "frameRate") {
|
} else if ((*iter).mName == "frameRate") {
|
||||||
|
@ -492,9 +518,9 @@ MD5CameraParser::MD5CameraParser(SectionList &mSections) {
|
||||||
|
|
||||||
frames.emplace_back();
|
frames.emplace_back();
|
||||||
CameraAnimFrameDesc &cur = frames.back();
|
CameraAnimFrameDesc &cur = frames.back();
|
||||||
AI_MD5_READ_TRIPLE(cur.vPositionXYZ);
|
AI_MD5_READ_TRIPLE(cur.vPositionXYZ, &sz, elem.end, elem.iLineNumber);
|
||||||
AI_MD5_READ_TRIPLE(cur.vRotationQuat);
|
AI_MD5_READ_TRIPLE(cur.vRotationQuat, &sz, elem.end, elem.iLineNumber);
|
||||||
AI_MD5_SKIP_SPACES();
|
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
|
||||||
cur.fFOV = fast_atof(sz);
|
cur.fFOV = fast_atof(sz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Open Asset Import Library (assimp)
|
Open Asset Import Library (assimp)
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
Copyright (c) 2006-2023, assimp team
|
Copyright (c) 2006-2024, assimp team
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
|
@ -68,12 +68,14 @@ struct Element {
|
||||||
//! Elements are terminated with \0
|
//! Elements are terminated with \0
|
||||||
char* szStart;
|
char* szStart;
|
||||||
|
|
||||||
|
const char *end;
|
||||||
|
|
||||||
//! Original line number (can be used in error messages
|
//! Original line number (can be used in error messages
|
||||||
//! if a parsing error occurs)
|
//! if a parsing error occurs)
|
||||||
unsigned int iLineNumber;
|
unsigned int iLineNumber;
|
||||||
};
|
};
|
||||||
|
|
||||||
using ElementList = std::vector<Element>;
|
using ElementArray = std::vector<Element>;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Represents a section of a MD5 file (such as the mesh or the joints section)
|
/** Represents a section of a MD5 file (such as the mesh or the joints section)
|
||||||
|
@ -86,7 +88,7 @@ struct Section {
|
||||||
unsigned int iLineNumber;
|
unsigned int iLineNumber;
|
||||||
|
|
||||||
//! List of all elements which have been parsed in this section.
|
//! List of all elements which have been parsed in this section.
|
||||||
ElementList mElements;
|
ElementArray mElements;
|
||||||
|
|
||||||
//! Name of the section
|
//! Name of the section
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
@ -96,7 +98,7 @@ struct Section {
|
||||||
std::string mGlobalValue;
|
std::string mGlobalValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
using SectionList = std::vector<Section>;
|
using SectionArray = std::vector<Section>;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Basic information about a joint
|
/** Basic information about a joint
|
||||||
|
@ -132,7 +134,7 @@ struct BoneDesc : BaseJointDescription {
|
||||||
unsigned int mMap;
|
unsigned int mMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
using BoneList = std::vector<BoneDesc>;
|
using BoneArray = std::vector<BoneDesc>;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Represents a bone (joint) descriptor in a MD5Anim file
|
/** Represents a bone (joint) descriptor in a MD5Anim file
|
||||||
|
@ -145,7 +147,7 @@ struct AnimBoneDesc : BaseJointDescription {
|
||||||
unsigned int iFirstKeyIndex;
|
unsigned int iFirstKeyIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
using AnimBoneList = std::vector< AnimBoneDesc >;
|
using AnimBoneArray = std::vector< AnimBoneDesc >;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Represents a base frame descriptor in a MD5Anim file
|
/** Represents a base frame descriptor in a MD5Anim file
|
||||||
|
@ -155,7 +157,7 @@ struct BaseFrameDesc {
|
||||||
aiVector3D vRotationQuat;
|
aiVector3D vRotationQuat;
|
||||||
};
|
};
|
||||||
|
|
||||||
using BaseFrameList = std::vector<BaseFrameDesc>;
|
using BaseFrameArray = std::vector<BaseFrameDesc>;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Represents a camera animation frame in a MDCamera file
|
/** Represents a camera animation frame in a MDCamera file
|
||||||
|
@ -164,7 +166,7 @@ struct CameraAnimFrameDesc : BaseFrameDesc {
|
||||||
float fFOV;
|
float fFOV;
|
||||||
};
|
};
|
||||||
|
|
||||||
using CameraFrameList = std::vector<CameraAnimFrameDesc>;
|
using CameraFrameArray = std::vector<CameraAnimFrameDesc>;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Represents a frame descriptor in a MD5Anim file
|
/** Represents a frame descriptor in a MD5Anim file
|
||||||
|
@ -177,7 +179,7 @@ struct FrameDesc {
|
||||||
std::vector< float > mValues;
|
std::vector< float > mValues;
|
||||||
};
|
};
|
||||||
|
|
||||||
using FrameList = std::vector<FrameDesc>;
|
using FrameArray = std::vector<FrameDesc>;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Represents a vertex descriptor in a MD5 file
|
/** Represents a vertex descriptor in a MD5 file
|
||||||
|
@ -199,7 +201,7 @@ struct VertexDesc {
|
||||||
unsigned int mNumWeights;
|
unsigned int mNumWeights;
|
||||||
};
|
};
|
||||||
|
|
||||||
using VertexList = std::vector<VertexDesc>;
|
using VertexArray = std::vector<VertexDesc>;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Represents a vertex weight descriptor in a MD5 file
|
/** Represents a vertex weight descriptor in a MD5 file
|
||||||
|
@ -216,27 +218,27 @@ struct WeightDesc {
|
||||||
aiVector3D vOffsetPosition;
|
aiVector3D vOffsetPosition;
|
||||||
};
|
};
|
||||||
|
|
||||||
using WeightList = std::vector<WeightDesc>;
|
using WeightArray = std::vector<WeightDesc>;
|
||||||
using FaceList = std::vector<aiFace>;
|
using FaceArray = std::vector<aiFace>;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Represents a mesh in a MD5 file
|
/** Represents a mesh in a MD5 file
|
||||||
*/
|
*/
|
||||||
struct MeshDesc {
|
struct MeshDesc {
|
||||||
//! Weights of the mesh
|
//! Weights of the mesh
|
||||||
WeightList mWeights;
|
WeightArray mWeights;
|
||||||
|
|
||||||
//! Vertices of the mesh
|
//! Vertices of the mesh
|
||||||
VertexList mVertices;
|
VertexArray mVertices;
|
||||||
|
|
||||||
//! Faces of the mesh
|
//! Faces of the mesh
|
||||||
FaceList mFaces;
|
FaceArray mFaces;
|
||||||
|
|
||||||
//! Name of the shader (=texture) to be assigned to the mesh
|
//! Name of the shader (=texture) to be assigned to the mesh
|
||||||
aiString mShader;
|
aiString mShader;
|
||||||
};
|
};
|
||||||
|
|
||||||
using MeshList = std::vector<MeshDesc>;
|
using MeshArray = std::vector<MeshDesc>;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Convert a quaternion to its usual representation
|
// Convert a quaternion to its usual representation
|
||||||
|
@ -269,13 +271,13 @@ public:
|
||||||
*
|
*
|
||||||
* @param mSections List of file sections (output of MD5Parser)
|
* @param mSections List of file sections (output of MD5Parser)
|
||||||
*/
|
*/
|
||||||
explicit MD5MeshParser(SectionList& mSections);
|
explicit MD5MeshParser(SectionArray& mSections);
|
||||||
|
|
||||||
//! List of all meshes
|
//! List of all meshes
|
||||||
MeshList mMeshes;
|
MeshArray mMeshes;
|
||||||
|
|
||||||
//! List of all joints
|
//! List of all joints
|
||||||
BoneList mJoints;
|
BoneArray mJoints;
|
||||||
};
|
};
|
||||||
|
|
||||||
// remove this flag if you need to the bounding box data
|
// remove this flag if you need to the bounding box data
|
||||||
|
@ -292,20 +294,20 @@ public:
|
||||||
*
|
*
|
||||||
* @param mSections List of file sections (output of MD5Parser)
|
* @param mSections List of file sections (output of MD5Parser)
|
||||||
*/
|
*/
|
||||||
explicit MD5AnimParser(SectionList& mSections);
|
explicit MD5AnimParser(SectionArray& mSections);
|
||||||
|
|
||||||
|
|
||||||
//! Output frame rate
|
//! Output frame rate
|
||||||
float fFrameRate;
|
float fFrameRate;
|
||||||
|
|
||||||
//! List of animation bones
|
//! List of animation bones
|
||||||
AnimBoneList mAnimatedBones;
|
AnimBoneArray mAnimatedBones;
|
||||||
|
|
||||||
//! List of base frames
|
//! List of base frames
|
||||||
BaseFrameList mBaseFrames;
|
BaseFrameArray mBaseFrames;
|
||||||
|
|
||||||
//! List of animation frames
|
//! List of animation frames
|
||||||
FrameList mFrames;
|
FrameArray mFrames;
|
||||||
|
|
||||||
//! Number of animated components
|
//! Number of animated components
|
||||||
unsigned int mNumAnimatedComponents;
|
unsigned int mNumAnimatedComponents;
|
||||||
|
@ -322,7 +324,7 @@ public:
|
||||||
*
|
*
|
||||||
* @param mSections List of file sections (output of MD5Parser)
|
* @param mSections List of file sections (output of MD5Parser)
|
||||||
*/
|
*/
|
||||||
explicit MD5CameraParser(SectionList& mSections);
|
explicit MD5CameraParser(SectionArray& mSections);
|
||||||
|
|
||||||
//! Output frame rate
|
//! Output frame rate
|
||||||
float fFrameRate;
|
float fFrameRate;
|
||||||
|
@ -331,7 +333,7 @@ public:
|
||||||
std::vector<unsigned int> cuts;
|
std::vector<unsigned int> cuts;
|
||||||
|
|
||||||
//! Frames
|
//! Frames
|
||||||
CameraFrameList frames;
|
CameraFrameArray frames;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
@ -375,7 +377,7 @@ public:
|
||||||
void ReportWarning (const char* warn);
|
void ReportWarning (const char* warn);
|
||||||
|
|
||||||
//! List of all sections which have been read
|
//! List of all sections which have been read
|
||||||
SectionList mSections;
|
SectionArray mSections;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool ParseSection(Section& out);
|
bool ParseSection(Section& out);
|
||||||
|
@ -388,7 +390,7 @@ private:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char* buffer;
|
char* buffer;
|
||||||
char* bufferEnd;
|
const char* bufferEnd;
|
||||||
unsigned int fileSize;
|
unsigned int fileSize;
|
||||||
unsigned int lineNumber;
|
unsigned int lineNumber;
|
||||||
};
|
};
|
||||||
|
@ -406,7 +408,7 @@ inline void MD5Parser::ReportError(const char* error) {
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
inline bool MD5Parser::SkipLine(const char* in, const char** out) {
|
inline bool MD5Parser::SkipLine(const char* in, const char** out) {
|
||||||
++lineNumber;
|
++lineNumber;
|
||||||
return Assimp::SkipLine(in ,out);
|
return Assimp::SkipLine(in, out, bufferEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
@ -450,7 +452,7 @@ inline bool MD5Parser::SkipSpacesAndLineEnd() {
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
inline bool MD5Parser::SkipSpaces() {
|
inline bool MD5Parser::SkipSpaces() {
|
||||||
return Assimp::SkipSpaces((const char**)&buffer);
|
return Assimp::SkipSpaces((const char**)&buffer, bufferEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Assimp
|
} // namespace Assimp
|
||||||
|
|
|
@ -85,7 +85,7 @@ const aiImporterDesc *NFFImporter::GetInfo() const {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
#define AI_NFF_PARSE_FLOAT(f) \
|
#define AI_NFF_PARSE_FLOAT(f) \
|
||||||
SkipSpaces(&sz); \
|
SkipSpaces(&sz, lineEnd); \
|
||||||
if (!IsLineEnd(*sz)) sz = fast_atoreal_move<ai_real>(sz, (ai_real &)f);
|
if (!IsLineEnd(*sz)) sz = fast_atoreal_move<ai_real>(sz, (ai_real &)f);
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -111,7 +111,7 @@ const aiImporterDesc *NFFImporter::GetInfo() const {
|
||||||
ASSIMP_LOG_WARN("NFF2: Unexpected EOF, can't read next token"); \
|
ASSIMP_LOG_WARN("NFF2: Unexpected EOF, can't read next token"); \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
SkipSpaces(line, &sz); \
|
SkipSpaces(line, &sz, lineEnd); \
|
||||||
} while (IsLineEnd(*sz))
|
} while (IsLineEnd(*sz))
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -148,9 +148,9 @@ void NFFImporter::LoadNFF2MaterialTable(std::vector<ShadingInfo> &output,
|
||||||
|
|
||||||
// No read the file line per line
|
// No read the file line per line
|
||||||
char line[4096];
|
char line[4096];
|
||||||
const char *sz;
|
const char *sz, *lineEnd = &line[2095]+1;
|
||||||
while (GetNextLine(buffer, line)) {
|
while (GetNextLine(buffer, line)) {
|
||||||
SkipSpaces(line, &sz);
|
SkipSpaces(line, &sz, lineEnd);
|
||||||
|
|
||||||
// 'version' defines the version of the file format
|
// 'version' defines the version of the file format
|
||||||
if (TokenMatch(sz, "version", 7)) {
|
if (TokenMatch(sz, "version", 7)) {
|
||||||
|
@ -198,18 +198,16 @@ void NFFImporter::LoadNFF2MaterialTable(std::vector<ShadingInfo> &output,
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Imports the given file into the given scene structure.
|
// Imports the given file into the given scene structure.
|
||||||
void NFFImporter::InternReadFile(const std::string &pFile,
|
void NFFImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSystem *pIOHandler) {
|
||||||
aiScene *pScene, IOSystem *pIOHandler) {
|
std::unique_ptr<IOStream> stream(pIOHandler->Open(file, "rb"));
|
||||||
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
|
if (!stream) {
|
||||||
|
throw DeadlyImportError("Failed to open NFF file ", file, ".");
|
||||||
// Check whether we can read from the file
|
}
|
||||||
if (!file)
|
|
||||||
throw DeadlyImportError("Failed to open NFF file ", pFile, ".");
|
|
||||||
|
|
||||||
// allocate storage and copy the contents of the file to a memory buffer
|
// allocate storage and copy the contents of the file to a memory buffer
|
||||||
// (terminate it with zero)
|
// (terminate it with zero)
|
||||||
std::vector<char> mBuffer2;
|
std::vector<char> mBuffer2;
|
||||||
TextFileToBuffer(file.get(), mBuffer2);
|
TextFileToBuffer(stream.get(), mBuffer2);
|
||||||
const char *buffer = &mBuffer2[0];
|
const char *buffer = &mBuffer2[0];
|
||||||
|
|
||||||
// mesh arrays - separate here to make the handling of the pointers below easier.
|
// mesh arrays - separate here to make the handling of the pointers below easier.
|
||||||
|
@ -219,8 +217,10 @@ void NFFImporter::InternReadFile(const std::string &pFile,
|
||||||
std::vector<MeshInfo> meshesLocked;
|
std::vector<MeshInfo> meshesLocked;
|
||||||
|
|
||||||
char line[4096];
|
char line[4096];
|
||||||
|
const char *lineEnd = &line[4096];
|
||||||
const char *sz;
|
const char *sz;
|
||||||
|
|
||||||
|
|
||||||
// camera parameters
|
// camera parameters
|
||||||
aiVector3D camPos, camUp(0.f, 1.f, 0.f), camLookAt(0.f, 0.f, 1.f);
|
aiVector3D camPos, camUp(0.f, 1.f, 0.f), camLookAt(0.f, 0.f, 1.f);
|
||||||
ai_real angle = 45.f;
|
ai_real angle = 45.f;
|
||||||
|
@ -265,7 +265,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
|
||||||
CommentRemover::RemoveLineComments("//", &mBuffer2[0]);
|
CommentRemover::RemoveLineComments("//", &mBuffer2[0]);
|
||||||
|
|
||||||
while (GetNextLine(buffer, line)) {
|
while (GetNextLine(buffer, line)) {
|
||||||
SkipSpaces(line, &sz);
|
SkipSpaces(line, &sz, lineEnd);
|
||||||
if (TokenMatch(sz, "version", 7)) {
|
if (TokenMatch(sz, "version", 7)) {
|
||||||
ASSIMP_LOG_INFO("NFF (Sense8) file format: ", sz);
|
ASSIMP_LOG_INFO("NFF (Sense8) file format: ", sz);
|
||||||
} else if (TokenMatch(sz, "viewpos", 7)) {
|
} else if (TokenMatch(sz, "viewpos", 7)) {
|
||||||
|
@ -295,7 +295,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
|
||||||
|
|
||||||
// material table - an external file
|
// material table - an external file
|
||||||
if (TokenMatch(sz, "mtable", 6)) {
|
if (TokenMatch(sz, "mtable", 6)) {
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, lineEnd);
|
||||||
sz3 = sz;
|
sz3 = sz;
|
||||||
while (!IsSpaceOrNewLine(*sz))
|
while (!IsSpaceOrNewLine(*sz))
|
||||||
++sz;
|
++sz;
|
||||||
|
@ -316,12 +316,12 @@ void NFFImporter::InternReadFile(const std::string &pFile,
|
||||||
std::string::size_type sepPos;
|
std::string::size_type sepPos;
|
||||||
if ((std::string::npos == (sepPos = path.find_last_of('\\')) || !sepPos) &&
|
if ((std::string::npos == (sepPos = path.find_last_of('\\')) || !sepPos) &&
|
||||||
(std::string::npos == (sepPos = path.find_last_of('/')) || !sepPos)) {
|
(std::string::npos == (sepPos = path.find_last_of('/')) || !sepPos)) {
|
||||||
sepPos = pFile.find_last_of('\\');
|
sepPos = file.find_last_of('\\');
|
||||||
if (std::string::npos == sepPos) {
|
if (std::string::npos == sepPos) {
|
||||||
sepPos = pFile.find_last_of('/');
|
sepPos = file.find_last_of('/');
|
||||||
}
|
}
|
||||||
if (std::string::npos != sepPos) {
|
if (std::string::npos != sepPos) {
|
||||||
path = pFile.substr(0, sepPos + 1) + path;
|
path = file.substr(0, sepPos + 1) + path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LoadNFF2MaterialTable(materialTable, path, pIOHandler);
|
LoadNFF2MaterialTable(materialTable, path, pIOHandler);
|
||||||
|
@ -351,7 +351,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
|
||||||
|
|
||||||
// parse all other attributes in the line
|
// parse all other attributes in the line
|
||||||
while (true) {
|
while (true) {
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, lineEnd);
|
||||||
if (IsLineEnd(*sz)) break;
|
if (IsLineEnd(*sz)) break;
|
||||||
|
|
||||||
// color definition
|
// color definition
|
||||||
|
@ -403,23 +403,20 @@ void NFFImporter::InternReadFile(const std::string &pFile,
|
||||||
tempIdx.reserve(10);
|
tempIdx.reserve(10);
|
||||||
for (unsigned int i = 0; i < num; ++i) {
|
for (unsigned int i = 0; i < num; ++i) {
|
||||||
AI_NFF2_GET_NEXT_TOKEN();
|
AI_NFF2_GET_NEXT_TOKEN();
|
||||||
SkipSpaces(line, &sz);
|
SkipSpaces(line, &sz, lineEnd);
|
||||||
unsigned int numIdx = strtoul10(sz, &sz);
|
unsigned int numIdx = strtoul10(sz, &sz);
|
||||||
|
|
||||||
// read all faces indices
|
// read all faces indices
|
||||||
if (numIdx) {
|
if (numIdx) {
|
||||||
// mesh.faces.push_back(numIdx);
|
|
||||||
// tempIdx.erase(tempIdx.begin(),tempIdx.end());
|
|
||||||
tempIdx.resize(numIdx);
|
tempIdx.resize(numIdx);
|
||||||
|
|
||||||
for (unsigned int a = 0; a < numIdx; ++a) {
|
for (unsigned int a = 0; a < numIdx; ++a) {
|
||||||
SkipSpaces(sz, &sz);
|
SkipSpaces(sz, &sz, lineEnd);
|
||||||
unsigned int m = strtoul10(sz, &sz);
|
unsigned int m = strtoul10(sz, &sz);
|
||||||
if (m >= (unsigned int)tempPositions.size()) {
|
if (m >= (unsigned int)tempPositions.size()) {
|
||||||
ASSIMP_LOG_ERROR("NFF2: Vertex index overflow");
|
ASSIMP_LOG_ERROR("NFF2: Vertex index overflow");
|
||||||
m = 0;
|
m = 0;
|
||||||
}
|
}
|
||||||
// mesh.vertices.push_back (tempPositions[idx]);
|
|
||||||
tempIdx[a] = m;
|
tempIdx[a] = m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -432,7 +429,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
|
||||||
shader.color = aiColor3D(1.f, 1.f, 1.f);
|
shader.color = aiColor3D(1.f, 1.f, 1.f);
|
||||||
aiColor4D c = aiColor4D(1.f, 1.f, 1.f, 1.f);
|
aiColor4D c = aiColor4D(1.f, 1.f, 1.f, 1.f);
|
||||||
while (true) {
|
while (true) {
|
||||||
SkipSpaces(sz, &sz);
|
SkipSpaces(sz, &sz, lineEnd);
|
||||||
if (IsLineEnd(*sz)) break;
|
if (IsLineEnd(*sz)) break;
|
||||||
|
|
||||||
// per-polygon colors
|
// per-polygon colors
|
||||||
|
@ -510,7 +507,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
|
||||||
|
|
||||||
// Material ID?
|
// Material ID?
|
||||||
else if (!materialTable.empty() && TokenMatch(sz, "matid", 5)) {
|
else if (!materialTable.empty() && TokenMatch(sz, "matid", 5)) {
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, lineEnd);
|
||||||
matIdx = strtoul10(sz, &sz);
|
matIdx = strtoul10(sz, &sz);
|
||||||
if (matIdx >= materialTable.size()) {
|
if (matIdx >= materialTable.size()) {
|
||||||
ASSIMP_LOG_ERROR("NFF2: Material index overflow.");
|
ASSIMP_LOG_ERROR("NFF2: Material index overflow.");
|
||||||
|
@ -527,7 +524,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
|
||||||
shader.specular = mat.specular;
|
shader.specular = mat.specular;
|
||||||
shader.shininess = mat.shininess;
|
shader.shininess = mat.shininess;
|
||||||
} else
|
} else
|
||||||
SkipToken(sz);
|
SkipToken(sz, lineEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// search the list of all shaders we have for this object whether
|
// search the list of all shaders we have for this object whether
|
||||||
|
@ -649,7 +646,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
|
||||||
sz = &line[1];
|
sz = &line[1];
|
||||||
out = currentMesh;
|
out = currentMesh;
|
||||||
}
|
}
|
||||||
SkipSpaces(sz, &sz);
|
SkipSpaces(sz, &sz, lineEnd);
|
||||||
unsigned int m = strtoul10(sz);
|
unsigned int m = strtoul10(sz);
|
||||||
|
|
||||||
// ---- flip the face order
|
// ---- flip the face order
|
||||||
|
@ -677,13 +674,13 @@ void NFFImporter::InternReadFile(const std::string &pFile,
|
||||||
}
|
}
|
||||||
if (out == currentMeshWithUVCoords) {
|
if (out == currentMeshWithUVCoords) {
|
||||||
// FIX: in one test file this wraps over multiple lines
|
// FIX: in one test file this wraps over multiple lines
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, lineEnd);
|
||||||
if (IsLineEnd(*sz)) {
|
if (IsLineEnd(*sz)) {
|
||||||
GetNextLine(buffer, line);
|
GetNextLine(buffer, line);
|
||||||
sz = line;
|
sz = line;
|
||||||
}
|
}
|
||||||
AI_NFF_PARSE_FLOAT(v.x);
|
AI_NFF_PARSE_FLOAT(v.x);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, lineEnd);
|
||||||
if (IsLineEnd(*sz)) {
|
if (IsLineEnd(*sz)) {
|
||||||
GetNextLine(buffer, line);
|
GetNextLine(buffer, line);
|
||||||
sz = line;
|
sz = line;
|
||||||
|
@ -717,7 +714,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
|
||||||
// if the next one is NOT a number we assume it is a texture file name
|
// if the next one is NOT a number we assume it is a texture file name
|
||||||
// this feature is used by some NFF files on the internet and it has
|
// this feature is used by some NFF files on the internet and it has
|
||||||
// been implemented as it can be really useful
|
// been implemented as it can be really useful
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, lineEnd);
|
||||||
if (!IsNumeric(*sz)) {
|
if (!IsNumeric(*sz)) {
|
||||||
// TODO: Support full file names with spaces and quotation marks ...
|
// TODO: Support full file names with spaces and quotation marks ...
|
||||||
const char *p = sz;
|
const char *p = sz;
|
||||||
|
@ -731,10 +728,8 @@ void NFFImporter::InternReadFile(const std::string &pFile,
|
||||||
} else {
|
} else {
|
||||||
AI_NFF_PARSE_FLOAT(s.ambient); // optional
|
AI_NFF_PARSE_FLOAT(s.ambient); // optional
|
||||||
}
|
}
|
||||||
}
|
} else if (TokenMatch(sz, "shader", 6)) { // 'shader' - other way to specify a texture
|
||||||
// 'shader' - other way to specify a texture
|
SkipSpaces(&sz, lineEnd);
|
||||||
else if (TokenMatch(sz, "shader", 6)) {
|
|
||||||
SkipSpaces(&sz);
|
|
||||||
const char *old = sz;
|
const char *old = sz;
|
||||||
while (!IsSpaceOrNewLine(*sz))
|
while (!IsSpaceOrNewLine(*sz))
|
||||||
++sz;
|
++sz;
|
||||||
|
@ -889,7 +884,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
|
||||||
}
|
}
|
||||||
// 'tess' - tessellation
|
// 'tess' - tessellation
|
||||||
else if (TokenMatch(sz, "tess", 4)) {
|
else if (TokenMatch(sz, "tess", 4)) {
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, lineEnd);
|
||||||
iTesselation = strtoul10(sz);
|
iTesselation = strtoul10(sz);
|
||||||
}
|
}
|
||||||
// 'from' - camera position
|
// 'from' - camera position
|
||||||
|
@ -929,7 +924,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
|
||||||
// '' - comment
|
// '' - comment
|
||||||
else if ('#' == line[0]) {
|
else if ('#' == line[0]) {
|
||||||
const char *space;
|
const char *space;
|
||||||
SkipSpaces(&line[1], &space);
|
SkipSpaces(&line[1], &space, lineEnd);
|
||||||
if (!IsLineEnd(*space)) {
|
if (!IsLineEnd(*space)) {
|
||||||
ASSIMP_LOG_INFO(space);
|
ASSIMP_LOG_INFO(space);
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,10 +84,10 @@ const aiImporterDesc *OFFImporter::GetInfo() const {
|
||||||
|
|
||||||
// skip blank space, lines and comments
|
// skip blank space, lines and comments
|
||||||
static void NextToken(const char **car, const char *end) {
|
static void NextToken(const char **car, const char *end) {
|
||||||
SkipSpacesAndLineEnd(car);
|
SkipSpacesAndLineEnd(car, end);
|
||||||
while (*car < end && (**car == '#' || **car == '\n' || **car == '\r')) {
|
while (*car < end && (**car == '#' || **car == '\n' || **car == '\r')) {
|
||||||
SkipLine(car);
|
SkipLine(car, end);
|
||||||
SkipSpacesAndLineEnd(car);
|
SkipSpacesAndLineEnd(car, end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,6 +195,7 @@ void OFFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
char line[4096];
|
char line[4096];
|
||||||
buffer = car;
|
buffer = car;
|
||||||
const char *sz = car;
|
const char *sz = car;
|
||||||
|
const char *lineEnd = &line[4096];
|
||||||
|
|
||||||
// now read all vertex lines
|
// now read all vertex lines
|
||||||
for (unsigned int i = 0; i < numVertices; ++i) {
|
for (unsigned int i = 0; i < numVertices; ++i) {
|
||||||
|
@ -210,13 +211,13 @@ void OFFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
|
|
||||||
// stop at dimensions: this allows loading 1D or 2D coordinate vertices
|
// stop at dimensions: this allows loading 1D or 2D coordinate vertices
|
||||||
for (unsigned int dim = 0; dim < dimensions; ++dim) {
|
for (unsigned int dim = 0; dim < dimensions; ++dim) {
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, lineEnd);
|
||||||
sz = fast_atoreal_move<ai_real>(sz, *vec[dim]);
|
sz = fast_atoreal_move<ai_real>(sz, *vec[dim]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if has homogeneous coordinate, divide others by this one
|
// if has homogeneous coordinate, divide others by this one
|
||||||
if (hasHomogenous) {
|
if (hasHomogenous) {
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, lineEnd);
|
||||||
ai_real w = 1.;
|
ai_real w = 1.;
|
||||||
sz = fast_atoreal_move<ai_real>(sz, w);
|
sz = fast_atoreal_move<ai_real>(sz, w);
|
||||||
for (unsigned int dim = 0; dim < dimensions; ++dim) {
|
for (unsigned int dim = 0; dim < dimensions; ++dim) {
|
||||||
|
@ -227,11 +228,11 @@ void OFFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
// read optional normals
|
// read optional normals
|
||||||
if (hasNormals) {
|
if (hasNormals) {
|
||||||
aiVector3D &n = mesh->mNormals[i];
|
aiVector3D &n = mesh->mNormals[i];
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, lineEnd);
|
||||||
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)n.x);
|
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)n.x);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, lineEnd);
|
||||||
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)n.y);
|
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)n.y);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, lineEnd);
|
||||||
fast_atoreal_move<ai_real>(sz, (ai_real &)n.z);
|
fast_atoreal_move<ai_real>(sz, (ai_real &)n.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,22 +242,22 @@ void OFFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
// in theory should be testing type !
|
// in theory should be testing type !
|
||||||
if (hasColors) {
|
if (hasColors) {
|
||||||
aiColor4D &c = mesh->mColors[0][i];
|
aiColor4D &c = mesh->mColors[0][i];
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, lineEnd);
|
||||||
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)c.r);
|
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)c.r);
|
||||||
if (*sz != '#' && *sz != '\n' && *sz != '\r') {
|
if (*sz != '#' && *sz != '\n' && *sz != '\r') {
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, lineEnd);
|
||||||
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)c.g);
|
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)c.g);
|
||||||
} else {
|
} else {
|
||||||
c.g = 0.;
|
c.g = 0.;
|
||||||
}
|
}
|
||||||
if (*sz != '#' && *sz != '\n' && *sz != '\r') {
|
if (*sz != '#' && *sz != '\n' && *sz != '\r') {
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, lineEnd);
|
||||||
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)c.b);
|
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)c.b);
|
||||||
} else {
|
} else {
|
||||||
c.b = 0.;
|
c.b = 0.;
|
||||||
}
|
}
|
||||||
if (*sz != '#' && *sz != '\n' && *sz != '\r') {
|
if (*sz != '#' && *sz != '\n' && *sz != '\r') {
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, lineEnd);
|
||||||
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)c.a);
|
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)c.a);
|
||||||
} else {
|
} else {
|
||||||
c.a = 1.;
|
c.a = 1.;
|
||||||
|
@ -264,9 +265,9 @@ void OFFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
}
|
}
|
||||||
if (hasTexCoord) {
|
if (hasTexCoord) {
|
||||||
aiVector3D &t = mesh->mTextureCoords[0][i];
|
aiVector3D &t = mesh->mTextureCoords[0][i];
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, lineEnd);
|
||||||
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)t.x);
|
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)t.x);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, lineEnd);
|
||||||
fast_atoreal_move<ai_real>(sz, (ai_real &)t.y);
|
fast_atoreal_move<ai_real>(sz, (ai_real &)t.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -280,7 +281,7 @@ void OFFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
}
|
}
|
||||||
unsigned int idx;
|
unsigned int idx;
|
||||||
sz = line;
|
sz = line;
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, lineEnd);
|
||||||
idx = strtoul10(sz, &sz);
|
idx = strtoul10(sz, &sz);
|
||||||
if (!idx || idx > 9) {
|
if (!idx || idx > 9) {
|
||||||
ASSIMP_LOG_ERROR("OFF: Faces with zero indices aren't allowed");
|
ASSIMP_LOG_ERROR("OFF: Faces with zero indices aren't allowed");
|
||||||
|
@ -291,7 +292,7 @@ void OFFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
faces->mNumIndices = idx;
|
faces->mNumIndices = idx;
|
||||||
faces->mIndices = new unsigned int[faces->mNumIndices];
|
faces->mIndices = new unsigned int[faces->mNumIndices];
|
||||||
for (unsigned int m = 0; m < faces->mNumIndices; ++m) {
|
for (unsigned int m = 0; m < faces->mNumIndices; ++m) {
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, lineEnd);
|
||||||
idx = strtoul10(sz, &sz);
|
idx = strtoul10(sz, &sz);
|
||||||
if (idx >= numVertices) {
|
if (idx >= numVertices) {
|
||||||
ASSIMP_LOG_ERROR("OFF: Vertex index is out of range");
|
ASSIMP_LOG_ERROR("OFF: Vertex index is out of range");
|
||||||
|
|
|
@ -64,6 +64,7 @@ ObjFileParser::ObjFileParser() :
|
||||||
m_pModel(nullptr),
|
m_pModel(nullptr),
|
||||||
m_uiLine(0),
|
m_uiLine(0),
|
||||||
m_buffer(),
|
m_buffer(),
|
||||||
|
mEnd(&m_buffer[Buffersize]),
|
||||||
m_pIO(nullptr),
|
m_pIO(nullptr),
|
||||||
m_progress(nullptr),
|
m_progress(nullptr),
|
||||||
m_originalObjFileName() {
|
m_originalObjFileName() {
|
||||||
|
@ -97,8 +98,6 @@ ObjFileParser::ObjFileParser(IOStreamBuffer<char> &streamBuffer, const std::stri
|
||||||
parseFile(streamBuffer);
|
parseFile(streamBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjFileParser::~ObjFileParser() = default;
|
|
||||||
|
|
||||||
void ObjFileParser::setBuffer(std::vector<char> &buffer) {
|
void ObjFileParser::setBuffer(std::vector<char> &buffer) {
|
||||||
m_DataIt = buffer.begin();
|
m_DataIt = buffer.begin();
|
||||||
m_DataItEnd = buffer.end();
|
m_DataItEnd = buffer.end();
|
||||||
|
@ -121,6 +120,7 @@ void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
|
||||||
while (streamBuffer.getNextDataLine(buffer, '\\')) {
|
while (streamBuffer.getNextDataLine(buffer, '\\')) {
|
||||||
m_DataIt = buffer.begin();
|
m_DataIt = buffer.begin();
|
||||||
m_DataItEnd = buffer.end();
|
m_DataItEnd = buffer.end();
|
||||||
|
mEnd = &buffer[buffer.size() - 1] + 1;
|
||||||
|
|
||||||
// Handle progress reporting
|
// Handle progress reporting
|
||||||
const size_t filePos(streamBuffer.getFilePos());
|
const size_t filePos(streamBuffer.getFilePos());
|
||||||
|
@ -130,7 +130,7 @@ void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
|
||||||
m_progress->UpdateFileRead(processed, progressTotal);
|
m_progress->UpdateFileRead(processed, progressTotal);
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle cstype section end (http://paulbourke.net/dataformats/obj/)
|
// handle c-stype section end (http://paulbourke.net/dataformats/obj/)
|
||||||
if (insideCstype) {
|
if (insideCstype) {
|
||||||
switch (*m_DataIt) {
|
switch (*m_DataIt) {
|
||||||
case 'e': {
|
case 'e': {
|
||||||
|
@ -301,18 +301,19 @@ size_t ObjFileParser::getNumComponentsInDataDefinition() {
|
||||||
} else if (IsLineEnd(*tmp)) {
|
} else if (IsLineEnd(*tmp)) {
|
||||||
end_of_definition = true;
|
end_of_definition = true;
|
||||||
}
|
}
|
||||||
if (!SkipSpaces(&tmp)) {
|
if (!SkipSpaces(&tmp, mEnd)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const bool isNum(IsNumeric(*tmp) || isNanOrInf(tmp));
|
const bool isNum(IsNumeric(*tmp) || isNanOrInf(tmp));
|
||||||
SkipToken(tmp);
|
SkipToken(tmp, mEnd);
|
||||||
if (isNum) {
|
if (isNum) {
|
||||||
++numComponents;
|
++numComponents;
|
||||||
}
|
}
|
||||||
if (!SkipSpaces(&tmp)) {
|
if (!SkipSpaces(&tmp, mEnd)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return numComponents;
|
return numComponents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,8 +488,9 @@ void ObjFileParser::getFace(aiPrimitiveType type) {
|
||||||
++iStep;
|
++iStep;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iPos == 1 && !vt && vn)
|
if (iPos == 1 && !vt && vn) {
|
||||||
iPos = 2; // skip texture coords for normals if there are no tex coords
|
iPos = 2; // skip texture coords for normals if there are no tex coords
|
||||||
|
}
|
||||||
|
|
||||||
if (iVal > 0) {
|
if (iVal > 0) {
|
||||||
// Store parsed index
|
// Store parsed index
|
||||||
|
@ -577,8 +579,9 @@ void ObjFileParser::getMaterialDesc() {
|
||||||
// Get name
|
// Get name
|
||||||
std::string strName(pStart, &(*m_DataIt));
|
std::string strName(pStart, &(*m_DataIt));
|
||||||
strName = trim_whitespaces(strName);
|
strName = trim_whitespaces(strName);
|
||||||
if (strName.empty())
|
if (strName.empty()) {
|
||||||
skip = true;
|
skip = true;
|
||||||
|
}
|
||||||
|
|
||||||
// If the current mesh has the same material, we simply ignore that 'usemtl' command
|
// If the current mesh has the same material, we simply ignore that 'usemtl' command
|
||||||
// There is no need to create another object or even mesh here
|
// There is no need to create another object or even mesh here
|
||||||
|
|
|
@ -41,6 +41,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef OBJ_FILEPARSER_H_INC
|
#ifndef OBJ_FILEPARSER_H_INC
|
||||||
#define OBJ_FILEPARSER_H_INC
|
#define OBJ_FILEPARSER_H_INC
|
||||||
|
|
||||||
|
#include "ObjFileData.h"
|
||||||
|
|
||||||
#include <assimp/IOStreamBuffer.h>
|
#include <assimp/IOStreamBuffer.h>
|
||||||
#include <assimp/material.h>
|
#include <assimp/material.h>
|
||||||
#include <assimp/mesh.h>
|
#include <assimp/mesh.h>
|
||||||
|
@ -53,14 +55,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
namespace ObjFile {
|
|
||||||
struct Model;
|
|
||||||
struct Object;
|
|
||||||
struct Material;
|
|
||||||
struct Point3;
|
|
||||||
struct Point2;
|
|
||||||
} // namespace ObjFile
|
|
||||||
|
|
||||||
class ObjFileImporter;
|
class ObjFileImporter;
|
||||||
class IOSystem;
|
class IOSystem;
|
||||||
class ProgressHandler;
|
class ProgressHandler;
|
||||||
|
@ -79,7 +73,7 @@ public:
|
||||||
/// @brief Constructor with data array.
|
/// @brief Constructor with data array.
|
||||||
ObjFileParser(IOStreamBuffer<char> &streamBuffer, const std::string &modelName, IOSystem *io, ProgressHandler *progress, const std::string &originalObjFileName);
|
ObjFileParser(IOStreamBuffer<char> &streamBuffer, const std::string &modelName, IOSystem *io, ProgressHandler *progress, const std::string &originalObjFileName);
|
||||||
/// @brief Destructor
|
/// @brief Destructor
|
||||||
~ObjFileParser();
|
~ObjFileParser() = default;
|
||||||
/// @brief If you want to load in-core data.
|
/// @brief If you want to load in-core data.
|
||||||
void setBuffer(std::vector<char> &buffer);
|
void setBuffer(std::vector<char> &buffer);
|
||||||
/// @brief Model getter.
|
/// @brief Model getter.
|
||||||
|
@ -149,6 +143,7 @@ private:
|
||||||
unsigned int m_uiLine;
|
unsigned int m_uiLine;
|
||||||
//! Helper buffer
|
//! Helper buffer
|
||||||
char m_buffer[Buffersize];
|
char m_buffer[Buffersize];
|
||||||
|
const char *mEnd;
|
||||||
/// Pointer to IO system instance.
|
/// Pointer to IO system instance.
|
||||||
IOSystem *m_pIO;
|
IOSystem *m_pIO;
|
||||||
//! Pointer to progress handler
|
//! Pointer to progress handler
|
||||||
|
|
|
@ -159,7 +159,8 @@ void PLYImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
mBuffer = (unsigned char *)&mBuffer2[0];
|
mBuffer = (unsigned char *)&mBuffer2[0];
|
||||||
|
|
||||||
char *szMe = (char *)&this->mBuffer[0];
|
char *szMe = (char *)&this->mBuffer[0];
|
||||||
SkipSpacesAndLineEnd(szMe, (const char **)&szMe);
|
const char *end = &mBuffer2[0] + mBuffer2.size();
|
||||||
|
SkipSpacesAndLineEnd(szMe, (const char **)&szMe, end);
|
||||||
|
|
||||||
// determine the format of the file data and construct the aiMesh
|
// determine the format of the file data and construct the aiMesh
|
||||||
PLY::DOM sPlyDom;
|
PLY::DOM sPlyDom;
|
||||||
|
@ -167,7 +168,7 @@ void PLYImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
|
|
||||||
if (TokenMatch(szMe, "format", 6)) {
|
if (TokenMatch(szMe, "format", 6)) {
|
||||||
if (TokenMatch(szMe, "ascii", 5)) {
|
if (TokenMatch(szMe, "ascii", 5)) {
|
||||||
SkipLine(szMe, (const char **)&szMe);
|
SkipLine(szMe, (const char **)&szMe, end);
|
||||||
if (!PLY::DOM::ParseInstance(streamedBuffer, &sPlyDom, this)) {
|
if (!PLY::DOM::ParseInstance(streamedBuffer, &sPlyDom, this)) {
|
||||||
if (mGeneratedMesh != nullptr) {
|
if (mGeneratedMesh != nullptr) {
|
||||||
delete (mGeneratedMesh);
|
delete (mGeneratedMesh);
|
||||||
|
|
|
@ -50,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <assimp/DefaultLogger.hpp>
|
#include <assimp/DefaultLogger.hpp>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
using namespace Assimp;
|
namespace Assimp {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
PLY::EDataType PLY::Property::ParseDataType(std::vector<char> &buffer) {
|
PLY::EDataType PLY::Property::ParseDataType(std::vector<char> &buffer) {
|
||||||
|
@ -321,13 +321,13 @@ bool PLY::Element::ParseElement(IOStreamBuffer<char> &streamBuffer, std::vector<
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
bool PLY::DOM::SkipSpaces(std::vector<char> &buffer) {
|
bool PLY::DOM::SkipSpaces(std::vector<char> &buffer) {
|
||||||
const char *pCur = buffer.empty() ? nullptr : (char *)&buffer[0];
|
const char *pCur = buffer.empty() ? nullptr : (char *)&buffer[0];
|
||||||
|
const char *end = pCur + buffer.size();
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
if (pCur) {
|
if (pCur) {
|
||||||
const char *szCur = pCur;
|
const char *szCur = pCur;
|
||||||
ret = Assimp::SkipSpaces(pCur, &pCur);
|
ret = Assimp::SkipSpaces(pCur, &pCur, end);
|
||||||
|
|
||||||
uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
|
uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
|
||||||
buffer.erase(buffer.begin(), buffer.begin() + iDiff);
|
buffer.erase(buffer.begin(), buffer.begin() + iDiff);
|
||||||
|
@ -339,10 +339,11 @@ bool PLY::DOM::SkipSpaces(std::vector<char> &buffer) {
|
||||||
|
|
||||||
bool PLY::DOM::SkipLine(std::vector<char> &buffer) {
|
bool PLY::DOM::SkipLine(std::vector<char> &buffer) {
|
||||||
const char *pCur = buffer.empty() ? nullptr : (char *)&buffer[0];
|
const char *pCur = buffer.empty() ? nullptr : (char *)&buffer[0];
|
||||||
|
const char *end = pCur + buffer.size();
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
if (pCur) {
|
if (pCur) {
|
||||||
const char *szCur = pCur;
|
const char *szCur = pCur;
|
||||||
ret = Assimp::SkipLine(pCur, &pCur);
|
ret = Assimp::SkipLine(pCur, &pCur, end);
|
||||||
|
|
||||||
uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
|
uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
|
||||||
buffer.erase(buffer.begin(), buffer.begin() + iDiff);
|
buffer.erase(buffer.begin(), buffer.begin() + iDiff);
|
||||||
|
@ -369,10 +370,11 @@ bool PLY::DOM::TokenMatch(std::vector<char> &buffer, const char *token, unsigned
|
||||||
|
|
||||||
bool PLY::DOM::SkipSpacesAndLineEnd(std::vector<char> &buffer) {
|
bool PLY::DOM::SkipSpacesAndLineEnd(std::vector<char> &buffer) {
|
||||||
const char *pCur = buffer.empty() ? nullptr : (char *)&buffer[0];
|
const char *pCur = buffer.empty() ? nullptr : (char *)&buffer[0];
|
||||||
|
const char *end = pCur + buffer.size();
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
if (pCur) {
|
if (pCur) {
|
||||||
const char *szCur = pCur;
|
const char *szCur = pCur;
|
||||||
ret = Assimp::SkipSpacesAndLineEnd(pCur, &pCur);
|
ret = Assimp::SkipSpacesAndLineEnd(pCur, &pCur, end);
|
||||||
|
|
||||||
uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
|
uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
|
||||||
buffer.erase(buffer.begin(), buffer.begin() + iDiff);
|
buffer.erase(buffer.begin(), buffer.begin() + iDiff);
|
||||||
|
@ -558,13 +560,14 @@ bool PLY::ElementInstanceList::ParseInstanceList(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const char *pCur = (const char *)&buffer[0];
|
const char *pCur = (const char *)&buffer[0];
|
||||||
|
const char *end = pCur + buffer.size();
|
||||||
// be sure to have enough storage
|
// be sure to have enough storage
|
||||||
for (unsigned int i = 0; i < pcElement->NumOccur; ++i) {
|
for (unsigned int i = 0; i < pcElement->NumOccur; ++i) {
|
||||||
if (p_pcOut)
|
if (p_pcOut)
|
||||||
PLY::ElementInstance::ParseInstance(pCur, pcElement, &p_pcOut->alInstances[i]);
|
PLY::ElementInstance::ParseInstance(pCur, end, pcElement, &p_pcOut->alInstances[i]);
|
||||||
else {
|
else {
|
||||||
ElementInstance elt;
|
ElementInstance elt;
|
||||||
PLY::ElementInstance::ParseInstance(pCur, pcElement, &elt);
|
PLY::ElementInstance::ParseInstance(pCur, end, pcElement, &elt);
|
||||||
|
|
||||||
// Create vertex or face
|
// Create vertex or face
|
||||||
if (pcElement->eSemantic == EEST_Vertex) {
|
if (pcElement->eSemantic == EEST_Vertex) {
|
||||||
|
@ -626,7 +629,7 @@ bool PLY::ElementInstanceList::ParseInstanceListBinary(
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool PLY::ElementInstance::ParseInstance(const char *&pCur,
|
bool PLY::ElementInstance::ParseInstance(const char *&pCur, const char *end,
|
||||||
const PLY::Element *pcElement,
|
const PLY::Element *pcElement,
|
||||||
PLY::ElementInstance *p_pcOut) {
|
PLY::ElementInstance *p_pcOut) {
|
||||||
ai_assert(nullptr != pcElement);
|
ai_assert(nullptr != pcElement);
|
||||||
|
@ -638,7 +641,7 @@ bool PLY::ElementInstance::ParseInstance(const char *&pCur,
|
||||||
std::vector<PLY::PropertyInstance>::iterator i = p_pcOut->alProperties.begin();
|
std::vector<PLY::PropertyInstance>::iterator i = p_pcOut->alProperties.begin();
|
||||||
std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
|
std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
|
||||||
for (; i != p_pcOut->alProperties.end(); ++i, ++a) {
|
for (; i != p_pcOut->alProperties.end(); ++i, ++a) {
|
||||||
if (!(PLY::PropertyInstance::ParseInstance(pCur, &(*a), &(*i)))) {
|
if (!(PLY::PropertyInstance::ParseInstance(pCur, end, &(*a), &(*i)))) {
|
||||||
ASSIMP_LOG_WARN("Unable to parse property instance. "
|
ASSIMP_LOG_WARN("Unable to parse property instance. "
|
||||||
"Skipping this element instance");
|
"Skipping this element instance");
|
||||||
|
|
||||||
|
@ -678,13 +681,13 @@ bool PLY::ElementInstance::ParseInstanceBinary(
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool PLY::PropertyInstance::ParseInstance(const char *&pCur,
|
bool PLY::PropertyInstance::ParseInstance(const char *&pCur, const char *end, const PLY::Property *prop,
|
||||||
const PLY::Property *prop, PLY::PropertyInstance *p_pcOut) {
|
PLY::PropertyInstance *p_pcOut) {
|
||||||
ai_assert(nullptr != prop);
|
ai_assert(nullptr != prop);
|
||||||
ai_assert(nullptr != p_pcOut);
|
ai_assert(nullptr != p_pcOut);
|
||||||
|
|
||||||
// skip spaces at the beginning
|
// skip spaces at the beginning
|
||||||
if (!SkipSpaces(&pCur)) {
|
if (!SkipSpaces(&pCur, end)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -699,7 +702,7 @@ bool PLY::PropertyInstance::ParseInstance(const char *&pCur,
|
||||||
// parse all list elements
|
// parse all list elements
|
||||||
p_pcOut->avList.resize(iNum);
|
p_pcOut->avList.resize(iNum);
|
||||||
for (unsigned int i = 0; i < iNum; ++i) {
|
for (unsigned int i = 0; i < iNum; ++i) {
|
||||||
if (!SkipSpaces(&pCur))
|
if (!SkipSpaces(&pCur, end))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
PLY::PropertyInstance::ParseValue(pCur, prop->eType, &p_pcOut->avList[i]);
|
PLY::PropertyInstance::ParseValue(pCur, prop->eType, &p_pcOut->avList[i]);
|
||||||
|
@ -711,7 +714,7 @@ bool PLY::PropertyInstance::ParseInstance(const char *&pCur,
|
||||||
PLY::PropertyInstance::ParseValue(pCur, prop->eType, &v);
|
PLY::PropertyInstance::ParseValue(pCur, prop->eType, &v);
|
||||||
p_pcOut->avList.push_back(v);
|
p_pcOut->avList.push_back(v);
|
||||||
}
|
}
|
||||||
SkipSpacesAndLineEnd(&pCur);
|
SkipSpacesAndLineEnd(&pCur, end);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -958,4 +961,6 @@ bool PLY::PropertyInstance::ParseValueBinary(IOStreamBuffer<char> &streamBuffer,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace Assimp
|
||||||
|
|
||||||
#endif // !! ASSIMP_BUILD_NO_PLY_IMPORTER
|
#endif // !! ASSIMP_BUILD_NO_PLY_IMPORTER
|
||||||
|
|
|
@ -324,7 +324,7 @@ public:
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
//! Parse a property instance
|
//! Parse a property instance
|
||||||
static bool ParseInstance(const char* &pCur,
|
static bool ParseInstance(const char* &pCur, const char *end,
|
||||||
const Property* prop, PropertyInstance* p_pcOut);
|
const Property* prop, PropertyInstance* p_pcOut);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
@ -364,7 +364,7 @@ public:
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
//! Parse an element instance
|
//! Parse an element instance
|
||||||
static bool ParseInstance(const char* &pCur,
|
static bool ParseInstance(const char *&pCur, const char *end,
|
||||||
const Element* pcElement, ElementInstance* p_pcOut);
|
const Element* pcElement, ElementInstance* p_pcOut);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
|
@ -104,11 +104,12 @@ void RAWImporter::InternReadFile(const std::string &pFile,
|
||||||
|
|
||||||
// now read all lines
|
// now read all lines
|
||||||
char line[4096];
|
char line[4096];
|
||||||
|
const char *end = &line[4096];
|
||||||
while (GetNextLine(buffer, line)) {
|
while (GetNextLine(buffer, line)) {
|
||||||
// if the line starts with a non-numeric identifier, it marks
|
// if the line starts with a non-numeric identifier, it marks
|
||||||
// the beginning of a new group
|
// the beginning of a new group
|
||||||
const char *sz = line;
|
const char *sz = line;
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, end);
|
||||||
if (IsLineEnd(*sz)) continue;
|
if (IsLineEnd(*sz)) continue;
|
||||||
if (!IsNumeric(*sz)) {
|
if (!IsNumeric(*sz)) {
|
||||||
const char *sz2 = sz;
|
const char *sz2 = sz;
|
||||||
|
@ -117,8 +118,8 @@ void RAWImporter::InternReadFile(const std::string &pFile,
|
||||||
const unsigned int length = (unsigned int)(sz2 - sz);
|
const unsigned int length = (unsigned int)(sz2 - sz);
|
||||||
|
|
||||||
// find an existing group with this name
|
// find an existing group with this name
|
||||||
for (std::vector<GroupInformation>::iterator it = outGroups.begin(), end = outGroups.end();
|
for (std::vector<GroupInformation>::iterator it = outGroups.begin(), endIt = outGroups.end();
|
||||||
it != end; ++it) {
|
it != endIt; ++it) {
|
||||||
if (length == (*it).name.length() && !::strcmp(sz, (*it).name.c_str())) {
|
if (length == (*it).name.length() && !::strcmp(sz, (*it).name.c_str())) {
|
||||||
curGroup = it;
|
curGroup = it;
|
||||||
sz2 = nullptr;
|
sz2 = nullptr;
|
||||||
|
@ -134,7 +135,7 @@ void RAWImporter::InternReadFile(const std::string &pFile,
|
||||||
float data[12];
|
float data[12];
|
||||||
unsigned int num;
|
unsigned int num;
|
||||||
for (num = 0; num < 12; ++num) {
|
for (num = 0; num < 12; ++num) {
|
||||||
if (!SkipSpaces(&sz) || !IsNumeric(*sz)) break;
|
if (!SkipSpaces(&sz, end) || !IsNumeric(*sz)) break;
|
||||||
sz = fast_atoreal_move<float>(sz, data[num]);
|
sz = fast_atoreal_move<float>(sz, data[num]);
|
||||||
}
|
}
|
||||||
if (num != 12 && num != 9) {
|
if (num != 12 && num != 9) {
|
||||||
|
|
|
@ -83,6 +83,8 @@ static constexpr aiImporterDesc desc = {
|
||||||
// Constructor to be privately used by Importer
|
// Constructor to be privately used by Importer
|
||||||
SMDImporter::SMDImporter() :
|
SMDImporter::SMDImporter() :
|
||||||
configFrameID(),
|
configFrameID(),
|
||||||
|
mBuffer(),
|
||||||
|
mEnd(nullptr),
|
||||||
pScene(nullptr),
|
pScene(nullptr),
|
||||||
iFileSize( 0 ),
|
iFileSize( 0 ),
|
||||||
iSmallestFrame( INT_MAX ),
|
iSmallestFrame( INT_MAX ),
|
||||||
|
@ -92,9 +94,6 @@ SMDImporter::SMDImporter() :
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// Destructor, private as well
|
|
||||||
SMDImporter::~SMDImporter() = default;
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Returns whether the class can handle the format of the given file.
|
// Returns whether the class can handle the format of the given file.
|
||||||
|
@ -632,13 +631,13 @@ void SMDImporter::ParseFile() {
|
||||||
|
|
||||||
// read line per line ...
|
// read line per line ...
|
||||||
for ( ;; ) {
|
for ( ;; ) {
|
||||||
if(!SkipSpacesAndLineEnd(szCurrent,&szCurrent)) {
|
if(!SkipSpacesAndLineEnd(szCurrent,&szCurrent, mEnd)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// "version <n> \n", <n> should be 1 for hl and hl2 SMD files
|
// "version <n> \n", <n> should be 1 for hl and hl2 SMD files
|
||||||
if (TokenMatch(szCurrent,"version",7)) {
|
if (TokenMatch(szCurrent,"version",7)) {
|
||||||
if(!SkipSpaces(szCurrent,&szCurrent)) break;
|
if(!SkipSpaces(szCurrent,&szCurrent, mEnd)) break;
|
||||||
if (1 != strtoul10(szCurrent,&szCurrent)) {
|
if (1 != strtoul10(szCurrent,&szCurrent)) {
|
||||||
ASSIMP_LOG_WARN("SMD.version is not 1. This "
|
ASSIMP_LOG_WARN("SMD.version is not 1. This "
|
||||||
"file format is not known. Continuing happily ...");
|
"file format is not known. Continuing happily ...");
|
||||||
|
@ -647,26 +646,26 @@ void SMDImporter::ParseFile() {
|
||||||
}
|
}
|
||||||
// "nodes\n" - Starts the node section
|
// "nodes\n" - Starts the node section
|
||||||
if (TokenMatch(szCurrent,"nodes",5)) {
|
if (TokenMatch(szCurrent,"nodes",5)) {
|
||||||
ParseNodesSection(szCurrent,&szCurrent);
|
ParseNodesSection(szCurrent, &szCurrent, mEnd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// "triangles\n" - Starts the triangle section
|
// "triangles\n" - Starts the triangle section
|
||||||
if (TokenMatch(szCurrent,"triangles",9)) {
|
if (TokenMatch(szCurrent,"triangles",9)) {
|
||||||
ParseTrianglesSection(szCurrent,&szCurrent);
|
ParseTrianglesSection(szCurrent, &szCurrent, mEnd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// "vertexanimation\n" - Starts the vertex animation section
|
// "vertexanimation\n" - Starts the vertex animation section
|
||||||
if (TokenMatch(szCurrent,"vertexanimation",15)) {
|
if (TokenMatch(szCurrent,"vertexanimation",15)) {
|
||||||
bHasUVs = false;
|
bHasUVs = false;
|
||||||
ParseVASection(szCurrent,&szCurrent);
|
ParseVASection(szCurrent, &szCurrent, mEnd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// "skeleton\n" - Starts the skeleton section
|
// "skeleton\n" - Starts the skeleton section
|
||||||
if (TokenMatch(szCurrent,"skeleton",8)) {
|
if (TokenMatch(szCurrent,"skeleton",8)) {
|
||||||
ParseSkeletonSection(szCurrent,&szCurrent);
|
ParseSkeletonSection(szCurrent, &szCurrent, mEnd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
SkipLine(szCurrent,&szCurrent);
|
SkipLine(szCurrent, &szCurrent, mEnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -683,6 +682,7 @@ void SMDImporter::ReadSmd(const std::string &pFile, IOSystem* pIOHandler) {
|
||||||
// Allocate storage and copy the contents of the file to a memory buffer
|
// Allocate storage and copy the contents of the file to a memory buffer
|
||||||
mBuffer.resize(iFileSize + 1);
|
mBuffer.resize(iFileSize + 1);
|
||||||
TextFileToBuffer(file.get(), mBuffer);
|
TextFileToBuffer(file.get(), mBuffer);
|
||||||
|
mEnd = &mBuffer[mBuffer.size() - 1] + 1;
|
||||||
|
|
||||||
iSmallestFrame = INT_MAX;
|
iSmallestFrame = INT_MAX;
|
||||||
bHasUVs = true;
|
bHasUVs = true;
|
||||||
|
@ -723,26 +723,26 @@ unsigned int SMDImporter::GetTextureIndex(const std::string& filename) {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Parse the nodes section of the file
|
// Parse the nodes section of the file
|
||||||
void SMDImporter::ParseNodesSection(const char* szCurrent, const char** szCurrentOut) {
|
void SMDImporter::ParseNodesSection(const char* szCurrent, const char** szCurrentOut, const char *end) {
|
||||||
for ( ;; ) {
|
for ( ;; ) {
|
||||||
// "end\n" - Ends the nodes section
|
// "end\n" - Ends the nodes section
|
||||||
if (0 == ASSIMP_strincmp(szCurrent, "end", 3) && IsSpaceOrNewLine(*(szCurrent+3))) {
|
if (0 == ASSIMP_strincmp(szCurrent, "end", 3) && IsSpaceOrNewLine(*(szCurrent+3))) {
|
||||||
szCurrent += 4;
|
szCurrent += 4;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ParseNodeInfo(szCurrent,&szCurrent);
|
ParseNodeInfo(szCurrent,&szCurrent, end);
|
||||||
}
|
}
|
||||||
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
|
SkipSpacesAndLineEnd(szCurrent, &szCurrent, end);
|
||||||
*szCurrentOut = szCurrent;
|
*szCurrentOut = szCurrent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Parse the triangles section of the file
|
// Parse the triangles section of the file
|
||||||
void SMDImporter::ParseTrianglesSection(const char* szCurrent, const char** szCurrentOut) {
|
void SMDImporter::ParseTrianglesSection(const char *szCurrent, const char **szCurrentOut, const char *end) {
|
||||||
// Parse a triangle, parse another triangle, parse the next triangle ...
|
// Parse a triangle, parse another triangle, parse the next triangle ...
|
||||||
// and so on until we reach a token that looks quite similar to "end"
|
// and so on until we reach a token that looks quite similar to "end"
|
||||||
for ( ;; ) {
|
for ( ;; ) {
|
||||||
if(!SkipSpacesAndLineEnd(szCurrent,&szCurrent)) {
|
if(!SkipSpacesAndLineEnd(szCurrent,&szCurrent, end)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -750,17 +750,17 @@ void SMDImporter::ParseTrianglesSection(const char* szCurrent, const char** szCu
|
||||||
if (TokenMatch(szCurrent,"end",3)) {
|
if (TokenMatch(szCurrent,"end",3)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ParseTriangle(szCurrent,&szCurrent);
|
ParseTriangle(szCurrent,&szCurrent, end);
|
||||||
}
|
}
|
||||||
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
|
SkipSpacesAndLineEnd(szCurrent,&szCurrent, end);
|
||||||
*szCurrentOut = szCurrent;
|
*szCurrentOut = szCurrent;
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Parse the vertex animation section of the file
|
// Parse the vertex animation section of the file
|
||||||
void SMDImporter::ParseVASection(const char* szCurrent, const char** szCurrentOut) {
|
void SMDImporter::ParseVASection(const char *szCurrent, const char **szCurrentOut, const char *end) {
|
||||||
unsigned int iCurIndex = 0;
|
unsigned int iCurIndex = 0;
|
||||||
for ( ;; ) {
|
for ( ;; ) {
|
||||||
if (!SkipSpacesAndLineEnd(szCurrent,&szCurrent)) {
|
if (!SkipSpacesAndLineEnd(szCurrent,&szCurrent, end)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -774,10 +774,10 @@ void SMDImporter::ParseVASection(const char* szCurrent, const char** szCurrentOu
|
||||||
// NOTE: The doc says that time values COULD be negative ...
|
// NOTE: The doc says that time values COULD be negative ...
|
||||||
// NOTE2: this is the shape key -> valve docs
|
// NOTE2: this is the shape key -> valve docs
|
||||||
int iTime = 0;
|
int iTime = 0;
|
||||||
if(!ParseSignedInt(szCurrent,&szCurrent,iTime) || configFrameID != (unsigned int)iTime) {
|
if (!ParseSignedInt(szCurrent, &szCurrent, end, iTime) || configFrameID != (unsigned int)iTime) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
SkipLine(szCurrent,&szCurrent);
|
SkipLine(szCurrent,&szCurrent, end);
|
||||||
} else {
|
} else {
|
||||||
if(0 == iCurIndex) {
|
if(0 == iCurIndex) {
|
||||||
asTriangles.emplace_back();
|
asTriangles.emplace_back();
|
||||||
|
@ -785,7 +785,7 @@ void SMDImporter::ParseVASection(const char* szCurrent, const char** szCurrentOu
|
||||||
if (++iCurIndex == 3) {
|
if (++iCurIndex == 3) {
|
||||||
iCurIndex = 0;
|
iCurIndex = 0;
|
||||||
}
|
}
|
||||||
ParseVertex(szCurrent,&szCurrent,asTriangles.back().avVertices[iCurIndex],true);
|
ParseVertex(szCurrent,&szCurrent, end, asTriangles.back().avVertices[iCurIndex],true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -794,16 +794,16 @@ void SMDImporter::ParseVASection(const char* szCurrent, const char** szCurrentOu
|
||||||
asTriangles.pop_back();
|
asTriangles.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
|
SkipSpacesAndLineEnd(szCurrent,&szCurrent, end);
|
||||||
*szCurrentOut = szCurrent;
|
*szCurrentOut = szCurrent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Parse the skeleton section of the file
|
// Parse the skeleton section of the file
|
||||||
void SMDImporter::ParseSkeletonSection(const char* szCurrent, const char** szCurrentOut) {
|
void SMDImporter::ParseSkeletonSection(const char *szCurrent, const char **szCurrentOut, const char *end) {
|
||||||
int iTime = 0;
|
int iTime = 0;
|
||||||
for ( ;; ) {
|
for ( ;; ) {
|
||||||
if (!SkipSpacesAndLineEnd(szCurrent,&szCurrent)) {
|
if (!SkipSpacesAndLineEnd(szCurrent,&szCurrent, end)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -812,14 +812,14 @@ void SMDImporter::ParseSkeletonSection(const char* szCurrent, const char** szCur
|
||||||
break;
|
break;
|
||||||
} else if (TokenMatch(szCurrent,"time",4)) {
|
} else if (TokenMatch(szCurrent,"time",4)) {
|
||||||
// "time <n>\n" - Specifies the current animation frame
|
// "time <n>\n" - Specifies the current animation frame
|
||||||
if(!ParseSignedInt(szCurrent,&szCurrent,iTime)) {
|
if (!ParseSignedInt(szCurrent, &szCurrent, end, iTime)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
iSmallestFrame = std::min(iSmallestFrame,iTime);
|
iSmallestFrame = std::min(iSmallestFrame,iTime);
|
||||||
SkipLine(szCurrent,&szCurrent);
|
SkipLine(szCurrent, &szCurrent, end);
|
||||||
} else {
|
} else {
|
||||||
ParseSkeletonElement(szCurrent,&szCurrent,iTime);
|
ParseSkeletonElement(szCurrent, &szCurrent, end, iTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*szCurrentOut = szCurrent;
|
*szCurrentOut = szCurrent;
|
||||||
|
@ -827,16 +827,16 @@ void SMDImporter::ParseSkeletonSection(const char* szCurrent, const char** szCur
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
#define SMDI_PARSE_RETURN { \
|
#define SMDI_PARSE_RETURN { \
|
||||||
SkipLine(szCurrent,&szCurrent); \
|
SkipLine(szCurrent,&szCurrent, end); \
|
||||||
*szCurrentOut = szCurrent; \
|
*szCurrentOut = szCurrent; \
|
||||||
return; \
|
return; \
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Parse a node line
|
// Parse a node line
|
||||||
void SMDImporter::ParseNodeInfo(const char* szCurrent, const char** szCurrentOut) {
|
void SMDImporter::ParseNodeInfo(const char *szCurrent, const char **szCurrentOut, const char *end) {
|
||||||
unsigned int iBone = 0;
|
unsigned int iBone = 0;
|
||||||
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
|
SkipSpacesAndLineEnd(szCurrent, &szCurrent, end);
|
||||||
if ( !ParseUnsignedInt(szCurrent,&szCurrent,iBone) || !SkipSpaces(szCurrent,&szCurrent)) {
|
if ( !ParseUnsignedInt(szCurrent, &szCurrent, end, iBone) || !SkipSpaces(szCurrent,&szCurrent, end)) {
|
||||||
throw DeadlyImportError("Unexpected EOF/EOL while parsing bone index");
|
throw DeadlyImportError("Unexpected EOF/EOL while parsing bone index");
|
||||||
}
|
}
|
||||||
if (iBone == UINT_MAX) {
|
if (iBone == UINT_MAX) {
|
||||||
|
@ -877,7 +877,7 @@ void SMDImporter::ParseNodeInfo(const char* szCurrent, const char** szCurrentOut
|
||||||
szCurrent = szEnd;
|
szCurrent = szEnd;
|
||||||
|
|
||||||
// the only negative bone parent index that could occur is -1 AFAIK
|
// the only negative bone parent index that could occur is -1 AFAIK
|
||||||
if(!ParseSignedInt(szCurrent,&szCurrent,(int&)bone.iParent)) {
|
if(!ParseSignedInt(szCurrent, &szCurrent, end, (int&)bone.iParent)) {
|
||||||
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone parent index. Assuming -1");
|
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone parent index. Assuming -1");
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
|
@ -888,12 +888,12 @@ void SMDImporter::ParseNodeInfo(const char* szCurrent, const char** szCurrentOut
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Parse a skeleton element
|
// Parse a skeleton element
|
||||||
void SMDImporter::ParseSkeletonElement(const char* szCurrent, const char** szCurrentOut,int iTime) {
|
void SMDImporter::ParseSkeletonElement(const char *szCurrent, const char **szCurrentOut, const char *end, int iTime) {
|
||||||
aiVector3D vPos;
|
aiVector3D vPos;
|
||||||
aiVector3D vRot;
|
aiVector3D vRot;
|
||||||
|
|
||||||
unsigned int iBone = 0;
|
unsigned int iBone = 0;
|
||||||
if(!ParseUnsignedInt(szCurrent,&szCurrent,iBone)) {
|
if (!ParseUnsignedInt(szCurrent, &szCurrent, end, iBone)) {
|
||||||
ASSIMP_LOG_ERROR("Unexpected EOF/EOL while parsing bone index");
|
ASSIMP_LOG_ERROR("Unexpected EOF/EOL while parsing bone index");
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
|
@ -907,27 +907,27 @@ void SMDImporter::ParseSkeletonElement(const char* szCurrent, const char** szCur
|
||||||
SMD::Bone::Animation::MatrixKey& key = bone.sAnim.asKeys.back();
|
SMD::Bone::Animation::MatrixKey& key = bone.sAnim.asKeys.back();
|
||||||
|
|
||||||
key.dTime = (double)iTime;
|
key.dTime = (double)iTime;
|
||||||
if(!ParseFloat(szCurrent,&szCurrent,(float&)vPos.x)) {
|
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vPos.x)) {
|
||||||
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.pos.x");
|
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.pos.x");
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
if(!ParseFloat(szCurrent,&szCurrent,(float&)vPos.y)) {
|
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vPos.y)) {
|
||||||
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.pos.y");
|
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.pos.y");
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
if(!ParseFloat(szCurrent,&szCurrent,(float&)vPos.z)) {
|
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vPos.z)) {
|
||||||
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.pos.z");
|
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.pos.z");
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
if(!ParseFloat(szCurrent,&szCurrent,(float&)vRot.x)) {
|
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vRot.x)) {
|
||||||
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.rot.x");
|
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.rot.x");
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
if(!ParseFloat(szCurrent,&szCurrent,(float&)vRot.y)) {
|
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vRot.y)) {
|
||||||
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.rot.y");
|
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.rot.y");
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
if(!ParseFloat(szCurrent,&szCurrent,(float&)vRot.z)) {
|
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vRot.z)) {
|
||||||
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.rot.z");
|
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.rot.z");
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
|
@ -947,11 +947,11 @@ void SMDImporter::ParseSkeletonElement(const char* szCurrent, const char** szCur
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Parse a triangle
|
// Parse a triangle
|
||||||
void SMDImporter::ParseTriangle(const char* szCurrent, const char** szCurrentOut) {
|
void SMDImporter::ParseTriangle(const char *szCurrent, const char **szCurrentOut, const char *end) {
|
||||||
asTriangles.emplace_back();
|
asTriangles.emplace_back();
|
||||||
SMD::Face& face = asTriangles.back();
|
SMD::Face& face = asTriangles.back();
|
||||||
|
|
||||||
if(!SkipSpaces(szCurrent,&szCurrent)) {
|
if(!SkipSpaces(szCurrent, &szCurrent, end)) {
|
||||||
LogErrorNoThrow("Unexpected EOF/EOL while parsing a triangle");
|
LogErrorNoThrow("Unexpected EOF/EOL while parsing a triangle");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -963,19 +963,19 @@ void SMDImporter::ParseTriangle(const char* szCurrent, const char** szCurrentOut
|
||||||
// ... and get the index that belongs to this file name
|
// ... and get the index that belongs to this file name
|
||||||
face.iTexture = GetTextureIndex(std::string(szLast,(uintptr_t)szCurrent-(uintptr_t)szLast));
|
face.iTexture = GetTextureIndex(std::string(szLast,(uintptr_t)szCurrent-(uintptr_t)szLast));
|
||||||
|
|
||||||
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
|
SkipSpacesAndLineEnd(szCurrent, &szCurrent, end);
|
||||||
|
|
||||||
// load three vertices
|
// load three vertices
|
||||||
for (auto &avVertex : face.avVertices) {
|
for (auto &avVertex : face.avVertices) {
|
||||||
ParseVertex(szCurrent,&szCurrent, avVertex);
|
ParseVertex(szCurrent, &szCurrent, end, avVertex);
|
||||||
}
|
}
|
||||||
*szCurrentOut = szCurrent;
|
*szCurrentOut = szCurrent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Parse a float
|
// Parse a float
|
||||||
bool SMDImporter::ParseFloat(const char* szCurrent, const char** szCurrentOut, float& out) {
|
bool SMDImporter::ParseFloat(const char *szCurrent, const char **szCurrentOut, const char *end, float &out) {
|
||||||
if(!SkipSpaces(&szCurrent)) {
|
if (!SkipSpaces(&szCurrent, end)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -985,8 +985,8 @@ bool SMDImporter::ParseFloat(const char* szCurrent, const char** szCurrentOut, f
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Parse an unsigned int
|
// Parse an unsigned int
|
||||||
bool SMDImporter::ParseUnsignedInt(const char* szCurrent, const char** szCurrentOut, unsigned int& out) {
|
bool SMDImporter::ParseUnsignedInt(const char *szCurrent, const char **szCurrentOut, const char *end, unsigned int &out) {
|
||||||
if(!SkipSpaces(&szCurrent)) {
|
if(!SkipSpaces(&szCurrent, end)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -996,8 +996,8 @@ bool SMDImporter::ParseUnsignedInt(const char* szCurrent, const char** szCurrent
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Parse a signed int
|
// Parse a signed int
|
||||||
bool SMDImporter::ParseSignedInt(const char* szCurrent, const char** szCurrentOut, int& out) {
|
bool SMDImporter::ParseSignedInt(const char *szCurrent, const char **szCurrentOut, const char *end, int &out) {
|
||||||
if(!SkipSpaces(&szCurrent)) {
|
if(!SkipSpaces(&szCurrent, end)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1008,37 +1008,37 @@ bool SMDImporter::ParseSignedInt(const char* szCurrent, const char** szCurrentOu
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Parse a vertex
|
// Parse a vertex
|
||||||
void SMDImporter::ParseVertex(const char* szCurrent,
|
void SMDImporter::ParseVertex(const char* szCurrent,
|
||||||
const char** szCurrentOut, SMD::Vertex& vertex,
|
const char **szCurrentOut, const char *end, SMD::Vertex &vertex,
|
||||||
bool bVASection /*= false*/) {
|
bool bVASection /*= false*/) {
|
||||||
if (SkipSpaces(&szCurrent) && IsLineEnd(*szCurrent)) {
|
if (SkipSpaces(&szCurrent, end) && IsLineEnd(*szCurrent)) {
|
||||||
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
|
SkipSpacesAndLineEnd(szCurrent,&szCurrent, end);
|
||||||
return ParseVertex(szCurrent,szCurrentOut,vertex,bVASection);
|
return ParseVertex(szCurrent, szCurrentOut, end, vertex, bVASection);
|
||||||
}
|
}
|
||||||
if(!ParseSignedInt(szCurrent,&szCurrent,(int&)vertex.iParentNode)) {
|
if(!ParseSignedInt(szCurrent, &szCurrent, end, (int&)vertex.iParentNode)) {
|
||||||
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.parent");
|
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.parent");
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.pos.x)) {
|
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vertex.pos.x)) {
|
||||||
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.pos.x");
|
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.pos.x");
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.pos.y)) {
|
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vertex.pos.y)) {
|
||||||
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.pos.y");
|
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.pos.y");
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.pos.z)) {
|
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vertex.pos.z)) {
|
||||||
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.pos.z");
|
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.pos.z");
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.nor.x)) {
|
if(!ParseFloat(szCurrent,&szCurrent,end, (float&)vertex.nor.x)) {
|
||||||
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.nor.x");
|
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.nor.x");
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.nor.y)) {
|
if(!ParseFloat(szCurrent,&szCurrent, end, (float&)vertex.nor.y)) {
|
||||||
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.nor.y");
|
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.nor.y");
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.nor.z)) {
|
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vertex.nor.z)) {
|
||||||
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.nor.z");
|
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.nor.z");
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
|
@ -1047,11 +1047,11 @@ void SMDImporter::ParseVertex(const char* szCurrent,
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.uv.x)) {
|
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vertex.uv.x)) {
|
||||||
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.uv.x");
|
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.uv.x");
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.uv.y)) {
|
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vertex.uv.y)) {
|
||||||
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.uv.y");
|
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.uv.y");
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
|
@ -1059,16 +1059,16 @@ void SMDImporter::ParseVertex(const char* szCurrent,
|
||||||
// now read the number of bones affecting this vertex
|
// now read the number of bones affecting this vertex
|
||||||
// all elements from now are fully optional, we don't need them
|
// all elements from now are fully optional, we don't need them
|
||||||
unsigned int iSize = 0;
|
unsigned int iSize = 0;
|
||||||
if(!ParseUnsignedInt(szCurrent,&szCurrent,iSize)) {
|
if(!ParseUnsignedInt(szCurrent, &szCurrent, end, iSize)) {
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
vertex.aiBoneLinks.resize(iSize,std::pair<unsigned int, float>(0,0.0f));
|
vertex.aiBoneLinks.resize(iSize,std::pair<unsigned int, float>(0,0.0f));
|
||||||
|
|
||||||
for (auto &aiBoneLink : vertex.aiBoneLinks) {
|
for (auto &aiBoneLink : vertex.aiBoneLinks) {
|
||||||
if(!ParseUnsignedInt(szCurrent,&szCurrent,aiBoneLink.first)) {
|
if(!ParseUnsignedInt(szCurrent, &szCurrent, end, aiBoneLink.first)) {
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
if(!ParseFloat(szCurrent,&szCurrent,aiBoneLink.second)) {
|
if(!ParseFloat(szCurrent, &szCurrent, end, aiBoneLink.second)) {
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1077,6 +1077,6 @@ void SMDImporter::ParseVertex(const char* szCurrent,
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace Assimp
|
||||||
|
|
||||||
#endif // !! ASSIMP_BUILD_NO_SMD_IMPORTER
|
#endif // !! ASSIMP_BUILD_NO_SMD_IMPORTER
|
||||||
|
|
|
@ -162,7 +162,7 @@ struct Bone {
|
||||||
class ASSIMP_API SMDImporter : public BaseImporter {
|
class ASSIMP_API SMDImporter : public BaseImporter {
|
||||||
public:
|
public:
|
||||||
SMDImporter();
|
SMDImporter();
|
||||||
~SMDImporter() override;
|
~SMDImporter() override = default;
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Returns whether the class can handle the format of the given file.
|
/** Returns whether the class can handle the format of the given file.
|
||||||
|
@ -206,7 +206,7 @@ protected:
|
||||||
* the next section (or to EOF)
|
* the next section (or to EOF)
|
||||||
*/
|
*/
|
||||||
void ParseTrianglesSection(const char* szCurrent,
|
void ParseTrianglesSection(const char* szCurrent,
|
||||||
const char** szCurrentOut);
|
const char **szCurrentOut, const char *end);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Parse the vertex animation section in VTA files
|
/** Parse the vertex animation section in VTA files
|
||||||
|
@ -216,7 +216,7 @@ protected:
|
||||||
* the next section (or to EOF)
|
* the next section (or to EOF)
|
||||||
*/
|
*/
|
||||||
void ParseVASection(const char* szCurrent,
|
void ParseVASection(const char* szCurrent,
|
||||||
const char** szCurrentOut);
|
const char **szCurrentOu, const char *end);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Parse the nodes section of the SMD file
|
/** Parse the nodes section of the SMD file
|
||||||
|
@ -226,7 +226,7 @@ protected:
|
||||||
* the next section (or to EOF)
|
* the next section (or to EOF)
|
||||||
*/
|
*/
|
||||||
void ParseNodesSection(const char* szCurrent,
|
void ParseNodesSection(const char* szCurrent,
|
||||||
const char** szCurrentOut);
|
const char **szCurrentOut, const char *end);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Parse the skeleton section of the SMD file
|
/** Parse the skeleton section of the SMD file
|
||||||
|
@ -236,7 +236,7 @@ protected:
|
||||||
* the next section (or to EOF)
|
* the next section (or to EOF)
|
||||||
*/
|
*/
|
||||||
void ParseSkeletonSection(const char* szCurrent,
|
void ParseSkeletonSection(const char* szCurrent,
|
||||||
const char** szCurrentOut);
|
const char **szCurrentOut, const char *end);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Parse a single triangle in the SMD file
|
/** Parse a single triangle in the SMD file
|
||||||
|
@ -245,8 +245,7 @@ protected:
|
||||||
* \param szCurrentOut Receives the output cursor position
|
* \param szCurrentOut Receives the output cursor position
|
||||||
*/
|
*/
|
||||||
void ParseTriangle(const char* szCurrent,
|
void ParseTriangle(const char* szCurrent,
|
||||||
const char** szCurrentOut);
|
const char **szCurrentOut, const char *end);
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Parse a single vertex in the SMD file
|
/** Parse a single vertex in the SMD file
|
||||||
|
@ -256,7 +255,7 @@ protected:
|
||||||
* \param vertex Vertex to be filled
|
* \param vertex Vertex to be filled
|
||||||
*/
|
*/
|
||||||
void ParseVertex(const char* szCurrent,
|
void ParseVertex(const char* szCurrent,
|
||||||
const char** szCurrentOut, SMD::Vertex& vertex,
|
const char **szCurrentOut, const char *end, SMD::Vertex &vertex,
|
||||||
bool bVASection = false);
|
bool bVASection = false);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
@ -271,32 +270,31 @@ protected:
|
||||||
/** Parse a line in the skeleton section
|
/** Parse a line in the skeleton section
|
||||||
*/
|
*/
|
||||||
void ParseSkeletonElement(const char* szCurrent,
|
void ParseSkeletonElement(const char* szCurrent,
|
||||||
const char** szCurrentOut,int iTime);
|
const char **szCurrentOut, const char *end, int iTime);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Parse a line in the nodes section
|
/** Parse a line in the nodes section
|
||||||
*/
|
*/
|
||||||
void ParseNodeInfo(const char* szCurrent,
|
void ParseNodeInfo(const char* szCurrent,
|
||||||
const char** szCurrentOut);
|
const char **szCurrentOut, const char *end);
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Parse a floating-point value
|
/** Parse a floating-point value
|
||||||
*/
|
*/
|
||||||
bool ParseFloat(const char* szCurrent,
|
bool ParseFloat(const char* szCurrent,
|
||||||
const char** szCurrentOut, float& out);
|
const char **szCurrentOut, const char *end, float &out);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Parse an unsigned integer. There may be no sign!
|
/** Parse an unsigned integer. There may be no sign!
|
||||||
*/
|
*/
|
||||||
bool ParseUnsignedInt(const char* szCurrent,
|
bool ParseUnsignedInt(const char* szCurrent,
|
||||||
const char** szCurrentOut, unsigned int& out);
|
const char **szCurrentOut, const char *end, unsigned int &out);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Parse a signed integer. Signs (+,-) are handled.
|
/** Parse a signed integer. Signs (+,-) are handled.
|
||||||
*/
|
*/
|
||||||
bool ParseSignedInt(const char* szCurrent,
|
bool ParseSignedInt(const char* szCurrent,
|
||||||
const char** szCurrentOut, int& out);
|
const char **szCurrentOut, const char *end, int &out);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Fix invalid time values in the file
|
/** Fix invalid time values in the file
|
||||||
|
@ -304,7 +302,7 @@ protected:
|
||||||
void FixTimeValues();
|
void FixTimeValues();
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Add all children of a bone as subnodes to a node
|
/** Add all children of a bone as sub-nodes to a node
|
||||||
* \param pcNode Parent node
|
* \param pcNode Parent node
|
||||||
* \param iParent Parent bone index
|
* \param iParent Parent bone index
|
||||||
*/
|
*/
|
||||||
|
@ -329,17 +327,15 @@ protected:
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
inline bool SkipLine( const char* in, const char** out)
|
inline bool SkipLine( const char* in, const char** out, const char *end) {
|
||||||
{
|
Assimp::SkipLine(in, out, end);
|
||||||
Assimp::SkipLine(in,out);
|
|
||||||
++iLineNumber;
|
++iLineNumber;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
inline bool SkipSpacesAndLineEnd( const char* in, const char** out)
|
inline bool SkipSpacesAndLineEnd(const char *in, const char **out, const char *end) {
|
||||||
{
|
|
||||||
++iLineNumber;
|
++iLineNumber;
|
||||||
return Assimp::SkipSpacesAndLineEnd(in,out);
|
return Assimp::SkipSpacesAndLineEnd(in, out, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -349,6 +345,7 @@ private:
|
||||||
|
|
||||||
/** Buffer to hold the loaded file */
|
/** Buffer to hold the loaded file */
|
||||||
std::vector<char> mBuffer;
|
std::vector<char> mBuffer;
|
||||||
|
char *mEnd;
|
||||||
|
|
||||||
/** Output scene to be filled
|
/** Output scene to be filled
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
|
||||||
|
|
||||||
Copyright (c) 2006-2022, assimp team
|
Copyright (c) 2006-2022, assimp team
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
@ -40,7 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file STEPFileReader.cpp
|
/**
|
||||||
|
* @file STEPFileReader.cpp
|
||||||
* @brief Implementation of the STEP file parser, which fills a
|
* @brief Implementation of the STEP file parser, which fills a
|
||||||
* STEP::DB with data read from a file.
|
* STEP::DB with data read from a file.
|
||||||
*/
|
*/
|
||||||
|
@ -58,34 +58,28 @@ using namespace Assimp;
|
||||||
namespace EXPRESS = STEP::EXPRESS;
|
namespace EXPRESS = STEP::EXPRESS;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
std::string AddLineNumber(const std::string& s,uint64_t line /*= LINE_NOT_SPECIFIED*/, const std::string& prefix = std::string())
|
std::string AddLineNumber(const std::string& s,uint64_t line /*= LINE_NOT_SPECIFIED*/, const std::string& prefix = std::string()) {
|
||||||
{
|
|
||||||
return line == STEP::SyntaxError::LINE_NOT_SPECIFIED ? prefix+s : static_cast<std::string>( (Formatter::format(),prefix,"(line ",line,") ",s) );
|
return line == STEP::SyntaxError::LINE_NOT_SPECIFIED ? prefix+s : static_cast<std::string>( (Formatter::format(),prefix,"(line ",line,") ",s) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
std::string AddEntityID(const std::string& s,uint64_t entity /*= ENTITY_NOT_SPECIFIED*/, const std::string& prefix = std::string())
|
std::string AddEntityID(const std::string& s,uint64_t entity /*= ENTITY_NOT_SPECIFIED*/, const std::string& prefix = std::string()) {
|
||||||
{
|
|
||||||
return entity == STEP::TypeError::ENTITY_NOT_SPECIFIED ? prefix+s : static_cast<std::string>( (Formatter::format(),prefix,"(entity #",entity,") ",s));
|
return entity == STEP::TypeError::ENTITY_NOT_SPECIFIED ? prefix+s : static_cast<std::string>( (Formatter::format(),prefix,"(entity #",entity,") ",s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
STEP::SyntaxError::SyntaxError (const std::string& s,uint64_t line /* = LINE_NOT_SPECIFIED */)
|
STEP::SyntaxError::SyntaxError (const std::string& s,uint64_t line) : DeadlyImportError(AddLineNumber(s,line)) {
|
||||||
: DeadlyImportError(AddLineNumber(s,line))
|
// empty
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
STEP::TypeError::TypeError (const std::string& s,uint64_t entity /* = ENTITY_NOT_SPECIFIED */,uint64_t line /*= LINE_NOT_SPECIFIED*/)
|
STEP::TypeError::TypeError (const std::string& s,uint64_t entity, uint64_t line) : DeadlyImportError(AddLineNumber(AddEntityID(s,entity),line)) {
|
||||||
: DeadlyImportError(AddLineNumber(AddEntityID(s,entity),line))
|
// empty
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *ISO_Token = "ISO-10303-21;";
|
static constexpr char ISO_Token[] = "ISO-10303-21;";
|
||||||
static const char *FILE_SCHEMA_Token = "FILE_SCHEMA";
|
static constexpr char FILE_SCHEMA_Token[] = "FILE_SCHEMA";
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
STEP::DB* STEP::ReadFileHeader(std::shared_ptr<IOStream> stream) {
|
STEP::DB* STEP::ReadFileHeader(std::shared_ptr<IOStream> stream) {
|
||||||
std::shared_ptr<StreamReaderLE> reader = std::shared_ptr<StreamReaderLE>(new StreamReaderLE(std::move(stream)));
|
std::shared_ptr<StreamReaderLE> reader = std::shared_ptr<StreamReaderLE>(new StreamReaderLE(std::move(stream)));
|
||||||
|
@ -110,8 +104,9 @@ STEP::DB* STEP::ReadFileHeader(std::shared_ptr<IOStream> stream) {
|
||||||
|
|
||||||
if (s.substr(0,11) == FILE_SCHEMA_Token) {
|
if (s.substr(0,11) == FILE_SCHEMA_Token) {
|
||||||
const char* sz = s.c_str()+11;
|
const char* sz = s.c_str()+11;
|
||||||
SkipSpaces(sz,&sz);
|
const char *end = s.c_str() + s.size();
|
||||||
std::shared_ptr< const EXPRESS::DataType > schema = EXPRESS::DataType::Parse(sz);
|
SkipSpaces(sz,&sz, end);
|
||||||
|
std::shared_ptr< const EXPRESS::DataType > schema = EXPRESS::DataType::Parse(sz, end);
|
||||||
|
|
||||||
// the file schema should be a regular list entity, although it usually contains exactly one entry
|
// the file schema should be a regular list entity, although it usually contains exactly one entry
|
||||||
// since the list itself is contained in a regular parameter list, we actually have
|
// since the list itself is contained in a regular parameter list, we actually have
|
||||||
|
@ -304,10 +299,10 @@ void STEP::ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
std::shared_ptr<const EXPRESS::DataType> EXPRESS::DataType::Parse(const char*& inout,uint64_t line, const EXPRESS::ConversionSchema* schema /*= nullptr*/)
|
std::shared_ptr<const EXPRESS::DataType> EXPRESS::DataType::Parse(const char*& inout, const char *end, uint64_t line, const EXPRESS::ConversionSchema* schema /*= nullptr*/)
|
||||||
{
|
{
|
||||||
const char* cur = inout;
|
const char* cur = inout;
|
||||||
SkipSpaces(&cur);
|
SkipSpaces(&cur, end);
|
||||||
if (*cur == ',' || IsSpaceOrNewLine(*cur)) {
|
if (*cur == ',' || IsSpaceOrNewLine(*cur)) {
|
||||||
throw STEP::SyntaxError("unexpected token, expected parameter",line);
|
throw STEP::SyntaxError("unexpected token, expected parameter",line);
|
||||||
}
|
}
|
||||||
|
@ -325,7 +320,7 @@ std::shared_ptr<const EXPRESS::DataType> EXPRESS::DataType::Parse(const char*& i
|
||||||
std::transform(s.begin(),s.end(),s.begin(),&ai_tolower<char> );
|
std::transform(s.begin(),s.end(),s.begin(),&ai_tolower<char> );
|
||||||
if (schema->IsKnownToken(s)) {
|
if (schema->IsKnownToken(s)) {
|
||||||
for(cur = t+1;*cur++ != '(';);
|
for(cur = t+1;*cur++ != '(';);
|
||||||
std::shared_ptr<const EXPRESS::DataType> dt = Parse(cur);
|
std::shared_ptr<const EXPRESS::DataType> dt = Parse(cur, end);
|
||||||
inout = *cur ? cur+1 : cur;
|
inout = *cur ? cur+1 : cur;
|
||||||
return dt;
|
return dt;
|
||||||
}
|
}
|
||||||
|
@ -348,7 +343,7 @@ std::shared_ptr<const EXPRESS::DataType> EXPRESS::DataType::Parse(const char*& i
|
||||||
else if (*cur == '(' ) {
|
else if (*cur == '(' ) {
|
||||||
// start of an aggregate, further parsing is done by the LIST factory constructor
|
// start of an aggregate, further parsing is done by the LIST factory constructor
|
||||||
inout = cur;
|
inout = cur;
|
||||||
return EXPRESS::LIST::Parse(inout,line,schema);
|
return EXPRESS::LIST::Parse(inout, end, line, schema);
|
||||||
}
|
}
|
||||||
else if (*cur == '.' ) {
|
else if (*cur == '.' ) {
|
||||||
// enum (includes boolean)
|
// enum (includes boolean)
|
||||||
|
@ -427,9 +422,10 @@ std::shared_ptr<const EXPRESS::DataType> EXPRESS::DataType::Parse(const char*& i
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
std::shared_ptr<const EXPRESS::LIST> EXPRESS::LIST::Parse(const char*& inout,uint64_t line, const EXPRESS::ConversionSchema* schema /*= nullptr*/) {
|
std::shared_ptr<const EXPRESS::LIST> EXPRESS::LIST::Parse(const char*& inout, const char *end,
|
||||||
|
uint64_t line, const EXPRESS::ConversionSchema* schema) {
|
||||||
const std::shared_ptr<EXPRESS::LIST> list = std::make_shared<EXPRESS::LIST>();
|
const std::shared_ptr<EXPRESS::LIST> list = std::make_shared<EXPRESS::LIST>();
|
||||||
EXPRESS::LIST::MemberList& members = list->members;
|
EXPRESS::LIST::MemberList& cur_members = list->members;
|
||||||
|
|
||||||
const char* cur = inout;
|
const char* cur = inout;
|
||||||
if (*cur++ != '(') {
|
if (*cur++ != '(') {
|
||||||
|
@ -442,19 +438,19 @@ std::shared_ptr<const EXPRESS::LIST> EXPRESS::LIST::Parse(const char*& inout,uin
|
||||||
count += (*c == ',' ? 1 : 0);
|
count += (*c == ',' ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
members.reserve(count);
|
cur_members.reserve(count);
|
||||||
|
|
||||||
for(;;++cur) {
|
for(;;++cur) {
|
||||||
if (!*cur) {
|
if (!*cur) {
|
||||||
throw STEP::SyntaxError("unexpected end of line while reading list");
|
throw STEP::SyntaxError("unexpected end of line while reading list");
|
||||||
}
|
}
|
||||||
SkipSpaces(cur,&cur);
|
SkipSpaces(cur,&cur, end);
|
||||||
if (*cur == ')') {
|
if (*cur == ')') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
members.push_back( EXPRESS::DataType::Parse(cur,line,schema));
|
cur_members.push_back(EXPRESS::DataType::Parse(cur, end, line, schema));
|
||||||
SkipSpaces(cur,&cur);
|
SkipSpaces(cur, &cur, end);
|
||||||
|
|
||||||
if (*cur != ',') {
|
if (*cur != ',') {
|
||||||
if (*cur == ')') {
|
if (*cur == ')') {
|
||||||
|
@ -543,7 +539,8 @@ void STEP::LazyObject::LazyInit() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* acopy = args;
|
const char* acopy = args;
|
||||||
std::shared_ptr<const EXPRESS::LIST> conv_args = EXPRESS::LIST::Parse(acopy,(uint64_t)STEP::SyntaxError::LINE_NOT_SPECIFIED,&db.GetSchema());
|
const char *end = acopy + std::strlen(args);
|
||||||
|
std::shared_ptr<const EXPRESS::LIST> conv_args = EXPRESS::LIST::Parse(acopy, end, (uint64_t)STEP::SyntaxError::LINE_NOT_SPECIFIED,&db.GetSchema());
|
||||||
delete[] args;
|
delete[] args;
|
||||||
args = nullptr;
|
args = nullptr;
|
||||||
|
|
||||||
|
|
|
@ -60,8 +60,7 @@ void ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme, const char* const*
|
||||||
|
|
||||||
/// @brief Helper to read a file.
|
/// @brief Helper to read a file.
|
||||||
template <size_t N, size_t N2>
|
template <size_t N, size_t N2>
|
||||||
inline
|
inline void ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme, const char* const (&arr)[N], const char* const (&arr2)[N2]) {
|
||||||
void ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme, const char* const (&arr)[N], const char* const (&arr2)[N2]) {
|
|
||||||
return ReadFile(db,scheme,arr,N,arr2,N2);
|
return ReadFile(db,scheme,arr,N,arr2,N2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ static bool IsAsciiSTL(const char *buffer, size_t fileSize) {
|
||||||
|
|
||||||
const char *bufferEnd = buffer + fileSize;
|
const char *bufferEnd = buffer + fileSize;
|
||||||
|
|
||||||
if (!SkipSpaces(&buffer)) {
|
if (!SkipSpaces(&buffer, bufferEnd)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,11 +244,11 @@ void STLImporter::LoadASCIIFile(aiNode *root) {
|
||||||
aiNode *node = new aiNode;
|
aiNode *node = new aiNode;
|
||||||
node->mParent = root;
|
node->mParent = root;
|
||||||
nodes.push_back(node);
|
nodes.push_back(node);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, bufferEnd);
|
||||||
ai_assert(!IsLineEnd(sz));
|
ai_assert(!IsLineEnd(sz));
|
||||||
|
|
||||||
sz += 5; // skip the "solid"
|
sz += 5; // skip the "solid"
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, bufferEnd);
|
||||||
const char *szMe = sz;
|
const char *szMe = sz;
|
||||||
while (!IsSpaceOrNewLine(*sz)) {
|
while (!IsSpaceOrNewLine(*sz)) {
|
||||||
sz++;
|
sz++;
|
||||||
|
@ -270,7 +270,7 @@ void STLImporter::LoadASCIIFile(aiNode *root) {
|
||||||
unsigned int faceVertexCounter = 3;
|
unsigned int faceVertexCounter = 3;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// go to the next token
|
// go to the next token
|
||||||
if (!SkipSpacesAndLineEnd(&sz)) {
|
if (!SkipSpacesAndLineEnd(&sz, bufferEnd)) {
|
||||||
// seems we're finished although there was no end marker
|
// seems we're finished although there was no end marker
|
||||||
ASSIMP_LOG_WARN("STL: unexpected EOF. \'endsolid\' keyword was expected");
|
ASSIMP_LOG_WARN("STL: unexpected EOF. \'endsolid\' keyword was expected");
|
||||||
break;
|
break;
|
||||||
|
@ -284,7 +284,7 @@ void STLImporter::LoadASCIIFile(aiNode *root) {
|
||||||
faceVertexCounter = 0;
|
faceVertexCounter = 0;
|
||||||
|
|
||||||
sz += 6;
|
sz += 6;
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, bufferEnd);
|
||||||
if (strncmp(sz, "normal", 6)) {
|
if (strncmp(sz, "normal", 6)) {
|
||||||
ASSIMP_LOG_WARN("STL: a facet normal vector was expected but not found");
|
ASSIMP_LOG_WARN("STL: a facet normal vector was expected but not found");
|
||||||
} else {
|
} else {
|
||||||
|
@ -293,11 +293,11 @@ void STLImporter::LoadASCIIFile(aiNode *root) {
|
||||||
}
|
}
|
||||||
aiVector3D vn;
|
aiVector3D vn;
|
||||||
sz += 7;
|
sz += 7;
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, bufferEnd);
|
||||||
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn.x);
|
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn.x);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, bufferEnd);
|
||||||
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn.y);
|
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn.y);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, bufferEnd);
|
||||||
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn.z);
|
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn.z);
|
||||||
normalBuffer.emplace_back(vn);
|
normalBuffer.emplace_back(vn);
|
||||||
normalBuffer.emplace_back(vn);
|
normalBuffer.emplace_back(vn);
|
||||||
|
@ -312,13 +312,13 @@ void STLImporter::LoadASCIIFile(aiNode *root) {
|
||||||
throw DeadlyImportError("STL: unexpected EOF while parsing facet");
|
throw DeadlyImportError("STL: unexpected EOF while parsing facet");
|
||||||
}
|
}
|
||||||
sz += 7;
|
sz += 7;
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, bufferEnd);
|
||||||
positionBuffer.emplace_back();
|
positionBuffer.emplace_back();
|
||||||
aiVector3D *vn = &positionBuffer.back();
|
aiVector3D *vn = &positionBuffer.back();
|
||||||
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn->x);
|
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn->x);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, bufferEnd);
|
||||||
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn->y);
|
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn->y);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz, bufferEnd);
|
||||||
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn->z);
|
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn->z);
|
||||||
faceVertexCounter++;
|
faceVertexCounter++;
|
||||||
}
|
}
|
||||||
|
@ -326,7 +326,7 @@ void STLImporter::LoadASCIIFile(aiNode *root) {
|
||||||
do {
|
do {
|
||||||
++sz;
|
++sz;
|
||||||
} while (!IsLineEnd(*sz));
|
} while (!IsLineEnd(*sz));
|
||||||
SkipSpacesAndLineEnd(&sz);
|
SkipSpacesAndLineEnd(&sz, bufferEnd);
|
||||||
// finished!
|
// finished!
|
||||||
break;
|
break;
|
||||||
} else { // else skip the whole identifier
|
} else { // else skip the whole identifier
|
||||||
|
|
|
@ -199,35 +199,27 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** parse a variable from a string and set 'inout' to the character
|
/// @brief Parse a variable from a string and set 'inout' to the character behind the last consumed character.
|
||||||
* behind the last consumed character. An optional schema enables,
|
///
|
||||||
* if specified, automatic conversion of custom data types.
|
/// An optional schema enables, if specified, automatic conversion of custom data types.
|
||||||
*
|
///
|
||||||
* @throw SyntaxError
|
/// @throw SyntaxError
|
||||||
*/
|
static std::shared_ptr<const EXPRESS::DataType> Parse(const char *&inout, const char *end,
|
||||||
static std::shared_ptr<const EXPRESS::DataType> Parse(const char *&inout,
|
uint64_t line = SyntaxError::LINE_NOT_SPECIFIED, const EXPRESS::ConversionSchema *schema = nullptr);
|
||||||
uint64_t line = SyntaxError::LINE_NOT_SPECIFIED,
|
|
||||||
const EXPRESS::ConversionSchema *schema = nullptr);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef DataType SELECT;
|
typedef DataType SELECT;
|
||||||
typedef DataType LOGICAL;
|
typedef DataType LOGICAL;
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
/** Sentinel class to represent explicitly unset (optional) fields ($) */
|
/// Sentinel class to represent explicitly unset (optional) fields ($)
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
class UNSET : public DataType {
|
class UNSET : public DataType {};
|
||||||
public:
|
|
||||||
private:
|
|
||||||
};
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
/** Sentinel class to represent explicitly derived fields (*) */
|
/// Sentinel class to represent explicitly derived fields (*)
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
class ISDERIVED : public DataType {
|
class ISDERIVED : public DataType {};
|
||||||
public:
|
|
||||||
private:
|
|
||||||
};
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
/** Shared implementation for some of the primitive data type, i.e. int, float
|
/** Shared implementation for some of the primitive data type, i.e. int, float
|
||||||
|
@ -304,7 +296,7 @@ public:
|
||||||
public:
|
public:
|
||||||
/** @see DaraType::Parse
|
/** @see DaraType::Parse
|
||||||
*/
|
*/
|
||||||
static std::shared_ptr<const EXPRESS::LIST> Parse(const char *&inout,
|
static std::shared_ptr<const EXPRESS::LIST> Parse(const char *&inout, const char *end,
|
||||||
uint64_t line = SyntaxError::LINE_NOT_SPECIFIED,
|
uint64_t line = SyntaxError::LINE_NOT_SPECIFIED,
|
||||||
const EXPRESS::ConversionSchema *schema = nullptr);
|
const EXPRESS::ConversionSchema *schema = nullptr);
|
||||||
|
|
||||||
|
|
|
@ -320,17 +320,18 @@ void UnrealImporter::InternReadFile(const std::string &pFile,
|
||||||
std::vector<char> _data;
|
std::vector<char> _data;
|
||||||
TextFileToBuffer(pb.get(), _data);
|
TextFileToBuffer(pb.get(), _data);
|
||||||
const char *data = &_data[0];
|
const char *data = &_data[0];
|
||||||
|
const char *end = &_data[_data.size() - 1] + 1;
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> tempTextures;
|
std::vector<std::pair<std::string, std::string>> tempTextures;
|
||||||
|
|
||||||
// do a quick search in the UC file for some known, usually texture-related, tags
|
// do a quick search in the UC file for some known, usually texture-related, tags
|
||||||
for (; *data; ++data) {
|
for (; *data; ++data) {
|
||||||
if (TokenMatchI(data, "#exec", 5)) {
|
if (TokenMatchI(data, "#exec", 5)) {
|
||||||
SkipSpacesAndLineEnd(&data);
|
SkipSpacesAndLineEnd(&data, end);
|
||||||
|
|
||||||
// #exec TEXTURE IMPORT [...] NAME=jjjjj [...] FILE=jjjj.pcx [...]
|
// #exec TEXTURE IMPORT [...] NAME=jjjjj [...] FILE=jjjj.pcx [...]
|
||||||
if (TokenMatchI(data, "TEXTURE", 7)) {
|
if (TokenMatchI(data, "TEXTURE", 7)) {
|
||||||
SkipSpacesAndLineEnd(&data);
|
SkipSpacesAndLineEnd(&data, end);
|
||||||
|
|
||||||
if (TokenMatchI(data, "IMPORT", 6)) {
|
if (TokenMatchI(data, "IMPORT", 6)) {
|
||||||
tempTextures.emplace_back();
|
tempTextures.emplace_back();
|
||||||
|
@ -348,14 +349,15 @@ void UnrealImporter::InternReadFile(const std::string &pFile,
|
||||||
me.second = std::string(d, (size_t)(data - d));
|
me.second = std::string(d, (size_t)(data - d));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!me.first.length() || !me.second.length())
|
if (!me.first.length() || !me.second.length()) {
|
||||||
tempTextures.pop_back();
|
tempTextures.pop_back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// #exec MESHMAP SETTEXTURE MESHMAP=box NUM=1 TEXTURE=Jtex1
|
// #exec MESHMAP SETTEXTURE MESHMAP=box NUM=1 TEXTURE=Jtex1
|
||||||
// #exec MESHMAP SCALE MESHMAP=box X=0.1 Y=0.1 Z=0.2
|
// #exec MESHMAP SCALE MESHMAP=box X=0.1 Y=0.1 Z=0.2
|
||||||
else if (TokenMatchI(data, "MESHMAP", 7)) {
|
else if (TokenMatchI(data, "MESHMAP", 7)) {
|
||||||
SkipSpacesAndLineEnd(&data);
|
SkipSpacesAndLineEnd(&data, end);
|
||||||
|
|
||||||
if (TokenMatchI(data, "SETTEXTURE", 10)) {
|
if (TokenMatchI(data, "SETTEXTURE", 10)) {
|
||||||
|
|
||||||
|
@ -369,8 +371,7 @@ void UnrealImporter::InternReadFile(const std::string &pFile,
|
||||||
} else if (!ASSIMP_strincmp(data, "TEXTURE=", 8)) {
|
} else if (!ASSIMP_strincmp(data, "TEXTURE=", 8)) {
|
||||||
data += 8;
|
data += 8;
|
||||||
const char *d = data;
|
const char *d = data;
|
||||||
for (; !IsSpaceOrNewLine(*data); ++data)
|
for (; !IsSpaceOrNewLine(*data); ++data);
|
||||||
;
|
|
||||||
me.second = std::string(d, (size_t)(data - d));
|
me.second = std::string(d, (size_t)(data - d));
|
||||||
|
|
||||||
// try to find matching path names, doesn't care if we don't find them
|
// try to find matching path names, doesn't care if we don't find them
|
||||||
|
@ -408,7 +409,7 @@ void UnrealImporter::InternReadFile(const std::string &pFile,
|
||||||
// find out how many output meshes and materials we'll have and build material indices
|
// find out how many output meshes and materials we'll have and build material indices
|
||||||
for (Unreal::Triangle &tri : triangles) {
|
for (Unreal::Triangle &tri : triangles) {
|
||||||
Unreal::TempMat mat(tri);
|
Unreal::TempMat mat(tri);
|
||||||
std::vector<Unreal::TempMat>::iterator nt = std::find(materials.begin(), materials.end(), mat);
|
auto nt = std::find(materials.begin(), materials.end(), mat);
|
||||||
if (nt == materials.end()) {
|
if (nt == materials.end()) {
|
||||||
// add material
|
// add material
|
||||||
tri.matIndex = static_cast<unsigned int>(materials.size());
|
tri.matIndex = static_cast<unsigned int>(materials.size());
|
||||||
|
|
|
@ -700,13 +700,14 @@ unsigned int XGLImporter::ReadIDAttr(XmlNode &node) {
|
||||||
float XGLImporter::ReadFloat(XmlNode &node) {
|
float XGLImporter::ReadFloat(XmlNode &node) {
|
||||||
std::string v;
|
std::string v;
|
||||||
XmlParser::getValueAsString(node, v);
|
XmlParser::getValueAsString(node, v);
|
||||||
const char *s = v.c_str(), *se;
|
const char *s = v.c_str();
|
||||||
if (!SkipSpaces(&s)) {
|
const char *end = v.c_str() + v.size();
|
||||||
|
if (!SkipSpaces(&s, end)) {
|
||||||
LogError("unexpected EOL, failed to parse index element");
|
LogError("unexpected EOL, failed to parse index element");
|
||||||
return 0.f;
|
return 0.f;
|
||||||
}
|
}
|
||||||
float t;
|
float t{ 0.0f };
|
||||||
se = fast_atoreal_move(s, t);
|
const char *se = fast_atoreal_move(s, t);
|
||||||
if (se == s) {
|
if (se == s) {
|
||||||
LogError("failed to read float text");
|
LogError("failed to read float text");
|
||||||
return 0.f;
|
return 0.f;
|
||||||
|
@ -720,7 +721,8 @@ unsigned int XGLImporter::ReadIndexFromText(XmlNode &node) {
|
||||||
std::string v;
|
std::string v;
|
||||||
XmlParser::getValueAsString(node, v);
|
XmlParser::getValueAsString(node, v);
|
||||||
const char *s = v.c_str();
|
const char *s = v.c_str();
|
||||||
if (!SkipSpaces(&s)) {
|
const char *end = v.c_str() + v.size();
|
||||||
|
if (!SkipSpaces(&s, end)) {
|
||||||
LogError("unexpected EOL, failed to parse index element");
|
LogError("unexpected EOL, failed to parse index element");
|
||||||
return ErrorId;
|
return ErrorId;
|
||||||
}
|
}
|
||||||
|
@ -741,16 +743,17 @@ aiVector2D XGLImporter::ReadVec2(XmlNode &node) {
|
||||||
std::string val;
|
std::string val;
|
||||||
XmlParser::getValueAsString(node, val);
|
XmlParser::getValueAsString(node, val);
|
||||||
const char *s = val.c_str();
|
const char *s = val.c_str();
|
||||||
|
const char *end = val.c_str() + val.size();
|
||||||
ai_real v[2] = {};
|
ai_real v[2] = {};
|
||||||
for (int i = 0; i < 2; ++i) {
|
for (int i = 0; i < 2; ++i) {
|
||||||
if (!SkipSpaces(&s)) {
|
if (!SkipSpaces(&s, end)) {
|
||||||
LogError("unexpected EOL, failed to parse vec2");
|
LogError("unexpected EOL, failed to parse vec2");
|
||||||
return vec;
|
return vec;
|
||||||
}
|
}
|
||||||
|
|
||||||
v[i] = fast_atof(&s);
|
v[i] = fast_atof(&s);
|
||||||
|
|
||||||
SkipSpaces(&s);
|
SkipSpaces(&s, end);
|
||||||
if (i != 1 && *s != ',') {
|
if (i != 1 && *s != ',') {
|
||||||
LogError("expected comma, failed to parse vec2");
|
LogError("expected comma, failed to parse vec2");
|
||||||
return vec;
|
return vec;
|
||||||
|
@ -769,14 +772,15 @@ aiVector3D XGLImporter::ReadVec3(XmlNode &node) {
|
||||||
std::string v;
|
std::string v;
|
||||||
XmlParser::getValueAsString(node, v);
|
XmlParser::getValueAsString(node, v);
|
||||||
const char *s = v.c_str();
|
const char *s = v.c_str();
|
||||||
|
const char *end = v.c_str() + v.size();
|
||||||
for (int i = 0; i < 3; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
if (!SkipSpaces(&s)) {
|
if (!SkipSpaces(&s, end)) {
|
||||||
LogError("unexpected EOL, failed to parse vec3");
|
LogError("unexpected EOL, failed to parse vec3");
|
||||||
return vec;
|
return vec;
|
||||||
}
|
}
|
||||||
vec[i] = fast_atof(&s);
|
vec[i] = fast_atof(&s);
|
||||||
|
|
||||||
SkipSpaces(&s);
|
SkipSpaces(&s, end);
|
||||||
if (i != 2 && *s != ',') {
|
if (i != 2 && *s != ',') {
|
||||||
LogError("expected comma, failed to parse vec3");
|
LogError("expected comma, failed to parse vec3");
|
||||||
return vec;
|
return vec;
|
||||||
|
|
|
@ -1193,6 +1193,10 @@ ENDIF ()
|
||||||
|
|
||||||
TARGET_USE_COMMON_OUTPUT_DIRECTORY(assimp)
|
TARGET_USE_COMMON_OUTPUT_DIRECTORY(assimp)
|
||||||
|
|
||||||
|
add_compile_options(
|
||||||
|
"$<$<CONFIG:DEBUG>:-O0;-g3;-ggdb>"
|
||||||
|
)
|
||||||
|
|
||||||
IF (ASSIMP_WARNINGS_AS_ERRORS)
|
IF (ASSIMP_WARNINGS_AS_ERRORS)
|
||||||
MESSAGE(STATUS "Treating all warnings as errors (for assimp library only)")
|
MESSAGE(STATUS "Treating all warnings as errors (for assimp library only)")
|
||||||
IF (MSVC)
|
IF (MSVC)
|
||||||
|
|
|
@ -52,8 +52,9 @@ namespace Assimp {
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
void ConvertListToStrings(const std::string &in, std::list<std::string> &out) {
|
void ConvertListToStrings(const std::string &in, std::list<std::string> &out) {
|
||||||
const char *s = in.c_str();
|
const char *s = in.c_str();
|
||||||
|
const char *end = in.c_str() + in.size();
|
||||||
while (*s) {
|
while (*s) {
|
||||||
SkipSpacesAndLineEnd(&s);
|
SkipSpacesAndLineEnd(&s, end);
|
||||||
if (*s == '\'') {
|
if (*s == '\'') {
|
||||||
const char *base = ++s;
|
const char *base = ++s;
|
||||||
while (*s != '\'') {
|
while (*s != '\'') {
|
||||||
|
@ -66,7 +67,7 @@ void ConvertListToStrings(const std::string &in, std::list<std::string> &out) {
|
||||||
out.emplace_back(base, (size_t)(s - base));
|
out.emplace_back(base, (size_t)(s - base));
|
||||||
++s;
|
++s;
|
||||||
} else {
|
} else {
|
||||||
out.push_back(GetNextToken(s));
|
out.push_back(GetNextToken(s, end));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,6 +110,8 @@ public:
|
||||||
|
|
||||||
std::string operator* () const;
|
std::string operator* () const;
|
||||||
|
|
||||||
|
const char *getEnd() const;
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
/** boolean context */
|
/** boolean context */
|
||||||
operator bool() const;
|
operator bool() const;
|
||||||
|
@ -139,17 +141,21 @@ public:
|
||||||
private:
|
private:
|
||||||
line_idx mIdx;
|
line_idx mIdx;
|
||||||
std::string mCur;
|
std::string mCur;
|
||||||
|
const char *mEnd;
|
||||||
StreamReaderLE& mStream;
|
StreamReaderLE& mStream;
|
||||||
bool mSwallow, mSkip_empty_lines, mTrim;
|
bool mSwallow, mSkip_empty_lines, mTrim;
|
||||||
};
|
};
|
||||||
|
|
||||||
AI_FORCE_INLINE LineSplitter::LineSplitter(StreamReaderLE& stream, bool skip_empty_lines, bool trim ) :
|
AI_FORCE_INLINE LineSplitter::LineSplitter(StreamReaderLE& stream, bool skip_empty_lines, bool trim ) :
|
||||||
mIdx(0),
|
mIdx(0),
|
||||||
|
mCur(),
|
||||||
|
mEnd(nullptr),
|
||||||
mStream(stream),
|
mStream(stream),
|
||||||
mSwallow(),
|
mSwallow(),
|
||||||
mSkip_empty_lines(skip_empty_lines),
|
mSkip_empty_lines(skip_empty_lines),
|
||||||
mTrim(trim) {
|
mTrim(trim) {
|
||||||
mCur.reserve(1024);
|
mCur.reserve(1024);
|
||||||
|
mEnd = mCur.c_str() + 1024;
|
||||||
operator++();
|
operator++();
|
||||||
mIdx = 0;
|
mIdx = 0;
|
||||||
}
|
}
|
||||||
|
@ -203,14 +209,14 @@ AI_FORCE_INLINE LineSplitter &LineSplitter::operator++(int) {
|
||||||
AI_FORCE_INLINE const char *LineSplitter::operator[] (size_t idx) const {
|
AI_FORCE_INLINE const char *LineSplitter::operator[] (size_t idx) const {
|
||||||
const char* s = operator->()->c_str();
|
const char* s = operator->()->c_str();
|
||||||
|
|
||||||
SkipSpaces(&s);
|
SkipSpaces(&s, mEnd);
|
||||||
for (size_t i = 0; i < idx; ++i) {
|
for (size_t i = 0; i < idx; ++i) {
|
||||||
for (; !IsSpace(*s); ++s) {
|
for (; !IsSpace(*s); ++s) {
|
||||||
if (IsLineEnd(*s)) {
|
if (IsLineEnd(*s)) {
|
||||||
throw std::range_error("Token index out of range, EOL reached");
|
throw std::range_error("Token index out of range, EOL reached");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SkipSpaces(&s);
|
SkipSpaces(&s, mEnd);
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
@ -219,7 +225,7 @@ template <size_t N>
|
||||||
AI_FORCE_INLINE void LineSplitter::get_tokens(const char* (&tokens)[N]) const {
|
AI_FORCE_INLINE void LineSplitter::get_tokens(const char* (&tokens)[N]) const {
|
||||||
const char* s = operator->()->c_str();
|
const char* s = operator->()->c_str();
|
||||||
|
|
||||||
SkipSpaces(&s);
|
SkipSpaces(&s, mEnd);
|
||||||
for (size_t i = 0; i < N; ++i) {
|
for (size_t i = 0; i < N; ++i) {
|
||||||
if (IsLineEnd(*s)) {
|
if (IsLineEnd(*s)) {
|
||||||
throw std::range_error("Token count out of range, EOL reached");
|
throw std::range_error("Token count out of range, EOL reached");
|
||||||
|
@ -227,7 +233,7 @@ AI_FORCE_INLINE void LineSplitter::get_tokens(const char* (&tokens)[N]) const {
|
||||||
tokens[i] = s;
|
tokens[i] = s;
|
||||||
|
|
||||||
for (; *s && !IsSpace(*s); ++s);
|
for (; *s && !IsSpace(*s); ++s);
|
||||||
SkipSpaces(&s);
|
SkipSpaces(&s, mEnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,6 +245,10 @@ AI_FORCE_INLINE std::string LineSplitter::operator* () const {
|
||||||
return mCur;
|
return mCur;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AI_FORCE_INLINE const char* LineSplitter::getEnd() const {
|
||||||
|
return mEnd;
|
||||||
|
}
|
||||||
|
|
||||||
AI_FORCE_INLINE LineSplitter::operator bool() const {
|
AI_FORCE_INLINE LineSplitter::operator bool() const {
|
||||||
return mStream.GetRemainingSize() > 0;
|
return mStream.GetRemainingSize() > 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,8 +102,8 @@ AI_FORCE_INLINE bool IsSpaceOrNewLine(char_t in) {
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
template <class char_t>
|
template <class char_t>
|
||||||
AI_FORCE_INLINE bool SkipSpaces(const char_t *in, const char_t **out) {
|
AI_FORCE_INLINE bool SkipSpaces(const char_t *in, const char_t **out, const char_t *end) {
|
||||||
while (*in == (char_t)' ' || *in == (char_t)'\t') {
|
while ((*in == (char_t)' ' || *in == (char_t)'\t') && in != end) {
|
||||||
++in;
|
++in;
|
||||||
}
|
}
|
||||||
*out = in;
|
*out = in;
|
||||||
|
@ -112,19 +112,19 @@ AI_FORCE_INLINE bool SkipSpaces(const char_t *in, const char_t **out) {
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
template <class char_t>
|
template <class char_t>
|
||||||
AI_FORCE_INLINE bool SkipSpaces(const char_t **inout) {
|
AI_FORCE_INLINE bool SkipSpaces(const char_t **inout, const char_t *end) {
|
||||||
return SkipSpaces<char_t>(*inout, inout);
|
return SkipSpaces<char_t>(*inout, inout, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
template <class char_t>
|
template <class char_t>
|
||||||
AI_FORCE_INLINE bool SkipLine(const char_t *in, const char_t **out) {
|
AI_FORCE_INLINE bool SkipLine(const char_t *in, const char_t **out, const char_t *end) {
|
||||||
while (*in != (char_t)'\r' && *in != (char_t)'\n' && *in != (char_t)'\0') {
|
while ((*in != (char_t)'\r' && *in != (char_t)'\n' && *in != (char_t)'\0') && in != end) {
|
||||||
++in;
|
++in;
|
||||||
}
|
}
|
||||||
|
|
||||||
// files are opened in binary mode. Ergo there are both NL and CR
|
// files are opened in binary mode. Ergo there are both NL and CR
|
||||||
while (*in == (char_t)'\r' || *in == (char_t)'\n') {
|
while ((*in == (char_t)'\r' || *in == (char_t)'\n') && in != end) {
|
||||||
++in;
|
++in;
|
||||||
}
|
}
|
||||||
*out = in;
|
*out = in;
|
||||||
|
@ -133,14 +133,14 @@ AI_FORCE_INLINE bool SkipLine(const char_t *in, const char_t **out) {
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
template <class char_t>
|
template <class char_t>
|
||||||
AI_FORCE_INLINE bool SkipLine(const char_t **inout) {
|
AI_FORCE_INLINE bool SkipLine(const char_t **inout, const char_t *end) {
|
||||||
return SkipLine<char_t>(*inout, inout);
|
return SkipLine<char_t>(*inout, inout, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
template <class char_t>
|
template <class char_t>
|
||||||
AI_FORCE_INLINE bool SkipSpacesAndLineEnd(const char_t *in, const char_t **out) {
|
AI_FORCE_INLINE bool SkipSpacesAndLineEnd(const char_t *in, const char_t **out, const char_t *end) {
|
||||||
while (*in == (char_t)' ' || *in == (char_t)'\t' || *in == (char_t)'\r' || *in == (char_t)'\n') {
|
while ((*in == (char_t)' ' || *in == (char_t)'\t' || *in == (char_t)'\r' || *in == (char_t)'\n') && in != end) {
|
||||||
++in;
|
++in;
|
||||||
}
|
}
|
||||||
*out = in;
|
*out = in;
|
||||||
|
@ -149,8 +149,8 @@ AI_FORCE_INLINE bool SkipSpacesAndLineEnd(const char_t *in, const char_t **out)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
template <class char_t>
|
template <class char_t>
|
||||||
AI_FORCE_INLINE bool SkipSpacesAndLineEnd(const char_t **inout) {
|
AI_FORCE_INLINE bool SkipSpacesAndLineEnd(const char_t **inout, const char_t *end) {
|
||||||
return SkipSpacesAndLineEnd<char_t>(*inout, inout);
|
return SkipSpacesAndLineEnd<char_t>(*inout, inout, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
|
@ -210,16 +210,16 @@ AI_FORCE_INLINE bool TokenMatchI(const char *&in, const char *token, unsigned in
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
AI_FORCE_INLINE void SkipToken(const char *&in) {
|
AI_FORCE_INLINE void SkipToken(const char *&in, const char *end) {
|
||||||
SkipSpaces(&in);
|
SkipSpaces(&in, end);
|
||||||
while (!IsSpaceOrNewLine(*in)) {
|
while (!IsSpaceOrNewLine(*in)) {
|
||||||
++in;
|
++in;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
AI_FORCE_INLINE std::string GetNextToken(const char *&in) {
|
AI_FORCE_INLINE std::string GetNextToken(const char *&in, const char *end) {
|
||||||
SkipSpacesAndLineEnd(&in);
|
SkipSpacesAndLineEnd(&in, end);
|
||||||
const char *cur = in;
|
const char *cur = in;
|
||||||
while (!IsSpaceOrNewLine(*in)) {
|
while (!IsSpaceOrNewLine(*in)) {
|
||||||
++in;
|
++in;
|
||||||
|
|
Loading…
Reference in New Issue