next fixed warnings

pull/3012/head
Kim Kulling 2020-03-01 13:15:45 +01:00
parent fb3c3048a5
commit 920535165d
41 changed files with 4124 additions and 4618 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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