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 9c484910c..a8a514f73 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -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 81db957d5..8d4570da8 100644 --- a/code/Collada/ColladaLoader.cpp +++ b/code/Collada/ColladaLoader.cpp @@ -772,10 +772,14 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada:: 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); + 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) 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..58cad3be8 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/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 c95f0e160..d08b929a1 100644 --- a/include/assimp/config.h.in +++ b/include/assimp/config.h.in @@ -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/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 index eef7cd426..f2ac612e8 100644 --- a/test/models/PLY/cube_test.ply +++ b/test/models/PLY/cube_test.ply @@ -1,6 +1,6 @@ ply format ascii 1.0 -comment Created by Open Asset Import Library - http://assimp.sf.net (v4.1.649942190) +comment Created by Open Asset Import Library - http://assimp.sf.net (v4.1.993695325) element vertex 8 property float x property float y 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..011aaa649 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,8 +51,8 @@ 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; @@ -66,7 +64,7 @@ public: }; 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/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/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/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..749e618da 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,28 @@ 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) - { + 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); + 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 +198,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 +207,3 @@ TEST_F(SortByPTypeProcessTest, SortByPTypeStep) } } } -