diff --git a/code/Assjson/cencode.c b/code/Assjson/cencode.c new file mode 100644 index 000000000..db99e7efa --- /dev/null +++ b/code/Assjson/cencode.c @@ -0,0 +1,109 @@ +/* +cencoder.c - c source to a base64 encoding algorithm implementation + +This is part of the libb64 project, and has been placed in the public domain. +For details, see http://sourceforge.net/projects/libb64 +*/ + +#include "cencode.h" // changed from + +const int CHARS_PER_LINE = 72; + +void base64_init_encodestate(base64_encodestate* state_in) +{ + state_in->step = step_A; + state_in->result = 0; + state_in->stepcount = 0; +} + +char base64_encode_value(char value_in) +{ + static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + if (value_in > 63) return '='; + return encoding[(int)value_in]; +} + +int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in) +{ + const char* plainchar = plaintext_in; + const char* const plaintextend = plaintext_in + length_in; + char* codechar = code_out; + char result; + char fragment; + + result = state_in->result; + + switch (state_in->step) + { + while (1) + { + case step_A: + if (plainchar == plaintextend) + { + state_in->result = result; + state_in->step = step_A; + return codechar - code_out; + } + fragment = *plainchar++; + result = (fragment & 0x0fc) >> 2; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x003) << 4; + case step_B: + if (plainchar == plaintextend) + { + state_in->result = result; + state_in->step = step_B; + return codechar - code_out; + } + fragment = *plainchar++; + result |= (fragment & 0x0f0) >> 4; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x00f) << 2; + case step_C: + if (plainchar == plaintextend) + { + state_in->result = result; + state_in->step = step_C; + return codechar - code_out; + } + fragment = *plainchar++; + result |= (fragment & 0x0c0) >> 6; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x03f) >> 0; + *codechar++ = base64_encode_value(result); + + ++(state_in->stepcount); + if (state_in->stepcount == CHARS_PER_LINE/4) + { + *codechar++ = '\n'; + state_in->stepcount = 0; + } + } + } + /* control should not reach here */ + return codechar - code_out; +} + +int base64_encode_blockend(char* code_out, base64_encodestate* state_in) +{ + char* codechar = code_out; + + switch (state_in->step) + { + case step_B: + *codechar++ = base64_encode_value(state_in->result); + *codechar++ = '='; + *codechar++ = '='; + break; + case step_C: + *codechar++ = base64_encode_value(state_in->result); + *codechar++ = '='; + break; + case step_A: + break; + } + *codechar++ = '\n'; + + return codechar - code_out; +} + diff --git a/code/Assjson/cencode.h b/code/Assjson/cencode.h new file mode 100644 index 000000000..c1e3464af --- /dev/null +++ b/code/Assjson/cencode.h @@ -0,0 +1,31 @@ +/* +cencode.h - c header for a base64 encoding algorithm + +This is part of the libb64 project, and has been placed in the public domain. +For details, see http://sourceforge.net/projects/libb64 +*/ + +#ifndef BASE64_CENCODE_H +#define BASE64_CENCODE_H + +typedef enum +{ + step_A, step_B, step_C +} base64_encodestep; + +typedef struct +{ + base64_encodestep step; + char result; + int stepcount; +} base64_encodestate; + +void base64_init_encodestate(base64_encodestate* state_in); + +char base64_encode_value(char value_in); + +int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in); + +int base64_encode_blockend(char* code_out, base64_encodestate* state_in); + +#endif /* BASE64_CENCODE_H */ diff --git a/code/Assjson/json_exporter.cpp b/code/Assjson/json_exporter.cpp new file mode 100644 index 000000000..cd542b29e --- /dev/null +++ b/code/Assjson/json_exporter.cpp @@ -0,0 +1,818 @@ +/* +Assimp2Json +Copyright (c) 2011, Alexander C. Gessler + +Licensed under a 3-clause BSD license. See the LICENSE file for more information. + +*/ + +#ifndef ASSIMP_BUILD_NO_EXPORT +#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define CURRENT_FORMAT_VERSION 100 + +// grab scoped_ptr from assimp to avoid a dependency on boost. +//#include + +#include "mesh_splitter.h" + +extern "C" { + #include "cencode.h" +} +namespace Assimp { + +void ExportAssimp2Json(const char*, Assimp::IOSystem*, const aiScene*, const Assimp::ExportProperties*); + +Exporter::ExportFormatEntry Assimp2Json_desc = Assimp::Exporter::ExportFormatEntry( + "json", + "Plain JSON representation of the Assimp scene data structure", + "json", + &ExportAssimp2Json, + 0u +); + + +// small utility class to simplify serializing the aiScene to Json +class JSONWriter { +public: + enum { + Flag_DoNotIndent = 0x1, + Flag_WriteSpecialFloats = 0x2, + }; + + JSONWriter(Assimp::IOStream& out, unsigned int flags = 0u) + : out(out) + , first() + , flags(flags) { + // make sure that all formatting happens using the standard, C locale and not the user's current locale + buff.imbue(std::locale("C")); + } + + ~JSONWriter() { + Flush(); + } + + void Flush() { + const std::string s = buff.str(); + out.Write(s.c_str(), s.length(), 1); + buff.clear(); + } + + void PushIndent() { + indent += '\t'; + } + + void PopIndent() { + indent.erase(indent.end() - 1); + } + + void Key(const std::string& name) { + AddIndentation(); + Delimit(); + buff << '\"' + name + "\": "; + } + + template + void Element(const Literal& name) { + AddIndentation(); + Delimit(); + + LiteralToString(buff, name) << '\n'; + } + + template + void SimpleValue(const Literal& s) { + LiteralToString(buff, s) << '\n'; + } + + void SimpleValue(const void* buffer, size_t len) { + base64_encodestate s; + base64_init_encodestate(&s); + + char* const out = new char[std::max(len * 2, static_cast(16u))]; + const int n = base64_encode_block(reinterpret_cast(buffer), static_cast(len), out, &s); + out[n + base64_encode_blockend(out + n, &s)] = '\0'; + + // base64 encoding may add newlines, but JSON strings may not contain 'real' newlines + // (only escaped ones). Remove any newlines in out. + for (char* cur = out; *cur; ++cur) { + if (*cur == '\n') { + *cur = ' '; + } + } + + buff << '\"' << out << "\"\n"; + delete[] out; + } + + void StartObj(bool is_element = false) { + // if this appears as a plain array element, we need to insert a delimiter and we should also indent it + if (is_element) { + AddIndentation(); + if (!first) { + buff << ','; + } + } + first = true; + buff << "{\n"; + PushIndent(); + } + + void EndObj() { + PopIndent(); + AddIndentation(); + first = false; + buff << "}\n"; + } + + void StartArray(bool is_element = false) { + // if this appears as a plain array element, we need to insert a delimiter and we should also indent it + if (is_element) { + AddIndentation(); + if (!first) { + buff << ','; + } + } + first = true; + buff << "[\n"; + PushIndent(); + } + + void EndArray() { + PopIndent(); + AddIndentation(); + buff << "]\n"; + first = false; + } + + void AddIndentation() { + if (!(flags & Flag_DoNotIndent)) { + buff << indent; + } + } + + void Delimit() { + if (!first) { + buff << ','; + } + else { + buff << ' '; + first = false; + } + } + +private: + template + std::stringstream& LiteralToString(std::stringstream& stream, const Literal& s) { + stream << s; + return stream; + } + + std::stringstream& LiteralToString(std::stringstream& stream, const aiString& s) { + std::string t; + + // escape backslashes and single quotes, both would render the JSON invalid if left as is + t.reserve(s.length); + for (size_t i = 0; i < s.length; ++i) { + + if (s.data[i] == '\\' || s.data[i] == '\'' || s.data[i] == '\"') { + t.push_back('\\'); + } + + t.push_back(s.data[i]); + } + stream << "\""; + stream << t; + stream << "\""; + return stream; + } + + std::stringstream& LiteralToString(std::stringstream& stream, float f) { + if (!std::numeric_limits::is_iec559) { + // on a non IEEE-754 platform, we make no assumptions about the representation or existence + // of special floating-point numbers. + stream << f; + return stream; + } + + // JSON does not support writing Inf/Nan + // [RFC 4672: "Numeric values that cannot be represented as sequences of digits + // (such as Infinity and NaN) are not permitted."] + // Nevertheless, many parsers will accept the special keywords Infinity, -Infinity and NaN + if (std::numeric_limits::infinity() == fabs(f)) { + if (flags & Flag_WriteSpecialFloats) { + stream << (f < 0 ? "\"-" : "\"") + std::string("Infinity\""); + return stream; + } + // we should print this warning, but we can't - this is called from within a generic assimp exporter, we cannot use cerr + // std::cerr << "warning: cannot represent infinite number literal, substituting 0 instead (use -i flag to enforce Infinity/NaN)" << std::endl; + stream << "0.0"; + return stream; + } + // f!=f is the most reliable test for NaNs that I know of + else if (f != f) { + if (flags & Flag_WriteSpecialFloats) { + stream << "\"NaN\""; + return stream; + } + // we should print this warning, but we can't - this is called from within a generic assimp exporter, we cannot use cerr + // std::cerr << "warning: cannot represent infinite number literal, substituting 0 instead (use -i flag to enforce Infinity/NaN)" << std::endl; + stream << "0.0"; + return stream; + } + + stream << f; + return stream; + } + +private: + Assimp::IOStream& out; + std::string indent, newline; + std::stringstream buff; + bool first; + + unsigned int flags; +}; + +void Write(JSONWriter& out, const aiVector3D& ai, bool is_elem = true) { + out.StartArray(is_elem); + out.Element(ai.x); + out.Element(ai.y); + out.Element(ai.z); + out.EndArray(); +} + +void Write(JSONWriter& out, const aiQuaternion& ai, bool is_elem = true) { + out.StartArray(is_elem); + out.Element(ai.w); + out.Element(ai.x); + out.Element(ai.y); + out.Element(ai.z); + out.EndArray(); +} + +void Write(JSONWriter& out, const aiColor3D& ai, bool is_elem = true) { + out.StartArray(is_elem); + out.Element(ai.r); + out.Element(ai.g); + out.Element(ai.b); + out.EndArray(); +} + +void Write(JSONWriter& out, const aiMatrix4x4& ai, bool is_elem = true) { + out.StartArray(is_elem); + for (unsigned int x = 0; x < 4; ++x) { + for (unsigned int y = 0; y < 4; ++y) { + out.Element(ai[x][y]); + } + } + out.EndArray(); +} + +void Write(JSONWriter& out, const aiBone& ai, bool is_elem = true) { + out.StartObj(is_elem); + + out.Key("name"); + out.SimpleValue(ai.mName); + + out.Key("offsetmatrix"); + Write(out, ai.mOffsetMatrix, false); + + out.Key("weights"); + out.StartArray(); + for (unsigned int i = 0; i < ai.mNumWeights; ++i) { + out.StartArray(true); + out.Element(ai.mWeights[i].mVertexId); + out.Element(ai.mWeights[i].mWeight); + out.EndArray(); + } + out.EndArray(); + out.EndObj(); +} + +void Write(JSONWriter& out, const aiFace& ai, bool is_elem = true) { + out.StartArray(is_elem); + for (unsigned int i = 0; i < ai.mNumIndices; ++i) { + out.Element(ai.mIndices[i]); + } + out.EndArray(); +} + +void Write(JSONWriter& out, const aiMesh& ai, bool is_elem = true) { + out.StartObj(is_elem); + + out.Key("name"); + out.SimpleValue(ai.mName); + + out.Key("materialindex"); + out.SimpleValue(ai.mMaterialIndex); + + out.Key("primitivetypes"); + out.SimpleValue(ai.mPrimitiveTypes); + + out.Key("vertices"); + out.StartArray(); + for (unsigned int i = 0; i < ai.mNumVertices; ++i) { + out.Element(ai.mVertices[i].x); + out.Element(ai.mVertices[i].y); + out.Element(ai.mVertices[i].z); + } + out.EndArray(); + + if (ai.HasNormals()) { + out.Key("normals"); + out.StartArray(); + for (unsigned int i = 0; i < ai.mNumVertices; ++i) { + out.Element(ai.mNormals[i].x); + out.Element(ai.mNormals[i].y); + out.Element(ai.mNormals[i].z); + } + out.EndArray(); + } + + if (ai.HasTangentsAndBitangents()) { + out.Key("tangents"); + out.StartArray(); + for (unsigned int i = 0; i < ai.mNumVertices; ++i) { + out.Element(ai.mTangents[i].x); + out.Element(ai.mTangents[i].y); + out.Element(ai.mTangents[i].z); + } + out.EndArray(); + + out.Key("bitangents"); + out.StartArray(); + for (unsigned int i = 0; i < ai.mNumVertices; ++i) { + out.Element(ai.mBitangents[i].x); + out.Element(ai.mBitangents[i].y); + out.Element(ai.mBitangents[i].z); + } + out.EndArray(); + } + + if (ai.GetNumUVChannels()) { + out.Key("numuvcomponents"); + out.StartArray(); + for (unsigned int n = 0; n < ai.GetNumUVChannels(); ++n) { + out.Element(ai.mNumUVComponents[n]); + } + out.EndArray(); + + out.Key("texturecoords"); + out.StartArray(); + for (unsigned int n = 0; n < ai.GetNumUVChannels(); ++n) { + const unsigned int numc = ai.mNumUVComponents[n] ? ai.mNumUVComponents[n] : 2; + + out.StartArray(true); + for (unsigned int i = 0; i < ai.mNumVertices; ++i) { + for (unsigned int c = 0; c < numc; ++c) { + out.Element(ai.mTextureCoords[n][i][c]); + } + } + out.EndArray(); + } + out.EndArray(); + } + + if (ai.GetNumColorChannels()) { + out.Key("colors"); + out.StartArray(); + for (unsigned int n = 0; n < ai.GetNumColorChannels(); ++n) { + out.StartArray(true); + for (unsigned int i = 0; i < ai.mNumVertices; ++i) { + out.Element(ai.mColors[n][i].r); + out.Element(ai.mColors[n][i].g); + out.Element(ai.mColors[n][i].b); + out.Element(ai.mColors[n][i].a); + } + out.EndArray(); + } + out.EndArray(); + } + + if (ai.mNumBones) { + out.Key("bones"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumBones; ++n) { + Write(out, *ai.mBones[n]); + } + out.EndArray(); + } + + out.Key("faces"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumFaces; ++n) { + Write(out, ai.mFaces[n]); + } + out.EndArray(); + + out.EndObj(); +} + +void Write(JSONWriter& out, const aiNode& ai, bool is_elem = true) { + out.StartObj(is_elem); + + out.Key("name"); + out.SimpleValue(ai.mName); + + out.Key("transformation"); + Write(out, ai.mTransformation, false); + + if (ai.mNumMeshes) { + out.Key("meshes"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumMeshes; ++n) { + out.Element(ai.mMeshes[n]); + } + out.EndArray(); + } + + if (ai.mNumChildren) { + out.Key("children"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumChildren; ++n) { + Write(out, *ai.mChildren[n]); + } + out.EndArray(); + } + + out.EndObj(); +} + +void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) { + out.StartObj(is_elem); + + out.Key("properties"); + out.StartArray(); + for (unsigned int i = 0; i < ai.mNumProperties; ++i) { + const aiMaterialProperty* const prop = ai.mProperties[i]; + out.StartObj(true); + out.Key("key"); + out.SimpleValue(prop->mKey); + out.Key("semantic"); + out.SimpleValue(prop->mSemantic); + out.Key("index"); + out.SimpleValue(prop->mIndex); + + out.Key("type"); + out.SimpleValue(prop->mType); + + out.Key("value"); + switch (prop->mType) { + case aiPTI_Float: + if (prop->mDataLength / sizeof(float) > 1) { + out.StartArray(); + for (unsigned int i = 0; i < prop->mDataLength / sizeof(float); ++i) { + out.Element(reinterpret_cast(prop->mData)[i]); + } + out.EndArray(); + } + else { + out.SimpleValue(*reinterpret_cast(prop->mData)); + } + break; + + case aiPTI_Integer: + if (prop->mDataLength / sizeof(int) > 1) { + out.StartArray(); + for (unsigned int i = 0; i < prop->mDataLength / sizeof(int); ++i) { + out.Element(reinterpret_cast(prop->mData)[i]); + } + out.EndArray(); + } else { + out.SimpleValue(*reinterpret_cast(prop->mData)); + } + break; + + case aiPTI_String: + { + aiString s; + aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s); + out.SimpleValue(s); + } + break; + case aiPTI_Buffer: + { + // binary data is written as series of hex-encoded octets + out.SimpleValue(prop->mData, prop->mDataLength); + } + break; + default: + assert(false); + } + + out.EndObj(); + } + + out.EndArray(); + out.EndObj(); +} + +void Write(JSONWriter& out, const aiTexture& ai, bool is_elem = true) { + out.StartObj(is_elem); + + out.Key("width"); + out.SimpleValue(ai.mWidth); + + out.Key("height"); + out.SimpleValue(ai.mHeight); + + out.Key("formathint"); + out.SimpleValue(aiString(ai.achFormatHint)); + + out.Key("data"); + if (!ai.mHeight) { + out.SimpleValue(ai.pcData, ai.mWidth); + } + else { + out.StartArray(); + for (unsigned int y = 0; y < ai.mHeight; ++y) { + out.StartArray(true); + for (unsigned int x = 0; x < ai.mWidth; ++x) { + const aiTexel& tx = ai.pcData[y*ai.mWidth + x]; + out.StartArray(true); + out.Element(static_cast(tx.r)); + out.Element(static_cast(tx.g)); + out.Element(static_cast(tx.b)); + out.Element(static_cast(tx.a)); + out.EndArray(); + } + out.EndArray(); + } + out.EndArray(); + } + + out.EndObj(); +} + +void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) { + out.StartObj(is_elem); + + out.Key("name"); + out.SimpleValue(ai.mName); + + out.Key("type"); + out.SimpleValue(ai.mType); + + if (ai.mType == aiLightSource_SPOT || ai.mType == aiLightSource_UNDEFINED) { + out.Key("angleinnercone"); + out.SimpleValue(ai.mAngleInnerCone); + + out.Key("angleoutercone"); + out.SimpleValue(ai.mAngleOuterCone); + } + + out.Key("attenuationconstant"); + out.SimpleValue(ai.mAttenuationConstant); + + out.Key("attenuationlinear"); + out.SimpleValue(ai.mAttenuationLinear); + + out.Key("attenuationquadratic"); + out.SimpleValue(ai.mAttenuationQuadratic); + + out.Key("diffusecolor"); + Write(out, ai.mColorDiffuse, false); + + out.Key("specularcolor"); + Write(out, ai.mColorSpecular, false); + + out.Key("ambientcolor"); + Write(out, ai.mColorAmbient, false); + + if (ai.mType != aiLightSource_POINT) { + out.Key("direction"); + Write(out, ai.mDirection, false); + + } + + if (ai.mType != aiLightSource_DIRECTIONAL) { + out.Key("position"); + Write(out, ai.mPosition, false); + } + + out.EndObj(); +} + +void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) { + out.StartObj(is_elem); + + out.Key("name"); + out.SimpleValue(ai.mNodeName); + + out.Key("prestate"); + out.SimpleValue(ai.mPreState); + + out.Key("poststate"); + out.SimpleValue(ai.mPostState); + + if (ai.mNumPositionKeys) { + out.Key("positionkeys"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumPositionKeys; ++n) { + const aiVectorKey& pos = ai.mPositionKeys[n]; + out.StartArray(true); + out.Element(pos.mTime); + Write(out, pos.mValue); + out.EndArray(); + } + out.EndArray(); + } + + if (ai.mNumRotationKeys) { + out.Key("rotationkeys"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumRotationKeys; ++n) { + const aiQuatKey& rot = ai.mRotationKeys[n]; + out.StartArray(true); + out.Element(rot.mTime); + Write(out, rot.mValue); + out.EndArray(); + } + out.EndArray(); + } + + if (ai.mNumScalingKeys) { + out.Key("scalingkeys"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumScalingKeys; ++n) { + const aiVectorKey& scl = ai.mScalingKeys[n]; + out.StartArray(true); + out.Element(scl.mTime); + Write(out, scl.mValue); + out.EndArray(); + } + out.EndArray(); + } + out.EndObj(); +} + +void Write(JSONWriter& out, const aiAnimation& ai, bool is_elem = true) { + out.StartObj(is_elem); + + out.Key("name"); + out.SimpleValue(ai.mName); + + out.Key("tickspersecond"); + out.SimpleValue(ai.mTicksPerSecond); + + out.Key("duration"); + out.SimpleValue(ai.mDuration); + + out.Key("channels"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumChannels; ++n) { + Write(out, *ai.mChannels[n]); + } + out.EndArray(); + out.EndObj(); +} + +void Write(JSONWriter& out, const aiCamera& ai, bool is_elem = true) { + out.StartObj(is_elem); + + out.Key("name"); + out.SimpleValue(ai.mName); + + out.Key("aspect"); + out.SimpleValue(ai.mAspect); + + out.Key("clipplanefar"); + out.SimpleValue(ai.mClipPlaneFar); + + out.Key("clipplanenear"); + out.SimpleValue(ai.mClipPlaneNear); + + out.Key("horizontalfov"); + out.SimpleValue(ai.mHorizontalFOV); + + out.Key("up"); + Write(out, ai.mUp, false); + + out.Key("lookat"); + Write(out, ai.mLookAt, false); + + out.EndObj(); +} + +void WriteFormatInfo(JSONWriter& out) { + out.StartObj(); + out.Key("format"); + out.SimpleValue("\"assimp2json\""); + out.Key("version"); + out.SimpleValue(CURRENT_FORMAT_VERSION); + out.EndObj(); +} + +void Write(JSONWriter& out, const aiScene& ai) { + out.StartObj(); + + out.Key("__metadata__"); + WriteFormatInfo(out); + + out.Key("rootnode"); + Write(out, *ai.mRootNode, false); + + out.Key("flags"); + out.SimpleValue(ai.mFlags); + + if (ai.HasMeshes()) { + out.Key("meshes"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumMeshes; ++n) { + Write(out, *ai.mMeshes[n]); + } + out.EndArray(); + } + + if (ai.HasMaterials()) { + out.Key("materials"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumMaterials; ++n) { + Write(out, *ai.mMaterials[n]); + } + out.EndArray(); + } + + if (ai.HasAnimations()) { + out.Key("animations"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumAnimations; ++n) { + Write(out, *ai.mAnimations[n]); + } + out.EndArray(); + } + + if (ai.HasLights()) { + out.Key("lights"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumLights; ++n) { + Write(out, *ai.mLights[n]); + } + out.EndArray(); + } + + if (ai.HasCameras()) { + out.Key("cameras"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumCameras; ++n) { + Write(out, *ai.mCameras[n]); + } + out.EndArray(); + } + + if (ai.HasTextures()) { + out.Key("textures"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumTextures; ++n) { + Write(out, *ai.mTextures[n]); + } + out.EndArray(); + } + out.EndObj(); +} + + +void ExportAssimp2Json(const char* file, Assimp::IOSystem* io, const aiScene* scene, const Assimp::ExportProperties*) { + std::unique_ptr str(io->Open(file, "wt")); + if (!str) { + //throw Assimp::DeadlyExportError("could not open output file"); + } + + // get a copy of the scene so we can modify it + aiScene* scenecopy_tmp; + aiCopyScene(scene, &scenecopy_tmp); + + try { + // split meshes so they fit into a 16 bit index buffer + MeshSplitter splitter; + splitter.SetLimit(1 << 16); + splitter.Execute(scenecopy_tmp); + + // XXX Flag_WriteSpecialFloats is turned on by default, right now we don't have a configuration interface for exporters + JSONWriter s(*str, JSONWriter::Flag_WriteSpecialFloats); + Write(s, *scenecopy_tmp); + + } + catch (...) { + aiFreeScene(scenecopy_tmp); + throw; + } + aiFreeScene(scenecopy_tmp); +} + +} + +#endif // ASSIMP_BUILD_NO_ASSJSON_EXPORTER +#endif // ASSIMP_BUILD_NO_EXPORT diff --git a/code/Assjson/mesh_splitter.cpp b/code/Assjson/mesh_splitter.cpp new file mode 100644 index 000000000..24385f9a0 --- /dev/null +++ b/code/Assjson/mesh_splitter.cpp @@ -0,0 +1,320 @@ +/* +Assimp2Json +Copyright (c) 2011, Alexander C. Gessler + +Licensed under a 3-clause BSD license. See the LICENSE file for more information. + +*/ + +#include "mesh_splitter.h" + +#include + +// ---------------------------------------------------------------------------- +// Note: this is largely based on assimp's SplitLargeMeshes_Vertex process. +// it is refactored and the coding style is slightly improved, though. +// ---------------------------------------------------------------------------- + +// ------------------------------------------------------------------------------------------------ +// Executes the post processing step on the given imported data. +void MeshSplitter::Execute( aiScene* pScene) { + std::vector > source_mesh_map; + + for( unsigned int a = 0; a < pScene->mNumMeshes; a++) { + SplitMesh(a, pScene->mMeshes[a],source_mesh_map); + } + + const unsigned int size = static_cast(source_mesh_map.size()); + if (size != pScene->mNumMeshes) { + // it seems something has been split. rebuild the mesh list + delete[] pScene->mMeshes; + pScene->mNumMeshes = size; + pScene->mMeshes = new aiMesh*[size](); + + for (unsigned int i = 0; i < size;++i) { + pScene->mMeshes[i] = source_mesh_map[i].first; + } + + // now we need to update all nodes + UpdateNode(pScene->mRootNode,source_mesh_map); + } +} + + +// ------------------------------------------------------------------------------------------------ +void MeshSplitter::UpdateNode(aiNode* pcNode, const std::vector >& source_mesh_map) { + // TODO: should better use std::(multi)set for source_mesh_map. + + // for every index in out list build a new entry + std::vector aiEntries; + aiEntries.reserve(pcNode->mNumMeshes + 1); + for (unsigned int i = 0; i < pcNode->mNumMeshes;++i) { + for (unsigned int a = 0, end = static_cast(source_mesh_map.size()); a < end;++a) { + if (source_mesh_map[a].second == pcNode->mMeshes[i]) { + aiEntries.push_back(a); + } + } + } + + // now build the new list + delete pcNode->mMeshes; + pcNode->mNumMeshes = static_cast(aiEntries.size()); + pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes]; + + for (unsigned int b = 0; b < pcNode->mNumMeshes;++b) { + pcNode->mMeshes[b] = aiEntries[b]; + } + + // recursively update children + for (unsigned int i = 0, end = pcNode->mNumChildren; i < end;++i) { + UpdateNode ( pcNode->mChildren[i], source_mesh_map ); + } + return; +} + +#define WAS_NOT_COPIED 0xffffffff + +typedef std::pair PerVertexWeight; +typedef std::vector VertexWeightTable; + +// ------------------------------------------------------------------------------------------------ +VertexWeightTable* ComputeVertexBoneWeightTable(const aiMesh* pMesh) { + if (!pMesh || !pMesh->mNumVertices || !pMesh->mNumBones) { + return nullptr; + } + + VertexWeightTable* const avPerVertexWeights = new VertexWeightTable[pMesh->mNumVertices]; + for (unsigned int i = 0; i < pMesh->mNumBones;++i) { + + aiBone* bone = pMesh->mBones[i]; + for (unsigned int a = 0; a < bone->mNumWeights;++a) { + const aiVertexWeight& weight = bone->mWeights[a]; + avPerVertexWeights[weight.mVertexId].push_back( std::make_pair(i,weight.mWeight) ); + } + } + return avPerVertexWeights; +} + +// ------------------------------------------------------------------------------------------------ +void MeshSplitter :: SplitMesh(unsigned int a, aiMesh* in_mesh, std::vector >& source_mesh_map) { + // TODO: should better use std::(multi)set for source_mesh_map. + + if (in_mesh->mNumVertices <= LIMIT) { + source_mesh_map.push_back(std::make_pair(in_mesh,a)); + return; + } + + // build a per-vertex weight list if necessary + VertexWeightTable* avPerVertexWeights = ComputeVertexBoneWeightTable(in_mesh); + + // we need to split this mesh into sub meshes. Estimate submesh size + const unsigned int sub_meshes = (in_mesh->mNumVertices / LIMIT) + 1; + + // create a std::vector to remember which vertices have already + // been copied and to which position (i.e. output index) + std::vector was_copied_to; + was_copied_to.resize(in_mesh->mNumVertices,WAS_NOT_COPIED); + + // Try to find a good estimate for the number of output faces + // per mesh. Add 12.5% as buffer + unsigned int size_estimated = in_mesh->mNumFaces / sub_meshes; + size_estimated += size_estimated / 8; + + // now generate all submeshes + unsigned int base = 0; + while (true) { + const unsigned int out_vertex_index = LIMIT; + + aiMesh* out_mesh = new aiMesh(); + out_mesh->mNumVertices = 0; + out_mesh->mMaterialIndex = in_mesh->mMaterialIndex; + + // the name carries the adjacency information between the meshes + out_mesh->mName = in_mesh->mName; + + typedef std::vector BoneWeightList; + if (in_mesh->HasBones()) { + out_mesh->mBones = new aiBone*[in_mesh->mNumBones](); + } + + // clear the temporary helper array + if (base) { + std::fill(was_copied_to.begin(), was_copied_to.end(), WAS_NOT_COPIED); + } + + std::vector vFaces; + + // reserve enough storage for most cases + if (in_mesh->HasPositions()) { + out_mesh->mVertices = new aiVector3D[out_vertex_index]; + } + + if (in_mesh->HasNormals()) { + out_mesh->mNormals = new aiVector3D[out_vertex_index]; + } + + if (in_mesh->HasTangentsAndBitangents()) { + out_mesh->mTangents = new aiVector3D[out_vertex_index]; + out_mesh->mBitangents = new aiVector3D[out_vertex_index]; + } + + for (unsigned int c = 0; in_mesh->HasVertexColors(c);++c) { + out_mesh->mColors[c] = new aiColor4D[out_vertex_index]; + } + + for (unsigned int c = 0; in_mesh->HasTextureCoords(c);++c) { + out_mesh->mNumUVComponents[c] = in_mesh->mNumUVComponents[c]; + out_mesh->mTextureCoords[c] = new aiVector3D[out_vertex_index]; + } + vFaces.reserve(size_estimated); + + // (we will also need to copy the array of indices) + while (base < in_mesh->mNumFaces) { + const unsigned int iNumIndices = in_mesh->mFaces[base].mNumIndices; + + // doesn't catch degenerates but is quite fast + unsigned int iNeed = 0; + for (unsigned int v = 0; v < iNumIndices;++v) { + unsigned int index = in_mesh->mFaces[base].mIndices[v]; + + // check whether we do already have this vertex + if (WAS_NOT_COPIED == was_copied_to[index]) { + iNeed++; + } + } + if (out_mesh->mNumVertices + iNeed > out_vertex_index) { + // don't use this face + break; + } + + vFaces.push_back(aiFace()); + aiFace& rFace = vFaces.back(); + + // setup face type and number of indices + rFace.mNumIndices = iNumIndices; + rFace.mIndices = new unsigned int[iNumIndices]; + + // need to update the output primitive types + switch (rFace.mNumIndices) + { + case 1: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; + break; + case 2: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; + break; + case 3: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; + break; + default: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; + } + + // and copy the contents of the old array, offset them by current base + for (unsigned int v = 0; v < iNumIndices;++v) { + const unsigned int index = in_mesh->mFaces[base].mIndices[v]; + + // check whether we do already have this vertex + if (WAS_NOT_COPIED != was_copied_to[index]) { + rFace.mIndices[v] = was_copied_to[index]; + continue; + } + + // copy positions + out_mesh->mVertices[out_mesh->mNumVertices] = (in_mesh->mVertices[index]); + + // copy normals + if (in_mesh->HasNormals()) { + out_mesh->mNormals[out_mesh->mNumVertices] = (in_mesh->mNormals[index]); + } + + // copy tangents/bi-tangents + if (in_mesh->HasTangentsAndBitangents()) { + out_mesh->mTangents[out_mesh->mNumVertices] = (in_mesh->mTangents[index]); + out_mesh->mBitangents[out_mesh->mNumVertices] = (in_mesh->mBitangents[index]); + } + + // texture coordinates + for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { + if (in_mesh->HasTextureCoords( c)) { + out_mesh->mTextureCoords[c][out_mesh->mNumVertices] = in_mesh->mTextureCoords[c][index]; + } + } + // vertex colors + for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS;++c) { + if (in_mesh->HasVertexColors( c)) { + out_mesh->mColors[c][out_mesh->mNumVertices] = in_mesh->mColors[c][index]; + } + } + // check whether we have bone weights assigned to this vertex + rFace.mIndices[v] = out_mesh->mNumVertices; + if (avPerVertexWeights) { + VertexWeightTable& table = avPerVertexWeights[ out_mesh->mNumVertices ]; + for (VertexWeightTable::const_iterator iter = table.begin(), end = table.end(); iter != end;++iter) { + // allocate the bone weight array if necessary and store it in the mBones field (HACK!) + BoneWeightList* weight_list = reinterpret_cast(out_mesh->mBones[(*iter).first]); + if (!weight_list) { + weight_list = new BoneWeightList(); + out_mesh->mBones[(*iter).first] = reinterpret_cast(weight_list); + } + weight_list->push_back(aiVertexWeight(out_mesh->mNumVertices,(*iter).second)); + } + } + + was_copied_to[index] = out_mesh->mNumVertices; + out_mesh->mNumVertices++; + } + base++; + if(out_mesh->mNumVertices == out_vertex_index) { + // break here. The face is only added if it was complete + break; + } + } + + // check which bones we'll need to create for this submesh + if (in_mesh->HasBones()) { + aiBone** ppCurrent = out_mesh->mBones; + for (unsigned int k = 0; k < in_mesh->mNumBones;++k) { + // check whether the bone exists + BoneWeightList* const weight_list = reinterpret_cast(out_mesh->mBones[k]); + + if (weight_list) { + const aiBone* const bone_in = in_mesh->mBones[k]; + aiBone* const bone_out = new aiBone(); + *ppCurrent++ = bone_out; + bone_out->mName = aiString(bone_in->mName); + bone_out->mOffsetMatrix =bone_in->mOffsetMatrix; + bone_out->mNumWeights = (unsigned int)weight_list->size(); + bone_out->mWeights = new aiVertexWeight[bone_out->mNumWeights]; + + // copy the vertex weights + ::memcpy(bone_out->mWeights, &(*weight_list)[0],bone_out->mNumWeights * sizeof(aiVertexWeight)); + + delete weight_list; + out_mesh->mNumBones++; + } + } + } + + // copy the face list to the mesh + out_mesh->mFaces = new aiFace[vFaces.size()]; + out_mesh->mNumFaces = (unsigned int)vFaces.size(); + + for (unsigned int p = 0; p < out_mesh->mNumFaces;++p) { + out_mesh->mFaces[p] = vFaces[p]; + } + + // add the newly created mesh to the list + source_mesh_map.push_back(std::make_pair(out_mesh,a)); + + if (base == in_mesh->mNumFaces) { + break; + } + } + + // delete the per-vertex weight list again + delete[] avPerVertexWeights; + + // now delete the old mesh data + delete in_mesh; +} diff --git a/code/Assjson/mesh_splitter.h b/code/Assjson/mesh_splitter.h new file mode 100644 index 000000000..326f73b41 --- /dev/null +++ b/code/Assjson/mesh_splitter.h @@ -0,0 +1,61 @@ +/* +Assimp2Json +Copyright (c) 2011, Alexander C. Gessler + +Licensed under a 3-clause BSD license. See the LICENSE file for more information. + +*/ + +#ifndef INCLUDED_MESH_SPLITTER +#define INCLUDED_MESH_SPLITTER + +// ---------------------------------------------------------------------------- +// Note: this is largely based on assimp's SplitLargeMeshes_Vertex process. +// it is refactored and the coding style is slightly improved, though. +// ---------------------------------------------------------------------------- + +#include + +struct aiScene; +struct aiMesh; +struct aiNode; + +// --------------------------------------------------------------------------- +/** Splits meshes of unique vertices into meshes with no more vertices than + * a given, configurable threshold value. + */ +class MeshSplitter +{ + +public: + + void SetLimit(unsigned int l) { + LIMIT = l; + } + + unsigned int GetLimit() const { + return LIMIT; + } + +public: + + // ------------------------------------------------------------------- + /** Executes the post processing step on the given imported data. + * At the moment a process is not supposed to fail. + * @param pScene The imported data to work at. + */ + void Execute( aiScene* pScene); + + +private: + + void UpdateNode(aiNode* pcNode, const std::vector >& source_mesh_map); + void SplitMesh (unsigned int index, aiMesh* mesh, std::vector >& source_mesh_map); + +public: + + unsigned int LIMIT; +}; + +#endif // INCLUDED_MESH_SPLITTER + diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 40840759b..a8a514f73 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -331,7 +331,7 @@ ADD_ASSIMP_EXPORTER( ASSBIN Assbin/AssbinExporter.cpp ) -ADD_ASSIMP_IMPORTER( ASSXML +ADD_ASSIMP_EXPORTER( ASSXML Assxml/AssxmlExporter.h Assxml/AssxmlExporter.cpp ) @@ -810,6 +810,14 @@ ADD_ASSIMP_IMPORTER( MMD MMD/MMDVmdParser.h ) +ADD_ASSIMP_EXPORTER( Assjson + Assjson/cencode.c + Assjson/cencode.h + Assjson/json_exporter.cpp + Assjson/mesh_splitter.cpp + Assjson/mesh_splitter.h +) + # Workaround for issue #2406 - force problematic large file to be optimized to prevent string table overflow error # Used -Os instead of -O2 as previous issues had mentioned, since -Os is roughly speaking -O2, excluding any # optimizations that take up extra space. Given that the issue is a string table overflowing, -Os seemed appropriate diff --git a/code/COB/COBLoader.cpp b/code/COB/COBLoader.cpp index b9eb5b7ea..19e3cd59e 100644 --- a/code/COB/COBLoader.cpp +++ b/code/COB/COBLoader.cpp @@ -898,6 +898,7 @@ public: : nfo(nfo) , reader(reader) , cur(reader.GetCurrentPos()) { + // empty } ~chunk_guard() { @@ -905,7 +906,7 @@ public: if(nfo.size != static_cast(-1)) { try { reader.IncPtr( static_cast< int >( nfo.size ) - reader.GetCurrentPos() + cur ); - } catch (const DeadlyImportError& e ) { + } catch (const DeadlyImportError& ) { // out of limit so correct the value reader.IncPtr( reader.GetReadLimit() ); } @@ -913,15 +914,17 @@ public: } private: - const COB::ChunkInfo& nfo; StreamReaderLE& reader; long cur; }; // ------------------------------------------------------------------------------------------------ -void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* reader) -{ +void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* reader) { + if (nullptr == reader) { + return; + } + while(1) { std::string type; type += reader -> GetI1() diff --git a/code/Collada/ColladaLoader.cpp b/code/Collada/ColladaLoader.cpp index cf548e890..e10edb732 100644 --- a/code/Collada/ColladaLoader.cpp +++ b/code/Collada/ColladaLoader.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2019, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -43,7 +41,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Implementation of the Collada loader */ - #ifndef ASSIMP_BUILD_NO_COLLADA_IMPORTER #include "ColladaLoader.h" @@ -65,8 +62,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "math.h" #include #include +#include -using namespace Assimp; +namespace Assimp { + using namespace Assimp::Formatter; static const aiImporterDesc desc = { @@ -111,7 +110,7 @@ ColladaLoader::~ColladaLoader() { // Returns whether the class can handle the format of the given file. bool ColladaLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { // check file extension - std::string extension = GetExtension(pFile); + const std::string extension = GetExtension(pFile); if (extension == "dae") { return true; @@ -126,7 +125,7 @@ bool ColladaLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, boo if (!pIOHandler) { return true; } - const char* tokens[] = {"GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0; ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION,0) != 0; useColladaName = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES,0) != 0; @@ -143,8 +141,7 @@ void ColladaLoader::SetupProperties(const Importer* pImp) // ------------------------------------------------------------------------------------------------ // Get file extension list -const aiImporterDesc* ColladaLoader::GetInfo () const -{ +const aiImporterDesc* ColladaLoader::GetInfo () const { return &desc; } @@ -167,12 +164,13 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I // parse the input file ColladaParser parser( pIOHandler, pFile); - if( !parser.mRootNode) + if( !parser.mRootNode) { throw DeadlyImportError( "Collada: File came out empty. Something is wrong here."); + } // reserve some storage to avoid unnecessary reallocs - newMats.reserve(parser.mMaterialLibrary.size()*2); - mMeshes.reserve(parser.mMeshLibrary.size()*2); + newMats.reserve(parser.mMaterialLibrary.size()*2u); + mMeshes.reserve(parser.mMeshLibrary.size()*2u); mCameras.reserve(parser.mCameraLibrary.size()); mLights.reserve(parser.mLightLibrary.size()); @@ -192,19 +190,20 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I 0, 0, parser.mUnitSize, 0, 0, 0, 0, 1); if( !ignoreUpDirection ) { - // Convert to Y_UP, if different orientation - if( parser.mUpDirection == ColladaParser::UP_X) - pScene->mRootNode->mTransformation *= aiMatrix4x4( - 0, -1, 0, 0, - 1, 0, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1); - else if( parser.mUpDirection == ColladaParser::UP_Z) - pScene->mRootNode->mTransformation *= aiMatrix4x4( - 1, 0, 0, 0, - 0, 0, 1, 0, - 0, -1, 0, 0, - 0, 0, 0, 1); + // Convert to Y_UP, if different orientation + if( parser.mUpDirection == ColladaParser::UP_X) { + pScene->mRootNode->mTransformation *= aiMatrix4x4( + 0, -1, 0, 0, + 1, 0, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); + } else if( parser.mUpDirection == ColladaParser::UP_Z) { + pScene->mRootNode->mTransformation *= aiMatrix4x4( + 1, 0, 0, 0, + 0, 0, 1, 0, + 0, -1, 0, 0, + 0, 0, 0, 1); + } } // Store scene metadata @@ -212,8 +211,7 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I const size_t numMeta(parser.mAssetMetaData.size()); pScene->mMetaData = aiMetadata::Alloc(static_cast(numMeta)); size_t i = 0; - for (auto it = parser.mAssetMetaData.cbegin(); it != parser.mAssetMetaData.cend(); ++it, ++i) - { + for (auto it = parser.mAssetMetaData.cbegin(); it != parser.mAssetMetaData.cend(); ++it, ++i) { pScene->mMetaData->Set(static_cast(i), (*it).first, (*it).second); } } @@ -233,9 +231,8 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I // store all animations StoreAnimations( pScene, parser); - // If no meshes have been loaded, it's probably just an animated skeleton. - if (!pScene->mNumMeshes) { + if ( 0u == pScene->mNumMeshes) { if (!noSkeletonMesh) { SkeletonMeshBuilder hero(pScene); @@ -246,8 +243,7 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I // ------------------------------------------------------------------------------------------------ // Recursively constructs a scene node for the given parser node and returns it. -aiNode* ColladaLoader::BuildHierarchy( const ColladaParser& pParser, const Collada::Node* pNode) -{ +aiNode* ColladaLoader::BuildHierarchy( const ColladaParser& pParser, const Collada::Node* pNode) { // create a node for it aiNode* node = new aiNode(); @@ -265,15 +261,13 @@ aiNode* ColladaLoader::BuildHierarchy( const ColladaParser& pParser, const Colla node->mNumChildren = static_cast(pNode->mChildren.size()+instances.size()); node->mChildren = new aiNode*[node->mNumChildren]; - for( size_t a = 0; a < pNode->mChildren.size(); a++) - { + for( size_t a = 0; a < pNode->mChildren.size(); ++a) { node->mChildren[a] = BuildHierarchy( pParser, pNode->mChildren[a]); node->mChildren[a]->mParent = node; } // ... and finally the resolved node instances - for( size_t a = 0; a < instances.size(); a++) - { + for( size_t a = 0; a < instances.size(); ++a) { node->mChildren[pNode->mChildren.size() + a] = BuildHierarchy( pParser, instances[a]); node->mChildren[pNode->mChildren.size() + a]->mParent = node; } @@ -286,20 +280,19 @@ aiNode* ColladaLoader::BuildHierarchy( const ColladaParser& pParser, const Colla // construct lights BuildLightsForNode(pParser, pNode, node); + return node; } // ------------------------------------------------------------------------------------------------ // Resolve node instances void ColladaLoader::ResolveNodeInstances( const ColladaParser& pParser, const Collada::Node* pNode, - std::vector& resolved) -{ + std::vector& resolved) { // reserve enough storage resolved.reserve(pNode->mNodeInstances.size()); // ... and iterate through all nodes to be instanced as children of pNode - for (const auto &nodeInst: pNode->mNodeInstances) - { + for (const auto &nodeInst: pNode->mNodeInstances) { // find the corresponding node in the library const ColladaParser::NodeLibrary::const_iterator itt = pParser.mNodeLibrary.find(nodeInst.mNode); const Collada::Node* nd = itt == pParser.mNodeLibrary.end() ? NULL : (*itt).second; @@ -307,13 +300,12 @@ void ColladaLoader::ResolveNodeInstances( const ColladaParser& pParser, const Co // FIX for http://sourceforge.net/tracker/?func=detail&aid=3054873&group_id=226462&atid=1067632 // need to check for both name and ID to catch all. To avoid breaking valid files, // the workaround is only enabled when the first attempt to resolve the node has failed. - if (!nd) { + if (nullptr == nd) { nd = FindNode(pParser.mRootNode, nodeInst.mNode); } - if (!nd) + if (nullptr == nd) { ASSIMP_LOG_ERROR_F("Collada: Unable to resolve reference to instanced node ", nodeInst.mNode); - - else { + } else { // attach this node to the list of children resolved.push_back(nd); } @@ -323,12 +315,12 @@ void ColladaLoader::ResolveNodeInstances( const ColladaParser& pParser, const Co // ------------------------------------------------------------------------------------------------ // Resolve UV channels void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler, - const Collada::SemanticMappingTable& table) -{ + const Collada::SemanticMappingTable& table) { std::map::const_iterator it = table.mMap.find(sampler.mUVChannel); if (it != table.mMap.end()) { - if (it->second.mType != Collada::IT_Texcoord) + if (it->second.mType != Collada::IT_Texcoord) { ASSIMP_LOG_ERROR("Collada: Unexpected effect input mapping"); + } sampler.mUVId = it->second.mSet; } @@ -336,14 +328,11 @@ void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler // ------------------------------------------------------------------------------------------------ // Builds lights for the given node and references them -void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget) -{ - for( const Collada::LightInstance& lid : pNode->mLights) - { +void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget) { + for( const Collada::LightInstance& lid : pNode->mLights) { // find the referred light ColladaParser::LightLibrary::const_iterator srcLightIt = pParser.mLightLibrary.find( lid.mLight); - if( srcLightIt == pParser.mLightLibrary.end()) - { + if( srcLightIt == pParser.mLightLibrary.end()) { ASSIMP_LOG_WARN_F("Collada: Unable to find light for ID \"" , lid.mLight , "\". Skipping."); continue; } @@ -365,8 +354,7 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll if (out->mType == aiLightSource_AMBIENT) { out->mColorDiffuse = out->mColorSpecular = aiColor3D(0, 0, 0); out->mColorAmbient = srcLight->mColor*srcLight->mIntensity; - } - else { + } else { // collada doesn't differentiate between these color types out->mColorDiffuse = out->mColorSpecular = srcLight->mColor*srcLight->mIntensity; out->mColorAmbient = aiColor3D(0, 0, 0); @@ -374,27 +362,24 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll // convert falloff angle and falloff exponent in our representation, if given if (out->mType == aiLightSource_SPOT) { - out->mAngleInnerCone = AI_DEG_TO_RAD( srcLight->mFalloffAngle ); // ... some extension magic. - if (srcLight->mOuterAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET*(1-1e-6f)) - { + if (srcLight->mOuterAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET*(1-1e-6f)) { // ... some deprecation magic. - if (srcLight->mPenumbraAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET*(1-1e-6f)) - { + if (srcLight->mPenumbraAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET*(1-1e-6f)) { // Need to rely on falloff_exponent. I don't know how to interpret it, so I need to guess .... // epsilon chosen to be 0.1 out->mAngleOuterCone = std::acos(std::pow(0.1f,1.f/srcLight->mFalloffExponent))+ out->mAngleInnerCone; - } - else { + } else { out->mAngleOuterCone = out->mAngleInnerCone + AI_DEG_TO_RAD( srcLight->mPenumbraAngle ); if (out->mAngleOuterCone < out->mAngleInnerCone) std::swap(out->mAngleInnerCone,out->mAngleOuterCone); } + } else { + out->mAngleOuterCone = AI_DEG_TO_RAD( srcLight->mOuterAngle ); } - else out->mAngleOuterCone = AI_DEG_TO_RAD( srcLight->mOuterAngle ); } // add to light list @@ -404,14 +389,11 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll // ------------------------------------------------------------------------------------------------ // Builds cameras for the given node and references them -void ColladaLoader::BuildCamerasForNode( const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget) -{ - for( const Collada::CameraInstance& cid : pNode->mCameras) - { +void ColladaLoader::BuildCamerasForNode( const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget) { + for( const Collada::CameraInstance& cid : pNode->mCameras) { // find the referred light ColladaParser::CameraLibrary::const_iterator srcCameraIt = pParser.mCameraLibrary.find( cid.mCamera); - if( srcCameraIt == pParser.mCameraLibrary.end()) - { + if( srcCameraIt == pParser.mCameraLibrary.end()) { ASSIMP_LOG_WARN_F("Collada: Unable to find camera for ID \"" , cid.mCamera , "\". Skipping."); continue; } @@ -435,8 +417,9 @@ void ColladaLoader::BuildCamerasForNode( const ColladaParser& pParser, const Col // ... but for the rest some values are optional // and we need to compute the others in any combination. - if (srcCamera->mAspect != 10e10f) + if (srcCamera->mAspect != 10e10f) { out->mAspect = srcCamera->mAspect; + } if (srcCamera->mHorFov != 10e10f) { out->mHorizontalFOV = srcCamera->mHorFov; @@ -445,8 +428,7 @@ void ColladaLoader::BuildCamerasForNode( const ColladaParser& pParser, const Col out->mAspect = std::tan(AI_DEG_TO_RAD(srcCamera->mHorFov)) / std::tan(AI_DEG_TO_RAD(srcCamera->mVerFov)); } - } - else if (srcCamera->mAspect != 10e10f && srcCamera->mVerFov != 10e10f) { + } else if (srcCamera->mAspect != 10e10f && srcCamera->mVerFov != 10e10f) { out->mHorizontalFOV = 2.0f * AI_RAD_TO_DEG(std::atan(srcCamera->mAspect * std::tan(AI_DEG_TO_RAD(srcCamera->mVerFov) * 0.5f))); } @@ -461,77 +443,69 @@ void ColladaLoader::BuildCamerasForNode( const ColladaParser& pParser, const Col // ------------------------------------------------------------------------------------------------ // Builds meshes for the given node and references them -void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget) -{ +void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget) { // accumulated mesh references by this node std::vector newMeshRefs; newMeshRefs.reserve(pNode->mMeshes.size()); // add a mesh for each subgroup in each collada mesh - for( const Collada::MeshInstance& mid : pNode->mMeshes) - { - const Collada::Mesh* srcMesh = NULL; - const Collada::Controller* srcController = NULL; + for( const Collada::MeshInstance& mid : pNode->mMeshes) { + const Collada::Mesh* srcMesh = nullptr; + const Collada::Controller* srcController = nullptr; // find the referred mesh ColladaParser::MeshLibrary::const_iterator srcMeshIt = pParser.mMeshLibrary.find( mid.mMeshOrController); - if( srcMeshIt == pParser.mMeshLibrary.end()) - { + if( srcMeshIt == pParser.mMeshLibrary.end()) { // if not found in the mesh-library, it might also be a controller referring to a mesh ColladaParser::ControllerLibrary::const_iterator srcContrIt = pParser.mControllerLibrary.find( mid.mMeshOrController); - if( srcContrIt != pParser.mControllerLibrary.end()) - { + if( srcContrIt != pParser.mControllerLibrary.end()) { srcController = &srcContrIt->second; srcMeshIt = pParser.mMeshLibrary.find( srcController->mMeshId); - if( srcMeshIt != pParser.mMeshLibrary.end()) + if( srcMeshIt != pParser.mMeshLibrary.end()) { srcMesh = srcMeshIt->second; + } } - if( !srcMesh) - { + if( nullptr == srcMesh) { ASSIMP_LOG_WARN_F( "Collada: Unable to find geometry for ID \"", mid.mMeshOrController, "\". Skipping." ); continue; } - } else - { + } else { // ID found in the mesh library -> direct reference to an unskinned mesh srcMesh = srcMeshIt->second; } // build a mesh for each of its subgroups size_t vertexStart = 0, faceStart = 0; - for( size_t sm = 0; sm < srcMesh->mSubMeshes.size(); ++sm) - { + for( size_t sm = 0; sm < srcMesh->mSubMeshes.size(); ++sm) { const Collada::SubMesh& submesh = srcMesh->mSubMeshes[sm]; - if( submesh.mNumFaces == 0) + if( submesh.mNumFaces == 0) { continue; + } // find material assigned to this submesh std::string meshMaterial; std::map::const_iterator meshMatIt = mid.mMaterials.find( submesh.mMaterial); - const Collada::SemanticMappingTable* table = NULL; - if( meshMatIt != mid.mMaterials.end()) - { + const Collada::SemanticMappingTable* table = nullptr; + if( meshMatIt != mid.mMaterials.end()) { table = &meshMatIt->second; meshMaterial = table->mMatName; - } - else - { + } else { ASSIMP_LOG_WARN_F( "Collada: No material specified for subgroup <", submesh.mMaterial, "> in geometry <", mid.mMeshOrController, ">." ); - if( !mid.mMaterials.empty() ) + if( !mid.mMaterials.empty() ) { meshMaterial = mid.mMaterials.begin()->second.mMatName; + } } // OK ... here the *real* fun starts ... we have the vertex-input-to-effect-semantic-table // given. The only mapping stuff which we do actually support is the UV channel. std::map::const_iterator matIt = mMaterialIndexByName.find( meshMaterial); - unsigned int matIdx; - if( matIt != mMaterialIndexByName.end()) + unsigned int matIdx = 0; + if( matIt != mMaterialIndexByName.end()) { matIdx = static_cast(matIt->second); - else - matIdx = 0; + } if (table && !table->mMap.empty() ) { std::pair& mat = newMats[matIdx]; @@ -553,9 +527,7 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll std::map::const_iterator dstMeshIt = mMeshIndexByID.find( index); if( dstMeshIt != mMeshIndexByID.end()) { newMeshRefs.push_back( dstMeshIt->second); - } - else - { + } else { // else we have to add the mesh to the collection and store its newly assigned index at the node aiMesh* dstMesh = CreateMesh( pParser, srcMesh, submesh, srcController, vertexStart, faceStart); @@ -567,22 +539,18 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll // assign the material index dstMesh->mMaterialIndex = matIdx; - if(dstMesh->mName.length == 0) - { + if(dstMesh->mName.length == 0) { dstMesh->mName = mid.mMeshOrController; } - } + } } } // now place all mesh references we gathered in the target node pTarget->mNumMeshes = static_cast(newMeshRefs.size()); - if( newMeshRefs.size()) - { - struct UIntTypeConverter - { - unsigned int operator()(const size_t& v) const - { + if( newMeshRefs.size()) { + struct UIntTypeConverter { + unsigned int operator()(const size_t& v) const { return static_cast(v); } }; @@ -594,25 +562,27 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll // ------------------------------------------------------------------------------------------------ // Find mesh from either meshes or morph target meshes -aiMesh *ColladaLoader::findMesh(std::string meshid) -{ - for (unsigned int i = 0; i < mMeshes.size(); i++) - if (std::string(mMeshes[i]->mName.data) == meshid) +aiMesh *ColladaLoader::findMesh(std::string meshid) { + for (unsigned int i = 0; i < mMeshes.size(); ++i ) { + if (std::string(mMeshes[i]->mName.data) == meshid) { return mMeshes[i]; + } + } - for (unsigned int i = 0; i < mTargetMeshes.size(); i++) - if (std::string(mTargetMeshes[i]->mName.data) == meshid) + for (unsigned int i = 0; i < mTargetMeshes.size(); ++i ) { + if (std::string(mTargetMeshes[i]->mName.data) == meshid) { return mTargetMeshes[i]; - - return NULL; + } + } + + return nullptr; } // ------------------------------------------------------------------------------------------------ // Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh, - const Collada::Controller* pSrcController, size_t pStartVertex, size_t pStartFace) -{ - aiMesh* dstMesh = new aiMesh; + const Collada::Controller* pSrcController, size_t pStartVertex, size_t pStartFace) { + std::unique_ptr dstMesh(new aiMesh); dstMesh->mName = pSrcMesh->mName; @@ -629,24 +599,21 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada:: // normals, if given. HACK: (thom) Due to the glorious Collada spec we never // know if we have the same number of normals as there are positions. So we // also ignore any vertex attribute if it has a different count - if( pSrcMesh->mNormals.size() >= pStartVertex + numVertices) - { + if( pSrcMesh->mNormals.size() >= pStartVertex + numVertices) { dstMesh->mNormals = new aiVector3D[numVertices]; std::copy( pSrcMesh->mNormals.begin() + pStartVertex, pSrcMesh->mNormals.begin() + pStartVertex + numVertices, dstMesh->mNormals); } // tangents, if given. - if( pSrcMesh->mTangents.size() >= pStartVertex + numVertices) - { + if( pSrcMesh->mTangents.size() >= pStartVertex + numVertices) { dstMesh->mTangents = new aiVector3D[numVertices]; std::copy( pSrcMesh->mTangents.begin() + pStartVertex, pSrcMesh->mTangents.begin() + pStartVertex + numVertices, dstMesh->mTangents); } // bitangents, if given. - if( pSrcMesh->mBitangents.size() >= pStartVertex + numVertices) - { + if( pSrcMesh->mBitangents.size() >= pStartVertex + numVertices) { dstMesh->mBitangents = new aiVector3D[numVertices]; std::copy( pSrcMesh->mBitangents.begin() + pStartVertex, pSrcMesh->mBitangents.begin() + pStartVertex + numVertices, dstMesh->mBitangents); @@ -654,13 +621,12 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada:: // same for texturecoords, as many as we have // empty slots are not allowed, need to pack and adjust UV indexes accordingly - for( size_t a = 0, real = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) - { - if( pSrcMesh->mTexCoords[a].size() >= pStartVertex + numVertices) - { + for( size_t a = 0, real = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) { + if( pSrcMesh->mTexCoords[a].size() >= pStartVertex + numVertices) { dstMesh->mTextureCoords[real] = new aiVector3D[numVertices]; - for( size_t b = 0; b < numVertices; ++b) + for( size_t b = 0; b < numVertices; ++b) { dstMesh->mTextureCoords[real][b] = pSrcMesh->mTexCoords[a][pStartVertex+b]; + } dstMesh->mNumUVComponents[real] = pSrcMesh->mNumUVComponents[a]; ++real; @@ -668,10 +634,8 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada:: } // same for vertex colors, as many as we have. again the same packing to avoid empty slots - for( size_t a = 0, real = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++) - { - if( pSrcMesh->mColors[a].size() >= pStartVertex + numVertices) - { + for( size_t a = 0, real = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a ) { + if( pSrcMesh->mColors[a].size() >= pStartVertex + numVertices) { dstMesh->mColors[real] = new aiColor4D[numVertices]; std::copy( pSrcMesh->mColors[a].begin() + pStartVertex, pSrcMesh->mColors[a].begin() + pStartVertex + numVertices,dstMesh->mColors[real]); ++real; @@ -682,14 +646,14 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada:: size_t vertex = 0; dstMesh->mNumFaces = static_cast(pSubMesh.mNumFaces); dstMesh->mFaces = new aiFace[dstMesh->mNumFaces]; - for( size_t a = 0; a < dstMesh->mNumFaces; ++a) - { + for( size_t a = 0; a < dstMesh->mNumFaces; ++a) { size_t s = pSrcMesh->mFaceSize[ pStartFace + a]; aiFace& face = dstMesh->mFaces[a]; face.mNumIndices = static_cast(s); face.mIndices = new unsigned int[s]; - for( size_t b = 0; b < s; ++b) + for( size_t b = 0; b < s; ++b) { face.mIndices[b] = static_cast(vertex++); + } } // create morph target meshes if any @@ -697,14 +661,12 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada:: std::vector targetWeights; Collada::MorphMethod method = Collada::Normalized; - for(std::map::const_iterator it = pParser.mControllerLibrary.begin(); - it != pParser.mControllerLibrary.end(); it++) - { + for(std::map::const_iterator it = pParser.mControllerLibrary.begin(); + it != pParser.mControllerLibrary.end(); it++) { const Collada::Controller &c = it->second; const Collada::Mesh* baseMesh = pParser.ResolveLibraryReference( pParser.mMeshLibrary, c.mMeshId); - if (c.mType == Collada::Morph && baseMesh->mName == pSrcMesh->mName) - { + if (c.mType == Collada::Morph && baseMesh->mName == pSrcMesh->mName) { const Collada::Accessor& targetAccessor = pParser.ResolveLibraryReference( pParser.mAccessorLibrary, c.mMorphTarget); const Collada::Accessor& weightAccessor = pParser.ResolveLibraryReference( pParser.mAccessorLibrary, c.mMorphWeight); const Collada::Data& targetData = pParser.ResolveLibraryReference( pParser.mDataLibrary, targetAccessor.mSource); @@ -713,34 +675,34 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada:: // take method method = c.mMethod; - if (!targetData.mIsStringArray) + if (!targetData.mIsStringArray) { throw DeadlyImportError( "target data must contain id. "); - if (weightData.mIsStringArray) + } + if (weightData.mIsStringArray) { throw DeadlyImportError( "target weight data must not be textual "); + } - for (unsigned int i = 0; i < targetData.mStrings.size(); ++i) - { + for (unsigned int i = 0; i < targetData.mStrings.size(); ++i) { const Collada::Mesh* targetMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, targetData.mStrings.at(i)); aiMesh *aimesh = findMesh(targetMesh->mName); - if (!aimesh) - { - if (targetMesh->mSubMeshes.size() > 1) + if (!aimesh) { + if (targetMesh->mSubMeshes.size() > 1) { throw DeadlyImportError( "Morhing target mesh must be a single"); + } aimesh = CreateMesh(pParser, targetMesh, targetMesh->mSubMeshes.at(0), NULL, 0, 0); mTargetMeshes.push_back(aimesh); } targetMeshes.push_back(aimesh); } - for (unsigned int i = 0; i < weightData.mValues.size(); ++i) + for (unsigned int i = 0; i < weightData.mValues.size(); ++i) { targetWeights.push_back(weightData.mValues.at(i)); + } } } - if (targetMeshes.size() > 0 && targetWeights.size() == targetMeshes.size()) - { + if (targetMeshes.size() > 0 && targetWeights.size() == targetMeshes.size()) { std::vector animMeshes; - for (unsigned int i = 0; i < targetMeshes.size(); i++) - { + for (unsigned int i = 0; i < targetMeshes.size(); ++i ) { aiMesh* targetMesh = targetMeshes.at(i); aiAnimMesh *animMesh = aiCreateAnimMesh(targetMesh); float weight = targetWeights[i]; @@ -753,13 +715,13 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada:: : aiMorphingMethod_MORPH_NORMALIZED; dstMesh->mAnimMeshes = new aiAnimMesh*[animMeshes.size()]; dstMesh->mNumAnimMeshes = static_cast(animMeshes.size()); - for (unsigned int i = 0; i < animMeshes.size(); i++) + for (unsigned int i = 0; i < animMeshes.size(); ++i ) { dstMesh->mAnimMeshes[i] = animMeshes.at(i); + } } // create bones if given - if( pSrcController && pSrcController->mType == Collada::Skin) - { + if( pSrcController && pSrcController->mType == Collada::Skin) { // resolve references - joint names const Collada::Accessor& jointNamesAcc = pParser.ResolveLibraryReference( pParser.mAccessorLibrary, pSrcController->mJointNameSource); const Collada::Data& jointNames = pParser.ResolveLibraryReference( pParser.mDataLibrary, jointNamesAcc.mSource); @@ -790,15 +752,13 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada:: weightStartPerVertex.resize(pSrcController->mWeightCounts.size(),pSrcController->mWeights.end()); IndexPairVector::const_iterator pit = pSrcController->mWeights.begin(); - for( size_t a = 0; a < pSrcController->mWeightCounts.size(); ++a) - { + for( size_t a = 0; a < pSrcController->mWeightCounts.size(); ++a) { weightStartPerVertex[a] = pit; pit += pSrcController->mWeightCounts[a]; } // now for each vertex put the corresponding vertex weights into each bone's weight collection - for( size_t a = pStartVertex; a < pStartVertex + numVertices; ++a) - { + for( size_t a = pStartVertex; a < pStartVertex + numVertices; ++a) { // which position index was responsible for this vertex? that's also the index by which // the controller assigns the vertex weights size_t orgIndex = pSrcMesh->mFacePosIndices[a]; @@ -806,12 +766,13 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada:: IndexPairVector::const_iterator iit = weightStartPerVertex[orgIndex]; size_t pairCount = pSrcController->mWeightCounts[orgIndex]; - for( size_t b = 0; b < pairCount; ++b, ++iit) - { - size_t jointIndex = iit->first; - size_t vertexIndex = iit->second; - - ai_real weight = ReadFloat( weightsAcc, weights, vertexIndex, 0); + for( size_t b = 0; b < pairCount; ++b, ++iit) { + const size_t jointIndex = iit->first; + const size_t vertexIndex = iit->second; + ai_real weight = 1.0f; + if (!weights.mValues.empty()) { + weight = ReadFloat(weightsAcc, weights, vertexIndex, 0); + } // one day I gonna kill that XSI Collada exporter if( weight > 0.0f) @@ -826,19 +787,21 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada:: // count the number of bones which influence vertices of the current submesh size_t numRemainingBones = 0; - for( std::vector >::const_iterator it = dstBones.begin(); it != dstBones.end(); ++it) - if( it->size() > 0) - numRemainingBones++; + for( std::vector >::const_iterator it = dstBones.begin(); it != dstBones.end(); ++it) { + if( it->size() > 0) { + ++numRemainingBones; + } + } // create bone array and copy bone weights one by one dstMesh->mNumBones = static_cast(numRemainingBones); dstMesh->mBones = new aiBone*[numRemainingBones]; size_t boneCount = 0; - for( size_t a = 0; a < numBones; ++a) - { + for( size_t a = 0; a < numBones; ++a) { // omit bones without weights - if( dstBones[a].size() == 0) + if( dstBones[a].empty() ) { continue; + } // create bone with its weights aiBone* bone = new aiBone; @@ -884,108 +847,101 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada:: // and replace the bone's name by the node's name so that the user can use the standard // find-by-name method to associate nodes with bones. const Collada::Node* bnode = FindNode( pParser.mRootNode, bone->mName.data); - if( !bnode) + if( !bnode) { bnode = FindNodeBySID( pParser.mRootNode, bone->mName.data); + } // assign the name that we would have assigned for the source node - if( bnode) + if( bnode) { bone->mName.Set( FindNameForNode( bnode)); - else + } else { ASSIMP_LOG_WARN_F( "ColladaLoader::CreateMesh(): could not find corresponding node for joint \"", bone->mName.data, "\"." ); + } // and insert bone dstMesh->mBones[boneCount++] = bone; } } - return dstMesh; + return dstMesh.release(); } // ------------------------------------------------------------------------------------------------ // Stores all meshes in the given scene -void ColladaLoader::StoreSceneMeshes( aiScene* pScene) -{ +void ColladaLoader::StoreSceneMeshes( aiScene* pScene) { pScene->mNumMeshes = static_cast(mMeshes.size()); - if( mMeshes.size() > 0) - { - pScene->mMeshes = new aiMesh*[mMeshes.size()]; - std::copy( mMeshes.begin(), mMeshes.end(), pScene->mMeshes); - mMeshes.clear(); + if( mMeshes.empty() ) { + return; } + pScene->mMeshes = new aiMesh*[mMeshes.size()]; + std::copy( mMeshes.begin(), mMeshes.end(), pScene->mMeshes); + mMeshes.clear(); } // ------------------------------------------------------------------------------------------------ // Stores all cameras in the given scene -void ColladaLoader::StoreSceneCameras( aiScene* pScene) -{ +void ColladaLoader::StoreSceneCameras( aiScene* pScene) { pScene->mNumCameras = static_cast(mCameras.size()); - if( mCameras.size() > 0) - { - pScene->mCameras = new aiCamera*[mCameras.size()]; - std::copy( mCameras.begin(), mCameras.end(), pScene->mCameras); - mCameras.clear(); + if( mCameras.empty() ) { + return; } + pScene->mCameras = new aiCamera*[mCameras.size()]; + std::copy( mCameras.begin(), mCameras.end(), pScene->mCameras); + mCameras.clear(); } // ------------------------------------------------------------------------------------------------ // Stores all lights in the given scene -void ColladaLoader::StoreSceneLights( aiScene* pScene) -{ +void ColladaLoader::StoreSceneLights( aiScene* pScene) { pScene->mNumLights = static_cast(mLights.size()); - if( mLights.size() > 0) - { - pScene->mLights = new aiLight*[mLights.size()]; - std::copy( mLights.begin(), mLights.end(), pScene->mLights); - mLights.clear(); + if( mLights.empty() ) { + return; } + pScene->mLights = new aiLight*[mLights.size()]; + std::copy( mLights.begin(), mLights.end(), pScene->mLights); + mLights.clear(); } // ------------------------------------------------------------------------------------------------ // Stores all textures in the given scene -void ColladaLoader::StoreSceneTextures( aiScene* pScene) -{ +void ColladaLoader::StoreSceneTextures( aiScene* pScene) { pScene->mNumTextures = static_cast(mTextures.size()); - if( mTextures.size() > 0) - { - pScene->mTextures = new aiTexture*[mTextures.size()]; - std::copy( mTextures.begin(), mTextures.end(), pScene->mTextures); - mTextures.clear(); + if( mTextures.empty() ) { + return; } + pScene->mTextures = new aiTexture*[mTextures.size()]; + std::copy( mTextures.begin(), mTextures.end(), pScene->mTextures); + mTextures.clear(); } // ------------------------------------------------------------------------------------------------ // Stores all materials in the given scene -void ColladaLoader::StoreSceneMaterials( aiScene* pScene) -{ +void ColladaLoader::StoreSceneMaterials( aiScene* pScene) { pScene->mNumMaterials = static_cast(newMats.size()); - - if (newMats.size() > 0) { - pScene->mMaterials = new aiMaterial*[newMats.size()]; - for (unsigned int i = 0; i < newMats.size();++i) - pScene->mMaterials[i] = newMats[i].second; - - newMats.clear(); + if (newMats.empty() ) { + return; } + pScene->mMaterials = new aiMaterial*[newMats.size()]; + for (unsigned int i = 0; i < newMats.size();++i) { + pScene->mMaterials[i] = newMats[i].second; + } + newMats.clear(); } // ------------------------------------------------------------------------------------------------ // Stores all animations -void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pParser) -{ +void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pParser) { // recursively collect all animations from the collada scene StoreAnimations( pScene, pParser, &pParser.mAnims, ""); // catch special case: many animations with the same length, each affecting only a single node. // we need to unite all those single-node-anims to a proper combined animation - for( size_t a = 0; a < mAnims.size(); ++a) - { + for( size_t a = 0; a < mAnims.size(); ++a) { aiAnimation* templateAnim = mAnims[a]; - if( templateAnim->mNumChannels == 1) - { + if( templateAnim->mNumChannels == 1) { // search for other single-channel-anims with the same duration std::vector collectedAnimIndices; - for( size_t b = a+1; b < mAnims.size(); ++b) - { + for( size_t b = a+1; b < mAnims.size(); ++b) { aiAnimation* other = mAnims[b]; if( other->mNumChannels == 1 && other->mDuration == templateAnim->mDuration && other->mTicksPerSecond == templateAnim->mTicksPerSecond ) @@ -1916,19 +1872,23 @@ const Collada::Node* ColladaLoader::FindNode( const Collada::Node* pNode, const // ------------------------------------------------------------------------------------------------ // Finds a node in the collada scene by the given SID -const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, const std::string& pSID) const -{ - if( pNode->mSID == pSID) - return pNode; +const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, const std::string& pSID) const { + if (nullptr == pNode) { + return nullptr; + } - for( size_t a = 0; a < pNode->mChildren.size(); ++a) - { - const Collada::Node* node = FindNodeBySID( pNode->mChildren[a], pSID); - if( node) - return node; - } + if (pNode->mSID == pSID) { + return pNode; + } - return NULL; + for( size_t a = 0; a < pNode->mChildren.size(); ++a) { + const Collada::Node* node = FindNodeBySID( pNode->mChildren[a], pSID); + if (node) { + return node; + } + } + + return nullptr; } // ------------------------------------------------------------------------------------------------ @@ -1962,4 +1922,6 @@ std::string ColladaLoader::FindNameForNode( const Collada::Node* pNode) } } +} // Namespace Assimp + #endif // !! ASSIMP_BUILD_NO_DAE_IMPORTER diff --git a/code/Common/CreateAnimMesh.cpp b/code/Common/CreateAnimMesh.cpp index 1a052849b..98b60e531 100644 --- a/code/Common/CreateAnimMesh.cpp +++ b/code/Common/CreateAnimMesh.cpp @@ -47,10 +47,6 @@ namespace Assimp { aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh) { aiAnimMesh *animesh = new aiAnimMesh; - animesh->mVertices = NULL; - animesh->mNormals = NULL; - animesh->mTangents = NULL; - animesh->mBitangents = NULL; animesh->mNumVertices = mesh->mNumVertices; if (mesh->mVertices) { animesh->mVertices = new aiVector3D[animesh->mNumVertices]; diff --git a/code/Common/Exporter.cpp b/code/Common/Exporter.cpp index b1caa4f96..87745bca9 100644 --- a/code/Common/Exporter.cpp +++ b/code/Common/Exporter.cpp @@ -102,6 +102,7 @@ void ExportSceneX3D(const char*, IOSystem*, const aiScene*, const ExportProperti void ExportSceneFBX(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneFBXA(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* ); +void ExportAssimp2Json(const char* , IOSystem*, const aiScene* , const Assimp::ExportProperties*); // ------------------------------------------------------------------------------------------------ // global array of all export formats which Assimp supports in its current build @@ -179,7 +180,11 @@ Exporter::ExportFormatEntry gExporters[] = #endif #ifndef ASSIMP_BUILD_NO_3MF_EXPORTER - Exporter::ExportFormatEntry( "3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0 ) + Exporter::ExportFormatEntry( "3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0 ), +#endif + +#ifndef ASSIMP_BUILD_NO_Assjson_EXPORTER + Exporter::ExportFormatEntry("json", "Plain JSON representation of the Assimp scene data structure", "json", &ExportAssimp2Json, 0) #endif }; diff --git a/code/Common/ImporterRegistry.cpp b/code/Common/ImporterRegistry.cpp index abcaf9130..32ac3b416 100644 --- a/code/Common/ImporterRegistry.cpp +++ b/code/Common/ImporterRegistry.cpp @@ -364,7 +364,7 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out) void DeleteImporterInstanceList(std::vector< BaseImporter* >& deleteList){ for(size_t i= 0; imAspect = cam.AspectWidth() / cam.AspectHeight(); - //cameras are defined along positive x direction - /*out_camera->mPosition = cam.Position(); - out_camera->mLookAt = (cam.InterestPosition() - out_camera->mPosition).Normalize(); - out_camera->mUp = cam.UpVector();*/ - out_camera->mPosition = aiVector3D(0.0f); out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f); out_camera->mUp = aiVector3D(0.0f, 1.0f, 0.0f); @@ -667,8 +662,7 @@ namespace Assimp { if ((v - all_ones).SquareLength() > zero_epsilon) { return true; } - } - else if (ok) { + } else if (ok) { if (v.SquareLength() > zero_epsilon) { return true; } @@ -1253,10 +1247,10 @@ namespace Assimp { ai_assert(count_faces); ai_assert(count_vertices); - // mapping from output indices to DOM indexing, needed to resolve weights + // mapping from output indices to DOM indexing, needed to resolve weights or blendshapes std::vector reverseMapping; std::map translateIndexMap; - if (process_weights) { + if (process_weights || mesh.GetBlendShapes().size() > 0) { reverseMapping.resize(count_vertices); } @@ -1413,8 +1407,10 @@ namespace Assimp { unsigned int count = 0; const unsigned int* outIndices = mesh.ToOutputVertexIndex(index, count); for (unsigned int k = 0; k < count; k++) { - unsigned int index = translateIndexMap[outIndices[k]]; - + unsigned int outIndex = outIndices[k]; + if (translateIndexMap.find(outIndex) == translateIndexMap.end()) + continue; + unsigned int index = translateIndexMap[outIndex]; animMesh->mVertices[index] += vertex; if (animMesh->mNormals != nullptr) { animMesh->mNormals[index] += normal; @@ -1428,6 +1424,15 @@ namespace Assimp { } } + const size_t numAnimMeshes = animMeshes.size(); + if (numAnimMeshes > 0) { + out_mesh->mNumAnimMeshes = static_cast(numAnimMeshes); + out_mesh->mAnimMeshes = new aiAnimMesh*[numAnimMeshes]; + for (size_t i = 0; i < numAnimMeshes; i++) { + out_mesh->mAnimMeshes[i] = animMeshes.at(i); + } + } + return static_cast(meshes.size() - 1); } @@ -1733,9 +1738,8 @@ namespace Assimp { } void FBXConverter::TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, - const std::string& propName, - aiTextureType target, const MeshGeometry* const mesh) - { + const std::string& propName, + aiTextureType target, const MeshGeometry* const mesh) { TextureMap::const_iterator it = textures.find(propName); if (it == textures.end()) { return; diff --git a/code/FBX/FBXConverter.h b/code/FBX/FBXConverter.h index dba7c0a05..17a7bc56b 100644 --- a/code/FBX/FBXConverter.h +++ b/code/FBX/FBXConverter.h @@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FBXUtil.h" #include "FBXProperties.h" #include "FBXImporter.h" + #include #include #include diff --git a/code/FBX/FBXDocument.h b/code/FBX/FBXDocument.h index 53bd65878..18e5c38f1 100644 --- a/code/FBX/FBXDocument.h +++ b/code/FBX/FBXDocument.h @@ -627,7 +627,7 @@ public: return content; } - uint32_t ContentLength() const { + uint64_t ContentLength() const { return contentLength; } diff --git a/code/FBX/FBXParser.cpp b/code/FBX/FBXParser.cpp index 5d5c2c6c1..4a9346040 100644 --- a/code/FBX/FBXParser.cpp +++ b/code/FBX/FBXParser.cpp @@ -963,7 +963,6 @@ void ParseVectorDataArray(std::vector& out, const Element& el) } } - // ------------------------------------------------------------------------------------------------ // read an array of uints void ParseVectorDataArray(std::vector& out, const Element& el) @@ -1280,7 +1279,6 @@ float ParseTokenAsFloat(const Token& t) return i; } - // ------------------------------------------------------------------------------------------------ // wrapper around ParseTokenAsInt() with ParseError handling int ParseTokenAsInt(const Token& t) @@ -1293,8 +1291,6 @@ int ParseTokenAsInt(const Token& t) return i; } - - // ------------------------------------------------------------------------------------------------ // wrapper around ParseTokenAsInt64() with ParseError handling int64_t ParseTokenAsInt64(const Token& t) diff --git a/code/Obj/ObjFileParser.cpp b/code/Obj/ObjFileParser.cpp index d1603c6f0..97ef4af70 100644 --- a/code/Obj/ObjFileParser.cpp +++ b/code/Obj/ObjFileParser.cpp @@ -118,7 +118,7 @@ void ObjFileParser::parseFile( IOStreamBuffer &streamBuffer ) { size_t lastFilePos( 0 ); std::vector buffer; - while ( streamBuffer.getNextDataLine( buffer, '\0' ) ) { + while ( streamBuffer.getNextDataLine( buffer, '\\' ) ) { m_DataIt = buffer.begin(); m_DataItEnd = buffer.end(); diff --git a/code/Unreal/UnrealLoader.h b/code/Unreal/UnrealLoader.h index f846eb43a..678aaa76b 100644 --- a/code/Unreal/UnrealLoader.h +++ b/code/Unreal/UnrealLoader.h @@ -127,7 +127,8 @@ inline void CompressVertex(const aiVector3D& v, uint32_t& out) n.X = (int32_t)v.x; n.Y = (int32_t)v.y; n.Z = (int32_t)v.z; - out = t; + ::memcpy( &out, &t, sizeof(int32_t)); + //out = t; } // UNREAL vertex decompression diff --git a/include/assimp/camera.h b/include/assimp/camera.h index dd45d90d1..e573eea5d 100644 --- a/include/assimp/camera.h +++ b/include/assimp/camera.h @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2019, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -60,7 +58,7 @@ extern "C" { * * Cameras have a representation in the node graph and can be animated. * An important aspect is that the camera itself is also part of the - * scenegraph. This means, any values such as the look-at vector are not + * scene-graph. This means, any values such as the look-at vector are not * *absolute*, they're relative to the coordinate system defined * by the node which corresponds to the camera. This allows for camera * animations. For static cameras parameters like the 'look-at' or 'up' vectors diff --git a/include/assimp/config.h.in b/include/assimp/config.h.in index c42aa63da..d08b929a1 100644 --- a/include/assimp/config.h.in +++ b/include/assimp/config.h.in @@ -142,7 +142,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @brief Specifies the maximum angle that may be between two vertex tangents * that their tangents and bi-tangents are smoothed. * - * This applies to the CalcTangentSpace-Step. The angle is specified + * This applies to the CalcTangentSpace-Step. TFvhe angle is specified * in degrees. The maximum value is 175. * Property type: float. Default value: 45 degrees */ @@ -981,8 +981,12 @@ enum aiComponent #define AI_CONFIG_EXPORT_XFILE_64BIT "EXPORT_XFILE_64BIT" -/** - * +/** @brief Specifies whether the assimp export shall be able to export point clouds + * + * When this flag is not defined the render data has to contain valid faces. + * Point clouds are only a collection of vertices which have nor spatial organization + * by a face and the validation process will remove them. Enabling this feature will + * switch off the flag and enable the functionality to export pure point clouds. */ #define AI_CONFIG_EXPORT_POINT_CLOUDS "EXPORT_POINT_CLOUDS" diff --git a/port/PyAssimp/pyassimp/helper.py b/port/PyAssimp/pyassimp/helper.py index 62384f54f..4003fb5ad 100644 --- a/port/PyAssimp/pyassimp/helper.py +++ b/port/PyAssimp/pyassimp/helper.py @@ -274,6 +274,8 @@ def hasattr_silent(object, name): """ try: + if not object: + return False return hasattr(object, name) except AttributeError: return False diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 000000000..b652d6aae --- /dev/null +++ b/test/.gitignore @@ -0,0 +1,3 @@ +# Ignore Unit Test Output files + +*_out.* diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 737a34610..913813c3b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -120,6 +120,7 @@ SET( IMPORTERS unit/utB3DImportExport.cpp unit/utMDCImportExport.cpp unit/utAssbinImportExport.cpp + unit/ImportExport/utAssjsonImportExport.cpp unit/ImportExport/utCOBImportExport.cpp unit/ImportExport/utOgreImportExport.cpp unit/ImportExport/utQ3BSPFileImportExport.cpp @@ -165,11 +166,11 @@ SET( POST_PROCESSES ) SOURCE_GROUP( UnitTests\\Compiler FILES unit/CCompilerTest.c ) -SOURCE_GROUP( UnitTests\\Common FILES ${COMMON} ) -SOURCE_GROUP( UnitTests\\Importers FILES ${IMPORTERS} ) -SOURCE_GROUP( UnitTests\\Material FILES ${MATERIAL} ) -SOURCE_GROUP( UnitTests\\Math FILES ${MATH} ) -SOURCE_GROUP( UnitTests\\PostProcess FILES ${POST_PROCESSES}) +SOURCE_GROUP( UnitTests\\Common FILES ${COMMON} ) +SOURCE_GROUP( UnitTests\\ImportExport FILES ${IMPORTERS} ) +SOURCE_GROUP( UnitTests\\Material FILES ${MATERIAL} ) +SOURCE_GROUP( UnitTests\\Math FILES ${MATH} ) +SOURCE_GROUP( UnitTests\\PostProcess FILES ${POST_PROCESSES}) add_executable( unit ../contrib/gtest/src/gtest-all.cc diff --git a/test/models/JT/conrod.jt b/test/models/JT/conrod.jt new file mode 100644 index 000000000..566507720 Binary files /dev/null and b/test/models/JT/conrod.jt differ diff --git a/test/models/PLY/cube_test.ply b/test/models/PLY/cube_test.ply deleted file mode 100644 index eef7cd426..000000000 --- a/test/models/PLY/cube_test.ply +++ /dev/null @@ -1,24 +0,0 @@ -ply -format ascii 1.0 -comment Created by Open Asset Import Library - http://assimp.sf.net (v4.1.649942190) -element vertex 8 -property float x -property float y -property float z -element face 6 -property list uchar int vertex_index -end_header -0 0 0 -0 0 1 -0 1 1 -0 1 0 -1 0 0 -1 0 1 -1 1 1 -1 1 0 -4 0 1 2 3 -4 7 6 5 4 -4 0 4 5 1 -4 1 5 6 2 -4 2 6 7 3 -4 3 7 4 0 diff --git a/test/unit/AbstractImportExportBase.h b/test/unit/AbstractImportExportBase.h index 529b9cf7d..d6ae37d60 100644 --- a/test/unit/AbstractImportExportBase.h +++ b/test/unit/AbstractImportExportBase.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -39,17 +39,37 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ #pragma once +#ifndef AI_ABSTRACTIMPORTEXPORTBASE_H_INC +#define AI_ABSTRACTIMPORTEXPORTBASE_H_INC #include "UnitTestPCH.h" +// --------------------------------------------------------------------------- +/** Abstract base class to test import and export + */ + // --------------------------------------------------------------------------- class AbstractImportExportBase : public ::testing::Test { public: + /// @brief The class destructor. virtual ~AbstractImportExportBase(); - virtual bool importerTest() = 0; + + /// @brief The importer-test, will return true for successful import. + /// @return true for success, false for failure. + virtual bool importerTest(); + + /// @brief The exporter-test, will return true for successful import. + /// @return true for success, false for failure. virtual bool exporterTest(); }; +inline +bool AbstractImportExportBase::importerTest() { + return true; +} + inline bool AbstractImportExportBase::exporterTest() { return true; } + +#endif // AI_ABSTRACTIMPORTEXPORTBASE_H_INC diff --git a/test/unit/ImportExport/utAssjsonImportExport.cpp b/test/unit/ImportExport/utAssjsonImportExport.cpp new file mode 100644 index 000000000..20a2a9e24 --- /dev/null +++ b/test/unit/ImportExport/utAssjsonImportExport.cpp @@ -0,0 +1,69 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2019, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ +#include "UnitTestPCH.h" +#include "AbstractImportExportBase.h" + +#include +#include +#include +#include + +using namespace Assimp; + +#ifndef ASSIMP_BUILD_NO_EXPORT + +class utAssjsonImportExport : public AbstractImportExportBase { +public: + bool exporterTest() override { + Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj", aiProcess_ValidateDataStructure); + + Exporter exporter; + aiReturn res = exporter.Export(scene, "json", "./spider_test.json"); + return aiReturn_SUCCESS == res; + } +}; + +TEST_F(utAssjsonImportExport, exportTest) { + EXPECT_TRUE(exporterTest()); +} + +#endif // ASSIMP_BUILD_NO_EXPORT diff --git a/test/unit/utAMFImportExport.cpp b/test/unit/utAMFImportExport.cpp index dc2c9b99b..6eb0b4418 100644 --- a/test/unit/utAMFImportExport.cpp +++ b/test/unit/utAMFImportExport.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2019, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/test/unit/utASEImportExport.cpp b/test/unit/utASEImportExport.cpp index 28168de7d..313f0f83a 100644 --- a/test/unit/utASEImportExport.cpp +++ b/test/unit/utASEImportExport.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2019, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/test/unit/utAssbinImportExport.cpp b/test/unit/utAssbinImportExport.cpp index 6def04796..42504df56 100644 --- a/test/unit/utAssbinImportExport.cpp +++ b/test/unit/utAssbinImportExport.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2019, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -53,20 +51,20 @@ using namespace Assimp; class utAssbinImportExport : public AbstractImportExportBase { public: - virtual bool importerTest() { - Assimp::Importer importer; + bool importerTest() override { + Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj", aiProcess_ValidateDataStructure ); Exporter exporter; - EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "assbin", ASSIMP_TEST_MODELS_DIR "/OBJ/spider_test.assbin" ) ); - const aiScene *newScene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/spider_test.assbin", aiProcess_ValidateDataStructure ); + EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "assbin", ASSIMP_TEST_MODELS_DIR "/OBJ/spider_out.assbin" ) ); + const aiScene *newScene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/spider_out.assbin", aiProcess_ValidateDataStructure ); return newScene != nullptr; } }; TEST_F( utAssbinImportExport, exportAssbin3DFromFileTest ) { - Assimp::Importer importer; + Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj", aiProcess_ValidateDataStructure ); EXPECT_NE( nullptr, scene ); } diff --git a/test/unit/utB3DImportExport.cpp b/test/unit/utB3DImportExport.cpp index d51ca51a6..ea75b1939 100644 --- a/test/unit/utB3DImportExport.cpp +++ b/test/unit/utB3DImportExport.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2019, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/test/unit/utBlenderWork.cpp b/test/unit/utBlenderWork.cpp index 65fefde28..c0e3347ab 100644 --- a/test/unit/utBlenderWork.cpp +++ b/test/unit/utBlenderWork.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2019, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -73,11 +71,6 @@ TEST_F(BlenderWorkTest,work_279) { ASSERT_TRUE(pTest->HasMaterials()); ASSERT_TRUE(pTest->HasMeshes()); ASSERT_TRUE(pTest->mMeshes[0]->mNumVertices > 0); - ASSERT_EQ(44, pTest->mMeshes[0]->mNumFaces); - EXPECT_EQ(1, pTest->mNumMaterials); + ASSERT_EQ(44u, pTest->mMeshes[0]->mNumFaces); + EXPECT_EQ(1u, pTest->mNumMaterials); } - - - - - diff --git a/test/unit/utFBXImporterExporter.cpp b/test/unit/utFBXImporterExporter.cpp index 3180d96a2..55471c023 100644 --- a/test/unit/utFBXImporterExporter.cpp +++ b/test/unit/utFBXImporterExporter.cpp @@ -70,10 +70,10 @@ TEST_F( utFBXImporterExporter, importBareBoxWithoutColorsAndTextureCoords ) { Assimp::Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/FBX/box.fbx", aiProcess_ValidateDataStructure ); EXPECT_NE( nullptr, scene ); - EXPECT_EQ(scene->mNumMeshes, 1); + EXPECT_EQ(scene->mNumMeshes, 1u); aiMesh* mesh = scene->mMeshes[0]; - EXPECT_EQ(mesh->mNumFaces, 12); - EXPECT_EQ(mesh->mNumVertices, 36); + EXPECT_EQ(mesh->mNumFaces, 12u); + EXPECT_EQ(mesh->mNumVertices, 36u); } TEST_F(utFBXImporterExporter, importCubesWithNoNames) { @@ -85,13 +85,13 @@ TEST_F(utFBXImporterExporter, importCubesWithNoNames) { const auto root = scene->mRootNode; ASSERT_STREQ(root->mName.C_Str(), "RootNode"); ASSERT_TRUE(root->mChildren); - ASSERT_EQ(root->mNumChildren, 2); + ASSERT_EQ(root->mNumChildren, 2u); const auto child0 = root->mChildren[0]; ASSERT_TRUE(child0); ASSERT_STREQ(child0->mName.C_Str(), "RootNode001"); ASSERT_TRUE(child0->mChildren); - ASSERT_EQ(child0->mNumChildren, 1); + ASSERT_EQ(child0->mNumChildren, 1u); const auto child00 = child0->mChildren[0]; ASSERT_TRUE(child00); @@ -101,7 +101,7 @@ TEST_F(utFBXImporterExporter, importCubesWithNoNames) { ASSERT_TRUE(child1); ASSERT_STREQ(child1->mName.C_Str(), "RootNode002"); ASSERT_TRUE(child1->mChildren); - ASSERT_EQ(child1->mNumChildren, 1); + ASSERT_EQ(child1->mNumChildren, 1u); const auto child10 = child1->mChildren[0]; ASSERT_TRUE(child10); @@ -117,13 +117,13 @@ TEST_F(utFBXImporterExporter, importCubesWithUnicodeDuplicatedNames) { const auto root = scene->mRootNode; ASSERT_STREQ(root->mName.C_Str(), "RootNode"); ASSERT_TRUE(root->mChildren); - ASSERT_EQ(root->mNumChildren, 2); + ASSERT_EQ(root->mNumChildren, 2u); const auto child0 = root->mChildren[0]; ASSERT_TRUE(child0); ASSERT_STREQ(child0->mName.C_Str(), "Cube2"); ASSERT_TRUE(child0->mChildren); - ASSERT_EQ(child0->mNumChildren, 1); + ASSERT_EQ(child0->mNumChildren, 1u); const auto child00 = child0->mChildren[0]; ASSERT_TRUE(child00); @@ -133,7 +133,7 @@ TEST_F(utFBXImporterExporter, importCubesWithUnicodeDuplicatedNames) { ASSERT_TRUE(child1); ASSERT_STREQ(child1->mName.C_Str(), "Cube3"); ASSERT_TRUE(child1->mChildren); - ASSERT_EQ(child1->mNumChildren, 1); + ASSERT_EQ(child1->mNumChildren, 1u); const auto child10 = child1->mChildren[0]; ASSERT_TRUE(child10); @@ -149,13 +149,13 @@ TEST_F(utFBXImporterExporter, importCubesComplexTransform) { const auto root = scene->mRootNode; ASSERT_STREQ(root->mName.C_Str(), "RootNode"); ASSERT_TRUE(root->mChildren); - ASSERT_EQ(root->mNumChildren, 2); + ASSERT_EQ(root->mNumChildren, 2u); const auto child0 = root->mChildren[0]; ASSERT_TRUE(child0); ASSERT_STREQ(child0->mName.C_Str(), "Cube2"); ASSERT_TRUE(child0->mChildren); - ASSERT_EQ(child0->mNumChildren, 1); + ASSERT_EQ(child0->mNumChildren, 1u); const auto child00 = child0->mChildren[0]; ASSERT_TRUE(child00); @@ -177,35 +177,36 @@ TEST_F(utFBXImporterExporter, importCubesComplexTransform) { "Cube1001_$AssimpFbx$_ScalingPivotInverse", "Cube1001" }; - for (size_t i = 0; i < chain_length; ++i) - { + for (size_t i = 0; i < chain_length; ++i) { ASSERT_TRUE(parent->mChildren); - ASSERT_EQ(parent->mNumChildren, 1); + ASSERT_EQ(parent->mNumChildren, 1u); auto node = parent->mChildren[0]; ASSERT_TRUE(node); ASSERT_STREQ(node->mName.C_Str(), chainStr[i]); parent = node; } - ASSERT_EQ(0, parent->mNumChildren) << "Leaf node"; + ASSERT_EQ(0u, parent->mNumChildren) << "Leaf node"; } TEST_F( utFBXImporterExporter, importPhongMaterial ) { Assimp::Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/FBX/phong_cube.fbx", aiProcess_ValidateDataStructure ); EXPECT_NE( nullptr, scene ); - EXPECT_EQ( (unsigned int)1, scene->mNumMaterials ); + EXPECT_EQ( 1u, scene->mNumMaterials ); const aiMaterial *mat = scene->mMaterials[0]; EXPECT_NE( nullptr, mat ); - float f; aiColor3D c; + float f; + aiColor3D c; + // phong_cube.fbx has all properties defined EXPECT_EQ( mat->Get(AI_MATKEY_COLOR_DIFFUSE, c), aiReturn_SUCCESS ); EXPECT_EQ( c, aiColor3D(0.5, 0.25, 0.25) ); EXPECT_EQ( mat->Get(AI_MATKEY_COLOR_SPECULAR, c), aiReturn_SUCCESS ); EXPECT_EQ( c, aiColor3D(0.25, 0.25, 0.5) ); EXPECT_EQ( mat->Get(AI_MATKEY_SHININESS_STRENGTH, f), aiReturn_SUCCESS ); - EXPECT_EQ( f, 0.5 ); + EXPECT_EQ( f, 0.5f ); EXPECT_EQ( mat->Get(AI_MATKEY_SHININESS, f), aiReturn_SUCCESS ); - EXPECT_EQ( f, 10.0 ); + EXPECT_EQ( f, 10.0f ); EXPECT_EQ( mat->Get(AI_MATKEY_COLOR_AMBIENT, c), aiReturn_SUCCESS ); EXPECT_EQ( c, aiColor3D(0.125, 0.25, 0.25) ); EXPECT_EQ( mat->Get(AI_MATKEY_COLOR_EMISSIVE, c), aiReturn_SUCCESS ); @@ -213,7 +214,7 @@ TEST_F( utFBXImporterExporter, importPhongMaterial ) { EXPECT_EQ( mat->Get(AI_MATKEY_COLOR_TRANSPARENT, c), aiReturn_SUCCESS ); EXPECT_EQ( c, aiColor3D(0.75, 0.5, 0.25) ); EXPECT_EQ( mat->Get(AI_MATKEY_OPACITY, f), aiReturn_SUCCESS ); - EXPECT_EQ( f, 0.5 ); + EXPECT_EQ( f, 0.5f ); } TEST_F(utFBXImporterExporter, importUnitScaleFactor) { @@ -234,7 +235,7 @@ TEST_F(utFBXImporterExporter, importEmbeddedAsciiTest) { const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/embedded_ascii/box.FBX", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(1, scene->mNumMaterials); + EXPECT_EQ(1u, scene->mNumMaterials); aiMaterial *mat = scene->mMaterials[0]; ASSERT_NE(nullptr, mat); @@ -243,7 +244,7 @@ TEST_F(utFBXImporterExporter, importEmbeddedAsciiTest) { EXPECT_EQ(aiReturn_SUCCESS, mat->GetTexture(aiTextureType_DIFFUSE, 0, &path, nullptr, nullptr, nullptr, nullptr, modes)); ASSERT_STREQ(path.C_Str(), "..\\..\\..\\Desktop\\uv_test.png"); - ASSERT_EQ(1, scene->mNumTextures); + ASSERT_EQ(1u, scene->mNumTextures); ASSERT_TRUE(scene->mTextures[0]->pcData); ASSERT_EQ(439176u, scene->mTextures[0]->mWidth) << "FBX ASCII base64 compression splits data by 512Kb, it should be two parts for this texture"; } @@ -254,7 +255,7 @@ TEST_F(utFBXImporterExporter, importEmbeddedFragmentedAsciiTest) { const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/embedded_ascii/box_embedded_texture_fragmented.fbx", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(1, scene->mNumMaterials); + EXPECT_EQ(1u, scene->mNumMaterials); aiMaterial *mat = scene->mMaterials[0]; ASSERT_NE(nullptr, mat); @@ -263,7 +264,7 @@ TEST_F(utFBXImporterExporter, importEmbeddedFragmentedAsciiTest) { ASSERT_EQ(aiReturn_SUCCESS, mat->GetTexture(aiTextureType_DIFFUSE, 0, &path, nullptr, nullptr, nullptr, nullptr, modes)); ASSERT_STREQ(path.C_Str(), "paper.png"); - ASSERT_EQ(1, scene->mNumTextures); + ASSERT_EQ(1u, scene->mNumTextures); ASSERT_TRUE(scene->mTextures[0]->pcData); ASSERT_EQ(968029u, scene->mTextures[0]->mWidth) << "FBX ASCII base64 compression splits data by 512Kb, it should be two parts for this texture"; } diff --git a/test/unit/utFindDegenerates.cpp b/test/unit/utFindDegenerates.cpp index ea539df27..064031f34 100644 --- a/test/unit/utFindDegenerates.cpp +++ b/test/unit/utFindDegenerates.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2019, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -49,35 +47,42 @@ using namespace Assimp; class FindDegeneratesProcessTest : public ::testing::Test { public: + FindDegeneratesProcessTest() + : Test() + , mMesh( nullptr ) + , mProcess( nullptr ) { + // empty + } + +protected: virtual void SetUp(); virtual void TearDown(); protected: - aiMesh* mesh; - FindDegeneratesProcess* process; + aiMesh* mMesh; + FindDegeneratesProcess* mProcess; }; -// ------------------------------------------------------------------------------------------------ void FindDegeneratesProcessTest::SetUp() { - mesh = new aiMesh(); - process = new FindDegeneratesProcess(); + mMesh = new aiMesh(); + mProcess = new FindDegeneratesProcess(); - mesh->mNumFaces = 1000; - mesh->mFaces = new aiFace[1000]; + mMesh->mNumFaces = 1000; + mMesh->mFaces = new aiFace[1000]; - mesh->mNumVertices = 5000*2; - mesh->mVertices = new aiVector3D[5000*2]; + mMesh->mNumVertices = 5000*2; + mMesh->mVertices = new aiVector3D[5000*2]; for (unsigned int i = 0; i < 5000; ++i) { - mesh->mVertices[i] = mesh->mVertices[i+5000] = aiVector3D((float)i); + mMesh->mVertices[i] = mMesh->mVertices[i+5000] = aiVector3D((float)i); } - mesh->mPrimitiveTypes = aiPrimitiveType_LINE | aiPrimitiveType_POINT | + mMesh->mPrimitiveTypes = aiPrimitiveType_LINE | aiPrimitiveType_POINT | aiPrimitiveType_POLYGON | aiPrimitiveType_TRIANGLE; unsigned int numOut = 0, numFaces = 0; for (unsigned int i = 0; i < 1000; ++i) { - aiFace& f = mesh->mFaces[i]; + aiFace& f = mMesh->mFaces[i]; f.mNumIndices = (i % 5)+1; // between 1 and 5 f.mIndices = new unsigned int[f.mNumIndices]; bool had = false; @@ -102,46 +107,46 @@ void FindDegeneratesProcessTest::SetUp() { if (!had) ++numFaces; } - mesh->mNumUVComponents[0] = numOut; - mesh->mNumUVComponents[1] = numFaces; + mMesh->mNumUVComponents[0] = numOut; + mMesh->mNumUVComponents[1] = numFaces; } void FindDegeneratesProcessTest::TearDown() { - delete mesh; - delete process; + delete mMesh; + delete mProcess; } TEST_F(FindDegeneratesProcessTest, testDegeneratesDetection) { - process->EnableInstantRemoval(false); - process->ExecuteOnMesh(mesh); + mProcess->EnableInstantRemoval(false); + mProcess->ExecuteOnMesh(mMesh); unsigned int out = 0; for (unsigned int i = 0; i < 1000; ++i) { - aiFace& f = mesh->mFaces[i]; + aiFace& f = mMesh->mFaces[i]; out += f.mNumIndices; } - EXPECT_EQ(1000U, mesh->mNumFaces); - EXPECT_EQ(10000U, mesh->mNumVertices); - EXPECT_EQ(out, mesh->mNumUVComponents[0]); + EXPECT_EQ(1000U, mMesh->mNumFaces); + EXPECT_EQ(10000U, mMesh->mNumVertices); + EXPECT_EQ(out, mMesh->mNumUVComponents[0]); EXPECT_EQ(static_cast( aiPrimitiveType_LINE | aiPrimitiveType_POINT | aiPrimitiveType_POLYGON | aiPrimitiveType_TRIANGLE), - mesh->mPrimitiveTypes); + mMesh->mPrimitiveTypes); } TEST_F(FindDegeneratesProcessTest, testDegeneratesRemoval) { - process->EnableAreaCheck(false); - process->EnableInstantRemoval(true); - process->ExecuteOnMesh(mesh); + mProcess->EnableAreaCheck(false); + mProcess->EnableInstantRemoval(true); + mProcess->ExecuteOnMesh(mMesh); - EXPECT_EQ(mesh->mNumUVComponents[1], mesh->mNumFaces); + EXPECT_EQ(mMesh->mNumUVComponents[1], mMesh->mNumFaces); } TEST_F(FindDegeneratesProcessTest, testDegeneratesRemovalWithAreaCheck) { - process->EnableAreaCheck(true); - process->EnableInstantRemoval(true); - process->ExecuteOnMesh(mesh); + mProcess->EnableAreaCheck(true); + mProcess->EnableInstantRemoval(true); + mProcess->ExecuteOnMesh(mMesh); - EXPECT_EQ(mesh->mNumUVComponents[1]-100, mesh->mNumFaces); + EXPECT_EQ(mMesh->mNumUVComponents[1]-100, mMesh->mNumFaces); } diff --git a/test/unit/utFindInvalidData.cpp b/test/unit/utFindInvalidData.cpp index 5b874a2a4..7c70a71a9 100644 --- a/test/unit/utFindInvalidData.cpp +++ b/test/unit/utFindInvalidData.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2019, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -48,89 +46,100 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace std; using namespace Assimp; -class FindInvalidDataProcessTest : public ::testing::Test -{ +class utFindInvalidDataProcess : public ::testing::Test { public: + utFindInvalidDataProcess() + : Test() + , mMesh(nullptr) + , mProcess(nullptr) { + // empty + } + +protected: virtual void SetUp(); virtual void TearDown(); protected: - aiMesh* pcMesh; - FindInvalidDataProcess* piProcess; + aiMesh* mMesh; + FindInvalidDataProcess* mProcess; }; // ------------------------------------------------------------------------------------------------ -void FindInvalidDataProcessTest::SetUp() { +void utFindInvalidDataProcess::SetUp() { ASSERT_TRUE( AI_MAX_NUMBER_OF_TEXTURECOORDS >= 3); - piProcess = new FindInvalidDataProcess(); - pcMesh = new aiMesh(); + mProcess = new FindInvalidDataProcess(); + mMesh = new aiMesh(); - pcMesh->mNumVertices = 1000; - pcMesh->mVertices = new aiVector3D[1000]; - for (unsigned int i = 0; i < 1000;++i) - pcMesh->mVertices[i] = aiVector3D((float)i); + mMesh->mNumVertices = 1000; + mMesh->mVertices = new aiVector3D[1000]; + for (unsigned int i = 0; i < 1000; ++i) { + mMesh->mVertices[i] = aiVector3D((float)i); + } - pcMesh->mNormals = new aiVector3D[1000]; - for (unsigned int i = 0; i < 1000;++i) - pcMesh->mNormals[i] = aiVector3D((float)i+1); + mMesh->mNormals = new aiVector3D[1000]; + for (unsigned int i = 0; i < 1000; ++i) { + mMesh->mNormals[i] = aiVector3D((float)i + 1); + } - pcMesh->mTangents = new aiVector3D[1000]; - for (unsigned int i = 0; i < 1000;++i) - pcMesh->mTangents[i] = aiVector3D((float)i); + mMesh->mTangents = new aiVector3D[1000]; + for (unsigned int i = 0; i < 1000; ++i) { + mMesh->mTangents[i] = aiVector3D((float)i); + } - pcMesh->mBitangents = new aiVector3D[1000]; - for (unsigned int i = 0; i < 1000;++i) - pcMesh->mBitangents[i] = aiVector3D((float)i); + mMesh->mBitangents = new aiVector3D[1000]; + for (unsigned int i = 0; i < 1000; ++i) { + mMesh->mBitangents[i] = aiVector3D((float)i); + } - for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) - { - pcMesh->mTextureCoords[a] = new aiVector3D[1000]; - for (unsigned int i = 0; i < 1000;++i) - pcMesh->mTextureCoords[a][i] = aiVector3D((float)i); + for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) { + mMesh->mTextureCoords[a] = new aiVector3D[1000]; + for (unsigned int i = 0; i < 1000; ++i) { + mMesh->mTextureCoords[a][i] = aiVector3D((float)i); + } } } // ------------------------------------------------------------------------------------------------ -void FindInvalidDataProcessTest::TearDown() -{ - delete piProcess; - delete pcMesh; +void utFindInvalidDataProcess::TearDown() { + delete mProcess; + delete mMesh; } // ------------------------------------------------------------------------------------------------ -TEST_F(FindInvalidDataProcessTest, testStepNegativeResult) -{ - ::memset(pcMesh->mNormals,0,pcMesh->mNumVertices*sizeof(aiVector3D)); - ::memset(pcMesh->mBitangents,0,pcMesh->mNumVertices*sizeof(aiVector3D)); +TEST_F(utFindInvalidDataProcess, testStepNegativeResult) { + ::memset(mMesh->mNormals, 0, mMesh->mNumVertices*sizeof(aiVector3D) ); + ::memset(mMesh->mBitangents, 0, mMesh->mNumVertices*sizeof(aiVector3D) ); - pcMesh->mTextureCoords[2][455] = aiVector3D( std::numeric_limits::quiet_NaN() ); + mMesh->mTextureCoords[2][455] = aiVector3D( std::numeric_limits::quiet_NaN() ); - piProcess->ProcessMesh(pcMesh); + mProcess->ProcessMesh(mMesh); - EXPECT_TRUE(NULL != pcMesh->mVertices); - EXPECT_TRUE(NULL == pcMesh->mNormals); - EXPECT_TRUE(NULL == pcMesh->mTangents); - EXPECT_TRUE(NULL == pcMesh->mBitangents); + EXPECT_TRUE(NULL != mMesh->mVertices); + EXPECT_EQ(NULL, mMesh->mNormals); + EXPECT_EQ(NULL, mMesh->mTangents); + EXPECT_EQ(NULL, mMesh->mBitangents); - for (unsigned int i = 0; i < 2;++i) - EXPECT_TRUE(NULL != pcMesh->mTextureCoords[i]); + for (unsigned int i = 0; i < 2; ++i) { + EXPECT_TRUE(NULL != mMesh->mTextureCoords[i]); + } - for (unsigned int i = 2; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) - EXPECT_TRUE(NULL == pcMesh->mTextureCoords[i]); + for (unsigned int i = 2; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { + EXPECT_EQ(NULL, mMesh->mTextureCoords[i]); + } } // ------------------------------------------------------------------------------------------------ -TEST_F(FindInvalidDataProcessTest, testStepPositiveResult) -{ - piProcess->ProcessMesh(pcMesh); +TEST_F(utFindInvalidDataProcess, testStepPositiveResult) { + mProcess->ProcessMesh(mMesh); - EXPECT_TRUE(NULL != pcMesh->mVertices); + EXPECT_NE(nullptr, mMesh->mVertices); - EXPECT_TRUE(NULL != pcMesh->mNormals); - EXPECT_TRUE(NULL != pcMesh->mTangents); - EXPECT_TRUE(NULL != pcMesh->mBitangents); + EXPECT_NE(nullptr, mMesh->mNormals); + EXPECT_NE(nullptr, mMesh->mTangents); + EXPECT_NE(nullptr, mMesh->mBitangents); - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) - EXPECT_TRUE(NULL != pcMesh->mTextureCoords[i]); + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { + EXPECT_NE(nullptr, mMesh->mTextureCoords[i]); + } } diff --git a/test/unit/utGenBoundingBoxesProcess.cpp b/test/unit/utGenBoundingBoxesProcess.cpp index a26edb7e3..2c2f831bc 100644 --- a/test/unit/utGenBoundingBoxesProcess.cpp +++ b/test/unit/utGenBoundingBoxesProcess.cpp @@ -48,13 +48,21 @@ using namespace Assimp; class utGenBoundingBoxesProcess : public ::testing::Test { public: + utGenBoundingBoxesProcess() + : Test() + , mProcess(nullptr) + , mMesh(nullptr) + , mScene(nullptr) { + // empty + } + void SetUp() override { mProcess = new GenBoundingBoxesProcess; mMesh = new aiMesh(); mMesh->mNumVertices = 100; mMesh->mVertices = new aiVector3D[100]; for (unsigned int i = 0; i < 100; ++i) { - mMesh->mVertices[i] = aiVector3D(i, i, i); + mMesh->mVertices[i] = aiVector3D((ai_real)i, (ai_real)i, (ai_real)i); } mScene = new aiScene(); mScene->mNumMeshes = 1; diff --git a/test/unit/utIssues.cpp b/test/unit/utIssues.cpp index 6a974d7b9..0e30fa182 100644 --- a/test/unit/utIssues.cpp +++ b/test/unit/utIssues.cpp @@ -74,7 +74,7 @@ TEST_F( utIssues, OpacityBugWhenExporting_727 ) { if ( newScene->mNumMaterials > 0 ) { std::cout << "Desc = " << desc->description << "\n"; EXPECT_EQ( AI_SUCCESS, newScene->mMaterials[ 0 ]->Get( AI_MATKEY_OPACITY, newOpacity ) ); - EXPECT_EQ( opacity, newOpacity ); + EXPECT_FLOAT_EQ( opacity, newOpacity ); } delete scene; } diff --git a/test/unit/utJoinVertices.cpp b/test/unit/utJoinVertices.cpp index 6b832b73d..215b0dd90 100644 --- a/test/unit/utJoinVertices.cpp +++ b/test/unit/utJoinVertices.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2019, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -49,8 +47,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace std; using namespace Assimp; -class JoinVerticesTest : public ::testing::Test { +class utJoinVertices : public ::testing::Test { public: + utJoinVertices() + : Test() + , piProcess(nullptr) + , pcMesh(nullptr) { + // empty + } + +protected: virtual void SetUp(); virtual void TearDown(); @@ -60,8 +66,7 @@ protected: }; // ------------------------------------------------------------------------------------------------ -void JoinVerticesTest::SetUp() -{ +void utJoinVertices::SetUp() { // construct the process piProcess = new JoinVerticesProcess(); @@ -71,11 +76,9 @@ void JoinVerticesTest::SetUp() pcMesh->mNumVertices = 900; aiVector3D*& pv = pcMesh->mVertices = new aiVector3D[900]; - for (unsigned int i = 0; i < 3;++i) - { + for (unsigned int i = 0; i < 3;++i) { const unsigned int base = i*300; - for (unsigned int a = 0; a < 300;++a) - { + for (unsigned int a = 0; a < 300;++a) { pv[base+a].x = pv[base+a].y = pv[base+a].z = (float)a; } } @@ -83,38 +86,37 @@ void JoinVerticesTest::SetUp() // generate faces - each vertex is referenced once pcMesh->mNumFaces = 300; pcMesh->mFaces = new aiFace[300]; - for (unsigned int i = 0,p = 0; i < 300;++i) - { + for (unsigned int i = 0,p = 0; i < 300;++i) { aiFace& face = pcMesh->mFaces[i]; face.mIndices = new unsigned int[ face.mNumIndices = 3 ]; - for (unsigned int a = 0; a < 3;++a) + for (unsigned int a = 0; a < 3; ++a) { face.mIndices[a] = p++; + } } // generate extra members - set them to zero to make sure they're identical pcMesh->mTextureCoords[0] = new aiVector3D[900]; - for (unsigned int i = 0; i < 900;++i)pcMesh->mTextureCoords[0][i] = aiVector3D( 0.f ); - - pcMesh->mNormals = new aiVector3D[900]; - for (unsigned int i = 0; i < 900;++i)pcMesh->mNormals[i] = aiVector3D( 0.f ); - - pcMesh->mTangents = new aiVector3D[900]; - for (unsigned int i = 0; i < 900;++i)pcMesh->mTangents[i] = aiVector3D( 0.f ); - pcMesh->mBitangents = new aiVector3D[900]; - for (unsigned int i = 0; i < 900;++i)pcMesh->mBitangents[i] = aiVector3D( 0.f ); + pcMesh->mNormals = new aiVector3D[900]; + pcMesh->mTangents = new aiVector3D[900]; + for (unsigned int i = 0; i < 900; ++i) { + pcMesh->mTextureCoords[0][i] = aiVector3D(0.f); + pcMesh->mNormals[i] = aiVector3D(0.f); + pcMesh->mTangents[i] = aiVector3D(0.f); + pcMesh->mBitangents[i] = aiVector3D(0.f); + } } // ------------------------------------------------------------------------------------------------ -void JoinVerticesTest::TearDown() -{ +void utJoinVertices::TearDown() { delete this->pcMesh; + pcMesh = nullptr; delete this->piProcess; + piProcess = nullptr; } // ------------------------------------------------------------------------------------------------ -TEST_F(JoinVerticesTest, testProcess) -{ +TEST_F(utJoinVertices, testProcess) { // execute the step on the given data piProcess->ProcessMesh(pcMesh,0); @@ -122,15 +124,14 @@ TEST_F(JoinVerticesTest, testProcess) ASSERT_EQ(300U, pcMesh->mNumFaces); ASSERT_EQ(300U, pcMesh->mNumVertices); - ASSERT_TRUE(NULL != pcMesh->mNormals); - ASSERT_TRUE(NULL != pcMesh->mTangents); - ASSERT_TRUE(NULL != pcMesh->mBitangents); - ASSERT_TRUE(NULL != pcMesh->mTextureCoords[0]); + ASSERT_TRUE( nullptr != pcMesh->mNormals); + ASSERT_TRUE( nullptr != pcMesh->mTangents); + ASSERT_TRUE( nullptr != pcMesh->mBitangents); + ASSERT_TRUE( nullptr != pcMesh->mTextureCoords[0]); // the order doesn't care float fSum = 0.f; - for (unsigned int i = 0; i < 300;++i) - { + for (unsigned int i = 0; i < 300; ++i) { aiVector3D& v = pcMesh->mVertices[i]; fSum += v.x + v.y + v.z; @@ -141,4 +142,3 @@ TEST_F(JoinVerticesTest, testProcess) } EXPECT_EQ(150.f*299.f*3.f, fSum); // gaussian sum equation } - diff --git a/test/unit/utLimitBoneWeights.cpp b/test/unit/utLimitBoneWeights.cpp index 5172976b4..927a9e37c 100644 --- a/test/unit/utLimitBoneWeights.cpp +++ b/test/unit/utLimitBoneWeights.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2019, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -50,83 +48,83 @@ using namespace Assimp; class LimitBoneWeightsTest : public ::testing::Test { public: + LimitBoneWeightsTest() + : Test() + , mProcess(nullptr) + , mMesh(nullptr) { + // empty + } + +protected: virtual void SetUp(); virtual void TearDown(); protected: - LimitBoneWeightsProcess* piProcess; - aiMesh* pcMesh; + LimitBoneWeightsProcess *mProcess; + aiMesh *mMesh; }; // ------------------------------------------------------------------------------------------------ -void LimitBoneWeightsTest::SetUp() -{ +void LimitBoneWeightsTest::SetUp() { // construct the process - this->piProcess = new LimitBoneWeightsProcess(); + this->mProcess = new LimitBoneWeightsProcess(); // now need to create a nice mesh for testing purposes - this->pcMesh = new aiMesh(); + this->mMesh = new aiMesh(); - pcMesh->mNumVertices = 500; - pcMesh->mVertices = new aiVector3D[500]; // uninit. - pcMesh->mNumBones = 30; - pcMesh->mBones = new aiBone*[30]; + mMesh->mNumVertices = 500; + mMesh->mVertices = new aiVector3D[500]; // uninit. + mMesh->mNumBones = 30; + mMesh->mBones = new aiBone*[30]; unsigned int iCur = 0; - for (unsigned int i = 0; i < 30;++i) - { - aiBone* pc = pcMesh->mBones[i] = new aiBone(); + for (unsigned int i = 0; i < 30;++i) { + aiBone* pc = mMesh->mBones[i] = new aiBone(); pc->mNumWeights = 250; pc->mWeights = new aiVertexWeight[pc->mNumWeights]; - for (unsigned int qq = 0; qq < pc->mNumWeights;++qq) - { + for (unsigned int qq = 0; qq < pc->mNumWeights;++qq) { aiVertexWeight& v = pc->mWeights[qq]; v.mVertexId = iCur++; - if (500 == iCur)iCur = 0; + if (500 == iCur) { + iCur = 0; + } v.mWeight = 1.0f / 15; // each vertex should occur once in two bones } } } // ------------------------------------------------------------------------------------------------ -void LimitBoneWeightsTest::TearDown() -{ - delete pcMesh; - delete piProcess; +void LimitBoneWeightsTest::TearDown() { + delete mMesh; + delete mProcess; } // ------------------------------------------------------------------------------------------------ -TEST_F(LimitBoneWeightsTest, testProcess) -{ +TEST_F(LimitBoneWeightsTest, testProcess) { // execute the step on the given data - piProcess->ProcessMesh(pcMesh); + mProcess->ProcessMesh(mMesh); // check whether everything is ok ... typedef std::vector VertexWeightList; - VertexWeightList* asWeights = new VertexWeightList[pcMesh->mNumVertices]; + VertexWeightList* asWeights = new VertexWeightList[mMesh->mNumVertices]; - for (unsigned int i = 0; i < pcMesh->mNumVertices;++i) + for (unsigned int i = 0; i < mMesh->mNumVertices; ++i) { asWeights[i].reserve(4); + } // sort back as per-vertex lists - for (unsigned int i = 0; i < pcMesh->mNumBones;++i) - { - aiBone& pcBone = **(pcMesh->mBones+i); - for (unsigned int q = 0; q < pcBone.mNumWeights;++q) - { + for (unsigned int i = 0; i < mMesh->mNumBones;++i) { + aiBone& pcBone = **(mMesh->mBones+i); + for (unsigned int q = 0; q < pcBone.mNumWeights;++q) { aiVertexWeight weight = pcBone.mWeights[q]; asWeights[weight.mVertexId].push_back(LimitBoneWeightsProcess::Weight (i,weight.mWeight)); } } // now validate the size of the lists and check whether all weights sum to 1.0f - for (unsigned int i = 0; i < pcMesh->mNumVertices;++i) - { + for (unsigned int i = 0; i < mMesh->mNumVertices;++i) { EXPECT_LE(asWeights[i].size(), 4U); float fSum = 0.0f; - for (VertexWeightList::const_iterator - iter = asWeights[i].begin(); - iter != asWeights[i].end();++iter) - { + for (VertexWeightList::const_iterator iter = asWeights[i].begin(); iter != asWeights[i].end();++iter) { fSum += (*iter).mWeight; } EXPECT_GE(fSum, 0.95F); diff --git a/test/unit/utObjImportExport.cpp b/test/unit/utObjImportExport.cpp index bb0d36b13..b6cb72623 100644 --- a/test/unit/utObjImportExport.cpp +++ b/test/unit/utObjImportExport.cpp @@ -205,8 +205,8 @@ protected: ::Assimp::Exporter exporter; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj", aiProcess_ValidateDataStructure ); EXPECT_NE( nullptr, scene ); - EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "obj", ASSIMP_TEST_MODELS_DIR "/OBJ/spider_test.obj" ) ); - EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "objnomtl", ASSIMP_TEST_MODELS_DIR "/OBJ/spider_nomtl_test.obj" ) ); + EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "obj", ASSIMP_TEST_MODELS_DIR "/OBJ/spider_out.obj" ) ); + EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "objnomtl", ASSIMP_TEST_MODELS_DIR "/OBJ/spider_nomtl_out.obj" ) ); return true; } @@ -263,7 +263,7 @@ TEST_F( utObjImportExport, issue809_vertex_color_Test ) { #ifndef ASSIMP_BUILD_NO_EXPORT ::Assimp::Exporter exporter; - EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "obj", ASSIMP_TEST_MODELS_DIR "/OBJ/test.obj" ) ); + EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "obj", ASSIMP_TEST_MODELS_DIR "/OBJ/test_out.obj" ) ); #endif // ASSIMP_BUILD_NO_EXPORT } @@ -448,3 +448,37 @@ TEST_F(utObjImportExport, import_without_linend) { const aiScene *scene = myImporter.ReadFile(ASSIMP_TEST_MODELS_DIR "/OBJ/box_without_lineending.obj", 0); ASSERT_NE(nullptr, scene); } + +TEST_F(utObjImportExport, import_with_line_continuations) { + static const char *ObjModel = + "v -0.5 -0.5 0.5\n" + "v -0.5 \\\n" + " -0.5 -0.5\n" + "v -0.5 \\\n" + " 0.5 \\\n" + " -0.5\n" + "f 1 2 3\n"; + + Assimp::Importer myImporter; + const aiScene *scene = myImporter.ReadFileFromMemory(ObjModel, strlen(ObjModel), 0); + EXPECT_NE(nullptr, scene); + + EXPECT_EQ(scene->mNumMeshes, 1U); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 3U); + EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 1U); + + auto vertices = scene->mMeshes[0]->mVertices; + const float threshold = 0.0001f; + + EXPECT_NEAR(vertices[0].x, -0.5f, threshold); + EXPECT_NEAR(vertices[0].y, -0.5f, threshold); + EXPECT_NEAR(vertices[0].z, 0.5f, threshold); + + EXPECT_NEAR(vertices[1].x, -0.5f, threshold); + EXPECT_NEAR(vertices[1].y, -0.5f, threshold); + EXPECT_NEAR(vertices[1].z, -0.5f, threshold); + + EXPECT_NEAR(vertices[2].x, -0.5f, threshold); + EXPECT_NEAR(vertices[2].y, 0.5f, threshold); + EXPECT_NEAR(vertices[2].z, -0.5f, threshold); +} diff --git a/test/unit/utPLYImportExport.cpp b/test/unit/utPLYImportExport.cpp index bb8ba64d9..17d1b28de 100644 --- a/test/unit/utPLYImportExport.cpp +++ b/test/unit/utPLYImportExport.cpp @@ -71,7 +71,7 @@ public: Exporter exporter; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/PLY/cube.ply", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "ply", ASSIMP_TEST_MODELS_DIR "/PLY/cube_test.ply")); + EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "ply", ASSIMP_TEST_MODELS_DIR "/PLY/cube_out.ply")); return true; } diff --git a/test/unit/utPretransformVertices.cpp b/test/unit/utPretransformVertices.cpp index 22d1b28b4..0839740ac 100644 --- a/test/unit/utPretransformVertices.cpp +++ b/test/unit/utPretransformVertices.cpp @@ -51,18 +51,24 @@ using namespace Assimp; class PretransformVerticesTest : public ::testing::Test { public: + PretransformVerticesTest() + : Test() + , mScene(nullptr) + , mProcess(nullptr) { + // empty + } + +protected: virtual void SetUp(); virtual void TearDown(); protected: - - aiScene* scene; - PretransformVertices* process; + aiScene *mScene; + PretransformVertices *mProcess; }; // ------------------------------------------------------------------------------------------------ -void AddNodes(unsigned int num, aiNode* father, unsigned int depth) -{ +void AddNodes(unsigned int num, aiNode* father, unsigned int depth) { father->mChildren = new aiNode*[father->mNumChildren = 5]; for (unsigned int i = 0; i < 5; ++i) { aiNode* nd = father->mChildren[i] = new aiNode(); @@ -79,26 +85,26 @@ void AddNodes(unsigned int num, aiNode* father, unsigned int depth) } if (depth > 1) { - for (unsigned int i = 0; i < 5; ++i) - AddNodes(i, father->mChildren[i],depth-1); + for (unsigned int i = 0; i < 5; ++i) { + AddNodes(i, father->mChildren[i], depth - 1); + } } } // ------------------------------------------------------------------------------------------------ -void PretransformVerticesTest::SetUp() -{ - scene = new aiScene(); +void PretransformVerticesTest::SetUp() { + mScene = new aiScene(); // add 5 empty materials - scene->mMaterials = new aiMaterial*[scene->mNumMaterials = 5]; + mScene->mMaterials = new aiMaterial*[mScene->mNumMaterials = 5]; for (unsigned int i = 0; i < 5;++i) { - scene->mMaterials[i] = new aiMaterial(); + mScene->mMaterials[i] = new aiMaterial(); } // add 25 test meshes - scene->mMeshes = new aiMesh*[scene->mNumMeshes = 25]; - for ( unsigned int i = 0; i < 25; ++i) { - aiMesh* mesh = scene->mMeshes[ i ] = new aiMesh(); + mScene->mMeshes = new aiMesh*[mScene->mNumMeshes = 25]; + for ( unsigned int i = 0; i < 25; ++i) { + aiMesh* mesh = mScene->mMeshes[ i ] = new aiMesh(); mesh->mPrimitiveTypes = aiPrimitiveType_POINT; mesh->mFaces = new aiFace[ mesh->mNumFaces = 10+i ]; @@ -124,36 +130,33 @@ void PretransformVerticesTest::SetUp() } // construct some nodes (1+25) - scene->mRootNode = new aiNode(); - scene->mRootNode->mName.Set("Root"); - AddNodes(0,scene->mRootNode,2); + mScene->mRootNode = new aiNode(); + mScene->mRootNode->mName.Set("Root"); + AddNodes(0, mScene->mRootNode, 2); - process = new PretransformVertices(); + mProcess = new PretransformVertices(); } // ------------------------------------------------------------------------------------------------ -void PretransformVerticesTest::TearDown() -{ - delete scene; - delete process; +void PretransformVerticesTest::TearDown() { + delete mScene; + delete mProcess; } // ------------------------------------------------------------------------------------------------ -TEST_F(PretransformVerticesTest, testProcessCollapseHierarchy) -{ - process->KeepHierarchy(false); - process->Execute(scene); +TEST_F(PretransformVerticesTest, testProcessCollapseHierarchy) { + mProcess->KeepHierarchy(false); + mProcess->Execute(mScene); - EXPECT_EQ(5U, scene->mNumMaterials); - EXPECT_EQ(10U, scene->mNumMeshes); // every second mesh has normals + EXPECT_EQ(5U, mScene->mNumMaterials); + EXPECT_EQ(10U, mScene->mNumMeshes); // every second mesh has normals } // ------------------------------------------------------------------------------------------------ -TEST_F(PretransformVerticesTest, testProcessKeepHierarchy) -{ - process->KeepHierarchy(true); - process->Execute(scene); +TEST_F(PretransformVerticesTest, testProcessKeepHierarchy) { + mProcess->KeepHierarchy(true); + mProcess->Execute(mScene); - EXPECT_EQ(5U, scene->mNumMaterials); - EXPECT_EQ(49U, scene->mNumMeshes); // see note on mesh 12 above + EXPECT_EQ(5U, mScene->mNumMaterials); + EXPECT_EQ(49U, mScene->mNumMeshes); // see note on mesh 12 above } diff --git a/test/unit/utScenePreprocessor.cpp b/test/unit/utScenePreprocessor.cpp index 2c181a90f..7233e1379 100644 --- a/test/unit/utScenePreprocessor.cpp +++ b/test/unit/utScenePreprocessor.cpp @@ -50,67 +50,67 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace std; using namespace Assimp; - -class ScenePreprocessorTest : public ::testing::Test -{ +class ScenePreprocessorTest : public ::testing::Test { public: + ScenePreprocessorTest() + : Test() + , mScenePreprocessor(nullptr) + , mScene(nullptr) { + // empty + } +protected: virtual void SetUp(); virtual void TearDown(); protected: - void CheckIfOnly(aiMesh* p, unsigned int num, unsigned flag); + void ProcessAnimation(aiAnimation* anim) { mScenePreprocessor->ProcessAnimation(anim); } + void ProcessMesh(aiMesh* mesh) { mScenePreprocessor->ProcessMesh(mesh); } - void ProcessAnimation(aiAnimation* anim) { pp->ProcessAnimation(anim); } - void ProcessMesh(aiMesh* mesh) { pp->ProcessMesh(mesh); } - - ScenePreprocessor* pp; - aiScene* scene; +private: + ScenePreprocessor *mScenePreprocessor; + aiScene *mScene; }; // ------------------------------------------------------------------------------------------------ -void ScenePreprocessorTest::SetUp() -{ +void ScenePreprocessorTest::SetUp() { // setup a dummy scene with a single node - scene = new aiScene(); - scene->mRootNode = new aiNode(); - scene->mRootNode->mName.Set(""); + mScene = new aiScene(); + mScene->mRootNode = new aiNode(); + mScene->mRootNode->mName.Set(""); // add some translation - scene->mRootNode->mTransformation.a4 = 1.f; - scene->mRootNode->mTransformation.b4 = 2.f; - scene->mRootNode->mTransformation.c4 = 3.f; + mScene->mRootNode->mTransformation.a4 = 1.f; + mScene->mRootNode->mTransformation.b4 = 2.f; + mScene->mRootNode->mTransformation.c4 = 3.f; // and allocate a ScenePreprocessor to operate on the scene - pp = new ScenePreprocessor(scene); + mScenePreprocessor = new ScenePreprocessor(mScene); } // ------------------------------------------------------------------------------------------------ -void ScenePreprocessorTest::TearDown() -{ - delete pp; - delete scene; +void ScenePreprocessorTest::TearDown() { + delete mScenePreprocessor; + delete mScene; } // ------------------------------------------------------------------------------------------------ // Check whether ProcessMesh() returns flag for a mesh that consist of primitives with num indices -void ScenePreprocessorTest::CheckIfOnly(aiMesh* p, unsigned int num, unsigned int flag) -{ +void ScenePreprocessorTest::CheckIfOnly(aiMesh* p, unsigned int num, unsigned int flag) { // Triangles only for (unsigned i = 0; i < p->mNumFaces;++i) { p->mFaces[i].mNumIndices = num; } - pp->ProcessMesh(p); + mScenePreprocessor->ProcessMesh(p); EXPECT_EQ(flag, p->mPrimitiveTypes); p->mPrimitiveTypes = 0; } // ------------------------------------------------------------------------------------------------ // Check whether a mesh is preprocessed correctly. Case 1: The mesh needs preprocessing -TEST_F(ScenePreprocessorTest, testMeshPreprocessingPos) -{ - aiMesh* p = new aiMesh(); +TEST_F(ScenePreprocessorTest, testMeshPreprocessingPos) { + aiMesh* p = new aiMesh; p->mNumFaces = 100; p->mFaces = new aiFace[p->mNumFaces]; @@ -145,9 +145,8 @@ TEST_F(ScenePreprocessorTest, testMeshPreprocessingPos) // ------------------------------------------------------------------------------------------------ // Check whether a mesh is preprocessed correctly. Case 1: The mesh doesn't need preprocessing -TEST_F(ScenePreprocessorTest, testMeshPreprocessingNeg) -{ - aiMesh* p = new aiMesh(); +TEST_F(ScenePreprocessorTest, testMeshPreprocessingNeg) { + aiMesh* p = new aiMesh; p->mPrimitiveTypes = aiPrimitiveType_TRIANGLE|aiPrimitiveType_POLYGON; ProcessMesh(p); @@ -160,8 +159,7 @@ TEST_F(ScenePreprocessorTest, testMeshPreprocessingNeg) // ------------------------------------------------------------------------------------------------ // Make a dummy animation with a single channel, '' -aiAnimation* MakeDummyAnimation() -{ +aiAnimation* MakeDummyAnimation() { aiAnimation* p = new aiAnimation(); p->mNumChannels = 1; p->mChannels = new aiNodeAnim*[1]; @@ -172,8 +170,7 @@ aiAnimation* MakeDummyAnimation() // ------------------------------------------------------------------------------------------------ // Check whether an anim is preprocessed correctly. Case 1: The anim needs preprocessing -TEST_F(ScenePreprocessorTest, testAnimationPreprocessingPos) -{ +TEST_F(ScenePreprocessorTest, testAnimationPreprocessingPos) { aiAnimation* p = MakeDummyAnimation(); aiNodeAnim* anim = p->mChannels[0]; diff --git a/test/unit/utSortByPType.cpp b/test/unit/utSortByPType.cpp index 1aa9dad0a..fb637b004 100644 --- a/test/unit/utSortByPType.cpp +++ b/test/unit/utSortByPType.cpp @@ -52,12 +52,20 @@ using namespace Assimp; class SortByPTypeProcessTest : public ::testing::Test { public: + SortByPTypeProcessTest() + : Test() + , mProcess1(nullptr) + , mScene(nullptr) { + // empty + } + +protected: virtual void SetUp(); virtual void TearDown(); protected: - SortByPTypeProcess* process1; - aiScene* scene; + SortByPTypeProcess* mProcess1; + aiScene* mScene; }; // ------------------------------------------------------------------------------------------------ @@ -75,8 +83,7 @@ static unsigned int num[10][4] = { }; // ------------------------------------------------------------------------------------------------ -static unsigned int result[10] = -{ +static unsigned int result[10] = { aiPrimitiveType_POLYGON, aiPrimitiveType_TRIANGLE, aiPrimitiveType_LINE, @@ -90,19 +97,16 @@ static unsigned int result[10] = }; // ------------------------------------------------------------------------------------------------ -void SortByPTypeProcessTest::SetUp() -{ -// process0 = new DeterminePTypeHelperProcess(); - process1 = new SortByPTypeProcess(); - scene = new aiScene(); +void SortByPTypeProcessTest::SetUp() { + mProcess1 = new SortByPTypeProcess(); + mScene = new aiScene(); - scene->mNumMeshes = 10; - scene->mMeshes = new aiMesh*[10]; + mScene->mNumMeshes = 10; + mScene->mMeshes = new aiMesh*[10]; bool five = false; - for (unsigned int i = 0; i < 10; ++i) - { - aiMesh* mesh = scene->mMeshes[i] = new aiMesh(); + for (unsigned int i = 0; i < 10; ++i) { + aiMesh* mesh = mScene->mMeshes[i] = new aiMesh(); mesh->mNumFaces = 1000; aiFace* faces = mesh->mFaces = new aiFace[1000]; aiVector3D* pv = mesh->mVertices = new aiVector3D[mesh->mNumFaces*5]; @@ -115,27 +119,24 @@ void SortByPTypeProcessTest::SetUp() unsigned int remaining[4] = {num[i][0],num[i][1],num[i][2],num[i][3]}; unsigned int n = 0; - for (unsigned int m = 0; m < 1000; ++m) - { + for (unsigned int m = 0; m < 1000; ++m) { unsigned int idx = m % 4; - while (true) - { - if (!remaining[idx]) - { - if (4 == ++idx)idx = 0; + while (true) { + if (!remaining[idx]) { + if (4 == ++idx) { + idx = 0; + } continue; } break; } faces->mNumIndices = idx+1; - if (4 == faces->mNumIndices) - { + if (4 == faces->mNumIndices) { if(five)++faces->mNumIndices; five = !five; } faces->mIndices = new unsigned int[faces->mNumIndices]; - for (unsigned int q = 0; q mNumIndices;++q,++n) - { + for (unsigned int q = 0; q mNumIndices;++q,++n) { faces->mIndices[q] = n; float f = (float)remaining[idx]; @@ -152,12 +153,11 @@ void SortByPTypeProcessTest::SetUp() mesh->mNumVertices = n; } - scene->mRootNode = new aiNode(); - scene->mRootNode->mNumChildren = 5; - scene->mRootNode->mChildren = new aiNode*[5]; - for (unsigned int i = 0; i< 5;++i ) - { - aiNode* node = scene->mRootNode->mChildren[i] = new aiNode(); + mScene->mRootNode = new aiNode(); + mScene->mRootNode->mNumChildren = 5; + mScene->mRootNode->mChildren = new aiNode*[5]; + for (unsigned int i = 0; i< 5;++i ) { + aiNode* node = mScene->mRootNode->mChildren[i] = new aiNode(); node->mNumMeshes = 2; node->mMeshes = new unsigned int[2]; node->mMeshes[0] = (i<<1u); @@ -166,48 +166,27 @@ void SortByPTypeProcessTest::SetUp() } // ------------------------------------------------------------------------------------------------ -void SortByPTypeProcessTest::TearDown() -{ - //delete process0; - delete process1; - delete scene; +void SortByPTypeProcessTest::TearDown() { + delete mProcess1; + delete mScene; } // ------------------------------------------------------------------------------------------------ -//TEST_F(SortByPTypeProcessTest, DeterminePTypeStep() -//{ -// process0->Execute(scene); -// -// for (unsigned int i = 0; i < 10; ++i) -// { -// aiMesh* mesh = scene->mMeshes[i]; -// EXPECT_TRUE(mesh->mPrimitiveTypes == result[i]); -// } -//} - -// ------------------------------------------------------------------------------------------------ -TEST_F(SortByPTypeProcessTest, SortByPTypeStep) -{ - // process0->Execute(scene); - - // and another small test for ScenePreprocessor - ScenePreprocessor s(scene); +TEST_F(SortByPTypeProcessTest, SortByPTypeStep) { + ScenePreprocessor s(mScene); s.ProcessScene(); for (unsigned int m = 0; m< 10;++m) - EXPECT_EQ(result[m], scene->mMeshes[m]->mPrimitiveTypes); + EXPECT_EQ(result[m], mScene->mMeshes[m]->mPrimitiveTypes); - process1->Execute(scene); + mProcess1->Execute(mScene); unsigned int idx = 0; - for (unsigned int m = 0,real = 0; m< 10;++m) - { - for (unsigned int n = 0; n < 4;++n) - { - if ((idx = num[m][n])) - { - EXPECT_TRUE(real < scene->mNumMeshes); + for (unsigned int m = 0,real = 0; m< 10;++m) { + for (unsigned int n = 0; n < 4;++n) { + if ((idx = num[m][n])) { + EXPECT_TRUE(real < mScene->mNumMeshes); - aiMesh* mesh = scene->mMeshes[real]; + aiMesh* mesh = mScene->mMeshes[real]; EXPECT_TRUE(NULL != mesh); EXPECT_EQ(AI_PRIMITIVE_TYPE_FOR_N_INDICES(n+1), mesh->mPrimitiveTypes); @@ -218,8 +197,7 @@ TEST_F(SortByPTypeProcessTest, SortByPTypeStep) EXPECT_TRUE(NULL != mesh->mTextureCoords[0]); EXPECT_TRUE(mesh->mNumFaces == idx); - for (unsigned int f = 0; f < mesh->mNumFaces;++f) - { + for (unsigned int f = 0; f < mesh->mNumFaces;++f) { aiFace& face = mesh->mFaces[f]; EXPECT_TRUE(face.mNumIndices == (n+1) || (3 == n && face.mNumIndices > 3)); } @@ -228,4 +206,3 @@ TEST_F(SortByPTypeProcessTest, SortByPTypeStep) } } } - diff --git a/test/unit/utglTF2ImportExport.cpp b/test/unit/utglTF2ImportExport.cpp index bac76473d..0ba5226cc 100644 --- a/test/unit/utglTF2ImportExport.cpp +++ b/test/unit/utglTF2ImportExport.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2019, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -55,17 +53,23 @@ class utglTF2ImportExport : public AbstractImportExportBase { public: virtual bool importerTest() { Assimp::Importer importer; - const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", aiProcess_ValidateDataStructure); + const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", + aiProcess_ValidateDataStructure); EXPECT_NE( scene, nullptr ); - if ( !scene ) return false; + if (!scene) { + return false; + } EXPECT_TRUE( scene->HasMaterials() ); - if ( !scene->HasMaterials() ) return false; + if (!scene->HasMaterials()) { + return false; + } const aiMaterial *material = scene->mMaterials[0]; aiString path; aiTextureMapMode modes[2]; - EXPECT_EQ( aiReturn_SUCCESS, material->GetTexture(aiTextureType_DIFFUSE, 0, &path, nullptr, nullptr, nullptr, nullptr, modes) ); + EXPECT_EQ( aiReturn_SUCCESS, material->GetTexture(aiTextureType_DIFFUSE, 0, &path, nullptr, nullptr, + nullptr, nullptr, modes) ); EXPECT_STREQ( path.C_Str(), "CesiumLogoFlat.png" ); EXPECT_EQ( modes[0], aiTextureMapMode_Mirror ); EXPECT_EQ( modes[1], aiTextureMapMode_Clamp ); @@ -75,7 +79,8 @@ public: virtual bool binaryImporterTest() { Assimp::Importer importer; - const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/2CylinderEngine-glTF-Binary/2CylinderEngine.glb", aiProcess_ValidateDataStructure); + const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/2CylinderEngine-glTF-Binary/2CylinderEngine.glb", + aiProcess_ValidateDataStructure); return nullptr != scene; } @@ -83,7 +88,8 @@ public: virtual bool exporterTest() { Assimp::Importer importer; Assimp::Exporter exporter; - const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", aiProcess_ValidateDataStructure ); + const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", + aiProcess_ValidateDataStructure ); EXPECT_NE( nullptr, scene ); EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "gltf2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured_out.gltf" ) ); @@ -105,7 +111,8 @@ TEST_F( utglTF2ImportExport, importBinaryglTF2FromFileTest ) { TEST_F(utglTF2ImportExport, importglTF2AndExportToOBJ) { Assimp::Importer importer; Assimp::Exporter exporter; - const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", aiProcess_ValidateDataStructure); + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", + aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "obj", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured_out.obj")); } @@ -113,7 +120,8 @@ TEST_F(utglTF2ImportExport, importglTF2AndExportToOBJ) { TEST_F(utglTF2ImportExport, importglTF2EmbeddedAndExportToOBJ) { Assimp::Importer importer; Assimp::Exporter exporter; - const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-Embedded/BoxTextured.gltf", aiProcess_ValidateDataStructure); + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-Embedded/BoxTextured.gltf", + aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "obj", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-Embedded/BoxTextured_out.obj")); } @@ -124,10 +132,9 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModePointsWithoutIndices) { //Points without indices const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_00.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 1024); - for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) - { - EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 1); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 1024u); + for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) { + EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 1u); EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], i); } } @@ -137,12 +144,11 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLinesWithoutIndices) { //Lines without indices const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_01.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 8); - for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) - { - EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 2); - EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], i*2); - EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], i*2 + 1); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 8u); + for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) { + EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 2u); + EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], i*2u); + EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], i*2u + 1u); } } @@ -151,15 +157,14 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLinesLoopWithoutIndices) { //Lines loop without indices const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_02.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u); - std::array l1 = {{ 0, 1, 2, 3, 0 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2); - for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) - { - EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 2); + std::array l1 = {{ 0u, 1u, 2u, 3u, 0u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2u); + for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) { + EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 2u); EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], l1[i]); - EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], l1[i + 1]); + EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], l1[i + 1u]); } } @@ -168,14 +173,13 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLinesStripWithoutIndices) { //Lines strip without indices const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_03.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 5); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 5u); - EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2); - for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) - { - EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 2); + EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2u); + for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) { + EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 2u); EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], i); - EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], i + 1); + EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], i + 1u); } } @@ -184,19 +188,17 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeTrianglesStripWithoutIndices //Triangles strip without indices const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_04.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4); - std::array f1 = {{ 0, 1, 2 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3); - for (int i = 0; i < 3; ++i) - { + EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2u); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u); + std::array f1 = {{ 0u, 1u, 2u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3u); + for (unsigned int i = 0; i < 3; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mIndices[i], f1[i]); } - std::array f2 = {{ 2, 1, 3 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3); - for (int i = 0; i < 3; ++i) - { + std::array f2 = {{ 2u, 1u, 3u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3u); + for (size_t i = 0; i < 3; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mIndices[i], f2[i]); } } @@ -206,19 +208,17 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeTrianglesFanWithoutIndices) //Triangles fan without indices const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_05.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4); - std::array f1 = {{ 0, 1, 2 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3); - for (int i = 0; i < 3; ++i) - { + EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2u); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u); + std::array f1 = {{ 0u, 1u, 2u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3u); + for (size_t i = 0; i < 3; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mIndices[i], f1[i]); } - std::array f2 = {{ 0, 2, 3 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3); - for (int i = 0; i < 3; ++i) - { + std::array f2 = {{ 0u, 2u, 3u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3u); + for (size_t i = 0; i < 3; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mIndices[i], f2[i]); } } @@ -228,19 +228,17 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeTrianglesWithoutIndices) { //Triangles without indices const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_06.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 6); - std::array f1 = {{ 0, 1, 2 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3); - for (int i = 0; i < 3; ++i) - { + EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2u); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 6u); + std::array f1 = {{ 0u, 1u, 2u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3u); + for (size_t i = 0; i < 3; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mIndices[i], f1[i]); } - std::array f2 = {{ 3, 4, 5 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3); - for (int i = 0; i < 3; ++i) - { + std::array f2 = {{ 3u, 4u, 5u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3u); + for (size_t i = 0; i < 3; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mIndices[i], f2[i]); } } @@ -250,10 +248,9 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModePoints) { //Line loop const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_07.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 1024); - for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) - { - EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 1); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 1024u); + for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) { + EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 1u); EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], i); } } @@ -263,9 +260,9 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLines) { //Lines const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_08.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4); - std::array l1 = {{ 0, 3, 2, 1, 0 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u); + std::array l1 = {{ 0u, 3u, 2u, 1u, 0u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2u); for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], l1[i]); @@ -278,9 +275,9 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLineLoop) { //Line loop const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_09.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4); - std::array l1 = {{ 0, 3, 2, 1, 0 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u); + std::array l1 = {{ 0, 3u, 2u, 1u, 0u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2u); for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], l1[i]); @@ -293,11 +290,10 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLineStrip) { //Lines Strip const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_10.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4); - std::array l1 = {{ 0, 3, 2, 1, 0 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2); - for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) - { + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u); + std::array l1 = {{ 0u, 3u, 2u, 1u, 0u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2u); + for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], l1[i]); EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], l1[i + 1]); } @@ -308,19 +304,17 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeTrianglesStrip) { //Triangles strip const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_11.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4); - std::array f1 = {{ 0, 3, 1 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3); - for (int i = 0; i < 3; ++i) - { + EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2u); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u); + std::array f1 = {{ 0u, 3u, 1u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3u); + for (size_t i = 0; i < 3; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mIndices[i], f1[i]); } - std::array f2 = {{ 1, 3, 2 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3); - for (int i = 0; i < 3; ++i) - { + std::array f2 = {{ 1u, 3u, 2u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3u); + for (size_t i = 0; i < 3; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mIndices[i], f2[i]); } } @@ -330,19 +324,17 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeTrianglesFan) { //Triangles fan const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_12.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4); - EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2); - std::array f1 = {{ 0, 3, 2 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3); - for (int i = 0; i < 3; ++i) - { + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u); + EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2u); + std::array f1 = {{ 0u, 3u, 2u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3u ); + for (size_t i = 0; i < 3; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mIndices[i], f1[i]); } - std::array f2 = {{ 0, 2, 1 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3); - for (int i = 0; i < 3; ++i) - { + std::array f2 = {{ 0u, 2u, 1u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3u ); + for (size_t i = 0; i < 3; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mIndices[i], f2[i]); } } @@ -378,7 +370,8 @@ TEST_F(utglTF2ImportExport, importglTF2FromMemory) { TEST_F( utglTF2ImportExport, bug_import_simple_skin ) { Assimp::Importer importer; - const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/simple_skin/simple_skin.gltf", aiProcess_ValidateDataStructure ); + const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/simple_skin/simple_skin.gltf", + aiProcess_ValidateDataStructure ); EXPECT_NE( nullptr, scene ); }