next fixed warnings
parent
fb3c3048a5
commit
920535165d
|
@ -321,7 +321,7 @@ public:
|
||||||
struct Face : public FaceWithSmoothingGroup {
|
struct Face : public FaceWithSmoothingGroup {
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma warning(disable : 4315 )
|
#pragma warning(disable : 4315)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Helper structure representing a texture */
|
/** Helper structure representing a texture */
|
||||||
|
@ -341,6 +341,20 @@ struct Texture {
|
||||||
mTextureBlend = get_qnan();
|
mTextureBlend = get_qnan();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Texture(const Texture &other) :
|
||||||
|
mTextureBlend(other.mTextureBlend),
|
||||||
|
mMapName(other.mMapName),
|
||||||
|
mOffsetU(other.mOffsetU),
|
||||||
|
mOffsetV(other.mOffsetV),
|
||||||
|
mScaleU(other.mScaleU),
|
||||||
|
mScaleV(other.mScaleV),
|
||||||
|
mRotation(other.mRotation),
|
||||||
|
mMapMode(other.mMapMode),
|
||||||
|
bPrivate(other.bPrivate),
|
||||||
|
iUVSrc(other.iUVSrc) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
Texture(Texture &&other) AI_NO_EXCEPT : mTextureBlend(std::move(other.mTextureBlend)),
|
Texture(Texture &&other) AI_NO_EXCEPT : mTextureBlend(std::move(other.mTextureBlend)),
|
||||||
mMapName(std::move(mMapName)),
|
mMapName(std::move(mMapName)),
|
||||||
mOffsetU(std::move(mOffsetU)),
|
mOffsetU(std::move(mOffsetU)),
|
||||||
|
@ -400,18 +414,29 @@ struct Texture {
|
||||||
/** Helper structure representing a 3ds material */
|
/** Helper structure representing a 3ds material */
|
||||||
struct Material {
|
struct Material {
|
||||||
//! Default constructor has been deleted
|
//! Default constructor has been deleted
|
||||||
Material() = delete;
|
Material() :
|
||||||
|
mName(),
|
||||||
//! Constructor with explicit name
|
mDiffuse(ai_real(0.6), ai_real(0.6), ai_real(0.6)),
|
||||||
explicit Material(const std::string &name) :
|
|
||||||
mName(name), mDiffuse(ai_real(0.6), ai_real(0.6), ai_real(0.6)) // FIX ... we won't want object to be black
|
|
||||||
,
|
|
||||||
mSpecularExponent(ai_real(0.0)),
|
mSpecularExponent(ai_real(0.0)),
|
||||||
mShininessStrength(ai_real(1.0)),
|
mShininessStrength(ai_real(1.0)),
|
||||||
mShading(Discreet3DS::Gouraud),
|
mShading(Discreet3DS::Gouraud),
|
||||||
mTransparency(ai_real(1.0)),
|
mTransparency(ai_real(1.0)),
|
||||||
mBumpHeight(ai_real(1.0)),
|
mBumpHeight(ai_real(1.0)),
|
||||||
mTwoSided(false) {
|
mTwoSided(false) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Constructor with explicit name
|
||||||
|
explicit Material(const std::string &name) :
|
||||||
|
mName(name),
|
||||||
|
mDiffuse(ai_real(0.6), ai_real(0.6), ai_real(0.6)),
|
||||||
|
mSpecularExponent(ai_real(0.0)),
|
||||||
|
mShininessStrength(ai_real(1.0)),
|
||||||
|
mShading(Discreet3DS::Gouraud),
|
||||||
|
mTransparency(ai_real(1.0)),
|
||||||
|
mBumpHeight(ai_real(1.0)),
|
||||||
|
mTwoSided(false) {
|
||||||
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
Material(const Material &other) = default;
|
Material(const Material &other) = default;
|
||||||
|
@ -468,7 +493,9 @@ struct Material {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~Material() {}
|
virtual ~Material() {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
//! Name of the material
|
//! Name of the material
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
Open Asset Import Library (assimp)
|
Open Asset Import Library (assimp)
|
||||||
|
@ -6,8 +5,6 @@ Open Asset Import Library (assimp)
|
||||||
|
|
||||||
Copyright (c) 2006-2020, assimp team
|
Copyright (c) 2006-2020, 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,
|
||||||
|
@ -80,47 +77,60 @@ static const aiImporterDesc desc = {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// skip to the next token
|
// skip to the next token
|
||||||
#define AI_AC_SKIP_TO_NEXT_TOKEN() \
|
inline
|
||||||
if (!SkipSpaces(&buffer)) { \
|
const char *AcSkipToNextToken( const char *buffer ) {
|
||||||
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL"); \
|
if (!SkipSpaces( &buffer )) {
|
||||||
continue; \
|
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL");
|
||||||
}
|
}
|
||||||
|
return 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 "
|
||||||
#define AI_AC_GET_STRING(out) \
|
inline
|
||||||
if (*buffer == '\0') { \
|
const char *AcGetString(const char *buffer, std::string &out) {
|
||||||
throw DeadlyImportError("AC3D: Unexpected EOF in string"); \
|
if (*buffer == '\0') {
|
||||||
} \
|
throw DeadlyImportError("AC3D: Unexpected EOF in string");
|
||||||
++buffer; \
|
}
|
||||||
const char *sz = buffer; \
|
|
||||||
while ('\"' != *buffer) { \
|
|
||||||
if (IsLineEnd(*buffer)) { \
|
|
||||||
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL in string"); \
|
|
||||||
out = "ERROR"; \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
++buffer; \
|
|
||||||
} \
|
|
||||||
if (IsLineEnd(*buffer)) continue; \
|
|
||||||
out = std::string(sz, (unsigned int)(buffer - sz)); \
|
|
||||||
++buffer;
|
++buffer;
|
||||||
|
const char *sz = buffer;
|
||||||
|
while ('\"' != *buffer) {
|
||||||
|
if (IsLineEnd(*buffer)) {
|
||||||
|
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL in string");
|
||||||
|
out = "ERROR";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++buffer;
|
||||||
|
}
|
||||||
|
if (IsLineEnd(*buffer)) {
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
out = std::string(sz, (unsigned int)(buffer - sz));
|
||||||
|
++buffer;
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// read 1 to n floats prefixed with an optional predefined identifier
|
// read 1 to n floats prefixed with an optional predefined identifier
|
||||||
#define AI_AC_CHECKED_LOAD_FLOAT_ARRAY(name, name_length, num, out) \
|
template<class T>
|
||||||
AI_AC_SKIP_TO_NEXT_TOKEN(); \
|
inline
|
||||||
if (name_length) { \
|
const char *TAcCheckedLoadFloatArray(const char *buffer, const char *name, size_t name_length, size_t num, T *out) {
|
||||||
if (strncmp(buffer, name, name_length) || !IsSpace(buffer[name_length])) { \
|
AcSkipToNextToken(buffer);
|
||||||
ASSIMP_LOG_ERROR("AC3D: Unexpexted token. " name " was expected."); \
|
if (0 != name_length) {
|
||||||
continue; \
|
if (0 != strncmp(buffer, name, name_length) || !IsSpace(buffer[name_length])) {
|
||||||
} \
|
ASSIMP_LOG_ERROR("AC3D: Unexpexted token. " + std::string( name ) + " was expected.");
|
||||||
buffer += name_length + 1; \
|
return buffer;
|
||||||
} \
|
|
||||||
for (unsigned int _i = 0; _i < num; ++_i) { \
|
|
||||||
AI_AC_SKIP_TO_NEXT_TOKEN(); \
|
|
||||||
buffer = fast_atoreal_move<float>(buffer, ((float *)out)[_i]); \
|
|
||||||
}
|
}
|
||||||
|
buffer += name_length + 1;
|
||||||
|
}
|
||||||
|
for (unsigned int _i = 0; _i < num; ++_i) {
|
||||||
|
AcSkipToNextToken(buffer);
|
||||||
|
buffer = fast_atoreal_move<float>(buffer, ((float *)out)[_i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructor to be privately used by Importer
|
// Constructor to be privately used by Importer
|
||||||
|
@ -222,7 +232,7 @@ void AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
|
||||||
return;
|
return;
|
||||||
} else if (TokenMatch(buffer, "name", 4)) {
|
} else if (TokenMatch(buffer, "name", 4)) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&buffer);
|
||||||
AI_AC_GET_STRING(obj.name);
|
buffer = AcGetString(buffer, 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.
|
||||||
|
@ -231,21 +241,21 @@ void AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
|
||||||
}
|
}
|
||||||
} else if (TokenMatch(buffer, "texture", 7)) {
|
} else if (TokenMatch(buffer, "texture", 7)) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&buffer);
|
||||||
AI_AC_GET_STRING(obj.texture);
|
buffer = AcGetString(buffer, obj.texture);
|
||||||
} else if (TokenMatch(buffer, "texrep", 6)) {
|
} else if (TokenMatch(buffer, "texrep", 6)) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&buffer);
|
||||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("", 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(buffer, "texoff", 6)) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&buffer);
|
||||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("", 0, 2, &obj.texOffset);
|
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &obj.texOffset);
|
||||||
} else if (TokenMatch(buffer, "rot", 3)) {
|
} else if (TokenMatch(buffer, "rot", 3)) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&buffer);
|
||||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("", 0, 9, &obj.rotation);
|
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 9, &obj.rotation);
|
||||||
} else if (TokenMatch(buffer, "loc", 3)) {
|
} else if (TokenMatch(buffer, "loc", 3)) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&buffer);
|
||||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("", 0, 3, &obj.translation);
|
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 3, &obj.translation);
|
||||||
} else if (TokenMatch(buffer, "subdiv", 6)) {
|
} else if (TokenMatch(buffer, "subdiv", 6)) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&buffer);
|
||||||
obj.subDiv = strtoul10(buffer, &buffer);
|
obj.subDiv = strtoul10(buffer, &buffer);
|
||||||
|
@ -271,7 +281,7 @@ void AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
|
||||||
}
|
}
|
||||||
obj.vertices.push_back(aiVector3D());
|
obj.vertices.push_back(aiVector3D());
|
||||||
aiVector3D &v = obj.vertices.back();
|
aiVector3D &v = obj.vertices.back();
|
||||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("", 0, 3, &v.x);
|
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 3, &v.x);
|
||||||
}
|
}
|
||||||
} else if (TokenMatch(buffer, "numsurf", 7)) {
|
} else if (TokenMatch(buffer, "numsurf", 7)) {
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&buffer);
|
||||||
|
@ -331,10 +341,9 @@ void AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
|
||||||
|
|
||||||
entry.first = strtoul10(buffer, &buffer);
|
entry.first = strtoul10(buffer, &buffer);
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&buffer);
|
||||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("", 0, 2, &entry.second);
|
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &entry.second);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
--buffer; // make sure the line is processed a second time
|
--buffer; // make sure the line is processed a second time
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -496,7 +505,9 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
|
||||||
const size_t oldm = meshes.size();
|
const size_t oldm = meshes.size();
|
||||||
for (MatTable::const_iterator cit = needMat.begin(), cend = needMat.end();
|
for (MatTable::const_iterator cit = needMat.begin(), cend = needMat.end();
|
||||||
cit != cend; ++cit, ++mat) {
|
cit != cend; ++cit, ++mat) {
|
||||||
if (!(*cit).first) continue;
|
if (!(*cit).first) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// allocate a new aiMesh object
|
// allocate a new aiMesh object
|
||||||
*pip++ = (unsigned int)meshes.size();
|
*pip++ = (unsigned int)meshes.size();
|
||||||
|
@ -541,7 +552,8 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
|
||||||
unsigned int type = (*it).flags & 0xf;
|
unsigned int type = (*it).flags & 0xf;
|
||||||
if (!type) {
|
if (!type) {
|
||||||
aiFace &face = *faces++;
|
aiFace &face = *faces++;
|
||||||
if ((face.mNumIndices = (unsigned int)src.entries.size())) {
|
face.mNumIndices = (unsigned int)src.entries.size();
|
||||||
|
if (0 != face.mNumIndices) {
|
||||||
face.mIndices = new unsigned int[face.mNumIndices];
|
face.mIndices = new unsigned int[face.mNumIndices];
|
||||||
for (unsigned int i = 0; i < face.mNumIndices; ++i, ++vertices) {
|
for (unsigned int i = 0; i < face.mNumIndices; ++i, ++vertices) {
|
||||||
const Surface::SurfaceEntry &entry = src.entries[i];
|
const Surface::SurfaceEntry &entry = src.entries[i];
|
||||||
|
@ -726,18 +738,18 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
|
||||||
// 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
|
||||||
|
|
||||||
AI_AC_SKIP_TO_NEXT_TOKEN();
|
buffer = AcSkipToNextToken(buffer);
|
||||||
if ('\"' == *buffer) {
|
if ('\"' == *buffer) {
|
||||||
AI_AC_GET_STRING(mat.name);
|
buffer = AcGetString(buffer, mat.name);
|
||||||
AI_AC_SKIP_TO_NEXT_TOKEN();
|
buffer = AcSkipToNextToken(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("rgb", 3, 3, &mat.rgb);
|
buffer = TAcCheckedLoadFloatArray(buffer, "rgb", 3, 3, &mat.rgb);
|
||||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("amb", 3, 3, &mat.amb);
|
buffer = TAcCheckedLoadFloatArray(buffer, "amb", 3, 3, &mat.amb);
|
||||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("emis", 4, 3, &mat.emis);
|
buffer = TAcCheckedLoadFloatArray(buffer, "emis", 4, 3, &mat.emis);
|
||||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("spec", 4, 3, &mat.spec);
|
buffer = TAcCheckedLoadFloatArray(buffer, "spec", 4, 3, &mat.spec);
|
||||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("shi", 3, 1, &mat.shin);
|
buffer = TAcCheckedLoadFloatArray(buffer, "shi", 3, 1, &mat.shin);
|
||||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("trans", 5, 1, &mat.trans);
|
buffer = TAcCheckedLoadFloatArray(buffer, "trans", 5, 1, &mat.trans);
|
||||||
}
|
}
|
||||||
LoadObjectSection(rootObjects);
|
LoadObjectSection(rootObjects);
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,8 +68,6 @@ public:
|
||||||
AC3DImporter();
|
AC3DImporter();
|
||||||
~AC3DImporter();
|
~AC3DImporter();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Represents an AC3D material
|
// Represents an AC3D material
|
||||||
struct Material
|
struct Material
|
||||||
{
|
{
|
||||||
|
@ -245,8 +243,6 @@ private:
|
||||||
aiMaterial& matDest);
|
aiMaterial& matDest);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
// points to the next data line
|
// points to the next data line
|
||||||
const char* buffer;
|
const char* buffer;
|
||||||
|
|
||||||
|
|
|
@ -429,7 +429,7 @@ void BlenderImporter::ResolveImage(aiMaterial* out, const Material* mat, const M
|
||||||
name.length = 1+ ASSIMP_itoa10(name.data+1,static_cast<unsigned int>(MAXLEN-1), static_cast<int32_t>(conv_data.textures->size()));
|
name.length = 1+ ASSIMP_itoa10(name.data+1,static_cast<unsigned int>(MAXLEN-1), static_cast<int32_t>(conv_data.textures->size()));
|
||||||
|
|
||||||
conv_data.textures->push_back(new aiTexture());
|
conv_data.textures->push_back(new aiTexture());
|
||||||
aiTexture* tex = conv_data.textures->back();
|
aiTexture* curTex = conv_data.textures->back();
|
||||||
|
|
||||||
// usually 'img->name' will be the original file name of the embedded textures,
|
// usually 'img->name' will be the original file name of the embedded textures,
|
||||||
// so we can extract the file extension from it.
|
// so we can extract the file extension from it.
|
||||||
|
@ -439,19 +439,19 @@ void BlenderImporter::ResolveImage(aiMaterial* out, const Material* mat, const M
|
||||||
--s;
|
--s;
|
||||||
}
|
}
|
||||||
|
|
||||||
tex->achFormatHint[0] = s+1>e ? '\0' : ::tolower( s[1] );
|
curTex->achFormatHint[0] = s + 1 > e ? '\0' : (char)::tolower(s[1]);
|
||||||
tex->achFormatHint[1] = s+2>e ? '\0' : ::tolower( s[2] );
|
curTex->achFormatHint[1] = s + 2 > e ? '\0' : (char)::tolower(s[2]);
|
||||||
tex->achFormatHint[2] = s+3>e ? '\0' : ::tolower( s[3] );
|
curTex->achFormatHint[2] = s + 3 > e ? '\0' : (char)::tolower(s[3]);
|
||||||
tex->achFormatHint[3] = '\0';
|
curTex->achFormatHint[3] = '\0';
|
||||||
|
|
||||||
// tex->mHeight = 0;
|
// tex->mHeight = 0;
|
||||||
tex->mWidth = img->packedfile->size;
|
curTex->mWidth = img->packedfile->size;
|
||||||
uint8_t* ch = new uint8_t[tex->mWidth];
|
uint8_t *ch = new uint8_t[curTex->mWidth];
|
||||||
|
|
||||||
conv_data.db.reader->SetCurrentPos(static_cast<size_t>( img->packedfile->data->val));
|
conv_data.db.reader->SetCurrentPos(static_cast<size_t>( img->packedfile->data->val));
|
||||||
conv_data.db.reader->CopyAndAdvance(ch,tex->mWidth);
|
conv_data.db.reader->CopyAndAdvance(ch, curTex->mWidth);
|
||||||
|
|
||||||
tex->pcData = reinterpret_cast<aiTexel*>(ch);
|
curTex->pcData = reinterpret_cast<aiTexel *>(ch);
|
||||||
|
|
||||||
LogInfo("Reading embedded texture, original file was "+std::string(img->name));
|
LogInfo("Reading embedded texture, original file was "+std::string(img->name));
|
||||||
} else {
|
} else {
|
||||||
|
@ -1078,9 +1078,9 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
|
||||||
const aiFace& f = out->mFaces[out->mNumFaces++];
|
const aiFace& f = out->mFaces[out->mNumFaces++];
|
||||||
|
|
||||||
aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
|
aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
|
||||||
for (unsigned int i = 0; i < f.mNumIndices; ++i,++vo,++out->mNumVertices) {
|
for (unsigned int j = 0; j < f.mNumIndices; ++j,++vo,++out->mNumVertices) {
|
||||||
vo->x = v->uv[i][0];
|
vo->x = v->uv[j][0];
|
||||||
vo->y = v->uv[i][1];
|
vo->y = v->uv[j][1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1098,8 +1098,7 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
|
||||||
vo->x = uv.uv[0];
|
vo->x = uv.uv[0];
|
||||||
vo->y = uv.uv[1];
|
vo->y = uv.uv[1];
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// create textureCoords for every mapped tex
|
// create textureCoords for every mapped tex
|
||||||
for (uint32_t m = 0; m < itMatTexUvMapping->second.size(); ++m) {
|
for (uint32_t m = 0; m < itMatTexUvMapping->second.size(); ++m) {
|
||||||
const MLoopUV *tm = itMatTexUvMapping->second[m];
|
const MLoopUV *tm = itMatTexUvMapping->second[m];
|
||||||
|
@ -1139,9 +1138,9 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
|
||||||
const aiFace& f = out->mFaces[out->mNumFaces++];
|
const aiFace& f = out->mFaces[out->mNumFaces++];
|
||||||
|
|
||||||
aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
|
aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
|
||||||
for (unsigned int i = 0; i < f.mNumIndices; ++i,++vo,++out->mNumVertices) {
|
for (unsigned int j = 0; j < f.mNumIndices; ++j,++vo,++out->mNumVertices) {
|
||||||
vo->x = v->uv[i][0];
|
vo->x = v->uv[j][0];
|
||||||
vo->y = v->uv[i][1];
|
vo->y = v->uv[j][1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,12 +57,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
using namespace Assimp::Blender;
|
using namespace Assimp::Blender;
|
||||||
|
|
||||||
template <typename T> BlenderModifier* god() {
|
template <typename T>
|
||||||
|
BlenderModifier *god() {
|
||||||
return new T();
|
return new T();
|
||||||
}
|
}
|
||||||
|
|
||||||
// add all available modifiers here
|
// add all available modifiers here
|
||||||
typedef BlenderModifier* (*fpCreateModifier)();
|
typedef BlenderModifier *(*fpCreateModifier)();
|
||||||
static const fpCreateModifier creators[] = {
|
static const fpCreateModifier creators[] = {
|
||||||
&god<BlenderModifier_Mirror>,
|
&god<BlenderModifier_Mirror>,
|
||||||
&god<BlenderModifier_Subdivision>,
|
&god<BlenderModifier_Subdivision>,
|
||||||
|
@ -71,38 +72,36 @@ static const fpCreateModifier creators[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
struct SharedModifierData : ElemBase
|
struct SharedModifierData : ElemBase {
|
||||||
{
|
|
||||||
ModifierData modifier;
|
ModifierData modifier;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_data, const Scene& in, const Object& orig_object )
|
void BlenderModifierShowcase::ApplyModifiers(aiNode &out, ConversionData &conv_data, const Scene &in, const Object &orig_object) {
|
||||||
{
|
|
||||||
size_t cnt = 0u, ful = 0u;
|
size_t cnt = 0u, ful = 0u;
|
||||||
|
|
||||||
// NOTE: this cast is potentially unsafe by design, so we need to perform type checks before
|
// NOTE: this cast is potentially unsafe by design, so we need to perform type checks before
|
||||||
// we're allowed to dereference the pointers without risking to crash. We might still be
|
// we're allowed to dereference the pointers without risking to crash. We might still be
|
||||||
// invoking UB btw - we're assuming that the ModifierData member of the respective modifier
|
// invoking UB btw - we're assuming that the ModifierData member of the respective modifier
|
||||||
// structures is at offset sizeof(vftable) with no padding.
|
// structures is at offset sizeof(vftable) with no padding.
|
||||||
const SharedModifierData* cur = static_cast<const SharedModifierData *> ( orig_object.modifiers.first.get() );
|
const SharedModifierData *cur = static_cast<const SharedModifierData *>(orig_object.modifiers.first.get());
|
||||||
for (; cur; cur = static_cast<const SharedModifierData *> ( cur->modifier.next.get() ), ++ful) {
|
for (; cur; cur = static_cast<const SharedModifierData *>(cur->modifier.next.get()), ++ful) {
|
||||||
ai_assert(cur->dna_type);
|
ai_assert(cur->dna_type);
|
||||||
|
|
||||||
const Structure* s = conv_data.db.dna.Get( cur->dna_type );
|
const Structure *s = conv_data.db.dna.Get(cur->dna_type);
|
||||||
if (!s) {
|
if (!s) {
|
||||||
ASSIMP_LOG_WARN_F("BlendModifier: could not resolve DNA name: ",cur->dna_type);
|
ASSIMP_LOG_WARN_F("BlendModifier: could not resolve DNA name: ", cur->dna_type);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is a common trait of all XXXMirrorData structures in BlenderDNA
|
// this is a common trait of all XXXMirrorData structures in BlenderDNA
|
||||||
const Field* f = s->Get("modifier");
|
const Field *f = s->Get("modifier");
|
||||||
if (!f || f->offset != 0) {
|
if (!f || f->offset != 0) {
|
||||||
ASSIMP_LOG_WARN("BlendModifier: expected a `modifier` member at offset 0");
|
ASSIMP_LOG_WARN("BlendModifier: expected a `modifier` member at offset 0");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
s = conv_data.db.dna.Get( f->type );
|
s = conv_data.db.dna.Get(f->type);
|
||||||
if (!s || s->name != "ModifierData") {
|
if (!s || s->name != "ModifierData") {
|
||||||
ASSIMP_LOG_WARN("BlendModifier: expected a ModifierData structure as first member");
|
ASSIMP_LOG_WARN("BlendModifier: expected a ModifierData structure as first member");
|
||||||
continue;
|
continue;
|
||||||
|
@ -110,22 +109,22 @@ void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_d
|
||||||
|
|
||||||
// now, we can be sure that we should be fine to dereference *cur* as
|
// now, we can be sure that we should be fine to dereference *cur* as
|
||||||
// ModifierData (with the above note).
|
// ModifierData (with the above note).
|
||||||
const ModifierData& dat = cur->modifier;
|
const ModifierData &dat = cur->modifier;
|
||||||
|
|
||||||
const fpCreateModifier* curgod = creators;
|
const fpCreateModifier *curgod = creators;
|
||||||
std::vector< BlenderModifier* >::iterator curmod = cached_modifiers->begin(), endmod = cached_modifiers->end();
|
std::vector<BlenderModifier *>::iterator curmod = cached_modifiers->begin(), endmod = cached_modifiers->end();
|
||||||
|
|
||||||
for (;*curgod;++curgod,++curmod) { // allocate modifiers on the fly
|
for (; *curgod; ++curgod, ++curmod) { // allocate modifiers on the fly
|
||||||
if (curmod == endmod) {
|
if (curmod == endmod) {
|
||||||
cached_modifiers->push_back((*curgod)());
|
cached_modifiers->push_back((*curgod)());
|
||||||
|
|
||||||
endmod = cached_modifiers->end();
|
endmod = cached_modifiers->end();
|
||||||
curmod = endmod-1;
|
curmod = endmod - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
BlenderModifier* const modifier = *curmod;
|
BlenderModifier *const modifier = *curmod;
|
||||||
if(modifier->IsActive(dat)) {
|
if (modifier->IsActive(dat)) {
|
||||||
modifier->DoIt(out,conv_data,*static_cast<const ElemBase *>(cur),in,orig_object);
|
modifier->DoIt(out, conv_data, *static_cast<const ElemBase *>(cur), in, orig_object);
|
||||||
cnt++;
|
cnt++;
|
||||||
|
|
||||||
curgod = NULL;
|
curgod = NULL;
|
||||||
|
@ -133,7 +132,7 @@ void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (curgod) {
|
if (curgod) {
|
||||||
ASSIMP_LOG_WARN_F("Couldn't find a handler for modifier: ",dat.name);
|
ASSIMP_LOG_WARN_F("Couldn't find a handler for modifier: ", dat.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,26 +140,22 @@ void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_d
|
||||||
// object, we still can't say whether our modifier implementations were
|
// object, we still can't say whether our modifier implementations were
|
||||||
// able to fully do their job.
|
// able to fully do their job.
|
||||||
if (ful) {
|
if (ful) {
|
||||||
ASSIMP_LOG_DEBUG_F("BlendModifier: found handlers for ",cnt," of ",ful," modifiers on `",orig_object.id.name,
|
ASSIMP_LOG_DEBUG_F("BlendModifier: found handlers for ", cnt, " of ", ful, " modifiers on `", orig_object.id.name,
|
||||||
"`, check log messages above for errors");
|
"`, check log messages above for errors");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool BlenderModifier_Mirror :: IsActive (const ModifierData& modin)
|
bool BlenderModifier_Mirror ::IsActive(const ModifierData &modin) {
|
||||||
{
|
|
||||||
return modin.type == ModifierData::eModifierType_Mirror;
|
return modin.type == ModifierData::eModifierType_Mirror;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, const ElemBase& orig_modifier,
|
void BlenderModifier_Mirror ::DoIt(aiNode &out, ConversionData &conv_data, const ElemBase &orig_modifier,
|
||||||
const Scene& /*in*/,
|
const Scene & /*in*/,
|
||||||
const Object& orig_object )
|
const Object &orig_object) {
|
||||||
{
|
|
||||||
// hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
|
// hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
|
||||||
const MirrorModifierData& mir = static_cast<const MirrorModifierData&>(orig_modifier);
|
const MirrorModifierData &mir = static_cast<const MirrorModifierData &>(orig_modifier);
|
||||||
ai_assert(mir.modifier.type == ModifierData::eModifierType_Mirror);
|
ai_assert(mir.modifier.type == ModifierData::eModifierType_Mirror);
|
||||||
|
|
||||||
conv_data.meshes->reserve(conv_data.meshes->size() + out.mNumMeshes);
|
conv_data.meshes->reserve(conv_data.meshes->size() + out.mNumMeshes);
|
||||||
|
@ -169,48 +164,55 @@ void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, co
|
||||||
|
|
||||||
// take all input meshes and clone them
|
// take all input meshes and clone them
|
||||||
for (unsigned int i = 0; i < out.mNumMeshes; ++i) {
|
for (unsigned int i = 0; i < out.mNumMeshes; ++i) {
|
||||||
aiMesh* mesh;
|
aiMesh *mesh;
|
||||||
SceneCombiner::Copy(&mesh,conv_data.meshes[out.mMeshes[i]]);
|
SceneCombiner::Copy(&mesh, conv_data.meshes[out.mMeshes[i]]);
|
||||||
|
|
||||||
const float xs = mir.flag & MirrorModifierData::Flags_AXIS_X ? -1.f : 1.f;
|
const float xs = mir.flag & MirrorModifierData::Flags_AXIS_X ? -1.f : 1.f;
|
||||||
const float ys = mir.flag & MirrorModifierData::Flags_AXIS_Y ? -1.f : 1.f;
|
const float ys = mir.flag & MirrorModifierData::Flags_AXIS_Y ? -1.f : 1.f;
|
||||||
const float zs = mir.flag & MirrorModifierData::Flags_AXIS_Z ? -1.f : 1.f;
|
const float zs = mir.flag & MirrorModifierData::Flags_AXIS_Z ? -1.f : 1.f;
|
||||||
|
|
||||||
if (mir.mirror_ob) {
|
if (mir.mirror_ob) {
|
||||||
const aiVector3D center( mir.mirror_ob->obmat[3][0],mir.mirror_ob->obmat[3][1],mir.mirror_ob->obmat[3][2] );
|
const aiVector3D center(mir.mirror_ob->obmat[3][0], mir.mirror_ob->obmat[3][1], mir.mirror_ob->obmat[3][2]);
|
||||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
|
||||||
aiVector3D& v = mesh->mVertices[i];
|
aiVector3D &v = mesh->mVertices[j];
|
||||||
|
|
||||||
v.x = center.x + xs*(center.x - v.x);
|
v.x = center.x + xs * (center.x - v.x);
|
||||||
v.y = center.y + ys*(center.y - v.y);
|
v.y = center.y + ys * (center.y - v.y);
|
||||||
v.z = center.z + zs*(center.z - v.z);
|
v.z = center.z + zs * (center.z - v.z);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
|
||||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
aiVector3D &v = mesh->mVertices[j];
|
||||||
aiVector3D& v = mesh->mVertices[i];
|
v.x *= xs;
|
||||||
v.x *= xs;v.y *= ys;v.z *= zs;
|
v.y *= ys;
|
||||||
|
v.z *= zs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mesh->mNormals) {
|
if (mesh->mNormals) {
|
||||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
|
||||||
aiVector3D& v = mesh->mNormals[i];
|
aiVector3D &v = mesh->mNormals[j];
|
||||||
v.x *= xs;v.y *= ys;v.z *= zs;
|
v.x *= xs;
|
||||||
|
v.y *= ys;
|
||||||
|
v.z *= zs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mesh->mTangents) {
|
if (mesh->mTangents) {
|
||||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
|
||||||
aiVector3D& v = mesh->mTangents[i];
|
aiVector3D &v = mesh->mTangents[j];
|
||||||
v.x *= xs;v.y *= ys;v.z *= zs;
|
v.x *= xs;
|
||||||
|
v.y *= ys;
|
||||||
|
v.z *= zs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mesh->mBitangents) {
|
if (mesh->mBitangents) {
|
||||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
|
||||||
aiVector3D& v = mesh->mBitangents[i];
|
aiVector3D &v = mesh->mBitangents[j];
|
||||||
v.x *= xs;v.y *= ys;v.z *= zs;
|
v.x *= xs;
|
||||||
|
v.y *= ys;
|
||||||
|
v.z *= zs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,27 +220,28 @@ void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, co
|
||||||
const float vs = mir.flag & MirrorModifierData::Flags_MIRROR_V ? -1.f : 1.f;
|
const float vs = mir.flag & MirrorModifierData::Flags_MIRROR_V ? -1.f : 1.f;
|
||||||
|
|
||||||
for (unsigned int n = 0; mesh->HasTextureCoords(n); ++n) {
|
for (unsigned int n = 0; mesh->HasTextureCoords(n); ++n) {
|
||||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
|
||||||
aiVector3D& v = mesh->mTextureCoords[n][i];
|
aiVector3D &v = mesh->mTextureCoords[n][j];
|
||||||
v.x *= us;v.y *= vs;
|
v.x *= us;
|
||||||
|
v.y *= vs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only reverse the winding order if an odd number of axes were mirrored.
|
// Only reverse the winding order if an odd number of axes were mirrored.
|
||||||
if (xs * ys * zs < 0) {
|
if (xs * ys * zs < 0) {
|
||||||
for( unsigned int i = 0; i < mesh->mNumFaces; i++) {
|
for (unsigned int j = 0; j < mesh->mNumFaces; ++j ) {
|
||||||
aiFace& face = mesh->mFaces[i];
|
aiFace &face = mesh->mFaces[j];
|
||||||
for( unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi)
|
for (unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi)
|
||||||
std::swap( face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]);
|
std::swap(face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
conv_data.meshes->push_back(mesh);
|
conv_data.meshes->push_back(mesh);
|
||||||
}
|
}
|
||||||
unsigned int* nind = new unsigned int[out.mNumMeshes*2];
|
unsigned int *nind = new unsigned int[out.mNumMeshes * 2];
|
||||||
|
|
||||||
std::copy(out.mMeshes,out.mMeshes+out.mNumMeshes,nind);
|
std::copy(out.mMeshes, out.mMeshes + out.mNumMeshes, nind);
|
||||||
std::transform(out.mMeshes,out.mMeshes+out.mNumMeshes,nind+out.mNumMeshes,
|
std::transform(out.mMeshes, out.mMeshes + out.mNumMeshes, nind + out.mNumMeshes,
|
||||||
[&out](unsigned int n) { return out.mNumMeshes + n; });
|
[&out](unsigned int n) { return out.mNumMeshes + n; });
|
||||||
|
|
||||||
delete[] out.mMeshes;
|
delete[] out.mMeshes;
|
||||||
|
@ -246,27 +249,24 @@ void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, co
|
||||||
out.mNumMeshes *= 2;
|
out.mNumMeshes *= 2;
|
||||||
|
|
||||||
ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Mirror` modifier to `",
|
ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Mirror` modifier to `",
|
||||||
orig_object.id.name,"`");
|
orig_object.id.name, "`");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool BlenderModifier_Subdivision :: IsActive (const ModifierData& modin)
|
bool BlenderModifier_Subdivision ::IsActive(const ModifierData &modin) {
|
||||||
{
|
|
||||||
return modin.type == ModifierData::eModifierType_Subsurf;
|
return modin.type == ModifierData::eModifierType_Subsurf;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void BlenderModifier_Subdivision :: DoIt(aiNode& out, ConversionData& conv_data, const ElemBase& orig_modifier,
|
void BlenderModifier_Subdivision ::DoIt(aiNode &out, ConversionData &conv_data, const ElemBase &orig_modifier,
|
||||||
const Scene& /*in*/,
|
const Scene & /*in*/,
|
||||||
const Object& orig_object )
|
const Object &orig_object) {
|
||||||
{
|
|
||||||
// hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
|
// hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
|
||||||
const SubsurfModifierData& mir = static_cast<const SubsurfModifierData&>(orig_modifier);
|
const SubsurfModifierData &mir = static_cast<const SubsurfModifierData &>(orig_modifier);
|
||||||
ai_assert(mir.modifier.type == ModifierData::eModifierType_Subsurf);
|
ai_assert(mir.modifier.type == ModifierData::eModifierType_Subsurf);
|
||||||
|
|
||||||
Subdivider::Algorithm algo;
|
Subdivider::Algorithm algo;
|
||||||
switch (mir.subdivType)
|
switch (mir.subdivType) {
|
||||||
{
|
|
||||||
case SubsurfModifierData::TYPE_CatmullClarke:
|
case SubsurfModifierData::TYPE_CatmullClarke:
|
||||||
algo = Subdivider::CATMULL_CLARKE;
|
algo = Subdivider::CATMULL_CLARKE;
|
||||||
break;
|
break;
|
||||||
|
@ -277,23 +277,23 @@ void BlenderModifier_Subdivision :: DoIt(aiNode& out, ConversionData& conv_data
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ",mir.subdivType);
|
ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ", mir.subdivType);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<Subdivider> subd(Subdivider::Create(algo));
|
std::unique_ptr<Subdivider> subd(Subdivider::Create(algo));
|
||||||
ai_assert(subd);
|
ai_assert(subd);
|
||||||
if ( conv_data.meshes->empty() ) {
|
if (conv_data.meshes->empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
aiMesh** const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes];
|
aiMesh **const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes];
|
||||||
std::unique_ptr<aiMesh*[]> tempmeshes(new aiMesh*[out.mNumMeshes]());
|
std::unique_ptr<aiMesh *[]> tempmeshes(new aiMesh *[out.mNumMeshes]());
|
||||||
|
|
||||||
subd->Subdivide(meshes,out.mNumMeshes,tempmeshes.get(),std::max( mir.renderLevels, mir.levels ),true);
|
subd->Subdivide(meshes, out.mNumMeshes, tempmeshes.get(), std::max(mir.renderLevels, mir.levels), true);
|
||||||
std::copy(tempmeshes.get(),tempmeshes.get()+out.mNumMeshes,meshes);
|
std::copy(tempmeshes.get(), tempmeshes.get() + out.mNumMeshes, meshes);
|
||||||
|
|
||||||
ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Subdivision` modifier to `",
|
ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Subdivision` modifier to `",
|
||||||
orig_object.id.name,"`");
|
orig_object.id.name, "`");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER
|
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER
|
||||||
|
|
|
@ -1015,8 +1015,8 @@ void COBImporter::ReadPolH_Binary(COB::Scene& out, StreamReaderLE& reader, const
|
||||||
// XXX backface culling flag is 0x10 in flags
|
// XXX backface culling flag is 0x10 in flags
|
||||||
|
|
||||||
// hole?
|
// hole?
|
||||||
bool hole;
|
bool hole = (reader.GetI1() & 0x08) != 0;
|
||||||
if ((hole = (reader.GetI1() & 0x08) != 0)) {
|
if ( hole ) {
|
||||||
// XXX Basically this should just work fine - then triangulator
|
// XXX Basically this should just work fine - then triangulator
|
||||||
// should output properly triangulated data even for polygons
|
// should output properly triangulated data even for polygons
|
||||||
// with holes. Test data specific to COB is needed to confirm it.
|
// with holes. Test data specific to COB is needed to confirm it.
|
||||||
|
|
|
@ -75,10 +75,10 @@ struct Face
|
||||||
|
|
||||||
// ------------------
|
// ------------------
|
||||||
/** COB chunk header information */
|
/** COB chunk header information */
|
||||||
|
const unsigned int NO_SIZE = UINT_MAX;
|
||||||
|
|
||||||
struct ChunkInfo
|
struct ChunkInfo
|
||||||
{
|
{
|
||||||
enum {NO_SIZE=UINT_MAX};
|
|
||||||
|
|
||||||
ChunkInfo ()
|
ChunkInfo ()
|
||||||
: id (0)
|
: id (0)
|
||||||
, parent_id (0)
|
, parent_id (0)
|
||||||
|
|
|
@ -714,8 +714,8 @@ void ColladaParser::ReadAnimation(Collada::Animation* pParent)
|
||||||
else if (IsElement("sampler"))
|
else if (IsElement("sampler"))
|
||||||
{
|
{
|
||||||
// read the ID to assign the corresponding collada channel afterwards.
|
// read the ID to assign the corresponding collada channel afterwards.
|
||||||
int indexID = GetAttribute("id");
|
int indexId = GetAttribute("id");
|
||||||
std::string id = mReader->getAttributeValue(indexID);
|
std::string id = mReader->getAttributeValue(indexId);
|
||||||
ChannelMap::iterator newChannel = channels.insert(std::make_pair(id, AnimationChannel())).first;
|
ChannelMap::iterator newChannel = channels.insert(std::make_pair(id, AnimationChannel())).first;
|
||||||
|
|
||||||
// have it read into a channel
|
// have it read into a channel
|
||||||
|
@ -3339,13 +3339,12 @@ void ColladaParser::TestClosing(const char* pName) {
|
||||||
// Returns the index of the named attribute or -1 if not found. Does not throw, therefore useful for optional attributes
|
// Returns the index of the named attribute or -1 if not found. Does not throw, therefore useful for optional attributes
|
||||||
int ColladaParser::GetAttribute(const char* pAttr) const {
|
int ColladaParser::GetAttribute(const char* pAttr) const {
|
||||||
int index = TestAttribute(pAttr);
|
int index = TestAttribute(pAttr);
|
||||||
if (index != -1) {
|
if (index == -1) {
|
||||||
return index;
|
ThrowException(format() << "Expected attribute \"" << pAttr << "\" for element <" << mReader->getNodeName() << ">.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// attribute not found -> throw an exception
|
// attribute not found -> throw an exception
|
||||||
ThrowException(format() << "Expected attribute \"" << pAttr << "\" for element <" << mReader->getNodeName() << ">.");
|
return index;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -428,8 +428,8 @@ void Document::ReadPropertyTemplates()
|
||||||
const ElementCollection otypes = sdefs.GetCollection("ObjectType");
|
const ElementCollection otypes = sdefs.GetCollection("ObjectType");
|
||||||
for(ElementMap::const_iterator it = otypes.first; it != otypes.second; ++it) {
|
for(ElementMap::const_iterator it = otypes.first; it != otypes.second; ++it) {
|
||||||
const Element& el = *(*it).second;
|
const Element& el = *(*it).second;
|
||||||
const Scope* sc = el.Compound();
|
const Scope* curSc = el.Compound();
|
||||||
if(!sc) {
|
if (!curSc) {
|
||||||
DOMWarning("expected nested scope in ObjectType, ignoring",&el);
|
DOMWarning("expected nested scope in ObjectType, ignoring",&el);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -442,24 +442,24 @@ void Document::ReadPropertyTemplates()
|
||||||
|
|
||||||
const std::string& oname = ParseTokenAsString(*tok[0]);
|
const std::string& oname = ParseTokenAsString(*tok[0]);
|
||||||
|
|
||||||
const ElementCollection templs = sc->GetCollection("PropertyTemplate");
|
const ElementCollection templs = curSc->GetCollection("PropertyTemplate");
|
||||||
for(ElementMap::const_iterator it = templs.first; it != templs.second; ++it) {
|
for (ElementMap::const_iterator elemIt = templs.first; elemIt != templs.second; ++elemIt) {
|
||||||
const Element& el = *(*it).second;
|
const Element &innerEl = *(*elemIt).second;
|
||||||
const Scope* sc = el.Compound();
|
const Scope *innerSc = innerEl.Compound();
|
||||||
if(!sc) {
|
if (!innerSc) {
|
||||||
DOMWarning("expected nested scope in PropertyTemplate, ignoring",&el);
|
DOMWarning("expected nested scope in PropertyTemplate, ignoring",&el);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TokenList& tok = el.Tokens();
|
const TokenList &curTok = innerEl.Tokens();
|
||||||
if(tok.empty()) {
|
if (curTok.empty()) {
|
||||||
DOMWarning("expected name for PropertyTemplate element, ignoring",&el);
|
DOMWarning("expected name for PropertyTemplate element, ignoring",&el);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& pname = ParseTokenAsString(*tok[0]);
|
const std::string &pname = ParseTokenAsString(*curTok[0]);
|
||||||
|
|
||||||
const Element* Properties70 = (*sc)["Properties70"];
|
const Element *Properties70 = (*innerSc)["Properties70"];
|
||||||
if(Properties70) {
|
if(Properties70) {
|
||||||
std::shared_ptr<const PropertyTable> props = std::make_shared<const PropertyTable>(
|
std::shared_ptr<const PropertyTable> props = std::make_shared<const PropertyTable>(
|
||||||
*Properties70,std::shared_ptr<const PropertyTable>(static_cast<const PropertyTable*>(NULL))
|
*Properties70,std::shared_ptr<const PropertyTable>(static_cast<const PropertyTable*>(NULL))
|
||||||
|
@ -529,8 +529,8 @@ const std::vector<const AnimationStack*>& Document::AnimationStacks() const
|
||||||
animationStacksResolved.reserve(animationStacks.size());
|
animationStacksResolved.reserve(animationStacks.size());
|
||||||
for(uint64_t id : animationStacks) {
|
for(uint64_t id : animationStacks) {
|
||||||
LazyObject* const lazy = GetObject(id);
|
LazyObject* const lazy = GetObject(id);
|
||||||
const AnimationStack* stack;
|
const AnimationStack *stack = lazy->Get<AnimationStack>();
|
||||||
if(!lazy || !(stack = lazy->Get<AnimationStack>())) {
|
if(!lazy || nullptr == stack ) {
|
||||||
DOMWarning("failed to read AnimationStack object");
|
DOMWarning("failed to read AnimationStack object");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -362,8 +362,9 @@ void TempMesh::FixupFaceOrientation()
|
||||||
{
|
{
|
||||||
std::reverse(mVerts.begin() + nbvsi, mVerts.begin() + nbvsi + nbvc);
|
std::reverse(mVerts.begin() + nbvsi, mVerts.begin() + nbvsi + nbvc);
|
||||||
std::reverse(neighbour.begin() + nbvsi, neighbour.begin() + nbvsi + nbvc);
|
std::reverse(neighbour.begin() + nbvsi, neighbour.begin() + nbvsi + nbvc);
|
||||||
for( size_t a = 0; a < nbvc - 1; ++a )
|
for (size_t aa = 0; aa < nbvc - 1; ++aa) {
|
||||||
std::swap(neighbour[nbvsi + a], neighbour[nbvsi + a + 1]);
|
std::swap(neighbour[nbvsi + aa], neighbour[nbvsi + aa + 1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// either way we're done with the neighbour. Mark it as done and continue checking from there recursively
|
// either way we're done with the neighbour. Mark it as done and continue checking from there recursively
|
||||||
|
|
|
@ -50,12 +50,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <assimp/TinyFormatter.h>
|
#include <assimp/TinyFormatter.h>
|
||||||
#include <assimp/fast_atof.h>
|
#include <assimp/fast_atof.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
namespace EXPRESS = STEP::EXPRESS;
|
|
||||||
|
|
||||||
#include <functional>
|
namespace EXPRESS = STEP::EXPRESS;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
std::string AddLineNumber(const std::string& s,uint64_t line /*= LINE_NOT_SPECIFIED*/, const std::string& prefix = "")
|
std::string AddLineNumber(const std::string& s,uint64_t line /*= LINE_NOT_SPECIFIED*/, const std::string& prefix = "")
|
||||||
|
@ -127,8 +126,8 @@ STEP::DB* STEP::ReadFileHeader(std::shared_ptr<IOStream> stream) {
|
||||||
if (list->GetSize() > 1) {
|
if (list->GetSize() > 1) {
|
||||||
ASSIMP_LOG_WARN(AddLineNumber("multiple schemas currently not supported",line));
|
ASSIMP_LOG_WARN(AddLineNumber("multiple schemas currently not supported",line));
|
||||||
}
|
}
|
||||||
const EXPRESS::STRING* string( nullptr );
|
const EXPRESS::STRING *string = dynamic_cast<const EXPRESS::STRING *>((*list)[0].get());
|
||||||
if (!list->GetSize() || !(string=dynamic_cast<const EXPRESS::STRING*>( (*list)[0].get() ))) {
|
if (!list->GetSize() || nullptr == string ) {
|
||||||
throw STEP::SyntaxError("expected FILE_SCHEMA to contain a single string literal",line);
|
throw STEP::SyntaxError("expected FILE_SCHEMA to contain a single string literal",line);
|
||||||
}
|
}
|
||||||
head.fileSchema = *string;
|
head.fileSchema = *string;
|
||||||
|
@ -539,7 +538,7 @@ 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,STEP::SyntaxError::LINE_NOT_SPECIFIED,&db.GetSchema());
|
std::shared_ptr<const EXPRESS::LIST> conv_args = EXPRESS::LIST::Parse(acopy,(uint64_t)STEP::SyntaxError::LINE_NOT_SPECIFIED,&db.GetSchema());
|
||||||
delete[] args;
|
delete[] args;
|
||||||
args = NULL;
|
args = NULL;
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -76,9 +76,6 @@ public:
|
||||||
LWOImporter();
|
LWOImporter();
|
||||||
~LWOImporter();
|
~LWOImporter();
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Returns whether the class can handle the format of the given file.
|
/** Returns whether the class can handle the format of the given file.
|
||||||
* See BaseImporter::CanRead() for details.
|
* See BaseImporter::CanRead() for details.
|
||||||
|
@ -86,7 +83,6 @@ public:
|
||||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
|
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
|
||||||
bool checkSig) const;
|
bool checkSig) const;
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Called prior to ReadFile().
|
/** Called prior to ReadFile().
|
||||||
* The function is a request to the importer to update its configuration
|
* The function is a request to the importer to update its configuration
|
||||||
|
@ -389,7 +385,7 @@ protected:
|
||||||
unsigned int fileSize;
|
unsigned int fileSize;
|
||||||
|
|
||||||
/** Output scene */
|
/** Output scene */
|
||||||
aiScene* pScene;
|
aiScene* mScene;
|
||||||
|
|
||||||
/** Configuration option: speed flag set? */
|
/** Configuration option: speed flag set? */
|
||||||
bool configSpeedFlag;
|
bool configSpeedFlag;
|
||||||
|
@ -406,8 +402,8 @@ protected:
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
inline float LWOImporter::GetF4()
|
inline
|
||||||
{
|
float LWOImporter::GetF4() {
|
||||||
float f;
|
float f;
|
||||||
::memcpy(&f, mFileBuffer, 4);
|
::memcpy(&f, mFileBuffer, 4);
|
||||||
mFileBuffer += 4;
|
mFileBuffer += 4;
|
||||||
|
|
|
@ -43,30 +43,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
/** @file Implementation of the material oart of the LWO importer class */
|
/** @file Implementation of the material oart of the LWO importer class */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_LWO_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_LWO_IMPORTER
|
||||||
|
|
||||||
// internal headers
|
// internal headers
|
||||||
#include "LWOLoader.h"
|
#include "LWOLoader.h"
|
||||||
#include <assimp/ByteSwapper.h>
|
#include <assimp/ByteSwapper.h>
|
||||||
|
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
template <class T>
|
template <class T>
|
||||||
T lerp(const T& one, const T& two, float val)
|
T lerp(const T &one, const T &two, float val) {
|
||||||
{
|
return one + (two - one) * val;
|
||||||
return one + (two-one)*val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Convert a lightwave mapping mode to our's
|
// Convert a lightwave mapping mode to our's
|
||||||
inline aiTextureMapMode GetMapMode(LWO::Texture::Wrap in)
|
inline aiTextureMapMode GetMapMode(LWO::Texture::Wrap in) {
|
||||||
{
|
switch (in) {
|
||||||
switch (in)
|
|
||||||
{
|
|
||||||
case LWO::Texture::REPEAT:
|
case LWO::Texture::REPEAT:
|
||||||
return aiTextureMapMode_Wrap;
|
return aiTextureMapMode_Wrap;
|
||||||
|
|
||||||
|
@ -84,8 +78,7 @@ inline aiTextureMapMode GetMapMode(LWO::Texture::Wrap in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool LWOImporter::HandleTextures(aiMaterial* pcMat, const TextureList& in, aiTextureType type)
|
bool LWOImporter::HandleTextures(aiMaterial *pcMat, const TextureList &in, aiTextureType type) {
|
||||||
{
|
|
||||||
ai_assert(NULL != pcMat);
|
ai_assert(NULL != pcMat);
|
||||||
|
|
||||||
unsigned int cur = 0, temp = 0;
|
unsigned int cur = 0, temp = 0;
|
||||||
|
@ -101,9 +94,8 @@ bool LWOImporter::HandleTextures(aiMaterial* pcMat, const TextureList& in, aiTex
|
||||||
// as they are, the GenUVcoords step will compute UV
|
// as they are, the GenUVcoords step will compute UV
|
||||||
// channels if they're not there.
|
// channels if they're not there.
|
||||||
|
|
||||||
aiTextureMapping mapping;
|
aiTextureMapping mapping = aiTextureMapping_OTHER;
|
||||||
switch (texture.mapMode)
|
switch (texture.mapMode) {
|
||||||
{
|
|
||||||
case LWO::Texture::Planar:
|
case LWO::Texture::Planar:
|
||||||
mapping = aiTextureMapping_PLANE;
|
mapping = aiTextureMapping_PLANE;
|
||||||
break;
|
break;
|
||||||
|
@ -120,20 +112,18 @@ bool LWOImporter::HandleTextures(aiMaterial* pcMat, const TextureList& in, aiTex
|
||||||
ASSIMP_LOG_ERROR("LWO2: Unsupported texture mapping: FrontProjection");
|
ASSIMP_LOG_ERROR("LWO2: Unsupported texture mapping: FrontProjection");
|
||||||
mapping = aiTextureMapping_OTHER;
|
mapping = aiTextureMapping_OTHER;
|
||||||
break;
|
break;
|
||||||
case LWO::Texture::UV:
|
case LWO::Texture::UV: {
|
||||||
{
|
if (UINT_MAX == texture.mRealUVIndex) {
|
||||||
if( UINT_MAX == texture.mRealUVIndex ) {
|
|
||||||
// We have no UV index for this texture, so we can't display it
|
// We have no UV index for this texture, so we can't display it
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the UV source index
|
// add the UV source index
|
||||||
temp = texture.mRealUVIndex;
|
temp = texture.mRealUVIndex;
|
||||||
pcMat->AddProperty<int>((int*)&temp,1,AI_MATKEY_UVWSRC(type,cur));
|
pcMat->AddProperty<int>((int *)&temp, 1, AI_MATKEY_UVWSRC(type, cur));
|
||||||
|
|
||||||
mapping = aiTextureMapping_UV;
|
mapping = aiTextureMapping_UV;
|
||||||
}
|
} break;
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
ai_assert(false);
|
ai_assert(false);
|
||||||
};
|
};
|
||||||
|
@ -143,17 +133,17 @@ bool LWOImporter::HandleTextures(aiMaterial* pcMat, const TextureList& in, aiTex
|
||||||
aiVector3D v;
|
aiVector3D v;
|
||||||
switch (texture.majorAxis) {
|
switch (texture.majorAxis) {
|
||||||
case Texture::AXIS_X:
|
case Texture::AXIS_X:
|
||||||
v = aiVector3D(1.0,0.0,0.0);
|
v = aiVector3D(1.0, 0.0, 0.0);
|
||||||
break;
|
break;
|
||||||
case Texture::AXIS_Y:
|
case Texture::AXIS_Y:
|
||||||
v = aiVector3D(0.0,1.0,0.0);
|
v = aiVector3D(0.0, 1.0, 0.0);
|
||||||
break;
|
break;
|
||||||
default: // case Texture::AXIS_Z:
|
default: // case Texture::AXIS_Z:
|
||||||
v = aiVector3D(0.0,0.0,1.0);
|
v = aiVector3D(0.0, 0.0, 1.0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
pcMat->AddProperty(&v,1,AI_MATKEY_TEXMAP_AXIS(type,cur));
|
pcMat->AddProperty(&v, 1, AI_MATKEY_TEXMAP_AXIS(type, cur));
|
||||||
|
|
||||||
// Setup UV scalings for cylindric and spherical projections
|
// Setup UV scalings for cylindric and spherical projections
|
||||||
if (mapping == aiTextureMapping_CYLINDER || mapping == aiTextureMapping_SPHERE) {
|
if (mapping == aiTextureMapping_CYLINDER || mapping == aiTextureMapping_SPHERE) {
|
||||||
|
@ -161,8 +151,8 @@ bool LWOImporter::HandleTextures(aiMaterial* pcMat, const TextureList& in, aiTex
|
||||||
trafo.mScaling.x = texture.wrapAmountW;
|
trafo.mScaling.x = texture.wrapAmountW;
|
||||||
trafo.mScaling.y = texture.wrapAmountH;
|
trafo.mScaling.y = texture.wrapAmountH;
|
||||||
|
|
||||||
static_assert(sizeof(aiUVTransform)/sizeof(ai_real) == 5, "sizeof(aiUVTransform)/sizeof(ai_real) == 5");
|
static_assert(sizeof(aiUVTransform) / sizeof(ai_real) == 5, "sizeof(aiUVTransform)/sizeof(ai_real) == 5");
|
||||||
pcMat->AddProperty(&trafo,1,AI_MATKEY_UVTRANSFORM(type,cur));
|
pcMat->AddProperty(&trafo, 1, AI_MATKEY_UVTRANSFORM(type, cur));
|
||||||
}
|
}
|
||||||
ASSIMP_LOG_DEBUG("LWO2: Setting up non-UV mapping");
|
ASSIMP_LOG_DEBUG("LWO2: Setting up non-UV mapping");
|
||||||
}
|
}
|
||||||
|
@ -178,7 +168,6 @@ bool LWOImporter::HandleTextures(aiMaterial* pcMat, const TextureList& in, aiTex
|
||||||
if ((*clip).idx == temp) {
|
if ((*clip).idx == temp) {
|
||||||
candidate = clip;
|
candidate = clip;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (candidate == end) {
|
if (candidate == end) {
|
||||||
ASSIMP_LOG_ERROR("LWO2: Clip index is out of bounds");
|
ASSIMP_LOG_ERROR("LWO2: Clip index is out of bounds");
|
||||||
|
@ -191,8 +180,7 @@ bool LWOImporter::HandleTextures(aiMaterial* pcMat, const TextureList& in, aiTex
|
||||||
s.Set("$texture.png");
|
s.Set("$texture.png");
|
||||||
|
|
||||||
//continue;
|
//continue;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (Clip::UNSUPPORTED == (*candidate).type) {
|
if (Clip::UNSUPPORTED == (*candidate).type) {
|
||||||
ASSIMP_LOG_ERROR("LWO2: Clip type is not supported");
|
ASSIMP_LOG_ERROR("LWO2: Clip type is not supported");
|
||||||
continue;
|
continue;
|
||||||
|
@ -205,11 +193,9 @@ bool LWOImporter::HandleTextures(aiMaterial* pcMat, const TextureList& in, aiTex
|
||||||
if ((*candidate).negate) {
|
if ((*candidate).negate) {
|
||||||
flags |= aiTextureFlags_Invert;
|
flags |= aiTextureFlags_Invert;
|
||||||
}
|
}
|
||||||
pcMat->AddProperty(&flags,1,AI_MATKEY_TEXFLAGS(type,cur));
|
pcMat->AddProperty(&flags, 1, AI_MATKEY_TEXFLAGS(type, cur));
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
std::string ss = texture.mFileName;
|
std::string ss = texture.mFileName;
|
||||||
if (!ss.length()) {
|
if (!ss.length()) {
|
||||||
ASSIMP_LOG_WARN("LWOB: Empty file name");
|
ASSIMP_LOG_WARN("LWOB: Empty file name");
|
||||||
|
@ -218,14 +204,13 @@ bool LWOImporter::HandleTextures(aiMaterial* pcMat, const TextureList& in, aiTex
|
||||||
AdjustTexturePath(ss);
|
AdjustTexturePath(ss);
|
||||||
s.Set(ss);
|
s.Set(ss);
|
||||||
}
|
}
|
||||||
pcMat->AddProperty(&s,AI_MATKEY_TEXTURE(type,cur));
|
pcMat->AddProperty(&s, AI_MATKEY_TEXTURE(type, cur));
|
||||||
|
|
||||||
// add the blend factor
|
// add the blend factor
|
||||||
pcMat->AddProperty<float>(&texture.mStrength,1,AI_MATKEY_TEXBLEND(type,cur));
|
pcMat->AddProperty<float>(&texture.mStrength, 1, AI_MATKEY_TEXBLEND(type, cur));
|
||||||
|
|
||||||
// add the blend operation
|
// add the blend operation
|
||||||
switch (texture.blendType)
|
switch (texture.blendType) {
|
||||||
{
|
|
||||||
case LWO::Texture::Normal:
|
case LWO::Texture::Normal:
|
||||||
case LWO::Texture::Multiply:
|
case LWO::Texture::Multiply:
|
||||||
temp = (unsigned int)aiTextureOp_Multiply;
|
temp = (unsigned int)aiTextureOp_Multiply;
|
||||||
|
@ -247,10 +232,9 @@ bool LWOImporter::HandleTextures(aiMaterial* pcMat, const TextureList& in, aiTex
|
||||||
default:
|
default:
|
||||||
temp = (unsigned int)aiTextureOp_Multiply;
|
temp = (unsigned int)aiTextureOp_Multiply;
|
||||||
ASSIMP_LOG_WARN("LWO2: Unsupported texture blend mode: alpha or displacement");
|
ASSIMP_LOG_WARN("LWO2: Unsupported texture blend mode: alpha or displacement");
|
||||||
|
|
||||||
}
|
}
|
||||||
// Setup texture operation
|
// Setup texture operation
|
||||||
pcMat->AddProperty<int>((int*)&temp,1,AI_MATKEY_TEXOP(type,cur));
|
pcMat->AddProperty<int>((int *)&temp, 1, AI_MATKEY_TEXOP(type, cur));
|
||||||
|
|
||||||
// setup the mapping mode
|
// setup the mapping mode
|
||||||
int mapping_ = static_cast<int>(mapping);
|
int mapping_ = static_cast<int>(mapping);
|
||||||
|
@ -258,11 +242,11 @@ bool LWOImporter::HandleTextures(aiMaterial* pcMat, const TextureList& in, aiTex
|
||||||
|
|
||||||
// add the u-wrapping
|
// add the u-wrapping
|
||||||
temp = (unsigned int)GetMapMode(texture.wrapModeWidth);
|
temp = (unsigned int)GetMapMode(texture.wrapModeWidth);
|
||||||
pcMat->AddProperty<int>((int*)&temp,1,AI_MATKEY_MAPPINGMODE_U(type,cur));
|
pcMat->AddProperty<int>((int *)&temp, 1, AI_MATKEY_MAPPINGMODE_U(type, cur));
|
||||||
|
|
||||||
// add the v-wrapping
|
// add the v-wrapping
|
||||||
temp = (unsigned int)GetMapMode(texture.wrapModeHeight);
|
temp = (unsigned int)GetMapMode(texture.wrapModeHeight);
|
||||||
pcMat->AddProperty<int>((int*)&temp,1,AI_MATKEY_MAPPINGMODE_V(type,cur));
|
pcMat->AddProperty<int>((int *)&temp, 1, AI_MATKEY_MAPPINGMODE_V(type, cur));
|
||||||
|
|
||||||
++cur;
|
++cur;
|
||||||
}
|
}
|
||||||
|
@ -270,76 +254,72 @@ bool LWOImporter::HandleTextures(aiMaterial* pcMat, const TextureList& in, aiTex
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void LWOImporter::ConvertMaterial(const LWO::Surface& surf,aiMaterial* pcMat)
|
void LWOImporter::ConvertMaterial(const LWO::Surface &surf, aiMaterial *pcMat) {
|
||||||
{
|
|
||||||
// copy the name of the surface
|
// copy the name of the surface
|
||||||
aiString st;
|
aiString st;
|
||||||
st.Set(surf.mName);
|
st.Set(surf.mName);
|
||||||
pcMat->AddProperty(&st,AI_MATKEY_NAME);
|
pcMat->AddProperty(&st, AI_MATKEY_NAME);
|
||||||
|
|
||||||
const int i = surf.bDoubleSided ? 1 : 0;
|
const int i = surf.bDoubleSided ? 1 : 0;
|
||||||
pcMat->AddProperty(&i,1,AI_MATKEY_TWOSIDED);
|
pcMat->AddProperty(&i, 1, AI_MATKEY_TWOSIDED);
|
||||||
|
|
||||||
// add the refraction index and the bump intensity
|
// add the refraction index and the bump intensity
|
||||||
pcMat->AddProperty(&surf.mIOR,1,AI_MATKEY_REFRACTI);
|
pcMat->AddProperty(&surf.mIOR, 1, AI_MATKEY_REFRACTI);
|
||||||
pcMat->AddProperty(&surf.mBumpIntensity,1,AI_MATKEY_BUMPSCALING);
|
pcMat->AddProperty(&surf.mBumpIntensity, 1, AI_MATKEY_BUMPSCALING);
|
||||||
|
|
||||||
aiShadingMode m;
|
aiShadingMode m;
|
||||||
if (surf.mSpecularValue && surf.mGlossiness)
|
if (surf.mSpecularValue && surf.mGlossiness) {
|
||||||
{
|
|
||||||
float fGloss;
|
float fGloss;
|
||||||
if (mIsLWO2) {
|
if (mIsLWO2) {
|
||||||
fGloss = std::pow( surf.mGlossiness*ai_real( 10.0 )+ ai_real( 2.0 ), ai_real( 2.0 ) );
|
fGloss = std::pow(surf.mGlossiness * ai_real(10.0) + ai_real(2.0), ai_real(2.0));
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
if (16.0 >= surf.mGlossiness)
|
if (16.0 >= surf.mGlossiness)
|
||||||
fGloss = 6.0;
|
fGloss = 6.0;
|
||||||
else if (64.0 >= surf.mGlossiness)
|
else if (64.0 >= surf.mGlossiness)
|
||||||
fGloss = 20.0;
|
fGloss = 20.0;
|
||||||
else if (256.0 >= surf.mGlossiness)
|
else if (256.0 >= surf.mGlossiness)
|
||||||
fGloss = 50.0;
|
fGloss = 50.0;
|
||||||
else fGloss = 80.0;
|
else
|
||||||
|
fGloss = 80.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pcMat->AddProperty(&surf.mSpecularValue,1,AI_MATKEY_SHININESS_STRENGTH);
|
pcMat->AddProperty(&surf.mSpecularValue, 1, AI_MATKEY_SHININESS_STRENGTH);
|
||||||
pcMat->AddProperty(&fGloss,1,AI_MATKEY_SHININESS);
|
pcMat->AddProperty(&fGloss, 1, AI_MATKEY_SHININESS);
|
||||||
m = aiShadingMode_Phong;
|
m = aiShadingMode_Phong;
|
||||||
}
|
} else
|
||||||
else m = aiShadingMode_Gouraud;
|
m = aiShadingMode_Gouraud;
|
||||||
|
|
||||||
// specular color
|
// specular color
|
||||||
aiColor3D clr = lerp( aiColor3D(1.0,1.0,1.0), surf.mColor, surf.mColorHighlights );
|
aiColor3D clr = lerp(aiColor3D(1.0, 1.0, 1.0), surf.mColor, surf.mColorHighlights);
|
||||||
pcMat->AddProperty(&clr,1,AI_MATKEY_COLOR_SPECULAR);
|
pcMat->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
|
||||||
pcMat->AddProperty(&surf.mSpecularValue,1,AI_MATKEY_SHININESS_STRENGTH);
|
pcMat->AddProperty(&surf.mSpecularValue, 1, AI_MATKEY_SHININESS_STRENGTH);
|
||||||
|
|
||||||
// emissive color
|
// emissive color
|
||||||
// luminosity is not really the same but it affects the surface in a similar way. Some scaling looks good.
|
// luminosity is not really the same but it affects the surface in a similar way. Some scaling looks good.
|
||||||
clr.g = clr.b = clr.r = surf.mLuminosity*ai_real( 0.8 );
|
clr.g = clr.b = clr.r = surf.mLuminosity * ai_real(0.8);
|
||||||
pcMat->AddProperty<aiColor3D>(&clr,1,AI_MATKEY_COLOR_EMISSIVE);
|
pcMat->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_EMISSIVE);
|
||||||
|
|
||||||
// opacity ... either additive or default-blended, please
|
// opacity ... either additive or default-blended, please
|
||||||
if (0.0 != surf.mAdditiveTransparency) {
|
if (0.0 != surf.mAdditiveTransparency) {
|
||||||
const int add = aiBlendMode_Additive;
|
const int add = aiBlendMode_Additive;
|
||||||
pcMat->AddProperty(&surf.mAdditiveTransparency,1,AI_MATKEY_OPACITY);
|
pcMat->AddProperty(&surf.mAdditiveTransparency, 1, AI_MATKEY_OPACITY);
|
||||||
pcMat->AddProperty(&add,1,AI_MATKEY_BLEND_FUNC);
|
pcMat->AddProperty(&add, 1, AI_MATKEY_BLEND_FUNC);
|
||||||
} else if (10e10f != surf.mTransparency) {
|
} else if (10e10f != surf.mTransparency) {
|
||||||
const int def = aiBlendMode_Default;
|
const int def = aiBlendMode_Default;
|
||||||
const float f = 1.0f-surf.mTransparency;
|
const float f = 1.0f - surf.mTransparency;
|
||||||
pcMat->AddProperty(&f,1,AI_MATKEY_OPACITY);
|
pcMat->AddProperty(&f, 1, AI_MATKEY_OPACITY);
|
||||||
pcMat->AddProperty(&def,1,AI_MATKEY_BLEND_FUNC);
|
pcMat->AddProperty(&def, 1, AI_MATKEY_BLEND_FUNC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ADD TEXTURES to the material
|
// ADD TEXTURES to the material
|
||||||
// TODO: find out how we can handle COLOR textures correctly...
|
// TODO: find out how we can handle COLOR textures correctly...
|
||||||
bool b = HandleTextures(pcMat,surf.mColorTextures,aiTextureType_DIFFUSE);
|
bool b = HandleTextures(pcMat, surf.mColorTextures, aiTextureType_DIFFUSE);
|
||||||
b = (b || HandleTextures(pcMat,surf.mDiffuseTextures,aiTextureType_DIFFUSE));
|
b = (b || HandleTextures(pcMat, surf.mDiffuseTextures, aiTextureType_DIFFUSE));
|
||||||
HandleTextures(pcMat,surf.mSpecularTextures,aiTextureType_SPECULAR);
|
HandleTextures(pcMat, surf.mSpecularTextures, aiTextureType_SPECULAR);
|
||||||
HandleTextures(pcMat,surf.mGlossinessTextures,aiTextureType_SHININESS);
|
HandleTextures(pcMat, surf.mGlossinessTextures, aiTextureType_SHININESS);
|
||||||
HandleTextures(pcMat,surf.mBumpTextures,aiTextureType_HEIGHT);
|
HandleTextures(pcMat, surf.mBumpTextures, aiTextureType_HEIGHT);
|
||||||
HandleTextures(pcMat,surf.mOpacityTextures,aiTextureType_OPACITY);
|
HandleTextures(pcMat, surf.mOpacityTextures, aiTextureType_OPACITY);
|
||||||
HandleTextures(pcMat,surf.mReflectionTextures,aiTextureType_REFLECTION);
|
HandleTextures(pcMat, surf.mReflectionTextures, aiTextureType_REFLECTION);
|
||||||
|
|
||||||
// Now we need to know which shader to use .. iterate through the shader list of
|
// Now we need to know which shader to use .. iterate through the shader list of
|
||||||
// the surface and search for a name which we know ...
|
// the surface and search for a name which we know ...
|
||||||
|
@ -349,15 +329,12 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,aiMaterial* pcMat)
|
||||||
|
|
||||||
m = aiShadingMode_Toon;
|
m = aiShadingMode_Toon;
|
||||||
break;
|
break;
|
||||||
}
|
} else if (shader.functionName == "LW_RealFresnel" || shader.functionName == "LW_FastFresnel") {
|
||||||
else if (shader.functionName == "LW_RealFresnel" || shader.functionName == "LW_FastFresnel") {
|
|
||||||
ASSIMP_LOG_INFO("LWO2: Mapping LW_RealFresnel/LW_FastFresnel to aiShadingMode_Fresnel");
|
ASSIMP_LOG_INFO("LWO2: Mapping LW_RealFresnel/LW_FastFresnel to aiShadingMode_Fresnel");
|
||||||
|
|
||||||
m = aiShadingMode_Fresnel;
|
m = aiShadingMode_Fresnel;
|
||||||
break;
|
break;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
ASSIMP_LOG_WARN_F("LWO2: Unknown surface shader: ", shader.functionName);
|
ASSIMP_LOG_WARN_F("LWO2: Unknown surface shader: ", shader.functionName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -368,17 +345,16 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,aiMaterial* pcMat)
|
||||||
|
|
||||||
// (the diffuse value is just a scaling factor)
|
// (the diffuse value is just a scaling factor)
|
||||||
// If a diffuse texture is set, we set this value to 1.0
|
// If a diffuse texture is set, we set this value to 1.0
|
||||||
clr = (b && false ? aiColor3D(1.0,1.0,1.0) : surf.mColor);
|
clr = (b && false ? aiColor3D(1.0, 1.0, 1.0) : surf.mColor);
|
||||||
clr.r *= surf.mDiffuseValue;
|
clr.r *= surf.mDiffuseValue;
|
||||||
clr.g *= surf.mDiffuseValue;
|
clr.g *= surf.mDiffuseValue;
|
||||||
clr.b *= surf.mDiffuseValue;
|
clr.b *= surf.mDiffuseValue;
|
||||||
pcMat->AddProperty<aiColor3D>(&clr,1,AI_MATKEY_COLOR_DIFFUSE);
|
pcMat->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
char LWOImporter::FindUVChannels(LWO::TextureList& list,
|
char LWOImporter::FindUVChannels(LWO::TextureList &list,
|
||||||
LWO::Layer& /*layer*/,LWO::UVChannel& uv, unsigned int next)
|
LWO::Layer & /*layer*/, LWO::UVChannel &uv, unsigned int next) {
|
||||||
{
|
|
||||||
char ret = 0;
|
char ret = 0;
|
||||||
for (auto &texture : list) {
|
for (auto &texture : list) {
|
||||||
|
|
||||||
|
@ -391,11 +367,9 @@ char LWOImporter::FindUVChannels(LWO::TextureList& list,
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
|
||||||
// got it.
|
// got it.
|
||||||
if (texture.mRealUVIndex == UINT_MAX || texture.mRealUVIndex == next)
|
if (texture.mRealUVIndex == UINT_MAX || texture.mRealUVIndex == next) {
|
||||||
{
|
|
||||||
texture.mRealUVIndex = next;
|
texture.mRealUVIndex = next;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// channel mismatch. need to duplicate the material.
|
// channel mismatch. need to duplicate the material.
|
||||||
ASSIMP_LOG_WARN("LWO: Channel mismatch, would need to duplicate surface [design bug]");
|
ASSIMP_LOG_WARN("LWO: Channel mismatch, would need to duplicate surface [design bug]");
|
||||||
|
|
||||||
|
@ -407,49 +381,48 @@ char LWOImporter::FindUVChannels(LWO::TextureList& list,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void LWOImporter::FindUVChannels(LWO::Surface& surf,
|
void LWOImporter::FindUVChannels(LWO::Surface &surf,
|
||||||
LWO::SortedRep& sorted,LWO::Layer& layer,
|
LWO::SortedRep &sorted, LWO::Layer &layer,
|
||||||
unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS])
|
unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS]) {
|
||||||
{
|
|
||||||
unsigned int next = 0, extra = 0, num_extra = 0;
|
unsigned int next = 0, extra = 0, num_extra = 0;
|
||||||
|
|
||||||
// Check whether we have an UV entry != 0 for one of the faces in 'sorted'
|
// Check whether we have an UV entry != 0 for one of the faces in 'sorted'
|
||||||
for (unsigned int i = 0; i < layer.mUVChannels.size();++i) {
|
for (unsigned int i = 0; i < layer.mUVChannels.size(); ++i) {
|
||||||
LWO::UVChannel& uv = layer.mUVChannels[i];
|
LWO::UVChannel &uv = layer.mUVChannels[i];
|
||||||
|
|
||||||
for (LWO::SortedRep::const_iterator it = sorted.begin(); it != sorted.end(); ++it) {
|
for (LWO::SortedRep::const_iterator it = sorted.begin(); it != sorted.end(); ++it) {
|
||||||
|
|
||||||
LWO::Face& face = layer.mFaces[*it];
|
LWO::Face &face = layer.mFaces[*it];
|
||||||
|
|
||||||
for (unsigned int n = 0; n < face.mNumIndices; ++n) {
|
for (unsigned int n = 0; n < face.mNumIndices; ++n) {
|
||||||
unsigned int idx = face.mIndices[n];
|
unsigned int idx = face.mIndices[n];
|
||||||
|
|
||||||
if (uv.abAssigned[idx] && ((aiVector2D*)&uv.rawData[0])[idx] != aiVector2D()) {
|
if (uv.abAssigned[idx] && ((aiVector2D *)&uv.rawData[0])[idx] != aiVector2D()) {
|
||||||
|
|
||||||
if (extra >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
|
if (extra >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
|
||||||
|
|
||||||
ASSIMP_LOG_ERROR("LWO: Maximum number of UV channels for "
|
ASSIMP_LOG_ERROR("LWO: Maximum number of UV channels for "
|
||||||
"this mesh reached. Skipping channel \'" + uv.name + "\'");
|
"this mesh reached. Skipping channel \'" +
|
||||||
|
uv.name + "\'");
|
||||||
|
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Search through all textures assigned to 'surf' and look for this UV channel
|
// Search through all textures assigned to 'surf' and look for this UV channel
|
||||||
char had = 0;
|
char had = 0;
|
||||||
had |= FindUVChannels(surf.mColorTextures,layer,uv,next);
|
had |= FindUVChannels(surf.mColorTextures, layer, uv, next);
|
||||||
had |= FindUVChannels(surf.mDiffuseTextures,layer,uv,next);
|
had |= FindUVChannels(surf.mDiffuseTextures, layer, uv, next);
|
||||||
had |= FindUVChannels(surf.mSpecularTextures,layer,uv,next);
|
had |= FindUVChannels(surf.mSpecularTextures, layer, uv, next);
|
||||||
had |= FindUVChannels(surf.mGlossinessTextures,layer,uv,next);
|
had |= FindUVChannels(surf.mGlossinessTextures, layer, uv, next);
|
||||||
had |= FindUVChannels(surf.mOpacityTextures,layer,uv,next);
|
had |= FindUVChannels(surf.mOpacityTextures, layer, uv, next);
|
||||||
had |= FindUVChannels(surf.mBumpTextures,layer,uv,next);
|
had |= FindUVChannels(surf.mBumpTextures, layer, uv, next);
|
||||||
had |= FindUVChannels(surf.mReflectionTextures,layer,uv,next);
|
had |= FindUVChannels(surf.mReflectionTextures, layer, uv, next);
|
||||||
|
|
||||||
// We have a texture referencing this UV channel so we have to take special care
|
// We have a texture referencing this UV channel so we have to take special care
|
||||||
// and are willing to drop unreferenced channels in favour of it.
|
// and are willing to drop unreferenced channels in favour of it.
|
||||||
if (had != 0) {
|
if (had != 0) {
|
||||||
if (num_extra) {
|
if (num_extra) {
|
||||||
|
|
||||||
for (unsigned int a = next; a < std::min( extra, AI_MAX_NUMBER_OF_TEXTURECOORDS-1u ); ++a) {
|
for (unsigned int a = next; a < std::min(extra, AI_MAX_NUMBER_OF_TEXTURECOORDS - 1u); ++a) {
|
||||||
out[a+1] = out[a];
|
out[a + 1] = out[a];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
++extra;
|
++extra;
|
||||||
|
@ -461,7 +434,7 @@ void LWOImporter::FindUVChannels(LWO::Surface& surf,
|
||||||
++num_extra;
|
++num_extra;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
it = sorted.end()-1;
|
it = sorted.end() - 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -473,42 +446,40 @@ void LWOImporter::FindUVChannels(LWO::Surface& surf,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void LWOImporter::FindVCChannels(const LWO::Surface& surf, LWO::SortedRep& sorted, const LWO::Layer& layer,
|
void LWOImporter::FindVCChannels(const LWO::Surface &surf, LWO::SortedRep &sorted, const LWO::Layer &layer,
|
||||||
unsigned int out[AI_MAX_NUMBER_OF_COLOR_SETS])
|
unsigned int out[AI_MAX_NUMBER_OF_COLOR_SETS]) {
|
||||||
{
|
|
||||||
unsigned int next = 0;
|
unsigned int next = 0;
|
||||||
|
|
||||||
// Check whether we have an vc entry != 0 for one of the faces in 'sorted'
|
// Check whether we have an vc entry != 0 for one of the faces in 'sorted'
|
||||||
for (unsigned int i = 0; i < layer.mVColorChannels.size();++i) {
|
for (unsigned int i = 0; i < layer.mVColorChannels.size(); ++i) {
|
||||||
const LWO::VColorChannel& vc = layer.mVColorChannels[i];
|
const LWO::VColorChannel &vc = layer.mVColorChannels[i];
|
||||||
|
|
||||||
if (surf.mVCMap == vc.name) {
|
if (surf.mVCMap == vc.name) {
|
||||||
// The vertex color map is explicitly requested by the surface so we need to take special care of it
|
// The vertex color map is explicitly requested by the surface so we need to take special care of it
|
||||||
for (unsigned int a = 0; a < std::min(next,AI_MAX_NUMBER_OF_COLOR_SETS-1u); ++a) {
|
for (unsigned int a = 0; a < std::min(next, AI_MAX_NUMBER_OF_COLOR_SETS - 1u); ++a) {
|
||||||
out[a+1] = out[a];
|
out[a + 1] = out[a];
|
||||||
}
|
}
|
||||||
out[0] = i;
|
out[0] = i;
|
||||||
++next;
|
++next;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
|
|
||||||
for (LWO::SortedRep::iterator it = sorted.begin(); it != sorted.end(); ++it) {
|
for (LWO::SortedRep::iterator it = sorted.begin(); it != sorted.end(); ++it) {
|
||||||
const LWO::Face& face = layer.mFaces[*it];
|
const LWO::Face &face = layer.mFaces[*it];
|
||||||
|
|
||||||
for (unsigned int n = 0; n < face.mNumIndices; ++n) {
|
for (unsigned int n = 0; n < face.mNumIndices; ++n) {
|
||||||
unsigned int idx = face.mIndices[n];
|
unsigned int idx = face.mIndices[n];
|
||||||
|
|
||||||
if (vc.abAssigned[idx] && ((aiColor4D*)&vc.rawData[0])[idx] != aiColor4D(0.0,0.0,0.0,1.0)) {
|
if (vc.abAssigned[idx] && ((aiColor4D *)&vc.rawData[0])[idx] != aiColor4D(0.0, 0.0, 0.0, 1.0)) {
|
||||||
if (next >= AI_MAX_NUMBER_OF_COLOR_SETS) {
|
if (next >= AI_MAX_NUMBER_OF_COLOR_SETS) {
|
||||||
|
|
||||||
ASSIMP_LOG_ERROR("LWO: Maximum number of vertex color channels for "
|
ASSIMP_LOG_ERROR("LWO: Maximum number of vertex color channels for "
|
||||||
"this mesh reached. Skipping channel \'" + vc.name + "\'");
|
"this mesh reached. Skipping channel \'" +
|
||||||
|
vc.name + "\'");
|
||||||
|
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
out[next++] = i;
|
out[next++] = i;
|
||||||
}
|
}
|
||||||
it = sorted.end()-1;
|
it = sorted.end() - 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -521,20 +492,17 @@ void LWOImporter::FindVCChannels(const LWO::Surface& surf, LWO::SortedRep& sorte
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void LWOImporter::LoadLWO2ImageMap(unsigned int size, LWO::Texture& tex )
|
void LWOImporter::LoadLWO2ImageMap(unsigned int size, LWO::Texture &tex) {
|
||||||
{
|
LE_NCONST uint8_t *const end = mFileBuffer + size;
|
||||||
LE_NCONST uint8_t* const end = mFileBuffer + size;
|
while (true) {
|
||||||
while (true)
|
if (mFileBuffer + 6 >= end) break;
|
||||||
{
|
|
||||||
if (mFileBuffer + 6 >= end)break;
|
|
||||||
LE_NCONST IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
|
LE_NCONST IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
|
||||||
|
|
||||||
if (mFileBuffer + head.length > end)
|
if (mFileBuffer + head.length > end)
|
||||||
throw DeadlyImportError("LWO2: Invalid SURF.BLOCK chunk length");
|
throw DeadlyImportError("LWO2: Invalid SURF.BLOCK chunk length");
|
||||||
|
|
||||||
uint8_t* const next = mFileBuffer+head.length;
|
uint8_t *const next = mFileBuffer + head.length;
|
||||||
switch (head.type)
|
switch (head.type) {
|
||||||
{
|
|
||||||
case AI_LWO_PROJ:
|
case AI_LWO_PROJ:
|
||||||
tex.mapMode = (Texture::MappingMode)GetU2();
|
tex.mapMode = (Texture::MappingMode)GetU2();
|
||||||
break;
|
break;
|
||||||
|
@ -549,7 +517,7 @@ void LWOImporter::LoadLWO2ImageMap(unsigned int size, LWO::Texture& tex )
|
||||||
tex.mClipIdx = GetU2();
|
tex.mClipIdx = GetU2();
|
||||||
break;
|
break;
|
||||||
case AI_LWO_VMAP:
|
case AI_LWO_VMAP:
|
||||||
GetS0(tex.mUVChannelIndex,head.length);
|
GetS0(tex.mUVChannelIndex, head.length);
|
||||||
break;
|
break;
|
||||||
case AI_LWO_WRPH:
|
case AI_LWO_WRPH:
|
||||||
tex.wrapAmountH = GetF4();
|
tex.wrapAmountH = GetF4();
|
||||||
|
@ -563,46 +531,40 @@ void LWOImporter::LoadLWO2ImageMap(unsigned int size, LWO::Texture& tex )
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void LWOImporter::LoadLWO2Procedural(unsigned int /*size*/, LWO::Texture& tex )
|
void LWOImporter::LoadLWO2Procedural(unsigned int /*size*/, LWO::Texture &tex) {
|
||||||
{
|
|
||||||
// --- not supported at the moment
|
// --- not supported at the moment
|
||||||
ASSIMP_LOG_ERROR("LWO2: Found procedural texture, this is not supported");
|
ASSIMP_LOG_ERROR("LWO2: Found procedural texture, this is not supported");
|
||||||
tex.bCanUse = false;
|
tex.bCanUse = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void LWOImporter::LoadLWO2Gradient(unsigned int /*size*/, LWO::Texture& tex )
|
void LWOImporter::LoadLWO2Gradient(unsigned int /*size*/, LWO::Texture &tex) {
|
||||||
{
|
|
||||||
// --- not supported at the moment
|
// --- not supported at the moment
|
||||||
ASSIMP_LOG_ERROR("LWO2: Found gradient texture, this is not supported");
|
ASSIMP_LOG_ERROR("LWO2: Found gradient texture, this is not supported");
|
||||||
tex.bCanUse = false;
|
tex.bCanUse = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void LWOImporter::LoadLWO2TextureHeader(unsigned int size, LWO::Texture& tex )
|
void LWOImporter::LoadLWO2TextureHeader(unsigned int size, LWO::Texture &tex) {
|
||||||
{
|
LE_NCONST uint8_t *const end = mFileBuffer + size;
|
||||||
LE_NCONST uint8_t* const end = mFileBuffer + size;
|
|
||||||
|
|
||||||
// get the ordinal string
|
// get the ordinal string
|
||||||
GetS0( tex.ordinal, size);
|
GetS0(tex.ordinal, size);
|
||||||
|
|
||||||
// we could crash later if this is an empty string ...
|
// we could crash later if this is an empty string ...
|
||||||
if (!tex.ordinal.length())
|
if (!tex.ordinal.length()) {
|
||||||
{
|
|
||||||
ASSIMP_LOG_ERROR("LWO2: Ill-formed SURF.BLOK ordinal string");
|
ASSIMP_LOG_ERROR("LWO2: Ill-formed SURF.BLOK ordinal string");
|
||||||
tex.ordinal = "\x00";
|
tex.ordinal = "\x00";
|
||||||
}
|
}
|
||||||
while (true)
|
while (true) {
|
||||||
{
|
if (mFileBuffer + 6 >= end) break;
|
||||||
if (mFileBuffer + 6 >= end)break;
|
|
||||||
const IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
|
const IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
|
||||||
|
|
||||||
if (mFileBuffer + head.length > end)
|
if (mFileBuffer + head.length > end)
|
||||||
throw DeadlyImportError("LWO2: Invalid texture header chunk length");
|
throw DeadlyImportError("LWO2: Invalid texture header chunk length");
|
||||||
|
|
||||||
uint8_t* const next = mFileBuffer+head.length;
|
uint8_t *const next = mFileBuffer + head.length;
|
||||||
switch (head.type)
|
switch (head.type) {
|
||||||
{
|
|
||||||
case AI_LWO_CHAN:
|
case AI_LWO_CHAN:
|
||||||
tex.type = GetU4();
|
tex.type = GetU4();
|
||||||
break;
|
break;
|
||||||
|
@ -619,56 +581,60 @@ void LWOImporter::LoadLWO2TextureHeader(unsigned int size, LWO::Texture& tex )
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void LWOImporter::LoadLWO2TextureBlock(LE_NCONST IFF::SubChunkHeader* head, unsigned int size )
|
void LWOImporter::LoadLWO2TextureBlock(LE_NCONST IFF::SubChunkHeader *head, unsigned int size) {
|
||||||
{
|
|
||||||
ai_assert(!mSurfaces->empty());
|
ai_assert(!mSurfaces->empty());
|
||||||
LWO::Surface& surf = mSurfaces->back();
|
LWO::Surface &surf = mSurfaces->back();
|
||||||
LWO::Texture tex;
|
LWO::Texture tex;
|
||||||
|
|
||||||
// load the texture header
|
// load the texture header
|
||||||
LoadLWO2TextureHeader(head->length,tex);
|
LoadLWO2TextureHeader(head->length, tex);
|
||||||
size -= head->length + 6;
|
size -= head->length + 6;
|
||||||
|
|
||||||
// now get the exact type of the texture
|
// now get the exact type of the texture
|
||||||
switch (head->type)
|
switch (head->type) {
|
||||||
{
|
|
||||||
case AI_LWO_PROC:
|
case AI_LWO_PROC:
|
||||||
LoadLWO2Procedural(size,tex);
|
LoadLWO2Procedural(size, tex);
|
||||||
break;
|
break;
|
||||||
case AI_LWO_GRAD:
|
case AI_LWO_GRAD:
|
||||||
LoadLWO2Gradient(size,tex);
|
LoadLWO2Gradient(size, tex);
|
||||||
break;
|
break;
|
||||||
case AI_LWO_IMAP:
|
case AI_LWO_IMAP:
|
||||||
LoadLWO2ImageMap(size,tex);
|
LoadLWO2ImageMap(size, tex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the destination channel
|
// get the destination channel
|
||||||
TextureList* listRef = NULL;
|
TextureList *listRef = NULL;
|
||||||
switch (tex.type)
|
switch (tex.type) {
|
||||||
{
|
|
||||||
case AI_LWO_COLR:
|
case AI_LWO_COLR:
|
||||||
listRef = &surf.mColorTextures;break;
|
listRef = &surf.mColorTextures;
|
||||||
|
break;
|
||||||
case AI_LWO_DIFF:
|
case AI_LWO_DIFF:
|
||||||
listRef = &surf.mDiffuseTextures;break;
|
listRef = &surf.mDiffuseTextures;
|
||||||
|
break;
|
||||||
case AI_LWO_SPEC:
|
case AI_LWO_SPEC:
|
||||||
listRef = &surf.mSpecularTextures;break;
|
listRef = &surf.mSpecularTextures;
|
||||||
|
break;
|
||||||
case AI_LWO_GLOS:
|
case AI_LWO_GLOS:
|
||||||
listRef = &surf.mGlossinessTextures;break;
|
listRef = &surf.mGlossinessTextures;
|
||||||
|
break;
|
||||||
case AI_LWO_BUMP:
|
case AI_LWO_BUMP:
|
||||||
listRef = &surf.mBumpTextures;break;
|
listRef = &surf.mBumpTextures;
|
||||||
|
break;
|
||||||
case AI_LWO_TRAN:
|
case AI_LWO_TRAN:
|
||||||
listRef = &surf.mOpacityTextures;break;
|
listRef = &surf.mOpacityTextures;
|
||||||
|
break;
|
||||||
case AI_LWO_REFL:
|
case AI_LWO_REFL:
|
||||||
listRef = &surf.mReflectionTextures;break;
|
listRef = &surf.mReflectionTextures;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ASSIMP_LOG_WARN("LWO2: Encountered unknown texture type");
|
ASSIMP_LOG_WARN("LWO2: Encountered unknown texture type");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now attach the texture to the parent surface - sort by ordinal string
|
// now attach the texture to the parent surface - sort by ordinal string
|
||||||
for (TextureList::iterator it = listRef->begin();it != listRef->end(); ++it) {
|
for (TextureList::iterator it = listRef->begin(); it != listRef->end(); ++it) {
|
||||||
if (::strcmp(tex.ordinal.c_str(),(*it).ordinal.c_str()) < 0) {
|
if (::strcmp(tex.ordinal.c_str(), (*it).ordinal.c_str()) < 0) {
|
||||||
listRef->insert(it,tex);
|
listRef->insert(it, tex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -676,50 +642,46 @@ void LWOImporter::LoadLWO2TextureBlock(LE_NCONST IFF::SubChunkHeader* head, unsi
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void LWOImporter::LoadLWO2ShaderBlock(LE_NCONST IFF::SubChunkHeader* /*head*/, unsigned int size )
|
void LWOImporter::LoadLWO2ShaderBlock(LE_NCONST IFF::SubChunkHeader * /*head*/, unsigned int size) {
|
||||||
{
|
LE_NCONST uint8_t *const end = mFileBuffer + size;
|
||||||
LE_NCONST uint8_t* const end = mFileBuffer + size;
|
|
||||||
|
|
||||||
ai_assert(!mSurfaces->empty());
|
ai_assert(!mSurfaces->empty());
|
||||||
LWO::Surface& surf = mSurfaces->back();
|
LWO::Surface &surf = mSurfaces->back();
|
||||||
LWO::Shader shader;
|
LWO::Shader shader;
|
||||||
|
|
||||||
// get the ordinal string
|
// get the ordinal string
|
||||||
GetS0( shader.ordinal, size);
|
GetS0(shader.ordinal, size);
|
||||||
|
|
||||||
// we could crash later if this is an empty string ...
|
// we could crash later if this is an empty string ...
|
||||||
if (!shader.ordinal.length())
|
if (!shader.ordinal.length()) {
|
||||||
{
|
|
||||||
ASSIMP_LOG_ERROR("LWO2: Ill-formed SURF.BLOK ordinal string");
|
ASSIMP_LOG_ERROR("LWO2: Ill-formed SURF.BLOK ordinal string");
|
||||||
shader.ordinal = "\x00";
|
shader.ordinal = "\x00";
|
||||||
}
|
}
|
||||||
|
|
||||||
// read the header
|
// read the header
|
||||||
while (true)
|
while (true) {
|
||||||
{
|
if (mFileBuffer + 6 >= end) break;
|
||||||
if (mFileBuffer + 6 >= end)break;
|
|
||||||
const IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
|
const IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
|
||||||
|
|
||||||
if (mFileBuffer + head.length > end)
|
if (mFileBuffer + head.length > end)
|
||||||
throw DeadlyImportError("LWO2: Invalid shader header chunk length");
|
throw DeadlyImportError("LWO2: Invalid shader header chunk length");
|
||||||
|
|
||||||
uint8_t* const next = mFileBuffer+head.length;
|
uint8_t *const next = mFileBuffer + head.length;
|
||||||
switch (head.type)
|
switch (head.type) {
|
||||||
{
|
|
||||||
case AI_LWO_ENAB:
|
case AI_LWO_ENAB:
|
||||||
shader.enabled = GetU2() ? true : false;
|
shader.enabled = GetU2() ? true : false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AI_LWO_FUNC:
|
case AI_LWO_FUNC:
|
||||||
GetS0( shader.functionName, head.length );
|
GetS0(shader.functionName, head.length);
|
||||||
}
|
}
|
||||||
mFileBuffer = next;
|
mFileBuffer = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now attach the shader to the parent surface - sort by ordinal string
|
// now attach the shader to the parent surface - sort by ordinal string
|
||||||
for (ShaderList::iterator it = surf.mShaders.begin();it != surf.mShaders.end(); ++it) {
|
for (ShaderList::iterator it = surf.mShaders.begin(); it != surf.mShaders.end(); ++it) {
|
||||||
if (::strcmp(shader.ordinal.c_str(),(*it).ordinal.c_str()) < 0) {
|
if (::strcmp(shader.ordinal.c_str(), (*it).ordinal.c_str()) < 0) {
|
||||||
surf.mShaders.insert(it,shader);
|
surf.mShaders.insert(it, shader);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -727,33 +689,33 @@ void LWOImporter::LoadLWO2ShaderBlock(LE_NCONST IFF::SubChunkHeader* /*head*/, u
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void LWOImporter::LoadLWO2Surface(unsigned int size)
|
void LWOImporter::LoadLWO2Surface(unsigned int size) {
|
||||||
{
|
LE_NCONST uint8_t *const end = mFileBuffer + size;
|
||||||
LE_NCONST uint8_t* const end = mFileBuffer + size;
|
|
||||||
|
|
||||||
mSurfaces->push_back( LWO::Surface () );
|
mSurfaces->push_back(LWO::Surface());
|
||||||
LWO::Surface& surf = mSurfaces->back();
|
LWO::Surface &surf = mSurfaces->back();
|
||||||
|
|
||||||
GetS0(surf.mName,size);
|
GetS0(surf.mName, size);
|
||||||
|
|
||||||
// check whether this surface was derived from any other surface
|
// check whether this surface was derived from any other surface
|
||||||
std::string derived;
|
std::string derived;
|
||||||
GetS0(derived,(unsigned int)(end - mFileBuffer));
|
GetS0(derived, (unsigned int)(end - mFileBuffer));
|
||||||
if (derived.length()) {
|
if (derived.length()) {
|
||||||
// yes, find this surface
|
// yes, find this surface
|
||||||
for (SurfaceList::iterator it = mSurfaces->begin(), end = mSurfaces->end()-1; it != end; ++it) {
|
for (SurfaceList::iterator it = mSurfaces->begin(), itEnd = mSurfaces->end() - 1; it != itEnd; ++it) {
|
||||||
if ((*it).mName == derived) {
|
if ((*it).mName == derived) {
|
||||||
// we have it ...
|
// we have it ...
|
||||||
surf = *it;
|
surf = *it;
|
||||||
derived.clear();break;
|
derived.clear();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (derived.size())
|
if (derived.size()) {
|
||||||
ASSIMP_LOG_WARN("LWO2: Unable to find source surface: " + derived);
|
ASSIMP_LOG_WARN("LWO2: Unable to find source surface: " + derived);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (true)
|
while (true) {
|
||||||
{
|
|
||||||
if (mFileBuffer + 6 >= end)
|
if (mFileBuffer + 6 >= end)
|
||||||
break;
|
break;
|
||||||
const IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
|
const IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
|
||||||
|
@ -761,120 +723,104 @@ void LWOImporter::LoadLWO2Surface(unsigned int size)
|
||||||
if (mFileBuffer + head.length > end)
|
if (mFileBuffer + head.length > end)
|
||||||
throw DeadlyImportError("LWO2: Invalid surface chunk length");
|
throw DeadlyImportError("LWO2: Invalid surface chunk length");
|
||||||
|
|
||||||
uint8_t* const next = mFileBuffer+head.length;
|
uint8_t *const next = mFileBuffer + head.length;
|
||||||
switch (head.type)
|
switch (head.type) {
|
||||||
{
|
|
||||||
// diffuse color
|
// diffuse color
|
||||||
case AI_LWO_COLR:
|
case AI_LWO_COLR: {
|
||||||
{
|
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, COLR, 12);
|
||||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,COLR,12);
|
|
||||||
surf.mColor.r = GetF4();
|
surf.mColor.r = GetF4();
|
||||||
surf.mColor.g = GetF4();
|
surf.mColor.g = GetF4();
|
||||||
surf.mColor.b = GetF4();
|
surf.mColor.b = GetF4();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// diffuse strength ... hopefully
|
// diffuse strength ... hopefully
|
||||||
case AI_LWO_DIFF:
|
case AI_LWO_DIFF: {
|
||||||
{
|
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, DIFF, 4);
|
||||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,DIFF,4);
|
|
||||||
surf.mDiffuseValue = GetF4();
|
surf.mDiffuseValue = GetF4();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// specular strength ... hopefully
|
// specular strength ... hopefully
|
||||||
case AI_LWO_SPEC:
|
case AI_LWO_SPEC: {
|
||||||
{
|
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, SPEC, 4);
|
||||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,SPEC,4);
|
|
||||||
surf.mSpecularValue = GetF4();
|
surf.mSpecularValue = GetF4();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// transparency
|
// transparency
|
||||||
case AI_LWO_TRAN:
|
case AI_LWO_TRAN: {
|
||||||
{
|
|
||||||
// transparency explicitly disabled?
|
// transparency explicitly disabled?
|
||||||
if (surf.mTransparency == 10e10f)
|
if (surf.mTransparency == 10e10f)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,TRAN,4);
|
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, TRAN, 4);
|
||||||
surf.mTransparency = GetF4();
|
surf.mTransparency = GetF4();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// additive transparency
|
// additive transparency
|
||||||
case AI_LWO_ADTR:
|
case AI_LWO_ADTR: {
|
||||||
{
|
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, ADTR, 4);
|
||||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,ADTR,4);
|
|
||||||
surf.mAdditiveTransparency = GetF4();
|
surf.mAdditiveTransparency = GetF4();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// wireframe mode
|
// wireframe mode
|
||||||
case AI_LWO_LINE:
|
case AI_LWO_LINE: {
|
||||||
{
|
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, LINE, 2);
|
||||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,LINE,2);
|
|
||||||
if (GetU2() & 0x1)
|
if (GetU2() & 0x1)
|
||||||
surf.mWireframe = true;
|
surf.mWireframe = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// glossiness
|
// glossiness
|
||||||
case AI_LWO_GLOS:
|
case AI_LWO_GLOS: {
|
||||||
{
|
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, GLOS, 4);
|
||||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,GLOS,4);
|
|
||||||
surf.mGlossiness = GetF4();
|
surf.mGlossiness = GetF4();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// bump intensity
|
// bump intensity
|
||||||
case AI_LWO_BUMP:
|
case AI_LWO_BUMP: {
|
||||||
{
|
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, BUMP, 4);
|
||||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,BUMP,4);
|
|
||||||
surf.mBumpIntensity = GetF4();
|
surf.mBumpIntensity = GetF4();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// color highlights
|
// color highlights
|
||||||
case AI_LWO_CLRH:
|
case AI_LWO_CLRH: {
|
||||||
{
|
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, CLRH, 4);
|
||||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,CLRH,4);
|
|
||||||
surf.mColorHighlights = GetF4();
|
surf.mColorHighlights = GetF4();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// index of refraction
|
// index of refraction
|
||||||
case AI_LWO_RIND:
|
case AI_LWO_RIND: {
|
||||||
{
|
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, RIND, 4);
|
||||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,RIND,4);
|
|
||||||
surf.mIOR = GetF4();
|
surf.mIOR = GetF4();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// polygon sidedness
|
// polygon sidedness
|
||||||
case AI_LWO_SIDE:
|
case AI_LWO_SIDE: {
|
||||||
{
|
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, SIDE, 2);
|
||||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,SIDE,2);
|
|
||||||
surf.bDoubleSided = (3 == GetU2());
|
surf.bDoubleSided = (3 == GetU2());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// maximum smoothing angle
|
// maximum smoothing angle
|
||||||
case AI_LWO_SMAN:
|
case AI_LWO_SMAN: {
|
||||||
{
|
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, SMAN, 4);
|
||||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,SMAN,4);
|
surf.mMaximumSmoothAngle = std::fabs(GetF4());
|
||||||
surf.mMaximumSmoothAngle = std::fabs( GetF4() );
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// vertex color channel to be applied to the surface
|
// vertex color channel to be applied to the surface
|
||||||
case AI_LWO_VCOL:
|
case AI_LWO_VCOL: {
|
||||||
{
|
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, VCOL, 12);
|
||||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,VCOL,12);
|
|
||||||
surf.mDiffuseValue *= GetF4(); // strength
|
surf.mDiffuseValue *= GetF4(); // strength
|
||||||
ReadVSizedIntLWO2(mFileBuffer); // skip envelope
|
ReadVSizedIntLWO2(mFileBuffer); // skip envelope
|
||||||
surf.mVCMapType = GetU4(); // type of the channel
|
surf.mVCMapType = GetU4(); // type of the channel
|
||||||
|
|
||||||
// name of the channel
|
// name of the channel
|
||||||
GetS0(surf.mVCMap, (unsigned int) (next - mFileBuffer ));
|
GetS0(surf.mVCMap, (unsigned int)(next - mFileBuffer));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// surface bock entry
|
// surface bock entry
|
||||||
case AI_LWO_BLOK:
|
case AI_LWO_BLOK: {
|
||||||
{
|
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, BLOK, 4);
|
||||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,BLOK,4);
|
|
||||||
IFF::SubChunkHeader head2 = IFF::LoadSubChunk(mFileBuffer);
|
IFF::SubChunkHeader head2 = IFF::LoadSubChunk(mFileBuffer);
|
||||||
|
|
||||||
switch (head2.type)
|
switch (head2.type) {
|
||||||
{
|
|
||||||
case AI_LWO_PROC:
|
case AI_LWO_PROC:
|
||||||
case AI_LWO_GRAD:
|
case AI_LWO_GRAD:
|
||||||
case AI_LWO_IMAP:
|
case AI_LWO_IMAP:
|
||||||
|
|
|
@ -45,22 +45,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* @brief Implementation of the LWS importer class
|
* @brief Implementation of the LWS importer class
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_LWS_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_LWS_IMPORTER
|
||||||
|
|
||||||
#include "LWS/LWSLoader.h"
|
#include "LWS/LWSLoader.h"
|
||||||
#include "PostProcessing/ConvertToLHProcess.h"
|
|
||||||
#include "Common/Importer.h"
|
#include "Common/Importer.h"
|
||||||
|
#include "PostProcessing/ConvertToLHProcess.h"
|
||||||
|
|
||||||
#include <assimp/ParsingUtils.h>
|
|
||||||
#include <assimp/fast_atof.h>
|
|
||||||
#include <assimp/SceneCombiner.h>
|
|
||||||
#include <assimp/GenericProperty.h>
|
#include <assimp/GenericProperty.h>
|
||||||
|
#include <assimp/ParsingUtils.h>
|
||||||
|
#include <assimp/SceneCombiner.h>
|
||||||
#include <assimp/SkeletonMeshBuilder.h>
|
#include <assimp/SkeletonMeshBuilder.h>
|
||||||
#include <assimp/DefaultLogger.hpp>
|
#include <assimp/fast_atof.h>
|
||||||
#include <assimp/scene.h>
|
|
||||||
#include <assimp/IOSystem.hpp>
|
|
||||||
#include <assimp/importerdesc.h>
|
#include <assimp/importerdesc.h>
|
||||||
|
#include <assimp/scene.h>
|
||||||
|
#include <assimp/DefaultLogger.hpp>
|
||||||
|
#include <assimp/IOSystem.hpp>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -81,9 +80,8 @@ static const 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) {
|
||||||
{
|
for (; SkipSpacesAndLineEnd(&buffer); SkipLine(&buffer)) {
|
||||||
for (;SkipSpacesAndLineEnd(&buffer);SkipLine(&buffer)) {
|
|
||||||
|
|
||||||
// begin of a new element with children
|
// begin of a new element with children
|
||||||
bool sub = false;
|
bool sub = false;
|
||||||
|
@ -91,27 +89,26 @@ void LWS::Element::Parse (const char*& buffer)
|
||||||
++buffer;
|
++buffer;
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&buffer);
|
||||||
sub = true;
|
sub = true;
|
||||||
}
|
} else if (*buffer == '}')
|
||||||
else if (*buffer == '}')
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
children.push_back(Element());
|
children.push_back(Element());
|
||||||
|
|
||||||
// copy data line - read token per token
|
// copy data line - read token per token
|
||||||
|
|
||||||
const char* cur = buffer;
|
const char *cur = buffer;
|
||||||
while (!IsSpaceOrNewLine(*buffer)) ++buffer;
|
while (!IsSpaceOrNewLine(*buffer))
|
||||||
children.back().tokens[0] = std::string(cur,(size_t) (buffer-cur));
|
++buffer;
|
||||||
|
children.back().tokens[0] = std::string(cur, (size_t)(buffer - cur));
|
||||||
SkipSpaces(&buffer);
|
SkipSpaces(&buffer);
|
||||||
|
|
||||||
if (children.back().tokens[0] == "Plugin")
|
if (children.back().tokens[0] == "Plugin") {
|
||||||
{
|
|
||||||
ASSIMP_LOG_DEBUG("LWS: Skipping over plugin-specific data");
|
ASSIMP_LOG_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); SkipLine(&buffer)) {
|
||||||
if (!::strncmp(buffer,"EndPlugin",9)) {
|
if (!::strncmp(buffer, "EndPlugin", 9)) {
|
||||||
//SkipLine(&buffer);
|
//SkipLine(&buffer);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -120,8 +117,9 @@ void LWS::Element::Parse (const char*& buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
cur = buffer;
|
cur = buffer;
|
||||||
while (!IsLineEnd(*buffer)) ++buffer;
|
while (!IsLineEnd(*buffer))
|
||||||
children.back().tokens[1] = std::string(cur,(size_t) (buffer-cur));
|
++buffer;
|
||||||
|
children.back().tokens[1] = std::string(cur, (size_t)(buffer - cur));
|
||||||
|
|
||||||
// parse more elements recursively
|
// parse more elements recursively
|
||||||
if (sub)
|
if (sub)
|
||||||
|
@ -131,28 +129,25 @@ void LWS::Element::Parse (const char*& buffer)
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructor to be privately used by Importer
|
// Constructor to be privately used by Importer
|
||||||
LWSImporter::LWSImporter()
|
LWSImporter::LWSImporter() :
|
||||||
: configSpeedFlag(),
|
configSpeedFlag(),
|
||||||
io(),
|
io(),
|
||||||
first(),
|
first(),
|
||||||
last(),
|
last(),
|
||||||
fps(),
|
fps(),
|
||||||
noSkeletonMesh()
|
noSkeletonMesh() {
|
||||||
{
|
|
||||||
// nothing to do here
|
// nothing to do here
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Destructor, private as well
|
// Destructor, private as well
|
||||||
LWSImporter::~LWSImporter()
|
LWSImporter::~LWSImporter() {
|
||||||
{
|
|
||||||
// nothing to do here
|
// nothing to do here
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// 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 LWSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler,bool checkSig) const
|
bool LWSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
|
||||||
{
|
|
||||||
const std::string extension = GetExtension(pFile);
|
const std::string extension = GetExtension(pFile);
|
||||||
if (extension == "lws" || extension == "mot")
|
if (extension == "lws" || extension == "mot")
|
||||||
return true;
|
return true;
|
||||||
|
@ -162,24 +157,22 @@ bool LWSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler,bool c
|
||||||
uint32_t tokens[2];
|
uint32_t tokens[2];
|
||||||
tokens[0] = AI_MAKE_MAGIC("LWSC");
|
tokens[0] = AI_MAKE_MAGIC("LWSC");
|
||||||
tokens[1] = AI_MAKE_MAGIC("LWMO");
|
tokens[1] = AI_MAKE_MAGIC("LWMO");
|
||||||
return CheckMagicToken(pIOHandler,pFile,tokens,2);
|
return CheckMagicToken(pIOHandler, pFile, tokens, 2);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Get list of file extensions
|
// Get list of file extensions
|
||||||
const aiImporterDesc* LWSImporter::GetInfo () const
|
const aiImporterDesc *LWSImporter::GetInfo() const {
|
||||||
{
|
|
||||||
return &desc;
|
return &desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Setup configuration properties
|
// Setup configuration properties
|
||||||
void LWSImporter::SetupProperties(const Importer* pImp)
|
void LWSImporter::SetupProperties(const Importer *pImp) {
|
||||||
{
|
|
||||||
// AI_CONFIG_FAVOUR_SPEED
|
// AI_CONFIG_FAVOUR_SPEED
|
||||||
configSpeedFlag = (0 != pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED,0));
|
configSpeedFlag = (0 != pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED, 0));
|
||||||
|
|
||||||
// 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,
|
||||||
|
@ -190,41 +183,41 @@ void LWSImporter::SetupProperties(const Importer* pImp)
|
||||||
150392 /* magic hack */);
|
150392 /* magic hack */);
|
||||||
|
|
||||||
if (last < first) {
|
if (last < first) {
|
||||||
std::swap(last,first);
|
std::swap(last, first);
|
||||||
}
|
}
|
||||||
|
|
||||||
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
|
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Read an envelope description
|
// Read an envelope description
|
||||||
void LWSImporter::ReadEnvelope(const LWS::Element& dad, LWO::Envelope& fill )
|
void LWSImporter::ReadEnvelope(const LWS::Element &dad, LWO::Envelope &fill) {
|
||||||
{
|
|
||||||
if (dad.children.empty()) {
|
if (dad.children.empty()) {
|
||||||
ASSIMP_LOG_ERROR("LWS: Envelope descriptions must not be empty");
|
ASSIMP_LOG_ERROR("LWS: Envelope descriptions must not be empty");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// reserve enough storage
|
// reserve enough storage
|
||||||
std::list< LWS::Element >::const_iterator it = dad.children.begin();;
|
std::list<LWS::Element>::const_iterator it = dad.children.begin();
|
||||||
|
;
|
||||||
fill.keys.reserve(strtoul10(it->tokens[1].c_str()));
|
fill.keys.reserve(strtoul10(it->tokens[1].c_str()));
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
if ((*it).tokens[0] == "Key") {
|
if ((*it).tokens[0] == "Key") {
|
||||||
fill.keys.push_back(LWO::Key());
|
fill.keys.push_back(LWO::Key());
|
||||||
LWO::Key& key = fill.keys.back();
|
LWO::Key &key = fill.keys.back();
|
||||||
|
|
||||||
float f;
|
float f;
|
||||||
SkipSpaces(&c);
|
SkipSpaces(&c);
|
||||||
c = fast_atoreal_move<float>(c,key.value);
|
c = fast_atoreal_move<float>(c, key.value);
|
||||||
SkipSpaces(&c);
|
SkipSpaces(&c);
|
||||||
c = fast_atoreal_move<float>(c,f);
|
c = fast_atoreal_move<float>(c, f);
|
||||||
|
|
||||||
key.time = f;
|
key.time = f;
|
||||||
|
|
||||||
unsigned int span = strtoul10(c,&c), num = 0;
|
unsigned int span = strtoul10(c, &c), num = 0;
|
||||||
switch (span) {
|
switch (span) {
|
||||||
|
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -251,16 +244,15 @@ void LWSImporter::ReadEnvelope(const LWS::Element& dad, LWO::Envelope& fill )
|
||||||
default:
|
default:
|
||||||
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);
|
||||||
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);
|
||||||
fill.pre = (LWO::PrePostBehaviour) strtoul10(c,&c);
|
fill.pre = (LWO::PrePostBehaviour)strtoul10(c, &c);
|
||||||
SkipSpaces(&c);
|
SkipSpaces(&c);
|
||||||
fill.post = (LWO::PrePostBehaviour) strtoul10(c,&c);
|
fill.post = (LWO::PrePostBehaviour)strtoul10(c, &c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,36 +260,35 @@ 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,
|
std::list<LWS::Element>::const_iterator &it,
|
||||||
const std::list< LWS::Element >::const_iterator& end,
|
const std::list<LWS::Element>::const_iterator &end,
|
||||||
LWS::NodeDesc& nodes,
|
LWS::NodeDesc &nodes,
|
||||||
unsigned int /*version*/)
|
unsigned int /*version*/) {
|
||||||
{
|
unsigned int num, sub_num;
|
||||||
unsigned int num,sub_num;
|
if (++it == end) goto unexpected_end;
|
||||||
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.push_back(LWO::Envelope());
|
nodes.channels.push_back(LWO::Envelope());
|
||||||
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)goto unexpected_end;
|
if (++it == end) goto unexpected_end;
|
||||||
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 == end)goto unexpected_end;
|
if (++it == end) goto unexpected_end;
|
||||||
|
|
||||||
// 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);
|
SkipSpaces(&c);
|
||||||
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;
|
||||||
|
|
||||||
envl.keys.push_back(key);
|
envl.keys.push_back(key);
|
||||||
|
@ -311,8 +302,7 @@ unexpected_end:
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Setup a nice name for a node
|
// Setup a nice name for a node
|
||||||
void LWSImporter::SetupNodeName(aiNode* nd, LWS::NodeDesc& src)
|
void LWSImporter::SetupNodeName(aiNode *nd, LWS::NodeDesc &src) {
|
||||||
{
|
|
||||||
const unsigned int combined = src.number | ((unsigned int)src.type) << 28u;
|
const unsigned int combined = src.number | ((unsigned int)src.type) << 28u;
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -323,39 +313,38 @@ void LWSImporter::SetupNodeName(aiNode* nd, LWS::NodeDesc& src)
|
||||||
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)
|
||||||
s = 0;
|
s = 0;
|
||||||
else ++s;
|
else
|
||||||
|
++s;
|
||||||
std::string::size_type t = src.path.substr(s).find_last_of(".");
|
std::string::size_type t = src.path.substr(s).find_last_of(".");
|
||||||
|
|
||||||
nd->mName.length = ::ai_snprintf(nd->mName.data, MAXLEN, "%s_(%08X)",src.path.substr(s).substr(0,t).c_str(),combined);
|
nd->mName.length = ::ai_snprintf(nd->mName.data, MAXLEN, "%s_(%08X)", src.path.substr(s).substr(0, t).c_str(), combined);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nd->mName.length = ::ai_snprintf(nd->mName.data, MAXLEN, "%s_(%08X)",src.name,combined);
|
nd->mName.length = ::ai_snprintf(nd->mName.data, MAXLEN, "%s_(%08X)", src.name, combined);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Recursively build the scenegraph
|
// Recursively build the scenegraph
|
||||||
void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<AttachmentInfo>& attach,
|
void LWSImporter::BuildGraph(aiNode *nd, LWS::NodeDesc &src, std::vector<AttachmentInfo> &attach,
|
||||||
BatchLoader& batch,
|
BatchLoader &batch,
|
||||||
aiCamera**& camOut,
|
aiCamera **&camOut,
|
||||||
aiLight**& lightOut,
|
aiLight **&lightOut,
|
||||||
std::vector<aiNodeAnim*>& animOut)
|
std::vector<aiNodeAnim *> &animOut) {
|
||||||
{
|
|
||||||
// Setup a very cryptic name for the node, we want the user to be happy
|
// Setup a very cryptic name for the node, we want the user to be happy
|
||||||
SetupNodeName(nd,src);
|
SetupNodeName(nd, src);
|
||||||
aiNode* ndAnim = nd;
|
aiNode *ndAnim = nd;
|
||||||
|
|
||||||
// If the node is an object
|
// If the node is an object
|
||||||
if (src.type == LWS::NodeDesc::OBJECT) {
|
if (src.type == LWS::NodeDesc::OBJECT) {
|
||||||
|
|
||||||
// If the object is from an external file, get it
|
// If the object is from an external file, get it
|
||||||
aiScene* obj = NULL;
|
aiScene *obj = NULL;
|
||||||
if (src.path.length() ) {
|
if (src.path.length()) {
|
||||||
obj = batch.GetImport(src.id);
|
obj = batch.GetImport(src.id);
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
ASSIMP_LOG_ERROR("LWS: Failed to read external file " + src.path);
|
ASSIMP_LOG_ERROR("LWS: Failed to read external file " + src.path);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (obj->mRootNode->mNumChildren == 1) {
|
if (obj->mRootNode->mNumChildren == 1) {
|
||||||
|
|
||||||
//If the pivot is not set for this layer, get it from the external object
|
//If the pivot is not set for this layer, get it from the external object
|
||||||
|
@ -366,7 +355,7 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<Attachm
|
||||||
}
|
}
|
||||||
|
|
||||||
//Remove first node from obj (the old pivot), reset transform of second node (the mesh node)
|
//Remove first node from obj (the old pivot), reset transform of second node (the mesh node)
|
||||||
aiNode* newRootNode = obj->mRootNode->mChildren[0];
|
aiNode *newRootNode = obj->mRootNode->mChildren[0];
|
||||||
obj->mRootNode->mChildren[0] = NULL;
|
obj->mRootNode->mChildren[0] = NULL;
|
||||||
delete obj->mRootNode;
|
delete obj->mRootNode;
|
||||||
|
|
||||||
|
@ -384,7 +373,7 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<Attachm
|
||||||
|
|
||||||
//Add the attachment node to it
|
//Add the attachment node to it
|
||||||
nd->mNumChildren = 1;
|
nd->mNumChildren = 1;
|
||||||
nd->mChildren = new aiNode*[1];
|
nd->mChildren = new aiNode *[1];
|
||||||
nd->mChildren[0] = new aiNode();
|
nd->mChildren[0] = new aiNode();
|
||||||
nd->mChildren[0]->mParent = nd;
|
nd->mChildren[0]->mParent = nd;
|
||||||
nd->mChildren[0]->mTransformation.a4 = -src.pivotPos.x;
|
nd->mChildren[0]->mTransformation.a4 = -src.pivotPos.x;
|
||||||
|
@ -397,16 +386,16 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<Attachm
|
||||||
|
|
||||||
//Push attachment, if the object came from an external file
|
//Push attachment, if the object came from an external file
|
||||||
if (obj) {
|
if (obj) {
|
||||||
attach.push_back(AttachmentInfo(obj,nd));
|
attach.push_back(AttachmentInfo(obj, nd));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If object is a light source - setup a corresponding ai structure
|
// If object is a light source - setup a corresponding ai structure
|
||||||
else if (src.type == LWS::NodeDesc::LIGHT) {
|
else if (src.type == LWS::NodeDesc::LIGHT) {
|
||||||
aiLight* lit = *lightOut++ = new aiLight();
|
aiLight *lit = *lightOut++ = new aiLight();
|
||||||
|
|
||||||
// compute final light color
|
// compute final light color
|
||||||
lit->mColorDiffuse = lit->mColorSpecular = src.lightColor*src.lightIntensity;
|
lit->mColorDiffuse = lit->mColorSpecular = src.lightColor * src.lightIntensity;
|
||||||
|
|
||||||
// name to attach light to node -> unique due to LWs indexing system
|
// name to attach light to node -> unique due to LWs indexing system
|
||||||
lit->mName = nd->mName;
|
lit->mName = nd->mName;
|
||||||
|
@ -415,14 +404,13 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<Attachm
|
||||||
if (src.lightType == 2) { /* spot light */
|
if (src.lightType == 2) { /* spot light */
|
||||||
|
|
||||||
lit->mType = aiLightSource_SPOT;
|
lit->mType = aiLightSource_SPOT;
|
||||||
lit->mAngleInnerCone = (float)AI_DEG_TO_RAD( src.lightConeAngle );
|
lit->mAngleInnerCone = (float)AI_DEG_TO_RAD(src.lightConeAngle);
|
||||||
lit->mAngleOuterCone = lit->mAngleInnerCone+(float)AI_DEG_TO_RAD( src.lightEdgeAngle );
|
lit->mAngleOuterCone = lit->mAngleInnerCone + (float)AI_DEG_TO_RAD(src.lightEdgeAngle);
|
||||||
|
|
||||||
}
|
} else if (src.lightType == 1) { /* directional light source */
|
||||||
else if (src.lightType == 1) { /* directional light source */
|
|
||||||
lit->mType = aiLightSource_DIRECTIONAL;
|
lit->mType = aiLightSource_DIRECTIONAL;
|
||||||
}
|
} else
|
||||||
else lit->mType = aiLightSource_POINT;
|
lit->mType = aiLightSource_POINT;
|
||||||
|
|
||||||
// fixme: no proper handling of light falloffs yet
|
// fixme: no proper handling of light falloffs yet
|
||||||
if (src.lightFalloffType == 1)
|
if (src.lightFalloffType == 1)
|
||||||
|
@ -435,22 +423,22 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<Attachm
|
||||||
|
|
||||||
// If object is a camera - setup a corresponding ai structure
|
// If object is a camera - setup a corresponding ai structure
|
||||||
else if (src.type == LWS::NodeDesc::CAMERA) {
|
else if (src.type == LWS::NodeDesc::CAMERA) {
|
||||||
aiCamera* cam = *camOut++ = new aiCamera();
|
aiCamera *cam = *camOut++ = new aiCamera();
|
||||||
|
|
||||||
// name to attach cam to node -> unique due to LWs indexing system
|
// name to attach cam to node -> unique due to LWs indexing system
|
||||||
cam->mName = nd->mName;
|
cam->mName = nd->mName;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the node transformation from the LWO key
|
// Get the node transformation from the LWO key
|
||||||
LWO::AnimResolver resolver(src.channels,fps);
|
LWO::AnimResolver resolver(src.channels, fps);
|
||||||
resolver.ExtractBindPose(ndAnim->mTransformation);
|
resolver.ExtractBindPose(ndAnim->mTransformation);
|
||||||
|
|
||||||
// .. and construct animation channels
|
// .. and construct animation channels
|
||||||
aiNodeAnim* anim = NULL;
|
aiNodeAnim *anim = NULL;
|
||||||
|
|
||||||
if (first != last) {
|
if (first != last) {
|
||||||
resolver.SetAnimationRange(first,last);
|
resolver.SetAnimationRange(first, last);
|
||||||
resolver.ExtractAnimChannel(&anim,AI_LWO_ANIM_FLAG_SAMPLE_ANIMS|AI_LWO_ANIM_FLAG_START_AT_ZERO);
|
resolver.ExtractAnimChannel(&anim, AI_LWO_ANIM_FLAG_SAMPLE_ANIMS | AI_LWO_ANIM_FLAG_START_AT_ZERO);
|
||||||
if (anim) {
|
if (anim) {
|
||||||
anim->mNodeName = ndAnim->mName;
|
anim->mNodeName = ndAnim->mName;
|
||||||
animOut.push_back(anim);
|
animOut.push_back(anim);
|
||||||
|
@ -459,27 +447,25 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<Attachm
|
||||||
|
|
||||||
// Add children
|
// Add children
|
||||||
if (!src.children.empty()) {
|
if (!src.children.empty()) {
|
||||||
nd->mChildren = new aiNode*[src.children.size()];
|
nd->mChildren = new aiNode *[src.children.size()];
|
||||||
for (std::list<LWS::NodeDesc*>::iterator it = src.children.begin(); it != src.children.end(); ++it) {
|
for (std::list<LWS::NodeDesc *>::iterator it = src.children.begin(); it != src.children.end(); ++it) {
|
||||||
aiNode* ndd = nd->mChildren[nd->mNumChildren++] = new aiNode();
|
aiNode *ndd = nd->mChildren[nd->mNumChildren++] = new aiNode();
|
||||||
ndd->mParent = nd;
|
ndd->mParent = nd;
|
||||||
|
|
||||||
BuildGraph(ndd,**it,attach,batch,camOut,lightOut,animOut);
|
BuildGraph(ndd, **it, attach, batch, camOut, lightOut, animOut);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Determine the exact location of a LWO file
|
// Determine the exact location of a LWO file
|
||||||
std::string LWSImporter::FindLWOFile(const std::string& in)
|
std::string LWSImporter::FindLWOFile(const std::string &in) {
|
||||||
{
|
|
||||||
// insert missing directory separator if necessary
|
// insert missing directory separator if necessary
|
||||||
std::string tmp;
|
std::string tmp;
|
||||||
if (in.length() > 3 && in[1] == ':'&& in[2] != '\\' && in[2] != '/')
|
if (in.length() > 3 && in[1] == ':' && in[2] != '\\' && in[2] != '/') {
|
||||||
{
|
|
||||||
tmp = in[0] + (std::string(":\\") + in.substr(2));
|
tmp = in[0] + (std::string(":\\") + in.substr(2));
|
||||||
}
|
} else
|
||||||
else tmp = in;
|
tmp = in;
|
||||||
|
|
||||||
if (io->Exists(tmp)) {
|
if (io->Exists(tmp)) {
|
||||||
return in;
|
return in;
|
||||||
|
@ -503,35 +489,34 @@ std::string LWSImporter::FindLWOFile(const std::string& in)
|
||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// return original path, maybe the IOsystem knows better
|
// return original path, maybe the IOsystem knows better
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Read file into given scene data structure
|
// Read file into given scene data structure
|
||||||
void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene,
|
||||||
IOSystem* pIOHandler)
|
IOSystem *pIOHandler) {
|
||||||
{
|
|
||||||
io = pIOHandler;
|
io = pIOHandler;
|
||||||
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
|
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
|
||||||
|
|
||||||
// Check whether we can read from the file
|
// Check whether we can read from the file
|
||||||
if( file.get() == NULL) {
|
if (file.get() == NULL) {
|
||||||
throw DeadlyImportError( "Failed to open LWS file " + pFile + ".");
|
throw DeadlyImportError("Failed to open LWS 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
|
||||||
std::vector< char > mBuffer;
|
std::vector<char> mBuffer;
|
||||||
TextFileToBuffer(file.get(),mBuffer);
|
TextFileToBuffer(file.get(), mBuffer);
|
||||||
|
|
||||||
// Parse the file structure
|
// Parse the file structure
|
||||||
LWS::Element root; const char* dummy = &mBuffer[0];
|
LWS::Element root;
|
||||||
|
const char *dummy = &mBuffer[0];
|
||||||
root.Parse(dummy);
|
root.Parse(dummy);
|
||||||
|
|
||||||
// Construct a Batchimporter to read more files recursively
|
// Construct a Batchimporter to read more files recursively
|
||||||
BatchLoader batch(pIOHandler);
|
BatchLoader batch(pIOHandler);
|
||||||
// batch.SetBasePath(pFile);
|
// batch.SetBasePath(pFile);
|
||||||
|
|
||||||
// Construct an array to receive the flat output graph
|
// Construct an array to receive the flat output graph
|
||||||
std::list<LWS::NodeDesc> nodes;
|
std::list<LWS::NodeDesc> nodes;
|
||||||
|
@ -541,7 +526,7 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
|
|
||||||
// check magic identifier, 'LWSC'
|
// check magic identifier, 'LWSC'
|
||||||
bool motion_file = false;
|
bool motion_file = false;
|
||||||
std::list< LWS::Element >::const_iterator it = root.children.begin();
|
std::list<LWS::Element>::const_iterator it = root.children.begin();
|
||||||
|
|
||||||
if ((*it).tokens[0] == "LWMO")
|
if ((*it).tokens[0] == "LWMO")
|
||||||
motion_file = true;
|
motion_file = true;
|
||||||
|
@ -559,49 +544,49 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
|
|
||||||
// Now read all elements in a very straghtforward manner
|
// Now read all elements in a very straghtforward 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();
|
||||||
|
|
||||||
// 'FirstFrame': begin of animation slice
|
// 'FirstFrame': begin of animation slice
|
||||||
if ((*it).tokens[0] == "FirstFrame") {
|
if ((*it).tokens[0] == "FirstFrame") {
|
||||||
if (150392. != first /* see SetupProperties() */)
|
if (150392. != first /* see SetupProperties() */)
|
||||||
first = strtoul10(c,&c)-1.; /* we're zero-based */
|
first = strtoul10(c, &c) - 1.; /* we're zero-based */
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'LastFrame': end of animation slice
|
// 'LastFrame': end of animation slice
|
||||||
else if ((*it).tokens[0] == "LastFrame") {
|
else if ((*it).tokens[0] == "LastFrame") {
|
||||||
if (150392. != last /* see SetupProperties() */)
|
if (150392. != last /* see SetupProperties() */)
|
||||||
last = strtoul10(c,&c)-1.; /* we're zero-based */
|
last = strtoul10(c, &c) - 1.; /* we're zero-based */
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'FramesPerSecond': frames per second
|
// 'FramesPerSecond': frames per second
|
||||||
else if ((*it).tokens[0] == "FramesPerSecond") {
|
else if ((*it).tokens[0] == "FramesPerSecond") {
|
||||||
fps = strtoul10(c,&c);
|
fps = strtoul10(c, &c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'LoadObjectLayer': load a layer of a specific LWO file
|
// 'LoadObjectLayer': load a layer of a specific LWO file
|
||||||
else if ((*it).tokens[0] == "LoadObjectLayer") {
|
else if ((*it).tokens[0] == "LoadObjectLayer") {
|
||||||
|
|
||||||
// get layer index
|
// get layer index
|
||||||
const int layer = strtoul10(c,&c);
|
const int layer = strtoul10(c, &c);
|
||||||
|
|
||||||
// setup the layer to be loaded
|
// setup the layer to be loaded
|
||||||
BatchLoader::PropertyMap props;
|
BatchLoader::PropertyMap props;
|
||||||
SetGenericProperty(props.ints,AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY,layer);
|
SetGenericProperty(props.ints, AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY, layer);
|
||||||
|
|
||||||
// add node to list
|
// add node to list
|
||||||
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);
|
||||||
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);
|
||||||
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);
|
||||||
|
|
||||||
nodes.push_back(d);
|
nodes.push_back(d);
|
||||||
num_object++;
|
num_object++;
|
||||||
|
@ -614,12 +599,12 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
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);
|
||||||
}
|
} else
|
||||||
else d.number = cur_object++;
|
d.number = cur_object++;
|
||||||
std::string path = FindLWOFile( c );
|
std::string path = FindLWOFile(c);
|
||||||
d.id = batch.AddLoadRequest(path,0,NULL);
|
d.id = batch.AddLoadRequest(path, 0, NULL);
|
||||||
|
|
||||||
d.path = path;
|
d.path = path;
|
||||||
nodes.push_back(d);
|
nodes.push_back(d);
|
||||||
|
@ -632,10 +617,10 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
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
|
||||||
d.number = strtoul16(c,&c) & AI_LWS_MASK;
|
d.number = strtoul16(c, &c) & AI_LWS_MASK;
|
||||||
SkipSpaces(&c);
|
SkipSpaces(&c);
|
||||||
}
|
} else
|
||||||
else d.number = cur_object++;
|
d.number = cur_object++;
|
||||||
d.name = c;
|
d.name = c;
|
||||||
nodes.push_back(d);
|
nodes.push_back(d);
|
||||||
|
|
||||||
|
@ -662,13 +647,13 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
|
|
||||||
// important: index of channel
|
// important: index of channel
|
||||||
nodes.back().channels.push_back(LWO::Envelope());
|
nodes.back().channels.push_back(LWO::Envelope());
|
||||||
LWO::Envelope& env = nodes.back().channels.back();
|
LWO::Envelope &env = nodes.back().channels.back();
|
||||||
|
|
||||||
env.index = strtoul10(c);
|
env.index = strtoul10(c);
|
||||||
|
|
||||||
// currently we can just interpret the standard channels 0...9
|
// currently we can just interpret the standard channels 0...9
|
||||||
// (hack) assume that index-i yields the binary channel type from LWO
|
// (hack) assume that index-i yields the binary channel type from LWO
|
||||||
env.type = (LWO::EnvelopeType)(env.index+1);
|
env.type = (LWO::EnvelopeType)(env.index + 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
// 'Envelope': a single animation channel
|
// 'Envelope': a single animation channel
|
||||||
|
@ -676,7 +661,7 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
if (nodes.empty() || nodes.back().channels.empty())
|
if (nodes.empty() || nodes.back().channels.empty())
|
||||||
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'Envelope\'");
|
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'Envelope\'");
|
||||||
else {
|
else {
|
||||||
ReadEnvelope((*it),nodes.back().channels.back());
|
ReadEnvelope((*it), nodes.back().channels.back());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 'ObjectMotion': animation information for older lightwave formats
|
// 'ObjectMotion': animation information for older lightwave formats
|
||||||
|
@ -687,7 +672,7 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
if (nodes.empty())
|
if (nodes.empty())
|
||||||
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'<Light|Object|Camera>Motion\'");
|
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'<Light|Object|Camera>Motion\'");
|
||||||
else {
|
else {
|
||||||
ReadEnvelope_Old(it,root.children.end(),nodes.back(),version);
|
ReadEnvelope_Old(it, root.children.end(), nodes.back(), version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 'Pre/PostBehavior': pre/post animation behaviour for LWSC 2
|
// 'Pre/PostBehavior': pre/post animation behaviour for LWSC 2
|
||||||
|
@ -695,11 +680,13 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
if (nodes.empty())
|
if (nodes.empty())
|
||||||
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'Pre/PostBehavior'");
|
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'Pre/PostBehavior'");
|
||||||
else {
|
else {
|
||||||
for (std::list<LWO::Envelope>::iterator it = nodes.back().channels.begin(); it != nodes.back().channels.end(); ++it) {
|
for (std::list<LWO::Envelope>::iterator envelopeIt = nodes.back().channels.begin(); envelopeIt != nodes.back().channels.end(); ++envelopeIt) {
|
||||||
// two ints per envelope
|
// two ints per envelope
|
||||||
LWO::Envelope& env = *it;
|
LWO::Envelope &env = *envelopeIt;
|
||||||
env.pre = (LWO::PrePostBehaviour) strtoul10(c,&c); SkipSpaces(&c);
|
env.pre = (LWO::PrePostBehaviour)strtoul10(c, &c);
|
||||||
env.post = (LWO::PrePostBehaviour) strtoul10(c,&c); SkipSpaces(&c);
|
SkipSpaces(&c);
|
||||||
|
env.post = (LWO::PrePostBehaviour)strtoul10(c, &c);
|
||||||
|
SkipSpaces(&c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -708,7 +695,8 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
if (nodes.empty())
|
if (nodes.empty())
|
||||||
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'ParentItem\'");
|
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'ParentItem\'");
|
||||||
|
|
||||||
else nodes.back().parent = strtoul16(c,&c);
|
else
|
||||||
|
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") {
|
||||||
|
@ -716,7 +704,7 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 'AddCamera': add a camera to the scenegraph
|
// 'AddCamera': add a camera to the scenegraph
|
||||||
|
@ -727,9 +715,9 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
d.type = LWS::NodeDesc::CAMERA;
|
d.type = LWS::NodeDesc::CAMERA;
|
||||||
|
|
||||||
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++;
|
||||||
|
@ -739,7 +727,8 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
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 nodes.back().name = c;
|
else
|
||||||
|
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") {
|
||||||
|
@ -749,9 +738,9 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
d.type = LWS::NodeDesc::LIGHT;
|
d.type = LWS::NodeDesc::LIGHT;
|
||||||
|
|
||||||
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++;
|
||||||
|
@ -761,14 +750,16 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
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 nodes.back().name = c;
|
else
|
||||||
|
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)
|
||||||
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightIntensity\'");
|
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightIntensity\'");
|
||||||
|
|
||||||
else fast_atoreal_move<float>(c, nodes.back().lightIntensity );
|
else
|
||||||
|
fast_atoreal_move<float>(c, nodes.back().lightIntensity);
|
||||||
|
|
||||||
}
|
}
|
||||||
// 'LightType': set type of currently active light
|
// 'LightType': set type of currently active light
|
||||||
|
@ -776,7 +767,8 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
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 nodes.back().lightType = strtoul10(c);
|
else
|
||||||
|
nodes.back().lightType = strtoul10(c);
|
||||||
|
|
||||||
}
|
}
|
||||||
// 'LightFalloffType': set falloff type of currently active light
|
// 'LightFalloffType': set falloff type of currently active light
|
||||||
|
@ -784,7 +776,8 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
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 nodes.back().lightFalloffType = strtoul10(c);
|
else
|
||||||
|
nodes.back().lightFalloffType = strtoul10(c);
|
||||||
|
|
||||||
}
|
}
|
||||||
// 'LightConeAngle': set cone angle of currently active light
|
// 'LightConeAngle': set cone angle of currently active light
|
||||||
|
@ -792,7 +785,8 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
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 nodes.back().lightConeAngle = fast_atof(c);
|
else
|
||||||
|
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
|
||||||
|
@ -800,7 +794,8 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
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 nodes.back().lightEdgeAngle = fast_atof(c);
|
else
|
||||||
|
nodes.back().lightEdgeAngle = fast_atof(c);
|
||||||
|
|
||||||
}
|
}
|
||||||
// 'LightColor': set color of currently active light
|
// 'LightColor': set color of currently active light
|
||||||
|
@ -809,11 +804,11 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
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);
|
||||||
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);
|
||||||
c = fast_atoreal_move<float>(c, (float&) nodes.back().lightColor.b );
|
c = fast_atoreal_move<float>(c, (float &)nodes.back().lightColor.b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -822,11 +817,11 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
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);
|
||||||
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);
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
@ -834,79 +829,80 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve parenting
|
// resolve parenting
|
||||||
for (std::list<LWS::NodeDesc>::iterator it = nodes.begin(); it != nodes.end(); ++it) {
|
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 != it && *it == (*dit).parent) {
|
if (dit != ndIt && *ndIt == (*dit).parent) {
|
||||||
if ((*dit).parent_resolved) {
|
if ((*dit).parent_resolved) {
|
||||||
// fixme: it's still possible to produce an overflow due to cross references ..
|
// fixme: it's still possible to produce an overflow due to cross references ..
|
||||||
ASSIMP_LOG_ERROR("LWS: Found cross reference in scene-graph");
|
ASSIMP_LOG_ERROR("LWS: Found cross reference in scene-graph");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
(*it).children.push_back(&*dit);
|
ndIt->children.push_back(&*dit);
|
||||||
(*dit).parent_resolved = &*it;
|
(*dit).parent_resolved = &*ndIt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// find out how many nodes have no parent yet
|
// find out how many nodes have no parent yet
|
||||||
unsigned int no_parent = 0;
|
unsigned int no_parent = 0;
|
||||||
for (std::list<LWS::NodeDesc>::iterator it = nodes.begin(); it != nodes.end(); ++it) {
|
for (std::list<LWS::NodeDesc>::iterator ndIt = nodes.begin(); ndIt != nodes.end(); ++ndIt) {
|
||||||
if (!(*it).parent_resolved)
|
if (!ndIt->parent_resolved) {
|
||||||
++ no_parent;
|
++no_parent;
|
||||||
}
|
}
|
||||||
if (!no_parent)
|
}
|
||||||
|
if (!no_parent) {
|
||||||
throw DeadlyImportError("LWS: Unable to find scene root node");
|
throw DeadlyImportError("LWS: Unable to find scene root node");
|
||||||
|
}
|
||||||
|
|
||||||
// Load all subsequent files
|
// Load all subsequent files
|
||||||
batch.LoadAll();
|
batch.LoadAll();
|
||||||
|
|
||||||
// and build the final output graph by attaching the loaded external
|
// and build the final output graph by attaching the loaded external
|
||||||
// files to ourselves. first build a master graph
|
// files to ourselves. first build a master graph
|
||||||
aiScene* master = new aiScene();
|
aiScene *master = new aiScene();
|
||||||
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) {
|
||||||
master->mCameras = new aiCamera*[master->mNumCameras = num_camera];
|
master->mCameras = new aiCamera *[master->mNumCameras = num_camera];
|
||||||
}
|
}
|
||||||
aiCamera** cams = master->mCameras;
|
aiCamera **cams = master->mCameras;
|
||||||
if (num_light) {
|
if (num_light) {
|
||||||
master->mLights = new aiLight*[master->mNumLights = num_light];
|
master->mLights = new aiLight *[master->mNumLights = num_light];
|
||||||
}
|
}
|
||||||
aiLight** lights = master->mLights;
|
aiLight **lights = master->mLights;
|
||||||
|
|
||||||
std::vector<AttachmentInfo> attach;
|
std::vector<AttachmentInfo> attach;
|
||||||
std::vector<aiNodeAnim*> anims;
|
std::vector<aiNodeAnim *> anims;
|
||||||
|
|
||||||
nd->mName.Set("<LWSRoot>");
|
nd->mName.Set("<LWSRoot>");
|
||||||
nd->mChildren = new aiNode*[no_parent];
|
nd->mChildren = new aiNode *[no_parent];
|
||||||
for (std::list<LWS::NodeDesc>::iterator it = nodes.begin(); it != nodes.end(); ++it) {
|
for (std::list<LWS::NodeDesc>::iterator ndIt = nodes.begin(); ndIt != nodes.end(); ++ndIt) {
|
||||||
if (!(*it).parent_resolved) {
|
if (!ndIt->parent_resolved) {
|
||||||
aiNode* ro = nd->mChildren[ nd->mNumChildren++ ] = new aiNode();
|
aiNode *ro = nd->mChildren[nd->mNumChildren++] = new aiNode();
|
||||||
ro->mParent = nd;
|
ro->mParent = nd;
|
||||||
|
|
||||||
// ... and build the scene graph. If we encounter object nodes,
|
// ... and build the scene graph. If we encounter object nodes,
|
||||||
// add then to our attachment table.
|
// add then to our attachment table.
|
||||||
BuildGraph(ro,*it, attach, batch, cams, lights, anims);
|
BuildGraph(ro, *ndIt, attach, batch, cams, lights, anims);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a master animation channel for us
|
// create a master animation channel for us
|
||||||
if (anims.size()) {
|
if (anims.size()) {
|
||||||
master->mAnimations = new aiAnimation*[master->mNumAnimations = 1];
|
master->mAnimations = new aiAnimation *[master->mNumAnimations = 1];
|
||||||
aiAnimation* anim = master->mAnimations[0] = new aiAnimation();
|
aiAnimation *anim = master->mAnimations[0] = new aiAnimation();
|
||||||
anim->mName.Set("LWSMasterAnim");
|
anim->mName.Set("LWSMasterAnim");
|
||||||
|
|
||||||
// LWS uses seconds as time units, but we convert to frames
|
// LWS uses seconds as time units, but we convert to frames
|
||||||
anim->mTicksPerSecond = fps;
|
anim->mTicksPerSecond = fps;
|
||||||
anim->mDuration = last-(first-1); /* fixme ... zero or one-based?*/
|
anim->mDuration = last - (first - 1); /* fixme ... zero or one-based?*/
|
||||||
|
|
||||||
anim->mChannels = new aiNodeAnim*[anim->mNumChannels = static_cast<unsigned int>(anims.size())];
|
anim->mChannels = new aiNodeAnim *[anim->mNumChannels = static_cast<unsigned int>(anims.size())];
|
||||||
std::copy(anims.begin(),anims.end(),anim->mChannels);
|
std::copy(anims.begin(), anims.end(), anim->mChannels);
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert the master scene to RH
|
// convert the master scene to RH
|
||||||
|
@ -918,9 +914,10 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
flipper.Execute(master);
|
flipper.Execute(master);
|
||||||
|
|
||||||
// OK ... finally build the output graph
|
// OK ... finally build the output graph
|
||||||
SceneCombiner::MergeScenes(&pScene,master,attach,
|
SceneCombiner::MergeScenes(&pScene, master, attach,
|
||||||
AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | (!configSpeedFlag ? (
|
AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | (!configSpeedFlag ? (
|
||||||
AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY | AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) : 0));
|
AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY | AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) :
|
||||||
|
0));
|
||||||
|
|
||||||
// Check flags
|
// Check flags
|
||||||
if (!pScene->mNumMeshes || !pScene->mNumMaterials) {
|
if (!pScene->mNumMeshes || !pScene->mNumMaterials) {
|
||||||
|
@ -931,7 +928,6 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
SkeletonMeshBuilder builder(pScene);
|
SkeletonMeshBuilder builder(pScene);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // !! ASSIMP_BUILD_NO_LWS_IMPORTER
|
#endif // !! ASSIMP_BUILD_NO_LWS_IMPORTER
|
||||||
|
|
|
@ -56,9 +56,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <assimp/Importer.hpp>
|
#include <assimp/Importer.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "M3DWrapper.h"
|
|
||||||
#include "M3DImporter.h"
|
#include "M3DImporter.h"
|
||||||
#include "M3DMaterials.h"
|
#include "M3DMaterials.h"
|
||||||
|
#include "M3DWrapper.h"
|
||||||
|
|
||||||
// RESOURCES:
|
// RESOURCES:
|
||||||
// https://gitlab.com/bztsrc/model3d/blob/master/docs/m3d_format.md
|
// https://gitlab.com/bztsrc/model3d/blob/master/docs/m3d_format.md
|
||||||
|
@ -111,7 +111,7 @@ using namespace std;
|
||||||
M3DImporter::M3DImporter() :
|
M3DImporter::M3DImporter() :
|
||||||
mScene(nullptr) {
|
mScene(nullptr) {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Returns true, if file is a binary or ASCII Model 3D file.
|
// Returns true, if file is a binary or ASCII Model 3D file.
|
||||||
|
@ -173,12 +173,12 @@ void M3DImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSys
|
||||||
throw DeadlyImportError("Failed to read the file " + file + ".");
|
throw DeadlyImportError("Failed to read the file " + file + ".");
|
||||||
}
|
}
|
||||||
// extra check for binary format's first 8 bytes. Not done for the ASCII variant
|
// extra check for binary format's first 8 bytes. Not done for the ASCII variant
|
||||||
if(!memcmp(buffer.data(), "3DMO", 4) && memcmp(buffer.data() + 4, &fileSize, 4)) {
|
if (!memcmp(buffer.data(), "3DMO", 4) && memcmp(buffer.data() + 4, &fileSize, 4)) {
|
||||||
throw DeadlyImportError("Bad binary header in file " + file + ".");
|
throw DeadlyImportError("Bad binary header in file " + file + ".");
|
||||||
}
|
}
|
||||||
#ifdef M3D_ASCII
|
#ifdef M3D_ASCII
|
||||||
// make sure there's a terminator zero character, as input must be ASCIIZ
|
// make sure there's a terminator zero character, as input must be ASCIIZ
|
||||||
if(!memcmp(buffer.data(), "3dmo", 4)) {
|
if (!memcmp(buffer.data(), "3dmo", 4)) {
|
||||||
buffer.push_back(0);
|
buffer.push_back(0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -256,9 +256,9 @@ void M3DImporter::importMaterials(const M3DWrapper &m3d) {
|
||||||
|
|
||||||
for (i = 0; i < m3d->nummaterial; i++) {
|
for (i = 0; i < m3d->nummaterial; i++) {
|
||||||
m = &m3d->material[i];
|
m = &m3d->material[i];
|
||||||
aiMaterial *mat = new aiMaterial;
|
aiMaterial *newMat = new aiMaterial;
|
||||||
name.Set(std::string(m->name));
|
name.Set(std::string(m->name));
|
||||||
mat->AddProperty(&name, AI_MATKEY_NAME);
|
newMat->AddProperty(&name, AI_MATKEY_NAME);
|
||||||
for (j = 0; j < m->numprop; j++) {
|
for (j = 0; j < m->numprop; j++) {
|
||||||
// look up property type
|
// look up property type
|
||||||
// 0 - 127 scalar values,
|
// 0 - 127 scalar values,
|
||||||
|
@ -271,29 +271,36 @@ void M3DImporter::importMaterials(const M3DWrapper &m3d) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// should never happen, but be safe than sorry
|
// should never happen, but be safe than sorry
|
||||||
if (k == 256) continue;
|
if (k == 256)
|
||||||
|
continue;
|
||||||
|
|
||||||
// scalar properties
|
// scalar properties
|
||||||
if (m->prop[j].type < 128 && aiProps[k].pKey) {
|
if (m->prop[j].type < 128 && aiProps[k].pKey) {
|
||||||
switch (m3d_propertytypes[k].format) {
|
switch (m3d_propertytypes[k].format) {
|
||||||
case m3dpf_color:
|
case m3dpf_color:
|
||||||
c = mkColor(m->prop[j].value.color);
|
c = mkColor(m->prop[j].value.color);
|
||||||
mat->AddProperty(&c, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index);
|
newMat->AddProperty(&c, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index);
|
||||||
break;
|
break;
|
||||||
case m3dpf_float:
|
case m3dpf_float:
|
||||||
f = m->prop[j].value.fnum;
|
f = m->prop[j].value.fnum;
|
||||||
mat->AddProperty(&f, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index);
|
newMat->AddProperty(&f, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
n = m->prop[j].value.num;
|
n = m->prop[j].value.num;
|
||||||
if (m->prop[j].type == m3dp_il) {
|
if (m->prop[j].type == m3dp_il) {
|
||||||
switch (n) {
|
switch (n) {
|
||||||
case 0: n = aiShadingMode_NoShading; break;
|
case 0:
|
||||||
case 2: n = aiShadingMode_Phong; break;
|
n = aiShadingMode_NoShading;
|
||||||
default: n = aiShadingMode_Gouraud; break;
|
break;
|
||||||
|
case 2:
|
||||||
|
n = aiShadingMode_Phong;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
n = aiShadingMode_Gouraud;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mat->AddProperty(&n, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index);
|
newMat->AddProperty(&n, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -403,7 +410,6 @@ void M3DImporter::importMeshes(const M3DWrapper &m3d) {
|
||||||
ai_assert(m3d);
|
ai_assert(m3d);
|
||||||
ai_assert(mScene->mRootNode != nullptr);
|
ai_assert(mScene->mRootNode != nullptr);
|
||||||
|
|
||||||
|
|
||||||
for (i = 0; i < m3d->numface; i++) {
|
for (i = 0; i < m3d->numface; i++) {
|
||||||
// we must switch mesh if material changes
|
// we must switch mesh if material changes
|
||||||
if (lastMat != m3d->face[i].materialid) {
|
if (lastMat != m3d->face[i].materialid) {
|
||||||
|
@ -437,7 +443,7 @@ void M3DImporter::importMeshes(const M3DWrapper &m3d) {
|
||||||
k = static_cast<unsigned int>(vertices->size());
|
k = static_cast<unsigned int>(vertices->size());
|
||||||
pFace->mIndices[j] = k;
|
pFace->mIndices[j] = k;
|
||||||
l = m3d->face[i].vertex[j];
|
l = m3d->face[i].vertex[j];
|
||||||
if(l >= m3d->numvertex) continue;
|
if (l >= m3d->numvertex) continue;
|
||||||
pos.x = m3d->vertex[l].x;
|
pos.x = m3d->vertex[l].x;
|
||||||
pos.y = m3d->vertex[l].y;
|
pos.y = m3d->vertex[l].y;
|
||||||
pos.z = m3d->vertex[l].z;
|
pos.z = m3d->vertex[l].z;
|
||||||
|
@ -578,7 +584,7 @@ void M3DImporter::importAnimations(const M3DWrapper &m3d) {
|
||||||
ori = a->frame[j].transform[k].ori;
|
ori = a->frame[j].transform[k].ori;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(pos >= m3d->numvertex || ori >= m3d->numvertex) continue;
|
if (pos >= m3d->numvertex || ori >= m3d->numvertex) continue;
|
||||||
m3dv_t *v = &m3d->vertex[pos];
|
m3dv_t *v = &m3d->vertex[pos];
|
||||||
m3dv_t *q = &m3d->vertex[ori];
|
m3dv_t *q = &m3d->vertex[ori];
|
||||||
pAnim->mChannels[l]->mPositionKeys[j].mTime = t;
|
pAnim->mChannels[l]->mPositionKeys[j].mTime = t;
|
||||||
|
@ -750,7 +756,7 @@ void M3DImporter::populateMesh(const M3DWrapper &m3d, aiMesh *pMesh, std::vector
|
||||||
unsigned int i, j;
|
unsigned int i, j;
|
||||||
// first count how many vertices we have per bone
|
// first count how many vertices we have per bone
|
||||||
for (i = 0; i < vertexids->size(); i++) {
|
for (i = 0; i < vertexids->size(); i++) {
|
||||||
if(vertexids->at(i) >= m3d->numvertex) {
|
if (vertexids->at(i) >= m3d->numvertex) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
unsigned int s = m3d->vertex[vertexids->at(i)].skinid;
|
unsigned int s = m3d->vertex[vertexids->at(i)].skinid;
|
||||||
|
@ -776,11 +782,11 @@ void M3DImporter::populateMesh(const M3DWrapper &m3d, aiMesh *pMesh, std::vector
|
||||||
}
|
}
|
||||||
// fill up with data
|
// fill up with data
|
||||||
for (i = 0; i < vertexids->size(); i++) {
|
for (i = 0; i < vertexids->size(); i++) {
|
||||||
if(vertexids->at(i) >= m3d->numvertex) continue;
|
if (vertexids->at(i) >= m3d->numvertex) continue;
|
||||||
unsigned int s = m3d->vertex[vertexids->at(i)].skinid;
|
unsigned int s = m3d->vertex[vertexids->at(i)].skinid;
|
||||||
if (s != M3D_UNDEF && s != M3D_INDEXMAX && s < m3d->numskin) {
|
if (s != M3D_UNDEF && s != M3D_INDEXMAX && s < m3d->numskin) {
|
||||||
for (unsigned int k = 0; k < M3D_NUMBONE && m3d->skin[s].weight[k] > 0.0; k++) {
|
for (unsigned int k = 0; k < M3D_NUMBONE && m3d->skin[s].weight[k] > 0.0; k++) {
|
||||||
if(m3d->skin[s].boneid[k] >= m3d->numbone) continue;
|
if (m3d->skin[s].boneid[k] >= m3d->numbone) continue;
|
||||||
aiString name = aiString(std::string(m3d->bone[m3d->skin[s].boneid[k]].name));
|
aiString name = aiString(std::string(m3d->bone[m3d->skin[s].boneid[k]].name));
|
||||||
for (j = 0; j < pMesh->mNumBones; j++) {
|
for (j = 0; j < pMesh->mNumBones; j++) {
|
||||||
if (pMesh->mBones[j]->mName == name) {
|
if (pMesh->mBones[j]->mName == name) {
|
||||||
|
|
|
@ -100,6 +100,10 @@ M3DWrapper::M3DWrapper() {
|
||||||
}
|
}
|
||||||
|
|
||||||
M3DWrapper::M3DWrapper(IOSystem *pIOHandler, const std::vector<unsigned char> &buffer) {
|
M3DWrapper::M3DWrapper(IOSystem *pIOHandler, const std::vector<unsigned char> &buffer) {
|
||||||
|
if (nullptr == pIOHandler) {
|
||||||
|
ai_assert(nullptr != pIOHandler);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ASSIMP_USE_M3D_READFILECB
|
#ifdef ASSIMP_USE_M3D_READFILECB
|
||||||
// pass this IOHandler to the C callback in a thread-local pointer
|
// pass this IOHandler to the C callback in a thread-local pointer
|
||||||
m3dimporter_pIOHandler = pIOHandler;
|
m3dimporter_pIOHandler = pIOHandler;
|
||||||
|
|
|
@ -99,6 +99,10 @@ typedef uint16_t M3D_INDEX;
|
||||||
#define _register
|
#define _register
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4127 )
|
||||||
|
#pragma warning(disable : 4505 )
|
||||||
|
|
||||||
/*** File format structures ***/
|
/*** File format structures ***/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2162,8 +2166,8 @@ M3D_INDEX _m3d_gettx(m3d_t *model, m3dread_t readfilecb, m3dfree_t freecb, char
|
||||||
w = h = len = 0;
|
w = h = len = 0;
|
||||||
ri.bits_per_channel = 8;
|
ri.bits_per_channel = 8;
|
||||||
model->texture[i].d = (uint8_t*)stbi__png_load(&s, (int*)&w, (int*)&h, (int*)&len, 0, &ri);
|
model->texture[i].d = (uint8_t*)stbi__png_load(&s, (int*)&w, (int*)&h, (int*)&len, 0, &ri);
|
||||||
model->texture[i].w = w;
|
model->texture[i].w = (uint16_t) w;
|
||||||
model->texture[i].h = h;
|
model->texture[i].h = (uint16_t) h;
|
||||||
model->texture[i].f = (uint8_t)len;
|
model->texture[i].f = (uint8_t)len;
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
|
@ -5605,6 +5609,9 @@ namespace M3D {
|
||||||
|
|
||||||
#endif /* impl */
|
#endif /* impl */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma warning(pop<)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
|
@ -45,21 +45,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* @brief Implementation of the MD5 importer class
|
* @brief Implementation of the MD5 importer class
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_MD5_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_MD5_IMPORTER
|
||||||
|
|
||||||
// internal headers
|
// internal headers
|
||||||
#include <assimp/RemoveComments.h>
|
|
||||||
#include "MD5Loader.h"
|
#include "MD5Loader.h"
|
||||||
|
#include <assimp/MathFunctions.h>
|
||||||
|
#include <assimp/RemoveComments.h>
|
||||||
|
#include <assimp/SkeletonMeshBuilder.h>
|
||||||
#include <assimp/StringComparison.h>
|
#include <assimp/StringComparison.h>
|
||||||
#include <assimp/fast_atof.h>
|
#include <assimp/fast_atof.h>
|
||||||
#include <assimp/MathFunctions.h>
|
|
||||||
#include <assimp/SkeletonMeshBuilder.h>
|
|
||||||
#include <assimp/Importer.hpp>
|
|
||||||
#include <assimp/scene.h>
|
|
||||||
#include <assimp/IOSystem.hpp>
|
|
||||||
#include <assimp/DefaultLogger.hpp>
|
|
||||||
#include <assimp/importerdesc.h>
|
#include <assimp/importerdesc.h>
|
||||||
|
#include <assimp/scene.h>
|
||||||
|
#include <assimp/DefaultLogger.hpp>
|
||||||
|
#include <assimp/IOSystem.hpp>
|
||||||
|
#include <assimp/Importer.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
@ -67,7 +66,6 @@ using namespace Assimp;
|
||||||
// Minimum weight value. Weights inside [-n ... n] are ignored
|
// Minimum weight value. Weights inside [-n ... n] are ignored
|
||||||
#define AI_MD5_WEIGHT_EPSILON Math::getEpsilon<float>()
|
#define AI_MD5_WEIGHT_EPSILON Math::getEpsilon<float>()
|
||||||
|
|
||||||
|
|
||||||
static const aiImporterDesc desc = {
|
static const aiImporterDesc desc = {
|
||||||
"Doom 3 / MD5 Mesh Importer",
|
"Doom 3 / MD5 Mesh Importer",
|
||||||
"",
|
"",
|
||||||
|
@ -83,28 +81,20 @@ static const aiImporterDesc desc = {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructor to be privately used by Importer
|
// Constructor to be privately used by Importer
|
||||||
MD5Importer::MD5Importer()
|
MD5Importer::MD5Importer() :
|
||||||
: mIOHandler()
|
mIOHandler(nullptr), mBuffer(), fileSize(), iLineNumber(), pScene(), bHadMD5Mesh(), bHadMD5Anim(), bHadMD5Camera(), configNoAutoLoad(false) {
|
||||||
, mBuffer()
|
// empty
|
||||||
, fileSize()
|
}
|
||||||
, iLineNumber()
|
|
||||||
, pScene()
|
|
||||||
, pIOHandler()
|
|
||||||
, bHadMD5Mesh()
|
|
||||||
, bHadMD5Anim()
|
|
||||||
, bHadMD5Camera()
|
|
||||||
, configNoAutoLoad (false)
|
|
||||||
{}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Destructor, private as well
|
// Destructor, private as well
|
||||||
MD5Importer::~MD5Importer()
|
MD5Importer::~MD5Importer() {
|
||||||
{}
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// 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 MD5Importer::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
bool MD5Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
|
||||||
{
|
|
||||||
const std::string extension = GetExtension(pFile);
|
const std::string extension = GetExtension(pFile);
|
||||||
|
|
||||||
if (extension == "md5anim" || extension == "md5mesh" || extension == "md5camera")
|
if (extension == "md5anim" || extension == "md5mesh" || extension == "md5camera")
|
||||||
|
@ -113,63 +103,56 @@ bool MD5Importer::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool
|
||||||
if (!pIOHandler) {
|
if (!pIOHandler) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const char* tokens[] = {"MD5Version"};
|
const char *tokens[] = { "MD5Version" };
|
||||||
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
|
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Get list of all supported extensions
|
// Get list of all supported extensions
|
||||||
const aiImporterDesc* MD5Importer::GetInfo () const
|
const aiImporterDesc *MD5Importer::GetInfo() const {
|
||||||
{
|
|
||||||
return &desc;
|
return &desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Setup import properties
|
// Setup import properties
|
||||||
void MD5Importer::SetupProperties(const Importer* pImp)
|
void MD5Importer::SetupProperties(const Importer *pImp) {
|
||||||
{
|
|
||||||
// AI_CONFIG_IMPORT_MD5_NO_ANIM_AUTOLOAD
|
// AI_CONFIG_IMPORT_MD5_NO_ANIM_AUTOLOAD
|
||||||
configNoAutoLoad = (0 != pImp->GetPropertyInteger(AI_CONFIG_IMPORT_MD5_NO_ANIM_AUTOLOAD,0));
|
configNoAutoLoad = (0 != pImp->GetPropertyInteger(AI_CONFIG_IMPORT_MD5_NO_ANIM_AUTOLOAD, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Imports the given file into the given scene structure.
|
// Imports the given file into the given scene structure.
|
||||||
void MD5Importer::InternReadFile( const std::string& pFile,
|
void MD5Importer::InternReadFile(const std::string &pFile,
|
||||||
aiScene* _pScene, IOSystem* _pIOHandler)
|
aiScene *_pScene, IOSystem *pIOHandler) {
|
||||||
{
|
mIOHandler = pIOHandler;
|
||||||
pIOHandler = _pIOHandler;
|
|
||||||
pScene = _pScene;
|
pScene = _pScene;
|
||||||
bHadMD5Mesh = bHadMD5Anim = bHadMD5Camera = false;
|
bHadMD5Mesh = bHadMD5Anim = bHadMD5Camera = false;
|
||||||
|
|
||||||
// remove the file extension
|
// remove the file extension
|
||||||
const std::string::size_type pos = pFile.find_last_of('.');
|
const std::string::size_type pos = pFile.find_last_of('.');
|
||||||
mFile = (std::string::npos == pos ? pFile : pFile.substr(0,pos+1));
|
mFile = (std::string::npos == pos ? pFile : pFile.substr(0, pos + 1));
|
||||||
|
|
||||||
const std::string extension = GetExtension(pFile);
|
const std::string extension = GetExtension(pFile);
|
||||||
try {
|
try {
|
||||||
if (extension == "md5camera") {
|
if (extension == "md5camera") {
|
||||||
LoadMD5CameraFile();
|
LoadMD5CameraFile();
|
||||||
}
|
} else if (configNoAutoLoad || extension == "md5anim") {
|
||||||
else if (configNoAutoLoad || extension == "md5anim") {
|
|
||||||
// determine file extension and process just *one* file
|
// determine file extension and process just *one* file
|
||||||
if (extension.length() == 0) {
|
if (extension.length() == 0) {
|
||||||
throw DeadlyImportError("Failure, need file extension to determine MD5 part type");
|
throw DeadlyImportError("Failure, need file extension to determine MD5 part type");
|
||||||
}
|
}
|
||||||
if (extension == "md5anim") {
|
if (extension == "md5anim") {
|
||||||
LoadMD5AnimFile();
|
LoadMD5AnimFile();
|
||||||
}
|
} else if (extension == "md5mesh") {
|
||||||
else if (extension == "md5mesh") {
|
|
||||||
LoadMD5MeshFile();
|
LoadMD5MeshFile();
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
LoadMD5MeshFile();
|
LoadMD5MeshFile();
|
||||||
LoadMD5AnimFile();
|
LoadMD5AnimFile();
|
||||||
}
|
}
|
||||||
}
|
} catch (...) { // std::exception, Assimp::DeadlyImportError
|
||||||
catch ( ... ) { // std::exception, Assimp::DeadlyImportError
|
|
||||||
UnloadFileFromMemory();
|
UnloadFileFromMemory();
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
@ -180,8 +163,8 @@ void MD5Importer::InternReadFile( const std::string& pFile,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now rotate the whole scene 90 degrees around the x axis to match our internal coordinate system
|
// Now rotate the whole scene 90 degrees around the x axis to match our internal coordinate system
|
||||||
pScene->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f,
|
pScene->mRootNode->mTransformation = aiMatrix4x4(1.f, 0.f, 0.f, 0.f,
|
||||||
0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f);
|
0.f, 0.f, 1.f, 0.f, 0.f, -1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f);
|
||||||
|
|
||||||
// the output scene wouldn't pass the validation without this flag
|
// the output scene wouldn't pass the validation without this flag
|
||||||
if (!bHadMD5Mesh) {
|
if (!bHadMD5Mesh) {
|
||||||
|
@ -194,8 +177,7 @@ void MD5Importer::InternReadFile( const std::string& pFile,
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Load a file into a memory buffer
|
// Load a file into a memory buffer
|
||||||
void MD5Importer::LoadFileIntoMemory (IOStream* file)
|
void MD5Importer::LoadFileIntoMemory(IOStream *file) {
|
||||||
{
|
|
||||||
// unload the previous buffer, if any
|
// unload the previous buffer, if any
|
||||||
UnloadFileFromMemory();
|
UnloadFileFromMemory();
|
||||||
|
|
||||||
|
@ -204,21 +186,20 @@ void MD5Importer::LoadFileIntoMemory (IOStream* file)
|
||||||
ai_assert(fileSize);
|
ai_assert(fileSize);
|
||||||
|
|
||||||
// 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 = new char[fileSize+1];
|
mBuffer = new char[fileSize + 1];
|
||||||
file->Read( (void*)mBuffer, 1, fileSize);
|
file->Read((void *)mBuffer, 1, fileSize);
|
||||||
iLineNumber = 1;
|
iLineNumber = 1;
|
||||||
|
|
||||||
// append a terminal 0
|
// append a terminal 0
|
||||||
mBuffer[fileSize] = '\0';
|
mBuffer[fileSize] = '\0';
|
||||||
|
|
||||||
// now remove all line comments from the file
|
// now remove all line comments from the file
|
||||||
CommentRemover::RemoveLineComments("//",mBuffer,' ');
|
CommentRemover::RemoveLineComments("//", mBuffer, ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Unload the current memory buffer
|
// Unload the current memory buffer
|
||||||
void MD5Importer::UnloadFileFromMemory ()
|
void MD5Importer::UnloadFileFromMemory() {
|
||||||
{
|
|
||||||
// delete the file buffer
|
// delete the file buffer
|
||||||
delete[] mBuffer;
|
delete[] mBuffer;
|
||||||
mBuffer = NULL;
|
mBuffer = NULL;
|
||||||
|
@ -227,23 +208,22 @@ void MD5Importer::UnloadFileFromMemory ()
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Build unique vertices
|
// Build unique vertices
|
||||||
void MD5Importer::MakeDataUnique (MD5::MeshDesc& meshSrc)
|
void MD5Importer::MakeDataUnique(MD5::MeshDesc &meshSrc) {
|
||||||
{
|
std::vector<bool> abHad(meshSrc.mVertices.size(), false);
|
||||||
std::vector<bool> abHad(meshSrc.mVertices.size(),false);
|
|
||||||
|
|
||||||
// allocate enough storage to keep the output structures
|
// allocate enough storage to keep the output structures
|
||||||
const unsigned int iNewNum = static_cast<unsigned int>(meshSrc.mFaces.size()*3);
|
const unsigned int iNewNum = static_cast<unsigned int>(meshSrc.mFaces.size() * 3);
|
||||||
unsigned int iNewIndex = static_cast<unsigned int>(meshSrc.mVertices.size());
|
unsigned int iNewIndex = static_cast<unsigned int>(meshSrc.mVertices.size());
|
||||||
meshSrc.mVertices.resize(iNewNum);
|
meshSrc.mVertices.resize(iNewNum);
|
||||||
|
|
||||||
// try to guess how much storage we'll need for new weights
|
// try to guess how much storage we'll need for new weights
|
||||||
const float fWeightsPerVert = meshSrc.mWeights.size() / (float)iNewIndex;
|
const float fWeightsPerVert = meshSrc.mWeights.size() / (float)iNewIndex;
|
||||||
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 (FaceList::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()) {
|
||||||
throw DeadlyImportError("MD5MESH: Invalid vertex index");
|
throw DeadlyImportError("MD5MESH: Invalid vertex index");
|
||||||
}
|
}
|
||||||
|
@ -252,32 +232,31 @@ void MD5Importer::MakeDataUnique (MD5::MeshDesc& meshSrc)
|
||||||
// generate a new vertex
|
// generate a new vertex
|
||||||
meshSrc.mVertices[iNewIndex] = meshSrc.mVertices[face.mIndices[i]];
|
meshSrc.mVertices[iNewIndex] = meshSrc.mVertices[face.mIndices[i]];
|
||||||
face.mIndices[i] = iNewIndex++;
|
face.mIndices[i] = iNewIndex++;
|
||||||
}
|
} else
|
||||||
else abHad[face.mIndices[i]] = true;
|
abHad[face.mIndices[i]] = true;
|
||||||
}
|
}
|
||||||
// swap face order
|
// swap face order
|
||||||
std::swap(face.mIndices[0],face.mIndices[2]);
|
std::swap(face.mIndices[0], face.mIndices[2]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// 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, BoneList &bones) {
|
||||||
{
|
|
||||||
ai_assert(NULL != piParent && !piParent->mNumChildren);
|
ai_assert(NULL != piParent && !piParent->mNumChildren);
|
||||||
|
|
||||||
// First find out how many children we'll have
|
// First find out how many children we'll have
|
||||||
for (int i = 0; i < (int)bones.size();++i) {
|
for (int i = 0; i < (int)bones.size(); ++i) {
|
||||||
if (iParentID != i && bones[i].mParentIndex == iParentID) {
|
if (iParentID != i && bones[i].mParentIndex == iParentID) {
|
||||||
++piParent->mNumChildren;
|
++piParent->mNumChildren;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (piParent->mNumChildren) {
|
if (piParent->mNumChildren) {
|
||||||
piParent->mChildren = new aiNode*[piParent->mNumChildren];
|
piParent->mChildren = new aiNode *[piParent->mNumChildren];
|
||||||
for (int i = 0; i < (int)bones.size();++i) {
|
for (int i = 0; i < (int)bones.size(); ++i) {
|
||||||
// (avoid infinite recursion)
|
// (avoid infinite recursion)
|
||||||
if (iParentID != i && bones[i].mParentIndex == iParentID) {
|
if (iParentID != i && bones[i].mParentIndex == iParentID) {
|
||||||
aiNode* pc;
|
aiNode *pc;
|
||||||
// setup a new node
|
// setup a new node
|
||||||
*piParent->mChildren++ = pc = new aiNode();
|
*piParent->mChildren++ = pc = new aiNode();
|
||||||
pc->mName = aiString(bones[i].mName);
|
pc->mName = aiString(bones[i].mName);
|
||||||
|
@ -285,9 +264,9 @@ void MD5Importer::AttachChilds_Mesh(int iParentID,aiNode* piParent, BoneList& bo
|
||||||
|
|
||||||
// get the transformation matrix from rotation and translational components
|
// get the transformation matrix from rotation and translational components
|
||||||
aiQuaternion quat;
|
aiQuaternion quat;
|
||||||
MD5::ConvertQuaternion ( bones[i].mRotationQuat, quat );
|
MD5::ConvertQuaternion(bones[i].mRotationQuat, quat);
|
||||||
|
|
||||||
bones[i].mTransform = aiMatrix4x4 ( quat.GetMatrix());
|
bones[i].mTransform = aiMatrix4x4(quat.GetMatrix());
|
||||||
bones[i].mTransform.a4 = bones[i].mPositionXYZ.x;
|
bones[i].mTransform.a4 = bones[i].mPositionXYZ.x;
|
||||||
bones[i].mTransform.b4 = bones[i].mPositionXYZ.y;
|
bones[i].mTransform.b4 = bones[i].mPositionXYZ.y;
|
||||||
bones[i].mTransform.c4 = bones[i].mPositionXYZ.z;
|
bones[i].mTransform.c4 = bones[i].mPositionXYZ.z;
|
||||||
|
@ -303,7 +282,7 @@ void MD5Importer::AttachChilds_Mesh(int iParentID,aiNode* piParent, BoneList& bo
|
||||||
}
|
}
|
||||||
|
|
||||||
// add children to this node, too
|
// add children to this node, too
|
||||||
AttachChilds_Mesh( i, pc, bones);
|
AttachChilds_Mesh(i, pc, bones);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// undo offset computations
|
// undo offset computations
|
||||||
|
@ -313,37 +292,36 @@ void MD5Importer::AttachChilds_Mesh(int iParentID,aiNode* piParent, BoneList& bo
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// 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, AnimBoneList &bones, const aiNodeAnim **node_anims) {
|
||||||
{
|
|
||||||
ai_assert(NULL != piParent && !piParent->mNumChildren);
|
ai_assert(NULL != piParent && !piParent->mNumChildren);
|
||||||
|
|
||||||
// First find out how many children we'll have
|
// First find out how many children we'll have
|
||||||
for (int i = 0; i < (int)bones.size();++i) {
|
for (int i = 0; i < (int)bones.size(); ++i) {
|
||||||
if (iParentID != i && bones[i].mParentIndex == iParentID) {
|
if (iParentID != i && bones[i].mParentIndex == iParentID) {
|
||||||
++piParent->mNumChildren;
|
++piParent->mNumChildren;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (piParent->mNumChildren) {
|
if (piParent->mNumChildren) {
|
||||||
piParent->mChildren = new aiNode*[piParent->mNumChildren];
|
piParent->mChildren = new aiNode *[piParent->mNumChildren];
|
||||||
for (int i = 0; i < (int)bones.size();++i) {
|
for (int i = 0; i < (int)bones.size(); ++i) {
|
||||||
// (avoid infinite recursion)
|
// (avoid infinite recursion)
|
||||||
if (iParentID != i && bones[i].mParentIndex == iParentID)
|
if (iParentID != i && bones[i].mParentIndex == iParentID) {
|
||||||
{
|
aiNode *pc;
|
||||||
aiNode* pc;
|
|
||||||
// setup a new node
|
// setup a new node
|
||||||
*piParent->mChildren++ = pc = new aiNode();
|
*piParent->mChildren++ = pc = new aiNode();
|
||||||
pc->mName = aiString(bones[i].mName);
|
pc->mName = aiString(bones[i].mName);
|
||||||
pc->mParent = piParent;
|
pc->mParent = piParent;
|
||||||
|
|
||||||
// get the corresponding animation channel and its first frame
|
// get the corresponding animation channel and its first frame
|
||||||
const aiNodeAnim** cur = node_anims;
|
const aiNodeAnim **cur = node_anims;
|
||||||
while ((**cur).mNodeName != pc->mName)++cur;
|
while ((**cur).mNodeName != pc->mName)
|
||||||
|
++cur;
|
||||||
|
|
||||||
aiMatrix4x4::Translation((**cur).mPositionKeys[0].mValue,pc->mTransformation);
|
aiMatrix4x4::Translation((**cur).mPositionKeys[0].mValue, pc->mTransformation);
|
||||||
pc->mTransformation = pc->mTransformation * aiMatrix4x4((**cur).mRotationKeys[0].mValue.GetMatrix()) ;
|
pc->mTransformation = pc->mTransformation * aiMatrix4x4((**cur).mRotationKeys[0].mValue.GetMatrix());
|
||||||
|
|
||||||
// add children to this node, too
|
// add children to this node, too
|
||||||
AttachChilds_Anim( i, pc, bones,node_anims);
|
AttachChilds_Anim(i, pc, bones, node_anims);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// undo offset computations
|
// undo offset computations
|
||||||
|
@ -353,13 +331,12 @@ void MD5Importer::AttachChilds_Anim(int iParentID,aiNode* piParent, AnimBoneList
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Load a MD5MESH file
|
// Load a MD5MESH file
|
||||||
void MD5Importer::LoadMD5MeshFile ()
|
void MD5Importer::LoadMD5MeshFile() {
|
||||||
{
|
|
||||||
std::string pFile = mFile + "md5mesh";
|
std::string pFile = mFile + "md5mesh";
|
||||||
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
|
std::unique_ptr<IOStream> file(mIOHandler->Open(pFile, "rb"));
|
||||||
|
|
||||||
// Check whether we can read from the file
|
// Check whether we can read from the file
|
||||||
if( file.get() == NULL || !file->FileSize()) {
|
if (file.get() == nullptr || !file->FileSize()) {
|
||||||
ASSIMP_LOG_WARN("Failed to access MD5MESH file: " + pFile);
|
ASSIMP_LOG_WARN("Failed to access MD5MESH file: " + pFile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -367,7 +344,7 @@ void MD5Importer::LoadMD5MeshFile ()
|
||||||
LoadFileIntoMemory(file.get());
|
LoadFileIntoMemory(file.get());
|
||||||
|
|
||||||
// now construct a parser and parse the file
|
// now construct a parser and parse the file
|
||||||
MD5::MD5Parser parser(mBuffer,fileSize);
|
MD5::MD5Parser parser(mBuffer, fileSize);
|
||||||
|
|
||||||
// load the mesh information from it
|
// load the mesh information from it
|
||||||
MD5::MD5MeshParser meshParser(parser.mSections);
|
MD5::MD5MeshParser meshParser(parser.mSections);
|
||||||
|
@ -375,13 +352,13 @@ void MD5Importer::LoadMD5MeshFile ()
|
||||||
// create the bone hierarchy - first the root node and dummy nodes for all meshes
|
// create the bone hierarchy - first the root node and dummy nodes for all meshes
|
||||||
pScene->mRootNode = new aiNode("<MD5_Root>");
|
pScene->mRootNode = new aiNode("<MD5_Root>");
|
||||||
pScene->mRootNode->mNumChildren = 2;
|
pScene->mRootNode->mNumChildren = 2;
|
||||||
pScene->mRootNode->mChildren = new aiNode*[2];
|
pScene->mRootNode->mChildren = new aiNode *[2];
|
||||||
|
|
||||||
// build the hierarchy from the MD5MESH file
|
// build the hierarchy from the MD5MESH file
|
||||||
aiNode* pcNode = pScene->mRootNode->mChildren[1] = new aiNode();
|
aiNode *pcNode = pScene->mRootNode->mChildren[1] = new aiNode();
|
||||||
pcNode->mName.Set("<MD5_Hierarchy>");
|
pcNode->mName.Set("<MD5_Hierarchy>");
|
||||||
pcNode->mParent = pScene->mRootNode;
|
pcNode->mParent = pScene->mRootNode;
|
||||||
AttachChilds_Mesh(-1,pcNode,meshParser.mJoints);
|
AttachChilds_Mesh(-1, pcNode, meshParser.mJoints);
|
||||||
|
|
||||||
pcNode = pScene->mRootNode->mChildren[0] = new aiNode();
|
pcNode = pScene->mRootNode->mChildren[0] = new aiNode();
|
||||||
pcNode->mName.Set("<MD5_Mesh>");
|
pcNode->mName.Set("<MD5_Mesh>");
|
||||||
|
@ -393,96 +370,94 @@ void MD5Importer::LoadMD5MeshFile ()
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// FIX: MD5 files exported from Blender can have empty meshes
|
// FIX: MD5 files exported from Blender can have empty meshes
|
||||||
for (std::vector<MD5::MeshDesc>::const_iterator it = meshParser.mMeshes.begin(),end = meshParser.mMeshes.end(); it != end;++it) {
|
for (std::vector<MD5::MeshDesc>::const_iterator it = meshParser.mMeshes.begin(), end = meshParser.mMeshes.end(); it != end; ++it) {
|
||||||
if (!(*it).mFaces.empty() && !(*it).mVertices.empty())
|
if (!(*it).mFaces.empty() && !(*it).mVertices.empty())
|
||||||
++pScene->mNumMaterials;
|
++pScene->mNumMaterials;
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate all meshes
|
// generate all meshes
|
||||||
pScene->mNumMeshes = pScene->mNumMaterials;
|
pScene->mNumMeshes = pScene->mNumMaterials;
|
||||||
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
|
pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
|
||||||
pScene->mMaterials = new aiMaterial*[pScene->mNumMeshes];
|
pScene->mMaterials = new aiMaterial *[pScene->mNumMeshes];
|
||||||
|
|
||||||
// storage for node mesh indices
|
// storage for node mesh indices
|
||||||
pcNode->mNumMeshes = pScene->mNumMeshes;
|
pcNode->mNumMeshes = pScene->mNumMeshes;
|
||||||
pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
|
pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
|
||||||
for (unsigned int m = 0; m < pcNode->mNumMeshes;++m)
|
for (unsigned int m = 0; m < pcNode->mNumMeshes; ++m)
|
||||||
pcNode->mMeshes[m] = m;
|
pcNode->mMeshes[m] = m;
|
||||||
|
|
||||||
unsigned int n = 0;
|
unsigned int n = 0;
|
||||||
for (std::vector<MD5::MeshDesc>::iterator it = meshParser.mMeshes.begin(),end = meshParser.mMeshes.end(); it != end;++it) {
|
for (std::vector<MD5::MeshDesc>::iterator it = meshParser.mMeshes.begin(), end = meshParser.mMeshes.end(); it != end; ++it) {
|
||||||
MD5::MeshDesc& meshSrc = *it;
|
MD5::MeshDesc &meshSrc = *it;
|
||||||
if (meshSrc.mFaces.empty() || meshSrc.mVertices.empty())
|
if (meshSrc.mFaces.empty() || meshSrc.mVertices.empty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
aiMesh* mesh = pScene->mMeshes[n] = new aiMesh();
|
aiMesh *mesh = pScene->mMeshes[n] = new aiMesh();
|
||||||
mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
|
mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
|
||||||
|
|
||||||
// generate unique vertices in our internal verbose format
|
// generate unique vertices in our internal verbose format
|
||||||
MakeDataUnique(meshSrc);
|
MakeDataUnique(meshSrc);
|
||||||
|
|
||||||
std::string name( meshSrc.mShader.C_Str() );
|
std::string name(meshSrc.mShader.C_Str());
|
||||||
name += ".msh";
|
name += ".msh";
|
||||||
mesh->mName = name;
|
mesh->mName = name;
|
||||||
mesh->mNumVertices = (unsigned int) meshSrc.mVertices.size();
|
mesh->mNumVertices = (unsigned int)meshSrc.mVertices.size();
|
||||||
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
|
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
|
||||||
mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
|
mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
|
||||||
mesh->mNumUVComponents[0] = 2;
|
mesh->mNumUVComponents[0] = 2;
|
||||||
|
|
||||||
// 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::VertexList::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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort all bone weights - per bone
|
// sort all bone weights - per bone
|
||||||
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::VertexList::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 */
|
||||||
if (!(weightDesc.mWeight < AI_MD5_WEIGHT_EPSILON && weightDesc.mWeight >= -AI_MD5_WEIGHT_EPSILON ))
|
if (!(weightDesc.mWeight < AI_MD5_WEIGHT_EPSILON && weightDesc.mWeight >= -AI_MD5_WEIGHT_EPSILON))
|
||||||
++piCount[weightDesc.mBone];
|
++piCount[weightDesc.mBone];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check how many we will need
|
// check how many we will need
|
||||||
for (unsigned int p = 0; p < meshParser.mJoints.size();++p)
|
for (unsigned int p = 0; p < meshParser.mJoints.size(); ++p)
|
||||||
if (piCount[p])mesh->mNumBones++;
|
if (piCount[p]) mesh->mNumBones++;
|
||||||
|
|
||||||
if (mesh->mNumBones) // just for safety
|
if (mesh->mNumBones) // just for safety
|
||||||
{
|
{
|
||||||
mesh->mBones = new aiBone*[mesh->mNumBones];
|
mesh->mBones = new aiBone *[mesh->mNumBones];
|
||||||
for (unsigned int q = 0,h = 0; q < meshParser.mJoints.size();++q)
|
for (unsigned int q = 0, h = 0; q < meshParser.mJoints.size(); ++q) {
|
||||||
{
|
if (!piCount[q]) continue;
|
||||||
if (!piCount[q])continue;
|
aiBone *p = mesh->mBones[h] = new aiBone();
|
||||||
aiBone* p = mesh->mBones[h] = new aiBone();
|
|
||||||
p->mNumWeights = piCount[q];
|
p->mNumWeights = piCount[q];
|
||||||
p->mWeights = new aiVertexWeight[p->mNumWeights];
|
p->mWeights = new aiVertexWeight[p->mNumWeights];
|
||||||
p->mName = aiString(meshParser.mJoints[q].mName);
|
p->mName = aiString(meshParser.mJoints[q].mName);
|
||||||
p->mOffsetMatrix = meshParser.mJoints[q].mInvTransform;
|
p->mOffsetMatrix = meshParser.mJoints[q].mInvTransform;
|
||||||
|
|
||||||
// store the index for later use
|
// store the index for later use
|
||||||
MD5::BoneDesc& boneSrc = meshParser.mJoints[q];
|
MD5::BoneDesc &boneSrc = meshParser.mJoints[q];
|
||||||
boneSrc.mMap = h++;
|
boneSrc.mMap = h++;
|
||||||
|
|
||||||
// compute w-component of quaternion
|
// compute w-component of quaternion
|
||||||
MD5::ConvertQuaternion( boneSrc.mRotationQuat, boneSrc.mRotationQuatConverted );
|
MD5::ConvertQuaternion(boneSrc.mRotationQuat, boneSrc.mRotationQuatConverted);
|
||||||
}
|
}
|
||||||
|
|
||||||
pv = mesh->mVertices;
|
pv = mesh->mVertices;
|
||||||
for (MD5::VertexList::const_iterator iter = meshSrc.mVertices.begin();iter != meshSrc.mVertices.end();++iter,++pv) {
|
for (MD5::VertexList::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();
|
||||||
|
|
||||||
// there are models which have weights which don't sum to 1 ...
|
// there are models which have weights which don't sum to 1 ...
|
||||||
ai_real fSum = 0.0;
|
ai_real fSum = 0.0;
|
||||||
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)
|
||||||
fSum += meshSrc.mWeights[w].mWeight;
|
fSum += meshSrc.mWeights[w].mWeight;
|
||||||
if (!fSum) {
|
if (!fSum) {
|
||||||
ASSIMP_LOG_ERROR("MD5MESH: The sum of all vertex bone weights is 0");
|
ASSIMP_LOG_ERROR("MD5MESH: The sum of all vertex bone weights is 0");
|
||||||
|
@ -490,32 +465,32 @@ void MD5Importer::LoadMD5MeshFile ()
|
||||||
}
|
}
|
||||||
|
|
||||||
// process bone weights
|
// process bone weights
|
||||||
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) {
|
||||||
if (w >= meshSrc.mWeights.size())
|
if (w >= meshSrc.mWeights.size())
|
||||||
throw DeadlyImportError("MD5MESH: Invalid weight index");
|
throw DeadlyImportError("MD5MESH: Invalid weight index");
|
||||||
|
|
||||||
MD5::WeightDesc& weightDesc = meshSrc.mWeights[w];
|
MD5::WeightDesc &weightDesc = meshSrc.mWeights[w];
|
||||||
if ( weightDesc.mWeight < AI_MD5_WEIGHT_EPSILON && weightDesc.mWeight >= -AI_MD5_WEIGHT_EPSILON) {
|
if (weightDesc.mWeight < AI_MD5_WEIGHT_EPSILON && weightDesc.mWeight >= -AI_MD5_WEIGHT_EPSILON) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ai_real fNewWeight = weightDesc.mWeight / fSum;
|
const ai_real fNewWeight = weightDesc.mWeight / fSum;
|
||||||
|
|
||||||
// transform the local position into worldspace
|
// transform the local position into worldspace
|
||||||
MD5::BoneDesc& boneSrc = meshParser.mJoints[weightDesc.mBone];
|
MD5::BoneDesc &boneSrc = meshParser.mJoints[weightDesc.mBone];
|
||||||
const aiVector3D v = boneSrc.mRotationQuatConverted.Rotate (weightDesc.vOffsetPosition);
|
const aiVector3D v = boneSrc.mRotationQuatConverted.Rotate(weightDesc.vOffsetPosition);
|
||||||
|
|
||||||
// use the original weight to compute the vertex position
|
// use the original weight to compute the vertex position
|
||||||
// (some MD5s seem to depend on the invalid weight values ...)
|
// (some MD5s seem to depend on the invalid weight values ...)
|
||||||
*pv += ((boneSrc.mPositionXYZ+v)* (ai_real)weightDesc.mWeight);
|
*pv += ((boneSrc.mPositionXYZ + v) * (ai_real)weightDesc.mWeight);
|
||||||
|
|
||||||
aiBone* bone = mesh->mBones[boneSrc.mMap];
|
aiBone *bone = mesh->mBones[boneSrc.mMap];
|
||||||
*bone->mWeights++ = aiVertexWeight((unsigned int)(pv-mesh->mVertices),fNewWeight);
|
*bone->mWeights++ = aiVertexWeight((unsigned int)(pv - mesh->mVertices), fNewWeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// undo our nice offset tricks ...
|
// undo our nice offset tricks ...
|
||||||
for (unsigned int p = 0; p < mesh->mNumBones;++p) {
|
for (unsigned int p = 0; p < mesh->mNumBones; ++p) {
|
||||||
mesh->mBones[p]->mWeights -= mesh->mBones[p]->mNumWeights;
|
mesh->mBones[p]->mWeights -= mesh->mBones[p]->mNumWeights;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -526,14 +501,14 @@ void MD5Importer::LoadMD5MeshFile ()
|
||||||
// (however, take care that the aiFace destructor doesn't delete the mIndices array)
|
// (however, take care that the aiFace destructor doesn't delete the mIndices array)
|
||||||
mesh->mNumFaces = (unsigned int)meshSrc.mFaces.size();
|
mesh->mNumFaces = (unsigned int)meshSrc.mFaces.size();
|
||||||
mesh->mFaces = new aiFace[mesh->mNumFaces];
|
mesh->mFaces = new aiFace[mesh->mNumFaces];
|
||||||
for (unsigned int c = 0; c < mesh->mNumFaces;++c) {
|
for (unsigned int c = 0; c < mesh->mNumFaces; ++c) {
|
||||||
mesh->mFaces[c].mNumIndices = 3;
|
mesh->mFaces[c].mNumIndices = 3;
|
||||||
mesh->mFaces[c].mIndices = meshSrc.mFaces[c].mIndices;
|
mesh->mFaces[c].mIndices = meshSrc.mFaces[c].mIndices;
|
||||||
meshSrc.mFaces[c].mIndices = NULL;
|
meshSrc.mFaces[c].mIndices = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate a material for the mesh
|
// generate a material for the mesh
|
||||||
aiMaterial* mat = new aiMaterial();
|
aiMaterial *mat = new aiMaterial();
|
||||||
pScene->mMaterials[n] = mat;
|
pScene->mMaterials[n] = mat;
|
||||||
|
|
||||||
// insert the typical doom3 textures:
|
// insert the typical doom3 textures:
|
||||||
|
@ -541,28 +516,27 @@ void MD5Importer::LoadMD5MeshFile ()
|
||||||
// nnn_h.tga - height map
|
// nnn_h.tga - height map
|
||||||
// nnn_s.tga - specular map
|
// nnn_s.tga - specular map
|
||||||
// nnn_d.tga - diffuse map
|
// nnn_d.tga - diffuse map
|
||||||
if (meshSrc.mShader.length && !strchr(meshSrc.mShader.data,'.')) {
|
if (meshSrc.mShader.length && !strchr(meshSrc.mShader.data, '.')) {
|
||||||
|
|
||||||
aiString temp(meshSrc.mShader);
|
aiString temp(meshSrc.mShader);
|
||||||
temp.Append("_local.tga");
|
temp.Append("_local.tga");
|
||||||
mat->AddProperty(&temp,AI_MATKEY_TEXTURE_NORMALS(0));
|
mat->AddProperty(&temp, AI_MATKEY_TEXTURE_NORMALS(0));
|
||||||
|
|
||||||
temp = aiString(meshSrc.mShader);
|
temp = aiString(meshSrc.mShader);
|
||||||
temp.Append("_s.tga");
|
temp.Append("_s.tga");
|
||||||
mat->AddProperty(&temp,AI_MATKEY_TEXTURE_SPECULAR(0));
|
mat->AddProperty(&temp, AI_MATKEY_TEXTURE_SPECULAR(0));
|
||||||
|
|
||||||
temp = aiString(meshSrc.mShader);
|
temp = aiString(meshSrc.mShader);
|
||||||
temp.Append("_d.tga");
|
temp.Append("_d.tga");
|
||||||
mat->AddProperty(&temp,AI_MATKEY_TEXTURE_DIFFUSE(0));
|
mat->AddProperty(&temp, AI_MATKEY_TEXTURE_DIFFUSE(0));
|
||||||
|
|
||||||
temp = aiString(meshSrc.mShader);
|
temp = aiString(meshSrc.mShader);
|
||||||
temp.Append("_h.tga");
|
temp.Append("_h.tga");
|
||||||
mat->AddProperty(&temp,AI_MATKEY_TEXTURE_HEIGHT(0));
|
mat->AddProperty(&temp, AI_MATKEY_TEXTURE_HEIGHT(0));
|
||||||
|
|
||||||
// set this also as material name
|
// set this also as material name
|
||||||
mat->AddProperty(&meshSrc.mShader,AI_MATKEY_NAME);
|
mat->AddProperty(&meshSrc.mShader, AI_MATKEY_NAME);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
mat->AddProperty(&meshSrc.mShader, AI_MATKEY_TEXTURE_DIFFUSE(0));
|
mat->AddProperty(&meshSrc.mShader, AI_MATKEY_TEXTURE_DIFFUSE(0));
|
||||||
}
|
}
|
||||||
mesh->mMaterialIndex = n++;
|
mesh->mMaterialIndex = n++;
|
||||||
|
@ -572,20 +546,19 @@ void MD5Importer::LoadMD5MeshFile ()
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Load an MD5ANIM file
|
// Load an MD5ANIM file
|
||||||
void MD5Importer::LoadMD5AnimFile ()
|
void MD5Importer::LoadMD5AnimFile() {
|
||||||
{
|
|
||||||
std::string pFile = mFile + "md5anim";
|
std::string pFile = mFile + "md5anim";
|
||||||
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
|
std::unique_ptr<IOStream> file(mIOHandler->Open(pFile, "rb"));
|
||||||
|
|
||||||
// Check whether we can read from the file
|
// Check whether we can read from the file
|
||||||
if( !file.get() || !file->FileSize()) {
|
if (!file.get() || !file->FileSize()) {
|
||||||
ASSIMP_LOG_WARN("Failed to read MD5ANIM file: " + pFile);
|
ASSIMP_LOG_WARN("Failed to read MD5ANIM file: " + pFile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LoadFileIntoMemory(file.get());
|
LoadFileIntoMemory(file.get());
|
||||||
|
|
||||||
// parse the basic file structure
|
// parse the basic file structure
|
||||||
MD5::MD5Parser parser(mBuffer,fileSize);
|
MD5::MD5Parser parser(mBuffer, fileSize);
|
||||||
|
|
||||||
// load the animation information from the parse tree
|
// load the animation information from the parse tree
|
||||||
MD5::MD5AnimParser animParser(parser.mSections);
|
MD5::MD5AnimParser animParser(parser.mSections);
|
||||||
|
@ -594,17 +567,16 @@ void MD5Importer::LoadMD5AnimFile ()
|
||||||
if (animParser.mAnimatedBones.empty() || animParser.mFrames.empty() ||
|
if (animParser.mAnimatedBones.empty() || animParser.mFrames.empty() ||
|
||||||
animParser.mBaseFrames.size() != animParser.mAnimatedBones.size()) {
|
animParser.mBaseFrames.size() != animParser.mAnimatedBones.size()) {
|
||||||
ASSIMP_LOG_ERROR("MD5ANIM: No frames or animated bones loaded");
|
ASSIMP_LOG_ERROR("MD5ANIM: No frames or animated bones loaded");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
bHadMD5Anim = true;
|
bHadMD5Anim = true;
|
||||||
|
|
||||||
pScene->mAnimations = new aiAnimation*[pScene->mNumAnimations = 1];
|
pScene->mAnimations = new aiAnimation *[pScene->mNumAnimations = 1];
|
||||||
aiAnimation* anim = pScene->mAnimations[0] = new aiAnimation();
|
aiAnimation *anim = pScene->mAnimations[0] = new aiAnimation();
|
||||||
anim->mNumChannels = (unsigned int)animParser.mAnimatedBones.size();
|
anim->mNumChannels = (unsigned int)animParser.mAnimatedBones.size();
|
||||||
anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
|
anim->mChannels = new aiNodeAnim *[anim->mNumChannels];
|
||||||
for (unsigned int i = 0; i < anim->mNumChannels;++i) {
|
for (unsigned int i = 0; i < anim->mNumChannels; ++i) {
|
||||||
aiNodeAnim* node = anim->mChannels[i] = new aiNodeAnim();
|
aiNodeAnim *node = anim->mChannels[i] = new aiNodeAnim();
|
||||||
node->mNodeName = aiString( animParser.mAnimatedBones[i].mName );
|
node->mNodeName = aiString(animParser.mAnimatedBones[i].mName);
|
||||||
|
|
||||||
// allocate storage for the keyframes
|
// allocate storage for the keyframes
|
||||||
node->mPositionKeys = new aiVectorKey[animParser.mFrames.size()];
|
node->mPositionKeys = new aiVectorKey[animParser.mFrames.size()];
|
||||||
|
@ -614,46 +586,44 @@ 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 (FrameList::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 (AnimBoneList::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()) {
|
|
||||||
|
|
||||||
// Allow for empty frames
|
// Allow for empty frames
|
||||||
if ((*iter2).iFlags != 0) {
|
if ((*iter2).iFlags != 0) {
|
||||||
throw DeadlyImportError("MD5: Keyframe index is out of range");
|
throw DeadlyImportError("MD5: Keyframe index is out of range");
|
||||||
|
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const float* fpCur = &(*iter).mValues[(*iter2).iFirstKeyIndex];
|
const float *fpCur = &(*iter).mValues[(*iter2).iFirstKeyIndex];
|
||||||
aiNodeAnim* pcCurAnimBone = *pcAnimNode;
|
aiNodeAnim *pcCurAnimBone = *pcAnimNode;
|
||||||
|
|
||||||
aiVectorKey* vKey = &pcCurAnimBone->mPositionKeys[pcCurAnimBone->mNumPositionKeys++];
|
aiVectorKey *vKey = &pcCurAnimBone->mPositionKeys[pcCurAnimBone->mNumPositionKeys++];
|
||||||
aiQuatKey* qKey = &pcCurAnimBone->mRotationKeys [pcCurAnimBone->mNumRotationKeys++];
|
aiQuatKey *qKey = &pcCurAnimBone->mRotationKeys[pcCurAnimBone->mNumRotationKeys++];
|
||||||
aiVector3D vTemp;
|
aiVector3D vTemp;
|
||||||
|
|
||||||
// translational component
|
// translational component
|
||||||
for (unsigned int i = 0; i < 3; ++i) {
|
for (unsigned int i = 0; i < 3; ++i) {
|
||||||
if ((*iter2).iFlags & (1u << i)) {
|
if ((*iter2).iFlags & (1u << i)) {
|
||||||
vKey->mValue[i] = *fpCur++;
|
vKey->mValue[i] = *fpCur++;
|
||||||
}
|
} else
|
||||||
else vKey->mValue[i] = pcBaseFrame->vPositionXYZ[i];
|
vKey->mValue[i] = pcBaseFrame->vPositionXYZ[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
// orientation component
|
// orientation component
|
||||||
for (unsigned int i = 0; i < 3; ++i) {
|
for (unsigned int i = 0; i < 3; ++i) {
|
||||||
if ((*iter2).iFlags & (8u << i)) {
|
if ((*iter2).iFlags & (8u << i)) {
|
||||||
vTemp[i] = *fpCur++;
|
vTemp[i] = *fpCur++;
|
||||||
}
|
} else
|
||||||
else vTemp[i] = pcBaseFrame->vRotationQuat[i];
|
vTemp[i] = pcBaseFrame->vRotationQuat[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
MD5::ConvertQuaternion(vTemp, qKey->mValue);
|
MD5::ConvertQuaternion(vTemp, qKey->mValue);
|
||||||
|
@ -662,7 +632,7 @@ void MD5Importer::LoadMD5AnimFile ()
|
||||||
}
|
}
|
||||||
|
|
||||||
// compute the duration of the animation
|
// compute the duration of the animation
|
||||||
anim->mDuration = std::max(dTime,anim->mDuration);
|
anim->mDuration = std::max(dTime, anim->mDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we didn't build the hierarchy yet (== we didn't load a MD5MESH),
|
// If we didn't build the hierarchy yet (== we didn't load a MD5MESH),
|
||||||
|
@ -671,11 +641,11 @@ void MD5Importer::LoadMD5AnimFile ()
|
||||||
pScene->mRootNode = new aiNode();
|
pScene->mRootNode = new aiNode();
|
||||||
pScene->mRootNode->mName.Set("<MD5_Hierarchy>");
|
pScene->mRootNode->mName.Set("<MD5_Hierarchy>");
|
||||||
|
|
||||||
AttachChilds_Anim(-1,pScene->mRootNode,animParser.mAnimatedBones,(const aiNodeAnim**)anim->mChannels);
|
AttachChilds_Anim(-1, pScene->mRootNode, animParser.mAnimatedBones, (const aiNodeAnim **)anim->mChannels);
|
||||||
|
|
||||||
// Call SkeletonMeshBuilder to construct a mesh to represent the shape
|
// Call SkeletonMeshBuilder to construct a mesh to represent the shape
|
||||||
if (pScene->mRootNode->mNumChildren) {
|
if (pScene->mRootNode->mNumChildren) {
|
||||||
SkeletonMeshBuilder skeleton_maker(pScene,pScene->mRootNode->mChildren[0]);
|
SkeletonMeshBuilder skeleton_maker(pScene, pScene->mRootNode->mChildren[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -683,20 +653,19 @@ void MD5Importer::LoadMD5AnimFile ()
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Load an MD5CAMERA file
|
// Load an MD5CAMERA file
|
||||||
void MD5Importer::LoadMD5CameraFile ()
|
void MD5Importer::LoadMD5CameraFile() {
|
||||||
{
|
|
||||||
std::string pFile = mFile + "md5camera";
|
std::string pFile = mFile + "md5camera";
|
||||||
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
|
std::unique_ptr<IOStream> file(mIOHandler->Open(pFile, "rb"));
|
||||||
|
|
||||||
// Check whether we can read from the file
|
// Check whether we can read from the file
|
||||||
if( !file.get() || !file->FileSize()) {
|
if (!file.get() || !file->FileSize()) {
|
||||||
throw DeadlyImportError("Failed to read MD5CAMERA file: " + pFile);
|
throw DeadlyImportError("Failed to read MD5CAMERA file: " + pFile);
|
||||||
}
|
}
|
||||||
bHadMD5Camera = true;
|
bHadMD5Camera = true;
|
||||||
LoadFileIntoMemory(file.get());
|
LoadFileIntoMemory(file.get());
|
||||||
|
|
||||||
// parse the basic file structure
|
// parse the basic file structure
|
||||||
MD5::MD5Parser parser(mBuffer,fileSize);
|
MD5::MD5Parser parser(mBuffer, fileSize);
|
||||||
|
|
||||||
// load the camera animation data from the parse tree
|
// load the camera animation data from the parse tree
|
||||||
MD5::MD5CameraParser cameraParser(parser.mSections);
|
MD5::MD5CameraParser cameraParser(parser.mSections);
|
||||||
|
@ -705,56 +674,55 @@ void MD5Importer::LoadMD5CameraFile ()
|
||||||
throw DeadlyImportError("MD5CAMERA: No frames parsed");
|
throw DeadlyImportError("MD5CAMERA: No frames parsed");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<unsigned int>& cuts = cameraParser.cuts;
|
std::vector<unsigned int> &cuts = cameraParser.cuts;
|
||||||
std::vector<MD5::CameraAnimFrameDesc>& frames = cameraParser.frames;
|
std::vector<MD5::CameraAnimFrameDesc> &frames = cameraParser.frames;
|
||||||
|
|
||||||
// Construct output graph - a simple root with a dummy child.
|
// Construct output graph - a simple root with a dummy child.
|
||||||
// The root node performs the coordinate system conversion
|
// The root node performs the coordinate system conversion
|
||||||
aiNode* root = pScene->mRootNode = new aiNode("<MD5CameraRoot>");
|
aiNode *root = pScene->mRootNode = new aiNode("<MD5CameraRoot>");
|
||||||
root->mChildren = new aiNode*[root->mNumChildren = 1];
|
root->mChildren = new aiNode *[root->mNumChildren = 1];
|
||||||
root->mChildren[0] = new aiNode("<MD5Camera>");
|
root->mChildren[0] = new aiNode("<MD5Camera>");
|
||||||
root->mChildren[0]->mParent = root;
|
root->mChildren[0]->mParent = root;
|
||||||
|
|
||||||
// ... but with one camera assigned to it
|
// ... but with one camera assigned to it
|
||||||
pScene->mCameras = new aiCamera*[pScene->mNumCameras = 1];
|
pScene->mCameras = new aiCamera *[pScene->mNumCameras = 1];
|
||||||
aiCamera* cam = pScene->mCameras[0] = new aiCamera();
|
aiCamera *cam = pScene->mCameras[0] = new aiCamera();
|
||||||
cam->mName = "<MD5Camera>";
|
cam->mName = "<MD5Camera>";
|
||||||
|
|
||||||
// FIXME: Fov is currently set to the first frame's value
|
// FIXME: Fov is currently set to the first frame's value
|
||||||
cam->mHorizontalFOV = AI_DEG_TO_RAD( frames.front().fFOV );
|
cam->mHorizontalFOV = AI_DEG_TO_RAD(frames.front().fFOV);
|
||||||
|
|
||||||
// every cut is written to a separate aiAnimation
|
// every cut is written to a separate aiAnimation
|
||||||
if (!cuts.size()) {
|
if (!cuts.size()) {
|
||||||
cuts.push_back(0);
|
cuts.push_back(0);
|
||||||
cuts.push_back(static_cast<unsigned int>(frames.size()-1));
|
cuts.push_back(static_cast<unsigned int>(frames.size() - 1));
|
||||||
}
|
} else {
|
||||||
else {
|
cuts.insert(cuts.begin(), 0);
|
||||||
cuts.insert(cuts.begin(),0);
|
|
||||||
|
|
||||||
if (cuts.back() < frames.size()-1)
|
if (cuts.back() < frames.size() - 1)
|
||||||
cuts.push_back(static_cast<unsigned int>(frames.size()-1));
|
cuts.push_back(static_cast<unsigned int>(frames.size() - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
pScene->mNumAnimations = static_cast<unsigned int>(cuts.size()-1);
|
pScene->mNumAnimations = static_cast<unsigned int>(cuts.size() - 1);
|
||||||
aiAnimation** tmp = pScene->mAnimations = new aiAnimation*[pScene->mNumAnimations];
|
aiAnimation **tmp = pScene->mAnimations = new aiAnimation *[pScene->mNumAnimations];
|
||||||
for (std::vector<unsigned int>::const_iterator it = cuts.begin(); it != cuts.end()-1; ++it) {
|
for (std::vector<unsigned int>::const_iterator it = cuts.begin(); it != cuts.end() - 1; ++it) {
|
||||||
|
|
||||||
aiAnimation* anim = *tmp++ = new aiAnimation();
|
aiAnimation *anim = *tmp++ = new aiAnimation();
|
||||||
anim->mName.length = ::ai_snprintf(anim->mName.data, MAXLEN, "anim%u_from_%u_to_%u",(unsigned int)(it-cuts.begin()),(*it),*(it+1));
|
anim->mName.length = ::ai_snprintf(anim->mName.data, MAXLEN, "anim%u_from_%u_to_%u", (unsigned int)(it - cuts.begin()), (*it), *(it + 1));
|
||||||
|
|
||||||
anim->mTicksPerSecond = cameraParser.fFrameRate;
|
anim->mTicksPerSecond = cameraParser.fFrameRate;
|
||||||
anim->mChannels = new aiNodeAnim*[anim->mNumChannels = 1];
|
anim->mChannels = new aiNodeAnim *[anim->mNumChannels = 1];
|
||||||
aiNodeAnim* nd = anim->mChannels[0] = new aiNodeAnim();
|
aiNodeAnim *nd = anim->mChannels[0] = new aiNodeAnim();
|
||||||
nd->mNodeName.Set("<MD5Camera>");
|
nd->mNodeName.Set("<MD5Camera>");
|
||||||
|
|
||||||
nd->mNumPositionKeys = nd->mNumRotationKeys = *(it+1) - (*it);
|
nd->mNumPositionKeys = nd->mNumRotationKeys = *(it + 1) - (*it);
|
||||||
nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
|
nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
|
||||||
nd->mRotationKeys = new aiQuatKey [nd->mNumRotationKeys];
|
nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys];
|
||||||
for (unsigned int i = 0; i < nd->mNumPositionKeys; ++i) {
|
for (unsigned int i = 0; i < nd->mNumPositionKeys; ++i) {
|
||||||
|
|
||||||
nd->mPositionKeys[i].mValue = frames[*it+i].vPositionXYZ;
|
nd->mPositionKeys[i].mValue = frames[*it + i].vPositionXYZ;
|
||||||
MD5::ConvertQuaternion(frames[*it+i].vRotationQuat,nd->mRotationKeys[i].mValue);
|
MD5::ConvertQuaternion(frames[*it + i].vRotationQuat, nd->mRotationKeys[i].mValue);
|
||||||
nd->mRotationKeys[i].mTime = nd->mPositionKeys[i].mTime = *it+i;
|
nd->mRotationKeys[i].mTime = nd->mPositionKeys[i].mTime = *it + i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/** @file MD5Loader.h
|
/** @file MD5Loader.h
|
||||||
* @brief Definition of the .MD5 importer class.
|
* @brief Definition of the .MD5 importer class.
|
||||||
* http://www.modwiki.net/wiki/MD5_(file_format)
|
* http://www.modwiki.net/wiki/MD5_(file_format)
|
||||||
|
@ -48,8 +47,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef AI_MD5LOADER_H_INCLUDED
|
#ifndef AI_MD5LOADER_H_INCLUDED
|
||||||
#define AI_MD5LOADER_H_INCLUDED
|
#define AI_MD5LOADER_H_INCLUDED
|
||||||
|
|
||||||
#include <assimp/BaseImporter.h>
|
|
||||||
#include "MD5Parser.h"
|
#include "MD5Parser.h"
|
||||||
|
#include <assimp/BaseImporter.h>
|
||||||
|
|
||||||
#include <assimp/types.h>
|
#include <assimp/types.h>
|
||||||
|
|
||||||
|
@ -64,61 +63,53 @@ using namespace Assimp::MD5;
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Importer class for the MD5 file format
|
/** Importer class for the MD5 file format
|
||||||
*/
|
*/
|
||||||
class MD5Importer : public BaseImporter
|
class MD5Importer : public BaseImporter {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
MD5Importer();
|
MD5Importer();
|
||||||
~MD5Importer();
|
~MD5Importer();
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Returns whether the class can handle the format of the given file.
|
/** Returns whether the class can handle the format of the given file.
|
||||||
* See BaseImporter::CanRead() for details.
|
* See BaseImporter::CanRead() for details.
|
||||||
*/
|
*/
|
||||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
|
bool CanRead(const std::string &pFile, IOSystem *pIOHandler,
|
||||||
bool checkSig) const;
|
bool checkSig) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Return importer meta information.
|
/** Return importer meta information.
|
||||||
* See #BaseImporter::GetInfo for the details
|
* See #BaseImporter::GetInfo for the details
|
||||||
*/
|
*/
|
||||||
const aiImporterDesc* GetInfo () const;
|
const aiImporterDesc *GetInfo() const;
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Called prior to ReadFile().
|
/** Called prior to ReadFile().
|
||||||
* The function is a request to the importer to update its configuration
|
* The function is a request to the importer to update its configuration
|
||||||
* basing on the Importer's configuration property list.
|
* basing on the Importer's configuration property list.
|
||||||
*/
|
*/
|
||||||
void SetupProperties(const Importer* pImp);
|
void SetupProperties(const Importer *pImp);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Imports the given file into the given scene structure.
|
/** Imports the given file into the given scene structure.
|
||||||
* See BaseImporter::InternReadFile() for details
|
* See BaseImporter::InternReadFile() for details
|
||||||
*/
|
*/
|
||||||
void InternReadFile( const std::string& pFile, aiScene* pScene,
|
void InternReadFile(const std::string &pFile, aiScene *pScene,
|
||||||
IOSystem* pIOHandler);
|
IOSystem *pIOHandler);
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Load a *.MD5MESH file.
|
/** Load a *.MD5MESH file.
|
||||||
*/
|
*/
|
||||||
void LoadMD5MeshFile ();
|
void LoadMD5MeshFile();
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Load a *.MD5ANIM file.
|
/** Load a *.MD5ANIM file.
|
||||||
*/
|
*/
|
||||||
void LoadMD5AnimFile ();
|
void LoadMD5AnimFile();
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Load a *.MD5CAMERA file.
|
/** Load a *.MD5CAMERA file.
|
||||||
*/
|
*/
|
||||||
void LoadMD5CameraFile ();
|
void LoadMD5CameraFile();
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Construct node hierarchy from a given MD5ANIM
|
/** Construct node hierarchy from a given MD5ANIM
|
||||||
|
@ -127,8 +118,8 @@ protected:
|
||||||
* @param bones Input bones
|
* @param bones Input bones
|
||||||
* @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);
|
AnimBoneList &bones, const aiNodeAnim **node_anims);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Construct node hierarchy from a given MD5MESH
|
/** Construct node hierarchy from a given MD5MESH
|
||||||
|
@ -136,13 +127,13 @@ 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, BoneList &bones);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Build unique vertex buffers from a given MD5ANIM
|
/** Build unique vertex buffers from a given MD5ANIM
|
||||||
* @param meshSrc Input data
|
* @param meshSrc Input data
|
||||||
*/
|
*/
|
||||||
void MakeDataUnique (MD5::MeshDesc& meshSrc);
|
void MakeDataUnique(MD5::MeshDesc &meshSrc);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Load the contents of a specific file into memory and
|
/** Load the contents of a specific file into memory and
|
||||||
|
@ -151,19 +142,18 @@ protected:
|
||||||
* mBuffer is modified to point to this buffer.
|
* mBuffer is modified to point to this buffer.
|
||||||
* @param pFile File stream to be read
|
* @param pFile File stream to be read
|
||||||
*/
|
*/
|
||||||
void LoadFileIntoMemory (IOStream* pFile);
|
void LoadFileIntoMemory(IOStream *pFile);
|
||||||
void UnloadFileFromMemory ();
|
void UnloadFileFromMemory();
|
||||||
|
|
||||||
|
|
||||||
/** IOSystem to be used to access files */
|
/** IOSystem to be used to access files */
|
||||||
IOSystem* mIOHandler;
|
IOSystem *mIOHandler;
|
||||||
|
|
||||||
/** Path to the file, excluding the file extension but
|
/** Path to the file, excluding the file extension but
|
||||||
with the dot */
|
with the dot */
|
||||||
std::string mFile;
|
std::string mFile;
|
||||||
|
|
||||||
/** Buffer to hold the loaded file */
|
/** Buffer to hold the loaded file */
|
||||||
char* mBuffer;
|
char *mBuffer;
|
||||||
|
|
||||||
/** Size of the file */
|
/** Size of the file */
|
||||||
unsigned int fileSize;
|
unsigned int fileSize;
|
||||||
|
@ -172,10 +162,7 @@ protected:
|
||||||
unsigned int iLineNumber;
|
unsigned int iLineNumber;
|
||||||
|
|
||||||
/** Scene to be filled */
|
/** Scene to be filled */
|
||||||
aiScene* pScene;
|
aiScene *pScene;
|
||||||
|
|
||||||
/** (Custom) I/O handler implementation */
|
|
||||||
IOSystem* pIOHandler;
|
|
||||||
|
|
||||||
/** true if a MD5MESH file has already been parsed */
|
/** true if a MD5MESH file has already been parsed */
|
||||||
bool bHadMD5Mesh;
|
bool bHadMD5Mesh;
|
||||||
|
|
|
@ -817,20 +817,20 @@ void HL1MDLLoader::read_meshes() {
|
||||||
mesh_faces.reserve(num_faces);
|
mesh_faces.reserve(num_faces);
|
||||||
|
|
||||||
if (is_triangle_fan) {
|
if (is_triangle_fan) {
|
||||||
for (int i = 0; i < num_faces; ++i) {
|
for (int faceIdx = 0; faceIdx < num_faces; ++faceIdx) {
|
||||||
mesh_faces.push_back(HL1MeshFace{
|
mesh_faces.push_back(HL1MeshFace{
|
||||||
tricmds[0],
|
tricmds[0],
|
||||||
tricmds[i + 1],
|
tricmds[faceIdx + 1],
|
||||||
tricmds[i + 2] });
|
tricmds[faceIdx + 2] });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < num_faces; ++i) {
|
for (int faceIdx = 0; faceIdx < num_faces; ++faceIdx) {
|
||||||
if (i & 1) {
|
if (i & 1) {
|
||||||
// Preserve winding order.
|
// Preserve winding order.
|
||||||
mesh_faces.push_back(HL1MeshFace{
|
mesh_faces.push_back(HL1MeshFace{
|
||||||
tricmds[i + 1],
|
tricmds[faceIdx + 1],
|
||||||
tricmds[i],
|
tricmds[faceIdx],
|
||||||
tricmds[i + 2] });
|
tricmds[faceIdx + 2] });
|
||||||
} else {
|
} else {
|
||||||
mesh_faces.push_back(HL1MeshFace{
|
mesh_faces.push_back(HL1MeshFace{
|
||||||
tricmds[i],
|
tricmds[i],
|
||||||
|
@ -1122,10 +1122,10 @@ void HL1MDLLoader::read_sequence_infos() {
|
||||||
aiNode *blend_controller_node = blend_controllers_node->mChildren[j] = new aiNode();
|
aiNode *blend_controller_node = blend_controllers_node->mChildren[j] = new aiNode();
|
||||||
blend_controller_node->mParent = blend_controllers_node;
|
blend_controller_node->mParent = blend_controllers_node;
|
||||||
|
|
||||||
aiMetadata *md = blend_controller_node->mMetaData = aiMetadata::Alloc(3);
|
aiMetadata *metaData = blend_controller_node->mMetaData = aiMetadata::Alloc(3);
|
||||||
md->Set(0, "Start", pseqdesc->blendstart[j]);
|
metaData->Set(0, "Start", pseqdesc->blendstart[j]);
|
||||||
md->Set(1, "End", pseqdesc->blendend[j]);
|
metaData->Set(1, "End", pseqdesc->blendend[j]);
|
||||||
md->Set(2, "MotionFlags", pseqdesc->blendtype[j]);
|
metaData->Set(2, "MotionFlags", pseqdesc->blendtype[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1151,10 +1151,10 @@ void HL1MDLLoader::read_sequence_infos() {
|
||||||
aiNode *pEvent = pEventsNode->mChildren[j] = new aiNode();
|
aiNode *pEvent = pEventsNode->mChildren[j] = new aiNode();
|
||||||
pEvent->mParent = pEventsNode;
|
pEvent->mParent = pEventsNode;
|
||||||
|
|
||||||
aiMetadata *md = pEvent->mMetaData = aiMetadata::Alloc(3);
|
aiMetadata *metaData = pEvent->mMetaData = aiMetadata::Alloc(3);
|
||||||
md->Set(0, "Frame", pevent->frame);
|
metaData->Set(0, "Frame", pevent->frame);
|
||||||
md->Set(1, "ScriptEvent", pevent->event);
|
metaData->Set(1, "ScriptEvent", pevent->event);
|
||||||
md->Set(2, "Options", aiString(pevent->options));
|
metaData->Set(2, "Options", aiString(pevent->options));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ struct HL1MeshTrivert {
|
||||||
normindex(normindex),
|
normindex(normindex),
|
||||||
s(s),
|
s(s),
|
||||||
t(t),
|
t(t),
|
||||||
localindex() {
|
localindex(localindex) {
|
||||||
}
|
}
|
||||||
|
|
||||||
HL1MeshTrivert(const Trivert &a) :
|
HL1MeshTrivert(const Trivert &a) :
|
||||||
|
|
|
@ -68,7 +68,7 @@ static aiTexel* const bad_texel = reinterpret_cast<aiTexel*>(SIZE_MAX);
|
||||||
void MDLImporter::SearchPalette(const unsigned char** pszColorMap)
|
void MDLImporter::SearchPalette(const unsigned char** pszColorMap)
|
||||||
{
|
{
|
||||||
// now try to find the color map in the current directory
|
// now try to find the color map in the current directory
|
||||||
IOStream* pcStream = pIOHandler->Open(configPalette,"rb");
|
IOStream* pcStream = mIOHandler->Open(configPalette,"rb");
|
||||||
|
|
||||||
const unsigned char* szColorMap = (const unsigned char*)::g_aclrDefaultColorMap;
|
const unsigned char* szColorMap = (const unsigned char*)::g_aclrDefaultColorMap;
|
||||||
if(pcStream)
|
if(pcStream)
|
||||||
|
@ -702,14 +702,13 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
|
||||||
// data structures in the aiScene instance
|
// data structures in the aiScene instance
|
||||||
if (pcNew && pScene->mNumTextures <= 999)
|
if (pcNew && pScene->mNumTextures <= 999)
|
||||||
{
|
{
|
||||||
|
|
||||||
// place this as diffuse texture
|
// place this as diffuse texture
|
||||||
char szCurrent[5];
|
char current[5];
|
||||||
ai_snprintf(szCurrent,5,"*%i",this->pScene->mNumTextures);
|
ai_snprintf(current, 5, "*%i", this->pScene->mNumTextures);
|
||||||
|
|
||||||
aiString szFile;
|
aiString szFile;
|
||||||
const size_t iLen = strlen((const char*)szCurrent);
|
const size_t iLen = strlen((const char *)current);
|
||||||
::memcpy(szFile.data,(const char*)szCurrent,iLen+1);
|
::memcpy(szFile.data, (const char *)current, iLen + 1);
|
||||||
szFile.length = (ai_uint32)iLen;
|
szFile.length = (ai_uint32)iLen;
|
||||||
|
|
||||||
pcMatOut->AddProperty(&szFile,AI_MATKEY_TEXTURE_DIFFUSE(0));
|
pcMatOut->AddProperty(&szFile,AI_MATKEY_TEXTURE_DIFFUSE(0));
|
||||||
|
|
|
@ -261,19 +261,19 @@ void MS3DImporter::InternReadFile( const std::string& pFile,
|
||||||
TempTriangle& t = triangles[i];
|
TempTriangle& t = triangles[i];
|
||||||
|
|
||||||
stream.IncPtr(2);
|
stream.IncPtr(2);
|
||||||
for (unsigned int i = 0; i < 3; ++i) {
|
for (unsigned int j = 0; j < 3; ++j) {
|
||||||
t.indices[i] = stream.GetI2();
|
t.indices[j] = stream.GetI2();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < 3; ++i) {
|
for (unsigned int j = 0; j < 3; ++j) {
|
||||||
ReadVector(stream,t.normals[i]);
|
ReadVector(stream,t.normals[j]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < 3; ++i) {
|
for (unsigned int j = 0; j < 3; ++j) {
|
||||||
stream >> (float&)(t.uv[i].x); // see note in ReadColor()
|
stream >> (float&)(t.uv[j].x); // see note in ReadColor()
|
||||||
}
|
}
|
||||||
for (unsigned int i = 0; i < 3; ++i) {
|
for (unsigned int j = 0; j < 3; ++j) {
|
||||||
stream >> (float&)(t.uv[i].y);
|
stream >> (float&)(t.uv[j].y);
|
||||||
}
|
}
|
||||||
|
|
||||||
t.sg = stream.GetI1();
|
t.sg = stream.GetI1();
|
||||||
|
@ -296,8 +296,8 @@ void MS3DImporter::InternReadFile( const std::string& pFile,
|
||||||
stream >> num;
|
stream >> num;
|
||||||
|
|
||||||
t.triangles.resize(num);
|
t.triangles.resize(num);
|
||||||
for (unsigned int i = 0; i < num; ++i) {
|
for (unsigned int j = 0; j < num; ++j) {
|
||||||
t.triangles[i] = stream.GetI2();
|
t.triangles[j] = stream.GetI2();
|
||||||
}
|
}
|
||||||
t.mat = stream.GetI1();
|
t.mat = stream.GetI1();
|
||||||
if (t.mat == UINT_MAX) {
|
if (t.mat == UINT_MAX) {
|
||||||
|
@ -309,8 +309,8 @@ void MS3DImporter::InternReadFile( const std::string& pFile,
|
||||||
stream >> mat;
|
stream >> mat;
|
||||||
|
|
||||||
std::vector<TempMaterial> materials(mat);
|
std::vector<TempMaterial> materials(mat);
|
||||||
for (unsigned int i = 0;i < mat; ++i) {
|
for (unsigned int j = 0;j < mat; ++j) {
|
||||||
TempMaterial& t = materials[i];
|
TempMaterial& t = materials[j];
|
||||||
|
|
||||||
stream.CopyAndAdvance(t.name,32);
|
stream.CopyAndAdvance(t.name,32);
|
||||||
t.name[32] = '\0';
|
t.name[32] = '\0';
|
||||||
|
@ -338,8 +338,8 @@ void MS3DImporter::InternReadFile( const std::string& pFile,
|
||||||
stream >> joint;
|
stream >> joint;
|
||||||
|
|
||||||
std::vector<TempJoint> joints(joint);
|
std::vector<TempJoint> joints(joint);
|
||||||
for(unsigned int i = 0; i < joint; ++i) {
|
for(unsigned int ii = 0; ii < joint; ++ii) {
|
||||||
TempJoint& j = joints[i];
|
TempJoint& j = joints[ii];
|
||||||
|
|
||||||
stream.IncPtr(1);
|
stream.IncPtr(1);
|
||||||
stream.CopyAndAdvance(j.name,32);
|
stream.CopyAndAdvance(j.name,32);
|
||||||
|
@ -494,17 +494,17 @@ void MS3DImporter::InternReadFile( const std::string& pFile,
|
||||||
typedef std::map<unsigned int,unsigned int> BoneSet;
|
typedef std::map<unsigned int,unsigned int> BoneSet;
|
||||||
BoneSet mybones;
|
BoneSet mybones;
|
||||||
|
|
||||||
for (unsigned int i = 0,n = 0; i < m->mNumFaces; ++i) {
|
for (unsigned int j = 0,n = 0; j < m->mNumFaces; ++j) {
|
||||||
aiFace& f = m->mFaces[i];
|
aiFace& f = m->mFaces[j];
|
||||||
if (g.triangles[i]>triangles.size()) {
|
if (g.triangles[j]>triangles.size()) {
|
||||||
throw DeadlyImportError("MS3D: Encountered invalid triangle index, file is malformed");
|
throw DeadlyImportError("MS3D: Encountered invalid triangle index, file is malformed");
|
||||||
}
|
}
|
||||||
|
|
||||||
TempTriangle& t = triangles[g.triangles[i]];
|
TempTriangle& t = triangles[g.triangles[i]];
|
||||||
f.mIndices = new unsigned int[f.mNumIndices=3];
|
f.mIndices = new unsigned int[f.mNumIndices=3];
|
||||||
|
|
||||||
for (unsigned int i = 0; i < 3; ++i,++n) {
|
for (unsigned int k = 0; k < 3; ++k,++n) {
|
||||||
if (t.indices[i]>vertices.size()) {
|
if (t.indices[k]>vertices.size()) {
|
||||||
throw DeadlyImportError("MS3D: Encountered invalid vertex index, file is malformed");
|
throw DeadlyImportError("MS3D: Encountered invalid vertex index, file is malformed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -545,11 +545,11 @@ void MS3DImporter::InternReadFile( const std::string& pFile,
|
||||||
}
|
}
|
||||||
|
|
||||||
// .. and collect bone weights
|
// .. and collect bone weights
|
||||||
for (unsigned int i = 0,n = 0; i < m->mNumFaces; ++i) {
|
for (unsigned int j = 0,n = 0; j < m->mNumFaces; ++j) {
|
||||||
TempTriangle& t = triangles[g.triangles[i]];
|
TempTriangle& t = triangles[g.triangles[j]];
|
||||||
|
|
||||||
for (unsigned int i = 0; i < 3; ++i,++n) {
|
for (unsigned int k = 0; k < 3; ++k,++n) {
|
||||||
const TempVertex& v = vertices[t.indices[i]];
|
const TempVertex& v = vertices[t.indices[k]];
|
||||||
for(unsigned int a = 0; a < 4; ++a) {
|
for(unsigned int a = 0; a < 4; ++a) {
|
||||||
const unsigned int bone = v.bone_id[a];
|
const unsigned int bone = v.bone_id[a];
|
||||||
if(bone==UINT_MAX){
|
if(bone==UINT_MAX){
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -185,8 +185,8 @@ private:
|
||||||
|
|
||||||
// for spheres, cones and cylinders: center point of the object
|
// for spheres, cones and cylinders: center point of the object
|
||||||
aiVector3D center, radius, dir;
|
aiVector3D center, radius, dir;
|
||||||
|
static const size_t MaxNameLen = 128;
|
||||||
char name[128];
|
char name[MaxNameLen];
|
||||||
|
|
||||||
std::vector<aiVector3D> vertices, normals, uvs;
|
std::vector<aiVector3D> vertices, normals, uvs;
|
||||||
std::vector<unsigned int> faces;
|
std::vector<unsigned int> faces;
|
||||||
|
|
|
@ -80,7 +80,7 @@ ObjFileParser::ObjFileParser( IOStreamBuffer<char> &streamBuffer, const std::str
|
||||||
m_progress(progress),
|
m_progress(progress),
|
||||||
m_originalObjFileName(originalObjFileName)
|
m_originalObjFileName(originalObjFileName)
|
||||||
{
|
{
|
||||||
std::fill_n(m_buffer,Buffersize,0);
|
std::fill_n(m_buffer,Buffersize,'\0');
|
||||||
|
|
||||||
// Create the model instance to store all the data
|
// Create the model instance to store all the data
|
||||||
m_pModel.reset(new ObjFile::Model());
|
m_pModel.reset(new ObjFile::Model());
|
||||||
|
|
|
@ -668,8 +668,8 @@ void OgreBinarySerializer::ReadEdgeList(Mesh * /*mesh*/)
|
||||||
|
|
||||||
for (size_t i=0; i<numEdgeGroups; ++i)
|
for (size_t i=0; i<numEdgeGroups; ++i)
|
||||||
{
|
{
|
||||||
uint16_t id = ReadHeader();
|
uint16_t curId = ReadHeader();
|
||||||
if (id != M_EDGE_GROUP)
|
if (curId != M_EDGE_GROUP)
|
||||||
throw DeadlyImportError("M_EDGE_GROUP not found in M_EDGE_LIST_LOD");
|
throw DeadlyImportError("M_EDGE_GROUP not found in M_EDGE_LIST_LOD");
|
||||||
|
|
||||||
m_reader->IncPtr(sizeof(uint32_t) * 3);
|
m_reader->IncPtr(sizeof(uint32_t) * 3);
|
||||||
|
|
|
@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
|
||||||
|
|
||||||
Copyright (c) 2006-2020, assimp team
|
Copyright (c) 2006-2020, 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,
|
||||||
|
|
|
@ -206,8 +206,8 @@ aiMaterial* OgreImporter::ReadMaterial(const std::string &pFile, Assimp::IOSyste
|
||||||
aiMaterial *material = new aiMaterial();
|
aiMaterial *material = new aiMaterial();
|
||||||
m_textures.clear();
|
m_textures.clear();
|
||||||
|
|
||||||
aiString ts(materialName);
|
aiString matName(materialName);
|
||||||
material->AddProperty(&ts, AI_MATKEY_NAME);
|
material->AddProperty(&matName, AI_MATKEY_NAME);
|
||||||
|
|
||||||
// The stringstream will push words from a line until newline.
|
// The stringstream will push words from a line until newline.
|
||||||
// It will also trim whitespace from line start and between words.
|
// It will also trim whitespace from line start and between words.
|
||||||
|
@ -279,14 +279,14 @@ aiMaterial* OgreImporter::ReadMaterial(const std::string &pFile, Assimp::IOSyste
|
||||||
else if (linePart=="$colormap")
|
else if (linePart=="$colormap")
|
||||||
{
|
{
|
||||||
ss >> linePart;
|
ss >> linePart;
|
||||||
aiString ts(linePart);
|
aiString cm(linePart);
|
||||||
material->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
|
material->AddProperty(&cm, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
|
||||||
}
|
}
|
||||||
else if (linePart=="$normalmap")
|
else if (linePart=="$normalmap")
|
||||||
{
|
{
|
||||||
ss >> linePart;
|
ss >> linePart;
|
||||||
aiString ts(linePart);
|
aiString nm(linePart);
|
||||||
material->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0));
|
material->AddProperty(&nm, AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0));
|
||||||
}
|
}
|
||||||
else if (linePart=="$shininess_strength")
|
else if (linePart=="$shininess_strength")
|
||||||
{
|
{
|
||||||
|
|
|
@ -46,26 +46,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||||
|
|
||||||
#include <assimp/ParsingUtils.h>
|
#include <assimp/ParsingUtils.h>
|
||||||
#include <functional>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <sstream>
|
#include <algorithm>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
#include <functional>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
namespace Ogre {
|
namespace Ogre {
|
||||||
|
|
||||||
/// Returns a lower cased copy of @s.
|
/// Returns a lower cased copy of @s.
|
||||||
static AI_FORCE_INLINE
|
static AI_FORCE_INLINE std::string ToLower(const std::string &s) {
|
||||||
std::string ToLower(std::string s)
|
std::string lower(s);
|
||||||
{
|
std::transform(lower.begin(), lower.end(), lower.begin(), Assimp::ToLower<char>);
|
||||||
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
|
|
||||||
return s;
|
return lower;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns if @c s ends with @c suffix. If @c caseSensitive is false, both strings will be lower cased before matching.
|
/// Returns if @c s ends with @c suffix. If @c caseSensitive is false, both strings will be lower cased before matching.
|
||||||
static AI_FORCE_INLINE
|
static AI_FORCE_INLINE bool EndsWith( const std::string &s, const std::string &suffix, bool caseSensitive = true) {
|
||||||
bool EndsWith(const std::string &s, const std::string &suffix, bool caseSensitive = true) {
|
|
||||||
if (s.empty() || suffix.empty()) {
|
if (s.empty() || suffix.empty()) {
|
||||||
return false;
|
return false;
|
||||||
} else if (s.length() < suffix.length()) {
|
} else if (s.length() < suffix.length()) {
|
||||||
|
@ -77,7 +76,7 @@ bool EndsWith(const std::string &s, const std::string &suffix, bool caseSensitiv
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t len = suffix.length();
|
size_t len = suffix.length();
|
||||||
std::string sSuffix = s.substr(s.length()-len, len);
|
std::string sSuffix = s.substr(s.length() - len, len);
|
||||||
|
|
||||||
return (ASSIMP_stricmp(sSuffix, suffix) == 0);
|
return (ASSIMP_stricmp(sSuffix, suffix) == 0);
|
||||||
}
|
}
|
||||||
|
@ -86,7 +85,8 @@ bool EndsWith(const std::string &s, const std::string &suffix, bool caseSensitiv
|
||||||
|
|
||||||
/// Trim from start
|
/// Trim from start
|
||||||
static AI_FORCE_INLINE
|
static AI_FORCE_INLINE
|
||||||
std::string &TrimLeft(std::string &s, bool newlines = true) {
|
std::string &
|
||||||
|
TrimLeft(std::string &s, bool newlines = true) {
|
||||||
if (!newlines) {
|
if (!newlines) {
|
||||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpace<char>(c); }));
|
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpace<char>(c); }));
|
||||||
} else {
|
} else {
|
||||||
|
@ -97,9 +97,10 @@ std::string &TrimLeft(std::string &s, bool newlines = true) {
|
||||||
|
|
||||||
/// Trim from end
|
/// Trim from end
|
||||||
static AI_FORCE_INLINE
|
static AI_FORCE_INLINE
|
||||||
std::string &TrimRight(std::string &s, bool newlines = true) {
|
std::string &
|
||||||
|
TrimRight(std::string &s, bool newlines = true) {
|
||||||
if (!newlines) {
|
if (!newlines) {
|
||||||
s.erase(std::find_if(s.rbegin(), s.rend(), [](char c) { return !Assimp::IsSpace<char>(c); }).base(),s.end());
|
s.erase(std::find_if(s.rbegin(), s.rend(), [](char c) { return !Assimp::IsSpace<char>(c); }).base(), s.end());
|
||||||
} else {
|
} else {
|
||||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpaceOrNewLine<char>(c); }));
|
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpaceOrNewLine<char>(c); }));
|
||||||
}
|
}
|
||||||
|
@ -108,13 +109,15 @@ std::string &TrimRight(std::string &s, bool newlines = true) {
|
||||||
|
|
||||||
/// Trim from both ends
|
/// Trim from both ends
|
||||||
static AI_FORCE_INLINE
|
static AI_FORCE_INLINE
|
||||||
std::string &Trim(std::string &s, bool newlines = true) {
|
std::string &
|
||||||
|
Trim(std::string &s, bool newlines = true) {
|
||||||
return TrimLeft(TrimRight(s, newlines), newlines);
|
return TrimLeft(TrimRight(s, newlines), newlines);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Skips a line from current @ss position until a newline. Returns the skipped part.
|
/// Skips a line from current @ss position until a newline. Returns the skipped part.
|
||||||
static AI_FORCE_INLINE
|
static AI_FORCE_INLINE
|
||||||
std::string SkipLine(std::stringstream &ss) {
|
std::string
|
||||||
|
SkipLine(std::stringstream &ss) {
|
||||||
std::string skipped;
|
std::string skipped;
|
||||||
getline(ss, skipped);
|
getline(ss, skipped);
|
||||||
return skipped;
|
return skipped;
|
||||||
|
@ -123,14 +126,15 @@ std::string SkipLine(std::stringstream &ss) {
|
||||||
/// Skips a line and reads next element from @c ss to @c nextElement.
|
/// Skips a line and reads next element from @c ss to @c nextElement.
|
||||||
/** @return Skipped line content until newline. */
|
/** @return Skipped line content until newline. */
|
||||||
static AI_FORCE_INLINE
|
static AI_FORCE_INLINE
|
||||||
std::string NextAfterNewLine(std::stringstream &ss, std::string &nextElement) {
|
std::string
|
||||||
|
NextAfterNewLine(std::stringstream &ss, std::string &nextElement) {
|
||||||
std::string skipped = SkipLine(ss);
|
std::string skipped = SkipLine(ss);
|
||||||
ss >> nextElement;
|
ss >> nextElement;
|
||||||
return skipped;
|
return skipped;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // Ogre
|
} // namespace Ogre
|
||||||
} // Assimp
|
} // namespace Assimp
|
||||||
|
|
||||||
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
|
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||||
#endif // AI_OGREPARSINGUTILS_H_INC
|
#endif // AI_OGREPARSINGUTILS_H_INC
|
||||||
|
|
|
@ -53,140 +53,94 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
// Define as 1 to get verbose logging.
|
// Define as 1 to get verbose logging.
|
||||||
#define OGRE_XML_SERIALIZER_DEBUG 0
|
#define OGRE_XML_SERIALIZER_DEBUG 0
|
||||||
|
|
||||||
namespace Assimp
|
namespace Assimp {
|
||||||
{
|
namespace Ogre {
|
||||||
namespace Ogre
|
|
||||||
{
|
|
||||||
|
|
||||||
AI_WONT_RETURN void ThrowAttibuteError(const XmlReader* reader, const std::string &name, const std::string &error = "") AI_WONT_RETURN_SUFFIX;
|
AI_WONT_RETURN void ThrowAttibuteError(const XmlReader *reader, const std::string &name, const std::string &error = "") AI_WONT_RETURN_SUFFIX;
|
||||||
AI_WONT_RETURN void ThrowAttibuteError(const XmlReader* reader, const std::string &name, const std::string &error)
|
AI_WONT_RETURN void ThrowAttibuteError(const XmlReader *reader, const std::string &name, const std::string &error) {
|
||||||
{
|
if (!error.empty()) {
|
||||||
if (!error.empty())
|
|
||||||
{
|
|
||||||
throw DeadlyImportError(error + " in node '" + std::string(reader->getNodeName()) + "' and attribute '" + name + "'");
|
throw DeadlyImportError(error + " in node '" + std::string(reader->getNodeName()) + "' and attribute '" + name + "'");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
throw DeadlyImportError("Attribute '" + name + "' does not exist in node '" + std::string(reader->getNodeName()) + "'");
|
throw DeadlyImportError("Attribute '" + name + "' does not exist in node '" + std::string(reader->getNodeName()) + "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
int32_t OgreXmlSerializer::ReadAttribute<int32_t>(const char *name) const
|
int32_t OgreXmlSerializer::ReadAttribute<int32_t>(const char *name) const {
|
||||||
{
|
if (!HasAttribute(name)) {
|
||||||
if (HasAttribute(name))
|
|
||||||
{
|
|
||||||
return static_cast<int32_t>(m_reader->getAttributeValueAsInt(name));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ThrowAttibuteError(m_reader, name);
|
ThrowAttibuteError(m_reader, name);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return static_cast<int32_t>(m_reader->getAttributeValueAsInt(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
uint32_t OgreXmlSerializer::ReadAttribute<uint32_t>(const char *name) const
|
uint32_t OgreXmlSerializer::ReadAttribute<uint32_t>(const char *name) const {
|
||||||
{
|
if (!HasAttribute(name)) {
|
||||||
if (HasAttribute(name))
|
ThrowAttibuteError(m_reader, name);
|
||||||
{
|
|
||||||
/** @note This is hackish. But we are never expecting unsigned values that go outside the
|
|
||||||
int32_t range. Just monitor for negative numbers and kill the import. */
|
|
||||||
int32_t temp = ReadAttribute<int32_t>(name);
|
|
||||||
if (temp >= 0)
|
|
||||||
{
|
|
||||||
return static_cast<uint32_t>(temp);
|
|
||||||
}
|
}
|
||||||
else
|
// @note This is hackish. But we are never expecting unsigned values that go outside the
|
||||||
{
|
// int32_t range. Just monitor for negative numbers and kill the import.
|
||||||
|
int32_t temp = ReadAttribute<int32_t>(name);
|
||||||
|
if (temp < 0) {
|
||||||
ThrowAttibuteError(m_reader, name, "Found a negative number value where expecting a uint32_t value");
|
ThrowAttibuteError(m_reader, name, "Found a negative number value where expecting a uint32_t value");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
return static_cast<uint32_t>(temp);
|
||||||
{
|
|
||||||
ThrowAttibuteError(m_reader, name);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
uint16_t OgreXmlSerializer::ReadAttribute<uint16_t>(const char *name) const
|
uint16_t OgreXmlSerializer::ReadAttribute<uint16_t>(const char *name) const {
|
||||||
{
|
if (!HasAttribute(name)) {
|
||||||
if (HasAttribute(name))
|
ThrowAttibuteError(m_reader, name);
|
||||||
{
|
}
|
||||||
|
|
||||||
return static_cast<uint16_t>(ReadAttribute<uint32_t>(name));
|
return static_cast<uint16_t>(ReadAttribute<uint32_t>(name));
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ThrowAttibuteError(m_reader, name);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
float OgreXmlSerializer::ReadAttribute<float>(const char *name) const
|
float OgreXmlSerializer::ReadAttribute<float>(const char *name) const {
|
||||||
{
|
if (!HasAttribute(name)) {
|
||||||
if (HasAttribute(name))
|
ThrowAttibuteError(m_reader, name);
|
||||||
{
|
}
|
||||||
|
|
||||||
return m_reader->getAttributeValueAsFloat(name);
|
return m_reader->getAttributeValueAsFloat(name);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ThrowAttibuteError(m_reader, name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
std::string OgreXmlSerializer::ReadAttribute<std::string>(const char *name) const
|
std::string OgreXmlSerializer::ReadAttribute<std::string>(const char *name) const {
|
||||||
{
|
const char *value = m_reader->getAttributeValue(name);
|
||||||
const char* value = m_reader->getAttributeValue(name);
|
if (nullptr == value) {
|
||||||
if (value)
|
ThrowAttibuteError(m_reader, name);
|
||||||
{
|
}
|
||||||
|
|
||||||
return std::string(value);
|
return std::string(value);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ThrowAttibuteError(m_reader, name);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
bool OgreXmlSerializer::ReadAttribute<bool>(const char *name) const
|
bool OgreXmlSerializer::ReadAttribute<bool>(const char *name) const {
|
||||||
{
|
|
||||||
std::string value = Ogre::ToLower(ReadAttribute<std::string>(name));
|
std::string value = Ogre::ToLower(ReadAttribute<std::string>(name));
|
||||||
if (ASSIMP_stricmp(value, "true") == 0)
|
if (ASSIMP_stricmp(value, "true") == 0) {
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
} else if (ASSIMP_stricmp(value, "false") == 0) {
|
||||||
else if (ASSIMP_stricmp(value, "false") == 0)
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
ThrowAttibuteError(m_reader, name, "Boolean value is expected to be 'true' or 'false', encountered '" + value + "'");
|
ThrowAttibuteError(m_reader, name, "Boolean value is expected to be 'true' or 'false', encountered '" + value + "'");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OgreXmlSerializer::HasAttribute(const char *name) const
|
bool OgreXmlSerializer::HasAttribute(const char *name) const {
|
||||||
{
|
|
||||||
return (m_reader->getAttributeValue(name) != 0);
|
return (m_reader->getAttributeValue(name) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string &OgreXmlSerializer::NextNode()
|
std::string &OgreXmlSerializer::NextNode() {
|
||||||
{
|
do {
|
||||||
do
|
if (!m_reader->read()) {
|
||||||
{
|
|
||||||
if (!m_reader->read())
|
|
||||||
{
|
|
||||||
m_currentNodeName = "";
|
m_currentNodeName = "";
|
||||||
return m_currentNodeName;
|
return m_currentNodeName;
|
||||||
}
|
}
|
||||||
}
|
} while (m_reader->getNodeType() != irr::io::EXN_ELEMENT);
|
||||||
while(m_reader->getNodeType() != irr::io::EXN_ELEMENT);
|
|
||||||
|
|
||||||
CurrentNodeName(true);
|
CurrentNodeName(true);
|
||||||
#if (OGRE_XML_SERIALIZER_DEBUG == 1)
|
#if (OGRE_XML_SERIALIZER_DEBUG == 1)
|
||||||
|
@ -195,32 +149,29 @@ std::string &OgreXmlSerializer::NextNode()
|
||||||
return m_currentNodeName;
|
return m_currentNodeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OgreXmlSerializer::CurrentNodeNameEquals(const std::string &name) const
|
bool OgreXmlSerializer::CurrentNodeNameEquals(const std::string &name) const {
|
||||||
{
|
|
||||||
return (ASSIMP_stricmp(m_currentNodeName, name) == 0);
|
return (ASSIMP_stricmp(m_currentNodeName, name) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string OgreXmlSerializer::CurrentNodeName(bool forceRead)
|
std::string OgreXmlSerializer::CurrentNodeName(bool forceRead) {
|
||||||
{
|
|
||||||
if (forceRead)
|
if (forceRead)
|
||||||
m_currentNodeName = std::string(m_reader->getNodeName());
|
m_currentNodeName = std::string(m_reader->getNodeName());
|
||||||
return m_currentNodeName;
|
return m_currentNodeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string &OgreXmlSerializer::SkipCurrentNode()
|
std::string &OgreXmlSerializer::SkipCurrentNode() {
|
||||||
{
|
|
||||||
#if (OGRE_XML_SERIALIZER_DEBUG == 1)
|
#if (OGRE_XML_SERIALIZER_DEBUG == 1)
|
||||||
ASSIMP_LOG_DEBUG("Skipping node <" + m_currentNodeName + ">");
|
ASSIMP_LOG_DEBUG("Skipping node <" + m_currentNodeName + ">");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for(;;) {
|
for (;;) {
|
||||||
if (!m_reader->read()) {
|
if (!m_reader->read()) {
|
||||||
m_currentNodeName = "";
|
m_currentNodeName = "";
|
||||||
return m_currentNodeName;
|
return m_currentNodeName;
|
||||||
}
|
}
|
||||||
if ( m_reader->getNodeType() != irr::io::EXN_ELEMENT_END ) {
|
if (m_reader->getNodeType() != irr::io::EXN_ELEMENT_END) {
|
||||||
continue;
|
continue;
|
||||||
} else if ( std::string( m_reader->getNodeName() ) == m_currentNodeName ) {
|
} else if (std::string(m_reader->getNodeName()) == m_currentNodeName) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -322,7 +273,7 @@ void OgreXmlSerializer::ReadMesh(MeshXml *mesh) {
|
||||||
NextNode();
|
NextNode();
|
||||||
|
|
||||||
// Root level nodes
|
// Root level nodes
|
||||||
while(m_currentNodeName == nnSharedGeometry ||
|
while (m_currentNodeName == nnSharedGeometry ||
|
||||||
m_currentNodeName == nnSubMeshes ||
|
m_currentNodeName == nnSubMeshes ||
|
||||||
m_currentNodeName == nnSkeletonLink ||
|
m_currentNodeName == nnSkeletonLink ||
|
||||||
m_currentNodeName == nnBoneAssignments ||
|
m_currentNodeName == nnBoneAssignments ||
|
||||||
|
@ -330,26 +281,18 @@ void OgreXmlSerializer::ReadMesh(MeshXml *mesh) {
|
||||||
m_currentNodeName == nnSubMeshNames ||
|
m_currentNodeName == nnSubMeshNames ||
|
||||||
m_currentNodeName == nnExtremes ||
|
m_currentNodeName == nnExtremes ||
|
||||||
m_currentNodeName == nnPoses ||
|
m_currentNodeName == nnPoses ||
|
||||||
m_currentNodeName == nnAnimations)
|
m_currentNodeName == nnAnimations) {
|
||||||
{
|
if (m_currentNodeName == nnSharedGeometry) {
|
||||||
if (m_currentNodeName == nnSharedGeometry)
|
|
||||||
{
|
|
||||||
mesh->sharedVertexData = new VertexDataXml();
|
mesh->sharedVertexData = new VertexDataXml();
|
||||||
ReadGeometry(mesh->sharedVertexData);
|
ReadGeometry(mesh->sharedVertexData);
|
||||||
}
|
} else if (m_currentNodeName == nnSubMeshes) {
|
||||||
else if (m_currentNodeName == nnSubMeshes)
|
|
||||||
{
|
|
||||||
NextNode();
|
NextNode();
|
||||||
while(m_currentNodeName == nnSubMesh) {
|
while (m_currentNodeName == nnSubMesh) {
|
||||||
ReadSubMesh(mesh);
|
ReadSubMesh(mesh);
|
||||||
}
|
}
|
||||||
}
|
} else if (m_currentNodeName == nnBoneAssignments) {
|
||||||
else if (m_currentNodeName == nnBoneAssignments)
|
|
||||||
{
|
|
||||||
ReadBoneAssignments(mesh->sharedVertexData);
|
ReadBoneAssignments(mesh->sharedVertexData);
|
||||||
}
|
} else if (m_currentNodeName == nnSkeletonLink) {
|
||||||
else if (m_currentNodeName == nnSkeletonLink)
|
|
||||||
{
|
|
||||||
mesh->skeletonRef = ReadAttribute<std::string>("name");
|
mesh->skeletonRef = ReadAttribute<std::string>("name");
|
||||||
ASSIMP_LOG_DEBUG_F("Read skeleton link ", mesh->skeletonRef);
|
ASSIMP_LOG_DEBUG_F("Read skeleton link ", mesh->skeletonRef);
|
||||||
NextNode();
|
NextNode();
|
||||||
|
@ -360,19 +303,17 @@ void OgreXmlSerializer::ReadMesh(MeshXml *mesh) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OgreXmlSerializer::ReadGeometry(VertexDataXml *dest)
|
void OgreXmlSerializer::ReadGeometry(VertexDataXml *dest) {
|
||||||
{
|
|
||||||
dest->count = ReadAttribute<uint32_t>("vertexcount");
|
dest->count = ReadAttribute<uint32_t>("vertexcount");
|
||||||
ASSIMP_LOG_DEBUG_F( " - Reading geometry of ", dest->count, " vertices");
|
ASSIMP_LOG_DEBUG_F(" - Reading geometry of ", dest->count, " vertices");
|
||||||
|
|
||||||
NextNode();
|
NextNode();
|
||||||
while(m_currentNodeName == nnVertexBuffer) {
|
while (m_currentNodeName == nnVertexBuffer) {
|
||||||
ReadGeometryVertexBuffer(dest);
|
ReadGeometryVertexBuffer(dest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest)
|
void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest) {
|
||||||
{
|
|
||||||
bool positions = (HasAttribute("positions") && ReadAttribute<bool>("positions"));
|
bool positions = (HasAttribute("positions") && ReadAttribute<bool>("positions"));
|
||||||
bool normals = (HasAttribute("normals") && ReadAttribute<bool>("normals"));
|
bool normals = (HasAttribute("normals") && ReadAttribute<bool>("normals"));
|
||||||
bool tangents = (HasAttribute("tangents") && ReadAttribute<bool>("tangents"));
|
bool tangents = (HasAttribute("tangents") && ReadAttribute<bool>("tangents"));
|
||||||
|
@ -383,26 +324,22 @@ void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest)
|
||||||
throw DeadlyImportError("Vertex buffer does not contain positions!");
|
throw DeadlyImportError("Vertex buffer does not contain positions!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (positions)
|
if (positions) {
|
||||||
{
|
|
||||||
ASSIMP_LOG_DEBUG(" - Contains positions");
|
ASSIMP_LOG_DEBUG(" - Contains positions");
|
||||||
dest->positions.reserve(dest->count);
|
dest->positions.reserve(dest->count);
|
||||||
}
|
}
|
||||||
if (normals)
|
if (normals) {
|
||||||
{
|
|
||||||
ASSIMP_LOG_DEBUG(" - Contains normals");
|
ASSIMP_LOG_DEBUG(" - Contains normals");
|
||||||
dest->normals.reserve(dest->count);
|
dest->normals.reserve(dest->count);
|
||||||
}
|
}
|
||||||
if (tangents)
|
if (tangents) {
|
||||||
{
|
|
||||||
ASSIMP_LOG_DEBUG(" - Contains tangents");
|
ASSIMP_LOG_DEBUG(" - Contains tangents");
|
||||||
dest->tangents.reserve(dest->count);
|
dest->tangents.reserve(dest->count);
|
||||||
}
|
}
|
||||||
if (uvs > 0)
|
if (uvs > 0) {
|
||||||
{
|
ASSIMP_LOG_DEBUG_F(" - Contains ", uvs, " texture coords");
|
||||||
ASSIMP_LOG_DEBUG_F( " - Contains ", uvs, " texture coords");
|
|
||||||
dest->uvs.resize(uvs);
|
dest->uvs.resize(uvs);
|
||||||
for(size_t i=0, len=dest->uvs.size(); i<len; ++i) {
|
for (size_t i = 0, len = dest->uvs.size(); i < len; ++i) {
|
||||||
dest->uvs[i].reserve(dest->count);
|
dest->uvs[i].reserve(dest->count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -413,49 +350,40 @@ void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest)
|
||||||
|
|
||||||
NextNode();
|
NextNode();
|
||||||
|
|
||||||
while(m_currentNodeName == nnVertex ||
|
while (m_currentNodeName == nnVertex ||
|
||||||
m_currentNodeName == nnPosition ||
|
m_currentNodeName == nnPosition ||
|
||||||
m_currentNodeName == nnNormal ||
|
m_currentNodeName == nnNormal ||
|
||||||
m_currentNodeName == nnTangent ||
|
m_currentNodeName == nnTangent ||
|
||||||
m_currentNodeName == nnBinormal ||
|
m_currentNodeName == nnBinormal ||
|
||||||
m_currentNodeName == nnTexCoord ||
|
m_currentNodeName == nnTexCoord ||
|
||||||
m_currentNodeName == nnColorDiffuse ||
|
m_currentNodeName == nnColorDiffuse ||
|
||||||
m_currentNodeName == nnColorSpecular)
|
m_currentNodeName == nnColorSpecular) {
|
||||||
{
|
|
||||||
if (m_currentNodeName == nnVertex) {
|
if (m_currentNodeName == nnVertex) {
|
||||||
NextNode();
|
NextNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @todo Implement nnBinormal, nnColorDiffuse and nnColorSpecular
|
/// @todo Implement nnBinormal, nnColorDiffuse and nnColorSpecular
|
||||||
|
|
||||||
if (positions && m_currentNodeName == nnPosition)
|
if (positions && m_currentNodeName == nnPosition) {
|
||||||
{
|
|
||||||
aiVector3D pos;
|
aiVector3D pos;
|
||||||
pos.x = ReadAttribute<float>(anX);
|
pos.x = ReadAttribute<float>(anX);
|
||||||
pos.y = ReadAttribute<float>(anY);
|
pos.y = ReadAttribute<float>(anY);
|
||||||
pos.z = ReadAttribute<float>(anZ);
|
pos.z = ReadAttribute<float>(anZ);
|
||||||
dest->positions.push_back(pos);
|
dest->positions.push_back(pos);
|
||||||
}
|
} else if (normals && m_currentNodeName == nnNormal) {
|
||||||
else if (normals && m_currentNodeName == nnNormal)
|
|
||||||
{
|
|
||||||
aiVector3D normal;
|
aiVector3D normal;
|
||||||
normal.x = ReadAttribute<float>(anX);
|
normal.x = ReadAttribute<float>(anX);
|
||||||
normal.y = ReadAttribute<float>(anY);
|
normal.y = ReadAttribute<float>(anY);
|
||||||
normal.z = ReadAttribute<float>(anZ);
|
normal.z = ReadAttribute<float>(anZ);
|
||||||
dest->normals.push_back(normal);
|
dest->normals.push_back(normal);
|
||||||
}
|
} else if (tangents && m_currentNodeName == nnTangent) {
|
||||||
else if (tangents && m_currentNodeName == nnTangent)
|
|
||||||
{
|
|
||||||
aiVector3D tangent;
|
aiVector3D tangent;
|
||||||
tangent.x = ReadAttribute<float>(anX);
|
tangent.x = ReadAttribute<float>(anX);
|
||||||
tangent.y = ReadAttribute<float>(anY);
|
tangent.y = ReadAttribute<float>(anY);
|
||||||
tangent.z = ReadAttribute<float>(anZ);
|
tangent.z = ReadAttribute<float>(anZ);
|
||||||
dest->tangents.push_back(tangent);
|
dest->tangents.push_back(tangent);
|
||||||
}
|
} else if (uvs > 0 && m_currentNodeName == nnTexCoord) {
|
||||||
else if (uvs > 0 && m_currentNodeName == nnTexCoord)
|
for (auto &curUvs : dest->uvs) {
|
||||||
{
|
|
||||||
for(auto &uvs : dest->uvs)
|
|
||||||
{
|
|
||||||
if (m_currentNodeName != nnTexCoord) {
|
if (m_currentNodeName != nnTexCoord) {
|
||||||
throw DeadlyImportError("Vertex buffer declared more UVs than can be found in a vertex");
|
throw DeadlyImportError("Vertex buffer declared more UVs than can be found in a vertex");
|
||||||
}
|
}
|
||||||
|
@ -463,47 +391,31 @@ void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest)
|
||||||
aiVector3D uv;
|
aiVector3D uv;
|
||||||
uv.x = ReadAttribute<float>("u");
|
uv.x = ReadAttribute<float>("u");
|
||||||
uv.y = (ReadAttribute<float>("v") * -1) + 1; // Flip UV from Ogre to Assimp form
|
uv.y = (ReadAttribute<float>("v") * -1) + 1; // Flip UV from Ogre to Assimp form
|
||||||
uvs.push_back(uv);
|
curUvs.push_back(uv);
|
||||||
|
|
||||||
NextNode();
|
NextNode();
|
||||||
}
|
}
|
||||||
// Continue main loop as above already read next node
|
// Continue main loop as above already read next node
|
||||||
continue;
|
continue;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
/// @todo Remove this stuff once implemented. We only want to log warnings once per element.
|
/// @todo Remove this stuff once implemented. We only want to log warnings once per element.
|
||||||
bool warn = true;
|
bool warn = true;
|
||||||
if (m_currentNodeName == nnBinormal)
|
if (m_currentNodeName == nnBinormal) {
|
||||||
{
|
if (warnBinormal) {
|
||||||
if (warnBinormal)
|
|
||||||
{
|
|
||||||
warnBinormal = false;
|
warnBinormal = false;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
warn = false;
|
warn = false;
|
||||||
}
|
}
|
||||||
}
|
} else if (m_currentNodeName == nnColorDiffuse) {
|
||||||
else if (m_currentNodeName == nnColorDiffuse)
|
if (warnColorDiffuse) {
|
||||||
{
|
|
||||||
if (warnColorDiffuse)
|
|
||||||
{
|
|
||||||
warnColorDiffuse = false;
|
warnColorDiffuse = false;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
warn = false;
|
warn = false;
|
||||||
}
|
}
|
||||||
}
|
} else if (m_currentNodeName == nnColorSpecular) {
|
||||||
else if (m_currentNodeName == nnColorSpecular)
|
if (warnColorSpecular) {
|
||||||
{
|
|
||||||
if (warnColorSpecular)
|
|
||||||
{
|
|
||||||
warnColorSpecular = false;
|
warnColorSpecular = false;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
warn = false;
|
warn = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -526,8 +438,7 @@ void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest)
|
||||||
if (tangents && dest->tangents.size() != dest->count) {
|
if (tangents && dest->tangents.size() != dest->count) {
|
||||||
throw DeadlyImportError(Formatter::format() << "Read only " << dest->tangents.size() << " tangents when should have read " << dest->count);
|
throw DeadlyImportError(Formatter::format() << "Read only " << dest->tangents.size() << " tangents when should have read " << dest->count);
|
||||||
}
|
}
|
||||||
for(unsigned int i=0; i<dest->uvs.size(); ++i)
|
for (unsigned int i = 0; i < dest->uvs.size(); ++i) {
|
||||||
{
|
|
||||||
if (dest->uvs[i].size() != dest->count) {
|
if (dest->uvs[i].size() != dest->count) {
|
||||||
throw DeadlyImportError(Formatter::format() << "Read only " << dest->uvs[i].size()
|
throw DeadlyImportError(Formatter::format() << "Read only " << dest->uvs[i].size()
|
||||||
<< " uvs for uv index " << i << " when should have read " << dest->count);
|
<< " uvs for uv index " << i << " when should have read " << dest->count);
|
||||||
|
@ -535,8 +446,7 @@ void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh)
|
void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh) {
|
||||||
{
|
|
||||||
static const char *anMaterial = "material";
|
static const char *anMaterial = "material";
|
||||||
static const char *anUseSharedVertices = "usesharedvertices";
|
static const char *anUseSharedVertices = "usesharedvertices";
|
||||||
static const char *anCount = "count";
|
static const char *anCount = "count";
|
||||||
|
@ -545,7 +455,7 @@ void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh)
|
||||||
static const char *anV3 = "v3";
|
static const char *anV3 = "v3";
|
||||||
static const char *anV4 = "v4";
|
static const char *anV4 = "v4";
|
||||||
|
|
||||||
SubMeshXml* submesh = new SubMeshXml();
|
SubMeshXml *submesh = new SubMeshXml();
|
||||||
|
|
||||||
if (HasAttribute(anMaterial)) {
|
if (HasAttribute(anMaterial)) {
|
||||||
submesh->materialRef = ReadAttribute<std::string>(anMaterial);
|
submesh->materialRef = ReadAttribute<std::string>(anMaterial);
|
||||||
|
@ -554,9 +464,9 @@ void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh)
|
||||||
submesh->usesSharedVertexData = ReadAttribute<bool>(anUseSharedVertices);
|
submesh->usesSharedVertexData = ReadAttribute<bool>(anUseSharedVertices);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSIMP_LOG_DEBUG_F( "Reading SubMesh ", mesh->subMeshes.size());
|
ASSIMP_LOG_DEBUG_F("Reading SubMesh ", mesh->subMeshes.size());
|
||||||
ASSIMP_LOG_DEBUG_F( " - Material: '", submesh->materialRef, "'");
|
ASSIMP_LOG_DEBUG_F(" - Material: '", submesh->materialRef, "'");
|
||||||
ASSIMP_LOG_DEBUG_F( " - Uses shared geometry: ", (submesh->usesSharedVertexData ? "true" : "false"));
|
ASSIMP_LOG_DEBUG_F(" - Uses shared geometry: ", (submesh->usesSharedVertexData ? "true" : "false"));
|
||||||
|
|
||||||
// TODO: maybe we have always just 1 faces and 1 geometry and always in this order. this loop will only work correct, when the order
|
// TODO: maybe we have always just 1 faces and 1 geometry and always in this order. this loop will only work correct, when the order
|
||||||
// of faces and geometry changed, and not if we have more than one of one
|
// of faces and geometry changed, and not if we have more than one of one
|
||||||
|
@ -565,19 +475,16 @@ void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh)
|
||||||
bool quadWarned = false;
|
bool quadWarned = false;
|
||||||
|
|
||||||
NextNode();
|
NextNode();
|
||||||
while(m_currentNodeName == nnFaces ||
|
while (m_currentNodeName == nnFaces ||
|
||||||
m_currentNodeName == nnGeometry ||
|
m_currentNodeName == nnGeometry ||
|
||||||
m_currentNodeName == nnTextures ||
|
m_currentNodeName == nnTextures ||
|
||||||
m_currentNodeName == nnBoneAssignments)
|
m_currentNodeName == nnBoneAssignments) {
|
||||||
{
|
if (m_currentNodeName == nnFaces) {
|
||||||
if (m_currentNodeName == nnFaces)
|
|
||||||
{
|
|
||||||
submesh->indexData->faceCount = ReadAttribute<uint32_t>(anCount);
|
submesh->indexData->faceCount = ReadAttribute<uint32_t>(anCount);
|
||||||
submesh->indexData->faces.reserve(submesh->indexData->faceCount);
|
submesh->indexData->faces.reserve(submesh->indexData->faceCount);
|
||||||
|
|
||||||
NextNode();
|
NextNode();
|
||||||
while(m_currentNodeName == nnFace)
|
while (m_currentNodeName == nnFace) {
|
||||||
{
|
|
||||||
aiFace face;
|
aiFace face;
|
||||||
face.mNumIndices = 3;
|
face.mNumIndices = 3;
|
||||||
face.mIndices = new unsigned int[3];
|
face.mIndices = new unsigned int[3];
|
||||||
|
@ -598,7 +505,7 @@ void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (submesh->indexData->faces.size() == submesh->indexData->faceCount) {
|
if (submesh->indexData->faces.size() == submesh->indexData->faceCount) {
|
||||||
ASSIMP_LOG_DEBUG_F( " - Faces ", submesh->indexData->faceCount);
|
ASSIMP_LOG_DEBUG_F(" - Faces ", submesh->indexData->faceCount);
|
||||||
} else {
|
} else {
|
||||||
throw DeadlyImportError(Formatter::format() << "Read only " << submesh->indexData->faces.size() << " faces when should have read " << submesh->indexData->faceCount);
|
throw DeadlyImportError(Formatter::format() << "Read only " << submesh->indexData->faces.size() << " faces when should have read " << submesh->indexData->faceCount);
|
||||||
}
|
}
|
||||||
|
@ -622,8 +529,7 @@ void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh)
|
||||||
mesh->subMeshes.push_back(submesh);
|
mesh->subMeshes.push_back(submesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OgreXmlSerializer::ReadBoneAssignments(VertexDataXml *dest)
|
void OgreXmlSerializer::ReadBoneAssignments(VertexDataXml *dest) {
|
||||||
{
|
|
||||||
if (!dest) {
|
if (!dest) {
|
||||||
throw DeadlyImportError("Cannot read bone assignments, vertex data is null.");
|
throw DeadlyImportError("Cannot read bone assignments, vertex data is null.");
|
||||||
}
|
}
|
||||||
|
@ -635,8 +541,7 @@ void OgreXmlSerializer::ReadBoneAssignments(VertexDataXml *dest)
|
||||||
std::set<uint32_t> influencedVertices;
|
std::set<uint32_t> influencedVertices;
|
||||||
|
|
||||||
NextNode();
|
NextNode();
|
||||||
while(m_currentNodeName == nnVertexBoneAssignment)
|
while (m_currentNodeName == nnVertexBoneAssignment) {
|
||||||
{
|
|
||||||
VertexBoneAssignment ba;
|
VertexBoneAssignment ba;
|
||||||
ba.vertexIndex = ReadAttribute<uint32_t>(anVertexIndex);
|
ba.vertexIndex = ReadAttribute<uint32_t>(anVertexIndex);
|
||||||
ba.boneIndex = ReadAttribute<uint16_t>(anBoneIndex);
|
ba.boneIndex = ReadAttribute<uint16_t>(anBoneIndex);
|
||||||
|
@ -652,38 +557,32 @@ void OgreXmlSerializer::ReadBoneAssignments(VertexDataXml *dest)
|
||||||
Some exporters won't care if the sum of all bone weights
|
Some exporters won't care if the sum of all bone weights
|
||||||
for a single vertex equals 1 or not, so validate here. */
|
for a single vertex equals 1 or not, so validate here. */
|
||||||
const float epsilon = 0.05f;
|
const float epsilon = 0.05f;
|
||||||
for (const uint32_t vertexIndex : influencedVertices)
|
for (const uint32_t vertexIndex : influencedVertices) {
|
||||||
{
|
|
||||||
float sum = 0.0f;
|
float sum = 0.0f;
|
||||||
for (VertexBoneAssignmentList::const_iterator baIter=dest->boneAssignments.begin(), baEnd=dest->boneAssignments.end(); baIter != baEnd; ++baIter)
|
for (VertexBoneAssignmentList::const_iterator baIter = dest->boneAssignments.begin(), baEnd = dest->boneAssignments.end(); baIter != baEnd; ++baIter) {
|
||||||
{
|
|
||||||
if (baIter->vertexIndex == vertexIndex)
|
if (baIter->vertexIndex == vertexIndex)
|
||||||
sum += baIter->weight;
|
sum += baIter->weight;
|
||||||
}
|
}
|
||||||
if ((sum < (1.0f - epsilon)) || (sum > (1.0f + epsilon)))
|
if ((sum < (1.0f - epsilon)) || (sum > (1.0f + epsilon))) {
|
||||||
{
|
for (auto &boneAssign : dest->boneAssignments) {
|
||||||
for (auto &boneAssign : dest->boneAssignments)
|
|
||||||
{
|
|
||||||
if (boneAssign.vertexIndex == vertexIndex)
|
if (boneAssign.vertexIndex == vertexIndex)
|
||||||
boneAssign.weight /= sum;
|
boneAssign.weight /= sum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSIMP_LOG_DEBUG_F( " - ", dest->boneAssignments.size(), " bone assignments");
|
ASSIMP_LOG_DEBUG_F(" - ", dest->boneAssignments.size(), " bone assignments");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skeleton
|
// Skeleton
|
||||||
|
|
||||||
bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh)
|
bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh) {
|
||||||
{
|
|
||||||
if (!mesh || mesh->skeletonRef.empty())
|
if (!mesh || mesh->skeletonRef.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Highly unusual to see in read world cases but support
|
// Highly unusual to see in read world cases but support
|
||||||
// XML mesh referencing a binary skeleton file.
|
// XML mesh referencing a binary skeleton file.
|
||||||
if (EndsWith(mesh->skeletonRef, ".skeleton", false))
|
if (EndsWith(mesh->skeletonRef, ".skeleton", false)) {
|
||||||
{
|
|
||||||
if (OgreBinarySerializer::ImportSkeleton(pIOHandler, mesh))
|
if (OgreBinarySerializer::ImportSkeleton(pIOHandler, mesh))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -705,8 +604,7 @@ bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *me
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh)
|
bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh) {
|
||||||
{
|
|
||||||
if (!mesh || mesh->skeletonRef.empty())
|
if (!mesh || mesh->skeletonRef.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -721,16 +619,13 @@ bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlReaderPtr OgreXmlSerializer::OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename)
|
XmlReaderPtr OgreXmlSerializer::OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename) {
|
||||||
{
|
if (!EndsWith(filename, ".skeleton.xml", false)) {
|
||||||
if (!EndsWith(filename, ".skeleton.xml", false))
|
|
||||||
{
|
|
||||||
ASSIMP_LOG_ERROR_F("Imported Mesh is referencing to unsupported '", filename, "' skeleton file.");
|
ASSIMP_LOG_ERROR_F("Imported Mesh is referencing to unsupported '", filename, "' skeleton file.");
|
||||||
return XmlReaderPtr();
|
return XmlReaderPtr();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pIOHandler->Exists(filename))
|
if (!pIOHandler->Exists(filename)) {
|
||||||
{
|
|
||||||
ASSIMP_LOG_ERROR_F("Failed to find skeleton file '", filename, "' that is referenced by imported Mesh.");
|
ASSIMP_LOG_ERROR_F("Failed to find skeleton file '", filename, "' that is referenced by imported Mesh.");
|
||||||
return XmlReaderPtr();
|
return XmlReaderPtr();
|
||||||
}
|
}
|
||||||
|
@ -748,8 +643,7 @@ XmlReaderPtr OgreXmlSerializer::OpenReader(Assimp::IOSystem *pIOHandler, const s
|
||||||
return reader;
|
return reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OgreXmlSerializer::ReadSkeleton(Skeleton *skeleton)
|
void OgreXmlSerializer::ReadSkeleton(Skeleton *skeleton) {
|
||||||
{
|
|
||||||
if (NextNode() != nnSkeleton) {
|
if (NextNode() != nnSkeleton) {
|
||||||
throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting <skeleton>");
|
throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting <skeleton>");
|
||||||
}
|
}
|
||||||
|
@ -758,18 +652,16 @@ void OgreXmlSerializer::ReadSkeleton(Skeleton *skeleton)
|
||||||
|
|
||||||
// Optional blend mode from root node
|
// Optional blend mode from root node
|
||||||
if (HasAttribute("blendmode")) {
|
if (HasAttribute("blendmode")) {
|
||||||
skeleton->blendMode = (ToLower(ReadAttribute<std::string>("blendmode")) == "cumulative"
|
skeleton->blendMode = (ToLower(ReadAttribute<std::string>("blendmode")) == "cumulative" ? Skeleton::ANIMBLEND_CUMULATIVE : Skeleton::ANIMBLEND_AVERAGE);
|
||||||
? Skeleton::ANIMBLEND_CUMULATIVE : Skeleton::ANIMBLEND_AVERAGE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NextNode();
|
NextNode();
|
||||||
|
|
||||||
// Root level nodes
|
// Root level nodes
|
||||||
while(m_currentNodeName == nnBones ||
|
while (m_currentNodeName == nnBones ||
|
||||||
m_currentNodeName == nnBoneHierarchy ||
|
m_currentNodeName == nnBoneHierarchy ||
|
||||||
m_currentNodeName == nnAnimations ||
|
m_currentNodeName == nnAnimations ||
|
||||||
m_currentNodeName == nnAnimationLinks)
|
m_currentNodeName == nnAnimationLinks) {
|
||||||
{
|
|
||||||
if (m_currentNodeName == nnBones)
|
if (m_currentNodeName == nnBones)
|
||||||
ReadBones(skeleton);
|
ReadBones(skeleton);
|
||||||
else if (m_currentNodeName == nnBoneHierarchy)
|
else if (m_currentNodeName == nnBoneHierarchy)
|
||||||
|
@ -781,8 +673,7 @@ void OgreXmlSerializer::ReadSkeleton(Skeleton *skeleton)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OgreXmlSerializer::ReadAnimations(Skeleton *skeleton)
|
void OgreXmlSerializer::ReadAnimations(Skeleton *skeleton) {
|
||||||
{
|
|
||||||
if (skeleton->bones.empty()) {
|
if (skeleton->bones.empty()) {
|
||||||
throw DeadlyImportError("Cannot read <animations> for a Skeleton without bones");
|
throw DeadlyImportError("Cannot read <animations> for a Skeleton without bones");
|
||||||
}
|
}
|
||||||
|
@ -790,8 +681,7 @@ void OgreXmlSerializer::ReadAnimations(Skeleton *skeleton)
|
||||||
ASSIMP_LOG_DEBUG(" - Animations");
|
ASSIMP_LOG_DEBUG(" - Animations");
|
||||||
|
|
||||||
NextNode();
|
NextNode();
|
||||||
while(m_currentNodeName == nnAnimation)
|
while (m_currentNodeName == nnAnimation) {
|
||||||
{
|
|
||||||
Animation *anim = new Animation(skeleton);
|
Animation *anim = new Animation(skeleton);
|
||||||
anim->name = ReadAttribute<std::string>("name");
|
anim->name = ReadAttribute<std::string>("name");
|
||||||
anim->length = ReadAttribute<float>("length");
|
anim->length = ReadAttribute<float>("length");
|
||||||
|
@ -803,15 +693,13 @@ void OgreXmlSerializer::ReadAnimations(Skeleton *skeleton)
|
||||||
ReadAnimationTracks(anim);
|
ReadAnimationTracks(anim);
|
||||||
skeleton->animations.push_back(anim);
|
skeleton->animations.push_back(anim);
|
||||||
|
|
||||||
ASSIMP_LOG_DEBUG_F( " ", anim->name, " (", anim->length, " sec, ", anim->tracks.size(), " tracks)");
|
ASSIMP_LOG_DEBUG_F(" ", anim->name, " (", anim->length, " sec, ", anim->tracks.size(), " tracks)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OgreXmlSerializer::ReadAnimationTracks(Animation *dest)
|
void OgreXmlSerializer::ReadAnimationTracks(Animation *dest) {
|
||||||
{
|
|
||||||
NextNode();
|
NextNode();
|
||||||
while(m_currentNodeName == nnTrack)
|
while (m_currentNodeName == nnTrack) {
|
||||||
{
|
|
||||||
VertexAnimationTrack track;
|
VertexAnimationTrack track;
|
||||||
track.type = VertexAnimationTrack::VAT_TRANSFORM;
|
track.type = VertexAnimationTrack::VAT_TRANSFORM;
|
||||||
track.boneName = ReadAttribute<std::string>("bone");
|
track.boneName = ReadAttribute<std::string>("bone");
|
||||||
|
@ -826,27 +714,21 @@ void OgreXmlSerializer::ReadAnimationTracks(Animation *dest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OgreXmlSerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *dest)
|
void OgreXmlSerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *dest) {
|
||||||
{
|
|
||||||
const aiVector3D zeroVec(0.f, 0.f, 0.f);
|
const aiVector3D zeroVec(0.f, 0.f, 0.f);
|
||||||
|
|
||||||
NextNode();
|
NextNode();
|
||||||
while(m_currentNodeName == nnKeyFrame)
|
while (m_currentNodeName == nnKeyFrame) {
|
||||||
{
|
|
||||||
TransformKeyFrame keyframe;
|
TransformKeyFrame keyframe;
|
||||||
keyframe.timePos = ReadAttribute<float>("time");
|
keyframe.timePos = ReadAttribute<float>("time");
|
||||||
|
|
||||||
NextNode();
|
NextNode();
|
||||||
while(m_currentNodeName == nnTranslate || m_currentNodeName == nnRotate || m_currentNodeName == nnScale)
|
while (m_currentNodeName == nnTranslate || m_currentNodeName == nnRotate || m_currentNodeName == nnScale) {
|
||||||
{
|
if (m_currentNodeName == nnTranslate) {
|
||||||
if (m_currentNodeName == nnTranslate)
|
|
||||||
{
|
|
||||||
keyframe.position.x = ReadAttribute<float>(anX);
|
keyframe.position.x = ReadAttribute<float>(anX);
|
||||||
keyframe.position.y = ReadAttribute<float>(anY);
|
keyframe.position.y = ReadAttribute<float>(anY);
|
||||||
keyframe.position.z = ReadAttribute<float>(anZ);
|
keyframe.position.z = ReadAttribute<float>(anZ);
|
||||||
}
|
} else if (m_currentNodeName == nnRotate) {
|
||||||
else if (m_currentNodeName == nnRotate)
|
|
||||||
{
|
|
||||||
float angle = ReadAttribute<float>("angle");
|
float angle = ReadAttribute<float>("angle");
|
||||||
|
|
||||||
if (NextNode() != nnAxis) {
|
if (NextNode() != nnAxis) {
|
||||||
|
@ -857,17 +739,14 @@ void OgreXmlSerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationT
|
||||||
axis.x = ReadAttribute<float>(anX);
|
axis.x = ReadAttribute<float>(anX);
|
||||||
axis.y = ReadAttribute<float>(anY);
|
axis.y = ReadAttribute<float>(anY);
|
||||||
axis.z = ReadAttribute<float>(anZ);
|
axis.z = ReadAttribute<float>(anZ);
|
||||||
if (axis.Equal(zeroVec))
|
if (axis.Equal(zeroVec)) {
|
||||||
{
|
|
||||||
axis.x = 1.0f;
|
axis.x = 1.0f;
|
||||||
if (angle != 0) {
|
if (angle != 0) {
|
||||||
ASSIMP_LOG_WARN_F("Found invalid a key frame with a zero rotation axis in animation: ", anim->name);
|
ASSIMP_LOG_WARN_F("Found invalid a key frame with a zero rotation axis in animation: ", anim->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
keyframe.rotation = aiQuaternion(axis, angle);
|
keyframe.rotation = aiQuaternion(axis, angle);
|
||||||
}
|
} else if (m_currentNodeName == nnScale) {
|
||||||
else if (m_currentNodeName == nnScale)
|
|
||||||
{
|
|
||||||
keyframe.scale.x = ReadAttribute<float>(anX);
|
keyframe.scale.x = ReadAttribute<float>(anX);
|
||||||
keyframe.scale.y = ReadAttribute<float>(anY);
|
keyframe.scale.y = ReadAttribute<float>(anY);
|
||||||
keyframe.scale.z = ReadAttribute<float>(anZ);
|
keyframe.scale.z = ReadAttribute<float>(anZ);
|
||||||
|
@ -880,14 +759,12 @@ void OgreXmlSerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OgreXmlSerializer::ReadBoneHierarchy(Skeleton *skeleton)
|
void OgreXmlSerializer::ReadBoneHierarchy(Skeleton *skeleton) {
|
||||||
{
|
|
||||||
if (skeleton->bones.empty()) {
|
if (skeleton->bones.empty()) {
|
||||||
throw DeadlyImportError("Cannot read <bonehierarchy> for a Skeleton without bones");
|
throw DeadlyImportError("Cannot read <bonehierarchy> for a Skeleton without bones");
|
||||||
}
|
}
|
||||||
|
|
||||||
while(NextNode() == nnBoneParent)
|
while (NextNode() == nnBoneParent) {
|
||||||
{
|
|
||||||
const std::string name = ReadAttribute<std::string>("bone");
|
const std::string name = ReadAttribute<std::string>("bone");
|
||||||
const std::string parentName = ReadAttribute<std::string>("parent");
|
const std::string parentName = ReadAttribute<std::string>("parent");
|
||||||
|
|
||||||
|
@ -901,46 +778,38 @@ void OgreXmlSerializer::ReadBoneHierarchy(Skeleton *skeleton)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate bone matrices for root bones. Recursively calculates their children.
|
// Calculate bone matrices for root bones. Recursively calculates their children.
|
||||||
for (size_t i=0, len=skeleton->bones.size(); i<len; ++i)
|
for (size_t i = 0, len = skeleton->bones.size(); i < len; ++i) {
|
||||||
{
|
|
||||||
Bone *bone = skeleton->bones[i];
|
Bone *bone = skeleton->bones[i];
|
||||||
if (!bone->IsParented())
|
if (!bone->IsParented())
|
||||||
bone->CalculateWorldMatrixAndDefaultPose(skeleton);
|
bone->CalculateWorldMatrixAndDefaultPose(skeleton);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool BoneCompare(Bone *a, Bone *b)
|
static bool BoneCompare(Bone *a, Bone *b) {
|
||||||
{
|
ai_assert(nullptr != a);
|
||||||
ai_assert( nullptr != a );
|
ai_assert(nullptr != b);
|
||||||
ai_assert( nullptr != b );
|
|
||||||
|
|
||||||
return (a->id < b->id);
|
return (a->id < b->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OgreXmlSerializer::ReadBones(Skeleton *skeleton)
|
void OgreXmlSerializer::ReadBones(Skeleton *skeleton) {
|
||||||
{
|
|
||||||
ASSIMP_LOG_DEBUG(" - Bones");
|
ASSIMP_LOG_DEBUG(" - Bones");
|
||||||
|
|
||||||
NextNode();
|
NextNode();
|
||||||
while(m_currentNodeName == nnBone)
|
while (m_currentNodeName == nnBone) {
|
||||||
{
|
|
||||||
Bone *bone = new Bone();
|
Bone *bone = new Bone();
|
||||||
bone->id = ReadAttribute<uint16_t>("id");
|
bone->id = ReadAttribute<uint16_t>("id");
|
||||||
bone->name = ReadAttribute<std::string>("name");
|
bone->name = ReadAttribute<std::string>("name");
|
||||||
|
|
||||||
NextNode();
|
NextNode();
|
||||||
while(m_currentNodeName == nnPosition ||
|
while (m_currentNodeName == nnPosition ||
|
||||||
m_currentNodeName == nnRotation ||
|
m_currentNodeName == nnRotation ||
|
||||||
m_currentNodeName == nnScale)
|
m_currentNodeName == nnScale) {
|
||||||
{
|
if (m_currentNodeName == nnPosition) {
|
||||||
if (m_currentNodeName == nnPosition)
|
|
||||||
{
|
|
||||||
bone->position.x = ReadAttribute<float>(anX);
|
bone->position.x = ReadAttribute<float>(anX);
|
||||||
bone->position.y = ReadAttribute<float>(anY);
|
bone->position.y = ReadAttribute<float>(anY);
|
||||||
bone->position.z = ReadAttribute<float>(anZ);
|
bone->position.z = ReadAttribute<float>(anZ);
|
||||||
}
|
} else if (m_currentNodeName == nnRotation) {
|
||||||
else if (m_currentNodeName == nnRotation)
|
|
||||||
{
|
|
||||||
float angle = ReadAttribute<float>("angle");
|
float angle = ReadAttribute<float>("angle");
|
||||||
|
|
||||||
if (NextNode() != nnAxis) {
|
if (NextNode() != nnAxis) {
|
||||||
|
@ -953,17 +822,12 @@ void OgreXmlSerializer::ReadBones(Skeleton *skeleton)
|
||||||
axis.z = ReadAttribute<float>(anZ);
|
axis.z = ReadAttribute<float>(anZ);
|
||||||
|
|
||||||
bone->rotation = aiQuaternion(axis, angle);
|
bone->rotation = aiQuaternion(axis, angle);
|
||||||
}
|
} else if (m_currentNodeName == nnScale) {
|
||||||
else if (m_currentNodeName == nnScale)
|
|
||||||
{
|
|
||||||
/// @todo Implement taking scale into account in matrix/pose calculations!
|
/// @todo Implement taking scale into account in matrix/pose calculations!
|
||||||
if (HasAttribute("factor"))
|
if (HasAttribute("factor")) {
|
||||||
{
|
|
||||||
float factor = ReadAttribute<float>("factor");
|
float factor = ReadAttribute<float>("factor");
|
||||||
bone->scale.Set(factor, factor, factor);
|
bone->scale.Set(factor, factor, factor);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
if (HasAttribute(anX))
|
if (HasAttribute(anX))
|
||||||
bone->scale.x = ReadAttribute<float>(anX);
|
bone->scale.x = ReadAttribute<float>(anX);
|
||||||
if (HasAttribute(anY))
|
if (HasAttribute(anY))
|
||||||
|
@ -985,10 +849,9 @@ void OgreXmlSerializer::ReadBones(Skeleton *skeleton)
|
||||||
// Validate that bone indexes are not skipped.
|
// Validate that bone indexes are not skipped.
|
||||||
/** @note Left this from original authors code, but not sure if this is strictly necessary
|
/** @note Left this from original authors code, but not sure if this is strictly necessary
|
||||||
as per the Ogre skeleton spec. It might be more that other (later) code in this imported does not break. */
|
as per the Ogre skeleton spec. It might be more that other (later) code in this imported does not break. */
|
||||||
for (size_t i=0, len=skeleton->bones.size(); i<len; ++i)
|
for (size_t i = 0, len = skeleton->bones.size(); i < len; ++i) {
|
||||||
{
|
|
||||||
Bone *b = skeleton->bones[i];
|
Bone *b = skeleton->bones[i];
|
||||||
ASSIMP_LOG_DEBUG_F( " ", b->id, " ", b->name);
|
ASSIMP_LOG_DEBUG_F(" ", b->id, " ", b->name);
|
||||||
|
|
||||||
if (b->id != static_cast<uint16_t>(i)) {
|
if (b->id != static_cast<uint16_t>(i)) {
|
||||||
throw DeadlyImportError(Formatter::format() << "Bone ids are not in sequence starting from 0. Missing index " << i);
|
throw DeadlyImportError(Formatter::format() << "Bone ids are not in sequence starting from 0. Missing index " << i);
|
||||||
|
@ -996,7 +859,7 @@ void OgreXmlSerializer::ReadBones(Skeleton *skeleton)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // Ogre
|
} // namespace Ogre
|
||||||
} // Assimp
|
} // namespace Assimp
|
||||||
|
|
||||||
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
|
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||||
|
|
|
@ -1212,8 +1212,8 @@ void OpenGEXImporter::resolveReferences() {
|
||||||
if( RefInfo::MeshRef == currentRefInfo->m_type ) {
|
if( RefInfo::MeshRef == currentRefInfo->m_type ) {
|
||||||
for( size_t i = 0; i < currentRefInfo->m_Names.size(); ++i ) {
|
for( size_t i = 0; i < currentRefInfo->m_Names.size(); ++i ) {
|
||||||
const std::string &name( currentRefInfo->m_Names[ i ] );
|
const std::string &name( currentRefInfo->m_Names[ i ] );
|
||||||
ReferenceMap::const_iterator it( m_mesh2refMap.find( name ) );
|
ReferenceMap::const_iterator curIt( m_mesh2refMap.find( name ) );
|
||||||
if( m_mesh2refMap.end() != it ) {
|
if (m_mesh2refMap.end() != curIt) {
|
||||||
unsigned int meshIdx = static_cast<unsigned int>(m_mesh2refMap[ name ]);
|
unsigned int meshIdx = static_cast<unsigned int>(m_mesh2refMap[ name ]);
|
||||||
node->mMeshes[ i ] = meshIdx;
|
node->mMeshes[ i ] = meshIdx;
|
||||||
}
|
}
|
||||||
|
@ -1221,8 +1221,8 @@ void OpenGEXImporter::resolveReferences() {
|
||||||
} else if( RefInfo::MaterialRef == currentRefInfo->m_type ) {
|
} else if( RefInfo::MaterialRef == currentRefInfo->m_type ) {
|
||||||
for ( size_t i = 0; i < currentRefInfo->m_Names.size(); ++i ) {
|
for ( size_t i = 0; i < currentRefInfo->m_Names.size(); ++i ) {
|
||||||
const std::string name( currentRefInfo->m_Names[ i ] );
|
const std::string name( currentRefInfo->m_Names[ i ] );
|
||||||
ReferenceMap::const_iterator it( m_material2refMap.find( name ) );
|
ReferenceMap::const_iterator curIt(m_material2refMap.find(name));
|
||||||
if ( m_material2refMap.end() != it ) {
|
if (m_material2refMap.end() != curIt) {
|
||||||
if ( nullptr != m_currentMesh ) {
|
if ( nullptr != m_currentMesh ) {
|
||||||
unsigned int matIdx = static_cast< unsigned int >( m_material2refMap[ name ] );
|
unsigned int matIdx = static_cast< unsigned int >( m_material2refMap[ name ] );
|
||||||
if ( m_currentMesh->mMaterialIndex != 0 ) {
|
if ( m_currentMesh->mMaterialIndex != 0 ) {
|
||||||
|
|
|
@ -49,10 +49,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
// internal headers
|
// internal headers
|
||||||
#include "PlyLoader.h"
|
#include "PlyLoader.h"
|
||||||
#include <assimp/IOStreamBuffer.h>
|
#include <assimp/IOStreamBuffer.h>
|
||||||
#include <memory>
|
|
||||||
#include <assimp/IOSystem.hpp>
|
|
||||||
#include <assimp/scene.h>
|
|
||||||
#include <assimp/importerdesc.h>
|
#include <assimp/importerdesc.h>
|
||||||
|
#include <assimp/scene.h>
|
||||||
|
#include <assimp/IOSystem.hpp>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
using namespace ::Assimp;
|
using namespace ::Assimp;
|
||||||
|
|
||||||
|
@ -69,29 +69,25 @@ static const aiImporterDesc desc = {
|
||||||
"ply"
|
"ply"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Internal stuff
|
// Internal stuff
|
||||||
namespace {
|
namespace {
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Checks that property index is within range
|
// Checks that property index is within range
|
||||||
template <class T>
|
template <class T>
|
||||||
inline
|
inline const T &GetProperty(const std::vector<T> &props, int idx) {
|
||||||
const T &GetProperty(const std::vector<T> &props, int idx) {
|
|
||||||
if (static_cast<size_t>(idx) >= props.size()) {
|
if (static_cast<size_t>(idx) >= props.size()) {
|
||||||
throw DeadlyImportError("Invalid .ply file: Property index is out of range.");
|
throw DeadlyImportError("Invalid .ply file: Property index is out of range.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return props[idx];
|
return props[idx];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructor to be privately used by Importer
|
// Constructor to be privately used by Importer
|
||||||
PLYImporter::PLYImporter()
|
PLYImporter::PLYImporter() :
|
||||||
: mBuffer(nullptr)
|
mBuffer(nullptr), pcDOM(nullptr), mGeneratedMesh(nullptr) {
|
||||||
, pcDOM(nullptr)
|
|
||||||
, mGeneratedMesh(nullptr) {
|
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,16 +99,16 @@ PLYImporter::~PLYImporter() {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// 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 PLYImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
|
bool PLYImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
|
||||||
const std::string extension = GetExtension(pFile);
|
const std::string extension = GetExtension(pFile);
|
||||||
|
|
||||||
if ( extension == "ply" ) {
|
if (extension == "ply") {
|
||||||
return true;
|
return true;
|
||||||
} else if (!extension.length() || checkSig) {
|
} else if (!extension.length() || checkSig) {
|
||||||
if ( !pIOHandler ) {
|
if (!pIOHandler) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
static const char* tokens[] = { "ply" };
|
static const char *tokens[] = { "ply" };
|
||||||
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
|
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,19 +116,19 @@ bool PLYImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool c
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
const aiImporterDesc* PLYImporter::GetInfo() const {
|
const aiImporterDesc *PLYImporter::GetInfo() const {
|
||||||
return &desc;
|
return &desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
static bool isBigEndian(const char* szMe) {
|
static bool isBigEndian(const char *szMe) {
|
||||||
ai_assert(nullptr != szMe);
|
ai_assert(nullptr != szMe);
|
||||||
|
|
||||||
// binary_little_endian
|
// binary_little_endian
|
||||||
// binary_big_endian
|
// binary_big_endian
|
||||||
bool isBigEndian(false);
|
bool isBigEndian(false);
|
||||||
#if (defined AI_BUILD_BIG_ENDIAN)
|
#if (defined AI_BUILD_BIG_ENDIAN)
|
||||||
if ( 'l' == *szMe || 'L' == *szMe ) {
|
if ('l' == *szMe || 'L' == *szMe) {
|
||||||
isBigEndian = true;
|
isBigEndian = true;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -146,7 +142,7 @@ static bool isBigEndian(const char* szMe) {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Imports the given file into the given scene structure.
|
// Imports the given file into the given scene structure.
|
||||||
void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) {
|
void PLYImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
|
||||||
const std::string mode = "rb";
|
const std::string mode = "rb";
|
||||||
std::unique_ptr<IOStream> fileStream(pIOHandler->Open(pFile, mode));
|
std::unique_ptr<IOStream> fileStream(pIOHandler->Open(pFile, mode));
|
||||||
if (!fileStream.get()) {
|
if (!fileStream.get()) {
|
||||||
|
@ -154,8 +150,8 @@ void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the file-size
|
// Get the file-size
|
||||||
const size_t fileSize( fileStream->FileSize() );
|
const size_t fileSize(fileStream->FileSize());
|
||||||
if ( 0 == fileSize ) {
|
if (0 == fileSize) {
|
||||||
throw DeadlyImportError("File " + pFile + " is empty.");
|
throw DeadlyImportError("File " + pFile + " is empty.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,17 +165,17 @@ void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
|
||||||
if ((headerCheck.size() < 3) ||
|
if ((headerCheck.size() < 3) ||
|
||||||
(headerCheck[0] != 'P' && headerCheck[0] != 'p') ||
|
(headerCheck[0] != 'P' && headerCheck[0] != 'p') ||
|
||||||
(headerCheck[1] != 'L' && headerCheck[1] != 'l') ||
|
(headerCheck[1] != 'L' && headerCheck[1] != 'l') ||
|
||||||
(headerCheck[2] != 'Y' && headerCheck[2] != 'y') ) {
|
(headerCheck[2] != 'Y' && headerCheck[2] != 'y')) {
|
||||||
streamedBuffer.close();
|
streamedBuffer.close();
|
||||||
throw DeadlyImportError("Invalid .ply file: Magic number \'ply\' is no there");
|
throw DeadlyImportError("Invalid .ply file: Magic number \'ply\' is no there");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<char> mBuffer2;
|
std::vector<char> mBuffer2;
|
||||||
streamedBuffer.getNextLine(mBuffer2);
|
streamedBuffer.getNextLine(mBuffer2);
|
||||||
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);
|
SkipSpacesAndLineEnd(szMe, (const char **)&szMe);
|
||||||
|
|
||||||
// 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;
|
||||||
|
@ -187,10 +183,10 @@ 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);
|
||||||
if (!PLY::DOM::ParseInstance(streamedBuffer, &sPlyDom, this)) {
|
if (!PLY::DOM::ParseInstance(streamedBuffer, &sPlyDom, this)) {
|
||||||
if (mGeneratedMesh != nullptr) {
|
if (mGeneratedMesh != nullptr) {
|
||||||
delete(mGeneratedMesh);
|
delete (mGeneratedMesh);
|
||||||
mGeneratedMesh = nullptr;
|
mGeneratedMesh = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,7 +200,7 @@ void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
|
||||||
// skip the line, parse the rest of the header and build the DOM
|
// skip the line, parse the rest of the header and build the DOM
|
||||||
if (!PLY::DOM::ParseInstanceBinary(streamedBuffer, &sPlyDom, this, bIsBE)) {
|
if (!PLY::DOM::ParseInstanceBinary(streamedBuffer, &sPlyDom, this, bIsBE)) {
|
||||||
if (mGeneratedMesh != nullptr) {
|
if (mGeneratedMesh != nullptr) {
|
||||||
delete(mGeneratedMesh);
|
delete (mGeneratedMesh);
|
||||||
mGeneratedMesh = nullptr;
|
mGeneratedMesh = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,7 +209,7 @@ void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (mGeneratedMesh != nullptr) {
|
if (mGeneratedMesh != nullptr) {
|
||||||
delete(mGeneratedMesh);
|
delete (mGeneratedMesh);
|
||||||
mGeneratedMesh = nullptr;
|
mGeneratedMesh = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,7 +219,7 @@ void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
|
||||||
} else {
|
} else {
|
||||||
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
||||||
if (mGeneratedMesh != nullptr) {
|
if (mGeneratedMesh != nullptr) {
|
||||||
delete(mGeneratedMesh);
|
delete (mGeneratedMesh);
|
||||||
mGeneratedMesh = nullptr;
|
mGeneratedMesh = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,20 +242,20 @@ void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
|
||||||
}
|
}
|
||||||
|
|
||||||
// now load a list of all materials
|
// now load a list of all materials
|
||||||
std::vector<aiMaterial*> avMaterials;
|
std::vector<aiMaterial *> avMaterials;
|
||||||
std::string defaultTexture;
|
std::string defaultTexture;
|
||||||
LoadMaterial(&avMaterials, defaultTexture, pointsOnly);
|
LoadMaterial(&avMaterials, defaultTexture, pointsOnly);
|
||||||
|
|
||||||
// now generate the output scene object. Fill the material list
|
// now generate the output scene object. Fill the material list
|
||||||
pScene->mNumMaterials = (unsigned int)avMaterials.size();
|
pScene->mNumMaterials = (unsigned int)avMaterials.size();
|
||||||
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
|
pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
|
||||||
for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
|
for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
|
||||||
pScene->mMaterials[i] = avMaterials[i];
|
pScene->mMaterials[i] = avMaterials[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
// fill the mesh list
|
// fill the mesh list
|
||||||
pScene->mNumMeshes = 1;
|
pScene->mNumMeshes = 1;
|
||||||
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
|
pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
|
||||||
pScene->mMeshes[0] = mGeneratedMesh;
|
pScene->mMeshes[0] = mGeneratedMesh;
|
||||||
mGeneratedMesh = nullptr;
|
mGeneratedMesh = nullptr;
|
||||||
|
|
||||||
|
@ -273,7 +269,7 @@ void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos) {
|
void PLYImporter::LoadVertex(const PLY::Element *pcElement, const PLY::ElementInstance *instElement, unsigned int pos) {
|
||||||
ai_assert(nullptr != pcElement);
|
ai_assert(nullptr != pcElement);
|
||||||
ai_assert(nullptr != instElement);
|
ai_assert(nullptr != instElement);
|
||||||
|
|
||||||
|
@ -290,8 +286,8 @@ void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementIn
|
||||||
PLY::EDataType aiTexcoordTypes[2] = { EDT_Char, EDT_Char };
|
PLY::EDataType aiTexcoordTypes[2] = { EDT_Char, EDT_Char };
|
||||||
|
|
||||||
// now check whether which normal components are available
|
// now check whether which normal components are available
|
||||||
unsigned int _a( 0 ), cnt( 0 );
|
unsigned int _a(0), cnt(0);
|
||||||
for ( std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
|
for (std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
|
||||||
a != pcElement->alProperties.end(); ++a, ++_a) {
|
a != pcElement->alProperties.end(); ++a, ++_a) {
|
||||||
if ((*a).bIsList) {
|
if ((*a).bIsList) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -397,19 +393,25 @@ void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementIn
|
||||||
bool haveColor = false;
|
bool haveColor = false;
|
||||||
if (0xFFFFFFFF != aiColors[0]) {
|
if (0xFFFFFFFF != aiColors[0]) {
|
||||||
cOut.r = NormalizeColorValue(GetProperty(instElement->alProperties,
|
cOut.r = NormalizeColorValue(GetProperty(instElement->alProperties,
|
||||||
aiColors[0]).avList.front(), aiColorsTypes[0]);
|
aiColors[0])
|
||||||
|
.avList.front(),
|
||||||
|
aiColorsTypes[0]);
|
||||||
haveColor = true;
|
haveColor = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0xFFFFFFFF != aiColors[1]) {
|
if (0xFFFFFFFF != aiColors[1]) {
|
||||||
cOut.g = NormalizeColorValue(GetProperty(instElement->alProperties,
|
cOut.g = NormalizeColorValue(GetProperty(instElement->alProperties,
|
||||||
aiColors[1]).avList.front(), aiColorsTypes[1]);
|
aiColors[1])
|
||||||
|
.avList.front(),
|
||||||
|
aiColorsTypes[1]);
|
||||||
haveColor = true;
|
haveColor = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0xFFFFFFFF != aiColors[2]) {
|
if (0xFFFFFFFF != aiColors[2]) {
|
||||||
cOut.b = NormalizeColorValue(GetProperty(instElement->alProperties,
|
cOut.b = NormalizeColorValue(GetProperty(instElement->alProperties,
|
||||||
aiColors[2]).avList.front(), aiColorsTypes[2]);
|
aiColors[2])
|
||||||
|
.avList.front(),
|
||||||
|
aiColorsTypes[2]);
|
||||||
haveColor = true;
|
haveColor = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,7 +420,9 @@ void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementIn
|
||||||
cOut.a = 1.0;
|
cOut.a = 1.0;
|
||||||
} else {
|
} else {
|
||||||
cOut.a = NormalizeColorValue(GetProperty(instElement->alProperties,
|
cOut.a = NormalizeColorValue(GetProperty(instElement->alProperties,
|
||||||
aiColors[3]).avList.front(), aiColorsTypes[3]);
|
aiColors[3])
|
||||||
|
.avList.front(),
|
||||||
|
aiColorsTypes[3]);
|
||||||
|
|
||||||
haveColor = true;
|
haveColor = true;
|
||||||
}
|
}
|
||||||
|
@ -440,7 +444,7 @@ void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementIn
|
||||||
}
|
}
|
||||||
|
|
||||||
//create aiMesh if needed
|
//create aiMesh if needed
|
||||||
if ( nullptr == mGeneratedMesh ) {
|
if (nullptr == mGeneratedMesh) {
|
||||||
mGeneratedMesh = new aiMesh();
|
mGeneratedMesh = new aiMesh();
|
||||||
mGeneratedMesh->mMaterialIndex = 0;
|
mGeneratedMesh->mMaterialIndex = 0;
|
||||||
}
|
}
|
||||||
|
@ -474,7 +478,6 @@ void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementIn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Convert a color component to [0...1]
|
// Convert a color component to [0...1]
|
||||||
ai_real PLYImporter::NormalizeColorValue(PLY::PropertyInstance::ValueUnion val, PLY::EDataType eType) {
|
ai_real PLYImporter::NormalizeColorValue(PLY::PropertyInstance::ValueUnion val, PLY::EDataType eType) {
|
||||||
|
@ -504,7 +507,7 @@ ai_real PLYImporter::NormalizeColorValue(PLY::PropertyInstance::ValueUnion val,
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Try to extract proper faces from the PLY DOM
|
// Try to extract proper faces from the PLY DOM
|
||||||
void PLYImporter::LoadFace(const PLY::Element* pcElement, const PLY::ElementInstance* instElement,
|
void PLYImporter::LoadFace(const PLY::Element *pcElement, const PLY::ElementInstance *instElement,
|
||||||
unsigned int pos) {
|
unsigned int pos) {
|
||||||
ai_assert(nullptr != pcElement);
|
ai_assert(nullptr != pcElement);
|
||||||
ai_assert(nullptr != instElement);
|
ai_assert(nullptr != instElement);
|
||||||
|
@ -613,7 +616,7 @@ void PLYImporter::LoadFace(const PLY::Element* pcElement, const PLY::ElementInst
|
||||||
for (unsigned int a = 0; a < iNum; ++a, ++p) {
|
for (unsigned int a = 0; a < iNum; ++a, ++p) {
|
||||||
unsigned int vindex = mGeneratedMesh->mFaces[pos].mIndices[a / 2];
|
unsigned int vindex = mGeneratedMesh->mFaces[pos].mIndices[a / 2];
|
||||||
if (vindex < mGeneratedMesh->mNumVertices) {
|
if (vindex < mGeneratedMesh->mNumVertices) {
|
||||||
if (mGeneratedMesh->mTextureCoords[0] == nullptr ) {
|
if (mGeneratedMesh->mTextureCoords[0] == nullptr) {
|
||||||
mGeneratedMesh->mNumUVComponents[0] = 2;
|
mGeneratedMesh->mNumUVComponents[0] = 2;
|
||||||
mGeneratedMesh->mTextureCoords[0] = new aiVector3D[mGeneratedMesh->mNumVertices];
|
mGeneratedMesh->mTextureCoords[0] = new aiVector3D[mGeneratedMesh->mNumVertices];
|
||||||
}
|
}
|
||||||
|
@ -633,7 +636,7 @@ void PLYImporter::LoadFace(const PLY::Element* pcElement, const PLY::ElementInst
|
||||||
// normally we have only one triangle strip instance where
|
// normally we have only one triangle strip instance where
|
||||||
// a value of -1 indicates a restart of the strip
|
// a value of -1 indicates a restart of the strip
|
||||||
bool flip = false;
|
bool flip = false;
|
||||||
const std::vector<PLY::PropertyInstance::ValueUnion>& quak = GetProperty(instElement->alProperties, iProperty).avList;
|
const std::vector<PLY::PropertyInstance::ValueUnion> &quak = GetProperty(instElement->alProperties, iProperty).avList;
|
||||||
//pvOut->reserve(pvOut->size() + quak.size() + (quak.size()>>2u)); //Limits memory consumption
|
//pvOut->reserve(pvOut->size() + quak.size() + (quak.size()>>2u)); //Limits memory consumption
|
||||||
|
|
||||||
int aiTable[2] = { -1, -1 };
|
int aiTable[2] = { -1, -1 };
|
||||||
|
@ -668,7 +671,7 @@ void PLYImporter::LoadFace(const PLY::Element* pcElement, const PLY::ElementInst
|
||||||
|
|
||||||
// every second pass swap the indices.
|
// every second pass swap the indices.
|
||||||
flip = !flip;
|
flip = !flip;
|
||||||
if ( flip ) {
|
if (flip) {
|
||||||
std::swap(mGeneratedMesh->mFaces[pos].mIndices[0], mGeneratedMesh->mFaces[pos].mIndices[1]);
|
std::swap(mGeneratedMesh->mFaces[pos].mIndices[0], mGeneratedMesh->mFaces[pos].mIndices[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -681,47 +684,53 @@ void PLYImporter::LoadFace(const PLY::Element* pcElement, const PLY::ElementInst
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Get a RGBA color in [0...1] range
|
// Get a RGBA color in [0...1] range
|
||||||
void PLYImporter::GetMaterialColor(const std::vector<PLY::PropertyInstance>& avList,
|
void PLYImporter::GetMaterialColor(const std::vector<PLY::PropertyInstance> &avList,
|
||||||
unsigned int aiPositions[4],
|
unsigned int aiPositions[4],
|
||||||
PLY::EDataType aiTypes[4],
|
PLY::EDataType aiTypes[4],
|
||||||
aiColor4D* clrOut)
|
aiColor4D *clrOut) {
|
||||||
{
|
|
||||||
ai_assert(NULL != clrOut);
|
ai_assert(NULL != clrOut);
|
||||||
|
|
||||||
if (0xFFFFFFFF == aiPositions[0])clrOut->r = 0.0f;
|
if (0xFFFFFFFF == aiPositions[0])
|
||||||
else
|
clrOut->r = 0.0f;
|
||||||
{
|
else {
|
||||||
clrOut->r = NormalizeColorValue(GetProperty(avList,
|
clrOut->r = NormalizeColorValue(GetProperty(avList,
|
||||||
aiPositions[0]).avList.front(), aiTypes[0]);
|
aiPositions[0])
|
||||||
|
.avList.front(),
|
||||||
|
aiTypes[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0xFFFFFFFF == aiPositions[1])clrOut->g = 0.0f;
|
if (0xFFFFFFFF == aiPositions[1])
|
||||||
else
|
clrOut->g = 0.0f;
|
||||||
{
|
else {
|
||||||
clrOut->g = NormalizeColorValue(GetProperty(avList,
|
clrOut->g = NormalizeColorValue(GetProperty(avList,
|
||||||
aiPositions[1]).avList.front(), aiTypes[1]);
|
aiPositions[1])
|
||||||
|
.avList.front(),
|
||||||
|
aiTypes[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0xFFFFFFFF == aiPositions[2])clrOut->b = 0.0f;
|
if (0xFFFFFFFF == aiPositions[2])
|
||||||
else
|
clrOut->b = 0.0f;
|
||||||
{
|
else {
|
||||||
clrOut->b = NormalizeColorValue(GetProperty(avList,
|
clrOut->b = NormalizeColorValue(GetProperty(avList,
|
||||||
aiPositions[2]).avList.front(), aiTypes[2]);
|
aiPositions[2])
|
||||||
|
.avList.front(),
|
||||||
|
aiTypes[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// assume 1.0 for the alpha channel ifit is not set
|
// assume 1.0 for the alpha channel ifit is not set
|
||||||
if (0xFFFFFFFF == aiPositions[3])clrOut->a = 1.0f;
|
if (0xFFFFFFFF == aiPositions[3])
|
||||||
else
|
clrOut->a = 1.0f;
|
||||||
{
|
else {
|
||||||
clrOut->a = NormalizeColorValue(GetProperty(avList,
|
clrOut->a = NormalizeColorValue(GetProperty(avList,
|
||||||
aiPositions[3]).avList.front(), aiTypes[3]);
|
aiPositions[3])
|
||||||
|
.avList.front(),
|
||||||
|
aiTypes[3]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Extract a material from the PLY DOM
|
// Extract a material from the PLY DOM
|
||||||
void PLYImporter::LoadMaterial(std::vector<aiMaterial*>* pvOut, std::string &defaultTexture, const bool pointsOnly)
|
void PLYImporter::LoadMaterial(std::vector<aiMaterial *> *pvOut, std::string &defaultTexture, const bool pointsOnly) {
|
||||||
{
|
|
||||||
ai_assert(NULL != pvOut);
|
ai_assert(NULL != pvOut);
|
||||||
|
|
||||||
// diffuse[4], specular[4], ambient[4]
|
// diffuse[4], specular[4], ambient[4]
|
||||||
|
@ -738,7 +747,7 @@ void PLYImporter::LoadMaterial(std::vector<aiMaterial*>* pvOut, std::string &def
|
||||||
{ EDT_Char, EDT_Char, EDT_Char, EDT_Char },
|
{ EDT_Char, EDT_Char, EDT_Char, EDT_Char },
|
||||||
{ EDT_Char, EDT_Char, EDT_Char, EDT_Char }
|
{ EDT_Char, EDT_Char, EDT_Char, EDT_Char }
|
||||||
};
|
};
|
||||||
PLY::ElementInstanceList* pcList = NULL;
|
PLY::ElementInstanceList *pcList = NULL;
|
||||||
|
|
||||||
unsigned int iPhong = 0xFFFFFFFF;
|
unsigned int iPhong = 0xFFFFFFFF;
|
||||||
PLY::EDataType ePhong = EDT_Char;
|
PLY::EDataType ePhong = EDT_Char;
|
||||||
|
@ -749,102 +758,74 @@ void PLYImporter::LoadMaterial(std::vector<aiMaterial*>* pvOut, std::string &def
|
||||||
// search in the DOM for a vertex entry
|
// search in the DOM for a vertex entry
|
||||||
unsigned int _i = 0;
|
unsigned int _i = 0;
|
||||||
for (std::vector<PLY::Element>::const_iterator i = this->pcDOM->alElements.begin();
|
for (std::vector<PLY::Element>::const_iterator i = this->pcDOM->alElements.begin();
|
||||||
i != this->pcDOM->alElements.end(); ++i, ++_i)
|
i != this->pcDOM->alElements.end(); ++i, ++_i) {
|
||||||
{
|
if (PLY::EEST_Material == (*i).eSemantic) {
|
||||||
if (PLY::EEST_Material == (*i).eSemantic)
|
|
||||||
{
|
|
||||||
pcList = &this->pcDOM->alElementData[_i];
|
pcList = &this->pcDOM->alElementData[_i];
|
||||||
|
|
||||||
// now check whether which coordinate sets are available
|
// now check whether which coordinate sets are available
|
||||||
unsigned int _a = 0;
|
unsigned int _a = 0;
|
||||||
for (std::vector<PLY::Property>::const_iterator
|
for (std::vector<PLY::Property>::const_iterator
|
||||||
a = (*i).alProperties.begin();
|
a = (*i).alProperties.begin();
|
||||||
a != (*i).alProperties.end(); ++a, ++_a)
|
a != (*i).alProperties.end(); ++a, ++_a) {
|
||||||
{
|
if ((*a).bIsList) continue;
|
||||||
if ((*a).bIsList)continue;
|
|
||||||
|
|
||||||
// pohng specularity -----------------------------------
|
// pohng specularity -----------------------------------
|
||||||
if (PLY::EST_PhongPower == (*a).Semantic)
|
if (PLY::EST_PhongPower == (*a).Semantic) {
|
||||||
{
|
|
||||||
iPhong = _a;
|
iPhong = _a;
|
||||||
ePhong = (*a).eType;
|
ePhong = (*a).eType;
|
||||||
}
|
}
|
||||||
|
|
||||||
// general opacity -----------------------------------
|
// general opacity -----------------------------------
|
||||||
if (PLY::EST_Opacity == (*a).Semantic)
|
if (PLY::EST_Opacity == (*a).Semantic) {
|
||||||
{
|
|
||||||
iOpacity = _a;
|
iOpacity = _a;
|
||||||
eOpacity = (*a).eType;
|
eOpacity = (*a).eType;
|
||||||
}
|
}
|
||||||
|
|
||||||
// diffuse color channels -----------------------------------
|
// diffuse color channels -----------------------------------
|
||||||
if (PLY::EST_DiffuseRed == (*a).Semantic)
|
if (PLY::EST_DiffuseRed == (*a).Semantic) {
|
||||||
{
|
|
||||||
aaiPositions[0][0] = _a;
|
aaiPositions[0][0] = _a;
|
||||||
aaiTypes[0][0] = (*a).eType;
|
aaiTypes[0][0] = (*a).eType;
|
||||||
}
|
} else if (PLY::EST_DiffuseGreen == (*a).Semantic) {
|
||||||
else if (PLY::EST_DiffuseGreen == (*a).Semantic)
|
|
||||||
{
|
|
||||||
aaiPositions[0][1] = _a;
|
aaiPositions[0][1] = _a;
|
||||||
aaiTypes[0][1] = (*a).eType;
|
aaiTypes[0][1] = (*a).eType;
|
||||||
}
|
} else if (PLY::EST_DiffuseBlue == (*a).Semantic) {
|
||||||
else if (PLY::EST_DiffuseBlue == (*a).Semantic)
|
|
||||||
{
|
|
||||||
aaiPositions[0][2] = _a;
|
aaiPositions[0][2] = _a;
|
||||||
aaiTypes[0][2] = (*a).eType;
|
aaiTypes[0][2] = (*a).eType;
|
||||||
}
|
} else if (PLY::EST_DiffuseAlpha == (*a).Semantic) {
|
||||||
else if (PLY::EST_DiffuseAlpha == (*a).Semantic)
|
|
||||||
{
|
|
||||||
aaiPositions[0][3] = _a;
|
aaiPositions[0][3] = _a;
|
||||||
aaiTypes[0][3] = (*a).eType;
|
aaiTypes[0][3] = (*a).eType;
|
||||||
}
|
}
|
||||||
// specular color channels -----------------------------------
|
// specular color channels -----------------------------------
|
||||||
else if (PLY::EST_SpecularRed == (*a).Semantic)
|
else if (PLY::EST_SpecularRed == (*a).Semantic) {
|
||||||
{
|
|
||||||
aaiPositions[1][0] = _a;
|
aaiPositions[1][0] = _a;
|
||||||
aaiTypes[1][0] = (*a).eType;
|
aaiTypes[1][0] = (*a).eType;
|
||||||
}
|
} else if (PLY::EST_SpecularGreen == (*a).Semantic) {
|
||||||
else if (PLY::EST_SpecularGreen == (*a).Semantic)
|
|
||||||
{
|
|
||||||
aaiPositions[1][1] = _a;
|
aaiPositions[1][1] = _a;
|
||||||
aaiTypes[1][1] = (*a).eType;
|
aaiTypes[1][1] = (*a).eType;
|
||||||
}
|
} else if (PLY::EST_SpecularBlue == (*a).Semantic) {
|
||||||
else if (PLY::EST_SpecularBlue == (*a).Semantic)
|
|
||||||
{
|
|
||||||
aaiPositions[1][2] = _a;
|
aaiPositions[1][2] = _a;
|
||||||
aaiTypes[1][2] = (*a).eType;
|
aaiTypes[1][2] = (*a).eType;
|
||||||
}
|
} else if (PLY::EST_SpecularAlpha == (*a).Semantic) {
|
||||||
else if (PLY::EST_SpecularAlpha == (*a).Semantic)
|
|
||||||
{
|
|
||||||
aaiPositions[1][3] = _a;
|
aaiPositions[1][3] = _a;
|
||||||
aaiTypes[1][3] = (*a).eType;
|
aaiTypes[1][3] = (*a).eType;
|
||||||
}
|
}
|
||||||
// ambient color channels -----------------------------------
|
// ambient color channels -----------------------------------
|
||||||
else if (PLY::EST_AmbientRed == (*a).Semantic)
|
else if (PLY::EST_AmbientRed == (*a).Semantic) {
|
||||||
{
|
|
||||||
aaiPositions[2][0] = _a;
|
aaiPositions[2][0] = _a;
|
||||||
aaiTypes[2][0] = (*a).eType;
|
aaiTypes[2][0] = (*a).eType;
|
||||||
}
|
} else if (PLY::EST_AmbientGreen == (*a).Semantic) {
|
||||||
else if (PLY::EST_AmbientGreen == (*a).Semantic)
|
|
||||||
{
|
|
||||||
aaiPositions[2][1] = _a;
|
aaiPositions[2][1] = _a;
|
||||||
aaiTypes[2][1] = (*a).eType;
|
aaiTypes[2][1] = (*a).eType;
|
||||||
}
|
} else if (PLY::EST_AmbientBlue == (*a).Semantic) {
|
||||||
else if (PLY::EST_AmbientBlue == (*a).Semantic)
|
|
||||||
{
|
|
||||||
aaiPositions[2][2] = _a;
|
aaiPositions[2][2] = _a;
|
||||||
aaiTypes[2][2] = (*a).eType;
|
aaiTypes[2][2] = (*a).eType;
|
||||||
}
|
} else if (PLY::EST_AmbientAlpha == (*a).Semantic) {
|
||||||
else if (PLY::EST_AmbientAlpha == (*a).Semantic)
|
|
||||||
{
|
|
||||||
aaiPositions[2][3] = _a;
|
aaiPositions[2][3] = _a;
|
||||||
aaiTypes[2][3] = (*a).eType;
|
aaiTypes[2][3] = (*a).eType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
} else if (PLY::EEST_TextureFile == (*i).eSemantic) {
|
||||||
else if (PLY::EEST_TextureFile == (*i).eSemantic)
|
|
||||||
{
|
|
||||||
defaultTexture = (*i).szName;
|
defaultTexture = (*i).szName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -852,7 +833,7 @@ void PLYImporter::LoadMaterial(std::vector<aiMaterial*>* pvOut, std::string &def
|
||||||
if (NULL != pcList) {
|
if (NULL != pcList) {
|
||||||
for (std::vector<ElementInstance>::const_iterator i = pcList->alInstances.begin(); i != pcList->alInstances.end(); ++i) {
|
for (std::vector<ElementInstance>::const_iterator i = pcList->alInstances.begin(); i != pcList->alInstances.end(); ++i) {
|
||||||
aiColor4D clrOut;
|
aiColor4D clrOut;
|
||||||
aiMaterial* pcHelper = new aiMaterial();
|
aiMaterial *pcHelper = new aiMaterial();
|
||||||
|
|
||||||
// build the diffuse material color
|
// build the diffuse material color
|
||||||
GetMaterialColor((*i).alProperties, aaiPositions[0], aaiTypes[0], &clrOut);
|
GetMaterialColor((*i).alProperties, aaiPositions[0], aaiTypes[0], &clrOut);
|
||||||
|
@ -895,21 +876,17 @@ void PLYImporter::LoadMaterial(std::vector<aiMaterial*>* pvOut, std::string &def
|
||||||
pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED);
|
pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED);
|
||||||
|
|
||||||
//default texture
|
//default texture
|
||||||
if (!defaultTexture.empty())
|
if (!defaultTexture.empty()) {
|
||||||
{
|
|
||||||
const aiString name(defaultTexture.c_str());
|
const aiString name(defaultTexture.c_str());
|
||||||
pcHelper->AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE, 0);
|
pcHelper->AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pointsOnly)
|
if (!pointsOnly) {
|
||||||
{
|
|
||||||
const int two_sided = 1;
|
|
||||||
pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED);
|
pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED);
|
||||||
}
|
}
|
||||||
|
|
||||||
//set to wireframe, so when using this material info we can switch to points rendering
|
//set to wireframe, so when using this material info we can switch to points rendering
|
||||||
if (pointsOnly)
|
if (pointsOnly) {
|
||||||
{
|
|
||||||
const int wireframe = 1;
|
const int wireframe = 1;
|
||||||
pcHelper->AddProperty(&wireframe, 1, AI_MATKEY_ENABLE_WIREFRAME);
|
pcHelper->AddProperty(&wireframe, 1, AI_MATKEY_ENABLE_WIREFRAME);
|
||||||
}
|
}
|
||||||
|
@ -917,11 +894,9 @@ void PLYImporter::LoadMaterial(std::vector<aiMaterial*>* pvOut, std::string &def
|
||||||
// add the newly created material instance to the list
|
// add the newly created material instance to the list
|
||||||
pvOut->push_back(pcHelper);
|
pvOut->push_back(pcHelper);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// generate a default material
|
// generate a default material
|
||||||
aiMaterial* pcHelper = new aiMaterial();
|
aiMaterial *pcHelper = new aiMaterial();
|
||||||
|
|
||||||
// fill in a default material
|
// fill in a default material
|
||||||
int iMode = (int)aiShadingMode_Gouraud;
|
int iMode = (int)aiShadingMode_Gouraud;
|
||||||
|
@ -938,22 +913,19 @@ void PLYImporter::LoadMaterial(std::vector<aiMaterial*>* pvOut, std::string &def
|
||||||
|
|
||||||
// The face order is absolutely undefined for PLY, so we have to
|
// The face order is absolutely undefined for PLY, so we have to
|
||||||
// use two-sided rendering to be sure it's ok.
|
// use two-sided rendering to be sure it's ok.
|
||||||
if (!pointsOnly)
|
if (!pointsOnly) {
|
||||||
{
|
|
||||||
const int two_sided = 1;
|
const int two_sided = 1;
|
||||||
pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED);
|
pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED);
|
||||||
}
|
}
|
||||||
|
|
||||||
//default texture
|
//default texture
|
||||||
if (!defaultTexture.empty())
|
if (!defaultTexture.empty()) {
|
||||||
{
|
|
||||||
const aiString name(defaultTexture.c_str());
|
const aiString name(defaultTexture.c_str());
|
||||||
pcHelper->AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE, 0);
|
pcHelper->AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//set to wireframe, so when using this material info we can switch to points rendering
|
//set to wireframe, so when using this material info we can switch to points rendering
|
||||||
if (pointsOnly)
|
if (pointsOnly) {
|
||||||
{
|
|
||||||
const int wireframe = 1;
|
const int wireframe = 1;
|
||||||
pcHelper->AddProperty(&wireframe, 1, AI_MATKEY_ENABLE_WIREFRAME);
|
pcHelper->AddProperty(&wireframe, 1, AI_MATKEY_ENABLE_WIREFRAME);
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,7 +137,7 @@ bool EmbedTexturesProcess::addTexture(aiScene* pScene, std::string path) const {
|
||||||
pTexture->pcData = imageContent;
|
pTexture->pcData = imageContent;
|
||||||
|
|
||||||
auto extension = path.substr(path.find_last_of('.') + 1u);
|
auto extension = path.substr(path.find_last_of('.') + 1u);
|
||||||
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
|
std::transform(extension.begin(), extension.end(), extension.begin(), ToLower<char> );
|
||||||
if (extension == "jpeg") {
|
if (extension == "jpeg") {
|
||||||
extension = "jpg";
|
extension = "jpg";
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,7 +105,8 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
|
||||||
if (info.mRotation)
|
if (info.mRotation)
|
||||||
{
|
{
|
||||||
float out = info.mRotation;
|
float out = info.mRotation;
|
||||||
if ((rounded = static_cast<int>((info.mRotation / static_cast<float>(AI_MATH_TWO_PI)))))
|
rounded = static_cast<int>((info.mRotation / static_cast<float>(AI_MATH_TWO_PI)));
|
||||||
|
if (rounded)
|
||||||
{
|
{
|
||||||
out -= rounded * static_cast<float>(AI_MATH_PI);
|
out -= rounded * static_cast<float>(AI_MATH_PI);
|
||||||
ASSIMP_LOG_INFO_F("Texture coordinate rotation ", info.mRotation, " can be simplified to ", out);
|
ASSIMP_LOG_INFO_F("Texture coordinate rotation ", info.mRotation, " can be simplified to ", out);
|
||||||
|
|
|
@ -517,8 +517,8 @@ outer:
|
||||||
for (FaceIdxArray::const_iterator it = fidx[i].begin(),end = fidx[i].end();
|
for (FaceIdxArray::const_iterator it = fidx[i].begin(),end = fidx[i].end();
|
||||||
it != end; ++it, ++faces)
|
it != end; ++it, ++faces)
|
||||||
{
|
{
|
||||||
Mesh& m = meshes[(*it).first];
|
Mesh& curMesh = meshes[(*it).first];
|
||||||
Face& face = m.faces[(*it).second];
|
Face &face = curMesh.faces[(*it).second];
|
||||||
faces->mNumIndices = (unsigned int)face.indices.size();
|
faces->mNumIndices = (unsigned int)face.indices.size();
|
||||||
faces->mIndices = new unsigned int [faces->mNumIndices];
|
faces->mIndices = new unsigned int [faces->mNumIndices];
|
||||||
|
|
||||||
|
@ -528,29 +528,30 @@ outer:
|
||||||
|
|
||||||
for (unsigned int n = 0; n < faces->mNumIndices;++n, ++cnt, ++norms, ++verts)
|
for (unsigned int n = 0; n < faces->mNumIndices;++n, ++cnt, ++norms, ++verts)
|
||||||
{
|
{
|
||||||
if (face.indices[n] >= m.verts.size())
|
if (face.indices[n] >= curMesh.verts.size())
|
||||||
{
|
{
|
||||||
ASSIMP_LOG_WARN("Quick3D: Vertex index overflow");
|
ASSIMP_LOG_WARN("Quick3D: Vertex index overflow");
|
||||||
face.indices[n] = 0;
|
face.indices[n] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy vertices
|
// copy vertices
|
||||||
*verts = m.verts[ face.indices[n] ];
|
*verts = curMesh.verts[face.indices[n]];
|
||||||
|
|
||||||
if (face.indices[n] >= m.normals.size() && faces->mNumIndices >= 3)
|
if (face.indices[n] >= curMesh.normals.size() && faces->mNumIndices >= 3)
|
||||||
{
|
{
|
||||||
// we have no normal here - assign the face normal
|
// we have no normal here - assign the face normal
|
||||||
if (!fnOK)
|
if (!fnOK)
|
||||||
{
|
{
|
||||||
const aiVector3D& pV1 = m.verts[ face.indices[0] ];
|
const aiVector3D &pV1 = curMesh.verts[face.indices[0]];
|
||||||
const aiVector3D& pV2 = m.verts[ face.indices[1] ];
|
const aiVector3D &pV2 = curMesh.verts[face.indices[1]];
|
||||||
const aiVector3D& pV3 = m.verts[ face.indices.size() - 1 ];
|
const aiVector3D &pV3 = curMesh.verts[face.indices.size() - 1];
|
||||||
faceNormal = (pV2 - pV1) ^ (pV3 - pV1).Normalize();
|
faceNormal = (pV2 - pV1) ^ (pV3 - pV1).Normalize();
|
||||||
fnOK = true;
|
fnOK = true;
|
||||||
}
|
}
|
||||||
*norms = faceNormal;
|
*norms = faceNormal;
|
||||||
|
} else {
|
||||||
|
*norms = curMesh.normals[face.indices[n]];
|
||||||
}
|
}
|
||||||
else *norms = m.normals[ face.indices[n] ];
|
|
||||||
|
|
||||||
// copy texture coordinates
|
// copy texture coordinates
|
||||||
if (uv && m.uv.size())
|
if (uv && m.uv.size())
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -297,8 +297,7 @@ std::string XGLImporter::GetElementName()
|
||||||
|
|
||||||
std::string ret;
|
std::string ret;
|
||||||
ret.resize(len);
|
ret.resize(len);
|
||||||
|
std::transform(s, s + len, ret.begin(), ::ToLower<char>);
|
||||||
std::transform(s,s+len,ret.begin(),::tolower);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -618,26 +617,22 @@ bool XGLImporter::ReadMesh(TempScope& scope)
|
||||||
bool has[3] = {0};
|
bool has[3] = {0};
|
||||||
|
|
||||||
while (ReadElementUpToClosing(s.c_str())) {
|
while (ReadElementUpToClosing(s.c_str())) {
|
||||||
const std::string& s = GetElementName();
|
const std::string& elemName = GetElementName();
|
||||||
if (s == "fv1" || s == "lv1" || s == "pv1") {
|
if (elemName == "fv1" || elemName == "lv1" || elemName == "pv1") {
|
||||||
ReadFaceVertex(t,tf[0]);
|
ReadFaceVertex(t,tf[0]);
|
||||||
has[0] = true;
|
has[0] = true;
|
||||||
}
|
} else if (elemName == "fv2" || elemName == "lv2") {
|
||||||
else if (s == "fv2" || s == "lv2") {
|
ReadFaceVertex(t, tf[1]);
|
||||||
ReadFaceVertex(t,tf[1]);
|
|
||||||
has[1] = true;
|
has[1] = true;
|
||||||
}
|
} else if (elemName == "fv3") {
|
||||||
else if (s == "fv3") {
|
ReadFaceVertex(t, tf[2]);
|
||||||
ReadFaceVertex(t,tf[2]);
|
|
||||||
has[2] = true;
|
has[2] = true;
|
||||||
}
|
} else if (elemName == "mat") {
|
||||||
else if (s == "mat") {
|
|
||||||
if (mid != ~0u) {
|
if (mid != ~0u) {
|
||||||
LogWarn("only one material tag allowed per <f>");
|
LogWarn("only one material tag allowed per <f>");
|
||||||
}
|
}
|
||||||
mid = ResolveMaterialRef(scope);
|
mid = ResolveMaterialRef(scope);
|
||||||
}
|
} else if (elemName == "matref") {
|
||||||
else if (s == "matref") {
|
|
||||||
if (mid != ~0u) {
|
if (mid != ~0u) {
|
||||||
LogWarn("only one material tag allowed per <f>");
|
LogWarn("only one material tag allowed per <f>");
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
|
||||||
|
|
||||||
Copyright (c) 2006-2020, assimp team
|
Copyright (c) 2006-2020, 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,
|
||||||
|
|
Loading…
Reference in New Issue