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 {
};
#pragma warning(disable : 4315 )
#pragma warning(disable : 4315)
// ---------------------------------------------------------------------------
/** Helper structure representing a texture */
@ -341,6 +341,20 @@ struct Texture {
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)),
mMapName(std::move(mMapName)),
mOffsetU(std::move(mOffsetU)),
@ -400,18 +414,29 @@ struct Texture {
/** Helper structure representing a 3ds material */
struct Material {
//! Default constructor has been deleted
Material() = delete;
//! 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)) // FIX ... we won't want object to be black
,
Material() :
mName(),
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
}
//! 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;
@ -468,7 +493,9 @@ struct Material {
return *this;
}
virtual ~Material() {}
virtual ~Material() {
// empty
}
//! Name of the material
std::string mName;

View File

@ -1,4 +1,3 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
@ -6,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
@ -80,47 +77,60 @@ static const aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------
// skip to the next token
#define AI_AC_SKIP_TO_NEXT_TOKEN() \
if (!SkipSpaces(&buffer)) { \
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL"); \
continue; \
inline
const char *AcSkipToNextToken( const char *buffer ) {
if (!SkipSpaces( &buffer )) {
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL");
}
return buffer;
}
// ------------------------------------------------------------------------------------------------
// read a string (may be enclosed in double quotation marks). buffer must point to "
#define AI_AC_GET_STRING(out) \
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)); \
inline
const char *AcGetString(const char *buffer, std::string &out) {
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)) {
return buffer;
}
out = std::string(sz, (unsigned int)(buffer - sz));
++buffer;
return buffer;
}
// ------------------------------------------------------------------------------------------------
// read 1 to n floats prefixed with an optional predefined identifier
#define AI_AC_CHECKED_LOAD_FLOAT_ARRAY(name, name_length, num, out) \
AI_AC_SKIP_TO_NEXT_TOKEN(); \
if (name_length) { \
if (strncmp(buffer, name, name_length) || !IsSpace(buffer[name_length])) { \
ASSIMP_LOG_ERROR("AC3D: Unexpexted token. " name " was expected."); \
continue; \
} \
buffer += name_length + 1; \
} \
for (unsigned int _i = 0; _i < num; ++_i) { \
AI_AC_SKIP_TO_NEXT_TOKEN(); \
buffer = fast_atoreal_move<float>(buffer, ((float *)out)[_i]); \
template<class T>
inline
const char *TAcCheckedLoadFloatArray(const char *buffer, const char *name, size_t name_length, size_t num, T *out) {
AcSkipToNextToken(buffer);
if (0 != name_length) {
if (0 != strncmp(buffer, name, name_length) || !IsSpace(buffer[name_length])) {
ASSIMP_LOG_ERROR("AC3D: Unexpexted token. " + std::string( name ) + " was expected.");
return buffer;
}
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
@ -222,7 +232,7 @@ void AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
return;
} else if (TokenMatch(buffer, "name", 4)) {
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
// the name of the node in it.
@ -231,21 +241,21 @@ void AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
}
} else if (TokenMatch(buffer, "texture", 7)) {
SkipSpaces(&buffer);
AI_AC_GET_STRING(obj.texture);
buffer = AcGetString(buffer, obj.texture);
} else if (TokenMatch(buffer, "texrep", 6)) {
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)
obj.texRepeat = aiVector2D(1.f, 1.f);
} else if (TokenMatch(buffer, "texoff", 6)) {
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)) {
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)) {
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)) {
SkipSpaces(&buffer);
obj.subDiv = strtoul10(buffer, &buffer);
@ -271,7 +281,7 @@ void AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
}
obj.vertices.push_back(aiVector3D());
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)) {
SkipSpaces(&buffer);
@ -331,10 +341,9 @@ void AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
entry.first = strtoul10(buffer, &buffer);
SkipSpaces(&buffer);
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("", 0, 2, &entry.second);
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &entry.second);
}
} else {
--buffer; // make sure the line is processed a second time
break;
}
@ -496,7 +505,9 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
const size_t oldm = meshes.size();
for (MatTable::const_iterator cit = needMat.begin(), cend = needMat.end();
cit != cend; ++cit, ++mat) {
if (!(*cit).first) continue;
if (!(*cit).first) {
continue;
}
// allocate a new aiMesh object
*pip++ = (unsigned int)meshes.size();
@ -541,7 +552,8 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
unsigned int type = (*it).flags & 0xf;
if (!type) {
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];
for (unsigned int i = 0; i < face.mNumIndices; ++i, ++vertices) {
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 ...
// 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) {
AI_AC_GET_STRING(mat.name);
AI_AC_SKIP_TO_NEXT_TOKEN();
buffer = AcGetString(buffer, mat.name);
buffer = AcSkipToNextToken(buffer);
}
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("rgb", 3, 3, &mat.rgb);
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("amb", 3, 3, &mat.amb);
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("emis", 4, 3, &mat.emis);
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("spec", 4, 3, &mat.spec);
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("shi", 3, 1, &mat.shin);
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("trans", 5, 1, &mat.trans);
buffer = TAcCheckedLoadFloatArray(buffer, "rgb", 3, 3, &mat.rgb);
buffer = TAcCheckedLoadFloatArray(buffer, "amb", 3, 3, &mat.amb);
buffer = TAcCheckedLoadFloatArray(buffer, "emis", 4, 3, &mat.emis);
buffer = TAcCheckedLoadFloatArray(buffer, "spec", 4, 3, &mat.spec);
buffer = TAcCheckedLoadFloatArray(buffer, "shi", 3, 1, &mat.shin);
buffer = TAcCheckedLoadFloatArray(buffer, "trans", 5, 1, &mat.trans);
}
LoadObjectSection(rootObjects);
}

View File

@ -68,8 +68,6 @@ public:
AC3DImporter();
~AC3DImporter();
// Represents an AC3D material
struct Material
{
@ -245,8 +243,6 @@ private:
aiMaterial& matDest);
private:
// points to the next data line
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()));
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,
// so we can extract the file extension from it.
@ -439,19 +439,19 @@ void BlenderImporter::ResolveImage(aiMaterial* out, const Material* mat, const M
--s;
}
tex->achFormatHint[0] = s+1>e ? '\0' : ::tolower( s[1] );
tex->achFormatHint[1] = s+2>e ? '\0' : ::tolower( s[2] );
tex->achFormatHint[2] = s+3>e ? '\0' : ::tolower( s[3] );
tex->achFormatHint[3] = '\0';
curTex->achFormatHint[0] = s + 1 > e ? '\0' : (char)::tolower(s[1]);
curTex->achFormatHint[1] = s + 2 > e ? '\0' : (char)::tolower(s[2]);
curTex->achFormatHint[2] = s + 3 > e ? '\0' : (char)::tolower(s[3]);
curTex->achFormatHint[3] = '\0';
// tex->mHeight = 0;
tex->mWidth = img->packedfile->size;
uint8_t* ch = new uint8_t[tex->mWidth];
curTex->mWidth = img->packedfile->size;
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->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));
} else {
@ -1078,9 +1078,9 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
const aiFace& f = out->mFaces[out->mNumFaces++];
aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
for (unsigned int i = 0; i < f.mNumIndices; ++i,++vo,++out->mNumVertices) {
vo->x = v->uv[i][0];
vo->y = v->uv[i][1];
for (unsigned int j = 0; j < f.mNumIndices; ++j,++vo,++out->mNumVertices) {
vo->x = v->uv[j][0];
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->y = uv.uv[1];
}
}
else {
} else {
// create textureCoords for every mapped tex
for (uint32_t m = 0; m < itMatTexUvMapping->second.size(); ++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++];
aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
for (unsigned int i = 0; i < f.mNumIndices; ++i,++vo,++out->mNumVertices) {
vo->x = v->uv[i][0];
vo->y = v->uv[i][1];
for (unsigned int j = 0; j < f.mNumIndices; ++j,++vo,++out->mNumVertices) {
vo->x = v->uv[j][0];
vo->y = v->uv[j][1];
}
}
}

View File

@ -57,52 +57,51 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp;
using namespace Assimp::Blender;
template <typename T> BlenderModifier* god() {
template <typename T>
BlenderModifier *god() {
return new T();
}
// add all available modifiers here
typedef BlenderModifier* (*fpCreateModifier)();
typedef BlenderModifier *(*fpCreateModifier)();
static const fpCreateModifier creators[] = {
&god<BlenderModifier_Mirror>,
&god<BlenderModifier_Subdivision>,
&god<BlenderModifier_Mirror>,
&god<BlenderModifier_Subdivision>,
NULL // sentinel
NULL // sentinel
};
// ------------------------------------------------------------------------------------------------
struct SharedModifierData : ElemBase
{
struct SharedModifierData : ElemBase {
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;
// 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
// invoking UB btw - we're assuming that the ModifierData member of the respective modifier
// structures is at offset sizeof(vftable) with no padding.
const SharedModifierData* cur = static_cast<const SharedModifierData *> ( orig_object.modifiers.first.get() );
for (; cur; cur = static_cast<const SharedModifierData *> ( cur->modifier.next.get() ), ++ful) {
const SharedModifierData *cur = static_cast<const SharedModifierData *>(orig_object.modifiers.first.get());
for (; cur; cur = static_cast<const SharedModifierData *>(cur->modifier.next.get()), ++ful) {
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) {
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;
}
// 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) {
ASSIMP_LOG_WARN("BlendModifier: expected a `modifier` member at offset 0");
continue;
}
s = conv_data.db.dna.Get( f->type );
s = conv_data.db.dna.Get(f->type);
if (!s || s->name != "ModifierData") {
ASSIMP_LOG_WARN("BlendModifier: expected a ModifierData structure as first member");
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
// ModifierData (with the above note).
const ModifierData& dat = cur->modifier;
const ModifierData &dat = cur->modifier;
const fpCreateModifier* curgod = creators;
std::vector< BlenderModifier* >::iterator curmod = cached_modifiers->begin(), endmod = cached_modifiers->end();
const fpCreateModifier *curgod = creators;
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) {
cached_modifiers->push_back((*curgod)());
endmod = cached_modifiers->end();
curmod = endmod-1;
curmod = endmod - 1;
}
BlenderModifier* const modifier = *curmod;
if(modifier->IsActive(dat)) {
modifier->DoIt(out,conv_data,*static_cast<const ElemBase *>(cur),in,orig_object);
BlenderModifier *const modifier = *curmod;
if (modifier->IsActive(dat)) {
modifier->DoIt(out, conv_data, *static_cast<const ElemBase *>(cur), in, orig_object);
cnt++;
curgod = NULL;
@ -133,7 +132,7 @@ void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_d
}
}
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
// able to fully do their job.
if (ful) {
ASSIMP_LOG_DEBUG_F("BlendModifier: found handlers for ",cnt," of ",ful," modifiers on `",orig_object.id.name,
"`, check log messages above for errors");
ASSIMP_LOG_DEBUG_F("BlendModifier: found handlers for ", cnt, " of ", ful, " modifiers on `", orig_object.id.name,
"`, 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;
}
// ------------------------------------------------------------------------------------------------
void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, const ElemBase& orig_modifier,
const Scene& /*in*/,
const Object& orig_object )
{
void BlenderModifier_Mirror ::DoIt(aiNode &out, ConversionData &conv_data, const ElemBase &orig_modifier,
const Scene & /*in*/,
const Object &orig_object) {
// 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);
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
for (unsigned int i = 0; i < out.mNumMeshes; ++i) {
aiMesh* mesh;
SceneCombiner::Copy(&mesh,conv_data.meshes[out.mMeshes[i]]);
aiMesh *mesh;
SceneCombiner::Copy(&mesh, conv_data.meshes[out.mMeshes[i]]);
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 zs = mir.flag & MirrorModifierData::Flags_AXIS_Z ? -1.f : 1.f;
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] );
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
aiVector3D& v = mesh->mVertices[i];
const aiVector3D center(mir.mirror_ob->obmat[3][0], mir.mirror_ob->obmat[3][1], mir.mirror_ob->obmat[3][2]);
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
aiVector3D &v = mesh->mVertices[j];
v.x = center.x + xs*(center.x - v.x);
v.y = center.y + ys*(center.y - v.y);
v.z = center.z + zs*(center.z - v.z);
v.x = center.x + xs * (center.x - v.x);
v.y = center.y + ys * (center.y - v.y);
v.z = center.z + zs * (center.z - v.z);
}
}
else {
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
aiVector3D& v = mesh->mVertices[i];
v.x *= xs;v.y *= ys;v.z *= zs;
} else {
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
aiVector3D &v = mesh->mVertices[j];
v.x *= xs;
v.y *= ys;
v.z *= zs;
}
}
if (mesh->mNormals) {
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
aiVector3D& v = mesh->mNormals[i];
v.x *= xs;v.y *= ys;v.z *= zs;
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
aiVector3D &v = mesh->mNormals[j];
v.x *= xs;
v.y *= ys;
v.z *= zs;
}
}
if (mesh->mTangents) {
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
aiVector3D& v = mesh->mTangents[i];
v.x *= xs;v.y *= ys;v.z *= zs;
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
aiVector3D &v = mesh->mTangents[j];
v.x *= xs;
v.y *= ys;
v.z *= zs;
}
}
if (mesh->mBitangents) {
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
aiVector3D& v = mesh->mBitangents[i];
v.x *= xs;v.y *= ys;v.z *= zs;
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
aiVector3D &v = mesh->mBitangents[j];
v.x *= xs;
v.y *= ys;
v.z *= zs;
}
}
@ -218,82 +220,80 @@ void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, co
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 i = 0; i < mesh->mNumVertices; ++i) {
aiVector3D& v = mesh->mTextureCoords[n][i];
v.x *= us;v.y *= vs;
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
aiVector3D &v = mesh->mTextureCoords[n][j];
v.x *= us;
v.y *= vs;
}
}
// Only reverse the winding order if an odd number of axes were mirrored.
if (xs * ys * zs < 0) {
for( unsigned int i = 0; i < mesh->mNumFaces; i++) {
aiFace& face = mesh->mFaces[i];
for( unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi)
std::swap( face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]);
for (unsigned int j = 0; j < mesh->mNumFaces; ++j ) {
aiFace &face = mesh->mFaces[j];
for (unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi)
std::swap(face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]);
}
}
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::transform(out.mMeshes,out.mMeshes+out.mNumMeshes,nind+out.mNumMeshes,
[&out](unsigned int n) { return out.mNumMeshes + n; });
std::copy(out.mMeshes, out.mMeshes + out.mNumMeshes, nind);
std::transform(out.mMeshes, out.mMeshes + out.mNumMeshes, nind + out.mNumMeshes,
[&out](unsigned int n) { return out.mNumMeshes + n; });
delete[] out.mMeshes;
out.mMeshes = nind;
out.mNumMeshes *= 2;
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;
}
// ------------------------------------------------------------------------------------------------
void BlenderModifier_Subdivision :: DoIt(aiNode& out, ConversionData& conv_data, const ElemBase& orig_modifier,
const Scene& /*in*/,
const Object& orig_object )
{
void BlenderModifier_Subdivision ::DoIt(aiNode &out, ConversionData &conv_data, const ElemBase &orig_modifier,
const Scene & /*in*/,
const Object &orig_object) {
// 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);
Subdivider::Algorithm algo;
switch (mir.subdivType)
{
case SubsurfModifierData::TYPE_CatmullClarke:
algo = Subdivider::CATMULL_CLARKE;
break;
switch (mir.subdivType) {
case SubsurfModifierData::TYPE_CatmullClarke:
algo = Subdivider::CATMULL_CLARKE;
break;
case SubsurfModifierData::TYPE_Simple:
ASSIMP_LOG_WARN("BlendModifier: The `SIMPLE` subdivision algorithm is not currently implemented, using Catmull-Clarke");
algo = Subdivider::CATMULL_CLARKE;
break;
case SubsurfModifierData::TYPE_Simple:
ASSIMP_LOG_WARN("BlendModifier: The `SIMPLE` subdivision algorithm is not currently implemented, using Catmull-Clarke");
algo = Subdivider::CATMULL_CLARKE;
break;
default:
ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ",mir.subdivType);
return;
default:
ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ", mir.subdivType);
return;
};
std::unique_ptr<Subdivider> subd(Subdivider::Create(algo));
ai_assert(subd);
if ( conv_data.meshes->empty() ) {
if (conv_data.meshes->empty()) {
return;
}
aiMesh** const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes];
std::unique_ptr<aiMesh*[]> tempmeshes(new aiMesh*[out.mNumMeshes]());
aiMesh **const meshes = &conv_data.meshes[conv_data.meshes->size() - 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);
std::copy(tempmeshes.get(),tempmeshes.get()+out.mNumMeshes,meshes);
subd->Subdivide(meshes, out.mNumMeshes, tempmeshes.get(), std::max(mir.renderLevels, mir.levels), true);
std::copy(tempmeshes.get(), tempmeshes.get() + out.mNumMeshes, meshes);
ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Subdivision` modifier to `",
orig_object.id.name,"`");
orig_object.id.name, "`");
}
#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
// hole?
bool hole;
if ((hole = (reader.GetI1() & 0x08) != 0)) {
bool hole = (reader.GetI1() & 0x08) != 0;
if ( hole ) {
// XXX Basically this should just work fine - then triangulator
// should output properly triangulated data even for polygons
// with holes. Test data specific to COB is needed to confirm it.

View File

@ -75,10 +75,10 @@ struct Face
// ------------------
/** COB chunk header information */
const unsigned int NO_SIZE = UINT_MAX;
struct ChunkInfo
{
enum {NO_SIZE=UINT_MAX};
ChunkInfo ()
: id (0)
, parent_id (0)

View File

@ -714,8 +714,8 @@ void ColladaParser::ReadAnimation(Collada::Animation* pParent)
else if (IsElement("sampler"))
{
// read the ID to assign the corresponding collada channel afterwards.
int indexID = GetAttribute("id");
std::string id = mReader->getAttributeValue(indexID);
int indexId = GetAttribute("id");
std::string id = mReader->getAttributeValue(indexId);
ChannelMap::iterator newChannel = channels.insert(std::make_pair(id, AnimationChannel())).first;
// 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
int ColladaParser::GetAttribute(const char* pAttr) const {
int index = TestAttribute(pAttr);
if (index != -1) {
return index;
if (index == -1) {
ThrowException(format() << "Expected attribute \"" << pAttr << "\" for element <" << mReader->getNodeName() << ">.");
}
// attribute not found -> throw an exception
ThrowException(format() << "Expected attribute \"" << pAttr << "\" for element <" << mReader->getNodeName() << ">.");
return -1;
return index;
}
// ------------------------------------------------------------------------------------------------

View File

@ -428,8 +428,8 @@ void Document::ReadPropertyTemplates()
const ElementCollection otypes = sdefs.GetCollection("ObjectType");
for(ElementMap::const_iterator it = otypes.first; it != otypes.second; ++it) {
const Element& el = *(*it).second;
const Scope* sc = el.Compound();
if(!sc) {
const Scope* curSc = el.Compound();
if (!curSc) {
DOMWarning("expected nested scope in ObjectType, ignoring",&el);
continue;
}
@ -442,24 +442,24 @@ void Document::ReadPropertyTemplates()
const std::string& oname = ParseTokenAsString(*tok[0]);
const ElementCollection templs = sc->GetCollection("PropertyTemplate");
for(ElementMap::const_iterator it = templs.first; it != templs.second; ++it) {
const Element& el = *(*it).second;
const Scope* sc = el.Compound();
if(!sc) {
const ElementCollection templs = curSc->GetCollection("PropertyTemplate");
for (ElementMap::const_iterator elemIt = templs.first; elemIt != templs.second; ++elemIt) {
const Element &innerEl = *(*elemIt).second;
const Scope *innerSc = innerEl.Compound();
if (!innerSc) {
DOMWarning("expected nested scope in PropertyTemplate, ignoring",&el);
continue;
}
const TokenList& tok = el.Tokens();
if(tok.empty()) {
const TokenList &curTok = innerEl.Tokens();
if (curTok.empty()) {
DOMWarning("expected name for PropertyTemplate element, ignoring",&el);
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) {
std::shared_ptr<const PropertyTable> props = std::make_shared<const PropertyTable>(
*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());
for(uint64_t id : animationStacks) {
LazyObject* const lazy = GetObject(id);
const AnimationStack* stack;
if(!lazy || !(stack = lazy->Get<AnimationStack>())) {
const AnimationStack *stack = lazy->Get<AnimationStack>();
if(!lazy || nullptr == stack ) {
DOMWarning("failed to read AnimationStack object");
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(neighbour.begin() + nbvsi, neighbour.begin() + nbvsi + nbvc);
for( size_t a = 0; a < nbvc - 1; ++a )
std::swap(neighbour[nbvsi + a], neighbour[nbvsi + a + 1]);
for (size_t aa = 0; aa < nbvc - 1; ++aa) {
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

View File

@ -50,12 +50,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/TinyFormatter.h>
#include <assimp/fast_atof.h>
#include <memory>
#include <functional>
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 = "")
@ -127,8 +126,8 @@ STEP::DB* STEP::ReadFileHeader(std::shared_ptr<IOStream> stream) {
if (list->GetSize() > 1) {
ASSIMP_LOG_WARN(AddLineNumber("multiple schemas currently not supported",line));
}
const EXPRESS::STRING* string( nullptr );
if (!list->GetSize() || !(string=dynamic_cast<const EXPRESS::STRING*>( (*list)[0].get() ))) {
const EXPRESS::STRING *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);
}
head.fileSchema = *string;
@ -539,7 +538,7 @@ void STEP::LazyObject::LazyInit() const {
}
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;
args = NULL;

File diff suppressed because it is too large Load Diff

View File

@ -76,9 +76,6 @@ public:
LWOImporter();
~LWOImporter();
public:
// -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details.
@ -86,7 +83,6 @@ public:
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
bool checkSig) const;
// -------------------------------------------------------------------
/** Called prior to ReadFile().
* The function is a request to the importer to update its configuration
@ -389,7 +385,7 @@ protected:
unsigned int fileSize;
/** Output scene */
aiScene* pScene;
aiScene* mScene;
/** Configuration option: speed flag set? */
bool configSpeedFlag;
@ -406,8 +402,8 @@ protected:
// ------------------------------------------------------------------------------------------------
inline float LWOImporter::GetF4()
{
inline
float LWOImporter::GetF4() {
float f;
::memcpy(&f, mFileBuffer, 4);
mFileBuffer += 4;

File diff suppressed because it is too large Load Diff

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
*/
#ifndef ASSIMP_BUILD_NO_LWS_IMPORTER
#include "LWS/LWSLoader.h"
#include "PostProcessing/ConvertToLHProcess.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/ParsingUtils.h>
#include <assimp/SceneCombiner.h>
#include <assimp/SkeletonMeshBuilder.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/scene.h>
#include <assimp/IOSystem.hpp>
#include <assimp/fast_atof.h>
#include <assimp/importerdesc.h>
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/IOSystem.hpp>
#include <memory>
@ -81,9 +80,8 @@ static const aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------
// Recursive parsing of LWS files
void LWS::Element::Parse (const char*& buffer)
{
for (;SkipSpacesAndLineEnd(&buffer);SkipLine(&buffer)) {
void LWS::Element::Parse(const char *&buffer) {
for (; SkipSpacesAndLineEnd(&buffer); SkipLine(&buffer)) {
// begin of a new element with children
bool sub = false;
@ -91,27 +89,26 @@ void LWS::Element::Parse (const char*& buffer)
++buffer;
SkipSpaces(&buffer);
sub = true;
}
else if (*buffer == '}')
} else if (*buffer == '}')
return;
children.push_back(Element());
// copy data line - read token per token
const char* cur = buffer;
while (!IsSpaceOrNewLine(*buffer)) ++buffer;
children.back().tokens[0] = std::string(cur,(size_t) (buffer-cur));
const char *cur = buffer;
while (!IsSpaceOrNewLine(*buffer))
++buffer;
children.back().tokens[0] = std::string(cur, (size_t)(buffer - cur));
SkipSpaces(&buffer);
if (children.back().tokens[0] == "Plugin")
{
if (children.back().tokens[0] == "Plugin") {
ASSIMP_LOG_DEBUG("LWS: Skipping over plugin-specific data");
// strange stuff inside Plugin/Endplugin blocks. Needn't
// follow LWS syntax, so we skip over it
for (;SkipSpacesAndLineEnd(&buffer);SkipLine(&buffer)) {
if (!::strncmp(buffer,"EndPlugin",9)) {
for (; SkipSpacesAndLineEnd(&buffer); SkipLine(&buffer)) {
if (!::strncmp(buffer, "EndPlugin", 9)) {
//SkipLine(&buffer);
break;
}
@ -120,8 +117,9 @@ void LWS::Element::Parse (const char*& buffer)
}
cur = buffer;
while (!IsLineEnd(*buffer)) ++buffer;
children.back().tokens[1] = std::string(cur,(size_t) (buffer-cur));
while (!IsLineEnd(*buffer))
++buffer;
children.back().tokens[1] = std::string(cur, (size_t)(buffer - cur));
// parse more elements recursively
if (sub)
@ -131,28 +129,25 @@ void LWS::Element::Parse (const char*& buffer)
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
LWSImporter::LWSImporter()
: configSpeedFlag(),
io(),
first(),
last(),
fps(),
noSkeletonMesh()
{
LWSImporter::LWSImporter() :
configSpeedFlag(),
io(),
first(),
last(),
fps(),
noSkeletonMesh() {
// nothing to do here
}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
LWSImporter::~LWSImporter()
{
LWSImporter::~LWSImporter() {
// nothing to do here
}
// ------------------------------------------------------------------------------------------------
// 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);
if (extension == "lws" || extension == "mot")
return true;
@ -162,69 +157,67 @@ bool LWSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler,bool c
uint32_t tokens[2];
tokens[0] = AI_MAKE_MAGIC("LWSC");
tokens[1] = AI_MAKE_MAGIC("LWMO");
return CheckMagicToken(pIOHandler,pFile,tokens,2);
return CheckMagicToken(pIOHandler, pFile, tokens, 2);
}
return false;
}
// ------------------------------------------------------------------------------------------------
// Get list of file extensions
const aiImporterDesc* LWSImporter::GetInfo () const
{
const aiImporterDesc *LWSImporter::GetInfo() const {
return &desc;
}
// ------------------------------------------------------------------------------------------------
// Setup configuration properties
void LWSImporter::SetupProperties(const Importer* pImp)
{
void LWSImporter::SetupProperties(const Importer *pImp) {
// 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
first = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWS_ANIM_START,
150392 /* magic hack */);
150392 /* magic hack */);
// AI_CONFIG_IMPORT_LWS_ANIM_END
last = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWS_ANIM_END,
150392 /* magic hack */);
150392 /* magic hack */);
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
void LWSImporter::ReadEnvelope(const LWS::Element& dad, LWO::Envelope& fill )
{
void LWSImporter::ReadEnvelope(const LWS::Element &dad, LWO::Envelope &fill) {
if (dad.children.empty()) {
ASSIMP_LOG_ERROR("LWS: Envelope descriptions must not be empty");
return;
}
// 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()));
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") {
fill.keys.push_back(LWO::Key());
LWO::Key& key = fill.keys.back();
LWO::Key &key = fill.keys.back();
float f;
SkipSpaces(&c);
c = fast_atoreal_move<float>(c,key.value);
c = fast_atoreal_move<float>(c, key.value);
SkipSpaces(&c);
c = fast_atoreal_move<float>(c,f);
c = fast_atoreal_move<float>(c, f);
key.time = f;
unsigned int span = strtoul10(c,&c), num = 0;
unsigned int span = strtoul10(c, &c), num = 0;
switch (span) {
case 0:
@ -251,16 +244,15 @@ void LWSImporter::ReadEnvelope(const LWS::Element& dad, LWO::Envelope& fill )
default:
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);
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);
fill.pre = (LWO::PrePostBehaviour) strtoul10(c,&c);
fill.pre = (LWO::PrePostBehaviour)strtoul10(c, &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
void LWSImporter::ReadEnvelope_Old(
std::list< LWS::Element >::const_iterator& it,
const std::list< LWS::Element >::const_iterator& end,
LWS::NodeDesc& nodes,
unsigned int /*version*/)
{
unsigned int num,sub_num;
if (++it == end)goto unexpected_end;
std::list<LWS::Element>::const_iterator &it,
const std::list<LWS::Element>::const_iterator &end,
LWS::NodeDesc &nodes,
unsigned int /*version*/) {
unsigned int num, sub_num;
if (++it == end) goto unexpected_end;
num = strtoul10((*it).tokens[0].c_str());
for (unsigned int i = 0; i < num; ++i) {
nodes.channels.push_back(LWO::Envelope());
LWO::Envelope& envl = nodes.channels.back();
LWO::Envelope &envl = nodes.channels.back();
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());
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.
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);
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;
envl.keys.push_back(key);
@ -311,51 +302,49 @@ unexpected_end:
// ------------------------------------------------------------------------------------------------
// 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;
// the name depends on the type. We break LWS's strange naming convention
// and return human-readable, but still machine-parsable and unique, strings.
if (src.type == LWS::NodeDesc::OBJECT) {
if (src.type == LWS::NodeDesc::OBJECT) {
if (src.path.length()) {
std::string::size_type s = src.path.find_last_of("\\/");
if (s == std::string::npos)
s = 0;
else ++s;
else
++s;
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;
}
}
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
void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<AttachmentInfo>& attach,
BatchLoader& batch,
aiCamera**& camOut,
aiLight**& lightOut,
std::vector<aiNodeAnim*>& animOut)
{
void LWSImporter::BuildGraph(aiNode *nd, LWS::NodeDesc &src, std::vector<AttachmentInfo> &attach,
BatchLoader &batch,
aiCamera **&camOut,
aiLight **&lightOut,
std::vector<aiNodeAnim *> &animOut) {
// Setup a very cryptic name for the node, we want the user to be happy
SetupNodeName(nd,src);
aiNode* ndAnim = nd;
SetupNodeName(nd, src);
aiNode *ndAnim = nd;
// If the node is an object
if (src.type == LWS::NodeDesc::OBJECT) {
// If the object is from an external file, get it
aiScene* obj = NULL;
if (src.path.length() ) {
aiScene *obj = NULL;
if (src.path.length()) {
obj = batch.GetImport(src.id);
if (!obj) {
ASSIMP_LOG_ERROR("LWS: Failed to read external file " + src.path);
}
else {
} else {
if (obj->mRootNode->mNumChildren == 1) {
//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)
aiNode* newRootNode = obj->mRootNode->mChildren[0];
aiNode *newRootNode = obj->mRootNode->mChildren[0];
obj->mRootNode->mChildren[0] = NULL;
delete obj->mRootNode;
@ -384,7 +373,7 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<Attachm
//Add the attachment node to it
nd->mNumChildren = 1;
nd->mChildren = new aiNode*[1];
nd->mChildren = new aiNode *[1];
nd->mChildren[0] = new aiNode();
nd->mChildren[0]->mParent = nd;
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
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
else if (src.type == LWS::NodeDesc::LIGHT) {
aiLight* lit = *lightOut++ = new aiLight();
aiLight *lit = *lightOut++ = new aiLight();
// 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
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 */
lit->mType = aiLightSource_SPOT;
lit->mAngleInnerCone = (float)AI_DEG_TO_RAD( src.lightConeAngle );
lit->mAngleOuterCone = lit->mAngleInnerCone+(float)AI_DEG_TO_RAD( src.lightEdgeAngle );
lit->mAngleInnerCone = (float)AI_DEG_TO_RAD(src.lightConeAngle);
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;
}
else lit->mType = aiLightSource_POINT;
} else
lit->mType = aiLightSource_POINT;
// fixme: no proper handling of light falloffs yet
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
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
cam->mName = nd->mName;
}
// Get the node transformation from the LWO key
LWO::AnimResolver resolver(src.channels,fps);
LWO::AnimResolver resolver(src.channels, fps);
resolver.ExtractBindPose(ndAnim->mTransformation);
// .. and construct animation channels
aiNodeAnim* anim = NULL;
aiNodeAnim *anim = NULL;
if (first != last) {
resolver.SetAnimationRange(first,last);
resolver.ExtractAnimChannel(&anim,AI_LWO_ANIM_FLAG_SAMPLE_ANIMS|AI_LWO_ANIM_FLAG_START_AT_ZERO);
resolver.SetAnimationRange(first, last);
resolver.ExtractAnimChannel(&anim, AI_LWO_ANIM_FLAG_SAMPLE_ANIMS | AI_LWO_ANIM_FLAG_START_AT_ZERO);
if (anim) {
anim->mNodeName = ndAnim->mName;
animOut.push_back(anim);
@ -459,27 +447,25 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<Attachm
// Add children
if (!src.children.empty()) {
nd->mChildren = new aiNode*[src.children.size()];
for (std::list<LWS::NodeDesc*>::iterator it = src.children.begin(); it != src.children.end(); ++it) {
aiNode* ndd = nd->mChildren[nd->mNumChildren++] = new aiNode();
nd->mChildren = new aiNode *[src.children.size()];
for (std::list<LWS::NodeDesc *>::iterator it = src.children.begin(); it != src.children.end(); ++it) {
aiNode *ndd = nd->mChildren[nd->mNumChildren++] = new aiNode();
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
std::string LWSImporter::FindLWOFile(const std::string& in)
{
std::string LWSImporter::FindLWOFile(const std::string &in) {
// insert missing directory separator if necessary
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));
}
else tmp = in;
} else
tmp = in;
if (io->Exists(tmp)) {
return in;
@ -503,35 +489,34 @@ std::string LWSImporter::FindLWOFile(const std::string& in)
return test;
}
// return original path, maybe the IOsystem knows better
return tmp;
}
// ------------------------------------------------------------------------------------------------
// Read file into given scene data structure
void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
IOSystem* pIOHandler)
{
void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene,
IOSystem *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
if( file.get() == NULL) {
throw DeadlyImportError( "Failed to open LWS file " + pFile + ".");
if (file.get() == NULL) {
throw DeadlyImportError("Failed to open LWS file " + pFile + ".");
}
// Allocate storage and copy the contents of the file to a memory buffer
std::vector< char > mBuffer;
TextFileToBuffer(file.get(),mBuffer);
std::vector<char> mBuffer;
TextFileToBuffer(file.get(), mBuffer);
// Parse the file structure
LWS::Element root; const char* dummy = &mBuffer[0];
LWS::Element root;
const char *dummy = &mBuffer[0];
root.Parse(dummy);
// Construct a Batchimporter to read more files recursively
BatchLoader batch(pIOHandler);
// batch.SetBasePath(pFile);
// batch.SetBasePath(pFile);
// Construct an array to receive the flat output graph
std::list<LWS::NodeDesc> nodes;
@ -541,7 +526,7 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
// check magic identifier, 'LWSC'
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")
motion_file = true;
@ -554,54 +539,54 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
unsigned int version = strtoul10((*it).tokens[0].c_str());
ASSIMP_LOG_INFO("LWS file format version is " + (*it).tokens[0]);
first = 0.;
last = 60.;
fps = 25.; /* seems to be a good default frame rate */
last = 60.;
fps = 25.; /* seems to be a good default frame rate */
// Now read all elements in a very straghtforward manner
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
if ((*it).tokens[0] == "FirstFrame") {
if (150392. != first /* see SetupProperties() */)
first = strtoul10(c,&c)-1.; /* we're zero-based */
if (150392. != first /* see SetupProperties() */)
first = strtoul10(c, &c) - 1.; /* we're zero-based */
}
// 'LastFrame': end of animation slice
else if ((*it).tokens[0] == "LastFrame") {
if (150392. != last /* see SetupProperties() */)
last = strtoul10(c,&c)-1.; /* we're zero-based */
if (150392. != last /* see SetupProperties() */)
last = strtoul10(c, &c) - 1.; /* we're zero-based */
}
// 'FramesPerSecond': frames per second
else if ((*it).tokens[0] == "FramesPerSecond") {
fps = strtoul10(c,&c);
fps = strtoul10(c, &c);
}
// 'LoadObjectLayer': load a layer of a specific LWO file
else if ((*it).tokens[0] == "LoadObjectLayer") {
// get layer index
const int layer = strtoul10(c,&c);
const int layer = strtoul10(c, &c);
// setup the layer to be loaded
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
LWS::NodeDesc d;
d.type = LWS::NodeDesc::OBJECT;
if (version >= 4) { // handle LWSC 4 explicit ID
SkipSpaces(&c);
d.number = strtoul16(c,&c) & AI_LWS_MASK;
}
else d.number = cur_object++;
d.number = strtoul16(c, &c) & AI_LWS_MASK;
} else
d.number = cur_object++;
// and add the file to the import list
SkipSpaces(&c);
std::string path = FindLWOFile( c );
std::string path = FindLWOFile(c);
d.path = path;
d.id = batch.AddLoadRequest(path,0,&props);
d.id = batch.AddLoadRequest(path, 0, &props);
nodes.push_back(d);
num_object++;
@ -614,12 +599,12 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
d.type = LWS::NodeDesc::OBJECT;
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);
}
else d.number = cur_object++;
std::string path = FindLWOFile( c );
d.id = batch.AddLoadRequest(path,0,NULL);
} else
d.number = cur_object++;
std::string path = FindLWOFile(c);
d.id = batch.AddLoadRequest(path, 0, NULL);
d.path = path;
nodes.push_back(d);
@ -632,10 +617,10 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
LWS::NodeDesc d;
d.type = LWS::NodeDesc::OBJECT;
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);
}
else d.number = cur_object++;
} else
d.number = cur_object++;
d.name = c;
nodes.push_back(d);
@ -662,13 +647,13 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
// important: index of channel
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);
// currently we can just interpret the standard channels 0...9
// (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
@ -676,18 +661,18 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
if (nodes.empty() || nodes.back().channels.empty())
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'Envelope\'");
else {
ReadEnvelope((*it),nodes.back().channels.back());
ReadEnvelope((*it), nodes.back().channels.back());
}
}
// 'ObjectMotion': animation information for older lightwave formats
else if (version < 3 && ((*it).tokens[0] == "ObjectMotion" ||
(*it).tokens[0] == "CameraMotion" ||
(*it).tokens[0] == "LightMotion")) {
else if (version < 3 && ((*it).tokens[0] == "ObjectMotion" ||
(*it).tokens[0] == "CameraMotion" ||
(*it).tokens[0] == "LightMotion")) {
if (nodes.empty())
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'<Light|Object|Camera>Motion\'");
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
@ -695,11 +680,13 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
if (nodes.empty())
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'Pre/PostBehavior'");
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
LWO::Envelope& env = *it;
env.pre = (LWO::PrePostBehaviour) strtoul10(c,&c); SkipSpaces(&c);
env.post = (LWO::PrePostBehaviour) strtoul10(c,&c); SkipSpaces(&c);
LWO::Envelope &env = *envelopeIt;
env.pre = (LWO::PrePostBehaviour)strtoul10(c, &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())
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
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\'");
else {
nodes.back().parent = strtoul10(c,&c) | (1u << 28u);
nodes.back().parent = strtoul10(c, &c) | (1u << 28u);
}
}
// '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;
if (version >= 4) { // handle LWSC 4 explicit ID
d.number = strtoul16(c,&c) & AI_LWS_MASK;
}
else d.number = cur_camera++;
d.number = strtoul16(c, &c) & AI_LWS_MASK;
} else
d.number = cur_camera++;
nodes.push_back(d);
num_camera++;
@ -739,7 +727,8 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::CAMERA)
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'CameraName\'");
else nodes.back().name = c;
else
nodes.back().name = c;
}
// 'AddLight': add a light to the scenegraph
else if ((*it).tokens[0] == "AddLight") {
@ -749,9 +738,9 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
d.type = LWS::NodeDesc::LIGHT;
if (version >= 4) { // handle LWSC 4 explicit ID
d.number = strtoul16(c,&c) & AI_LWS_MASK;
}
else d.number = cur_light++;
d.number = strtoul16(c, &c) & AI_LWS_MASK;
} else
d.number = cur_light++;
nodes.push_back(d);
num_light++;
@ -761,14 +750,16 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightName\'");
else nodes.back().name = c;
else
nodes.back().name = c;
}
// '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)
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
@ -776,7 +767,8 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
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
@ -784,7 +776,8 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
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
@ -792,7 +785,8 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
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
@ -800,7 +794,8 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
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
@ -809,11 +804,11 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightColor\'");
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);
c = fast_atoreal_move<float>(c, (float&) nodes.back().lightColor.g );
c = fast_atoreal_move<float>(c, (float &)nodes.back().lightColor.g);
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())
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'PivotPosition\'");
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);
c = fast_atoreal_move<float>(c, (float&) nodes.back().pivotPos.y );
c = fast_atoreal_move<float>(c, (float &)nodes.back().pivotPos.y);
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
nodes.back().isPivotSet = true;
}
@ -834,79 +829,80 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
}
// 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
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) {
// fixme: it's still possible to produce an overflow due to cross references ..
ASSIMP_LOG_ERROR("LWS: Found cross reference in scene-graph");
continue;
}
(*it).children.push_back(&*dit);
(*dit).parent_resolved = &*it;
ndIt->children.push_back(&*dit);
(*dit).parent_resolved = &*ndIt;
}
}
}
// find out how many nodes have no parent yet
unsigned int no_parent = 0;
for (std::list<LWS::NodeDesc>::iterator it = nodes.begin(); it != nodes.end(); ++it) {
if (!(*it).parent_resolved)
++ no_parent;
for (std::list<LWS::NodeDesc>::iterator ndIt = nodes.begin(); ndIt != nodes.end(); ++ndIt) {
if (!ndIt->parent_resolved) {
++no_parent;
}
}
if (!no_parent)
if (!no_parent) {
throw DeadlyImportError("LWS: Unable to find scene root node");
}
// Load all subsequent files
batch.LoadAll();
// and build the final output graph by attaching the loaded external
// files to ourselves. first build a master graph
aiScene* master = new aiScene();
aiNode* nd = master->mRootNode = new aiNode();
aiScene *master = new aiScene();
aiNode *nd = master->mRootNode = new aiNode();
// allocate storage for cameras&lights
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) {
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<aiNodeAnim*> anims;
std::vector<aiNodeAnim *> anims;
nd->mName.Set("<LWSRoot>");
nd->mChildren = new aiNode*[no_parent];
for (std::list<LWS::NodeDesc>::iterator it = nodes.begin(); it != nodes.end(); ++it) {
if (!(*it).parent_resolved) {
aiNode* ro = nd->mChildren[ nd->mNumChildren++ ] = new aiNode();
nd->mChildren = new aiNode *[no_parent];
for (std::list<LWS::NodeDesc>::iterator ndIt = nodes.begin(); ndIt != nodes.end(); ++ndIt) {
if (!ndIt->parent_resolved) {
aiNode *ro = nd->mChildren[nd->mNumChildren++] = new aiNode();
ro->mParent = nd;
// ... and build the scene graph. If we encounter object nodes,
// 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
if (anims.size()) {
master->mAnimations = new aiAnimation*[master->mNumAnimations = 1];
aiAnimation* anim = master->mAnimations[0] = new aiAnimation();
master->mAnimations = new aiAnimation *[master->mNumAnimations = 1];
aiAnimation *anim = master->mAnimations[0] = new aiAnimation();
anim->mName.Set("LWSMasterAnim");
// LWS uses seconds as time units, but we convert to frames
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())];
std::copy(anims.begin(),anims.end(),anim->mChannels);
anim->mChannels = new aiNodeAnim *[anim->mNumChannels = static_cast<unsigned int>(anims.size())];
std::copy(anims.begin(), anims.end(), anim->mChannels);
}
// convert the master scene to RH
@ -918,9 +914,10 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
flipper.Execute(master);
// OK ... finally build the output graph
SceneCombiner::MergeScenes(&pScene,master,attach,
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));
SceneCombiner::MergeScenes(&pScene, master, attach,
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));
// Check flags
if (!pScene->mNumMeshes || !pScene->mNumMaterials) {
@ -931,7 +928,6 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
SkeletonMeshBuilder builder(pScene);
}
}
}
#endif // !! ASSIMP_BUILD_NO_LWS_IMPORTER

File diff suppressed because it is too large Load Diff

View File

@ -100,6 +100,10 @@ M3DWrapper::M3DWrapper() {
}
M3DWrapper::M3DWrapper(IOSystem *pIOHandler, const std::vector<unsigned char> &buffer) {
if (nullptr == pIOHandler) {
ai_assert(nullptr != pIOHandler);
}
#ifdef ASSIMP_USE_M3D_READFILECB
// pass this IOHandler to the C callback in a thread-local pointer
m3dimporter_pIOHandler = pIOHandler;

View File

@ -99,6 +99,10 @@ typedef uint16_t M3D_INDEX;
#define _register
#endif
#pragma warning(push)
#pragma warning(disable : 4127 )
#pragma warning(disable : 4505 )
/*** 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;
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].w = w;
model->texture[i].h = h;
model->texture[i].w = (uint16_t) w;
model->texture[i].h = (uint16_t) h;
model->texture[i].f = (uint8_t)len;
#endif
} else {
@ -5605,6 +5609,9 @@ namespace M3D {
#endif /* impl */
}
#pragma warning(pop<)
#endif
#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
*/
#ifndef ASSIMP_BUILD_NO_MD5_IMPORTER
// internal headers
#include <assimp/RemoveComments.h>
#include "MD5Loader.h"
#include <assimp/MathFunctions.h>
#include <assimp/RemoveComments.h>
#include <assimp/SkeletonMeshBuilder.h>
#include <assimp/StringComparison.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/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/IOSystem.hpp>
#include <assimp/Importer.hpp>
#include <memory>
using namespace Assimp;
@ -67,7 +66,6 @@ using namespace Assimp;
// Minimum weight value. Weights inside [-n ... n] are ignored
#define AI_MD5_WEIGHT_EPSILON Math::getEpsilon<float>()
static const aiImporterDesc desc = {
"Doom 3 / MD5 Mesh Importer",
"",
@ -83,93 +81,78 @@ static const aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
MD5Importer::MD5Importer()
: mIOHandler()
, mBuffer()
, fileSize()
, iLineNumber()
, pScene()
, pIOHandler()
, bHadMD5Mesh()
, bHadMD5Anim()
, bHadMD5Camera()
, configNoAutoLoad (false)
{}
MD5Importer::MD5Importer() :
mIOHandler(nullptr), mBuffer(), fileSize(), iLineNumber(), pScene(), bHadMD5Mesh(), bHadMD5Anim(), bHadMD5Camera(), configNoAutoLoad(false) {
// empty
}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
MD5Importer::~MD5Importer()
{}
MD5Importer::~MD5Importer() {
// empty
}
// ------------------------------------------------------------------------------------------------
// 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);
if (extension == "md5anim" || extension == "md5mesh" || extension == "md5camera")
return true;
else if (!extension.length() || checkSig) {
else if (!extension.length() || checkSig) {
if (!pIOHandler) {
return true;
}
const char* tokens[] = {"MD5Version"};
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
const char *tokens[] = { "MD5Version" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
}
return false;
}
// ------------------------------------------------------------------------------------------------
// Get list of all supported extensions
const aiImporterDesc* MD5Importer::GetInfo () const
{
const aiImporterDesc *MD5Importer::GetInfo() const {
return &desc;
}
// ------------------------------------------------------------------------------------------------
// Setup import properties
void MD5Importer::SetupProperties(const Importer* pImp)
{
void MD5Importer::SetupProperties(const Importer *pImp) {
// 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.
void MD5Importer::InternReadFile( const std::string& pFile,
aiScene* _pScene, IOSystem* _pIOHandler)
{
pIOHandler = _pIOHandler;
pScene = _pScene;
void MD5Importer::InternReadFile(const std::string &pFile,
aiScene *_pScene, IOSystem *pIOHandler) {
mIOHandler = pIOHandler;
pScene = _pScene;
bHadMD5Mesh = bHadMD5Anim = bHadMD5Camera = false;
// remove the file extension
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);
try {
if (extension == "md5camera") {
LoadMD5CameraFile();
}
else if (configNoAutoLoad || extension == "md5anim") {
} else if (configNoAutoLoad || extension == "md5anim") {
// determine file extension and process just *one* file
if (extension.length() == 0) {
throw DeadlyImportError("Failure, need file extension to determine MD5 part type");
}
if (extension == "md5anim") {
LoadMD5AnimFile();
}
else if (extension == "md5mesh") {
} else if (extension == "md5mesh") {
LoadMD5MeshFile();
}
}
else {
} else {
LoadMD5MeshFile();
LoadMD5AnimFile();
}
}
catch ( ... ) { // std::exception, Assimp::DeadlyImportError
} catch (...) { // std::exception, Assimp::DeadlyImportError
UnloadFileFromMemory();
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
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);
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);
// the output scene wouldn't pass the validation without this flag
if (!bHadMD5Mesh) {
@ -194,8 +177,7 @@ void MD5Importer::InternReadFile( const std::string& pFile,
// ------------------------------------------------------------------------------------------------
// Load a file into a memory buffer
void MD5Importer::LoadFileIntoMemory (IOStream* file)
{
void MD5Importer::LoadFileIntoMemory(IOStream *file) {
// unload the previous buffer, if any
UnloadFileFromMemory();
@ -204,21 +186,20 @@ void MD5Importer::LoadFileIntoMemory (IOStream* file)
ai_assert(fileSize);
// allocate storage and copy the contents of the file to a memory buffer
mBuffer = new char[fileSize+1];
file->Read( (void*)mBuffer, 1, fileSize);
mBuffer = new char[fileSize + 1];
file->Read((void *)mBuffer, 1, fileSize);
iLineNumber = 1;
// append a terminal 0
mBuffer[fileSize] = '\0';
// now remove all line comments from the file
CommentRemover::RemoveLineComments("//",mBuffer,' ');
CommentRemover::RemoveLineComments("//", mBuffer, ' ');
}
// ------------------------------------------------------------------------------------------------
// Unload the current memory buffer
void MD5Importer::UnloadFileFromMemory ()
{
void MD5Importer::UnloadFileFromMemory() {
// delete the file buffer
delete[] mBuffer;
mBuffer = NULL;
@ -227,57 +208,55 @@ void MD5Importer::UnloadFileFromMemory ()
// ------------------------------------------------------------------------------------------------
// Build unique vertices
void MD5Importer::MakeDataUnique (MD5::MeshDesc& meshSrc)
{
std::vector<bool> abHad(meshSrc.mVertices.size(),false);
void MD5Importer::MakeDataUnique(MD5::MeshDesc &meshSrc) {
std::vector<bool> abHad(meshSrc.mVertices.size(), false);
// 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());
meshSrc.mVertices.resize(iNewNum);
// try to guess how much storage we'll need for new weights
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
for (FaceList::const_iterator iter = meshSrc.mFaces.begin(),iterEnd = meshSrc.mFaces.end();iter != iterEnd;++iter){
const aiFace& face = *iter;
for (unsigned int i = 0; i < 3;++i) {
for (FaceList::const_iterator iter = meshSrc.mFaces.begin(), iterEnd = meshSrc.mFaces.end(); iter != iterEnd; ++iter) {
const aiFace &face = *iter;
for (unsigned int i = 0; i < 3; ++i) {
if (face.mIndices[0] >= meshSrc.mVertices.size()) {
throw DeadlyImportError("MD5MESH: Invalid vertex index");
}
if (abHad[face.mIndices[i]]) {
if (abHad[face.mIndices[i]]) {
// generate a new vertex
meshSrc.mVertices[iNewIndex] = meshSrc.mVertices[face.mIndices[i]];
face.mIndices[i] = iNewIndex++;
}
else abHad[face.mIndices[i]] = true;
} else
abHad[face.mIndices[i]] = true;
}
// 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
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);
// First find out how many children we'll have
for (int i = 0; i < (int)bones.size();++i) {
if (iParentID != i && bones[i].mParentIndex == iParentID) {
for (int i = 0; i < (int)bones.size(); ++i) {
if (iParentID != i && bones[i].mParentIndex == iParentID) {
++piParent->mNumChildren;
}
}
if (piParent->mNumChildren) {
piParent->mChildren = new aiNode*[piParent->mNumChildren];
for (int i = 0; i < (int)bones.size();++i) {
piParent->mChildren = new aiNode *[piParent->mNumChildren];
for (int i = 0; i < (int)bones.size(); ++i) {
// (avoid infinite recursion)
if (iParentID != i && bones[i].mParentIndex == iParentID) {
aiNode* pc;
if (iParentID != i && bones[i].mParentIndex == iParentID) {
aiNode *pc;
// setup a new node
*piParent->mChildren++ = pc = new aiNode();
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
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.b4 = bones[i].mPositionXYZ.y;
bones[i].mTransform.c4 = bones[i].mPositionXYZ.z;
@ -298,12 +277,12 @@ void MD5Importer::AttachChilds_Mesh(int iParentID,aiNode* piParent, BoneList& bo
// the transformations for each bone are absolute, so we need to multiply them
// with the inverse of the absolute matrix of the parent joint
if (-1 != iParentID) {
if (-1 != iParentID) {
pc->mTransformation = bones[iParentID].mInvTransform * pc->mTransformation;
}
// add children to this node, too
AttachChilds_Mesh( i, pc, bones);
AttachChilds_Mesh(i, pc, bones);
}
}
// undo offset computations
@ -313,37 +292,36 @@ void MD5Importer::AttachChilds_Mesh(int iParentID,aiNode* piParent, BoneList& bo
// ------------------------------------------------------------------------------------------------
// 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);
// First find out how many children we'll have
for (int i = 0; i < (int)bones.size();++i) {
if (iParentID != i && bones[i].mParentIndex == iParentID) {
for (int i = 0; i < (int)bones.size(); ++i) {
if (iParentID != i && bones[i].mParentIndex == iParentID) {
++piParent->mNumChildren;
}
}
if (piParent->mNumChildren) {
piParent->mChildren = new aiNode*[piParent->mNumChildren];
for (int i = 0; i < (int)bones.size();++i) {
piParent->mChildren = new aiNode *[piParent->mNumChildren];
for (int i = 0; i < (int)bones.size(); ++i) {
// (avoid infinite recursion)
if (iParentID != i && bones[i].mParentIndex == iParentID)
{
aiNode* pc;
if (iParentID != i && bones[i].mParentIndex == iParentID) {
aiNode *pc;
// setup a new node
*piParent->mChildren++ = pc = new aiNode();
pc->mName = aiString(bones[i].mName);
pc->mParent = piParent;
// get the corresponding animation channel and its first frame
const aiNodeAnim** cur = node_anims;
while ((**cur).mNodeName != pc->mName)++cur;
const aiNodeAnim **cur = node_anims;
while ((**cur).mNodeName != pc->mName)
++cur;
aiMatrix4x4::Translation((**cur).mPositionKeys[0].mValue,pc->mTransformation);
pc->mTransformation = pc->mTransformation * aiMatrix4x4((**cur).mRotationKeys[0].mValue.GetMatrix()) ;
aiMatrix4x4::Translation((**cur).mPositionKeys[0].mValue, pc->mTransformation);
pc->mTransformation = pc->mTransformation * aiMatrix4x4((**cur).mRotationKeys[0].mValue.GetMatrix());
// add children to this node, too
AttachChilds_Anim( i, pc, bones,node_anims);
AttachChilds_Anim(i, pc, bones, node_anims);
}
}
// undo offset computations
@ -353,13 +331,12 @@ void MD5Importer::AttachChilds_Anim(int iParentID,aiNode* piParent, AnimBoneList
// ------------------------------------------------------------------------------------------------
// Load a MD5MESH file
void MD5Importer::LoadMD5MeshFile ()
{
void MD5Importer::LoadMD5MeshFile() {
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
if( file.get() == NULL || !file->FileSize()) {
if (file.get() == nullptr || !file->FileSize()) {
ASSIMP_LOG_WARN("Failed to access MD5MESH file: " + pFile);
return;
}
@ -367,7 +344,7 @@ void MD5Importer::LoadMD5MeshFile ()
LoadFileIntoMemory(file.get());
// now construct a parser and parse the file
MD5::MD5Parser parser(mBuffer,fileSize);
MD5::MD5Parser parser(mBuffer, fileSize);
// load the mesh information from it
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
pScene->mRootNode = new aiNode("<MD5_Root>");
pScene->mRootNode->mNumChildren = 2;
pScene->mRootNode->mChildren = new aiNode*[2];
pScene->mRootNode->mChildren = new aiNode *[2];
// 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->mParent = pScene->mRootNode;
AttachChilds_Mesh(-1,pcNode,meshParser.mJoints);
AttachChilds_Mesh(-1, pcNode, meshParser.mJoints);
pcNode = pScene->mRootNode->mChildren[0] = new aiNode();
pcNode->mName.Set("<MD5_Mesh>");
@ -393,96 +370,94 @@ void MD5Importer::LoadMD5MeshFile ()
#else
// 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())
++pScene->mNumMaterials;
}
// generate all meshes
pScene->mNumMeshes = pScene->mNumMaterials;
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
pScene->mMaterials = new aiMaterial*[pScene->mNumMeshes];
pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
pScene->mMaterials = new aiMaterial *[pScene->mNumMeshes];
// storage for node mesh indices
pcNode->mNumMeshes = pScene->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;
unsigned int n = 0;
for (std::vector<MD5::MeshDesc>::iterator it = meshParser.mMeshes.begin(),end = meshParser.mMeshes.end(); it != end;++it) {
MD5::MeshDesc& meshSrc = *it;
for (std::vector<MD5::MeshDesc>::iterator it = meshParser.mMeshes.begin(), end = meshParser.mMeshes.end(); it != end; ++it) {
MD5::MeshDesc &meshSrc = *it;
if (meshSrc.mFaces.empty() || meshSrc.mVertices.empty())
continue;
aiMesh* mesh = pScene->mMeshes[n] = new aiMesh();
aiMesh *mesh = pScene->mMeshes[n] = new aiMesh();
mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
// generate unique vertices in our internal verbose format
MakeDataUnique(meshSrc);
std::string name( meshSrc.mShader.C_Str() );
std::string name(meshSrc.mShader.C_Str());
name += ".msh";
mesh->mName = name;
mesh->mNumVertices = (unsigned int) meshSrc.mVertices.size();
mesh->mNumVertices = (unsigned int)meshSrc.mVertices.size();
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
mesh->mNumUVComponents[0] = 2;
// copy texture coordinates
aiVector3D* pv = mesh->mTextureCoords[0];
for (MD5::VertexList::const_iterator iter = meshSrc.mVertices.begin();iter != meshSrc.mVertices.end();++iter,++pv) {
aiVector3D *pv = mesh->mTextureCoords[0];
for (MD5::VertexList::const_iterator iter = meshSrc.mVertices.begin(); iter != meshSrc.mVertices.end(); ++iter, ++pv) {
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;
}
// sort all bone weights - per bone
unsigned int* piCount = new unsigned int[meshParser.mJoints.size()];
::memset(piCount,0,sizeof(unsigned int)*meshParser.mJoints.size());
unsigned int *piCount = new 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 (unsigned int jub = (*iter).mFirstWeight, w = jub; w < jub + (*iter).mNumWeights;++w)
{
MD5::WeightDesc& weightDesc = meshSrc.mWeights[w];
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) {
MD5::WeightDesc &weightDesc = meshSrc.mWeights[w];
/* 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];
}
}
// check how many we will need
for (unsigned int p = 0; p < meshParser.mJoints.size();++p)
if (piCount[p])mesh->mNumBones++;
for (unsigned int p = 0; p < meshParser.mJoints.size(); ++p)
if (piCount[p]) mesh->mNumBones++;
if (mesh->mNumBones) // just for safety
{
mesh->mBones = new aiBone*[mesh->mNumBones];
for (unsigned int q = 0,h = 0; q < meshParser.mJoints.size();++q)
{
if (!piCount[q])continue;
aiBone* p = mesh->mBones[h] = new aiBone();
mesh->mBones = new aiBone *[mesh->mNumBones];
for (unsigned int q = 0, h = 0; q < meshParser.mJoints.size(); ++q) {
if (!piCount[q]) continue;
aiBone *p = mesh->mBones[h] = new aiBone();
p->mNumWeights = piCount[q];
p->mWeights = new aiVertexWeight[p->mNumWeights];
p->mName = aiString(meshParser.mJoints[q].mName);
p->mOffsetMatrix = meshParser.mJoints[q].mInvTransform;
// store the index for later use
MD5::BoneDesc& boneSrc = meshParser.mJoints[q];
MD5::BoneDesc &boneSrc = meshParser.mJoints[q];
boneSrc.mMap = h++;
// compute w-component of quaternion
MD5::ConvertQuaternion( boneSrc.mRotationQuat, boneSrc.mRotationQuatConverted );
MD5::ConvertQuaternion(boneSrc.mRotationQuat, boneSrc.mRotationQuatConverted);
}
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
*pv = aiVector3D();
// there are models which have weights which don't sum to 1 ...
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;
if (!fSum) {
ASSIMP_LOG_ERROR("MD5MESH: The sum of all vertex bone weights is 0");
@ -490,32 +465,32 @@ void MD5Importer::LoadMD5MeshFile ()
}
// 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())
throw DeadlyImportError("MD5MESH: Invalid weight index");
MD5::WeightDesc& weightDesc = meshSrc.mWeights[w];
if ( weightDesc.mWeight < AI_MD5_WEIGHT_EPSILON && weightDesc.mWeight >= -AI_MD5_WEIGHT_EPSILON) {
MD5::WeightDesc &weightDesc = meshSrc.mWeights[w];
if (weightDesc.mWeight < AI_MD5_WEIGHT_EPSILON && weightDesc.mWeight >= -AI_MD5_WEIGHT_EPSILON) {
continue;
}
const ai_real fNewWeight = weightDesc.mWeight / fSum;
// transform the local position into worldspace
MD5::BoneDesc& boneSrc = meshParser.mJoints[weightDesc.mBone];
const aiVector3D v = boneSrc.mRotationQuatConverted.Rotate (weightDesc.vOffsetPosition);
MD5::BoneDesc &boneSrc = meshParser.mJoints[weightDesc.mBone];
const aiVector3D v = boneSrc.mRotationQuatConverted.Rotate(weightDesc.vOffsetPosition);
// use the original weight to compute the vertex position
// (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];
*bone->mWeights++ = aiVertexWeight((unsigned int)(pv-mesh->mVertices),fNewWeight);
aiBone *bone = mesh->mBones[boneSrc.mMap];
*bone->mWeights++ = aiVertexWeight((unsigned int)(pv - mesh->mVertices), fNewWeight);
}
}
// 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;
}
}
@ -526,14 +501,14 @@ void MD5Importer::LoadMD5MeshFile ()
// (however, take care that the aiFace destructor doesn't delete the mIndices array)
mesh->mNumFaces = (unsigned int)meshSrc.mFaces.size();
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].mIndices = meshSrc.mFaces[c].mIndices;
meshSrc.mFaces[c].mIndices = NULL;
}
// generate a material for the mesh
aiMaterial* mat = new aiMaterial();
aiMaterial *mat = new aiMaterial();
pScene->mMaterials[n] = mat;
// insert the typical doom3 textures:
@ -541,28 +516,27 @@ void MD5Importer::LoadMD5MeshFile ()
// nnn_h.tga - height map
// nnn_s.tga - specular 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);
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");
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");
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");
mat->AddProperty(&temp,AI_MATKEY_TEXTURE_HEIGHT(0));
mat->AddProperty(&temp, AI_MATKEY_TEXTURE_HEIGHT(0));
// set this also as material name
mat->AddProperty(&meshSrc.mShader,AI_MATKEY_NAME);
}
else {
mat->AddProperty(&meshSrc.mShader, AI_MATKEY_NAME);
} else {
mat->AddProperty(&meshSrc.mShader, AI_MATKEY_TEXTURE_DIFFUSE(0));
}
mesh->mMaterialIndex = n++;
@ -572,39 +546,37 @@ void MD5Importer::LoadMD5MeshFile ()
// ------------------------------------------------------------------------------------------------
// Load an MD5ANIM file
void MD5Importer::LoadMD5AnimFile ()
{
void MD5Importer::LoadMD5AnimFile() {
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
if( !file.get() || !file->FileSize()) {
if (!file.get() || !file->FileSize()) {
ASSIMP_LOG_WARN("Failed to read MD5ANIM file: " + pFile);
return;
}
LoadFileIntoMemory(file.get());
// parse the basic file structure
MD5::MD5Parser parser(mBuffer,fileSize);
MD5::MD5Parser parser(mBuffer, fileSize);
// load the animation information from the parse tree
MD5::MD5AnimParser animParser(parser.mSections);
// generate and fill the output animation
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");
}
else {
} else {
bHadMD5Anim = true;
pScene->mAnimations = new aiAnimation*[pScene->mNumAnimations = 1];
aiAnimation* anim = pScene->mAnimations[0] = new aiAnimation();
pScene->mAnimations = new aiAnimation *[pScene->mNumAnimations = 1];
aiAnimation *anim = pScene->mAnimations[0] = new aiAnimation();
anim->mNumChannels = (unsigned int)animParser.mAnimatedBones.size();
anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
for (unsigned int i = 0; i < anim->mNumChannels;++i) {
aiNodeAnim* node = anim->mChannels[i] = new aiNodeAnim();
node->mNodeName = aiString( animParser.mAnimatedBones[i].mName );
anim->mChannels = new aiNodeAnim *[anim->mNumChannels];
for (unsigned int i = 0; i < anim->mNumChannels; ++i) {
aiNodeAnim *node = anim->mChannels[i] = new aiNodeAnim();
node->mNodeName = aiString(animParser.mAnimatedBones[i].mName);
// allocate storage for the keyframes
node->mPositionKeys = new aiVectorKey[animParser.mFrames.size()];
@ -614,46 +586,44 @@ void MD5Importer::LoadMD5AnimFile ()
// 1 tick == 1 frame
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;
aiNodeAnim** pcAnimNode = anim->mChannels;
aiNodeAnim **pcAnimNode = anim->mChannels;
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
MD5::BaseFrameDesc* pcBaseFrame = &animParser.mBaseFrames[0];
for (AnimBoneList::const_iterator iter2 = animParser.mAnimatedBones.begin(); iter2 != animParser.mAnimatedBones.end();++iter2,
++pcAnimNode,++pcBaseFrame)
{
if((*iter2).iFirstKeyIndex >= (*iter).mValues.size()) {
MD5::BaseFrameDesc *pcBaseFrame = &animParser.mBaseFrames[0];
for (AnimBoneList::const_iterator iter2 = animParser.mAnimatedBones.begin(); iter2 != animParser.mAnimatedBones.end(); ++iter2,
++pcAnimNode, ++pcBaseFrame) {
if ((*iter2).iFirstKeyIndex >= (*iter).mValues.size()) {
// Allow for empty frames
if ((*iter2).iFlags != 0) {
throw DeadlyImportError("MD5: Keyframe index is out of range");
}
continue;
}
const float* fpCur = &(*iter).mValues[(*iter2).iFirstKeyIndex];
aiNodeAnim* pcCurAnimBone = *pcAnimNode;
const float *fpCur = &(*iter).mValues[(*iter2).iFirstKeyIndex];
aiNodeAnim *pcCurAnimBone = *pcAnimNode;
aiVectorKey* vKey = &pcCurAnimBone->mPositionKeys[pcCurAnimBone->mNumPositionKeys++];
aiQuatKey* qKey = &pcCurAnimBone->mRotationKeys [pcCurAnimBone->mNumRotationKeys++];
aiVectorKey *vKey = &pcCurAnimBone->mPositionKeys[pcCurAnimBone->mNumPositionKeys++];
aiQuatKey *qKey = &pcCurAnimBone->mRotationKeys[pcCurAnimBone->mNumRotationKeys++];
aiVector3D vTemp;
// translational component
for (unsigned int i = 0; i < 3; ++i) {
if ((*iter2).iFlags & (1u << i)) {
vKey->mValue[i] = *fpCur++;
}
else vKey->mValue[i] = pcBaseFrame->vPositionXYZ[i];
vKey->mValue[i] = *fpCur++;
} else
vKey->mValue[i] = pcBaseFrame->vPositionXYZ[i];
}
// orientation component
for (unsigned int i = 0; i < 3; ++i) {
if ((*iter2).iFlags & (8u << i)) {
vTemp[i] = *fpCur++;
}
else vTemp[i] = pcBaseFrame->vRotationQuat[i];
vTemp[i] = *fpCur++;
} else
vTemp[i] = pcBaseFrame->vRotationQuat[i];
}
MD5::ConvertQuaternion(vTemp, qKey->mValue);
@ -662,7 +632,7 @@ void MD5Importer::LoadMD5AnimFile ()
}
// 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),
@ -671,11 +641,11 @@ void MD5Importer::LoadMD5AnimFile ()
pScene->mRootNode = new aiNode();
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
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
void MD5Importer::LoadMD5CameraFile ()
{
void MD5Importer::LoadMD5CameraFile() {
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
if( !file.get() || !file->FileSize()) {
if (!file.get() || !file->FileSize()) {
throw DeadlyImportError("Failed to read MD5CAMERA file: " + pFile);
}
bHadMD5Camera = true;
LoadFileIntoMemory(file.get());
// parse the basic file structure
MD5::MD5Parser parser(mBuffer,fileSize);
MD5::MD5Parser parser(mBuffer, fileSize);
// load the camera animation data from the parse tree
MD5::MD5CameraParser cameraParser(parser.mSections);
@ -705,56 +674,55 @@ void MD5Importer::LoadMD5CameraFile ()
throw DeadlyImportError("MD5CAMERA: No frames parsed");
}
std::vector<unsigned int>& cuts = cameraParser.cuts;
std::vector<MD5::CameraAnimFrameDesc>& frames = cameraParser.frames;
std::vector<unsigned int> &cuts = cameraParser.cuts;
std::vector<MD5::CameraAnimFrameDesc> &frames = cameraParser.frames;
// Construct output graph - a simple root with a dummy child.
// The root node performs the coordinate system conversion
aiNode* root = pScene->mRootNode = new aiNode("<MD5CameraRoot>");
root->mChildren = new aiNode*[root->mNumChildren = 1];
aiNode *root = pScene->mRootNode = new aiNode("<MD5CameraRoot>");
root->mChildren = new aiNode *[root->mNumChildren = 1];
root->mChildren[0] = new aiNode("<MD5Camera>");
root->mChildren[0]->mParent = root;
// ... but with one camera assigned to it
pScene->mCameras = new aiCamera*[pScene->mNumCameras = 1];
aiCamera* cam = pScene->mCameras[0] = new aiCamera();
pScene->mCameras = new aiCamera *[pScene->mNumCameras = 1];
aiCamera *cam = pScene->mCameras[0] = new aiCamera();
cam->mName = "<MD5Camera>";
// 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
if (!cuts.size()) {
cuts.push_back(0);
cuts.push_back(static_cast<unsigned int>(frames.size()-1));
}
else {
cuts.insert(cuts.begin(),0);
cuts.push_back(static_cast<unsigned int>(frames.size() - 1));
} else {
cuts.insert(cuts.begin(), 0);
if (cuts.back() < frames.size()-1)
cuts.push_back(static_cast<unsigned int>(frames.size()-1));
if (cuts.back() < frames.size() - 1)
cuts.push_back(static_cast<unsigned int>(frames.size() - 1));
}
pScene->mNumAnimations = static_cast<unsigned int>(cuts.size()-1);
aiAnimation** tmp = pScene->mAnimations = new aiAnimation*[pScene->mNumAnimations];
for (std::vector<unsigned int>::const_iterator it = cuts.begin(); it != cuts.end()-1; ++it) {
pScene->mNumAnimations = static_cast<unsigned int>(cuts.size() - 1);
aiAnimation **tmp = pScene->mAnimations = new aiAnimation *[pScene->mNumAnimations];
for (std::vector<unsigned int>::const_iterator it = cuts.begin(); it != cuts.end() - 1; ++it) {
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));
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->mTicksPerSecond = cameraParser.fFrameRate;
anim->mChannels = new aiNodeAnim*[anim->mNumChannels = 1];
aiNodeAnim* nd = anim->mChannels[0] = new aiNodeAnim();
anim->mChannels = new aiNodeAnim *[anim->mNumChannels = 1];
aiNodeAnim *nd = anim->mChannels[0] = new aiNodeAnim();
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->mRotationKeys = new aiQuatKey [nd->mNumRotationKeys];
nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys];
for (unsigned int i = 0; i < nd->mNumPositionKeys; ++i) {
nd->mPositionKeys[i].mValue = frames[*it+i].vPositionXYZ;
MD5::ConvertQuaternion(frames[*it+i].vRotationQuat,nd->mRotationKeys[i].mValue);
nd->mRotationKeys[i].mTime = nd->mPositionKeys[i].mTime = *it+i;
nd->mPositionKeys[i].mValue = frames[*it + i].vPositionXYZ;
MD5::ConvertQuaternion(frames[*it + i].vRotationQuat, nd->mRotationKeys[i].mValue);
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
* @brief Definition of the .MD5 importer class.
* http://www.modwiki.net/wiki/MD5_(file_format)
@ -48,15 +47,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AI_MD5LOADER_H_INCLUDED
#define AI_MD5LOADER_H_INCLUDED
#include <assimp/BaseImporter.h>
#include "MD5Parser.h"
#include <assimp/BaseImporter.h>
#include <assimp/types.h>
struct aiNode;
struct aiNodeAnim;
namespace Assimp {
namespace Assimp {
class IOStream;
using namespace Assimp::MD5;
@ -64,61 +63,53 @@ using namespace Assimp::MD5;
// ---------------------------------------------------------------------------
/** Importer class for the MD5 file format
*/
class MD5Importer : public BaseImporter
{
class MD5Importer : public BaseImporter {
public:
MD5Importer();
~MD5Importer();
public:
// -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details.
*/
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
bool checkSig) const;
bool CanRead(const std::string &pFile, IOSystem *pIOHandler,
bool checkSig) const;
protected:
// -------------------------------------------------------------------
/** Return importer meta information.
* See #BaseImporter::GetInfo for the details
*/
const aiImporterDesc* GetInfo () const;
const aiImporterDesc *GetInfo() const;
// -------------------------------------------------------------------
/** Called prior to ReadFile().
* The function is a request to the importer to update its configuration
* 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.
* See BaseImporter::InternReadFile() for details
*/
void InternReadFile( const std::string& pFile, aiScene* pScene,
IOSystem* pIOHandler);
protected:
void InternReadFile(const std::string &pFile, aiScene *pScene,
IOSystem *pIOHandler);
// -------------------------------------------------------------------
/** Load a *.MD5MESH file.
*/
void LoadMD5MeshFile ();
void LoadMD5MeshFile();
// -------------------------------------------------------------------
/** Load a *.MD5ANIM file.
*/
void LoadMD5AnimFile ();
void LoadMD5AnimFile();
// -------------------------------------------------------------------
/** Load a *.MD5CAMERA file.
*/
void LoadMD5CameraFile ();
void LoadMD5CameraFile();
// -------------------------------------------------------------------
/** Construct node hierarchy from a given MD5ANIM
@ -127,8 +118,8 @@ protected:
* @param bones Input bones
* @param node_anims Generated node animations
*/
void AttachChilds_Anim(int iParentID,aiNode* piParent,
AnimBoneList& bones,const aiNodeAnim** node_anims);
void AttachChilds_Anim(int iParentID, aiNode *piParent,
AnimBoneList &bones, const aiNodeAnim **node_anims);
// -------------------------------------------------------------------
/** Construct node hierarchy from a given MD5MESH
@ -136,13 +127,13 @@ protected:
* @param piParent Parent node to attach to
* @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
* @param meshSrc Input data
*/
void MakeDataUnique (MD5::MeshDesc& meshSrc);
void MakeDataUnique(MD5::MeshDesc &meshSrc);
// -------------------------------------------------------------------
/** Load the contents of a specific file into memory and
@ -151,19 +142,18 @@ protected:
* mBuffer is modified to point to this buffer.
* @param pFile File stream to be read
*/
void LoadFileIntoMemory (IOStream* pFile);
void UnloadFileFromMemory ();
void LoadFileIntoMemory(IOStream *pFile);
void UnloadFileFromMemory();
/** IOSystem to be used to access files */
IOSystem* mIOHandler;
IOSystem *mIOHandler;
/** Path to the file, excluding the file extension but
with the dot */
std::string mFile;
/** Buffer to hold the loaded file */
char* mBuffer;
char *mBuffer;
/** Size of the file */
unsigned int fileSize;
@ -172,10 +162,7 @@ protected:
unsigned int iLineNumber;
/** Scene to be filled */
aiScene* pScene;
/** (Custom) I/O handler implementation */
IOSystem* pIOHandler;
aiScene *pScene;
/** true if a MD5MESH file has already been parsed */
bool bHadMD5Mesh;

View File

@ -817,20 +817,20 @@ void HL1MDLLoader::read_meshes() {
mesh_faces.reserve(num_faces);
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{
tricmds[0],
tricmds[i + 1],
tricmds[i + 2] });
tricmds[faceIdx + 1],
tricmds[faceIdx + 2] });
}
} else {
for (int i = 0; i < num_faces; ++i) {
for (int faceIdx = 0; faceIdx < num_faces; ++faceIdx) {
if (i & 1) {
// Preserve winding order.
mesh_faces.push_back(HL1MeshFace{
tricmds[i + 1],
tricmds[i],
tricmds[i + 2] });
tricmds[faceIdx + 1],
tricmds[faceIdx],
tricmds[faceIdx + 2] });
} else {
mesh_faces.push_back(HL1MeshFace{
tricmds[i],
@ -1122,10 +1122,10 @@ void HL1MDLLoader::read_sequence_infos() {
aiNode *blend_controller_node = blend_controllers_node->mChildren[j] = new aiNode();
blend_controller_node->mParent = blend_controllers_node;
aiMetadata *md = blend_controller_node->mMetaData = aiMetadata::Alloc(3);
md->Set(0, "Start", pseqdesc->blendstart[j]);
md->Set(1, "End", pseqdesc->blendend[j]);
md->Set(2, "MotionFlags", pseqdesc->blendtype[j]);
aiMetadata *metaData = blend_controller_node->mMetaData = aiMetadata::Alloc(3);
metaData->Set(0, "Start", pseqdesc->blendstart[j]);
metaData->Set(1, "End", pseqdesc->blendend[j]);
metaData->Set(2, "MotionFlags", pseqdesc->blendtype[j]);
}
}
}
@ -1151,10 +1151,10 @@ void HL1MDLLoader::read_sequence_infos() {
aiNode *pEvent = pEventsNode->mChildren[j] = new aiNode();
pEvent->mParent = pEventsNode;
aiMetadata *md = pEvent->mMetaData = aiMetadata::Alloc(3);
md->Set(0, "Frame", pevent->frame);
md->Set(1, "ScriptEvent", pevent->event);
md->Set(2, "Options", aiString(pevent->options));
aiMetadata *metaData = pEvent->mMetaData = aiMetadata::Alloc(3);
metaData->Set(0, "Frame", pevent->frame);
metaData->Set(1, "ScriptEvent", pevent->event);
metaData->Set(2, "Options", aiString(pevent->options));
}
}

View File

@ -56,27 +56,27 @@ namespace HalfLife {
/* A class to help map model triverts to mesh triverts. */
struct HL1MeshTrivert {
HL1MeshTrivert() :
vertindex(-1),
normindex(-1),
s(0),
t(0),
localindex(-1) {
vertindex(-1),
normindex(-1),
s(0),
t(0),
localindex(-1) {
}
HL1MeshTrivert(short vertindex, short normindex, short s, short t, short localindex) :
vertindex(vertindex),
normindex(normindex),
s(s),
t(t),
localindex() {
vertindex(vertindex),
normindex(normindex),
s(s),
t(t),
localindex(localindex) {
}
HL1MeshTrivert(const Trivert &a) :
vertindex(a.vertindex),
normindex(a.normindex),
s(a.s),
t(a.t),
localindex(-1) {
vertindex(a.vertindex),
normindex(a.normindex),
s(a.s),
t(a.t),
localindex(-1) {
}
inline bool operator==(const Trivert &a) const {

View File

@ -68,7 +68,7 @@ static aiTexel* const bad_texel = reinterpret_cast<aiTexel*>(SIZE_MAX);
void MDLImporter::SearchPalette(const unsigned char** pszColorMap)
{
// 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;
if(pcStream)
@ -702,14 +702,13 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
// data structures in the aiScene instance
if (pcNew && pScene->mNumTextures <= 999)
{
// place this as diffuse texture
char szCurrent[5];
ai_snprintf(szCurrent,5,"*%i",this->pScene->mNumTextures);
char current[5];
ai_snprintf(current, 5, "*%i", this->pScene->mNumTextures);
aiString szFile;
const size_t iLen = strlen((const char*)szCurrent);
::memcpy(szFile.data,(const char*)szCurrent,iLen+1);
const size_t iLen = strlen((const char *)current);
::memcpy(szFile.data, (const char *)current, iLen + 1);
szFile.length = (ai_uint32)iLen;
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];
stream.IncPtr(2);
for (unsigned int i = 0; i < 3; ++i) {
t.indices[i] = stream.GetI2();
for (unsigned int j = 0; j < 3; ++j) {
t.indices[j] = stream.GetI2();
}
for (unsigned int i = 0; i < 3; ++i) {
ReadVector(stream,t.normals[i]);
for (unsigned int j = 0; j < 3; ++j) {
ReadVector(stream,t.normals[j]);
}
for (unsigned int i = 0; i < 3; ++i) {
stream >> (float&)(t.uv[i].x); // see note in ReadColor()
for (unsigned int j = 0; j < 3; ++j) {
stream >> (float&)(t.uv[j].x); // see note in ReadColor()
}
for (unsigned int i = 0; i < 3; ++i) {
stream >> (float&)(t.uv[i].y);
for (unsigned int j = 0; j < 3; ++j) {
stream >> (float&)(t.uv[j].y);
}
t.sg = stream.GetI1();
@ -296,8 +296,8 @@ void MS3DImporter::InternReadFile( const std::string& pFile,
stream >> num;
t.triangles.resize(num);
for (unsigned int i = 0; i < num; ++i) {
t.triangles[i] = stream.GetI2();
for (unsigned int j = 0; j < num; ++j) {
t.triangles[j] = stream.GetI2();
}
t.mat = stream.GetI1();
if (t.mat == UINT_MAX) {
@ -309,8 +309,8 @@ void MS3DImporter::InternReadFile( const std::string& pFile,
stream >> mat;
std::vector<TempMaterial> materials(mat);
for (unsigned int i = 0;i < mat; ++i) {
TempMaterial& t = materials[i];
for (unsigned int j = 0;j < mat; ++j) {
TempMaterial& t = materials[j];
stream.CopyAndAdvance(t.name,32);
t.name[32] = '\0';
@ -338,8 +338,8 @@ void MS3DImporter::InternReadFile( const std::string& pFile,
stream >> joint;
std::vector<TempJoint> joints(joint);
for(unsigned int i = 0; i < joint; ++i) {
TempJoint& j = joints[i];
for(unsigned int ii = 0; ii < joint; ++ii) {
TempJoint& j = joints[ii];
stream.IncPtr(1);
stream.CopyAndAdvance(j.name,32);
@ -494,17 +494,17 @@ void MS3DImporter::InternReadFile( const std::string& pFile,
typedef std::map<unsigned int,unsigned int> BoneSet;
BoneSet mybones;
for (unsigned int i = 0,n = 0; i < m->mNumFaces; ++i) {
aiFace& f = m->mFaces[i];
if (g.triangles[i]>triangles.size()) {
for (unsigned int j = 0,n = 0; j < m->mNumFaces; ++j) {
aiFace& f = m->mFaces[j];
if (g.triangles[j]>triangles.size()) {
throw DeadlyImportError("MS3D: Encountered invalid triangle index, file is malformed");
}
TempTriangle& t = triangles[g.triangles[i]];
f.mIndices = new unsigned int[f.mNumIndices=3];
for (unsigned int i = 0; i < 3; ++i,++n) {
if (t.indices[i]>vertices.size()) {
for (unsigned int k = 0; k < 3; ++k,++n) {
if (t.indices[k]>vertices.size()) {
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
for (unsigned int i = 0,n = 0; i < m->mNumFaces; ++i) {
TempTriangle& t = triangles[g.triangles[i]];
for (unsigned int j = 0,n = 0; j < m->mNumFaces; ++j) {
TempTriangle& t = triangles[g.triangles[j]];
for (unsigned int i = 0; i < 3; ++i,++n) {
const TempVertex& v = vertices[t.indices[i]];
for (unsigned int k = 0; k < 3; ++k,++n) {
const TempVertex& v = vertices[t.indices[k]];
for(unsigned int a = 0; a < 4; ++a) {
const unsigned int bone = v.bone_id[a];
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
aiVector3D center, radius, dir;
char name[128];
static const size_t MaxNameLen = 128;
char name[MaxNameLen];
std::vector<aiVector3D> vertices, normals, uvs;
std::vector<unsigned int> faces;

View File

@ -80,7 +80,7 @@ ObjFileParser::ObjFileParser( IOStreamBuffer<char> &streamBuffer, const std::str
m_progress(progress),
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
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)
{
uint16_t id = ReadHeader();
if (id != M_EDGE_GROUP)
uint16_t curId = ReadHeader();
if (curId != M_EDGE_GROUP)
throw DeadlyImportError("M_EDGE_GROUP not found in M_EDGE_LIST_LOD");
m_reader->IncPtr(sizeof(uint32_t) * 3);

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team
All rights reserved.
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();
m_textures.clear();
aiString ts(materialName);
material->AddProperty(&ts, AI_MATKEY_NAME);
aiString matName(materialName);
material->AddProperty(&matName, AI_MATKEY_NAME);
// The stringstream will push words from a line until newline.
// 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")
{
ss >> linePart;
aiString ts(linePart);
material->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
aiString cm(linePart);
material->AddProperty(&cm, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
}
else if (linePart=="$normalmap")
{
ss >> linePart;
aiString ts(linePart);
material->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0));
aiString nm(linePart);
material->AddProperty(&nm, AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0));
}
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
#include <assimp/ParsingUtils.h>
#include <functional>
#include <algorithm>
#include <stdint.h>
#include <sstream>
#include <algorithm>
#include <cctype>
#include <functional>
#include <sstream>
namespace Assimp {
namespace Ogre {
/// Returns a lower cased copy of @s.
static AI_FORCE_INLINE
std::string ToLower(std::string s)
{
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
return s;
static AI_FORCE_INLINE std::string ToLower(const std::string &s) {
std::string lower(s);
std::transform(lower.begin(), lower.end(), lower.begin(), Assimp::ToLower<char>);
return lower;
}
/// 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
bool EndsWith(const std::string &s, const std::string &suffix, bool caseSensitive = true) {
static AI_FORCE_INLINE bool EndsWith( const std::string &s, const std::string &suffix, bool caseSensitive = true) {
if (s.empty() || suffix.empty()) {
return false;
} 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();
std::string sSuffix = s.substr(s.length()-len, len);
std::string sSuffix = s.substr(s.length() - len, len);
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
static AI_FORCE_INLINE
std::string &TrimLeft(std::string &s, bool newlines = true) {
std::string &
TrimLeft(std::string &s, bool newlines = true) {
if (!newlines) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpace<char>(c); }));
} else {
@ -97,9 +97,10 @@ std::string &TrimLeft(std::string &s, bool newlines = true) {
/// Trim from end
static AI_FORCE_INLINE
std::string &TrimRight(std::string &s, bool newlines = true) {
std::string &
TrimRight(std::string &s, bool newlines = true) {
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 {
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
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);
}
/// Skips a line from current @ss position until a newline. Returns the skipped part.
static AI_FORCE_INLINE
std::string SkipLine(std::stringstream &ss) {
std::string
SkipLine(std::stringstream &ss) {
std::string skipped;
getline(ss, 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.
/** @return Skipped line content until newline. */
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);
ss >> nextElement;
return skipped;
}
} // Ogre
} // Assimp
} // namespace Ogre
} // namespace Assimp
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
#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 OGRE_XML_SERIALIZER_DEBUG 0
namespace Assimp
{
namespace Ogre
{
namespace Assimp {
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)
{
if (!error.empty())
{
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) {
if (!error.empty()) {
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()) + "'");
}
}
template<>
int32_t OgreXmlSerializer::ReadAttribute<int32_t>(const char *name) const
{
if (HasAttribute(name))
{
return static_cast<int32_t>(m_reader->getAttributeValueAsInt(name));
}
else
{
ThrowAttibuteError(m_reader, name);
return 0;
}
}
template<>
uint32_t OgreXmlSerializer::ReadAttribute<uint32_t>(const char *name) const
{
if (HasAttribute(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
{
ThrowAttibuteError(m_reader, name, "Found a negative number value where expecting a uint32_t value");
}
}
else
{
template <>
int32_t OgreXmlSerializer::ReadAttribute<int32_t>(const char *name) const {
if (!HasAttribute(name)) {
ThrowAttibuteError(m_reader, name);
}
return 0;
return static_cast<int32_t>(m_reader->getAttributeValueAsInt(name));
}
template<>
uint16_t OgreXmlSerializer::ReadAttribute<uint16_t>(const char *name) const
{
if (HasAttribute(name))
{
return static_cast<uint16_t>(ReadAttribute<uint32_t>(name));
}
else
{
template <>
uint32_t OgreXmlSerializer::ReadAttribute<uint32_t>(const char *name) const {
if (!HasAttribute(name)) {
ThrowAttibuteError(m_reader, name);
}
return 0;
// @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");
}
return static_cast<uint32_t>(temp);
}
template<>
float OgreXmlSerializer::ReadAttribute<float>(const char *name) const
{
if (HasAttribute(name))
{
return m_reader->getAttributeValueAsFloat(name);
}
else
{
template <>
uint16_t OgreXmlSerializer::ReadAttribute<uint16_t>(const char *name) const {
if (!HasAttribute(name)) {
ThrowAttibuteError(m_reader, name);
return 0;
}
return static_cast<uint16_t>(ReadAttribute<uint32_t>(name));
}
template<>
std::string OgreXmlSerializer::ReadAttribute<std::string>(const char *name) const
{
const char* value = m_reader->getAttributeValue(name);
if (value)
{
return std::string(value);
}
else
{
template <>
float OgreXmlSerializer::ReadAttribute<float>(const char *name) const {
if (!HasAttribute(name)) {
ThrowAttibuteError(m_reader, name);
return "";
}
return m_reader->getAttributeValueAsFloat(name);
}
template<>
bool OgreXmlSerializer::ReadAttribute<bool>(const char *name) const
{
template <>
std::string OgreXmlSerializer::ReadAttribute<std::string>(const char *name) const {
const char *value = m_reader->getAttributeValue(name);
if (nullptr == value) {
ThrowAttibuteError(m_reader, name);
}
return std::string(value);
}
template <>
bool OgreXmlSerializer::ReadAttribute<bool>(const char *name) const {
std::string value = Ogre::ToLower(ReadAttribute<std::string>(name));
if (ASSIMP_stricmp(value, "true") == 0)
{
if (ASSIMP_stricmp(value, "true") == 0) {
return true;
}
else if (ASSIMP_stricmp(value, "false") == 0)
{
} else if (ASSIMP_stricmp(value, "false") == 0) {
return false;
}
else
{
} else {
ThrowAttibuteError(m_reader, name, "Boolean value is expected to be 'true' or 'false', encountered '" + value + "'");
return false;
}
}
bool OgreXmlSerializer::HasAttribute(const char *name) const
{
bool OgreXmlSerializer::HasAttribute(const char *name) const {
return (m_reader->getAttributeValue(name) != 0);
}
std::string &OgreXmlSerializer::NextNode()
{
do
{
if (!m_reader->read())
{
std::string &OgreXmlSerializer::NextNode() {
do {
if (!m_reader->read()) {
m_currentNodeName = "";
return m_currentNodeName;
}
}
while(m_reader->getNodeType() != irr::io::EXN_ELEMENT);
} while (m_reader->getNodeType() != irr::io::EXN_ELEMENT);
CurrentNodeName(true);
#if (OGRE_XML_SERIALIZER_DEBUG == 1)
@ -195,32 +149,29 @@ std::string &OgreXmlSerializer::NextNode()
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);
}
std::string OgreXmlSerializer::CurrentNodeName(bool forceRead)
{
std::string OgreXmlSerializer::CurrentNodeName(bool forceRead) {
if (forceRead)
m_currentNodeName = std::string(m_reader->getNodeName());
return m_currentNodeName;
}
std::string &OgreXmlSerializer::SkipCurrentNode()
{
std::string &OgreXmlSerializer::SkipCurrentNode() {
#if (OGRE_XML_SERIALIZER_DEBUG == 1)
ASSIMP_LOG_DEBUG("Skipping node <" + m_currentNodeName + ">");
#endif
for(;;) {
for (;;) {
if (!m_reader->read()) {
m_currentNodeName = "";
return m_currentNodeName;
}
if ( m_reader->getNodeType() != irr::io::EXN_ELEMENT_END ) {
if (m_reader->getNodeType() != irr::io::EXN_ELEMENT_END) {
continue;
} else if ( std::string( m_reader->getNodeName() ) == m_currentNodeName ) {
} else if (std::string(m_reader->getNodeName()) == m_currentNodeName) {
break;
}
}
@ -231,38 +182,38 @@ std::string &OgreXmlSerializer::SkipCurrentNode()
// Mesh XML constants
// <mesh>
static const char *nnMesh = "mesh";
static const char *nnSharedGeometry = "sharedgeometry";
static const char *nnSubMeshes = "submeshes";
static const char *nnSubMesh = "submesh";
static const char *nnSubMeshNames = "submeshnames";
static const char *nnSkeletonLink = "skeletonlink";
static const char *nnLOD = "levelofdetail";
static const char *nnExtremes = "extremes";
static const char *nnPoses = "poses";
static const char *nnAnimations = "animations";
static const char *nnMesh = "mesh";
static const char *nnSharedGeometry = "sharedgeometry";
static const char *nnSubMeshes = "submeshes";
static const char *nnSubMesh = "submesh";
static const char *nnSubMeshNames = "submeshnames";
static const char *nnSkeletonLink = "skeletonlink";
static const char *nnLOD = "levelofdetail";
static const char *nnExtremes = "extremes";
static const char *nnPoses = "poses";
static const char *nnAnimations = "animations";
// <submesh>
static const char *nnFaces = "faces";
static const char *nnFace = "face";
static const char *nnGeometry = "geometry";
static const char *nnTextures = "textures";
static const char *nnFaces = "faces";
static const char *nnFace = "face";
static const char *nnGeometry = "geometry";
static const char *nnTextures = "textures";
// <mesh/submesh>
static const char *nnBoneAssignments = "boneassignments";
static const char *nnBoneAssignments = "boneassignments";
// <sharedgeometry/geometry>
static const char *nnVertexBuffer = "vertexbuffer";
static const char *nnVertexBuffer = "vertexbuffer";
// <vertexbuffer>
static const char *nnVertex = "vertex";
static const char *nnPosition = "position";
static const char *nnNormal = "normal";
static const char *nnTangent = "tangent";
static const char *nnBinormal = "binormal";
static const char *nnTexCoord = "texcoord";
static const char *nnColorDiffuse = "colour_diffuse";
static const char *nnColorSpecular = "colour_specular";
static const char *nnVertex = "vertex";
static const char *nnPosition = "position";
static const char *nnNormal = "normal";
static const char *nnTangent = "tangent";
static const char *nnBinormal = "binormal";
static const char *nnTexCoord = "texcoord";
static const char *nnColorDiffuse = "colour_diffuse";
static const char *nnColorSpecular = "colour_specular";
// <boneassignments>
static const char *nnVertexBoneAssignment = "vertexboneassignment";
@ -270,30 +221,30 @@ static const char *nnVertexBoneAssignment = "vertexboneassignment";
// Skeleton XML constants
// <skeleton>
static const char *nnSkeleton = "skeleton";
static const char *nnBones = "bones";
static const char *nnBoneHierarchy = "bonehierarchy";
static const char *nnAnimationLinks = "animationlinks";
static const char *nnSkeleton = "skeleton";
static const char *nnBones = "bones";
static const char *nnBoneHierarchy = "bonehierarchy";
static const char *nnAnimationLinks = "animationlinks";
// <bones>
static const char *nnBone = "bone";
static const char *nnRotation = "rotation";
static const char *nnAxis = "axis";
static const char *nnScale = "scale";
static const char *nnBone = "bone";
static const char *nnRotation = "rotation";
static const char *nnAxis = "axis";
static const char *nnScale = "scale";
// <bonehierarchy>
static const char *nnBoneParent = "boneparent";
static const char *nnBoneParent = "boneparent";
// <animations>
static const char *nnAnimation = "animation";
static const char *nnTracks = "tracks";
static const char *nnAnimation = "animation";
static const char *nnTracks = "tracks";
// <tracks>
static const char *nnTrack = "track";
static const char *nnKeyFrames = "keyframes";
static const char *nnKeyFrame = "keyframe";
static const char *nnTranslate = "translate";
static const char *nnRotate = "rotate";
static const char *nnTrack = "track";
static const char *nnKeyFrames = "keyframes";
static const char *nnKeyFrame = "keyframe";
static const char *nnTranslate = "translate";
static const char *nnRotate = "rotate";
// Common XML constants
@ -322,34 +273,26 @@ void OgreXmlSerializer::ReadMesh(MeshXml *mesh) {
NextNode();
// Root level nodes
while(m_currentNodeName == nnSharedGeometry ||
m_currentNodeName == nnSubMeshes ||
m_currentNodeName == nnSkeletonLink ||
m_currentNodeName == nnBoneAssignments ||
m_currentNodeName == nnLOD ||
m_currentNodeName == nnSubMeshNames ||
m_currentNodeName == nnExtremes ||
m_currentNodeName == nnPoses ||
m_currentNodeName == nnAnimations)
{
if (m_currentNodeName == nnSharedGeometry)
{
while (m_currentNodeName == nnSharedGeometry ||
m_currentNodeName == nnSubMeshes ||
m_currentNodeName == nnSkeletonLink ||
m_currentNodeName == nnBoneAssignments ||
m_currentNodeName == nnLOD ||
m_currentNodeName == nnSubMeshNames ||
m_currentNodeName == nnExtremes ||
m_currentNodeName == nnPoses ||
m_currentNodeName == nnAnimations) {
if (m_currentNodeName == nnSharedGeometry) {
mesh->sharedVertexData = new VertexDataXml();
ReadGeometry(mesh->sharedVertexData);
}
else if (m_currentNodeName == nnSubMeshes)
{
} else if (m_currentNodeName == nnSubMeshes) {
NextNode();
while(m_currentNodeName == nnSubMesh) {
while (m_currentNodeName == nnSubMesh) {
ReadSubMesh(mesh);
}
}
else if (m_currentNodeName == nnBoneAssignments)
{
} else if (m_currentNodeName == nnBoneAssignments) {
ReadBoneAssignments(mesh->sharedVertexData);
}
else if (m_currentNodeName == nnSkeletonLink)
{
} else if (m_currentNodeName == nnSkeletonLink) {
mesh->skeletonRef = ReadAttribute<std::string>("name");
ASSIMP_LOG_DEBUG_F("Read skeleton link ", mesh->skeletonRef);
NextNode();
@ -360,49 +303,43 @@ void OgreXmlSerializer::ReadMesh(MeshXml *mesh) {
}
}
void OgreXmlSerializer::ReadGeometry(VertexDataXml *dest)
{
void OgreXmlSerializer::ReadGeometry(VertexDataXml *dest) {
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();
while(m_currentNodeName == nnVertexBuffer) {
while (m_currentNodeName == nnVertexBuffer) {
ReadGeometryVertexBuffer(dest);
}
}
void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest)
{
void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest) {
bool positions = (HasAttribute("positions") && ReadAttribute<bool>("positions"));
bool normals = (HasAttribute("normals") && ReadAttribute<bool>("normals"));
bool tangents = (HasAttribute("tangents") && ReadAttribute<bool>("tangents"));
uint32_t uvs = (HasAttribute("texture_coords") ? ReadAttribute<uint32_t>("texture_coords") : 0);
bool normals = (HasAttribute("normals") && ReadAttribute<bool>("normals"));
bool tangents = (HasAttribute("tangents") && ReadAttribute<bool>("tangents"));
uint32_t uvs = (HasAttribute("texture_coords") ? ReadAttribute<uint32_t>("texture_coords") : 0);
// Not having positions is a error only if a previous vertex buffer did not have them.
if (!positions && !dest->HasPositions()) {
throw DeadlyImportError("Vertex buffer does not contain positions!");
}
if (positions)
{
if (positions) {
ASSIMP_LOG_DEBUG(" - Contains positions");
dest->positions.reserve(dest->count);
}
if (normals)
{
if (normals) {
ASSIMP_LOG_DEBUG(" - Contains normals");
dest->normals.reserve(dest->count);
}
if (tangents)
{
if (tangents) {
ASSIMP_LOG_DEBUG(" - Contains tangents");
dest->tangents.reserve(dest->count);
}
if (uvs > 0)
{
ASSIMP_LOG_DEBUG_F( " - Contains ", uvs, " texture coords");
if (uvs > 0) {
ASSIMP_LOG_DEBUG_F(" - Contains ", uvs, " texture coords");
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);
}
}
@ -413,49 +350,40 @@ void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest)
NextNode();
while(m_currentNodeName == nnVertex ||
m_currentNodeName == nnPosition ||
m_currentNodeName == nnNormal ||
m_currentNodeName == nnTangent ||
m_currentNodeName == nnBinormal ||
m_currentNodeName == nnTexCoord ||
m_currentNodeName == nnColorDiffuse ||
m_currentNodeName == nnColorSpecular)
{
while (m_currentNodeName == nnVertex ||
m_currentNodeName == nnPosition ||
m_currentNodeName == nnNormal ||
m_currentNodeName == nnTangent ||
m_currentNodeName == nnBinormal ||
m_currentNodeName == nnTexCoord ||
m_currentNodeName == nnColorDiffuse ||
m_currentNodeName == nnColorSpecular) {
if (m_currentNodeName == nnVertex) {
NextNode();
}
/// @todo Implement nnBinormal, nnColorDiffuse and nnColorSpecular
if (positions && m_currentNodeName == nnPosition)
{
if (positions && m_currentNodeName == nnPosition) {
aiVector3D pos;
pos.x = ReadAttribute<float>(anX);
pos.y = ReadAttribute<float>(anY);
pos.z = ReadAttribute<float>(anZ);
dest->positions.push_back(pos);
}
else if (normals && m_currentNodeName == nnNormal)
{
} else if (normals && m_currentNodeName == nnNormal) {
aiVector3D normal;
normal.x = ReadAttribute<float>(anX);
normal.y = ReadAttribute<float>(anY);
normal.z = ReadAttribute<float>(anZ);
dest->normals.push_back(normal);
}
else if (tangents && m_currentNodeName == nnTangent)
{
} else if (tangents && m_currentNodeName == nnTangent) {
aiVector3D tangent;
tangent.x = ReadAttribute<float>(anX);
tangent.y = ReadAttribute<float>(anY);
tangent.z = ReadAttribute<float>(anZ);
dest->tangents.push_back(tangent);
}
else if (uvs > 0 && m_currentNodeName == nnTexCoord)
{
for(auto &uvs : dest->uvs)
{
} else if (uvs > 0 && m_currentNodeName == nnTexCoord) {
for (auto &curUvs : dest->uvs) {
if (m_currentNodeName != nnTexCoord) {
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;
uv.x = ReadAttribute<float>("u");
uv.y = (ReadAttribute<float>("v") * -1) + 1; // Flip UV from Ogre to Assimp form
uvs.push_back(uv);
curUvs.push_back(uv);
NextNode();
}
// Continue main loop as above already read next node
continue;
}
else
{
} else {
/// @todo Remove this stuff once implemented. We only want to log warnings once per element.
bool warn = true;
if (m_currentNodeName == nnBinormal)
{
if (warnBinormal)
{
if (m_currentNodeName == nnBinormal) {
if (warnBinormal) {
warnBinormal = false;
}
else
{
} else {
warn = false;
}
}
else if (m_currentNodeName == nnColorDiffuse)
{
if (warnColorDiffuse)
{
} else if (m_currentNodeName == nnColorDiffuse) {
if (warnColorDiffuse) {
warnColorDiffuse = false;
}
else
{
} else {
warn = false;
}
}
else if (m_currentNodeName == nnColorSpecular)
{
if (warnColorSpecular)
{
} else if (m_currentNodeName == nnColorSpecular) {
if (warnColorSpecular) {
warnColorSpecular = false;
}
else
{
} else {
warn = false;
}
}
@ -518,7 +430,7 @@ void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest)
// Sanity checks
if (dest->positions.size() != dest->count) {
throw DeadlyImportError(Formatter::format() << "Read only " << dest->positions.size() << " positions when should have read " << dest->count);
throw DeadlyImportError(Formatter::format() << "Read only " << dest->positions.size() << " positions when should have read " << dest->count);
}
if (normals && dest->normals.size() != dest->count) {
throw DeadlyImportError(Formatter::format() << "Read only " << dest->normals.size() << " normals when should have read " << dest->count);
@ -526,26 +438,24 @@ void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest)
if (tangents && dest->tangents.size() != 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) {
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);
}
}
}
void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh)
{
static const char *anMaterial = "material";
void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh) {
static const char *anMaterial = "material";
static const char *anUseSharedVertices = "usesharedvertices";
static const char *anCount = "count";
static const char *anV1 = "v1";
static const char *anV2 = "v2";
static const char *anV3 = "v3";
static const char *anV4 = "v4";
static const char *anCount = "count";
static const char *anV1 = "v1";
static const char *anV2 = "v2";
static const char *anV3 = "v3";
static const char *anV4 = "v4";
SubMeshXml* submesh = new SubMeshXml();
SubMeshXml *submesh = new SubMeshXml();
if (HasAttribute(anMaterial)) {
submesh->materialRef = ReadAttribute<std::string>(anMaterial);
@ -554,9 +464,9 @@ void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh)
submesh->usesSharedVertexData = ReadAttribute<bool>(anUseSharedVertices);
}
ASSIMP_LOG_DEBUG_F( "Reading SubMesh ", mesh->subMeshes.size());
ASSIMP_LOG_DEBUG_F( " - Material: '", submesh->materialRef, "'");
ASSIMP_LOG_DEBUG_F( " - Uses shared geometry: ", (submesh->usesSharedVertexData ? "true" : "false"));
ASSIMP_LOG_DEBUG_F("Reading SubMesh ", mesh->subMeshes.size());
ASSIMP_LOG_DEBUG_F(" - Material: '", submesh->materialRef, "'");
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
// 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;
NextNode();
while(m_currentNodeName == nnFaces ||
m_currentNodeName == nnGeometry ||
m_currentNodeName == nnTextures ||
m_currentNodeName == nnBoneAssignments)
{
if (m_currentNodeName == nnFaces)
{
while (m_currentNodeName == nnFaces ||
m_currentNodeName == nnGeometry ||
m_currentNodeName == nnTextures ||
m_currentNodeName == nnBoneAssignments) {
if (m_currentNodeName == nnFaces) {
submesh->indexData->faceCount = ReadAttribute<uint32_t>(anCount);
submesh->indexData->faces.reserve(submesh->indexData->faceCount);
NextNode();
while(m_currentNodeName == nnFace)
{
while (m_currentNodeName == nnFace) {
aiFace face;
face.mNumIndices = 3;
face.mIndices = new unsigned int[3];
@ -598,7 +505,7 @@ void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh)
}
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 {
throw DeadlyImportError(Formatter::format() << "Read only " << submesh->indexData->faces.size() << " faces when should have read " << submesh->indexData->faceCount);
}
@ -622,21 +529,19 @@ void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh)
mesh->subMeshes.push_back(submesh);
}
void OgreXmlSerializer::ReadBoneAssignments(VertexDataXml *dest)
{
void OgreXmlSerializer::ReadBoneAssignments(VertexDataXml *dest) {
if (!dest) {
throw DeadlyImportError("Cannot read bone assignments, vertex data is null.");
}
static const char *anVertexIndex = "vertexindex";
static const char *anBoneIndex = "boneindex";
static const char *anWeight = "weight";
static const char *anBoneIndex = "boneindex";
static const char *anWeight = "weight";
std::set<uint32_t> influencedVertices;
NextNode();
while(m_currentNodeName == nnVertexBoneAssignment)
{
while (m_currentNodeName == nnVertexBoneAssignment) {
VertexBoneAssignment ba;
ba.vertexIndex = ReadAttribute<uint32_t>(anVertexIndex);
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
for a single vertex equals 1 or not, so validate here. */
const float epsilon = 0.05f;
for (const uint32_t vertexIndex : influencedVertices)
{
for (const uint32_t vertexIndex : influencedVertices) {
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)
sum += baIter->weight;
}
if ((sum < (1.0f - epsilon)) || (sum > (1.0f + epsilon)))
{
for (auto &boneAssign : dest->boneAssignments)
{
if ((sum < (1.0f - epsilon)) || (sum > (1.0f + epsilon))) {
for (auto &boneAssign : dest->boneAssignments) {
if (boneAssign.vertexIndex == vertexIndex)
boneAssign.weight /= sum;
}
}
}
ASSIMP_LOG_DEBUG_F( " - ", dest->boneAssignments.size(), " bone assignments");
ASSIMP_LOG_DEBUG_F(" - ", dest->boneAssignments.size(), " bone assignments");
}
// Skeleton
bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh)
{
bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh) {
if (!mesh || mesh->skeletonRef.empty())
return false;
// Highly unusual to see in read world cases but support
// XML mesh referencing a binary skeleton file.
if (EndsWith(mesh->skeletonRef, ".skeleton", false))
{
if (EndsWith(mesh->skeletonRef, ".skeleton", false)) {
if (OgreBinarySerializer::ImportSkeleton(pIOHandler, mesh))
return true;
@ -705,8 +604,7 @@ bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *me
return true;
}
bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh)
{
bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh) {
if (!mesh || mesh->skeletonRef.empty())
return false;
@ -721,16 +619,13 @@ bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh)
return true;
}
XmlReaderPtr OgreXmlSerializer::OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename)
{
if (!EndsWith(filename, ".skeleton.xml", false))
{
XmlReaderPtr OgreXmlSerializer::OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename) {
if (!EndsWith(filename, ".skeleton.xml", false)) {
ASSIMP_LOG_ERROR_F("Imported Mesh is referencing to unsupported '", filename, "' skeleton file.");
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.");
return XmlReaderPtr();
}
@ -748,8 +643,7 @@ XmlReaderPtr OgreXmlSerializer::OpenReader(Assimp::IOSystem *pIOHandler, const s
return reader;
}
void OgreXmlSerializer::ReadSkeleton(Skeleton *skeleton)
{
void OgreXmlSerializer::ReadSkeleton(Skeleton *skeleton) {
if (NextNode() != nnSkeleton) {
throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting <skeleton>");
}
@ -758,18 +652,16 @@ void OgreXmlSerializer::ReadSkeleton(Skeleton *skeleton)
// Optional blend mode from root node
if (HasAttribute("blendmode")) {
skeleton->blendMode = (ToLower(ReadAttribute<std::string>("blendmode")) == "cumulative"
? Skeleton::ANIMBLEND_CUMULATIVE : Skeleton::ANIMBLEND_AVERAGE);
skeleton->blendMode = (ToLower(ReadAttribute<std::string>("blendmode")) == "cumulative" ? Skeleton::ANIMBLEND_CUMULATIVE : Skeleton::ANIMBLEND_AVERAGE);
}
NextNode();
// Root level nodes
while(m_currentNodeName == nnBones ||
m_currentNodeName == nnBoneHierarchy ||
m_currentNodeName == nnAnimations ||
m_currentNodeName == nnAnimationLinks)
{
while (m_currentNodeName == nnBones ||
m_currentNodeName == nnBoneHierarchy ||
m_currentNodeName == nnAnimations ||
m_currentNodeName == nnAnimationLinks) {
if (m_currentNodeName == nnBones)
ReadBones(skeleton);
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()) {
throw DeadlyImportError("Cannot read <animations> for a Skeleton without bones");
}
@ -790,8 +681,7 @@ void OgreXmlSerializer::ReadAnimations(Skeleton *skeleton)
ASSIMP_LOG_DEBUG(" - Animations");
NextNode();
while(m_currentNodeName == nnAnimation)
{
while (m_currentNodeName == nnAnimation) {
Animation *anim = new Animation(skeleton);
anim->name = ReadAttribute<std::string>("name");
anim->length = ReadAttribute<float>("length");
@ -803,15 +693,13 @@ void OgreXmlSerializer::ReadAnimations(Skeleton *skeleton)
ReadAnimationTracks(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();
while(m_currentNodeName == nnTrack)
{
while (m_currentNodeName == nnTrack) {
VertexAnimationTrack track;
track.type = VertexAnimationTrack::VAT_TRANSFORM;
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);
NextNode();
while(m_currentNodeName == nnKeyFrame)
{
while (m_currentNodeName == nnKeyFrame) {
TransformKeyFrame keyframe;
keyframe.timePos = ReadAttribute<float>("time");
NextNode();
while(m_currentNodeName == nnTranslate || m_currentNodeName == nnRotate || m_currentNodeName == nnScale)
{
if (m_currentNodeName == nnTranslate)
{
while (m_currentNodeName == nnTranslate || m_currentNodeName == nnRotate || m_currentNodeName == nnScale) {
if (m_currentNodeName == nnTranslate) {
keyframe.position.x = ReadAttribute<float>(anX);
keyframe.position.y = ReadAttribute<float>(anY);
keyframe.position.z = ReadAttribute<float>(anZ);
}
else if (m_currentNodeName == nnRotate)
{
} else if (m_currentNodeName == nnRotate) {
float angle = ReadAttribute<float>("angle");
if (NextNode() != nnAxis) {
@ -857,17 +739,14 @@ void OgreXmlSerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationT
axis.x = ReadAttribute<float>(anX);
axis.y = ReadAttribute<float>(anY);
axis.z = ReadAttribute<float>(anZ);
if (axis.Equal(zeroVec))
{
if (axis.Equal(zeroVec)) {
axis.x = 1.0f;
if (angle != 0) {
ASSIMP_LOG_WARN_F("Found invalid a key frame with a zero rotation axis in animation: ", anim->name);
}
}
keyframe.rotation = aiQuaternion(axis, angle);
}
else if (m_currentNodeName == nnScale)
{
} else if (m_currentNodeName == nnScale) {
keyframe.scale.x = ReadAttribute<float>(anX);
keyframe.scale.y = ReadAttribute<float>(anY);
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()) {
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 parentName = ReadAttribute<std::string>("parent");
@ -901,46 +778,38 @@ void OgreXmlSerializer::ReadBoneHierarchy(Skeleton *skeleton)
}
// 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];
if (!bone->IsParented())
bone->CalculateWorldMatrixAndDefaultPose(skeleton);
}
}
static bool BoneCompare(Bone *a, Bone *b)
{
ai_assert( nullptr != a );
ai_assert( nullptr != b );
static bool BoneCompare(Bone *a, Bone *b) {
ai_assert(nullptr != a);
ai_assert(nullptr != b);
return (a->id < b->id);
}
void OgreXmlSerializer::ReadBones(Skeleton *skeleton)
{
void OgreXmlSerializer::ReadBones(Skeleton *skeleton) {
ASSIMP_LOG_DEBUG(" - Bones");
NextNode();
while(m_currentNodeName == nnBone)
{
while (m_currentNodeName == nnBone) {
Bone *bone = new Bone();
bone->id = ReadAttribute<uint16_t>("id");
bone->name = ReadAttribute<std::string>("name");
NextNode();
while(m_currentNodeName == nnPosition ||
m_currentNodeName == nnRotation ||
m_currentNodeName == nnScale)
{
if (m_currentNodeName == nnPosition)
{
while (m_currentNodeName == nnPosition ||
m_currentNodeName == nnRotation ||
m_currentNodeName == nnScale) {
if (m_currentNodeName == nnPosition) {
bone->position.x = ReadAttribute<float>(anX);
bone->position.y = ReadAttribute<float>(anY);
bone->position.z = ReadAttribute<float>(anZ);
}
else if (m_currentNodeName == nnRotation)
{
} else if (m_currentNodeName == nnRotation) {
float angle = ReadAttribute<float>("angle");
if (NextNode() != nnAxis) {
@ -953,17 +822,12 @@ void OgreXmlSerializer::ReadBones(Skeleton *skeleton)
axis.z = ReadAttribute<float>(anZ);
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!
if (HasAttribute("factor"))
{
if (HasAttribute("factor")) {
float factor = ReadAttribute<float>("factor");
bone->scale.Set(factor, factor, factor);
}
else
{
} else {
if (HasAttribute(anX))
bone->scale.x = ReadAttribute<float>(anX);
if (HasAttribute(anY))
@ -985,10 +849,9 @@ void OgreXmlSerializer::ReadBones(Skeleton *skeleton)
// Validate that bone indexes are not skipped.
/** @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. */
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];
ASSIMP_LOG_DEBUG_F( " ", b->id, " ", b->name);
ASSIMP_LOG_DEBUG_F(" ", b->id, " ", b->name);
if (b->id != static_cast<uint16_t>(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
} // Assimp
} // namespace Ogre
} // namespace Assimp
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER

View File

@ -1212,8 +1212,8 @@ void OpenGEXImporter::resolveReferences() {
if( RefInfo::MeshRef == currentRefInfo->m_type ) {
for( size_t i = 0; i < currentRefInfo->m_Names.size(); ++i ) {
const std::string &name( currentRefInfo->m_Names[ i ] );
ReferenceMap::const_iterator it( m_mesh2refMap.find( name ) );
if( m_mesh2refMap.end() != it ) {
ReferenceMap::const_iterator curIt( m_mesh2refMap.find( name ) );
if (m_mesh2refMap.end() != curIt) {
unsigned int meshIdx = static_cast<unsigned int>(m_mesh2refMap[ name ]);
node->mMeshes[ i ] = meshIdx;
}
@ -1221,8 +1221,8 @@ void OpenGEXImporter::resolveReferences() {
} else if( RefInfo::MaterialRef == currentRefInfo->m_type ) {
for ( size_t i = 0; i < currentRefInfo->m_Names.size(); ++i ) {
const std::string name( currentRefInfo->m_Names[ i ] );
ReferenceMap::const_iterator it( m_material2refMap.find( name ) );
if ( m_material2refMap.end() != it ) {
ReferenceMap::const_iterator curIt(m_material2refMap.find(name));
if (m_material2refMap.end() != curIt) {
if ( nullptr != m_currentMesh ) {
unsigned int matIdx = static_cast< unsigned int >( m_material2refMap[ name ] );
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
#include "PlyLoader.h"
#include <assimp/IOStreamBuffer.h>
#include <memory>
#include <assimp/IOSystem.hpp>
#include <assimp/scene.h>
#include <assimp/importerdesc.h>
#include <assimp/scene.h>
#include <assimp/IOSystem.hpp>
#include <memory>
using namespace ::Assimp;
@ -69,29 +69,25 @@ static const aiImporterDesc desc = {
"ply"
};
// ------------------------------------------------------------------------------------------------
// Internal stuff
namespace {
// ------------------------------------------------------------------------------------------------
// Checks that property index is within range
template <class T>
inline
const T &GetProperty(const std::vector<T> &props, int idx) {
if (static_cast<size_t>(idx) >= props.size()) {
throw DeadlyImportError("Invalid .ply file: Property index is out of range.");
}
return props[idx];
// ------------------------------------------------------------------------------------------------
// Checks that property index is within range
template <class T>
inline const T &GetProperty(const std::vector<T> &props, int idx) {
if (static_cast<size_t>(idx) >= props.size()) {
throw DeadlyImportError("Invalid .ply file: Property index is out of range.");
}
return props[idx];
}
} // namespace
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
PLYImporter::PLYImporter()
: mBuffer(nullptr)
, pcDOM(nullptr)
, mGeneratedMesh(nullptr) {
PLYImporter::PLYImporter() :
mBuffer(nullptr), pcDOM(nullptr), mGeneratedMesh(nullptr) {
// empty
}
@ -103,16 +99,16 @@ PLYImporter::~PLYImporter() {
// ------------------------------------------------------------------------------------------------
// 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);
if ( extension == "ply" ) {
if (extension == "ply") {
return true;
} else if (!extension.length() || checkSig) {
if ( !pIOHandler ) {
if (!pIOHandler) {
return true;
}
static const char* tokens[] = { "ply" };
static const char *tokens[] = { "ply" };
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;
}
// ------------------------------------------------------------------------------------------------
static bool isBigEndian(const char* szMe) {
static bool isBigEndian(const char *szMe) {
ai_assert(nullptr != szMe);
// binary_little_endian
// binary_big_endian
bool isBigEndian(false);
#if (defined AI_BUILD_BIG_ENDIAN)
if ( 'l' == *szMe || 'L' == *szMe ) {
if ('l' == *szMe || 'L' == *szMe) {
isBigEndian = true;
}
#else
@ -146,7 +142,7 @@ static bool isBigEndian(const char* szMe) {
// ------------------------------------------------------------------------------------------------
// 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";
std::unique_ptr<IOStream> fileStream(pIOHandler->Open(pFile, mode));
if (!fileStream.get()) {
@ -154,8 +150,8 @@ void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
}
// Get the file-size
const size_t fileSize( fileStream->FileSize() );
if ( 0 == fileSize ) {
const size_t fileSize(fileStream->FileSize());
if (0 == fileSize) {
throw DeadlyImportError("File " + pFile + " is empty.");
}
@ -169,17 +165,17 @@ void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
if ((headerCheck.size() < 3) ||
(headerCheck[0] != 'P' && headerCheck[0] != 'p') ||
(headerCheck[1] != 'L' && headerCheck[1] != 'l') ||
(headerCheck[2] != 'Y' && headerCheck[2] != 'y') ) {
(headerCheck[2] != 'Y' && headerCheck[2] != 'y')) {
streamedBuffer.close();
throw DeadlyImportError("Invalid .ply file: Magic number \'ply\' is no there");
}
std::vector<char> mBuffer2;
streamedBuffer.getNextLine(mBuffer2);
mBuffer = (unsigned char*)&mBuffer2[0];
mBuffer = (unsigned char *)&mBuffer2[0];
char* szMe = (char*)&this->mBuffer[0];
SkipSpacesAndLineEnd(szMe, (const char**)&szMe);
char *szMe = (char *)&this->mBuffer[0];
SkipSpacesAndLineEnd(szMe, (const char **)&szMe);
// determine the format of the file data and construct the aiMesh
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, "ascii", 5)) {
SkipLine(szMe, (const char**)&szMe);
SkipLine(szMe, (const char **)&szMe);
if (!PLY::DOM::ParseInstance(streamedBuffer, &sPlyDom, this)) {
if (mGeneratedMesh != nullptr) {
delete(mGeneratedMesh);
delete (mGeneratedMesh);
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
if (!PLY::DOM::ParseInstanceBinary(streamedBuffer, &sPlyDom, this, bIsBE)) {
if (mGeneratedMesh != nullptr) {
delete(mGeneratedMesh);
delete (mGeneratedMesh);
mGeneratedMesh = nullptr;
}
@ -213,7 +209,7 @@ void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
}
} else {
if (mGeneratedMesh != nullptr) {
delete(mGeneratedMesh);
delete (mGeneratedMesh);
mGeneratedMesh = nullptr;
}
@ -223,7 +219,7 @@ void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
} else {
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
if (mGeneratedMesh != nullptr) {
delete(mGeneratedMesh);
delete (mGeneratedMesh);
mGeneratedMesh = nullptr;
}
@ -242,24 +238,24 @@ void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
// list is containing a list of points
bool pointsOnly = mGeneratedMesh->mFaces == nullptr ? true : false;
if (pointsOnly) {
mGeneratedMesh->mPrimitiveTypes = aiPrimitiveType::aiPrimitiveType_POINT;
mGeneratedMesh->mPrimitiveTypes = aiPrimitiveType::aiPrimitiveType_POINT;
}
// now load a list of all materials
std::vector<aiMaterial*> avMaterials;
std::vector<aiMaterial *> avMaterials;
std::string defaultTexture;
LoadMaterial(&avMaterials, defaultTexture, pointsOnly);
// now generate the output scene object. Fill the material list
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) {
pScene->mMaterials[i] = avMaterials[i];
}
// fill the mesh list
pScene->mNumMeshes = 1;
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
pScene->mMeshes[0] = mGeneratedMesh;
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 != instElement);
@ -290,8 +286,8 @@ void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementIn
PLY::EDataType aiTexcoordTypes[2] = { EDT_Char, EDT_Char };
// now check whether which normal components are available
unsigned int _a( 0 ), cnt( 0 );
for ( std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
unsigned int _a(0), cnt(0);
for (std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
a != pcElement->alProperties.end(); ++a, ++_a) {
if ((*a).bIsList) {
continue;
@ -358,17 +354,17 @@ void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementIn
aiVector3D vOut;
if (0xFFFFFFFF != aiPositions[0]) {
vOut.x = PLY::PropertyInstance::ConvertTo<ai_real>(
GetProperty(instElement->alProperties, aiPositions[0]).avList.front(), aiTypes[0]);
GetProperty(instElement->alProperties, aiPositions[0]).avList.front(), aiTypes[0]);
}
if (0xFFFFFFFF != aiPositions[1]) {
vOut.y = PLY::PropertyInstance::ConvertTo<ai_real>(
GetProperty(instElement->alProperties, aiPositions[1]).avList.front(), aiTypes[1]);
GetProperty(instElement->alProperties, aiPositions[1]).avList.front(), aiTypes[1]);
}
if (0xFFFFFFFF != aiPositions[2]) {
vOut.z = PLY::PropertyInstance::ConvertTo<ai_real>(
GetProperty(instElement->alProperties, aiPositions[2]).avList.front(), aiTypes[2]);
GetProperty(instElement->alProperties, aiPositions[2]).avList.front(), aiTypes[2]);
}
// Normals
@ -376,19 +372,19 @@ void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementIn
bool haveNormal = false;
if (0xFFFFFFFF != aiNormal[0]) {
nOut.x = PLY::PropertyInstance::ConvertTo<ai_real>(
GetProperty(instElement->alProperties, aiNormal[0]).avList.front(), aiNormalTypes[0]);
GetProperty(instElement->alProperties, aiNormal[0]).avList.front(), aiNormalTypes[0]);
haveNormal = true;
}
if (0xFFFFFFFF != aiNormal[1]) {
nOut.y = PLY::PropertyInstance::ConvertTo<ai_real>(
GetProperty(instElement->alProperties, aiNormal[1]).avList.front(), aiNormalTypes[1]);
GetProperty(instElement->alProperties, aiNormal[1]).avList.front(), aiNormalTypes[1]);
haveNormal = true;
}
if (0xFFFFFFFF != aiNormal[2]) {
nOut.z = PLY::PropertyInstance::ConvertTo<ai_real>(
GetProperty(instElement->alProperties, aiNormal[2]).avList.front(), aiNormalTypes[2]);
GetProperty(instElement->alProperties, aiNormal[2]).avList.front(), aiNormalTypes[2]);
haveNormal = true;
}
@ -397,19 +393,25 @@ void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementIn
bool haveColor = false;
if (0xFFFFFFFF != aiColors[0]) {
cOut.r = NormalizeColorValue(GetProperty(instElement->alProperties,
aiColors[0]).avList.front(), aiColorsTypes[0]);
aiColors[0])
.avList.front(),
aiColorsTypes[0]);
haveColor = true;
}
if (0xFFFFFFFF != aiColors[1]) {
cOut.g = NormalizeColorValue(GetProperty(instElement->alProperties,
aiColors[1]).avList.front(), aiColorsTypes[1]);
aiColors[1])
.avList.front(),
aiColorsTypes[1]);
haveColor = true;
}
if (0xFFFFFFFF != aiColors[2]) {
cOut.b = NormalizeColorValue(GetProperty(instElement->alProperties,
aiColors[2]).avList.front(), aiColorsTypes[2]);
aiColors[2])
.avList.front(),
aiColorsTypes[2]);
haveColor = true;
}
@ -418,7 +420,9 @@ void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementIn
cOut.a = 1.0;
} else {
cOut.a = NormalizeColorValue(GetProperty(instElement->alProperties,
aiColors[3]).avList.front(), aiColorsTypes[3]);
aiColors[3])
.avList.front(),
aiColorsTypes[3]);
haveColor = true;
}
@ -429,18 +433,18 @@ void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementIn
bool haveTextureCoords = false;
if (0xFFFFFFFF != aiTexcoord[0]) {
tOut.x = PLY::PropertyInstance::ConvertTo<ai_real>(
GetProperty(instElement->alProperties, aiTexcoord[0]).avList.front(), aiTexcoordTypes[0]);
GetProperty(instElement->alProperties, aiTexcoord[0]).avList.front(), aiTexcoordTypes[0]);
haveTextureCoords = true;
}
if (0xFFFFFFFF != aiTexcoord[1]) {
tOut.y = PLY::PropertyInstance::ConvertTo<ai_real>(
GetProperty(instElement->alProperties, aiTexcoord[1]).avList.front(), aiTexcoordTypes[1]);
GetProperty(instElement->alProperties, aiTexcoord[1]).avList.front(), aiTexcoordTypes[1]);
haveTextureCoords = true;
}
//create aiMesh if needed
if ( nullptr == mGeneratedMesh ) {
if (nullptr == mGeneratedMesh) {
mGeneratedMesh = new aiMesh();
mGeneratedMesh->mMaterialIndex = 0;
}
@ -474,7 +478,6 @@ void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementIn
}
}
// ------------------------------------------------------------------------------------------------
// Convert a color component to [0...1]
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
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) {
ai_assert(nullptr != pcElement);
ai_assert(nullptr != instElement);
@ -586,16 +589,16 @@ void PLYImporter::LoadFace(const PLY::Element* pcElement, const PLY::ElementInst
mGeneratedMesh->mFaces[pos].mIndices = new unsigned int[iNum];
std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator p =
GetProperty(instElement->alProperties, iProperty).avList.begin();
GetProperty(instElement->alProperties, iProperty).avList.begin();
for (unsigned int a = 0; a < iNum; ++a, ++p) {
mGeneratedMesh->mFaces[pos].mIndices[a] = PLY::PropertyInstance::ConvertTo<unsigned int>(*p, eType);
}
}
// parse the material index
// cannot be handled without processing the whole file first
/*if (0xFFFFFFFF != iMaterialIndex)
// parse the material index
// cannot be handled without processing the whole file first
/*if (0xFFFFFFFF != iMaterialIndex)
{
mGeneratedMesh->mFaces[pos]. = PLY::PropertyInstance::ConvertTo<unsigned int>(
GetProperty(instElement->alProperties, iMaterialIndex).avList.front(), eType2);
@ -606,14 +609,14 @@ void PLYImporter::LoadFace(const PLY::Element* pcElement, const PLY::ElementInst
//should be 6 coords
std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator p =
GetProperty(instElement->alProperties, iTextureCoord).avList.begin();
GetProperty(instElement->alProperties, iTextureCoord).avList.begin();
if ((iNum / 3) == 2) // X Y coord
{
for (unsigned int a = 0; a < iNum; ++a, ++p) {
unsigned int vindex = mGeneratedMesh->mFaces[pos].mIndices[a / 2];
if (vindex < mGeneratedMesh->mNumVertices) {
if (mGeneratedMesh->mTextureCoords[0] == nullptr ) {
if (mGeneratedMesh->mTextureCoords[0] == nullptr) {
mGeneratedMesh->mNumUVComponents[0] = 2;
mGeneratedMesh->mTextureCoords[0] = new aiVector3D[mGeneratedMesh->mNumVertices];
}
@ -633,11 +636,11 @@ void PLYImporter::LoadFace(const PLY::Element* pcElement, const PLY::ElementInst
// normally we have only one triangle strip instance where
// a value of -1 indicates a restart of the strip
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
int aiTable[2] = { -1, -1 };
for (std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator a = quak.begin(); a != quak.end(); ++a) {
for (std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator a = quak.begin(); a != quak.end(); ++a) {
const int p = PLY::PropertyInstance::ConvertTo<int>(*a, eType);
if (-1 == p) {
@ -668,7 +671,7 @@ void PLYImporter::LoadFace(const PLY::Element* pcElement, const PLY::ElementInst
// every second pass swap the indices.
flip = !flip;
if ( flip ) {
if (flip) {
std::swap(mGeneratedMesh->mFaces[pos].mIndices[0], mGeneratedMesh->mFaces[pos].mIndices[1]);
}
@ -681,285 +684,254 @@ void PLYImporter::LoadFace(const PLY::Element* pcElement, const PLY::ElementInst
// ------------------------------------------------------------------------------------------------
// Get a RGBA color in [0...1] range
void PLYImporter::GetMaterialColor(const std::vector<PLY::PropertyInstance>& avList,
unsigned int aiPositions[4],
PLY::EDataType aiTypes[4],
aiColor4D* clrOut)
{
ai_assert(NULL != clrOut);
void PLYImporter::GetMaterialColor(const std::vector<PLY::PropertyInstance> &avList,
unsigned int aiPositions[4],
PLY::EDataType aiTypes[4],
aiColor4D *clrOut) {
ai_assert(NULL != clrOut);
if (0xFFFFFFFF == aiPositions[0])clrOut->r = 0.0f;
else
{
clrOut->r = NormalizeColorValue(GetProperty(avList,
aiPositions[0]).avList.front(), aiTypes[0]);
}
if (0xFFFFFFFF == aiPositions[0])
clrOut->r = 0.0f;
else {
clrOut->r = NormalizeColorValue(GetProperty(avList,
aiPositions[0])
.avList.front(),
aiTypes[0]);
}
if (0xFFFFFFFF == aiPositions[1])clrOut->g = 0.0f;
else
{
clrOut->g = NormalizeColorValue(GetProperty(avList,
aiPositions[1]).avList.front(), aiTypes[1]);
}
if (0xFFFFFFFF == aiPositions[1])
clrOut->g = 0.0f;
else {
clrOut->g = NormalizeColorValue(GetProperty(avList,
aiPositions[1])
.avList.front(),
aiTypes[1]);
}
if (0xFFFFFFFF == aiPositions[2])clrOut->b = 0.0f;
else
{
clrOut->b = NormalizeColorValue(GetProperty(avList,
aiPositions[2]).avList.front(), aiTypes[2]);
}
if (0xFFFFFFFF == aiPositions[2])
clrOut->b = 0.0f;
else {
clrOut->b = NormalizeColorValue(GetProperty(avList,
aiPositions[2])
.avList.front(),
aiTypes[2]);
}
// assume 1.0 for the alpha channel ifit is not set
if (0xFFFFFFFF == aiPositions[3])clrOut->a = 1.0f;
else
{
clrOut->a = NormalizeColorValue(GetProperty(avList,
aiPositions[3]).avList.front(), aiTypes[3]);
}
// assume 1.0 for the alpha channel ifit is not set
if (0xFFFFFFFF == aiPositions[3])
clrOut->a = 1.0f;
else {
clrOut->a = NormalizeColorValue(GetProperty(avList,
aiPositions[3])
.avList.front(),
aiTypes[3]);
}
}
// ------------------------------------------------------------------------------------------------
// Extract a material from the PLY DOM
void PLYImporter::LoadMaterial(std::vector<aiMaterial*>* pvOut, std::string &defaultTexture, const bool pointsOnly)
{
ai_assert(NULL != pvOut);
void PLYImporter::LoadMaterial(std::vector<aiMaterial *> *pvOut, std::string &defaultTexture, const bool pointsOnly) {
ai_assert(NULL != pvOut);
// diffuse[4], specular[4], ambient[4]
// rgba order
unsigned int aaiPositions[3][4] = {
// diffuse[4], specular[4], ambient[4]
// rgba order
unsigned int aaiPositions[3][4] = {
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF },
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF },
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF },
};
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF },
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF },
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF },
};
PLY::EDataType aaiTypes[3][4] = {
{ 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::EDataType aaiTypes[3][4] = {
{ 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;
unsigned int iPhong = 0xFFFFFFFF;
PLY::EDataType ePhong = EDT_Char;
unsigned int iPhong = 0xFFFFFFFF;
PLY::EDataType ePhong = EDT_Char;
unsigned int iOpacity = 0xFFFFFFFF;
PLY::EDataType eOpacity = EDT_Char;
unsigned int iOpacity = 0xFFFFFFFF;
PLY::EDataType eOpacity = EDT_Char;
// search in the DOM for a vertex entry
unsigned int _i = 0;
for (std::vector<PLY::Element>::const_iterator i = this->pcDOM->alElements.begin();
i != this->pcDOM->alElements.end(); ++i, ++_i)
{
if (PLY::EEST_Material == (*i).eSemantic)
{
pcList = &this->pcDOM->alElementData[_i];
// search in the DOM for a vertex entry
unsigned int _i = 0;
for (std::vector<PLY::Element>::const_iterator i = this->pcDOM->alElements.begin();
i != this->pcDOM->alElements.end(); ++i, ++_i) {
if (PLY::EEST_Material == (*i).eSemantic) {
pcList = &this->pcDOM->alElementData[_i];
// now check whether which coordinate sets are available
unsigned int _a = 0;
for (std::vector<PLY::Property>::const_iterator
a = (*i).alProperties.begin();
a != (*i).alProperties.end(); ++a, ++_a)
{
if ((*a).bIsList)continue;
// now check whether which coordinate sets are available
unsigned int _a = 0;
for (std::vector<PLY::Property>::const_iterator
a = (*i).alProperties.begin();
a != (*i).alProperties.end(); ++a, ++_a) {
if ((*a).bIsList) continue;
// pohng specularity -----------------------------------
if (PLY::EST_PhongPower == (*a).Semantic)
{
iPhong = _a;
ePhong = (*a).eType;
}
// pohng specularity -----------------------------------
if (PLY::EST_PhongPower == (*a).Semantic) {
iPhong = _a;
ePhong = (*a).eType;
}
// general opacity -----------------------------------
if (PLY::EST_Opacity == (*a).Semantic)
{
iOpacity = _a;
eOpacity = (*a).eType;
}
// general opacity -----------------------------------
if (PLY::EST_Opacity == (*a).Semantic) {
iOpacity = _a;
eOpacity = (*a).eType;
}
// diffuse color channels -----------------------------------
if (PLY::EST_DiffuseRed == (*a).Semantic)
{
aaiPositions[0][0] = _a;
aaiTypes[0][0] = (*a).eType;
// diffuse color channels -----------------------------------
if (PLY::EST_DiffuseRed == (*a).Semantic) {
aaiPositions[0][0] = _a;
aaiTypes[0][0] = (*a).eType;
} else if (PLY::EST_DiffuseGreen == (*a).Semantic) {
aaiPositions[0][1] = _a;
aaiTypes[0][1] = (*a).eType;
} else if (PLY::EST_DiffuseBlue == (*a).Semantic) {
aaiPositions[0][2] = _a;
aaiTypes[0][2] = (*a).eType;
} else if (PLY::EST_DiffuseAlpha == (*a).Semantic) {
aaiPositions[0][3] = _a;
aaiTypes[0][3] = (*a).eType;
}
// specular color channels -----------------------------------
else if (PLY::EST_SpecularRed == (*a).Semantic) {
aaiPositions[1][0] = _a;
aaiTypes[1][0] = (*a).eType;
} else if (PLY::EST_SpecularGreen == (*a).Semantic) {
aaiPositions[1][1] = _a;
aaiTypes[1][1] = (*a).eType;
} else if (PLY::EST_SpecularBlue == (*a).Semantic) {
aaiPositions[1][2] = _a;
aaiTypes[1][2] = (*a).eType;
} else if (PLY::EST_SpecularAlpha == (*a).Semantic) {
aaiPositions[1][3] = _a;
aaiTypes[1][3] = (*a).eType;
}
// ambient color channels -----------------------------------
else if (PLY::EST_AmbientRed == (*a).Semantic) {
aaiPositions[2][0] = _a;
aaiTypes[2][0] = (*a).eType;
} else if (PLY::EST_AmbientGreen == (*a).Semantic) {
aaiPositions[2][1] = _a;
aaiTypes[2][1] = (*a).eType;
} else if (PLY::EST_AmbientBlue == (*a).Semantic) {
aaiPositions[2][2] = _a;
aaiTypes[2][2] = (*a).eType;
} else if (PLY::EST_AmbientAlpha == (*a).Semantic) {
aaiPositions[2][3] = _a;
aaiTypes[2][3] = (*a).eType;
}
}
break;
} else if (PLY::EEST_TextureFile == (*i).eSemantic) {
defaultTexture = (*i).szName;
}
else if (PLY::EST_DiffuseGreen == (*a).Semantic)
{
aaiPositions[0][1] = _a;
aaiTypes[0][1] = (*a).eType;
}
else if (PLY::EST_DiffuseBlue == (*a).Semantic)
{
aaiPositions[0][2] = _a;
aaiTypes[0][2] = (*a).eType;
}
else if (PLY::EST_DiffuseAlpha == (*a).Semantic)
{
aaiPositions[0][3] = _a;
aaiTypes[0][3] = (*a).eType;
}
// specular color channels -----------------------------------
else if (PLY::EST_SpecularRed == (*a).Semantic)
{
aaiPositions[1][0] = _a;
aaiTypes[1][0] = (*a).eType;
}
else if (PLY::EST_SpecularGreen == (*a).Semantic)
{
aaiPositions[1][1] = _a;
aaiTypes[1][1] = (*a).eType;
}
else if (PLY::EST_SpecularBlue == (*a).Semantic)
{
aaiPositions[1][2] = _a;
aaiTypes[1][2] = (*a).eType;
}
else if (PLY::EST_SpecularAlpha == (*a).Semantic)
{
aaiPositions[1][3] = _a;
aaiTypes[1][3] = (*a).eType;
}
// ambient color channels -----------------------------------
else if (PLY::EST_AmbientRed == (*a).Semantic)
{
aaiPositions[2][0] = _a;
aaiTypes[2][0] = (*a).eType;
}
else if (PLY::EST_AmbientGreen == (*a).Semantic)
{
aaiPositions[2][1] = _a;
aaiTypes[2][1] = (*a).eType;
}
else if (PLY::EST_AmbientBlue == (*a).Semantic)
{
aaiPositions[2][2] = _a;
aaiTypes[2][2] = (*a).eType;
}
else if (PLY::EST_AmbientAlpha == (*a).Semantic)
{
aaiPositions[2][3] = _a;
aaiTypes[2][3] = (*a).eType;
}
}
break;
}
else if (PLY::EEST_TextureFile == (*i).eSemantic)
{
defaultTexture = (*i).szName;
}
}
// check whether we have a valid source for the material data
if (NULL != pcList) {
for (std::vector<ElementInstance>::const_iterator i = pcList->alInstances.begin(); i != pcList->alInstances.end(); ++i) {
aiColor4D clrOut;
aiMaterial* pcHelper = new aiMaterial();
// check whether we have a valid source for the material data
if (NULL != pcList) {
for (std::vector<ElementInstance>::const_iterator i = pcList->alInstances.begin(); i != pcList->alInstances.end(); ++i) {
aiColor4D clrOut;
aiMaterial *pcHelper = new aiMaterial();
// build the diffuse material color
GetMaterialColor((*i).alProperties, aaiPositions[0], aaiTypes[0], &clrOut);
pcHelper->AddProperty<aiColor4D>(&clrOut, 1, AI_MATKEY_COLOR_DIFFUSE);
// build the diffuse material color
GetMaterialColor((*i).alProperties, aaiPositions[0], aaiTypes[0], &clrOut);
pcHelper->AddProperty<aiColor4D>(&clrOut, 1, AI_MATKEY_COLOR_DIFFUSE);
// build the specular material color
GetMaterialColor((*i).alProperties, aaiPositions[1], aaiTypes[1], &clrOut);
pcHelper->AddProperty<aiColor4D>(&clrOut, 1, AI_MATKEY_COLOR_SPECULAR);
// build the specular material color
GetMaterialColor((*i).alProperties, aaiPositions[1], aaiTypes[1], &clrOut);
pcHelper->AddProperty<aiColor4D>(&clrOut, 1, AI_MATKEY_COLOR_SPECULAR);
// build the ambient material color
GetMaterialColor((*i).alProperties, aaiPositions[2], aaiTypes[2], &clrOut);
pcHelper->AddProperty<aiColor4D>(&clrOut, 1, AI_MATKEY_COLOR_AMBIENT);
// build the ambient material color
GetMaterialColor((*i).alProperties, aaiPositions[2], aaiTypes[2], &clrOut);
pcHelper->AddProperty<aiColor4D>(&clrOut, 1, AI_MATKEY_COLOR_AMBIENT);
// handle phong power and shading mode
int iMode = (int)aiShadingMode_Gouraud;
if (0xFFFFFFFF != iPhong) {
ai_real fSpec = PLY::PropertyInstance::ConvertTo<ai_real>(GetProperty((*i).alProperties, iPhong).avList.front(), ePhong);
// handle phong power and shading mode
int iMode = (int)aiShadingMode_Gouraud;
if (0xFFFFFFFF != iPhong) {
ai_real fSpec = PLY::PropertyInstance::ConvertTo<ai_real>(GetProperty((*i).alProperties, iPhong).avList.front(), ePhong);
// if shininess is 0 (and the pow() calculation would therefore always
// become 1, not depending on the angle), use gouraud lighting
if (fSpec) {
// scale this with 15 ... hopefully this is correct
fSpec *= 15;
pcHelper->AddProperty<ai_real>(&fSpec, 1, AI_MATKEY_SHININESS);
// if shininess is 0 (and the pow() calculation would therefore always
// become 1, not depending on the angle), use gouraud lighting
if (fSpec) {
// scale this with 15 ... hopefully this is correct
fSpec *= 15;
pcHelper->AddProperty<ai_real>(&fSpec, 1, AI_MATKEY_SHININESS);
iMode = (int)aiShadingMode_Phong;
iMode = (int)aiShadingMode_Phong;
}
}
pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
// handle opacity
if (0xFFFFFFFF != iOpacity) {
ai_real fOpacity = PLY::PropertyInstance::ConvertTo<ai_real>(GetProperty((*i).alProperties, iPhong).avList.front(), eOpacity);
pcHelper->AddProperty<ai_real>(&fOpacity, 1, AI_MATKEY_OPACITY);
}
// The face order is absolutely undefined for PLY, so we have to
// use two-sided rendering to be sure it's ok.
const int two_sided = 1;
pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED);
//default texture
if (!defaultTexture.empty()) {
const aiString name(defaultTexture.c_str());
pcHelper->AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE, 0);
}
if (!pointsOnly) {
pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED);
}
//set to wireframe, so when using this material info we can switch to points rendering
if (pointsOnly) {
const int wireframe = 1;
pcHelper->AddProperty(&wireframe, 1, AI_MATKEY_ENABLE_WIREFRAME);
}
// add the newly created material instance to the list
pvOut->push_back(pcHelper);
}
}
pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
} else {
// generate a default material
aiMaterial *pcHelper = new aiMaterial();
// handle opacity
if (0xFFFFFFFF != iOpacity) {
ai_real fOpacity = PLY::PropertyInstance::ConvertTo<ai_real>(GetProperty((*i).alProperties, iPhong).avList.front(), eOpacity);
pcHelper->AddProperty<ai_real>(&fOpacity, 1, AI_MATKEY_OPACITY);
}
// fill in a default material
int iMode = (int)aiShadingMode_Gouraud;
pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
// The face order is absolutely undefined for PLY, so we have to
// use two-sided rendering to be sure it's ok.
const int two_sided = 1;
pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED);
//generate white material most 3D engine just multiply ambient / diffuse color with actual ambient / light color
aiColor3D clr;
clr.b = clr.g = clr.r = 1.0f;
pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
//default texture
if (!defaultTexture.empty())
{
const aiString name(defaultTexture.c_str());
pcHelper->AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE, 0);
}
clr.b = clr.g = clr.r = 1.0f;
pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
if (!pointsOnly)
{
const int two_sided = 1;
pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED);
}
// The face order is absolutely undefined for PLY, so we have to
// use two-sided rendering to be sure it's ok.
if (!pointsOnly) {
const int two_sided = 1;
pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED);
}
//set to wireframe, so when using this material info we can switch to points rendering
if (pointsOnly)
{
const int wireframe = 1;
pcHelper->AddProperty(&wireframe, 1, AI_MATKEY_ENABLE_WIREFRAME);
}
//default texture
if (!defaultTexture.empty()) {
const aiString name(defaultTexture.c_str());
pcHelper->AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE, 0);
}
// add the newly created material instance to the list
pvOut->push_back(pcHelper);
//set to wireframe, so when using this material info we can switch to points rendering
if (pointsOnly) {
const int wireframe = 1;
pcHelper->AddProperty(&wireframe, 1, AI_MATKEY_ENABLE_WIREFRAME);
}
pvOut->push_back(pcHelper);
}
}
else
{
// generate a default material
aiMaterial* pcHelper = new aiMaterial();
// fill in a default material
int iMode = (int)aiShadingMode_Gouraud;
pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
//generate white material most 3D engine just multiply ambient / diffuse color with actual ambient / light color
aiColor3D clr;
clr.b = clr.g = clr.r = 1.0f;
pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
clr.b = clr.g = clr.r = 1.0f;
pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
// The face order is absolutely undefined for PLY, so we have to
// use two-sided rendering to be sure it's ok.
if (!pointsOnly)
{
const int two_sided = 1;
pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED);
}
//default texture
if (!defaultTexture.empty())
{
const aiString name(defaultTexture.c_str());
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
if (pointsOnly)
{
const int wireframe = 1;
pcHelper->AddProperty(&wireframe, 1, AI_MATKEY_ENABLE_WIREFRAME);
}
pvOut->push_back(pcHelper);
}
}
#endif // !! ASSIMP_BUILD_NO_PLY_IMPORTER

View File

@ -137,7 +137,7 @@ bool EmbedTexturesProcess::addTexture(aiScene* pScene, std::string path) const {
pTexture->pcData = imageContent;
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") {
extension = "jpg";
}

View File

@ -105,7 +105,8 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
if (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);
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();
it != end; ++it, ++faces)
{
Mesh& m = meshes[(*it).first];
Face& face = m.faces[(*it).second];
Mesh& curMesh = meshes[(*it).first];
Face &face = curMesh.faces[(*it).second];
faces->mNumIndices = (unsigned int)face.indices.size();
faces->mIndices = new unsigned int [faces->mNumIndices];
@ -528,29 +528,30 @@ outer:
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");
face.indices[n] = 0;
}
// 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
if (!fnOK)
{
const aiVector3D& pV1 = m.verts[ face.indices[0] ];
const aiVector3D& pV2 = m.verts[ face.indices[1] ];
const aiVector3D& pV3 = m.verts[ face.indices.size() - 1 ];
const aiVector3D &pV1 = curMesh.verts[face.indices[0]];
const aiVector3D &pV2 = curMesh.verts[face.indices[1]];
const aiVector3D &pV3 = curMesh.verts[face.indices.size() - 1];
faceNormal = (pV2 - pV1) ^ (pV3 - pV1).Normalize();
fnOK = true;
}
*norms = faceNormal;
} else {
*norms = curMesh.normals[face.indices[n]];
}
else *norms = m.normals[ face.indices[n] ];
// copy texture coordinates
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;
ret.resize(len);
std::transform(s,s+len,ret.begin(),::tolower);
std::transform(s, s + len, ret.begin(), ::ToLower<char>);
return ret;
}
@ -618,26 +617,22 @@ bool XGLImporter::ReadMesh(TempScope& scope)
bool has[3] = {0};
while (ReadElementUpToClosing(s.c_str())) {
const std::string& s = GetElementName();
if (s == "fv1" || s == "lv1" || s == "pv1") {
const std::string& elemName = GetElementName();
if (elemName == "fv1" || elemName == "lv1" || elemName == "pv1") {
ReadFaceVertex(t,tf[0]);
has[0] = true;
}
else if (s == "fv2" || s == "lv2") {
ReadFaceVertex(t,tf[1]);
} else if (elemName == "fv2" || elemName == "lv2") {
ReadFaceVertex(t, tf[1]);
has[1] = true;
}
else if (s == "fv3") {
ReadFaceVertex(t,tf[2]);
} else if (elemName == "fv3") {
ReadFaceVertex(t, tf[2]);
has[2] = true;
}
else if (s == "mat") {
} else if (elemName == "mat") {
if (mid != ~0u) {
LogWarn("only one material tag allowed per <f>");
}
mid = ResolveMaterialRef(scope);
}
else if (s == "matref") {
} else if (elemName == "matref") {
if (mid != ~0u) {
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
All rights reserved.
Redistribution and use of this software in source and binary forms,