diff --git a/Engine/lib/assimp/code/3DS/3DSConverter.cpp b/Engine/lib/assimp/code/3DS/3DSConverter.cpp index 3c3da36a3..3f0e20bb0 100644 --- a/Engine/lib/assimp/code/3DS/3DSConverter.cpp +++ b/Engine/lib/assimp/code/3DS/3DSConverter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/3DS/3DSExporter.cpp b/Engine/lib/assimp/code/3DS/3DSExporter.cpp index 1117a52ef..14810cbff 100644 --- a/Engine/lib/assimp/code/3DS/3DSExporter.cpp +++ b/Engine/lib/assimp/code/3DS/3DSExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/3DS/3DSExporter.h b/Engine/lib/assimp/code/3DS/3DSExporter.h index 035b562cf..9dcd92d58 100644 --- a/Engine/lib/assimp/code/3DS/3DSExporter.h +++ b/Engine/lib/assimp/code/3DS/3DSExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/3DS/3DSHelper.h b/Engine/lib/assimp/code/3DS/3DSHelper.h index 8eb4cd97c..e483f1a25 100644 --- a/Engine/lib/assimp/code/3DS/3DSHelper.h +++ b/Engine/lib/assimp/code/3DS/3DSHelper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/3DS/3DSLoader.cpp b/Engine/lib/assimp/code/3DS/3DSLoader.cpp index 3c659d0b0..3e8e08967 100644 --- a/Engine/lib/assimp/code/3DS/3DSLoader.cpp +++ b/Engine/lib/assimp/code/3DS/3DSLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/3DS/3DSLoader.h b/Engine/lib/assimp/code/3DS/3DSLoader.h index f57e6a8e3..9181294b3 100644 --- a/Engine/lib/assimp/code/3DS/3DSLoader.h +++ b/Engine/lib/assimp/code/3DS/3DSLoader.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/3MF/3MFXmlTags.h b/Engine/lib/assimp/code/3MF/3MFXmlTags.h index ea6aeede0..3f1fc01ed 100644 --- a/Engine/lib/assimp/code/3MF/3MFXmlTags.h +++ b/Engine/lib/assimp/code/3MF/3MFXmlTags.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/3MF/D3MFExporter.cpp b/Engine/lib/assimp/code/3MF/D3MFExporter.cpp index 1f388ad3e..9d71a54f2 100644 --- a/Engine/lib/assimp/code/3MF/D3MFExporter.cpp +++ b/Engine/lib/assimp/code/3MF/D3MFExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/3MF/D3MFExporter.h b/Engine/lib/assimp/code/3MF/D3MFExporter.h index e82120247..6a447236b 100644 --- a/Engine/lib/assimp/code/3MF/D3MFExporter.h +++ b/Engine/lib/assimp/code/3MF/D3MFExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/3MF/D3MFImporter.cpp b/Engine/lib/assimp/code/3MF/D3MFImporter.cpp index 682de684a..2f30c4fc0 100644 --- a/Engine/lib/assimp/code/3MF/D3MFImporter.cpp +++ b/Engine/lib/assimp/code/3MF/D3MFImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/3MF/D3MFImporter.h b/Engine/lib/assimp/code/3MF/D3MFImporter.h index 3dbdf07bf..638971247 100644 --- a/Engine/lib/assimp/code/3MF/D3MFImporter.h +++ b/Engine/lib/assimp/code/3MF/D3MFImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/3MF/D3MFOpcPackage.cpp b/Engine/lib/assimp/code/3MF/D3MFOpcPackage.cpp index 873ba8ee8..565790656 100644 --- a/Engine/lib/assimp/code/3MF/D3MFOpcPackage.cpp +++ b/Engine/lib/assimp/code/3MF/D3MFOpcPackage.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/3MF/D3MFOpcPackage.h b/Engine/lib/assimp/code/3MF/D3MFOpcPackage.h index 87d172116..291f8ad53 100644 --- a/Engine/lib/assimp/code/3MF/D3MFOpcPackage.h +++ b/Engine/lib/assimp/code/3MF/D3MFOpcPackage.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/AC/ACLoader.cpp b/Engine/lib/assimp/code/AC/ACLoader.cpp index d4c4bd1a6..ea533743f 100644 --- a/Engine/lib/assimp/code/AC/ACLoader.cpp +++ b/Engine/lib/assimp/code/AC/ACLoader.cpp @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/AC/ACLoader.h b/Engine/lib/assimp/code/AC/ACLoader.h index cab2c3ae5..1fc654f3c 100644 --- a/Engine/lib/assimp/code/AC/ACLoader.h +++ b/Engine/lib/assimp/code/AC/ACLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/AMF/AMFImporter.cpp b/Engine/lib/assimp/code/AMF/AMFImporter.cpp index dedb6dcdd..df4324d4d 100644 --- a/Engine/lib/assimp/code/AMF/AMFImporter.cpp +++ b/Engine/lib/assimp/code/AMF/AMFImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/AMF/AMFImporter.hpp b/Engine/lib/assimp/code/AMF/AMFImporter.hpp index 2b8086a06..5994717b8 100644 --- a/Engine/lib/assimp/code/AMF/AMFImporter.hpp +++ b/Engine/lib/assimp/code/AMF/AMFImporter.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/AMF/AMFImporter_Geometry.cpp b/Engine/lib/assimp/code/AMF/AMFImporter_Geometry.cpp index f1538e3fb..e9a50b656 100644 --- a/Engine/lib/assimp/code/AMF/AMFImporter_Geometry.cpp +++ b/Engine/lib/assimp/code/AMF/AMFImporter_Geometry.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/AMF/AMFImporter_Macro.hpp b/Engine/lib/assimp/code/AMF/AMFImporter_Macro.hpp index f60c5fbbb..ec06cb999 100644 --- a/Engine/lib/assimp/code/AMF/AMFImporter_Macro.hpp +++ b/Engine/lib/assimp/code/AMF/AMFImporter_Macro.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/AMF/AMFImporter_Material.cpp b/Engine/lib/assimp/code/AMF/AMFImporter_Material.cpp index 2f36df061..64da12dda 100644 --- a/Engine/lib/assimp/code/AMF/AMFImporter_Material.cpp +++ b/Engine/lib/assimp/code/AMF/AMFImporter_Material.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/AMF/AMFImporter_Node.hpp b/Engine/lib/assimp/code/AMF/AMFImporter_Node.hpp index a1bf9f008..b7b7836f3 100644 --- a/Engine/lib/assimp/code/AMF/AMFImporter_Node.hpp +++ b/Engine/lib/assimp/code/AMF/AMFImporter_Node.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/AMF/AMFImporter_Postprocess.cpp b/Engine/lib/assimp/code/AMF/AMFImporter_Postprocess.cpp index 79b5e15e2..8496d8ded 100644 --- a/Engine/lib/assimp/code/AMF/AMFImporter_Postprocess.cpp +++ b/Engine/lib/assimp/code/AMF/AMFImporter_Postprocess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/ASE/ASELoader.cpp b/Engine/lib/assimp/code/ASE/ASELoader.cpp index 8e99214a8..b2155d5e5 100644 --- a/Engine/lib/assimp/code/ASE/ASELoader.cpp +++ b/Engine/lib/assimp/code/ASE/ASELoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/ASE/ASELoader.h b/Engine/lib/assimp/code/ASE/ASELoader.h index b497aa48b..bb7707bb6 100644 --- a/Engine/lib/assimp/code/ASE/ASELoader.h +++ b/Engine/lib/assimp/code/ASE/ASELoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/ASE/ASEParser.cpp b/Engine/lib/assimp/code/ASE/ASEParser.cpp index 913e7b118..efc6ecd0d 100644 --- a/Engine/lib/assimp/code/ASE/ASEParser.cpp +++ b/Engine/lib/assimp/code/ASE/ASEParser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/ASE/ASEParser.h b/Engine/lib/assimp/code/ASE/ASEParser.h index 988cbda8d..e55949f99 100644 --- a/Engine/lib/assimp/code/ASE/ASEParser.h +++ b/Engine/lib/assimp/code/ASE/ASEParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Assbin/AssbinExporter.cpp b/Engine/lib/assimp/code/Assbin/AssbinExporter.cpp index 76c823f82..496b39d49 100644 --- a/Engine/lib/assimp/code/Assbin/AssbinExporter.cpp +++ b/Engine/lib/assimp/code/Assbin/AssbinExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -46,799 +46,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_EXPORT #ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER -#include "Common/assbin_chunks.h" -#include "PostProcessing/ProcessHelper.h" +#include "AssbinFileWriter.h" -#include -#include +#include #include #include -#include - -#ifdef ASSIMP_BUILD_NO_OWN_ZLIB -# include -#else -# include "../contrib/zlib/zlib.h" -#endif - -#include namespace Assimp { -template -size_t Write(IOStream * stream, const T& v) { - return stream->Write( &v, sizeof(T), 1 ); -} - -// ----------------------------------------------------------------------------------- -// Serialize an aiString -template <> -inline -size_t Write(IOStream * stream, const aiString& s) { - const size_t s2 = (uint32_t)s.length; - stream->Write(&s,4,1); - stream->Write(s.data,s2,1); - - return s2+4; -} - -// ----------------------------------------------------------------------------------- -// Serialize an unsigned int as uint32_t -template <> -inline -size_t Write(IOStream * stream, const unsigned int& w) { - const uint32_t t = (uint32_t)w; - if (w > t) { - // this shouldn't happen, integers in Assimp data structures never exceed 2^32 - throw DeadlyExportError("loss of data due to 64 -> 32 bit integer conversion"); - } - - stream->Write(&t,4,1); - - return 4; -} - -// ----------------------------------------------------------------------------------- -// Serialize an unsigned int as uint16_t -template <> -inline -size_t Write(IOStream * stream, const uint16_t& w) { - static_assert(sizeof(uint16_t)==2, "sizeof(uint16_t)==2"); - stream->Write(&w,2,1); - - return 2; -} - -// ----------------------------------------------------------------------------------- -// Serialize a float -template <> -inline -size_t Write(IOStream * stream, const float& f) { - static_assert(sizeof(float)==4, "sizeof(float)==4"); - stream->Write(&f,4,1); - - return 4; -} - -// ----------------------------------------------------------------------------------- -// Serialize a double -template <> -inline -size_t Write(IOStream * stream, const double& f) { - static_assert(sizeof(double)==8, "sizeof(double)==8"); - stream->Write(&f,8,1); - - return 8; -} - -// ----------------------------------------------------------------------------------- -// Serialize a vec3 -template <> -inline -size_t Write(IOStream * stream, const aiVector3D& v) { - size_t t = Write(stream,v.x); - t += Write(stream,v.y); - t += Write(stream,v.z); - - return t; -} - -// ----------------------------------------------------------------------------------- -// Serialize a color value -template <> -inline -size_t Write(IOStream * stream, const aiColor3D& v) { - size_t t = Write(stream,v.r); - t += Write(stream,v.g); - t += Write(stream,v.b); - - return t; -} - -// ----------------------------------------------------------------------------------- -// Serialize a color value -template <> -inline -size_t Write(IOStream * stream, const aiColor4D& v) { - size_t t = Write(stream,v.r); - t += Write(stream,v.g); - t += Write(stream,v.b); - t += Write(stream,v.a); - - return t; -} - -// ----------------------------------------------------------------------------------- -// Serialize a quaternion -template <> -inline -size_t Write(IOStream * stream, const aiQuaternion& v) { - size_t t = Write(stream,v.w); - t += Write(stream,v.x); - t += Write(stream,v.y); - t += Write(stream,v.z); - ai_assert(t == 16); - - return 16; -} - -// ----------------------------------------------------------------------------------- -// Serialize a vertex weight -template <> -inline -size_t Write(IOStream * stream, const aiVertexWeight& v) { - size_t t = Write(stream,v.mVertexId); - - return t+Write(stream,v.mWeight); -} - -// ----------------------------------------------------------------------------------- -// Serialize a mat4x4 -template <> -inline -size_t Write(IOStream * stream, const aiMatrix4x4& m) { - for (unsigned int i = 0; i < 4;++i) { - for (unsigned int i2 = 0; i2 < 4;++i2) { - Write(stream,m[i][i2]); - } - } - - return 64; -} - -// ----------------------------------------------------------------------------------- -// Serialize an aiVectorKey -template <> -inline -size_t Write(IOStream * stream, const aiVectorKey& v) { - const size_t t = Write(stream,v.mTime); - return t + Write(stream,v.mValue); -} - -// ----------------------------------------------------------------------------------- -// Serialize an aiQuatKey -template <> -inline -size_t Write(IOStream * stream, const aiQuatKey& v) { - const size_t t = Write(stream,v.mTime); - return t + Write(stream,v.mValue); -} - -template -inline -size_t WriteBounds(IOStream * stream, const T* in, unsigned int size) { - T minc, maxc; - ArrayBounds(in,size,minc,maxc); - - const size_t t = Write(stream,minc); - return t + Write(stream,maxc); -} - -// We use this to write out non-byte arrays so that we write using the specializations. -// This way we avoid writing out extra bytes that potentially come from struct alignment. -template -inline -size_t WriteArray(IOStream * stream, const T* in, unsigned int size) { - size_t n = 0; - for (unsigned int i=0; i(stream,in[i]); - - return n; -} - -// ---------------------------------------------------------------------------------- -/** @class AssbinChunkWriter - * @brief Chunk writer mechanism for the .assbin file structure - * - * This is a standard in-memory IOStream (most of the code is based on BlobIOStream), - * the difference being that this takes another IOStream as a "container" in the - * constructor, and when it is destroyed, it appends the magic number, the chunk size, - * and the chunk contents to the container stream. This allows relatively easy chunk - * chunk construction, even recursively. - */ -class AssbinChunkWriter : public IOStream -{ -private: - - uint8_t* buffer; - uint32_t magic; - IOStream * container; - size_t cur_size, cursor, initial; - -private: - // ------------------------------------------------------------------- - void Grow(size_t need = 0) - { - size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) )); - - const uint8_t* const old = buffer; - buffer = new uint8_t[new_size]; - - if (old) { - memcpy(buffer,old,cur_size); - delete[] old; - } - - cur_size = new_size; - } - -public: - - AssbinChunkWriter( IOStream * container, uint32_t magic, size_t initial = 4096) - : buffer(NULL), magic(magic), container(container), cur_size(0), cursor(0), initial(initial) - { - } - - virtual ~AssbinChunkWriter() - { - if (container) { - container->Write( &magic, sizeof(uint32_t), 1 ); - container->Write( &cursor, sizeof(uint32_t), 1 ); - container->Write( buffer, 1, cursor ); - } - if (buffer) delete[] buffer; - } - - void * GetBufferPointer() { return buffer; } - - // ------------------------------------------------------------------- - virtual size_t Read(void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { - return 0; - } - virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) { - return aiReturn_FAILURE; - } - virtual size_t Tell() const { - return cursor; - } - virtual void Flush() { - // not implemented - } - - virtual size_t FileSize() const { - return cursor; - } - - // ------------------------------------------------------------------- - virtual size_t Write(const void* pvBuffer, size_t pSize, size_t pCount) { - pSize *= pCount; - if (cursor + pSize > cur_size) { - Grow(cursor + pSize); - } - - memcpy(buffer+cursor, pvBuffer, pSize); - cursor += pSize; - - return pCount; - } - -}; - -// ---------------------------------------------------------------------------------- -/** @class AssbinExport - * @brief Assbin exporter class - * - * This class performs the .assbin exporting, and is responsible for the file layout. - */ -class AssbinExport -{ -private: - bool shortened; - bool compressed; - -protected: - // ----------------------------------------------------------------------------------- - void WriteBinaryNode( IOStream * container, const aiNode* node) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODE ); - - unsigned int nb_metadata = (node->mMetaData != NULL ? node->mMetaData->mNumProperties : 0); - - Write(&chunk,node->mName); - Write(&chunk,node->mTransformation); - Write(&chunk,node->mNumChildren); - Write(&chunk,node->mNumMeshes); - Write(&chunk,nb_metadata); - - for (unsigned int i = 0; i < node->mNumMeshes;++i) { - Write(&chunk,node->mMeshes[i]); - } - - for (unsigned int i = 0; i < node->mNumChildren;++i) { - WriteBinaryNode( &chunk, node->mChildren[i] ); - } - - for (unsigned int i = 0; i < nb_metadata; ++i) { - const aiString& key = node->mMetaData->mKeys[i]; - aiMetadataType type = node->mMetaData->mValues[i].mType; - void* value = node->mMetaData->mValues[i].mData; - - Write(&chunk, key); - Write(&chunk, type); - - switch (type) { - case AI_BOOL: - Write(&chunk, *((bool*) value)); - break; - case AI_INT32: - Write(&chunk, *((int32_t*) value)); - break; - case AI_UINT64: - Write(&chunk, *((uint64_t*) value)); - break; - case AI_FLOAT: - Write(&chunk, *((float*) value)); - break; - case AI_DOUBLE: - Write(&chunk, *((double*) value)); - break; - case AI_AISTRING: - Write(&chunk, *((aiString*) value)); - break; - case AI_AIVECTOR3D: - Write(&chunk, *((aiVector3D*) value)); - break; -#ifdef SWIG - case FORCE_32BIT: -#endif // SWIG - default: - break; - } - } - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryTexture(IOStream * container, const aiTexture* tex) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AITEXTURE ); - - Write(&chunk,tex->mWidth); - Write(&chunk,tex->mHeight); - chunk.Write( tex->achFormatHint, sizeof(char), 4 ); - - if(!shortened) { - if (!tex->mHeight) { - chunk.Write(tex->pcData,1,tex->mWidth); - } - else { - chunk.Write(tex->pcData,1,tex->mWidth*tex->mHeight*4); - } - } - - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryBone(IOStream * container, const aiBone* b) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIBONE ); - - Write(&chunk,b->mName); - Write(&chunk,b->mNumWeights); - Write(&chunk,b->mOffsetMatrix); - - // for the moment we write dumb min/max values for the bones, too. - // maybe I'll add a better, hash-like solution later - if (shortened) { - WriteBounds(&chunk,b->mWeights,b->mNumWeights); - } // else write as usual - else WriteArray(&chunk,b->mWeights,b->mNumWeights); - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryMesh(IOStream * container, const aiMesh* mesh) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMESH ); - - Write(&chunk,mesh->mPrimitiveTypes); - Write(&chunk,mesh->mNumVertices); - Write(&chunk,mesh->mNumFaces); - Write(&chunk,mesh->mNumBones); - Write(&chunk,mesh->mMaterialIndex); - - // first of all, write bits for all existent vertex components - unsigned int c = 0; - if (mesh->mVertices) { - c |= ASSBIN_MESH_HAS_POSITIONS; - } - if (mesh->mNormals) { - c |= ASSBIN_MESH_HAS_NORMALS; - } - if (mesh->mTangents && mesh->mBitangents) { - c |= ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS; - } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { - if (!mesh->mTextureCoords[n]) { - break; - } - c |= ASSBIN_MESH_HAS_TEXCOORD(n); - } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { - if (!mesh->mColors[n]) { - break; - } - c |= ASSBIN_MESH_HAS_COLOR(n); - } - Write(&chunk,c); - - aiVector3D minVec, maxVec; - if (mesh->mVertices) { - if (shortened) { - WriteBounds(&chunk,mesh->mVertices,mesh->mNumVertices); - } // else write as usual - else WriteArray(&chunk,mesh->mVertices,mesh->mNumVertices); - } - if (mesh->mNormals) { - if (shortened) { - WriteBounds(&chunk,mesh->mNormals,mesh->mNumVertices); - } // else write as usual - else WriteArray(&chunk,mesh->mNormals,mesh->mNumVertices); - } - if (mesh->mTangents && mesh->mBitangents) { - if (shortened) { - WriteBounds(&chunk,mesh->mTangents,mesh->mNumVertices); - WriteBounds(&chunk,mesh->mBitangents,mesh->mNumVertices); - } // else write as usual - else { - WriteArray(&chunk,mesh->mTangents,mesh->mNumVertices); - WriteArray(&chunk,mesh->mBitangents,mesh->mNumVertices); - } - } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { - if (!mesh->mColors[n]) - break; - - if (shortened) { - WriteBounds(&chunk,mesh->mColors[n],mesh->mNumVertices); - } // else write as usual - else WriteArray(&chunk,mesh->mColors[n],mesh->mNumVertices); - } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { - if (!mesh->mTextureCoords[n]) - break; - - // write number of UV components - Write(&chunk,mesh->mNumUVComponents[n]); - - if (shortened) { - WriteBounds(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices); - } // else write as usual - else WriteArray(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices); - } - - // write faces. There are no floating-point calculations involved - // in these, so we can write a simple hash over the face data - // to the dump file. We generate a single 32 Bit hash for 512 faces - // using Assimp's standard hashing function. - if (shortened) { - unsigned int processed = 0; - for (unsigned int job;(job = std::min(mesh->mNumFaces-processed,512u));processed += job) { - - uint32_t hash = 0; - for (unsigned int a = 0; a < job;++a) { - - const aiFace& f = mesh->mFaces[processed+a]; - uint32_t tmp = f.mNumIndices; - hash = SuperFastHash(reinterpret_cast(&tmp),sizeof tmp,hash); - for (unsigned int i = 0; i < f.mNumIndices; ++i) { - static_assert(AI_MAX_VERTICES <= 0xffffffff, "AI_MAX_VERTICES <= 0xffffffff"); - tmp = static_cast( f.mIndices[i] ); - hash = SuperFastHash(reinterpret_cast(&tmp),sizeof tmp,hash); - } - } - Write(&chunk,hash); - } - } - else // else write as usual - { - // if there are less than 2^16 vertices, we can simply use 16 bit integers ... - for (unsigned int i = 0; i < mesh->mNumFaces;++i) { - const aiFace& f = mesh->mFaces[i]; - - static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff"); - Write(&chunk,f.mNumIndices); - - for (unsigned int a = 0; a < f.mNumIndices;++a) { - if (mesh->mNumVertices < (1u<<16)) { - Write(&chunk,f.mIndices[a]); - } - else Write(&chunk,f.mIndices[a]); - } - } - } - - // write bones - if (mesh->mNumBones) { - for (unsigned int a = 0; a < mesh->mNumBones;++a) { - const aiBone* b = mesh->mBones[a]; - WriteBinaryBone(&chunk,b); - } - } - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryMaterialProperty(IOStream * container, const aiMaterialProperty* prop) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIALPROPERTY ); - - Write(&chunk,prop->mKey); - Write(&chunk,prop->mSemantic); - Write(&chunk,prop->mIndex); - - Write(&chunk,prop->mDataLength); - Write(&chunk,(unsigned int)prop->mType); - chunk.Write(prop->mData,1,prop->mDataLength); - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryMaterial(IOStream * container, const aiMaterial* mat) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIAL); - - Write(&chunk,mat->mNumProperties); - for (unsigned int i = 0; i < mat->mNumProperties;++i) { - WriteBinaryMaterialProperty( &chunk, mat->mProperties[i]); - } - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryNodeAnim(IOStream * container, const aiNodeAnim* nd) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODEANIM ); - - Write(&chunk,nd->mNodeName); - Write(&chunk,nd->mNumPositionKeys); - Write(&chunk,nd->mNumRotationKeys); - Write(&chunk,nd->mNumScalingKeys); - Write(&chunk,nd->mPreState); - Write(&chunk,nd->mPostState); - - if (nd->mPositionKeys) { - if (shortened) { - WriteBounds(&chunk,nd->mPositionKeys,nd->mNumPositionKeys); - - } // else write as usual - else WriteArray(&chunk,nd->mPositionKeys,nd->mNumPositionKeys); - } - if (nd->mRotationKeys) { - if (shortened) { - WriteBounds(&chunk,nd->mRotationKeys,nd->mNumRotationKeys); - - } // else write as usual - else WriteArray(&chunk,nd->mRotationKeys,nd->mNumRotationKeys); - } - if (nd->mScalingKeys) { - if (shortened) { - WriteBounds(&chunk,nd->mScalingKeys,nd->mNumScalingKeys); - - } // else write as usual - else WriteArray(&chunk,nd->mScalingKeys,nd->mNumScalingKeys); - } - } - - - // ----------------------------------------------------------------------------------- - void WriteBinaryAnim( IOStream * container, const aiAnimation* anim ) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIANIMATION ); - - Write(&chunk,anim->mName); - Write(&chunk,anim->mDuration); - Write(&chunk,anim->mTicksPerSecond); - Write(&chunk,anim->mNumChannels); - - for (unsigned int a = 0; a < anim->mNumChannels;++a) { - const aiNodeAnim* nd = anim->mChannels[a]; - WriteBinaryNodeAnim(&chunk,nd); - } - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryLight( IOStream * container, const aiLight* l ) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AILIGHT ); - - Write(&chunk,l->mName); - Write(&chunk,l->mType); - - if (l->mType != aiLightSource_DIRECTIONAL) { - Write(&chunk,l->mAttenuationConstant); - Write(&chunk,l->mAttenuationLinear); - Write(&chunk,l->mAttenuationQuadratic); - } - - Write(&chunk,l->mColorDiffuse); - Write(&chunk,l->mColorSpecular); - Write(&chunk,l->mColorAmbient); - - if (l->mType == aiLightSource_SPOT) { - Write(&chunk,l->mAngleInnerCone); - Write(&chunk,l->mAngleOuterCone); - } - - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryCamera( IOStream * container, const aiCamera* cam ) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AICAMERA ); - - Write(&chunk,cam->mName); - Write(&chunk,cam->mPosition); - Write(&chunk,cam->mLookAt); - Write(&chunk,cam->mUp); - Write(&chunk,cam->mHorizontalFOV); - Write(&chunk,cam->mClipPlaneNear); - Write(&chunk,cam->mClipPlaneFar); - Write(&chunk,cam->mAspect); - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryScene( IOStream * container, const aiScene* scene) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AISCENE ); - - // basic scene information - Write(&chunk,scene->mFlags); - Write(&chunk,scene->mNumMeshes); - Write(&chunk,scene->mNumMaterials); - Write(&chunk,scene->mNumAnimations); - Write(&chunk,scene->mNumTextures); - Write(&chunk,scene->mNumLights); - Write(&chunk,scene->mNumCameras); - - // write node graph - WriteBinaryNode( &chunk, scene->mRootNode ); - - // write all meshes - for (unsigned int i = 0; i < scene->mNumMeshes;++i) { - const aiMesh* mesh = scene->mMeshes[i]; - WriteBinaryMesh( &chunk,mesh); - } - - // write materials - for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { - const aiMaterial* mat = scene->mMaterials[i]; - WriteBinaryMaterial(&chunk,mat); - } - - // write all animations - for (unsigned int i = 0; i < scene->mNumAnimations;++i) { - const aiAnimation* anim = scene->mAnimations[i]; - WriteBinaryAnim(&chunk,anim); - } - - - // write all textures - for (unsigned int i = 0; i < scene->mNumTextures;++i) { - const aiTexture* mesh = scene->mTextures[i]; - WriteBinaryTexture(&chunk,mesh); - } - - // write lights - for (unsigned int i = 0; i < scene->mNumLights;++i) { - const aiLight* l = scene->mLights[i]; - WriteBinaryLight(&chunk,l); - } - - // write cameras - for (unsigned int i = 0; i < scene->mNumCameras;++i) { - const aiCamera* cam = scene->mCameras[i]; - WriteBinaryCamera(&chunk,cam); - } - - } - -public: - AssbinExport() - : shortened(false), compressed(false) // temporary settings until properties are introduced for exporters - { - } - - // ----------------------------------------------------------------------------------- - // Write a binary model dump - void WriteBinaryDump(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene) - { - IOStream * out = pIOSystem->Open( pFile, "wb" ); - if (!out) return; - - time_t tt = time(NULL); -#if _WIN32 - tm* p = gmtime(&tt); -#else - struct tm now; - tm* p = gmtime_r(&tt, &now); -#endif - - // header - char s[64]; - memset( s, 0, 64 ); -#if _MSC_VER >= 1400 - sprintf_s(s,"ASSIMP.binary-dump.%s",asctime(p)); -#else - ai_snprintf(s,64,"ASSIMP.binary-dump.%s",asctime(p)); -#endif - out->Write( s, 44, 1 ); - // == 44 bytes - - Write( out, ASSBIN_VERSION_MAJOR ); - Write( out, ASSBIN_VERSION_MINOR ); - Write( out, aiGetVersionRevision() ); - Write( out, aiGetCompileFlags() ); - Write( out, shortened ); - Write( out, compressed ); - // == 20 bytes - - char buff[256]; - strncpy(buff,pFile,256); - out->Write(buff,sizeof(char),256); - - char cmd[] = "\0"; - strncpy(buff,cmd,128); - out->Write(buff,sizeof(char),128); - - // leave 64 bytes free for future extensions - memset(buff,0xcd,64); - out->Write(buff,sizeof(char),64); - // == 435 bytes - - // ==== total header size: 512 bytes - ai_assert( out->Tell() == ASSBIN_HEADER_LENGTH ); - - // Up to here the data is uncompressed. For compressed files, the rest - // is compressed using standard DEFLATE from zlib. - if (compressed) - { - AssbinChunkWriter uncompressedStream( NULL, 0 ); - WriteBinaryScene( &uncompressedStream, pScene ); - - uLongf uncompressedSize = static_cast(uncompressedStream.Tell()); - uLongf compressedSize = (uLongf)compressBound(uncompressedSize); - uint8_t* compressedBuffer = new uint8_t[ compressedSize ]; - - int res = compress2( compressedBuffer, &compressedSize, (const Bytef*)uncompressedStream.GetBufferPointer(), uncompressedSize, 9 ); - if(res != Z_OK) - { - delete [] compressedBuffer; - pIOSystem->Close(out); - throw DeadlyExportError("Compression failed."); - } - - out->Write( &uncompressedSize, sizeof(uint32_t), 1 ); - out->Write( compressedBuffer, sizeof(char), compressedSize ); - - delete[] compressedBuffer; - } - else - { - WriteBinaryScene( out, pScene ); - } - - pIOSystem->Close( out ); - } -}; - void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) { - AssbinExport exporter; - exporter.WriteBinaryDump( pFile, pIOSystem, pScene ); + DumpSceneToAssbin( + pFile, + "\0", // no command(s). + pIOSystem, + pScene, + false, // shortened? + false); // compressed? } } // end of namespace Assimp diff --git a/Engine/lib/assimp/code/Assbin/AssbinExporter.h b/Engine/lib/assimp/code/Assbin/AssbinExporter.h index 3e13639bb..350ed85e3 100644 --- a/Engine/lib/assimp/code/Assbin/AssbinExporter.h +++ b/Engine/lib/assimp/code/Assbin/AssbinExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Assbin/AssbinFileWriter.cpp b/Engine/lib/assimp/code/Assbin/AssbinFileWriter.cpp new file mode 100644 index 000000000..4bc8f7cac --- /dev/null +++ b/Engine/lib/assimp/code/Assbin/AssbinFileWriter.cpp @@ -0,0 +1,858 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +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. + +---------------------------------------------------------------------- +*/ +/** @file AssbinFileWriter.cpp + * @brief Implementation of Assbin file writer. + */ + +#include "AssbinFileWriter.h" + +#include "Common/assbin_chunks.h" +#include "PostProcessing/ProcessHelper.h" + +#include +#include +#include +#include + +#ifdef ASSIMP_BUILD_NO_OWN_ZLIB +# include +#else +# include "../contrib/zlib/zlib.h" +#endif + +#include + +namespace Assimp { + +template +size_t Write(IOStream * stream, const T& v) { + return stream->Write( &v, sizeof(T), 1 ); +} + +// ----------------------------------------------------------------------------------- +// Serialize an aiString +template <> +inline +size_t Write(IOStream * stream, const aiString& s) { + const size_t s2 = (uint32_t)s.length; + stream->Write(&s,4,1); + stream->Write(s.data,s2,1); + + return s2+4; +} + +// ----------------------------------------------------------------------------------- +// Serialize an unsigned int as uint32_t +template <> +inline +size_t Write(IOStream * stream, const unsigned int& w) { + const uint32_t t = (uint32_t)w; + if (w > t) { + // this shouldn't happen, integers in Assimp data structures never exceed 2^32 + throw DeadlyExportError("loss of data due to 64 -> 32 bit integer conversion"); + } + + stream->Write(&t,4,1); + + return 4; +} + +// ----------------------------------------------------------------------------------- +// Serialize an unsigned int as uint16_t +template <> +inline +size_t Write(IOStream * stream, const uint16_t& w) { + static_assert(sizeof(uint16_t)==2, "sizeof(uint16_t)==2"); + stream->Write(&w,2,1); + + return 2; +} + +// ----------------------------------------------------------------------------------- +// Serialize a float +template <> +inline +size_t Write(IOStream * stream, const float& f) { + static_assert(sizeof(float)==4, "sizeof(float)==4"); + stream->Write(&f,4,1); + + return 4; +} + +// ----------------------------------------------------------------------------------- +// Serialize a double +template <> +inline +size_t Write(IOStream * stream, const double& f) { + static_assert(sizeof(double)==8, "sizeof(double)==8"); + stream->Write(&f,8,1); + + return 8; +} + +// ----------------------------------------------------------------------------------- +// Serialize a vec3 +template <> +inline +size_t Write(IOStream * stream, const aiVector3D& v) { + size_t t = Write(stream,v.x); + t += Write(stream,v.y); + t += Write(stream,v.z); + + return t; +} + +// ----------------------------------------------------------------------------------- +// Serialize a color value +template <> +inline +size_t Write(IOStream * stream, const aiColor3D& v) { + size_t t = Write(stream,v.r); + t += Write(stream,v.g); + t += Write(stream,v.b); + + return t; +} + +// ----------------------------------------------------------------------------------- +// Serialize a color value +template <> +inline +size_t Write(IOStream * stream, const aiColor4D& v) { + size_t t = Write(stream,v.r); + t += Write(stream,v.g); + t += Write(stream,v.b); + t += Write(stream,v.a); + + return t; +} + +// ----------------------------------------------------------------------------------- +// Serialize a quaternion +template <> +inline +size_t Write(IOStream * stream, const aiQuaternion& v) { + size_t t = Write(stream,v.w); + t += Write(stream,v.x); + t += Write(stream,v.y); + t += Write(stream,v.z); + ai_assert(t == 16); + + return 16; +} + +// ----------------------------------------------------------------------------------- +// Serialize a vertex weight +template <> +inline +size_t Write(IOStream * stream, const aiVertexWeight& v) { + size_t t = Write(stream,v.mVertexId); + + return t+Write(stream,v.mWeight); +} + +// ----------------------------------------------------------------------------------- +// Serialize a mat4x4 +template <> +inline +size_t Write(IOStream * stream, const aiMatrix4x4& m) { + for (unsigned int i = 0; i < 4;++i) { + for (unsigned int i2 = 0; i2 < 4;++i2) { + Write(stream,m[i][i2]); + } + } + + return 64; +} + +// ----------------------------------------------------------------------------------- +// Serialize an aiVectorKey +template <> +inline +size_t Write(IOStream * stream, const aiVectorKey& v) { + const size_t t = Write(stream,v.mTime); + return t + Write(stream,v.mValue); +} + +// ----------------------------------------------------------------------------------- +// Serialize an aiQuatKey +template <> +inline +size_t Write(IOStream * stream, const aiQuatKey& v) { + const size_t t = Write(stream,v.mTime); + return t + Write(stream,v.mValue); +} + +template +inline +size_t WriteBounds(IOStream * stream, const T* in, unsigned int size) { + T minc, maxc; + ArrayBounds(in,size,minc,maxc); + + const size_t t = Write(stream,minc); + return t + Write(stream,maxc); +} + +// We use this to write out non-byte arrays so that we write using the specializations. +// This way we avoid writing out extra bytes that potentially come from struct alignment. +template +inline +size_t WriteArray(IOStream * stream, const T* in, unsigned int size) { + size_t n = 0; + for (unsigned int i=0; i(stream,in[i]); + + return n; +} + +// ---------------------------------------------------------------------------------- +/** @class AssbinChunkWriter + * @brief Chunk writer mechanism for the .assbin file structure + * + * This is a standard in-memory IOStream (most of the code is based on BlobIOStream), + * the difference being that this takes another IOStream as a "container" in the + * constructor, and when it is destroyed, it appends the magic number, the chunk size, + * and the chunk contents to the container stream. This allows relatively easy chunk + * chunk construction, even recursively. + */ +class AssbinChunkWriter : public IOStream +{ +private: + + uint8_t* buffer; + uint32_t magic; + IOStream * container; + size_t cur_size, cursor, initial; + +private: + // ------------------------------------------------------------------- + void Grow(size_t need = 0) + { + size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) )); + + const uint8_t* const old = buffer; + buffer = new uint8_t[new_size]; + + if (old) { + memcpy(buffer,old,cur_size); + delete[] old; + } + + cur_size = new_size; + } + +public: + + AssbinChunkWriter( IOStream * container, uint32_t magic, size_t initial = 4096) + : buffer(NULL), magic(magic), container(container), cur_size(0), cursor(0), initial(initial) + { + } + + virtual ~AssbinChunkWriter() + { + if (container) { + container->Write( &magic, sizeof(uint32_t), 1 ); + container->Write( &cursor, sizeof(uint32_t), 1 ); + container->Write( buffer, 1, cursor ); + } + if (buffer) delete[] buffer; + } + + void * GetBufferPointer() { return buffer; } + + // ------------------------------------------------------------------- + virtual size_t Read(void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { + return 0; + } + virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) { + return aiReturn_FAILURE; + } + virtual size_t Tell() const { + return cursor; + } + virtual void Flush() { + // not implemented + } + + virtual size_t FileSize() const { + return cursor; + } + + // ------------------------------------------------------------------- + virtual size_t Write(const void* pvBuffer, size_t pSize, size_t pCount) { + pSize *= pCount; + if (cursor + pSize > cur_size) { + Grow(cursor + pSize); + } + + memcpy(buffer+cursor, pvBuffer, pSize); + cursor += pSize; + + return pCount; + } + +}; + +// ---------------------------------------------------------------------------------- +/** @class AssbinFileWriter + * @brief Assbin file writer class + * + * This class writes an .assbin file, and is responsible for the file layout. + */ +class AssbinFileWriter +{ +private: + bool shortened; + bool compressed; + +protected: + // ----------------------------------------------------------------------------------- + void WriteBinaryNode( IOStream * container, const aiNode* node) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODE ); + + unsigned int nb_metadata = (node->mMetaData != NULL ? node->mMetaData->mNumProperties : 0); + + Write(&chunk,node->mName); + Write(&chunk,node->mTransformation); + Write(&chunk,node->mNumChildren); + Write(&chunk,node->mNumMeshes); + Write(&chunk,nb_metadata); + + for (unsigned int i = 0; i < node->mNumMeshes;++i) { + Write(&chunk,node->mMeshes[i]); + } + + for (unsigned int i = 0; i < node->mNumChildren;++i) { + WriteBinaryNode( &chunk, node->mChildren[i] ); + } + + for (unsigned int i = 0; i < nb_metadata; ++i) { + const aiString& key = node->mMetaData->mKeys[i]; + aiMetadataType type = node->mMetaData->mValues[i].mType; + void* value = node->mMetaData->mValues[i].mData; + + Write(&chunk, key); + Write(&chunk, type); + + switch (type) { + case AI_BOOL: + Write(&chunk, *((bool*) value)); + break; + case AI_INT32: + Write(&chunk, *((int32_t*) value)); + break; + case AI_UINT64: + Write(&chunk, *((uint64_t*) value)); + break; + case AI_FLOAT: + Write(&chunk, *((float*) value)); + break; + case AI_DOUBLE: + Write(&chunk, *((double*) value)); + break; + case AI_AISTRING: + Write(&chunk, *((aiString*) value)); + break; + case AI_AIVECTOR3D: + Write(&chunk, *((aiVector3D*) value)); + break; +#ifdef SWIG + case FORCE_32BIT: +#endif // SWIG + default: + break; + } + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryTexture(IOStream * container, const aiTexture* tex) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AITEXTURE ); + + Write(&chunk,tex->mWidth); + Write(&chunk,tex->mHeight); + // Write the texture format, but don't include the null terminator. + chunk.Write( tex->achFormatHint, sizeof(char), HINTMAXTEXTURELEN - 1 ); + + if(!shortened) { + if (!tex->mHeight) { + chunk.Write(tex->pcData,1,tex->mWidth); + } + else { + chunk.Write(tex->pcData,1,tex->mWidth*tex->mHeight*4); + } + } + + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryBone(IOStream * container, const aiBone* b) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIBONE ); + + Write(&chunk,b->mName); + Write(&chunk,b->mNumWeights); + Write(&chunk,b->mOffsetMatrix); + + // for the moment we write dumb min/max values for the bones, too. + // maybe I'll add a better, hash-like solution later + if (shortened) { + WriteBounds(&chunk,b->mWeights,b->mNumWeights); + } // else write as usual + else WriteArray(&chunk,b->mWeights,b->mNumWeights); + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryMesh(IOStream * container, const aiMesh* mesh) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMESH ); + + Write(&chunk,mesh->mPrimitiveTypes); + Write(&chunk,mesh->mNumVertices); + Write(&chunk,mesh->mNumFaces); + Write(&chunk,mesh->mNumBones); + Write(&chunk,mesh->mMaterialIndex); + + // first of all, write bits for all existent vertex components + unsigned int c = 0; + if (mesh->mVertices) { + c |= ASSBIN_MESH_HAS_POSITIONS; + } + if (mesh->mNormals) { + c |= ASSBIN_MESH_HAS_NORMALS; + } + if (mesh->mTangents && mesh->mBitangents) { + c |= ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS; + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { + if (!mesh->mTextureCoords[n]) { + break; + } + c |= ASSBIN_MESH_HAS_TEXCOORD(n); + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { + if (!mesh->mColors[n]) { + break; + } + c |= ASSBIN_MESH_HAS_COLOR(n); + } + Write(&chunk,c); + + aiVector3D minVec, maxVec; + if (mesh->mVertices) { + if (shortened) { + WriteBounds(&chunk,mesh->mVertices,mesh->mNumVertices); + } // else write as usual + else WriteArray(&chunk,mesh->mVertices,mesh->mNumVertices); + } + if (mesh->mNormals) { + if (shortened) { + WriteBounds(&chunk,mesh->mNormals,mesh->mNumVertices); + } // else write as usual + else WriteArray(&chunk,mesh->mNormals,mesh->mNumVertices); + } + if (mesh->mTangents && mesh->mBitangents) { + if (shortened) { + WriteBounds(&chunk,mesh->mTangents,mesh->mNumVertices); + WriteBounds(&chunk,mesh->mBitangents,mesh->mNumVertices); + } // else write as usual + else { + WriteArray(&chunk,mesh->mTangents,mesh->mNumVertices); + WriteArray(&chunk,mesh->mBitangents,mesh->mNumVertices); + } + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { + if (!mesh->mColors[n]) + break; + + if (shortened) { + WriteBounds(&chunk,mesh->mColors[n],mesh->mNumVertices); + } // else write as usual + else WriteArray(&chunk,mesh->mColors[n],mesh->mNumVertices); + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { + if (!mesh->mTextureCoords[n]) + break; + + // write number of UV components + Write(&chunk,mesh->mNumUVComponents[n]); + + if (shortened) { + WriteBounds(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices); + } // else write as usual + else WriteArray(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices); + } + + // write faces. There are no floating-point calculations involved + // in these, so we can write a simple hash over the face data + // to the dump file. We generate a single 32 Bit hash for 512 faces + // using Assimp's standard hashing function. + if (shortened) { + unsigned int processed = 0; + for (unsigned int job;(job = std::min(mesh->mNumFaces-processed,512u));processed += job) { + + uint32_t hash = 0; + for (unsigned int a = 0; a < job;++a) { + + const aiFace& f = mesh->mFaces[processed+a]; + uint32_t tmp = f.mNumIndices; + hash = SuperFastHash(reinterpret_cast(&tmp),sizeof tmp,hash); + for (unsigned int i = 0; i < f.mNumIndices; ++i) { + static_assert(AI_MAX_VERTICES <= 0xffffffff, "AI_MAX_VERTICES <= 0xffffffff"); + tmp = static_cast( f.mIndices[i] ); + hash = SuperFastHash(reinterpret_cast(&tmp),sizeof tmp,hash); + } + } + Write(&chunk,hash); + } + } + else // else write as usual + { + // if there are less than 2^16 vertices, we can simply use 16 bit integers ... + for (unsigned int i = 0; i < mesh->mNumFaces;++i) { + const aiFace& f = mesh->mFaces[i]; + + static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff"); + Write(&chunk,f.mNumIndices); + + for (unsigned int a = 0; a < f.mNumIndices;++a) { + if (mesh->mNumVertices < (1u<<16)) { + Write(&chunk,f.mIndices[a]); + } + else Write(&chunk,f.mIndices[a]); + } + } + } + + // write bones + if (mesh->mNumBones) { + for (unsigned int a = 0; a < mesh->mNumBones;++a) { + const aiBone* b = mesh->mBones[a]; + WriteBinaryBone(&chunk,b); + } + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryMaterialProperty(IOStream * container, const aiMaterialProperty* prop) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIALPROPERTY ); + + Write(&chunk,prop->mKey); + Write(&chunk,prop->mSemantic); + Write(&chunk,prop->mIndex); + + Write(&chunk,prop->mDataLength); + Write(&chunk,(unsigned int)prop->mType); + chunk.Write(prop->mData,1,prop->mDataLength); + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryMaterial(IOStream * container, const aiMaterial* mat) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIAL); + + Write(&chunk,mat->mNumProperties); + for (unsigned int i = 0; i < mat->mNumProperties;++i) { + WriteBinaryMaterialProperty( &chunk, mat->mProperties[i]); + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryNodeAnim(IOStream * container, const aiNodeAnim* nd) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODEANIM ); + + Write(&chunk,nd->mNodeName); + Write(&chunk,nd->mNumPositionKeys); + Write(&chunk,nd->mNumRotationKeys); + Write(&chunk,nd->mNumScalingKeys); + Write(&chunk,nd->mPreState); + Write(&chunk,nd->mPostState); + + if (nd->mPositionKeys) { + if (shortened) { + WriteBounds(&chunk,nd->mPositionKeys,nd->mNumPositionKeys); + + } // else write as usual + else WriteArray(&chunk,nd->mPositionKeys,nd->mNumPositionKeys); + } + if (nd->mRotationKeys) { + if (shortened) { + WriteBounds(&chunk,nd->mRotationKeys,nd->mNumRotationKeys); + + } // else write as usual + else WriteArray(&chunk,nd->mRotationKeys,nd->mNumRotationKeys); + } + if (nd->mScalingKeys) { + if (shortened) { + WriteBounds(&chunk,nd->mScalingKeys,nd->mNumScalingKeys); + + } // else write as usual + else WriteArray(&chunk,nd->mScalingKeys,nd->mNumScalingKeys); + } + } + + + // ----------------------------------------------------------------------------------- + void WriteBinaryAnim( IOStream * container, const aiAnimation* anim ) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIANIMATION ); + + Write(&chunk,anim->mName); + Write(&chunk,anim->mDuration); + Write(&chunk,anim->mTicksPerSecond); + Write(&chunk,anim->mNumChannels); + + for (unsigned int a = 0; a < anim->mNumChannels;++a) { + const aiNodeAnim* nd = anim->mChannels[a]; + WriteBinaryNodeAnim(&chunk,nd); + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryLight( IOStream * container, const aiLight* l ) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AILIGHT ); + + Write(&chunk,l->mName); + Write(&chunk,l->mType); + + if (l->mType != aiLightSource_DIRECTIONAL) { + Write(&chunk,l->mAttenuationConstant); + Write(&chunk,l->mAttenuationLinear); + Write(&chunk,l->mAttenuationQuadratic); + } + + Write(&chunk,l->mColorDiffuse); + Write(&chunk,l->mColorSpecular); + Write(&chunk,l->mColorAmbient); + + if (l->mType == aiLightSource_SPOT) { + Write(&chunk,l->mAngleInnerCone); + Write(&chunk,l->mAngleOuterCone); + } + + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryCamera( IOStream * container, const aiCamera* cam ) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AICAMERA ); + + Write(&chunk,cam->mName); + Write(&chunk,cam->mPosition); + Write(&chunk,cam->mLookAt); + Write(&chunk,cam->mUp); + Write(&chunk,cam->mHorizontalFOV); + Write(&chunk,cam->mClipPlaneNear); + Write(&chunk,cam->mClipPlaneFar); + Write(&chunk,cam->mAspect); + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryScene( IOStream * container, const aiScene* scene) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AISCENE ); + + // basic scene information + Write(&chunk,scene->mFlags); + Write(&chunk,scene->mNumMeshes); + Write(&chunk,scene->mNumMaterials); + Write(&chunk,scene->mNumAnimations); + Write(&chunk,scene->mNumTextures); + Write(&chunk,scene->mNumLights); + Write(&chunk,scene->mNumCameras); + + // write node graph + WriteBinaryNode( &chunk, scene->mRootNode ); + + // write all meshes + for (unsigned int i = 0; i < scene->mNumMeshes;++i) { + const aiMesh* mesh = scene->mMeshes[i]; + WriteBinaryMesh( &chunk,mesh); + } + + // write materials + for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { + const aiMaterial* mat = scene->mMaterials[i]; + WriteBinaryMaterial(&chunk,mat); + } + + // write all animations + for (unsigned int i = 0; i < scene->mNumAnimations;++i) { + const aiAnimation* anim = scene->mAnimations[i]; + WriteBinaryAnim(&chunk,anim); + } + + + // write all textures + for (unsigned int i = 0; i < scene->mNumTextures;++i) { + const aiTexture* mesh = scene->mTextures[i]; + WriteBinaryTexture(&chunk,mesh); + } + + // write lights + for (unsigned int i = 0; i < scene->mNumLights;++i) { + const aiLight* l = scene->mLights[i]; + WriteBinaryLight(&chunk,l); + } + + // write cameras + for (unsigned int i = 0; i < scene->mNumCameras;++i) { + const aiCamera* cam = scene->mCameras[i]; + WriteBinaryCamera(&chunk,cam); + } + + } + +public: + AssbinFileWriter(bool shortened, bool compressed) + : shortened(shortened), compressed(compressed) + { + } + + // ----------------------------------------------------------------------------------- + // Write a binary model dump + void WriteBinaryDump(const char* pFile, const char* cmd, IOSystem* pIOSystem, const aiScene* pScene) + { + IOStream * out = pIOSystem->Open( pFile, "wb" ); + if (!out) + throw std::runtime_error("Unable to open output file " + std::string(pFile) + '\n'); + + auto CloseIOStream = [&]() { + if (out) { + pIOSystem->Close(out); + out = nullptr; // Ensure this is only done once. + } + }; + + try { + time_t tt = time(NULL); +#if _WIN32 + tm* p = gmtime(&tt); +#else + struct tm now; + tm* p = gmtime_r(&tt, &now); +#endif + + // header + char s[64]; + memset(s, 0, 64); +#if _MSC_VER >= 1400 + sprintf_s(s, "ASSIMP.binary-dump.%s", asctime(p)); +#else + ai_snprintf(s, 64, "ASSIMP.binary-dump.%s", asctime(p)); +#endif + out->Write(s, 44, 1); + // == 44 bytes + + Write(out, ASSBIN_VERSION_MAJOR); + Write(out, ASSBIN_VERSION_MINOR); + Write(out, aiGetVersionRevision()); + Write(out, aiGetCompileFlags()); + Write(out, shortened); + Write(out, compressed); + // == 20 bytes + + char buff[256] = {0}; + ai_snprintf(buff, 256, "%s", pFile); + out->Write(buff, sizeof(char), 256); + + memset(buff, 0, sizeof(buff)); + ai_snprintf(buff, 128, "%s", cmd); + out->Write(buff, sizeof(char), 128); + + // leave 64 bytes free for future extensions + memset(buff, 0xcd, 64); + out->Write(buff, sizeof(char), 64); + // == 435 bytes + + // ==== total header size: 512 bytes + ai_assert(out->Tell() == ASSBIN_HEADER_LENGTH); + + // Up to here the data is uncompressed. For compressed files, the rest + // is compressed using standard DEFLATE from zlib. + if (compressed) + { + AssbinChunkWriter uncompressedStream(NULL, 0); + WriteBinaryScene(&uncompressedStream, pScene); + + uLongf uncompressedSize = static_cast(uncompressedStream.Tell()); + uLongf compressedSize = (uLongf)compressBound(uncompressedSize); + uint8_t* compressedBuffer = new uint8_t[compressedSize]; + + int res = compress2(compressedBuffer, &compressedSize, (const Bytef*)uncompressedStream.GetBufferPointer(), uncompressedSize, 9); + if (res != Z_OK) + { + delete[] compressedBuffer; + throw DeadlyExportError("Compression failed."); + } + + out->Write(&uncompressedSize, sizeof(uint32_t), 1); + out->Write(compressedBuffer, sizeof(char), compressedSize); + + delete[] compressedBuffer; + } + else + { + WriteBinaryScene(out, pScene); + } + + CloseIOStream(); + } + catch (...) { + CloseIOStream(); + throw; + } + } +}; + +void DumpSceneToAssbin( + const char* pFile, const char* cmd, IOSystem* pIOSystem, + const aiScene* pScene, bool shortened, bool compressed) { + AssbinFileWriter fileWriter(shortened, compressed); + fileWriter.WriteBinaryDump(pFile, cmd, pIOSystem, pScene); +} + +} // end of namespace Assimp diff --git a/Engine/lib/assimp/code/Assbin/AssbinFileWriter.h b/Engine/lib/assimp/code/Assbin/AssbinFileWriter.h new file mode 100644 index 000000000..25db6db2d --- /dev/null +++ b/Engine/lib/assimp/code/Assbin/AssbinFileWriter.h @@ -0,0 +1,66 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +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. + +---------------------------------------------------------------------- +*/ + +/** @file AssbinFileWriter.h + * @brief Declaration of Assbin file writer. + */ + +#ifndef AI_ASSBINFILEWRITER_H_INC +#define AI_ASSBINFILEWRITER_H_INC + +#include +#include +#include + +namespace Assimp { + +void ASSIMP_API DumpSceneToAssbin( + const char* pFile, + const char* cmd, + IOSystem* pIOSystem, + const aiScene* pScene, + bool shortened, + bool compressed); + +} + +#endif // AI_ASSBINFILEWRITER_H_INC diff --git a/Engine/lib/assimp/code/Assbin/AssbinLoader.cpp b/Engine/lib/assimp/code/Assbin/AssbinLoader.cpp index becc3f8fc..71e35cb6a 100644 --- a/Engine/lib/assimp/code/Assbin/AssbinLoader.cpp +++ b/Engine/lib/assimp/code/Assbin/AssbinLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team @@ -535,7 +535,7 @@ void AssbinImporter::ReadBinaryTexture(IOStream * stream, aiTexture* tex) { tex->mWidth = Read(stream); tex->mHeight = Read(stream); - stream->Read( tex->achFormatHint, sizeof(char), 4 ); + stream->Read( tex->achFormatHint, sizeof(char), HINTMAXTEXTURELEN - 1 ); if(!shortened) { if (!tex->mHeight) { diff --git a/Engine/lib/assimp/code/Assbin/AssbinLoader.h b/Engine/lib/assimp/code/Assbin/AssbinLoader.h index 9f2dde125..e6e99f26e 100644 --- a/Engine/lib/assimp/code/Assbin/AssbinLoader.h +++ b/Engine/lib/assimp/code/Assbin/AssbinLoader.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Assjson/cencode.c b/Engine/lib/assimp/code/Assjson/cencode.c index db99e7efa..bd302100b 100644 --- a/Engine/lib/assimp/code/Assjson/cencode.c +++ b/Engine/lib/assimp/code/Assjson/cencode.c @@ -42,7 +42,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, { state_in->result = result; state_in->step = step_A; - return codechar - code_out; + return (int)(codechar - code_out); } fragment = *plainchar++; result = (fragment & 0x0fc) >> 2; @@ -53,7 +53,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, { state_in->result = result; state_in->step = step_B; - return codechar - code_out; + return (int)(codechar - code_out); } fragment = *plainchar++; result |= (fragment & 0x0f0) >> 4; @@ -64,7 +64,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, { state_in->result = result; state_in->step = step_C; - return codechar - code_out; + return (int)(codechar - code_out); } fragment = *plainchar++; result |= (fragment & 0x0c0) >> 6; @@ -81,7 +81,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, } } /* control should not reach here */ - return codechar - code_out; + return (int)(codechar - code_out); } int base64_encode_blockend(char* code_out, base64_encodestate* state_in) @@ -104,6 +104,6 @@ int base64_encode_blockend(char* code_out, base64_encodestate* state_in) } *codechar++ = '\n'; - return codechar - code_out; + return (int)(codechar - code_out); } diff --git a/Engine/lib/assimp/code/Assxml/AssxmlExporter.cpp b/Engine/lib/assimp/code/Assxml/AssxmlExporter.cpp index afdecbaf6..720fd5b40 100644 --- a/Engine/lib/assimp/code/Assxml/AssxmlExporter.cpp +++ b/Engine/lib/assimp/code/Assxml/AssxmlExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -46,607 +46,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_EXPORT #ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER -#include "PostProcessing/ProcessHelper.h" - -#include -#include +#include "AssxmlFileWriter.h" #include #include -#include - -#ifdef ASSIMP_BUILD_NO_OWN_ZLIB -# include -#else -# include -#endif - -#include -#include - -using namespace Assimp; - namespace Assimp { -namespace AssxmlExport { - -// ----------------------------------------------------------------------------------- -static int ioprintf( IOStream * io, const char *format, ... ) { - using namespace std; - if ( nullptr == io ) { - return -1; - } - - static const int Size = 4096; - char sz[ Size ]; - ::memset( sz, '\0', Size ); - va_list va; - va_start( va, format ); - const unsigned int nSize = vsnprintf( sz, Size-1, format, va ); - ai_assert( nSize < Size ); - va_end( va ); - - io->Write( sz, sizeof(char), nSize ); - - return nSize; -} - -// ----------------------------------------------------------------------------------- -// Convert a name to standard XML format -static void ConvertName(aiString& out, const aiString& in) { - out.length = 0; - for (unsigned int i = 0; i < in.length; ++i) { - switch (in.data[i]) { - case '<': - out.Append("<");break; - case '>': - out.Append(">");break; - case '&': - out.Append("&");break; - case '\"': - out.Append(""");break; - case '\'': - out.Append("'");break; - default: - out.data[out.length++] = in.data[i]; - } - } - out.data[out.length] = 0; -} - -// ----------------------------------------------------------------------------------- -// Write a single node as text dump -static void WriteNode(const aiNode* node, IOStream * io, unsigned int depth) { - char prefix[512]; - for (unsigned int i = 0; i < depth;++i) - prefix[i] = '\t'; - prefix[depth] = '\0'; - - const aiMatrix4x4& m = node->mTransformation; - - aiString name; - ConvertName(name,node->mName); - ioprintf(io,"%s \n" - "%s\t \n" - "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" - "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" - "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" - "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" - "%s\t \n", - prefix,name.data,prefix, - prefix,m.a1,m.a2,m.a3,m.a4, - prefix,m.b1,m.b2,m.b3,m.b4, - prefix,m.c1,m.c2,m.c3,m.c4, - prefix,m.d1,m.d2,m.d3,m.d4,prefix); - - if (node->mNumMeshes) { - ioprintf(io, "%s\t\n%s\t", - prefix,node->mNumMeshes,prefix); - - for (unsigned int i = 0; i < node->mNumMeshes;++i) { - ioprintf(io,"%i ",node->mMeshes[i]); - } - ioprintf(io,"\n%s\t\n",prefix); - } - - if (node->mNumChildren) { - ioprintf(io,"%s\t\n", - prefix,node->mNumChildren); - - for (unsigned int i = 0; i < node->mNumChildren;++i) { - WriteNode(node->mChildren[i],io,depth+2); - } - ioprintf(io,"%s\t\n",prefix); - } - ioprintf(io,"%s\n",prefix); -} - - -// ----------------------------------------------------------------------------------- -// Some chuncks of text will need to be encoded for XML -// http://stackoverflow.com/questions/5665231/most-efficient-way-to-escape-xml-html-in-c-string#5665377 -static std::string encodeXML(const std::string& data) { - std::string buffer; - buffer.reserve(data.size()); - for(size_t pos = 0; pos != data.size(); ++pos) { - switch(data[pos]) { - case '&': buffer.append("&"); break; - case '\"': buffer.append("""); break; - case '\'': buffer.append("'"); break; - case '<': buffer.append("<"); break; - case '>': buffer.append(">"); break; - default: buffer.append(&data[pos], 1); break; - } - } - return buffer; -} - -// ----------------------------------------------------------------------------------- -// Write a text model dump -static -void WriteDump(const aiScene* scene, IOStream* io, bool shortened) { - time_t tt = ::time( NULL ); -#if _WIN32 - tm* p = gmtime(&tt); -#else - struct tm now; - tm* p = gmtime_r(&tt, &now); -#endif - ai_assert(nullptr != p); - - // write header - std::string header( - "\n" - "\n\n" - "" - " \n\n" - "\n" - ); - - const unsigned int majorVersion( aiGetVersionMajor() ); - const unsigned int minorVersion( aiGetVersionMinor() ); - const unsigned int rev( aiGetVersionRevision() ); - const char *curtime( asctime( p ) ); - ioprintf( io, header.c_str(), majorVersion, minorVersion, rev, curtime, scene->mFlags, 0 ); - - // write the node graph - WriteNode(scene->mRootNode, io, 0); - -#if 0 - // write cameras - for (unsigned int i = 0; i < scene->mNumCameras;++i) { - aiCamera* cam = scene->mCameras[i]; - ConvertName(name,cam->mName); - - // camera header - ioprintf(io,"\t\n" - "\t\t %0 8f %0 8f %0 8f \n" - "\t\t %0 8f %0 8f %0 8f \n" - "\t\t %0 8f %0 8f %0 8f \n" - "\t\t %f \n" - "\t\t %f \n" - "\t\t %f \n" - "\t\t %f \n" - "\t\n", - name.data, - cam->mUp.x,cam->mUp.y,cam->mUp.z, - cam->mLookAt.x,cam->mLookAt.y,cam->mLookAt.z, - cam->mPosition.x,cam->mPosition.y,cam->mPosition.z, - cam->mHorizontalFOV,cam->mAspect,cam->mClipPlaneNear,cam->mClipPlaneFar,i); - } - - // write lights - for (unsigned int i = 0; i < scene->mNumLights;++i) { - aiLight* l = scene->mLights[i]; - ConvertName(name,l->mName); - - // light header - ioprintf(io,"\t type=\"%s\"\n" - "\t\t %0 8f %0 8f %0 8f \n" - "\t\t %0 8f %0 8f %0 8f \n" - "\t\t %0 8f %0 8f %0 8f \n", - name.data, - (l->mType == aiLightSource_DIRECTIONAL ? "directional" : - (l->mType == aiLightSource_POINT ? "point" : "spot" )), - l->mColorDiffuse.r, l->mColorDiffuse.g, l->mColorDiffuse.b, - l->mColorSpecular.r,l->mColorSpecular.g,l->mColorSpecular.b, - l->mColorAmbient.r, l->mColorAmbient.g, l->mColorAmbient.b); - - if (l->mType != aiLightSource_DIRECTIONAL) { - ioprintf(io, - "\t\t %0 8f %0 8f %0 8f \n" - "\t\t %f \n" - "\t\t %f \n" - "\t\t %f \n", - l->mPosition.x,l->mPosition.y,l->mPosition.z, - l->mAttenuationConstant,l->mAttenuationLinear,l->mAttenuationQuadratic); - } - - if (l->mType != aiLightSource_POINT) { - ioprintf(io, - "\t\t %0 8f %0 8f %0 8f \n", - l->mDirection.x,l->mDirection.y,l->mDirection.z); - } - - if (l->mType == aiLightSource_SPOT) { - ioprintf(io, - "\t\t %f \n" - "\t\t %f \n", - l->mAngleOuterCone,l->mAngleInnerCone); - } - ioprintf(io,"\t\n"); - } -#endif - aiString name; - - // write textures - if (scene->mNumTextures) { - ioprintf(io,"\n",scene->mNumTextures); - for (unsigned int i = 0; i < scene->mNumTextures;++i) { - aiTexture* tex = scene->mTextures[i]; - bool compressed = (tex->mHeight == 0); - - // mesh header - ioprintf(io,"\t \n", - (compressed ? -1 : tex->mWidth),(compressed ? -1 : tex->mHeight), - (compressed ? "true" : "false")); - - if (compressed) { - ioprintf(io,"\t\t \n",tex->mWidth); - - if (!shortened) { - for (unsigned int n = 0; n < tex->mWidth;++n) { - ioprintf(io,"\t\t\t%2x",reinterpret_cast(tex->pcData)[n]); - if (n && !(n % 50)) { - ioprintf(io,"\n"); - } - } - } - } - else if (!shortened){ - ioprintf(io,"\t\t \n",tex->mWidth*tex->mHeight*4); - - // const unsigned int width = (unsigned int)std::log10((double)std::max(tex->mHeight,tex->mWidth))+1; - for (unsigned int y = 0; y < tex->mHeight;++y) { - for (unsigned int x = 0; x < tex->mWidth;++x) { - aiTexel* tx = tex->pcData + y*tex->mWidth+x; - unsigned int r = tx->r,g=tx->g,b=tx->b,a=tx->a; - ioprintf(io,"\t\t\t%2x %2x %2x %2x",r,g,b,a); - - // group by four for readability - if ( 0 == ( x + y*tex->mWidth ) % 4 ) { - ioprintf( io, "\n" ); - } - } - } - } - ioprintf(io,"\t\t\n\t\n"); - } - ioprintf(io,"\n"); - } - - // write materials - if (scene->mNumMaterials) { - ioprintf(io,"\n",scene->mNumMaterials); - for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { - const aiMaterial* mat = scene->mMaterials[i]; - - ioprintf(io,"\t\n"); - ioprintf(io,"\t\t\n",mat->mNumProperties); - for (unsigned int n = 0; n < mat->mNumProperties;++n) { - - const aiMaterialProperty* prop = mat->mProperties[n]; - const char* sz = ""; - if (prop->mType == aiPTI_Float) { - sz = "float"; - } - else if (prop->mType == aiPTI_Integer) { - sz = "integer"; - } - else if (prop->mType == aiPTI_String) { - sz = "string"; - } - else if (prop->mType == aiPTI_Buffer) { - sz = "binary_buffer"; - } - - ioprintf(io,"\t\t\tmKey.data, sz, - ::TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex); - - if (prop->mType == aiPTI_Float) { - ioprintf(io," size=\"%i\">\n\t\t\t\t", - static_cast(prop->mDataLength/sizeof(float))); - - for (unsigned int p = 0; p < prop->mDataLength/sizeof(float);++p) { - ioprintf(io,"%f ",*((float*)(prop->mData+p*sizeof(float)))); - } - } - else if (prop->mType == aiPTI_Integer) { - ioprintf(io," size=\"%i\">\n\t\t\t\t", - static_cast(prop->mDataLength/sizeof(int))); - - for (unsigned int p = 0; p < prop->mDataLength/sizeof(int);++p) { - ioprintf(io,"%i ",*((int*)(prop->mData+p*sizeof(int)))); - } - } - else if (prop->mType == aiPTI_Buffer) { - ioprintf(io," size=\"%i\">\n\t\t\t\t", - static_cast(prop->mDataLength)); - - for (unsigned int p = 0; p < prop->mDataLength;++p) { - ioprintf(io,"%2x ",prop->mData[p]); - if (p && 0 == p%30) { - ioprintf(io,"\n\t\t\t\t"); - } - } - } - else if (prop->mType == aiPTI_String) { - ioprintf(io,">\n\t\t\t\t\"%s\"",encodeXML(prop->mData+4).c_str() /* skip length */); - } - ioprintf(io,"\n\t\t\t\n"); - } - ioprintf(io,"\t\t\n"); - ioprintf(io,"\t\n"); - } - ioprintf(io,"\n"); - } - - // write animations - if (scene->mNumAnimations) { - ioprintf(io,"\n",scene->mNumAnimations); - for (unsigned int i = 0; i < scene->mNumAnimations;++i) { - aiAnimation* anim = scene->mAnimations[i]; - - // anim header - ConvertName(name,anim->mName); - ioprintf(io,"\t\n", - name.data, anim->mDuration, anim->mTicksPerSecond); - - // write bone animation channels - if (anim->mNumChannels) { - ioprintf(io,"\t\t\n",anim->mNumChannels); - for (unsigned int n = 0; n < anim->mNumChannels;++n) { - aiNodeAnim* nd = anim->mChannels[n]; - - // node anim header - ConvertName(name,nd->mNodeName); - ioprintf(io,"\t\t\t\n",name.data); - - if (!shortened) { - // write position keys - if (nd->mNumPositionKeys) { - ioprintf(io,"\t\t\t\t\n",nd->mNumPositionKeys); - for (unsigned int a = 0; a < nd->mNumPositionKeys;++a) { - aiVectorKey* vc = nd->mPositionKeys+a; - ioprintf(io,"\t\t\t\t\t\n" - "\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t\n", - vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z); - } - ioprintf(io,"\t\t\t\t\n"); - } - - // write scaling keys - if (nd->mNumScalingKeys) { - ioprintf(io,"\t\t\t\t\n",nd->mNumScalingKeys); - for (unsigned int a = 0; a < nd->mNumScalingKeys;++a) { - aiVectorKey* vc = nd->mScalingKeys+a; - ioprintf(io,"\t\t\t\t\t\n" - "\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t\n", - vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z); - } - ioprintf(io,"\t\t\t\t\n"); - } - - // write rotation keys - if (nd->mNumRotationKeys) { - ioprintf(io,"\t\t\t\t\n",nd->mNumRotationKeys); - for (unsigned int a = 0; a < nd->mNumRotationKeys;++a) { - aiQuatKey* vc = nd->mRotationKeys+a; - ioprintf(io,"\t\t\t\t\t\n" - "\t\t\t\t\t\t%0 8f %0 8f %0 8f %0 8f\n\t\t\t\t\t\n", - vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z,vc->mValue.w); - } - ioprintf(io,"\t\t\t\t\n"); - } - } - ioprintf(io,"\t\t\t\n"); - } - ioprintf(io,"\t\t\n"); - } - ioprintf(io,"\t\n"); - } - ioprintf(io,"\n"); - } - - // write meshes - if (scene->mNumMeshes) { - ioprintf(io,"\n",scene->mNumMeshes); - for (unsigned int i = 0; i < scene->mNumMeshes;++i) { - aiMesh* mesh = scene->mMeshes[i]; - // const unsigned int width = (unsigned int)std::log10((double)mesh->mNumVertices)+1; - - // mesh header - ioprintf(io,"\t\n", - (mesh->mPrimitiveTypes & aiPrimitiveType_POINT ? "points" : ""), - (mesh->mPrimitiveTypes & aiPrimitiveType_LINE ? "lines" : ""), - (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE ? "triangles" : ""), - (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON ? "polygons" : ""), - mesh->mMaterialIndex); - - // bones - if (mesh->mNumBones) { - ioprintf(io,"\t\t\n",mesh->mNumBones); - - for (unsigned int n = 0; n < mesh->mNumBones;++n) { - aiBone* bone = mesh->mBones[n]; - - ConvertName(name,bone->mName); - // bone header - ioprintf(io,"\t\t\t\n" - "\t\t\t\t \n" - "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" - "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" - "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" - "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" - "\t\t\t\t \n", - name.data, - bone->mOffsetMatrix.a1,bone->mOffsetMatrix.a2,bone->mOffsetMatrix.a3,bone->mOffsetMatrix.a4, - bone->mOffsetMatrix.b1,bone->mOffsetMatrix.b2,bone->mOffsetMatrix.b3,bone->mOffsetMatrix.b4, - bone->mOffsetMatrix.c1,bone->mOffsetMatrix.c2,bone->mOffsetMatrix.c3,bone->mOffsetMatrix.c4, - bone->mOffsetMatrix.d1,bone->mOffsetMatrix.d2,bone->mOffsetMatrix.d3,bone->mOffsetMatrix.d4); - - if (!shortened && bone->mNumWeights) { - ioprintf(io,"\t\t\t\t\n",bone->mNumWeights); - - // bone weights - for (unsigned int a = 0; a < bone->mNumWeights;++a) { - aiVertexWeight* wght = bone->mWeights+a; - - ioprintf(io,"\t\t\t\t\t\n\t\t\t\t\t\t%f\n\t\t\t\t\t\n", - wght->mVertexId,wght->mWeight); - } - ioprintf(io,"\t\t\t\t\n"); - } - ioprintf(io,"\t\t\t\n"); - } - ioprintf(io,"\t\t\n"); - } - - // faces - if (!shortened && mesh->mNumFaces) { - ioprintf(io,"\t\t\n",mesh->mNumFaces); - for (unsigned int n = 0; n < mesh->mNumFaces; ++n) { - aiFace& f = mesh->mFaces[n]; - ioprintf(io,"\t\t\t\n" - "\t\t\t\t",f.mNumIndices); - - for (unsigned int j = 0; j < f.mNumIndices;++j) - ioprintf(io,"%i ",f.mIndices[j]); - - ioprintf(io,"\n\t\t\t\n"); - } - ioprintf(io,"\t\t\n"); - } - - // vertex positions - if (mesh->HasPositions()) { - ioprintf(io,"\t\t \n",mesh->mNumVertices); - if (!shortened) { - for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { - ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", - mesh->mVertices[n].x, - mesh->mVertices[n].y, - mesh->mVertices[n].z); - } - } - ioprintf(io,"\t\t\n"); - } - - // vertex normals - if (mesh->HasNormals()) { - ioprintf(io,"\t\t \n",mesh->mNumVertices); - if (!shortened) { - for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { - ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", - mesh->mNormals[n].x, - mesh->mNormals[n].y, - mesh->mNormals[n].z); - } - } - ioprintf(io,"\t\t\n"); - } - - // vertex tangents and bitangents - if (mesh->HasTangentsAndBitangents()) { - ioprintf(io,"\t\t \n",mesh->mNumVertices); - if (!shortened) { - for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { - ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", - mesh->mTangents[n].x, - mesh->mTangents[n].y, - mesh->mTangents[n].z); - } - } - ioprintf(io,"\t\t\n"); - - ioprintf(io,"\t\t \n",mesh->mNumVertices); - if (!shortened) { - for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { - ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", - mesh->mBitangents[n].x, - mesh->mBitangents[n].y, - mesh->mBitangents[n].z); - } - } - ioprintf(io,"\t\t\n"); - } - - // texture coordinates - for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { - if (!mesh->mTextureCoords[a]) - break; - - ioprintf(io,"\t\t \n",mesh->mNumVertices, - a,mesh->mNumUVComponents[a]); - - if (!shortened) { - if (mesh->mNumUVComponents[a] == 3) { - for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { - ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", - mesh->mTextureCoords[a][n].x, - mesh->mTextureCoords[a][n].y, - mesh->mTextureCoords[a][n].z); - } - } - else { - for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { - ioprintf(io,"\t\t%0 8f %0 8f\n", - mesh->mTextureCoords[a][n].x, - mesh->mTextureCoords[a][n].y); - } - } - } - ioprintf(io,"\t\t\n"); - } - - // vertex colors - for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) { - if (!mesh->mColors[a]) - break; - ioprintf(io,"\t\t \n",mesh->mNumVertices,a); - if (!shortened) { - for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { - ioprintf(io,"\t\t%0 8f %0 8f %0 8f %0 8f\n", - mesh->mColors[a][n].r, - mesh->mColors[a][n].g, - mesh->mColors[a][n].b, - mesh->mColors[a][n].a); - } - } - ioprintf(io,"\t\t\n"); - } - ioprintf(io,"\t\n"); - } - ioprintf(io,"\n"); - } - ioprintf(io,"\n"); -} - -} // end of namespace AssxmlExport - void ExportSceneAssxml(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) { - IOStream * out = pIOSystem->Open( pFile, "wt" ); - if (!out) return; - - bool shortened = false; - AssxmlExport::WriteDump( pScene, out, shortened ); - - pIOSystem->Close( out ); + DumpSceneToAssxml( + pFile, + "\0", // command(s) + pIOSystem, + pScene, + false); // shortened? } } // end of namespace Assimp diff --git a/Engine/lib/assimp/code/Assxml/AssxmlExporter.h b/Engine/lib/assimp/code/Assxml/AssxmlExporter.h index 8ca887eea..a2b40ada1 100644 --- a/Engine/lib/assimp/code/Assxml/AssxmlExporter.h +++ b/Engine/lib/assimp/code/Assxml/AssxmlExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Assxml/AssxmlFileWriter.cpp b/Engine/lib/assimp/code/Assxml/AssxmlFileWriter.cpp new file mode 100644 index 000000000..0ed59e509 --- /dev/null +++ b/Engine/lib/assimp/code/Assxml/AssxmlFileWriter.cpp @@ -0,0 +1,664 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +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. + +---------------------------------------------------------------------- +*/ + +/** @file AssxmlFileWriter.cpp + * @brief Implementation of Assxml file writer. + */ + +#include "AssxmlFileWriter.h" + +#include "PostProcessing/ProcessHelper.h" + +#include +#include +#include +#include + +#include + +#ifdef ASSIMP_BUILD_NO_OWN_ZLIB +# include +#else +# include +#endif + +#include +#include +#include + +using namespace Assimp; + +namespace Assimp { + +namespace AssxmlFileWriter { + +// ----------------------------------------------------------------------------------- +static int ioprintf( IOStream * io, const char *format, ... ) { + using namespace std; + if ( nullptr == io ) { + return -1; + } + + static const int Size = 4096; + char sz[ Size ]; + ::memset( sz, '\0', Size ); + va_list va; + va_start( va, format ); + const unsigned int nSize = vsnprintf( sz, Size-1, format, va ); + ai_assert( nSize < Size ); + va_end( va ); + + io->Write( sz, sizeof(char), nSize ); + + return nSize; +} + +// ----------------------------------------------------------------------------------- +// Convert a name to standard XML format +static void ConvertName(aiString& out, const aiString& in) { + out.length = 0; + for (unsigned int i = 0; i < in.length; ++i) { + switch (in.data[i]) { + case '<': + out.Append("<");break; + case '>': + out.Append(">");break; + case '&': + out.Append("&");break; + case '\"': + out.Append(""");break; + case '\'': + out.Append("'");break; + default: + out.data[out.length++] = in.data[i]; + } + } + out.data[out.length] = 0; +} + +// ----------------------------------------------------------------------------------- +// Write a single node as text dump +static void WriteNode(const aiNode* node, IOStream * io, unsigned int depth) { + char prefix[512]; + for (unsigned int i = 0; i < depth;++i) + prefix[i] = '\t'; + prefix[depth] = '\0'; + + const aiMatrix4x4& m = node->mTransformation; + + aiString name; + ConvertName(name,node->mName); + ioprintf(io,"%s \n" + "%s\t \n" + "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" + "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" + "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" + "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" + "%s\t \n", + prefix,name.data,prefix, + prefix,m.a1,m.a2,m.a3,m.a4, + prefix,m.b1,m.b2,m.b3,m.b4, + prefix,m.c1,m.c2,m.c3,m.c4, + prefix,m.d1,m.d2,m.d3,m.d4,prefix); + + if (node->mNumMeshes) { + ioprintf(io, "%s\t\n%s\t", + prefix,node->mNumMeshes,prefix); + + for (unsigned int i = 0; i < node->mNumMeshes;++i) { + ioprintf(io,"%u ",node->mMeshes[i]); + } + ioprintf(io,"\n%s\t\n",prefix); + } + + if (node->mNumChildren) { + ioprintf(io,"%s\t\n", + prefix,node->mNumChildren); + + for (unsigned int i = 0; i < node->mNumChildren;++i) { + WriteNode(node->mChildren[i],io,depth+2); + } + ioprintf(io,"%s\t\n",prefix); + } + ioprintf(io,"%s\n",prefix); +} + + +// ----------------------------------------------------------------------------------- +// Some chuncks of text will need to be encoded for XML +// http://stackoverflow.com/questions/5665231/most-efficient-way-to-escape-xml-html-in-c-string#5665377 +static std::string encodeXML(const std::string& data) { + std::string buffer; + buffer.reserve(data.size()); + for(size_t pos = 0; pos != data.size(); ++pos) { + switch(data[pos]) { + case '&': buffer.append("&"); break; + case '\"': buffer.append("""); break; + case '\'': buffer.append("'"); break; + case '<': buffer.append("<"); break; + case '>': buffer.append(">"); break; + default: buffer.append(&data[pos], 1); break; + } + } + return buffer; +} + +// ----------------------------------------------------------------------------------- +// Write a text model dump +static +void WriteDump(const char* pFile, const char* cmd, const aiScene* scene, IOStream* io, bool shortened) { + time_t tt = ::time( NULL ); +#if _WIN32 + tm* p = gmtime(&tt); +#else + struct tm now; + tm* p = gmtime_r(&tt, &now); +#endif + ai_assert(nullptr != p); + + std::string c = cmd; + std::string::size_type s; + + // https://sourceforge.net/tracker/?func=detail&aid=3167364&group_id=226462&atid=1067632 + // -- not allowed in XML comments + while((s = c.find("--")) != std::string::npos) { + c[s] = '?'; + } + + // write header + std::string header( + "\n" + "\n\n" + "" + " \n\n" + "\n" + ); + + const unsigned int majorVersion( aiGetVersionMajor() ); + const unsigned int minorVersion( aiGetVersionMinor() ); + const unsigned int rev( aiGetVersionRevision() ); + const char *curtime( asctime( p ) ); + ioprintf( io, header.c_str(), majorVersion, minorVersion, rev, pFile, c.c_str(), curtime, scene->mFlags, 0u ); + + // write the node graph + WriteNode(scene->mRootNode, io, 0); + +#if 0 + // write cameras + for (unsigned int i = 0; i < scene->mNumCameras;++i) { + aiCamera* cam = scene->mCameras[i]; + ConvertName(name,cam->mName); + + // camera header + ioprintf(io,"\t\n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %f \n" + "\t\t %f \n" + "\t\t %f \n" + "\t\t %f \n" + "\t\n", + name.data, + cam->mUp.x,cam->mUp.y,cam->mUp.z, + cam->mLookAt.x,cam->mLookAt.y,cam->mLookAt.z, + cam->mPosition.x,cam->mPosition.y,cam->mPosition.z, + cam->mHorizontalFOV,cam->mAspect,cam->mClipPlaneNear,cam->mClipPlaneFar,i); + } + + // write lights + for (unsigned int i = 0; i < scene->mNumLights;++i) { + aiLight* l = scene->mLights[i]; + ConvertName(name,l->mName); + + // light header + ioprintf(io,"\t type=\"%s\"\n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %0 8f %0 8f %0 8f \n", + name.data, + (l->mType == aiLightSource_DIRECTIONAL ? "directional" : + (l->mType == aiLightSource_POINT ? "point" : "spot" )), + l->mColorDiffuse.r, l->mColorDiffuse.g, l->mColorDiffuse.b, + l->mColorSpecular.r,l->mColorSpecular.g,l->mColorSpecular.b, + l->mColorAmbient.r, l->mColorAmbient.g, l->mColorAmbient.b); + + if (l->mType != aiLightSource_DIRECTIONAL) { + ioprintf(io, + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %f \n" + "\t\t %f \n" + "\t\t %f \n", + l->mPosition.x,l->mPosition.y,l->mPosition.z, + l->mAttenuationConstant,l->mAttenuationLinear,l->mAttenuationQuadratic); + } + + if (l->mType != aiLightSource_POINT) { + ioprintf(io, + "\t\t %0 8f %0 8f %0 8f \n", + l->mDirection.x,l->mDirection.y,l->mDirection.z); + } + + if (l->mType == aiLightSource_SPOT) { + ioprintf(io, + "\t\t %f \n" + "\t\t %f \n", + l->mAngleOuterCone,l->mAngleInnerCone); + } + ioprintf(io,"\t\n"); + } +#endif + aiString name; + + // write textures + if (scene->mNumTextures) { + ioprintf(io,"\n",scene->mNumTextures); + for (unsigned int i = 0; i < scene->mNumTextures;++i) { + aiTexture* tex = scene->mTextures[i]; + bool compressed = (tex->mHeight == 0); + + // mesh header + ioprintf(io,"\t \n", + (compressed ? -1 : tex->mWidth),(compressed ? -1 : tex->mHeight), + (compressed ? "true" : "false")); + + if (compressed) { + ioprintf(io,"\t\t \n",tex->mWidth); + + if (!shortened) { + for (unsigned int n = 0; n < tex->mWidth;++n) { + ioprintf(io,"\t\t\t%2x",reinterpret_cast(tex->pcData)[n]); + if (n && !(n % 50)) { + ioprintf(io,"\n"); + } + } + } + } + else if (!shortened){ + ioprintf(io,"\t\t \n",tex->mWidth*tex->mHeight*4); + + // const unsigned int width = (unsigned int)std::log10((double)std::max(tex->mHeight,tex->mWidth))+1; + for (unsigned int y = 0; y < tex->mHeight;++y) { + for (unsigned int x = 0; x < tex->mWidth;++x) { + aiTexel* tx = tex->pcData + y*tex->mWidth+x; + unsigned int r = tx->r,g=tx->g,b=tx->b,a=tx->a; + ioprintf(io,"\t\t\t%2x %2x %2x %2x",r,g,b,a); + + // group by four for readability + if ( 0 == ( x + y*tex->mWidth ) % 4 ) { + ioprintf( io, "\n" ); + } + } + } + } + ioprintf(io,"\t\t\n\t\n"); + } + ioprintf(io,"\n"); + } + + // write materials + if (scene->mNumMaterials) { + ioprintf(io,"\n",scene->mNumMaterials); + for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { + const aiMaterial* mat = scene->mMaterials[i]; + + ioprintf(io,"\t\n"); + ioprintf(io,"\t\t\n",mat->mNumProperties); + for (unsigned int n = 0; n < mat->mNumProperties;++n) { + + const aiMaterialProperty* prop = mat->mProperties[n]; + const char* sz = ""; + if (prop->mType == aiPTI_Float) { + sz = "float"; + } + else if (prop->mType == aiPTI_Integer) { + sz = "integer"; + } + else if (prop->mType == aiPTI_String) { + sz = "string"; + } + else if (prop->mType == aiPTI_Buffer) { + sz = "binary_buffer"; + } + + ioprintf(io,"\t\t\tmKey.data, sz, + ::TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex); + + if (prop->mType == aiPTI_Float) { + ioprintf(io," size=\"%i\">\n\t\t\t\t", + static_cast(prop->mDataLength/sizeof(float))); + + for (unsigned int p = 0; p < prop->mDataLength/sizeof(float);++p) { + ioprintf(io,"%f ",*((float*)(prop->mData+p*sizeof(float)))); + } + } + else if (prop->mType == aiPTI_Integer) { + ioprintf(io," size=\"%i\">\n\t\t\t\t", + static_cast(prop->mDataLength/sizeof(int))); + + for (unsigned int p = 0; p < prop->mDataLength/sizeof(int);++p) { + ioprintf(io,"%i ",*((int*)(prop->mData+p*sizeof(int)))); + } + } + else if (prop->mType == aiPTI_Buffer) { + ioprintf(io," size=\"%i\">\n\t\t\t\t", + static_cast(prop->mDataLength)); + + for (unsigned int p = 0; p < prop->mDataLength;++p) { + ioprintf(io,"%2x ",prop->mData[p]); + if (p && 0 == p%30) { + ioprintf(io,"\n\t\t\t\t"); + } + } + } + else if (prop->mType == aiPTI_String) { + ioprintf(io,">\n\t\t\t\t\"%s\"",encodeXML(prop->mData+4).c_str() /* skip length */); + } + ioprintf(io,"\n\t\t\t\n"); + } + ioprintf(io,"\t\t\n"); + ioprintf(io,"\t\n"); + } + ioprintf(io,"\n"); + } + + // write animations + if (scene->mNumAnimations) { + ioprintf(io,"\n",scene->mNumAnimations); + for (unsigned int i = 0; i < scene->mNumAnimations;++i) { + aiAnimation* anim = scene->mAnimations[i]; + + // anim header + ConvertName(name,anim->mName); + ioprintf(io,"\t\n", + name.data, anim->mDuration, anim->mTicksPerSecond); + + // write bone animation channels + if (anim->mNumChannels) { + ioprintf(io,"\t\t\n",anim->mNumChannels); + for (unsigned int n = 0; n < anim->mNumChannels;++n) { + aiNodeAnim* nd = anim->mChannels[n]; + + // node anim header + ConvertName(name,nd->mNodeName); + ioprintf(io,"\t\t\t\n",name.data); + + if (!shortened) { + // write position keys + if (nd->mNumPositionKeys) { + ioprintf(io,"\t\t\t\t\n",nd->mNumPositionKeys); + for (unsigned int a = 0; a < nd->mNumPositionKeys;++a) { + aiVectorKey* vc = nd->mPositionKeys+a; + ioprintf(io,"\t\t\t\t\t\n" + "\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t\n", + vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z); + } + ioprintf(io,"\t\t\t\t\n"); + } + + // write scaling keys + if (nd->mNumScalingKeys) { + ioprintf(io,"\t\t\t\t\n",nd->mNumScalingKeys); + for (unsigned int a = 0; a < nd->mNumScalingKeys;++a) { + aiVectorKey* vc = nd->mScalingKeys+a; + ioprintf(io,"\t\t\t\t\t\n" + "\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t\n", + vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z); + } + ioprintf(io,"\t\t\t\t\n"); + } + + // write rotation keys + if (nd->mNumRotationKeys) { + ioprintf(io,"\t\t\t\t\n",nd->mNumRotationKeys); + for (unsigned int a = 0; a < nd->mNumRotationKeys;++a) { + aiQuatKey* vc = nd->mRotationKeys+a; + ioprintf(io,"\t\t\t\t\t\n" + "\t\t\t\t\t\t%0 8f %0 8f %0 8f %0 8f\n\t\t\t\t\t\n", + vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z,vc->mValue.w); + } + ioprintf(io,"\t\t\t\t\n"); + } + } + ioprintf(io,"\t\t\t\n"); + } + ioprintf(io,"\t\t\n"); + } + ioprintf(io,"\t\n"); + } + ioprintf(io,"\n"); + } + + // write meshes + if (scene->mNumMeshes) { + ioprintf(io,"\n",scene->mNumMeshes); + for (unsigned int i = 0; i < scene->mNumMeshes;++i) { + aiMesh* mesh = scene->mMeshes[i]; + // const unsigned int width = (unsigned int)std::log10((double)mesh->mNumVertices)+1; + + // mesh header + ioprintf(io,"\t\n", + (mesh->mPrimitiveTypes & aiPrimitiveType_POINT ? "points" : ""), + (mesh->mPrimitiveTypes & aiPrimitiveType_LINE ? "lines" : ""), + (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE ? "triangles" : ""), + (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON ? "polygons" : ""), + mesh->mMaterialIndex); + + // bones + if (mesh->mNumBones) { + ioprintf(io,"\t\t\n",mesh->mNumBones); + + for (unsigned int n = 0; n < mesh->mNumBones;++n) { + aiBone* bone = mesh->mBones[n]; + + ConvertName(name,bone->mName); + // bone header + ioprintf(io,"\t\t\t\n" + "\t\t\t\t \n" + "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t \n", + name.data, + bone->mOffsetMatrix.a1,bone->mOffsetMatrix.a2,bone->mOffsetMatrix.a3,bone->mOffsetMatrix.a4, + bone->mOffsetMatrix.b1,bone->mOffsetMatrix.b2,bone->mOffsetMatrix.b3,bone->mOffsetMatrix.b4, + bone->mOffsetMatrix.c1,bone->mOffsetMatrix.c2,bone->mOffsetMatrix.c3,bone->mOffsetMatrix.c4, + bone->mOffsetMatrix.d1,bone->mOffsetMatrix.d2,bone->mOffsetMatrix.d3,bone->mOffsetMatrix.d4); + + if (!shortened && bone->mNumWeights) { + ioprintf(io,"\t\t\t\t\n",bone->mNumWeights); + + // bone weights + for (unsigned int a = 0; a < bone->mNumWeights;++a) { + aiVertexWeight* wght = bone->mWeights+a; + + ioprintf(io,"\t\t\t\t\t\n\t\t\t\t\t\t%f\n\t\t\t\t\t\n", + wght->mVertexId,wght->mWeight); + } + ioprintf(io,"\t\t\t\t\n"); + } + ioprintf(io,"\t\t\t\n"); + } + ioprintf(io,"\t\t\n"); + } + + // faces + if (!shortened && mesh->mNumFaces) { + ioprintf(io,"\t\t\n",mesh->mNumFaces); + for (unsigned int n = 0; n < mesh->mNumFaces; ++n) { + aiFace& f = mesh->mFaces[n]; + ioprintf(io,"\t\t\t\n" + "\t\t\t\t",f.mNumIndices); + + for (unsigned int j = 0; j < f.mNumIndices;++j) + ioprintf(io,"%u ",f.mIndices[j]); + + ioprintf(io,"\n\t\t\t\n"); + } + ioprintf(io,"\t\t\n"); + } + + // vertex positions + if (mesh->HasPositions()) { + ioprintf(io,"\t\t \n",mesh->mNumVertices); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mVertices[n].x, + mesh->mVertices[n].y, + mesh->mVertices[n].z); + } + } + ioprintf(io,"\t\t\n"); + } + + // vertex normals + if (mesh->HasNormals()) { + ioprintf(io,"\t\t \n",mesh->mNumVertices); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mNormals[n].x, + mesh->mNormals[n].y, + mesh->mNormals[n].z); + } + } + ioprintf(io,"\t\t\n"); + } + + // vertex tangents and bitangents + if (mesh->HasTangentsAndBitangents()) { + ioprintf(io,"\t\t \n",mesh->mNumVertices); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mTangents[n].x, + mesh->mTangents[n].y, + mesh->mTangents[n].z); + } + } + ioprintf(io,"\t\t\n"); + + ioprintf(io,"\t\t \n",mesh->mNumVertices); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mBitangents[n].x, + mesh->mBitangents[n].y, + mesh->mBitangents[n].z); + } + } + ioprintf(io,"\t\t\n"); + } + + // texture coordinates + for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { + if (!mesh->mTextureCoords[a]) + break; + + ioprintf(io,"\t\t \n",mesh->mNumVertices, + a,mesh->mNumUVComponents[a]); + + if (!shortened) { + if (mesh->mNumUVComponents[a] == 3) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mTextureCoords[a][n].x, + mesh->mTextureCoords[a][n].y, + mesh->mTextureCoords[a][n].z); + } + } + else { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io,"\t\t%0 8f %0 8f\n", + mesh->mTextureCoords[a][n].x, + mesh->mTextureCoords[a][n].y); + } + } + } + ioprintf(io,"\t\t\n"); + } + + // vertex colors + for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) { + if (!mesh->mColors[a]) + break; + ioprintf(io,"\t\t \n",mesh->mNumVertices,a); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io,"\t\t%0 8f %0 8f %0 8f %0 8f\n", + mesh->mColors[a][n].r, + mesh->mColors[a][n].g, + mesh->mColors[a][n].b, + mesh->mColors[a][n].a); + } + } + ioprintf(io,"\t\t\n"); + } + ioprintf(io,"\t\n"); + } + ioprintf(io,"\n"); + } + ioprintf(io,"\n"); +} + +} // end of namespace AssxmlFileWriter + +void DumpSceneToAssxml( + const char* pFile, const char* cmd, IOSystem* pIOSystem, + const aiScene* pScene, bool shortened) { + std::unique_ptr file(pIOSystem->Open(pFile, "wt")); + if (!file.get()) { + throw std::runtime_error("Unable to open output file " + std::string(pFile) + '\n'); + } + + AssxmlFileWriter::WriteDump(pFile, cmd, pScene, file.get(), shortened); +} + +} // end of namespace Assimp diff --git a/Engine/lib/assimp/code/Assxml/AssxmlFileWriter.h b/Engine/lib/assimp/code/Assxml/AssxmlFileWriter.h new file mode 100644 index 000000000..c10a8a5aa --- /dev/null +++ b/Engine/lib/assimp/code/Assxml/AssxmlFileWriter.h @@ -0,0 +1,65 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +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. + +---------------------------------------------------------------------- +*/ + +/** @file AssxmlFileWriter.h + * @brief Declaration of Assxml file writer. + */ + +#ifndef AI_ASSXMLFILEWRITER_H_INC +#define AI_ASSXMLFILEWRITER_H_INC + +#include +#include +#include + +namespace Assimp { + +void ASSIMP_API DumpSceneToAssxml( + const char* pFile, + const char* cmd, + IOSystem* pIOSystem, + const aiScene* pScene, + bool shortened); + +} + +#endif // AI_ASSXMLFILEWRITER_H_INC diff --git a/Engine/lib/assimp/code/B3D/B3DImporter.cpp b/Engine/lib/assimp/code/B3D/B3DImporter.cpp index ba484ca00..07336df65 100644 --- a/Engine/lib/assimp/code/B3D/B3DImporter.cpp +++ b/Engine/lib/assimp/code/B3D/B3DImporter.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team - - +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -78,7 +76,6 @@ static const aiImporterDesc desc = { "b3d" }; -// (fixme, Aramis) quick workaround to get rid of all those signed to unsigned warnings #ifdef _MSC_VER # pragma warning (disable: 4018) #endif @@ -86,10 +83,8 @@ static const aiImporterDesc desc = { //#define DEBUG_B3D template -void DeleteAllBarePointers(std::vector& x) -{ - for(auto p : x) - { +void DeleteAllBarePointers(std::vector& x) { + for(auto p : x) { delete p; } } @@ -102,10 +97,14 @@ B3DImporter::~B3DImporter() bool B3DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const{ size_t pos=pFile.find_last_of( '.' ); - if( pos==string::npos ) return false; + if( pos==string::npos ) { + return false; + } string ext=pFile.substr( pos+1 ); - if( ext.size()!=3 ) return false; + if( ext.size()!=3 ) { + return false; + } return (ext[0]=='b' || ext[0]=='B') && (ext[1]=='3') && (ext[2]=='d' || ext[2]=='D'); } @@ -117,30 +116,21 @@ const aiImporterDesc* B3DImporter::GetInfo () const return &desc; } -#ifdef DEBUG_B3D - extern "C"{ void _stdcall AllocConsole(); } -#endif // ------------------------------------------------------------------------------------------------ void B3DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler){ - -#ifdef DEBUG_B3D - AllocConsole(); - freopen( "conin$","r",stdin ); - freopen( "conout$","w",stdout ); - freopen( "conout$","w",stderr ); - cout<<"Hello world from the B3DImporter!"< file( pIOHandler->Open( pFile)); // Check whether we can read from the file - if( file.get() == NULL) + if( file.get() == nullptr) { throw DeadlyImportError( "Failed to open B3D file " + pFile + "."); + } // check whether the .b3d file is large enough to contain // at least one chunk. size_t fileSize = file->FileSize(); - if( fileSize<8 ) throw DeadlyImportError( "B3D File is too small."); + if( fileSize<8 ) { + throw DeadlyImportError( "B3D File is too small."); + } _pos=0; _buf.resize( fileSize ); @@ -158,14 +148,17 @@ AI_WONT_RETURN void B3DImporter::Oops(){ // ------------------------------------------------------------------------------------------------ AI_WONT_RETURN void B3DImporter::Fail( string str ){ #ifdef DEBUG_B3D - cout<<"Error in B3D file data: "< &v ){ return p; } - // ------------------------------------------------------------------------------------------------ template T **unique_to_array( vector > &v ){ @@ -283,7 +277,6 @@ T **unique_to_array( vector > &v ){ return p; } - // ------------------------------------------------------------------------------------------------ void B3DImporter::ReadTEXS(){ while( ChunkSize() ){ @@ -376,9 +369,13 @@ void B3DImporter::ReadVRTS(){ v.vertex=ReadVec3(); - if( _vflags & 1 ) v.normal=ReadVec3(); + if( _vflags & 1 ) { + v.normal=ReadVec3(); + } - if( _vflags & 2 ) ReadQuat(); //skip v 4bytes... + if( _vflags & 2 ) { + ReadQuat(); //skip v 4bytes... + } for( int i=0;i<_tcsets;++i ){ float t[4]={0,0,0,0}; @@ -386,53 +383,55 @@ void B3DImporter::ReadVRTS(){ t[j]=ReadFloat(); } t[1]=1-t[1]; - if( !i ) v.texcoords=aiVector3D( t[0],t[1],t[2] ); + if( !i ) { + v.texcoords=aiVector3D( t[0],t[1],t[2] ); + } } } } // ------------------------------------------------------------------------------------------------ -void B3DImporter::ReadTRIS( int v0 ){ - int matid=ReadInt(); - if( matid==-1 ){ - matid=0; - }else if( matid<0 || matid>=(int)_materials.size() ){ +void B3DImporter::ReadTRIS(int v0) { + int matid = ReadInt(); + if (matid == -1) { + matid = 0; + } else if (matid < 0 || matid >= (int)_materials.size()) { #ifdef DEBUG_B3D - cout<<"material id="< mesh(new aiMesh); + std::unique_ptr mesh(new aiMesh); - mesh->mMaterialIndex=matid; - mesh->mNumFaces=0; - mesh->mPrimitiveTypes=aiPrimitiveType_TRIANGLE; + mesh->mMaterialIndex = matid; + mesh->mNumFaces = 0; + mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; - int n_tris=ChunkSize()/12; - aiFace *face=mesh->mFaces=new aiFace[n_tris]; + int n_tris = ChunkSize() / 12; + aiFace *face = mesh->mFaces = new aiFace[n_tris]; - for( int i=0;i=(int)_vertices.size() || i1<0 || i1>=(int)_vertices.size() || i2<0 || i2>=(int)_vertices.size() ){ + for (int i = 0; i < n_tris; ++i) { + int i0 = ReadInt() + v0; + int i1 = ReadInt() + v0; + int i2 = ReadInt() + v0; + if (i0 < 0 || i0 >= (int)_vertices.size() || i1 < 0 || i1 >= (int)_vertices.size() || i2 < 0 || i2 >= (int)_vertices.size()) { #ifdef DEBUG_B3D - cout<<"Bad triangle index: i0="<mNumIndices=3; - face->mIndices=new unsigned[3]; - face->mIndices[0]=i0; - face->mIndices[1]=i1; - face->mIndices[2]=i2; - ++mesh->mNumFaces; - ++face; - } + Fail("Bad triangle index"); + continue; + } + face->mNumIndices = 3; + face->mIndices = new unsigned[3]; + face->mIndices[0] = i0; + face->mIndices[1] = i1; + face->mIndices[2] = i2; + ++mesh->mNumFaces; + ++face; + } - _meshes.emplace_back( std::move(mesh) ); + _meshes.emplace_back(std::move(mesh)); } // ------------------------------------------------------------------------------------------------ @@ -453,29 +452,23 @@ void B3DImporter::ReadMESH(){ } // ------------------------------------------------------------------------------------------------ -void B3DImporter::ReadBONE( int id ){ - while( ChunkSize() ){ - int vertex=ReadInt(); - float weight=ReadFloat(); - if( vertex<0 || vertex>=(int)_vertices.size() ){ - Fail( "Bad vertex index" ); - } +void B3DImporter::ReadBONE(int id) { + while (ChunkSize()) { + int vertex = ReadInt(); + float weight = ReadFloat(); + if (vertex < 0 || vertex >= (int)_vertices.size()) { + Fail("Bad vertex index"); + } - Vertex &v=_vertices[vertex]; - int i; - for( i=0;i<4;++i ){ - if( !v.weights[i] ){ - v.bones[i]=id; - v.weights[i]=weight; - break; - } - } -#ifdef DEBUG_B3D - if( i==4 ){ - cout<<"Too many bone weights"<mNumVertices=n_tris * 3; aiVector3D *mv=mesh->mVertices=new aiVector3D[ n_verts ],*mn=0,*mc=0; - if( _vflags & 1 ) mn=mesh->mNormals=new aiVector3D[ n_verts ]; - if( _tcsets ) mc=mesh->mTextureCoords[0]=new aiVector3D[ n_verts ]; + if( _vflags & 1 ) { + mn=mesh->mNormals=new aiVector3D[ n_verts ]; + } + if( _tcsets ) { + mc=mesh->mTextureCoords[0]=new aiVector3D[ n_verts ]; + } aiFace *face=mesh->mFaces; diff --git a/Engine/lib/assimp/code/B3D/B3DImporter.h b/Engine/lib/assimp/code/B3D/B3DImporter.h index d52dac34a..f0568dd16 100644 --- a/Engine/lib/assimp/code/B3D/B3DImporter.h +++ b/Engine/lib/assimp/code/B3D/B3DImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/BVH/BVHLoader.cpp b/Engine/lib/assimp/code/BVH/BVHLoader.cpp index cd9ab0843..1110754c2 100644 --- a/Engine/lib/assimp/code/BVH/BVHLoader.cpp +++ b/Engine/lib/assimp/code/BVH/BVHLoader.cpp @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/BVH/BVHLoader.h b/Engine/lib/assimp/code/BVH/BVHLoader.h index 33b4e2453..93a3e5e83 100644 --- a/Engine/lib/assimp/code/BVH/BVHLoader.h +++ b/Engine/lib/assimp/code/BVH/BVHLoader.h @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Blender/BlenderBMesh.cpp b/Engine/lib/assimp/code/Blender/BlenderBMesh.cpp index 8a13819a6..039302e12 100644 --- a/Engine/lib/assimp/code/Blender/BlenderBMesh.cpp +++ b/Engine/lib/assimp/code/Blender/BlenderBMesh.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2013, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Blender/BlenderBMesh.h b/Engine/lib/assimp/code/Blender/BlenderBMesh.h index 5b65fb503..893128606 100644 --- a/Engine/lib/assimp/code/Blender/BlenderBMesh.h +++ b/Engine/lib/assimp/code/Blender/BlenderBMesh.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2013, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Blender/BlenderDNA.cpp b/Engine/lib/assimp/code/Blender/BlenderDNA.cpp index f274e02f9..53fb84824 100644 --- a/Engine/lib/assimp/code/Blender/BlenderDNA.cpp +++ b/Engine/lib/assimp/code/Blender/BlenderDNA.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Blender/BlenderDNA.h b/Engine/lib/assimp/code/Blender/BlenderDNA.h index 375d0c4bf..16ce960e2 100644 --- a/Engine/lib/assimp/code/Blender/BlenderDNA.h +++ b/Engine/lib/assimp/code/Blender/BlenderDNA.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Blender/BlenderDNA.inl b/Engine/lib/assimp/code/Blender/BlenderDNA.inl index 65bc1374c..fd9993008 100644 --- a/Engine/lib/assimp/code/Blender/BlenderDNA.inl +++ b/Engine/lib/assimp/code/Blender/BlenderDNA.inl @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Blender/BlenderIntermediate.h b/Engine/lib/assimp/code/Blender/BlenderIntermediate.h index 95fdf0f03..2c480b848 100644 --- a/Engine/lib/assimp/code/Blender/BlenderIntermediate.h +++ b/Engine/lib/assimp/code/Blender/BlenderIntermediate.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Blender/BlenderLoader.cpp b/Engine/lib/assimp/code/Blender/BlenderLoader.cpp index d39cb9699..93e6d1589 100644 --- a/Engine/lib/assimp/code/Blender/BlenderLoader.cpp +++ b/Engine/lib/assimp/code/Blender/BlenderLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Blender/BlenderLoader.h b/Engine/lib/assimp/code/Blender/BlenderLoader.h index d85a82842..8110ac946 100644 --- a/Engine/lib/assimp/code/Blender/BlenderLoader.h +++ b/Engine/lib/assimp/code/Blender/BlenderLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Blender/BlenderModifier.cpp b/Engine/lib/assimp/code/Blender/BlenderModifier.cpp index cc7acc929..6f8a5d7ee 100644 --- a/Engine/lib/assimp/code/Blender/BlenderModifier.cpp +++ b/Engine/lib/assimp/code/Blender/BlenderModifier.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Blender/BlenderModifier.h b/Engine/lib/assimp/code/Blender/BlenderModifier.h index c260ba1f6..ad6fad68d 100644 --- a/Engine/lib/assimp/code/Blender/BlenderModifier.h +++ b/Engine/lib/assimp/code/Blender/BlenderModifier.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Blender/BlenderScene.cpp b/Engine/lib/assimp/code/Blender/BlenderScene.cpp index 39c2793d5..1391a2833 100644 --- a/Engine/lib/assimp/code/Blender/BlenderScene.cpp +++ b/Engine/lib/assimp/code/Blender/BlenderScene.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Blender/BlenderScene.h b/Engine/lib/assimp/code/Blender/BlenderScene.h index dd3f1444c..afa168d49 100644 --- a/Engine/lib/assimp/code/Blender/BlenderScene.h +++ b/Engine/lib/assimp/code/Blender/BlenderScene.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Blender/BlenderSceneGen.h b/Engine/lib/assimp/code/Blender/BlenderSceneGen.h index ce94d0dc2..0c93d17a3 100644 --- a/Engine/lib/assimp/code/Blender/BlenderSceneGen.h +++ b/Engine/lib/assimp/code/Blender/BlenderSceneGen.h @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Blender/BlenderTessellator.cpp b/Engine/lib/assimp/code/Blender/BlenderTessellator.cpp index d98c2e865..3c1cd6ea8 100644 --- a/Engine/lib/assimp/code/Blender/BlenderTessellator.cpp +++ b/Engine/lib/assimp/code/Blender/BlenderTessellator.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Blender/BlenderTessellator.h b/Engine/lib/assimp/code/Blender/BlenderTessellator.h index 518e56c72..63ea1f828 100644 --- a/Engine/lib/assimp/code/Blender/BlenderTessellator.h +++ b/Engine/lib/assimp/code/Blender/BlenderTessellator.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/C4D/C4DImporter.cpp b/Engine/lib/assimp/code/C4D/C4DImporter.cpp index 6e5b7d39b..24fd6f622 100644 --- a/Engine/lib/assimp/code/C4D/C4DImporter.cpp +++ b/Engine/lib/assimp/code/C4D/C4DImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/C4D/C4DImporter.h b/Engine/lib/assimp/code/C4D/C4DImporter.h index f3b1351f6..f9406c3e0 100644 --- a/Engine/lib/assimp/code/C4D/C4DImporter.h +++ b/Engine/lib/assimp/code/C4D/C4DImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/CApi/AssimpCExport.cpp b/Engine/lib/assimp/code/CApi/AssimpCExport.cpp index 7557edcfc..137cc2894 100644 --- a/Engine/lib/assimp/code/CApi/AssimpCExport.cpp +++ b/Engine/lib/assimp/code/CApi/AssimpCExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/CApi/CInterfaceIOWrapper.cpp b/Engine/lib/assimp/code/CApi/CInterfaceIOWrapper.cpp index 5a3a49565..91dd07f37 100644 --- a/Engine/lib/assimp/code/CApi/CInterfaceIOWrapper.cpp +++ b/Engine/lib/assimp/code/CApi/CInterfaceIOWrapper.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/CApi/CInterfaceIOWrapper.h b/Engine/lib/assimp/code/CApi/CInterfaceIOWrapper.h index 216232030..298847494 100644 --- a/Engine/lib/assimp/code/CApi/CInterfaceIOWrapper.h +++ b/Engine/lib/assimp/code/CApi/CInterfaceIOWrapper.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/CMakeLists.txt b/Engine/lib/assimp/code/CMakeLists.txt index 827f43333..0dff5d9e4 100644 --- a/Engine/lib/assimp/code/CMakeLists.txt +++ b/Engine/lib/assimp/code/CMakeLists.txt @@ -1,7 +1,7 @@ # Open Asset Import Library (assimp) # ---------------------------------------------------------------------- # -# Copyright (c) 2006-2019, assimp team +# Copyright (c) 2006-2020, assimp team # # All rights reserved. # @@ -49,7 +49,7 @@ SET( HEADER_PATH ../include/assimp ) if(NOT ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM) message(WARNING "Requesting Android JNI I/O-System in non-Android toolchain. Resetting ASSIMP_ANDROID_JNIIOSYSTEM to OFF.") set(ASSIMP_ANDROID_JNIIOSYSTEM OFF) -endif(NOT ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM) +endif() SET( COMPILER_HEADERS ${HEADER_PATH}/Compiler/pushpack1.h @@ -66,6 +66,7 @@ SET( PUBLIC_HEADERS ${HEADER_PATH}/color4.h ${HEADER_PATH}/color4.inl ${CMAKE_CURRENT_BINARY_DIR}/../include/assimp/config.h + ${HEADER_PATH}/commonMetaData.h ${HEADER_PATH}/defs.h ${HEADER_PATH}/Defines.h ${HEADER_PATH}/cfileio.h @@ -147,7 +148,7 @@ SET( Core_SRCS IF(MSVC) list(APPEND Core_SRCS "res/assimp.rc") -ENDIF(MSVC) +ENDIF() SET( Logging_SRCS ${HEADER_PATH}/DefaultLogger.hpp @@ -184,8 +185,6 @@ SET( Common_SRCS Common/ScenePreprocessor.cpp Common/ScenePreprocessor.h Common/SkeletonMeshBuilder.cpp - Common/SplitByBoneCountProcess.cpp - Common/SplitByBoneCountProcess.h Common/StandardShapes.cpp Common/TargetAnimation.cpp Common/TargetAnimation.h @@ -197,6 +196,7 @@ SET( Common_SRCS Common/CreateAnimMesh.cpp Common/simd.h Common/simd.cpp + Common/material.cpp ) SOURCE_GROUP(Common FILES ${Common_SRCS}) @@ -220,7 +220,7 @@ IF ( ASSIMP_BUILD_NONFREE_C4D_IMPORTER ) C4D/C4DImporter.h ) SOURCE_GROUP( C4D FILES ${C4D_SRCS}) -ENDIF ( ASSIMP_BUILD_NONFREE_C4D_IMPORTER ) +ENDIF () # if this variable is set to TRUE, the user can manually disable importers by setting # ASSIMP_BUILD_XXX_IMPORTER to FALSE for each importer @@ -250,35 +250,39 @@ MACRO(ADD_ASSIMP_IMPORTER name) ENDIF() ENDMACRO() -# if this variable is set to TRUE, the user can manually disable exporters by setting -# ASSIMP_BUILD_XXX_EXPORTER to FALSE for each exporter -# if this variable is set to FALSE, the user can manually enable exporters by setting -# ASSIMP_BUILD_XXX_EXPORTER to TRUE for each exporter -OPTION(ASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT "default value of all ASSIMP_BUILD_XXX_EXPORTER values" TRUE) +if (NOT ASSIMP_NO_EXPORT) -# macro to add the CMake Option ADD_ASSIMP_IMPORTER_ which enables compile of loader -# this way selective loaders can be compiled (reduces filesize + compile time) -MACRO(ADD_ASSIMP_EXPORTER name) - IF (ASSIMP_NO_EXPORT) - set(ASSIMP_EXPORTER_ENABLED FALSE) - ELSEIF (ASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT) - set(ASSIMP_EXPORTER_ENABLED TRUE) - IF (DEFINED ASSIMP_BUILD_${name}_EXPORTER AND NOT ASSIMP_BUILD_${name}_EXPORTER) + # if this variable is set to TRUE, the user can manually disable exporters by setting + # ASSIMP_BUILD_XXX_EXPORTER to FALSE for each exporter + # if this variable is set to FALSE, the user can manually enable exporters by setting + # ASSIMP_BUILD_XXX_EXPORTER to TRUE for each exporter + OPTION(ASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT "default value of all ASSIMP_BUILD_XXX_EXPORTER values" TRUE) + + # macro to add the CMake Option ADD_ASSIMP_IMPORTER_ which enables compile of loader + # this way selective loaders can be compiled (reduces filesize + compile time) + MACRO(ADD_ASSIMP_EXPORTER name) + IF (ASSIMP_NO_EXPORT) set(ASSIMP_EXPORTER_ENABLED FALSE) + ELSEIF (ASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT) + set(ASSIMP_EXPORTER_ENABLED TRUE) + IF (DEFINED ASSIMP_BUILD_${name}_EXPORTER AND NOT ASSIMP_BUILD_${name}_EXPORTER) + set(ASSIMP_EXPORTER_ENABLED FALSE) + ENDIF () + ELSE () + set(ASSIMP_EXPORTER_ENABLED ${ASSIMP_BUILD_${name}_EXPORTER}) ENDIF () - ELSE () - set(ASSIMP_EXPORTER_ENABLED ${ASSIMP_BUILD_${name}_EXPORTER}) - ENDIF () - IF (ASSIMP_EXPORTER_ENABLED) - SET(ASSIMP_EXPORTERS_ENABLED "${ASSIMP_EXPORTERS_ENABLED} ${name}") - LIST(APPEND ASSIMP_EXPORTER_SRCS ${ARGN}) - SOURCE_GROUP(${name}_EXPORTER FILES ${ARGN}) - ELSE() - SET(ASSIMP_EXPORTERS_DISABLED "${ASSIMP_EXPORTERS_DISABLED} ${name}") - add_definitions(-DASSIMP_BUILD_NO_${name}_EXPORTER) - ENDIF() -ENDMACRO() + IF (ASSIMP_EXPORTER_ENABLED) + SET(ASSIMP_EXPORTERS_ENABLED "${ASSIMP_EXPORTERS_ENABLED} ${name}") + LIST(APPEND ASSIMP_EXPORTER_SRCS ${ARGN}) + SOURCE_GROUP(${name}_EXPORTER FILES ${ARGN}) + ELSE() + SET(ASSIMP_EXPORTERS_DISABLED "${ASSIMP_EXPORTERS_DISABLED} ${name}") + add_definitions(-DASSIMP_BUILD_NO_${name}_EXPORTER) + ENDIF() + ENDMACRO() + +endif() SET(ASSIMP_LOADER_SRCS "") SET(ASSIMP_IMPORTERS_ENABLED "") # list of enabled importers @@ -305,11 +309,6 @@ ADD_ASSIMP_IMPORTER( 3DS 3DS/3DSLoader.h ) -ADD_ASSIMP_EXPORTER( 3DS - 3DS/3DSExporter.h - 3DS/3DSExporter.cpp -) - ADD_ASSIMP_IMPORTER( AC AC/ACLoader.cpp AC/ACLoader.h @@ -327,16 +326,6 @@ ADD_ASSIMP_IMPORTER( ASSBIN Assbin/AssbinLoader.cpp ) -ADD_ASSIMP_EXPORTER( ASSBIN - Assbin/AssbinExporter.h - Assbin/AssbinExporter.cpp -) - -ADD_ASSIMP_EXPORTER( ASSXML - Assxml/AssxmlExporter.h - Assxml/AssxmlExporter.cpp -) - ADD_ASSIMP_IMPORTER( B3D B3D/B3DImporter.cpp B3D/B3DImporter.h @@ -348,6 +337,7 @@ ADD_ASSIMP_IMPORTER( BVH ) ADD_ASSIMP_IMPORTER( COLLADA + Collada/ColladaHelper.cpp Collada/ColladaHelper.h Collada/ColladaLoader.cpp Collada/ColladaLoader.h @@ -355,11 +345,6 @@ ADD_ASSIMP_IMPORTER( COLLADA Collada/ColladaParser.h ) -ADD_ASSIMP_EXPORTER( COLLADA - Collada/ColladaExporter.h - Collada/ColladaExporter.cpp -) - ADD_ASSIMP_IMPORTER( DXF DXF/DXFLoader.cpp DXF/DXFLoader.h @@ -411,14 +396,11 @@ ADD_ASSIMP_IMPORTER( M3D M3D/M3DMaterials.h M3D/M3DImporter.h M3D/M3DImporter.cpp + M3D/M3DWrapper.h + M3D/M3DWrapper.cpp M3D/m3d.h ) -ADD_ASSIMP_EXPORTER( M3D - M3D/M3DExporter.h - M3D/M3DExporter.cpp -) - ADD_ASSIMP_IMPORTER( MD2 MD2/MD2FileData.h MD2/MD2Loader.cpp @@ -452,6 +434,16 @@ ADD_ASSIMP_IMPORTER( MDL MDL/MDLLoader.cpp MDL/MDLLoader.h MDL/MDLMaterialLoader.cpp + MDL/HalfLife/HalfLifeMDLBaseHeader.h + MDL/HalfLife/HL1FileData.h + MDL/HalfLife/HL1MDLLoader.cpp + MDL/HalfLife/HL1MDLLoader.h + MDL/HalfLife/HL1ImportDefinitions.h + MDL/HalfLife/HL1ImportSettings.h + MDL/HalfLife/HL1MeshTrivert.h + MDL/HalfLife/LogFunctions.h + MDL/HalfLife/UniqueNameGenerator.cpp + MDL/HalfLife/UniqueNameGenerator.h ) SET( MaterialSystem_SRCS @@ -486,11 +478,6 @@ ADD_ASSIMP_IMPORTER( OBJ Obj/ObjTools.h ) -ADD_ASSIMP_EXPORTER( OBJ - Obj/ObjExporter.h - Obj/ObjExporter.cpp -) - ADD_ASSIMP_IMPORTER( OGRE Ogre/OgreImporter.h Ogre/OgreStructs.h @@ -510,11 +497,6 @@ ADD_ASSIMP_IMPORTER( OPENGEX OpenGEX/OpenGEXStructs.h ) -ADD_ASSIMP_EXPORTER( OPENGEX - OpenGEX/OpenGEXExporter.cpp - OpenGEX/OpenGEXExporter.h -) - ADD_ASSIMP_IMPORTER( PLY Ply/PlyLoader.cpp Ply/PlyLoader.h @@ -522,11 +504,6 @@ ADD_ASSIMP_IMPORTER( PLY Ply/PlyParser.h ) -ADD_ASSIMP_EXPORTER( PLY - Ply/PlyExporter.cpp - Ply/PlyExporter.h -) - ADD_ASSIMP_IMPORTER( MS3D MS3D/MS3DLoader.cpp MS3D/MS3DLoader.h @@ -580,7 +557,7 @@ if (ASSIMP_BUILD_IFC_IMPORTER) elseif(CMAKE_COMPILER_IS_MINGW) set_source_files_properties(Importer/IFC/IFCReaderGen1_2x3.cpp Importer/IFC/IFCReaderGen2_2x3.cpp PROPERTIES COMPILE_FLAGS "-O2 -Wa,-mbig-obj") endif() -endif (ASSIMP_BUILD_IFC_IMPORTER) +endif () ADD_ASSIMP_IMPORTER( XGL XGL/XGLLoader.cpp @@ -616,14 +593,86 @@ ADD_ASSIMP_IMPORTER( FBX FBX/FBXCommon.h ) -ADD_ASSIMP_EXPORTER( FBX - FBX/FBXExporter.h - FBX/FBXExporter.cpp - FBX/FBXExportNode.h - FBX/FBXExportNode.cpp - FBX/FBXExportProperty.h - FBX/FBXExportProperty.cpp -) +if (NOT ASSIMP_NO_EXPORT) + + ADD_ASSIMP_EXPORTER( OBJ + Obj/ObjExporter.h + Obj/ObjExporter.cpp) + + ADD_ASSIMP_EXPORTER( OPENGEX + OpenGEX/OpenGEXExporter.cpp + OpenGEX/OpenGEXExporter.h) + + ADD_ASSIMP_EXPORTER( PLY + Ply/PlyExporter.cpp + Ply/PlyExporter.h) + + ADD_ASSIMP_EXPORTER( 3DS + 3DS/3DSExporter.h + 3DS/3DSExporter.cpp) + + ADD_ASSIMP_EXPORTER( ASSBIN + Assbin/AssbinExporter.h + Assbin/AssbinExporter.cpp + Assbin/AssbinFileWriter.h + Assbin/AssbinFileWriter.cpp) + + ADD_ASSIMP_EXPORTER( ASSXML + Assxml/AssxmlExporter.h + Assxml/AssxmlExporter.cpp + Assxml/AssxmlFileWriter.h + Assxml/AssxmlFileWriter.cpp) + + ADD_ASSIMP_EXPORTER(M3D + M3D/M3DExporter.h + M3D/M3DExporter.cpp) + + ADD_ASSIMP_EXPORTER(COLLADA + Collada/ColladaExporter.h + Collada/ColladaExporter.cpp) + + ADD_ASSIMP_EXPORTER( FBX + FBX/FBXExporter.h + FBX/FBXExporter.cpp + FBX/FBXExportNode.h + FBX/FBXExportNode.cpp + FBX/FBXExportProperty.h + FBX/FBXExportProperty.cpp) + + ADD_ASSIMP_EXPORTER( STL + STL/STLExporter.h + STL/STLExporter.cpp) + + ADD_ASSIMP_EXPORTER( X + X/XFileExporter.h + X/XFileExporter.cpp) + + ADD_ASSIMP_EXPORTER( X3D + X3D/X3DExporter.cpp + X3D/X3DExporter.hpp) + + ADD_ASSIMP_EXPORTER( GLTF + glTF/glTFExporter.h + glTF/glTFExporter.cpp + glTF2/glTF2Exporter.h + glTF2/glTF2Exporter.cpp) + + ADD_ASSIMP_EXPORTER( 3MF + 3MF/D3MFExporter.h + 3MF/D3MFExporter.cpp) + + ADD_ASSIMP_EXPORTER( ASSJSON + Assjson/cencode.c + Assjson/cencode.h + Assjson/json_exporter.cpp + Assjson/mesh_splitter.cpp + Assjson/mesh_splitter.h) + + ADD_ASSIMP_EXPORTER( STEP + Step/StepExporter.h + Step/StepExporter.cpp) + +endif() SET( PostProcessing_SRCS PostProcessing/CalcTangentsProcess.cpp @@ -686,6 +735,8 @@ SET( PostProcessing_SRCS PostProcessing/ArmaturePopulate.h PostProcessing/GenBoundingBoxesProcess.cpp PostProcessing/GenBoundingBoxesProcess.h + PostProcessing/SplitByBoneCountProcess.cpp + PostProcessing/SplitByBoneCountProcess.h ) SOURCE_GROUP( PostProcessing FILES ${PostProcessing_SRCS}) @@ -725,11 +776,6 @@ ADD_ASSIMP_IMPORTER( STL STL/STLLoader.h ) -ADD_ASSIMP_EXPORTER( STL - STL/STLExporter.h - STL/STLExporter.cpp -) - ADD_ASSIMP_IMPORTER( TERRAGEN Terragen/TerragenLoader.cpp Terragen/TerragenLoader.h @@ -748,11 +794,6 @@ ADD_ASSIMP_IMPORTER( X X/XFileParser.h ) -ADD_ASSIMP_EXPORTER( X - X/XFileExporter.h - X/XFileExporter.cpp -) - ADD_ASSIMP_IMPORTER( X3D X3D/X3DImporter.cpp X3D/X3DImporter.hpp @@ -773,11 +814,6 @@ ADD_ASSIMP_IMPORTER( X3D X3D/X3DVocabulary.cpp ) -ADD_ASSIMP_EXPORTER( X3D - X3D/X3DExporter.cpp - X3D/X3DExporter.hpp -) - ADD_ASSIMP_IMPORTER( GLTF glTF/glTFCommon.h glTF/glTFCommon.cpp @@ -795,13 +831,6 @@ ADD_ASSIMP_IMPORTER( GLTF glTF2/glTF2Importer.h ) -ADD_ASSIMP_EXPORTER( GLTF - glTF/glTFExporter.h - glTF/glTFExporter.cpp - glTF2/glTF2Exporter.h - glTF2/glTF2Exporter.cpp -) - ADD_ASSIMP_IMPORTER( 3MF 3MF/D3MFImporter.h 3MF/D3MFImporter.cpp @@ -810,11 +839,6 @@ ADD_ASSIMP_IMPORTER( 3MF 3MF/3MFXmlTags.h ) -ADD_ASSIMP_EXPORTER( 3MF - 3MF/D3MFExporter.h - 3MF/D3MFExporter.cpp -) - ADD_ASSIMP_IMPORTER( MMD MMD/MMDCpp14.h MMD/MMDImporter.cpp @@ -825,14 +849,6 @@ 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 @@ -855,11 +871,6 @@ ADD_ASSIMP_IMPORTER( STEP Importer/StepFile/StepReaderGen.h ) -ADD_ASSIMP_EXPORTER( STEP - Step/StepExporter.h - Step/StepExporter.cpp -) - if ((NOT ASSIMP_NO_EXPORT) OR (NOT ASSIMP_EXPORTERS_ENABLED STREQUAL "")) SET( Exporter_SRCS Common/Exporter.cpp @@ -878,35 +889,35 @@ SOURCE_GROUP( Extra FILES ${Extra_SRCS}) IF(HUNTER_ENABLED) hunter_add_package(irrXML) find_package(irrXML CONFIG REQUIRED) -ELSE(HUNTER_ENABLED) +ELSE() # irrXML already included in contrib directory by parent CMakeLists.txt. -ENDIF(HUNTER_ENABLED) +ENDIF() # utf8 IF(HUNTER_ENABLED) hunter_add_package(utf8) find_package(utf8 CONFIG REQUIRED) -ELSE(HUNTER_ENABLED) +ELSE() # utf8 is header-only, so Assimp doesn't need to do anything. -ENDIF(HUNTER_ENABLED) +ENDIF() # polyclipping IF(HUNTER_ENABLED) hunter_add_package(polyclipping) find_package(polyclipping CONFIG REQUIRED) -ELSE(HUNTER_ENABLED) +ELSE() SET( Clipper_SRCS ../contrib/clipper/clipper.hpp ../contrib/clipper/clipper.cpp ) SOURCE_GROUP( Contrib\\Clipper FILES ${Clipper_SRCS}) -ENDIF(HUNTER_ENABLED) +ENDIF() # poly2tri IF(HUNTER_ENABLED) hunter_add_package(poly2tri) find_package(poly2tri CONFIG REQUIRED) -ELSE(HUNTER_ENABLED) +ELSE() SET( Poly2Tri_SRCS ../contrib/poly2tri/poly2tri/common/shapes.cc ../contrib/poly2tri/poly2tri/common/shapes.h @@ -921,13 +932,13 @@ ELSE(HUNTER_ENABLED) ../contrib/poly2tri/poly2tri/sweep/sweep_context.h ) SOURCE_GROUP( Contrib\\Poly2Tri FILES ${Poly2Tri_SRCS}) -ENDIF(HUNTER_ENABLED) +ENDIF() # minizip/unzip IF(HUNTER_ENABLED) hunter_add_package(minizip) find_package(minizip CONFIG REQUIRED) -ELSE(HUNTER_ENABLED) +ELSE() SET( unzip_SRCS ../contrib/unzip/crypt.h ../contrib/unzip/ioapi.c @@ -936,13 +947,13 @@ ELSE(HUNTER_ENABLED) ../contrib/unzip/unzip.h ) SOURCE_GROUP(Contrib\\unzip FILES ${unzip_SRCS}) -ENDIF(HUNTER_ENABLED) +ENDIF() # zip (https://github.com/kuba--/zip) IF(HUNTER_ENABLED) hunter_add_package(zip) find_package(zip CONFIG REQUIRED) -ELSE(HUNTER_ENABLED) +ELSE() SET( ziplib_SRCS ../contrib/zip/src/miniz.h ../contrib/zip/src/zip.c @@ -957,13 +968,13 @@ ELSE(HUNTER_ENABLED) endif() SOURCE_GROUP( ziplib FILES ${ziplib_SRCS} ) -ENDIF(HUNTER_ENABLED) +ENDIF() # openddlparser IF(HUNTER_ENABLED) hunter_add_package(openddlparser) find_package(openddlparser CONFIG REQUIRED) -ELSE(HUNTER_ENABLED) +ELSE() SET ( openddl_parser_SRCS ../contrib/openddlparser/code/OpenDDLParser.cpp ../contrib/openddlparser/code/DDLNode.cpp @@ -980,12 +991,12 @@ ELSE(HUNTER_ENABLED) ../contrib/openddlparser/include/openddlparser/Value.h ) SOURCE_GROUP( Contrib\\openddl_parser FILES ${openddl_parser_SRCS}) -ENDIF(HUNTER_ENABLED) +ENDIF() # Open3DGC IF(HUNTER_ENABLED) # Nothing to do, not available in Hunter yet. -ELSE(HUNTER_ENABLED) +ELSE() SET ( open3dgc_SRCS ../contrib/Open3DGC/o3dgcAdjacencyInfo.h ../contrib/Open3DGC/o3dgcArithmeticCodec.cpp @@ -1018,7 +1029,7 @@ ELSE(HUNTER_ENABLED) ../contrib/Open3DGC/o3dgcVector.inl ) SOURCE_GROUP( Contrib\\open3dgc FILES ${open3dgc_SRCS}) -ENDIF(HUNTER_ENABLED) +ENDIF() # Check dependencies for glTF importer with Open3DGC-compression. # RT-extensions is used in "contrib/Open3DGC/o3dgcTimer.h" for collecting statistics. Pointed file @@ -1037,40 +1048,42 @@ ENDIF () IF(HUNTER_ENABLED) hunter_add_package(RapidJSON) find_package(RapidJSON CONFIG REQUIRED) -ELSE(HUNTER_ENABLED) +ELSE() INCLUDE_DIRECTORIES( "../contrib/rapidjson/include" ) INCLUDE_DIRECTORIES( "../contrib" ) -ENDIF(HUNTER_ENABLED) +ENDIF() # VC2010 fixes if(MSVC10) option( VC10_STDINT_FIX "Fix for VC10 Compiler regarding pstdint.h redefinition errors" OFF ) if( VC10_STDINT_FIX ) ADD_DEFINITIONS( -D_STDINT ) - endif( VC10_STDINT_FIX ) -endif(MSVC10) + endif() +endif() ADD_DEFINITIONS( -DASSIMP_BUILD_DLL_EXPORT ) if ( MSVC ) ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS ) ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS ) -endif ( MSVC ) +endif () IF(NOT HUNTER_ENABLED) if (UNZIP_FOUND) SET (unzip_compile_SRCS "") - else (UNZIP_FOUND) + else () SET (unzip_compile_SRCS ${unzip_SRCS}) INCLUDE_DIRECTORIES( "../contrib/unzip/" ) - endif (UNZIP_FOUND) -ENDIF(NOT HUNTER_ENABLED) + endif () +ENDIF() MESSAGE(STATUS "Enabled importer formats:${ASSIMP_IMPORTERS_ENABLED}") MESSAGE(STATUS "Disabled importer formats:${ASSIMP_IMPORTERS_DISABLED}") -MESSAGE(STATUS "Enabled exporter formats:${ASSIMP_EXPORTERS_ENABLED}") -MESSAGE(STATUS "Disabled exporter formats:${ASSIMP_EXPORTERS_DISABLED}") +if (NOT ASSIMP_NO_EXPORT) + MESSAGE(STATUS "Enabled exporter formats:${ASSIMP_EXPORTERS_ENABLED}") + MESSAGE(STATUS "Disabled exporter formats:${ASSIMP_EXPORTERS_DISABLED}") +endif() SOURCE_GROUP( include\\assimp FILES ${PUBLIC_HEADERS} ) @@ -1110,12 +1123,12 @@ IF(NOT HUNTER_ENABLED) ${IRRXML_INCLUDE_DIR} ../contrib/openddlparser/include ) -ENDIF(NOT HUNTER_ENABLED) +ENDIF() IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) SET( assimp_src ${assimp_src} ${C4D_SRCS}) INCLUDE_DIRECTORIES(${C4D_INCLUDES}) -ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) +ENDIF () ADD_LIBRARY( assimp ${assimp_src} ) ADD_LIBRARY(assimp::assimp ALIAS assimp) @@ -1139,21 +1152,21 @@ IF(HUNTER_ENABLED) utf8::utf8 zip::zip ) -ELSE(HUNTER_ENABLED) +ELSE() TARGET_LINK_LIBRARIES(assimp ${ZLIB_LIBRARIES} ${OPENDDL_PARSER_LIBRARIES} ${IRRXML_LIBRARY} ) -ENDIF(HUNTER_ENABLED) +ENDIF() if(ASSIMP_ANDROID_JNIIOSYSTEM) set(ASSIMP_ANDROID_JNIIOSYSTEM_PATH port/AndroidJNI) add_subdirectory(../${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/ ../${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/) target_link_libraries(assimp android_jniiosystem) -endif(ASSIMP_ANDROID_JNIIOSYSTEM) +endif() IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) TARGET_LINK_LIBRARIES(assimp optimized ${C4D_RELEASE_LIBRARIES}) TARGET_LINK_LIBRARIES(assimp debug ${C4D_DEBUG_LIBRARIES}) TARGET_LINK_LIBRARIES(assimp ${C4D_EXTRA_LIBRARIES}) -ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) +ENDIF () if( MSVC ) # in order to prevent DLL hell, each of the DLLs have to be suffixed with the major version and msvc prefix @@ -1199,10 +1212,6 @@ SET_TARGET_PROPERTIES( assimp PROPERTIES ) if (APPLE) - SET_TARGET_PROPERTIES( assimp PROPERTIES - INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${ASSIMP_LIB_INSTALL_DIR}" - ) - if (BUILD_FRAMEWORK) SET_TARGET_PROPERTIES( assimp PROPERTIES FRAMEWORK TRUE @@ -1218,8 +1227,8 @@ if (APPLE) "../${HEADER_PATH}/Compiler" assimp.framework/Headers/Compiler COMMENT "Copying public ./Compiler/ header files to framework bundle's Headers/Compiler/") - ENDIF(BUILD_FRAMEWORK) -ENDIF(APPLE) + ENDIF() +ENDIF() # Build against external unzip, or add ../contrib/unzip so # assimp can #include "unzip.h" @@ -1227,15 +1236,15 @@ IF(NOT HUNTER_ENABLED) if (UNZIP_FOUND) INCLUDE_DIRECTORIES(${UNZIP_INCLUDE_DIRS}) TARGET_LINK_LIBRARIES(assimp ${UNZIP_LIBRARIES}) - else (UNZIP_FOUND) + else () INCLUDE_DIRECTORIES("../") - endif (UNZIP_FOUND) -ENDIF(NOT HUNTER_ENABLED) + endif () +ENDIF() # Add RT-extension library for glTF importer with Open3DGC-compression. IF (RT_FOUND AND ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC) TARGET_LINK_LIBRARIES(assimp ${RT_LIBRARY}) -ENDIF (RT_FOUND AND ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC) +ENDIF () IF(HUNTER_ENABLED) INSTALL( TARGETS assimp @@ -1246,14 +1255,14 @@ IF(HUNTER_ENABLED) FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT} INCLUDES DESTINATION "include") -ELSE(HUNTER_ENABLED) +ELSE() INSTALL( TARGETS assimp LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR} FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT}) -ENDIF(HUNTER_ENABLED) +ENDIF() INSTALL( FILES ${PUBLIC_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp COMPONENT assimp-dev) INSTALL( FILES ${COMPILER_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp/Compiler COMPONENT assimp-dev) @@ -1261,7 +1270,7 @@ if (ASSIMP_ANDROID_JNIIOSYSTEM) INSTALL(FILES ${HEADER_PATH}/${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/AndroidJNIIOSystem.h DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR} COMPONENT assimp-dev) -ENDIF(ASSIMP_ANDROID_JNIIOSYSTEM) +ENDIF() if(MSVC AND ASSIMP_INSTALL_PDB) # When only the static library is built, these properties must diff --git a/Engine/lib/assimp/code/COB/COBLoader.cpp b/Engine/lib/assimp/code/COB/COBLoader.cpp index 19e3cd59e..8e7c81192 100644 --- a/Engine/lib/assimp/code/COB/COBLoader.cpp +++ b/Engine/lib/assimp/code/COB/COBLoader.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -250,7 +250,7 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill const Mesh& ndmesh = (const Mesh&)(root); if (ndmesh.vertex_positions.size() && ndmesh.texture_coords.size()) { - typedef std::pair Entry; + typedef std::pair Entry; for(const Entry& reflist : ndmesh.temp_map) { { // create mesh size_t n = 0; diff --git a/Engine/lib/assimp/code/COB/COBLoader.h b/Engine/lib/assimp/code/COB/COBLoader.h index 40fed324b..8b3110a32 100644 --- a/Engine/lib/assimp/code/COB/COBLoader.h +++ b/Engine/lib/assimp/code/COB/COBLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/COB/COBScene.h b/Engine/lib/assimp/code/COB/COBScene.h index 90349be70..87f4f4570 100644 --- a/Engine/lib/assimp/code/COB/COBScene.h +++ b/Engine/lib/assimp/code/COB/COBScene.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/CSM/CSMLoader.cpp b/Engine/lib/assimp/code/CSM/CSMLoader.cpp index 9dbb38467..fbabea12e 100644 --- a/Engine/lib/assimp/code/CSM/CSMLoader.cpp +++ b/Engine/lib/assimp/code/CSM/CSMLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team @@ -178,7 +178,7 @@ void CSMImporter::InternReadFile( const std::string& pFile, *ot++ = *buffer++; *ot = '\0'; - nda->mNodeName.length = (size_t)(ot-nda->mNodeName.data); + nda->mNodeName.length = (ai_uint32)(ot-nda->mNodeName.data); } anim->mNumChannels = static_cast(anims_temp.size()); diff --git a/Engine/lib/assimp/code/CSM/CSMLoader.h b/Engine/lib/assimp/code/CSM/CSMLoader.h index 31a814b52..907c7aa43 100644 --- a/Engine/lib/assimp/code/CSM/CSMLoader.h +++ b/Engine/lib/assimp/code/CSM/CSMLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Collada/ColladaExporter.cpp b/Engine/lib/assimp/code/Collada/ColladaExporter.cpp index a93dfa59a..99cdc097b 100644 --- a/Engine/lib/assimp/code/Collada/ColladaExporter.cpp +++ b/Engine/lib/assimp/code/Collada/ColladaExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ColladaExporter.h" #include +#include #include #include #include @@ -277,7 +278,7 @@ void ColladaExporter::WriteHeader() { mOutput << startstr << "" << XMLEscape(value.C_Str()) << "" << endstr; } - if (nullptr == meta || !meta->Get("AuthoringTool", value)) { + if (nullptr == meta || !meta->Get(AI_METADATA_SOURCE_GENERATOR, value)) { mOutput << startstr << "" << "Assimp Exporter" << "" << endstr; } else { mOutput << startstr << "" << XMLEscape(value.C_Str()) << "" << endstr; @@ -287,7 +288,7 @@ void ColladaExporter::WriteHeader() { if (meta->Get("Comments", value)) { mOutput << startstr << "" << XMLEscape(value.C_Str()) << "" << endstr; } - if (meta->Get("Copyright", value)) { + if (meta->Get(AI_METADATA_SOURCE_COPYRIGHT, value)) { mOutput << startstr << "" << XMLEscape(value.C_Str()) << "" << endstr; } if (meta->Get("SourceData", value)) { diff --git a/Engine/lib/assimp/code/Collada/ColladaExporter.h b/Engine/lib/assimp/code/Collada/ColladaExporter.h index 0b4fa59a3..f6c66e279 100644 --- a/Engine/lib/assimp/code/Collada/ColladaExporter.h +++ b/Engine/lib/assimp/code/Collada/ColladaExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Collada/ColladaHelper.cpp b/Engine/lib/assimp/code/Collada/ColladaHelper.cpp new file mode 100644 index 000000000..6f1fed366 --- /dev/null +++ b/Engine/lib/assimp/code/Collada/ColladaHelper.cpp @@ -0,0 +1,107 @@ +/** Helper structures for the Collada loader */ + +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +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 "ColladaHelper.h" + +#include +#include + +namespace Assimp { +namespace Collada { + +const MetaKeyPairVector MakeColladaAssimpMetaKeys() { + MetaKeyPairVector result; + result.emplace_back("authoring_tool", AI_METADATA_SOURCE_GENERATOR); + result.emplace_back("copyright", AI_METADATA_SOURCE_COPYRIGHT); + return result; +}; + +const MetaKeyPairVector &GetColladaAssimpMetaKeys() { + static const MetaKeyPairVector result = MakeColladaAssimpMetaKeys(); + return result; +} + +const MetaKeyPairVector MakeColladaAssimpMetaKeysCamelCase() { + MetaKeyPairVector result = MakeColladaAssimpMetaKeys(); + for (auto &val : result) + { + ToCamelCase(val.first); + } + return result; +}; + +const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase() +{ + static const MetaKeyPairVector result = MakeColladaAssimpMetaKeysCamelCase(); + return result; +} + +// ------------------------------------------------------------------------------------------------ +// Convert underscore_separated to CamelCase: "authoring_tool" becomes "AuthoringTool" +void ToCamelCase(std::string &text) +{ + if (text.empty()) + return; + // Capitalise first character + auto it = text.begin(); + (*it) = ToUpper(*it); + ++it; + for (/*started above*/ ; it != text.end(); /*iterated below*/) + { + if ((*it) == '_') + { + it = text.erase(it); + if (it != text.end()) + (*it) = ToUpper(*it); + } + else + { + // Make lower case + (*it) = ToLower(*it); + ++it; + } + } +} + +} // namespace Collada +} // namespace Assimp diff --git a/Engine/lib/assimp/code/Collada/ColladaHelper.h b/Engine/lib/assimp/code/Collada/ColladaHelper.h index b7d47da15..c6e2e7ddd 100644 --- a/Engine/lib/assimp/code/Collada/ColladaHelper.h +++ b/Engine/lib/assimp/code/Collada/ColladaHelper.h @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include #include #include @@ -104,6 +105,17 @@ enum MorphMethod Relative }; +/** Common metadata keys as */ +typedef std::pair MetaKeyPair; +typedef std::vector MetaKeyPairVector; + +// Collada as lower_case (native) +const MetaKeyPairVector &GetColladaAssimpMetaKeys(); +// Collada as CamelCase (used by Assimp for consistency) +const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase(); + +/** Convert underscore_separated to CamelCase "authoring_tool" becomes "AuthoringTool" */ +void ToCamelCase(std::string &text); /** Contains all data for one of the different transformation types */ struct Transform @@ -647,23 +659,37 @@ struct Animation void CombineSingleChannelAnimationsRecursively(Animation *pParent) { + std::set childrenTargets; + bool childrenAnimationsHaveDifferentChannels = true; + for (std::vector::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) { Animation *anim = *it; - CombineSingleChannelAnimationsRecursively(anim); - if (anim->mChannels.size() == 1) + if (childrenAnimationsHaveDifferentChannels && anim->mChannels.size() == 1 && + childrenTargets.find(anim->mChannels[0].mTarget) == childrenTargets.end()) { + childrenTargets.insert(anim->mChannels[0].mTarget); + } else { + childrenAnimationsHaveDifferentChannels = false; + } + + ++it; + } + + // We only want to combine animations if they have different channels + if (childrenAnimationsHaveDifferentChannels) + { + for (std::vector::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) { + Animation *anim = *it; + pParent->mChannels.push_back(anim->mChannels[0]); it = pParent->mSubAnims.erase(it); delete anim; - } - else - { - ++it; + continue; } } } diff --git a/Engine/lib/assimp/code/Collada/ColladaLoader.cpp b/Engine/lib/assimp/code/Collada/ColladaLoader.cpp index 37529bc98..b78fc0e3b 100644 --- a/Engine/lib/assimp/code/Collada/ColladaLoader.cpp +++ b/Engine/lib/assimp/code/Collada/ColladaLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -963,18 +963,38 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars // 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) { aiAnimation* other = mAnims[b]; if (other->mNumChannels == 1 && other->mDuration == templateAnim->mDuration && other->mTicksPerSecond == templateAnim->mTicksPerSecond) - collectedAnimIndices.push_back(b); + collectedAnimIndices.push_back(b); } + // We only want to combine the animations if they have different channels + std::set animTargets; + animTargets.insert(templateAnim->mChannels[0]->mNodeName.C_Str()); + bool collectedAnimationsHaveDifferentChannels = true; + for (size_t b = 0; b < collectedAnimIndices.size(); ++b) + { + aiAnimation* srcAnimation = mAnims[collectedAnimIndices[b]]; + std::string channelName = std::string(srcAnimation->mChannels[0]->mNodeName.C_Str()); + if (animTargets.find(channelName) == animTargets.end()) { + animTargets.insert(channelName); + } else { + collectedAnimationsHaveDifferentChannels = false; + break; + } + } + + if (!collectedAnimationsHaveDifferentChannels) + continue; + // if there are other animations which fit the template anim, combine all channels into a single anim if (!collectedAnimIndices.empty()) { diff --git a/Engine/lib/assimp/code/Collada/ColladaLoader.h b/Engine/lib/assimp/code/Collada/ColladaLoader.h index d8d3f4f52..198b7a215 100644 --- a/Engine/lib/assimp/code/Collada/ColladaLoader.h +++ b/Engine/lib/assimp/code/Collada/ColladaLoader.h @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Collada/ColladaParser.cpp b/Engine/lib/assimp/code/Collada/ColladaParser.cpp index 1a7b96189..d0f71d95a 100644 --- a/Engine/lib/assimp/code/Collada/ColladaParser.cpp +++ b/Engine/lib/assimp/code/Collada/ColladaParser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team @@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include "ColladaParser.h" +#include #include #include #include @@ -249,6 +250,9 @@ void ColladaParser::UriDecodePath(aiString& ss) bool ColladaParser::ReadBoolFromTextContent() { const char* cur = GetTextContent(); + if ( nullptr == cur) { + return false; + } return (!ASSIMP_strincmp(cur, "true", 4) || '0' != *cur); } @@ -257,6 +261,9 @@ bool ColladaParser::ReadBoolFromTextContent() ai_real ColladaParser::ReadFloatFromTextContent() { const char* cur = GetTextContent(); + if ( nullptr == cur ) { + return 0.0; + } return fast_atof(cur); } @@ -276,6 +283,11 @@ void ColladaParser::ReadContents() if (attrib != -1) { const char* version = mReader->getAttributeValue(attrib); + // Store declared format version string + aiString v; + v.Set(version); + mAssetMetaData.emplace(AI_METADATA_SOURCE_FORMAT_VERSION, v ); + if (!::strncmp(version, "1.5", 3)) { mFormat = FV_1_5_n; ASSIMP_LOG_DEBUG("Collada schema version is 1.5.n"); @@ -434,23 +446,39 @@ void ColladaParser::ReadContributorInfo() } } +static bool FindCommonKey(const std::string &collada_key, const MetaKeyPairVector &key_renaming, size_t &found_index) { + for (size_t i = 0; i < key_renaming.size(); ++i) { + if (key_renaming[i].first == collada_key) { + found_index = i; + return true; + } + } + found_index = std::numeric_limits::max(); + return false; +} + // ------------------------------------------------------------------------------------------------ // Reads a single string metadata item -void ColladaParser::ReadMetaDataItem(StringMetaData &metadata) -{ - // Metadata such as created, keywords, subject etc - const char* key_char = mReader->getNodeName(); - if (key_char != nullptr) - { +void ColladaParser::ReadMetaDataItem(StringMetaData &metadata) { + const Collada::MetaKeyPairVector &key_renaming = GetColladaAssimpMetaKeysCamelCase(); + // Metadata such as created, keywords, subject etc + const char *key_char = mReader->getNodeName(); + if (key_char != nullptr) { const std::string key_str(key_char); - const char* value_char = TestTextContent(); - if (value_char != nullptr) - { - std::string camel_key_str = key_str; - ToCamelCase(camel_key_str); + const char *value_char = TestTextContent(); + if (value_char != nullptr) { aiString aistr; - aistr.Set(value_char); - metadata.emplace(camel_key_str, aistr); + aistr.Set(value_char); + + std::string camel_key_str(key_str); + ToCamelCase(camel_key_str); + + size_t found_index; + if (FindCommonKey(camel_key_str, key_renaming, found_index)) { + metadata.emplace(key_renaming[found_index].second, aistr); + } else { + metadata.emplace(camel_key_str, aistr); + } } TestClosing(key_str.c_str()); } @@ -458,27 +486,6 @@ void ColladaParser::ReadMetaDataItem(StringMetaData &metadata) SkipElement(); } -// ------------------------------------------------------------------------------------------------ -// Convert underscore_seperated to CamelCase: "authoring_tool" becomes "AuthoringTool" -void ColladaParser::ToCamelCase(std::string &text) -{ - if (text.empty()) - return; - // Capitalise first character - text[0] = ToUpper(text[0]); - for (auto it = text.begin(); it != text.end(); /*iterated below*/) - { - if ((*it) == '_') - { - it = text.erase(it); - if (it != text.end()) - (*it) = ToUpper(*it); - } - else - ++it; - } -} - // ------------------------------------------------------------------------------------------------ // Reads the animation clips void ColladaParser::ReadAnimationClipLibrary() @@ -3234,13 +3241,12 @@ void ColladaParser::ReadScene() // ------------------------------------------------------------------------------------------------ // Aborts the file reading with an exception -AI_WONT_RETURN void ColladaParser::ThrowException(const std::string& pError) const -{ +AI_WONT_RETURN void ColladaParser::ThrowException(const std::string& pError) const { throw DeadlyImportError(format() << "Collada: " << mFileName << " - " << pError); } -void ColladaParser::ReportWarning(const char* msg, ...) -{ - ai_assert(NULL != msg); + +void ColladaParser::ReportWarning(const char* msg, ...) { + ai_assert(nullptr != msg); va_list args; va_start(args, msg); @@ -3255,11 +3261,11 @@ void ColladaParser::ReportWarning(const char* msg, ...) // ------------------------------------------------------------------------------------------------ // Skips all data until the end node of the current element -void ColladaParser::SkipElement() -{ +void ColladaParser::SkipElement() { // nothing to skip if it's an - if (mReader->isEmptyElement()) + if (mReader->isEmptyElement()) { return; + } // reroute SkipElement(mReader->getNodeName()); @@ -3267,63 +3273,75 @@ void ColladaParser::SkipElement() // ------------------------------------------------------------------------------------------------ // Skips all data until the end node of the given element -void ColladaParser::SkipElement(const char* pElement) -{ +void ColladaParser::SkipElement(const char* pElement) { // copy the current node's name because it'a pointer to the reader's internal buffer, // which is going to change with the upcoming parsing std::string element = pElement; - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - if (mReader->getNodeName() == element) + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + if (mReader->getNodeName() == element) { break; + } + } } } // ------------------------------------------------------------------------------------------------ // Tests for an opening element of the given name, throws an exception if not found -void ColladaParser::TestOpening(const char* pName) -{ +void ColladaParser::TestOpening(const char* pName) { // read element start - if (!mReader->read()) + if (!mReader->read()) { ThrowException(format() << "Unexpected end of file while beginning of <" << pName << "> element."); + } // whitespace in front is ok, just read again if found - if (mReader->getNodeType() == irr::io::EXN_TEXT) - if (!mReader->read()) + if (mReader->getNodeType() == irr::io::EXN_TEXT) { + if (!mReader->read()) { ThrowException(format() << "Unexpected end of file while reading beginning of <" << pName << "> element."); + } + } - if (mReader->getNodeType() != irr::io::EXN_ELEMENT || strcmp(mReader->getNodeName(), pName) != 0) + if (mReader->getNodeType() != irr::io::EXN_ELEMENT || strcmp(mReader->getNodeName(), pName) != 0) { ThrowException(format() << "Expected start of <" << pName << "> element."); + } } // ------------------------------------------------------------------------------------------------ // Tests for the closing tag of the given element, throws an exception if not found -void ColladaParser::TestClosing(const char* pName) -{ - // check if we're already on the closing tag and return right away - if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END && strcmp(mReader->getNodeName(), pName) == 0) +void ColladaParser::TestClosing(const char* pName) { + // check if we have an empty (self-closing) element + if (mReader->isEmptyElement()) { return; + } + + // check if we're already on the closing tag and return right away + if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END && strcmp(mReader->getNodeName(), pName) == 0) { + return; + } // if not, read some more - if (!mReader->read()) + if (!mReader->read()) { ThrowException(format() << "Unexpected end of file while reading end of <" << pName << "> element."); + } // whitespace in front is ok, just read again if found - if (mReader->getNodeType() == irr::io::EXN_TEXT) - if (!mReader->read()) + if (mReader->getNodeType() == irr::io::EXN_TEXT) { + if (!mReader->read()) { ThrowException(format() << "Unexpected end of file while reading end of <" << pName << "> element."); + } + } // but this has the be the closing tag, or we're lost - if (mReader->getNodeType() != irr::io::EXN_ELEMENT_END || strcmp(mReader->getNodeName(), pName) != 0) + if (mReader->getNodeType() != irr::io::EXN_ELEMENT_END || strcmp(mReader->getNodeName(), pName) != 0) { ThrowException(format() << "Expected end of <" << pName << "> element."); + } } // ------------------------------------------------------------------------------------------------ // Returns the index of the named attribute or -1 if not found. Does not throw, therefore useful for optional attributes -int ColladaParser::GetAttribute(const char* pAttr) const -{ +int ColladaParser::GetAttribute(const char* pAttr) const { int index = TestAttribute(pAttr); - if (index != -1) + if (index != -1) { return index; + } // attribute not found -> throw an exception ThrowException(format() << "Expected attribute \"" << pAttr << "\" for element <" << mReader->getNodeName() << ">."); diff --git a/Engine/lib/assimp/code/Collada/ColladaParser.h b/Engine/lib/assimp/code/Collada/ColladaParser.h index 4e8c8fccf..d1e812bd2 100644 --- a/Engine/lib/assimp/code/Collada/ColladaParser.h +++ b/Engine/lib/assimp/code/Collada/ColladaParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- - Copyright (c) 2006-2019, assimp team + Copyright (c) 2006-2020, assimp team All rights reserved. @@ -94,12 +94,9 @@ namespace Assimp /** Reads contributor information such as author and legal blah */ void ReadContributorInfo(); - /** Reads generic metadata into provided map */ + /** Reads generic metadata into provided map and renames keys for Assimp */ void ReadMetaDataItem(StringMetaData &metadata); - /** Convert underscore_seperated to CamelCase "authoring_tool" becomes "AuthoringTool" */ - static void ToCamelCase(std::string &text); - /** Reads the animation library */ void ReadAnimationLibrary(); diff --git a/Engine/lib/assimp/code/Common/Assimp.cpp b/Engine/lib/assimp/code/Common/Assimp.cpp index 178b2c01d..66588f0bc 100644 --- a/Engine/lib/assimp/code/Common/Assimp.cpp +++ b/Engine/lib/assimp/code/Common/Assimp.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Common/BaseImporter.cpp b/Engine/lib/assimp/code/Common/BaseImporter.cpp index 5c1e60554..8d7b029ba 100644 --- a/Engine/lib/assimp/code/Common/BaseImporter.cpp +++ b/Engine/lib/assimp/code/Common/BaseImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team @@ -191,7 +191,7 @@ void BaseImporter::GetExtensionList(std::set& extensions) { } std::unique_ptr pStream (pIOHandler->Open(pFile)); - if (pStream.get() ) { + if (pStream) { // read 200 characters from the file std::unique_ptr _buffer (new char[searchBytes+1 /* for the '\0' */]); char *buffer( _buffer.get() ); @@ -283,7 +283,6 @@ std::string BaseImporter::GetExtension( const std::string& file ) { return ""; } - // thanks to Andy Maloney for the hint std::string ret = file.substr( pos + 1 ); std::transform( ret.begin(), ret.end(), ret.begin(), ToLower); @@ -309,7 +308,7 @@ std::string BaseImporter::GetExtension( const std::string& file ) { }; magic = reinterpret_cast(_magic); std::unique_ptr pStream (pIOHandler->Open(pFile)); - if (pStream.get() ) { + if (pStream) { // skip to offset pStream->Seek(offset,aiOrigin_SET); @@ -603,7 +602,7 @@ unsigned int BatchLoader::AddLoadRequest(const std::string& file, } // no, we don't have it. So add it to the queue ... - m_data->requests.push_back(LoadRequest(file,steps,map, m_data->next_id)); + m_data->requests.emplace_back(file, steps, map, m_data->next_id); return m_data->next_id++; } diff --git a/Engine/lib/assimp/code/Common/BaseProcess.cpp b/Engine/lib/assimp/code/Common/BaseProcess.cpp index e247be418..d02653cf2 100644 --- a/Engine/lib/assimp/code/Common/BaseProcess.cpp +++ b/Engine/lib/assimp/code/Common/BaseProcess.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team - - +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -43,45 +41,43 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Implementation of BaseProcess */ -#include #include "BaseProcess.h" -#include -#include #include "Importer.h" +#include +#include +#include using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer BaseProcess::BaseProcess() AI_NO_EXCEPT -: shared() -, progress() -{ + : shared(), + progress() { + // empty } // ------------------------------------------------------------------------------------------------ // Destructor, private as well -BaseProcess::~BaseProcess() -{ +BaseProcess::~BaseProcess() { // nothing to do here } // ------------------------------------------------------------------------------------------------ -void BaseProcess::ExecuteOnScene( Importer* pImp) -{ - ai_assert(NULL != pImp && NULL != pImp->Pimpl()->mScene); +void BaseProcess::ExecuteOnScene(Importer *pImp) { + ai_assert( nullptr != pImp ); + ai_assert( nullptr != pImp->Pimpl()->mScene); progress = pImp->GetProgressHandler(); - ai_assert(progress); + ai_assert(nullptr != progress); - SetupProperties( pImp ); + SetupProperties(pImp); // catch exceptions thrown inside the PostProcess-Step - try - { + try { Execute(pImp->Pimpl()->mScene); - } catch( const std::exception& err ) { + } catch (const std::exception &err) { // extract error description pImp->Pimpl()->mErrorString = err.what(); @@ -94,14 +90,11 @@ void BaseProcess::ExecuteOnScene( Importer* pImp) } // ------------------------------------------------------------------------------------------------ -void BaseProcess::SetupProperties(const Importer* /*pImp*/) -{ +void BaseProcess::SetupProperties(const Importer * /*pImp*/) { // the default implementation does nothing } // ------------------------------------------------------------------------------------------------ -bool BaseProcess::RequireVerboseFormat() const -{ +bool BaseProcess::RequireVerboseFormat() const { return true; } - diff --git a/Engine/lib/assimp/code/Common/BaseProcess.h b/Engine/lib/assimp/code/Common/BaseProcess.h index 4d5c7a76b..bf1f2586f 100644 --- a/Engine/lib/assimp/code/Common/BaseProcess.h +++ b/Engine/lib/assimp/code/Common/BaseProcess.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team - +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -44,12 +43,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef INCLUDED_AI_BASEPROCESS_H #define INCLUDED_AI_BASEPROCESS_H -#include #include +#include + struct aiScene; -namespace Assimp { +namespace Assimp { class Importer; @@ -60,64 +60,50 @@ class Importer; * to provide additional information to other steps. This is primarily * intended for cross-step optimizations. */ -class SharedPostProcessInfo -{ +class SharedPostProcessInfo { public: - - struct Base - { - virtual ~Base() - {} + struct Base { + virtual ~Base() {} }; //! Represents data that is allocated on the heap, thus needs to be deleted template - struct THeapData : public Base - { - explicit THeapData(T* in) - : data (in) - {} + struct THeapData : public Base { + explicit THeapData(T *in) : + data(in) {} - ~THeapData() - { + ~THeapData() { delete data; } - T* data; + T *data; }; //! Represents static, by-value data not allocated on the heap template - struct TStaticData : public Base - { - explicit TStaticData(T in) - : data (in) - {} + struct TStaticData : public Base { + explicit TStaticData(T in) : + data(in) {} - ~TStaticData() - {} + ~TStaticData() {} T data; }; // some typedefs for cleaner code typedef unsigned int KeyType; - typedef std::map PropertyMap; + typedef std::map PropertyMap; public: - //! Destructor - ~SharedPostProcessInfo() - { + ~SharedPostProcessInfo() { Clean(); } //! Remove all stored properties from the table - void Clean() - { + void Clean() { // invoke the virtual destructor for all stored properties for (PropertyMap::iterator it = pmap.begin(), end = pmap.end(); - it != end; ++it) - { + it != end; ++it) { delete (*it).second; } pmap.clear(); @@ -125,24 +111,21 @@ public: //! Add a heap property to the list template - void AddProperty( const char* name, T* in ){ - AddProperty(name,(Base*)new THeapData(in)); + void AddProperty(const char *name, T *in) { + AddProperty(name, (Base *)new THeapData(in)); } //! Add a static by-value property to the list template - void AddProperty( const char* name, T in ){ - AddProperty(name,(Base*)new TStaticData(in)); + void AddProperty(const char *name, T in) { + AddProperty(name, (Base *)new TStaticData(in)); } - //! Get a heap property template - bool GetProperty( const char* name, T*& out ) const - { - THeapData* t = (THeapData*)GetPropertyInternal(name); - if(!t) - { + bool GetProperty(const char *name, T *&out) const { + THeapData *t = (THeapData *)GetPropertyInternal(name); + if (!t) { out = NULL; return false; } @@ -152,53 +135,34 @@ public: //! Get a static, by-value property template - bool GetProperty( const char* name, T& out ) const - { - TStaticData* t = (TStaticData*)GetPropertyInternal(name); - if(!t)return false; + bool GetProperty(const char *name, T &out) const { + TStaticData *t = (TStaticData *)GetPropertyInternal(name); + if ( nullptr == t) { + return false; + } out = t->data; return true; } //! Remove a property of a specific type - void RemoveProperty( const char* name) { - SetGenericPropertyPtr(pmap,name,NULL); + void RemoveProperty(const char *name) { + SetGenericPropertyPtr(pmap, name, nullptr ); } private: - - void AddProperty( const char* name, Base* data) { - SetGenericPropertyPtr(pmap,name,data); + void AddProperty(const char *name, Base *data) { + SetGenericPropertyPtr(pmap, name, data); } - Base* GetPropertyInternal( const char* name) const { - return GetGenericProperty(pmap,name,NULL); + Base *GetPropertyInternal(const char *name) const { + return GetGenericProperty(pmap, name, nullptr ); } private: - //! Map of all stored properties PropertyMap pmap; }; -#if 0 - -// --------------------------------------------------------------------------- -/** @brief Represents a dependency table for a postprocessing steps. - * - * For future use. - */ - struct PPDependencyTable - { - unsigned int execute_me_before_these; - unsigned int execute_me_after_these; - unsigned int only_if_these_are_not_specified; - unsigned int mutually_exclusive_with; - }; - -#endif - - #define AI_SPP_SPATIAL_SORT "$Spat" // --------------------------------------------------------------------------- @@ -228,7 +192,7 @@ public: * @return true if the process is present in this flag fields, * false if not. */ - virtual bool IsActive( unsigned int pFlags) const = 0; + virtual bool IsActive(unsigned int pFlags) const = 0; // ------------------------------------------------------------------- /** Check whether this step expects its input vertex data to be @@ -241,14 +205,14 @@ public: * the object pointer will be set to NULL). * @param pImp Importer instance (pImp->mScene must be valid) */ - void ExecuteOnScene( Importer* pImp); + void ExecuteOnScene(Importer *pImp); // ------------------------------------------------------------------- /** Called prior to ExecuteOnScene(). * The function is a request to the process to update its configuration * basing on the Importer's configuration property list. */ - virtual void SetupProperties(const Importer* pImp); + virtual void SetupProperties(const Importer *pImp); // ------------------------------------------------------------------- /** Executes the post processing step on the given imported data. @@ -256,35 +220,32 @@ public: * This method must be implemented by deriving classes. * @param pScene The imported data to work at. */ - virtual void Execute( aiScene* pScene) = 0; - + virtual void Execute(aiScene *pScene) = 0; // ------------------------------------------------------------------- /** Assign a new SharedPostProcessInfo to the step. This object * allows multiple postprocess steps to share data. * @param sh May be NULL */ - inline void SetSharedData(SharedPostProcessInfo* sh) { + inline void SetSharedData(SharedPostProcessInfo *sh) { shared = sh; } // ------------------------------------------------------------------- /** Get the shared data that is assigned to the step. */ - inline SharedPostProcessInfo* GetSharedData() { + inline SharedPostProcessInfo *GetSharedData() { return shared; } protected: - /** See the doc of #SharedPostProcessInfo for more details */ - SharedPostProcessInfo* shared; + SharedPostProcessInfo *shared; /** Currently active progress handler */ - ProgressHandler* progress; + ProgressHandler *progress; }; - } // end of namespace Assimp #endif // AI_BASEPROCESS_H_INC diff --git a/Engine/lib/assimp/code/Common/Bitmap.cpp b/Engine/lib/assimp/code/Common/Bitmap.cpp index b22b71ea9..7d8225704 100644 --- a/Engine/lib/assimp/code/Common/Bitmap.cpp +++ b/Engine/lib/assimp/code/Common/Bitmap.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Common/CreateAnimMesh.cpp b/Engine/lib/assimp/code/Common/CreateAnimMesh.cpp index 98b60e531..7317dc45b 100644 --- a/Engine/lib/assimp/code/Common/CreateAnimMesh.cpp +++ b/Engine/lib/assimp/code/Common/CreateAnimMesh.cpp @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- Copyright (C) 2016 The Qt Company Ltd. -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/DefaultIOStream.cpp b/Engine/lib/assimp/code/Common/DefaultIOStream.cpp index 829b44731..205f19e37 100644 --- a/Engine/lib/assimp/code/Common/DefaultIOStream.cpp +++ b/Engine/lib/assimp/code/Common/DefaultIOStream.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Common/DefaultIOSystem.cpp b/Engine/lib/assimp/code/Common/DefaultIOSystem.cpp index 6fdc24dd8..0343cb289 100644 --- a/Engine/lib/assimp/code/Common/DefaultIOSystem.cpp +++ b/Engine/lib/assimp/code/Common/DefaultIOSystem.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Common/DefaultLogger.cpp b/Engine/lib/assimp/code/Common/DefaultLogger.cpp index de3528d2b..adb9ba160 100644 --- a/Engine/lib/assimp/code/Common/DefaultLogger.cpp +++ b/Engine/lib/assimp/code/Common/DefaultLogger.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team @@ -107,7 +107,7 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams, return nullptr; #endif - // Platform-independent default streams + // Platform-independent default streams case aiDefaultLogStream_STDERR: return new StdOStreamLogStream(std::cerr); case aiDefaultLogStream_STDOUT: @@ -121,7 +121,7 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams, }; // For compilers without dead code path detection - return NULL; + return nullptr; } // ---------------------------------------------------------------------------------- diff --git a/Engine/lib/assimp/code/Common/DefaultProgressHandler.h b/Engine/lib/assimp/code/Common/DefaultProgressHandler.h index bd2cce00b..ebf7f118c 100644 --- a/Engine/lib/assimp/code/Common/DefaultProgressHandler.h +++ b/Engine/lib/assimp/code/Common/DefaultProgressHandler.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/Exporter.cpp b/Engine/lib/assimp/code/Common/Exporter.cpp index 8a95ceae5..9f9a33b58 100644 --- a/Engine/lib/assimp/code/Common/Exporter.cpp +++ b/Engine/lib/assimp/code/Common/Exporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team @@ -103,7 +103,7 @@ void ExportSceneFBX(const char*, IOSystem*, const aiScene*, const ExportProperti void ExportSceneFBXA(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* ); void ExportSceneM3D(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneA3D(const char*, IOSystem*, const aiScene*, const ExportProperties*); +void ExportSceneM3DA(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportAssimp2Json(const char* , IOSystem*, const aiScene* , const Assimp::ExportProperties*); @@ -177,7 +177,7 @@ static void setupExporterArray(std::vector &exporte #ifndef ASSIMP_BUILD_NO_M3D_EXPORTER exporters.push_back(Exporter::ExportFormatEntry("m3d", "Model 3D (binary)", "m3d", &ExportSceneM3D, 0)); - exporters.push_back(Exporter::ExportFormatEntry("a3d", "Model 3D (ascii)", "m3d", &ExportSceneA3D, 0)); + exporters.push_back(Exporter::ExportFormatEntry("m3da", "Model 3D (ascii)", "a3d", &ExportSceneM3DA, 0)); #endif #ifndef ASSIMP_BUILD_NO_3MF_EXPORTER @@ -445,8 +445,7 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c ExportProperties emptyProperties; // Never pass NULL ExportProperties so Exporters don't have to worry. ExportProperties* pProp = pProperties ? (ExportProperties*)pProperties : &emptyProperties; - pProp->SetPropertyBool("bJoinIdenticalVertices", must_join_again); - exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp); + pProp->SetPropertyBool("bJoinIdenticalVertices", pp & aiProcess_JoinIdenticalVertices); exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp); pimpl->mProgressHandler->UpdateFileWrite(4, 4); diff --git a/Engine/lib/assimp/code/Common/FileLogStream.h b/Engine/lib/assimp/code/Common/FileLogStream.h index 740c50319..ecff03a7e 100644 --- a/Engine/lib/assimp/code/Common/FileLogStream.h +++ b/Engine/lib/assimp/code/Common/FileLogStream.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/FileSystemFilter.h b/Engine/lib/assimp/code/Common/FileSystemFilter.h index 9923cdbdd..1440cf97d 100644 --- a/Engine/lib/assimp/code/Common/FileSystemFilter.h +++ b/Engine/lib/assimp/code/Common/FileSystemFilter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2008, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Common/Importer.cpp b/Engine/lib/assimp/code/Common/Importer.cpp index 91b50859a..a59ec9812 100644 --- a/Engine/lib/assimp/code/Common/Importer.cpp +++ b/Engine/lib/assimp/code/Common/Importer.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team - - +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -78,6 +76,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include + #include #include #include @@ -119,7 +119,7 @@ void* AllocateFromAssimpHeap::operator new ( size_t num_bytes, const std::nothro return AllocateFromAssimpHeap::operator new( num_bytes ); } catch( ... ) { - return NULL; + return nullptr; } } @@ -134,9 +134,8 @@ void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes) { void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes, const std::nothrow_t& ) throw() { try { return AllocateFromAssimpHeap::operator new[]( num_bytes ); - } - catch( ... ) { - return NULL; + } catch( ... ) { + return nullptr; } } @@ -148,7 +147,7 @@ void AllocateFromAssimpHeap::operator delete[] ( void* data) { // Importer constructor. Importer::Importer() : pimpl( new ImporterPimpl ) { - pimpl->mScene = NULL; + pimpl->mScene = nullptr; pimpl->mErrorString = ""; // Allocate a default IO handler @@ -174,14 +173,14 @@ Importer::Importer() // ------------------------------------------------------------------------------------------------ // Destructor of Importer -Importer::~Importer() -{ +Importer::~Importer() { // Delete all import plugins DeleteImporterInstanceList(pimpl->mImporter); // Delete all post-processing plug-ins - for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) + for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); ++a ) { delete pimpl->mPostProcessingSteps[a]; + } // Delete the assigned IO and progress handler delete pimpl->mIOHandler; @@ -199,9 +198,9 @@ Importer::~Importer() // ------------------------------------------------------------------------------------------------ // Register a custom post-processing step -aiReturn Importer::RegisterPPStep(BaseProcess* pImp) -{ - ai_assert(NULL != pImp); +aiReturn Importer::RegisterPPStep(BaseProcess* pImp) { + ai_assert( nullptr != pImp ); + ASSIMP_BEGIN_EXCEPTION_REGION(); pimpl->mPostProcessingSteps.push_back(pImp); @@ -213,9 +212,9 @@ aiReturn Importer::RegisterPPStep(BaseProcess* pImp) // ------------------------------------------------------------------------------------------------ // Register a custom loader plugin -aiReturn Importer::RegisterLoader(BaseImporter* pImp) -{ - ai_assert(NULL != pImp); +aiReturn Importer::RegisterLoader(BaseImporter* pImp) { + ai_assert(nullptr != pImp); + ASSIMP_BEGIN_EXCEPTION_REGION(); // -------------------------------------------------------------------- @@ -242,13 +241,13 @@ aiReturn Importer::RegisterLoader(BaseImporter* pImp) pimpl->mImporter.push_back(pImp); ASSIMP_LOG_INFO_F("Registering custom importer for these file extensions: ", baked); ASSIMP_END_EXCEPTION_REGION(aiReturn); + return AI_SUCCESS; } // ------------------------------------------------------------------------------------------------ // Unregister a custom loader plugin -aiReturn Importer::UnregisterLoader(BaseImporter* pImp) -{ +aiReturn Importer::UnregisterLoader(BaseImporter* pImp) { if(!pImp) { // unregistering a NULL importer is no problem for us ... really! return AI_SUCCESS; @@ -265,13 +264,13 @@ aiReturn Importer::UnregisterLoader(BaseImporter* pImp) } ASSIMP_LOG_WARN("Unable to remove custom importer: I can't find you ..."); ASSIMP_END_EXCEPTION_REGION(aiReturn); + return AI_FAILURE; } // ------------------------------------------------------------------------------------------------ // Unregister a custom loader plugin -aiReturn Importer::UnregisterPPStep(BaseProcess* pImp) -{ +aiReturn Importer::UnregisterPPStep(BaseProcess* pImp) { if(!pImp) { // unregistering a NULL ppstep is no problem for us ... really! return AI_SUCCESS; @@ -288,24 +287,22 @@ aiReturn Importer::UnregisterPPStep(BaseProcess* pImp) } ASSIMP_LOG_WARN("Unable to remove custom post-processing step: I can't find you .."); ASSIMP_END_EXCEPTION_REGION(aiReturn); + return AI_FAILURE; } // ------------------------------------------------------------------------------------------------ // Supplies a custom IO handler to the importer to open and access files. -void Importer::SetIOHandler( IOSystem* pIOHandler) -{ +void Importer::SetIOHandler( IOSystem* pIOHandler) { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); // If the new handler is zero, allocate a default IO implementation. - if (!pIOHandler) - { + if (!pIOHandler) { // Release pointer in the possession of the caller pimpl->mIOHandler = new DefaultIOSystem(); pimpl->mIsDefaultHandler = true; - } - // Otherwise register the custom handler - else if (pimpl->mIOHandler != pIOHandler) - { + } else if (pimpl->mIOHandler != pIOHandler) { // Otherwise register the custom handler delete pimpl->mIOHandler; pimpl->mIOHandler = pIOHandler; pimpl->mIsDefaultHandler = false; @@ -316,29 +313,32 @@ void Importer::SetIOHandler( IOSystem* pIOHandler) // ------------------------------------------------------------------------------------------------ // Get the currently set IO handler IOSystem* Importer::GetIOHandler() const { + ai_assert(nullptr != pimpl); + return pimpl->mIOHandler; } // ------------------------------------------------------------------------------------------------ // Check whether a custom IO handler is currently set bool Importer::IsDefaultIOHandler() const { + ai_assert(nullptr != pimpl); + return pimpl->mIsDefaultHandler; } // ------------------------------------------------------------------------------------------------ // Supplies a custom progress handler to get regular callbacks during importing void Importer::SetProgressHandler ( ProgressHandler* pHandler ) { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); + // If the new handler is zero, allocate a default implementation. - if (!pHandler) - { + if (!pHandler) { // Release pointer in the possession of the caller pimpl->mProgressHandler = new DefaultProgressHandler(); pimpl->mIsDefaultProgressHandler = true; - } - // Otherwise register the custom handler - else if (pimpl->mProgressHandler != pHandler) - { + } else if (pimpl->mProgressHandler != pHandler) { // Otherwise register the custom handler delete pimpl->mProgressHandler; pimpl->mProgressHandler = pHandler; pimpl->mIsDefaultProgressHandler = false; @@ -349,19 +349,22 @@ void Importer::SetProgressHandler ( ProgressHandler* pHandler ) { // ------------------------------------------------------------------------------------------------ // Get the currently set progress handler ProgressHandler* Importer::GetProgressHandler() const { + ai_assert(nullptr != pimpl); + return pimpl->mProgressHandler; } // ------------------------------------------------------------------------------------------------ // Check whether a custom progress handler is currently set bool Importer::IsDefaultProgressHandler() const { + ai_assert(nullptr != pimpl); + return pimpl->mIsDefaultProgressHandler; } // ------------------------------------------------------------------------------------------------ // Validate post process step flags -bool _ValidateFlags(unsigned int pFlags) -{ +bool _ValidateFlags(unsigned int pFlags) { if (pFlags & aiProcess_GenSmoothNormals && pFlags & aiProcess_GenNormals) { ASSIMP_LOG_ERROR("#aiProcess_GenSmoothNormals and #aiProcess_GenNormals are incompatible"); return false; @@ -375,12 +378,13 @@ bool _ValidateFlags(unsigned int pFlags) // ------------------------------------------------------------------------------------------------ // Free the current scene -void Importer::FreeScene( ) -{ +void Importer::FreeScene( ) { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); delete pimpl->mScene; - pimpl->mScene = NULL; + pimpl->mScene = nullptr; pimpl->mErrorString = ""; ASSIMP_END_EXCEPTION_REGION(void); @@ -388,44 +392,48 @@ void Importer::FreeScene( ) // ------------------------------------------------------------------------------------------------ // Get the current error string, if any -const char* Importer::GetErrorString() const -{ - /* Must remain valid as long as ReadFile() or FreeFile() are not called */ +const char* Importer::GetErrorString() const { + ai_assert(nullptr != pimpl); + + // Must remain valid as long as ReadFile() or FreeFile() are not called return pimpl->mErrorString.c_str(); } // ------------------------------------------------------------------------------------------------ // Enable extra-verbose mode -void Importer::SetExtraVerbose(bool bDo) -{ +void Importer::SetExtraVerbose(bool bDo) { + ai_assert(nullptr != pimpl); + pimpl->bExtraVerbose = bDo; } // ------------------------------------------------------------------------------------------------ // Get the current scene -const aiScene* Importer::GetScene() const -{ +const aiScene* Importer::GetScene() const { + ai_assert(nullptr != pimpl); + return pimpl->mScene; } // ------------------------------------------------------------------------------------------------ // Orphan the current scene and return it. -aiScene* Importer::GetOrphanedScene() -{ +aiScene* Importer::GetOrphanedScene() { + ai_assert(nullptr != pimpl); + aiScene* s = pimpl->mScene; ASSIMP_BEGIN_EXCEPTION_REGION(); - pimpl->mScene = NULL; + pimpl->mScene = nullptr; - pimpl->mErrorString = ""; /* reset error string */ + pimpl->mErrorString = ""; // reset error string ASSIMP_END_EXCEPTION_REGION(aiScene*); + return s; } // ------------------------------------------------------------------------------------------------ // Validate post-processing flags -bool Importer::ValidateFlags(unsigned int pFlags) const -{ +bool Importer::ValidateFlags(unsigned int pFlags) const { ASSIMP_BEGIN_EXCEPTION_REGION(); // run basic checks for mutually exclusive flags if(!_ValidateFlags(pFlags)) { @@ -467,8 +475,9 @@ bool Importer::ValidateFlags(unsigned int pFlags) const const aiScene* Importer::ReadFileFromMemory( const void* pBuffer, size_t pLength, unsigned int pFlags, - const char* pHint /*= ""*/) -{ + const char* pHint /*= ""*/) { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); if (!pHint) { pHint = ""; @@ -476,12 +485,12 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer, if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint ) { pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()"; - return NULL; + return nullptr; } // prevent deletion of the previous IOHandler IOSystem* io = pimpl->mIOHandler; - pimpl->mIOHandler = NULL; + pimpl->mIOHandler = nullptr; SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength,io)); @@ -493,13 +502,13 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer, ReadFile(fbuff,pFlags); SetIOHandler(io); - ASSIMP_END_EXCEPTION_REGION(const aiScene*); + ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString); return pimpl->mScene; } // ------------------------------------------------------------------------------------------------ -void WriteLogOpening(const std::string& file) -{ +void WriteLogOpening(const std::string& file) { + ASSIMP_LOG_INFO_F("Load ", file); // print a full version dump. This is nice because we don't @@ -550,8 +559,9 @@ void WriteLogOpening(const std::string& file) // ------------------------------------------------------------------------------------------------ // Reads the given file and returns its contents if successful. -const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) -{ +const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); const std::string pFile(_pFile); @@ -580,7 +590,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) pimpl->mErrorString = "Unable to open file \"" + pFile + "\"."; ASSIMP_LOG_ERROR(pimpl->mErrorString); - return NULL; + return nullptr; } std::unique_ptr profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL); @@ -589,7 +599,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) } // Find an worker class which can handle the file - BaseImporter* imp = NULL; + BaseImporter* imp = nullptr; SetPropertyInteger("importerIndex", -1); for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) { @@ -617,7 +627,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) if( !imp) { pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\"."; ASSIMP_LOG_ERROR(pimpl->mErrorString); - return NULL; + return nullptr; } } @@ -633,7 +643,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) // Dispatch the reading to the worker class for this format const aiImporterDesc *desc( imp->GetInfo() ); std::string ext( "unknown" ); - if ( NULL != desc ) { + if ( nullptr != desc ) { ext = desc->mName; } ASSIMP_LOG_INFO("Found a matching importer for this file format: " + ext + "." ); @@ -654,15 +664,20 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) // If successful, apply all active post processing steps to the imported data if( pimpl->mScene) { + if (!pimpl->mScene->mMetaData || !pimpl->mScene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT)) { + if (!pimpl->mScene->mMetaData) { + pimpl->mScene->mMetaData = new aiMetadata; + } + pimpl->mScene->mMetaData->Add(AI_METADATA_SOURCE_FORMAT, aiString(ext)); + } #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS // The ValidateDS process is an exception. It is executed first, even before ScenePreprocessor is called. - if (pFlags & aiProcess_ValidateDataStructure) - { + if (pFlags & aiProcess_ValidateDataStructure) { ValidateDSProcess ds; ds.ExecuteOnScene (this); if (!pimpl->mScene) { - return NULL; + return nullptr; } } #endif // no validation @@ -695,8 +710,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) } } #ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS - catch (std::exception &e) - { + catch (std::exception &e) { #if (defined _MSC_VER) && (defined _CPPRTTI) // if we have RTTI get the full name of the exception that occurred pimpl->mErrorString = std::string(typeid( e ).name()) + ": " + e.what(); @@ -705,24 +719,26 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) #endif ASSIMP_LOG_ERROR(pimpl->mErrorString); - delete pimpl->mScene; pimpl->mScene = NULL; + delete pimpl->mScene; pimpl->mScene = nullptr; } #endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS // either successful or failure - the pointer expresses it anyways - ASSIMP_END_EXCEPTION_REGION(const aiScene*); + ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString); + return pimpl->mScene; } // ------------------------------------------------------------------------------------------------ // Apply post-processing to the currently bound scene -const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) -{ +const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); // Return immediately if no scene is active if (!pimpl->mScene) { - return NULL; + return nullptr; } // If no flags are given, return the current scene with no further action @@ -737,12 +753,11 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS // The ValidateDS process plays an exceptional role. It isn't contained in the global // list of post-processing steps, so we need to call it manually. - if (pFlags & aiProcess_ValidateDataStructure) - { + if (pFlags & aiProcess_ValidateDataStructure) { ValidateDSProcess ds; ds.ExecuteOnScene (this); if (!pimpl->mScene) { - return NULL; + return nullptr; } } #endif // no validation @@ -762,11 +777,9 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) std::unique_ptr profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL); for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) { - BaseProcess* process = pimpl->mPostProcessingSteps[a]; pimpl->mProgressHandler->UpdatePostProcess(static_cast(a), static_cast(pimpl->mPostProcessingSteps.size()) ); if( process->IsActive( pFlags)) { - if (profiler) { profiler->BeginRegion("postprocess"); } @@ -803,24 +816,28 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) static_cast(pimpl->mPostProcessingSteps.size()) ); // update private scene flags - if( pimpl->mScene ) + if( pimpl->mScene ) { ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags; + } // clear any data allocated by post-process steps pimpl->mPPShared->Clean(); ASSIMP_LOG_INFO("Leaving post processing pipeline"); ASSIMP_END_EXCEPTION_REGION(const aiScene*); + return pimpl->mScene; } // ------------------------------------------------------------------------------------------------ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess, bool requestValidation ) { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); // Return immediately if no scene is active - if ( NULL == pimpl->mScene ) { - return NULL; + if ( nullptr == pimpl->mScene ) { + return nullptr; } // If no flags are given, return the current scene with no further action @@ -839,7 +856,7 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess ValidateDSProcess ds; ds.ExecuteOnScene( this ); if ( !pimpl->mScene ) { - return NULL; + return nullptr; } } #endif // no validation @@ -890,46 +907,50 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess // ------------------------------------------------------------------------------------------------ // Helper function to check whether an extension is supported by ASSIMP -bool Importer::IsExtensionSupported(const char* szExtension) const -{ +bool Importer::IsExtensionSupported(const char* szExtension) const { return nullptr != GetImporter(szExtension); } // ------------------------------------------------------------------------------------------------ -size_t Importer::GetImporterCount() const -{ +size_t Importer::GetImporterCount() const { + ai_assert(nullptr != pimpl); + return pimpl->mImporter.size(); } // ------------------------------------------------------------------------------------------------ -const aiImporterDesc* Importer::GetImporterInfo(size_t index) const -{ +const aiImporterDesc* Importer::GetImporterInfo(size_t index) const { + ai_assert(nullptr != pimpl); + if (index >= pimpl->mImporter.size()) { - return NULL; + return nullptr; } return pimpl->mImporter[index]->GetInfo(); } // ------------------------------------------------------------------------------------------------ -BaseImporter* Importer::GetImporter (size_t index) const -{ +BaseImporter* Importer::GetImporter (size_t index) const { + ai_assert(nullptr != pimpl); + if (index >= pimpl->mImporter.size()) { - return NULL; + return nullptr; } return pimpl->mImporter[index]; } // ------------------------------------------------------------------------------------------------ // Find a loader plugin for a given file extension -BaseImporter* Importer::GetImporter (const char* szExtension) const -{ +BaseImporter* Importer::GetImporter (const char* szExtension) const { + ai_assert(nullptr != pimpl); + return GetImporter(GetImporterIndex(szExtension)); } // ------------------------------------------------------------------------------------------------ // Find a loader plugin for a given file extension size_t Importer::GetImporterIndex (const char* szExtension) const { + ai_assert(nullptr != pimpl); ai_assert(nullptr != szExtension); ASSIMP_BEGIN_EXCEPTION_REGION(); @@ -960,8 +981,9 @@ size_t Importer::GetImporterIndex (const char* szExtension) const { // ------------------------------------------------------------------------------------------------ // Helper function to build a list of all file extensions supported by ASSIMP -void Importer::GetExtensionList(aiString& szOut) const -{ +void Importer::GetExtensionList(aiString& szOut) const { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); std::set str; for (std::vector::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i) { @@ -985,8 +1007,9 @@ void Importer::GetExtensionList(aiString& szOut) const // ------------------------------------------------------------------------------------------------ // Set a configuration property -bool Importer::SetPropertyInteger(const char* szName, int iValue) -{ +bool Importer::SetPropertyInteger(const char* szName, int iValue) { + ai_assert(nullptr != pimpl); + bool existing; ASSIMP_BEGIN_EXCEPTION_REGION(); existing = SetGenericProperty(pimpl->mIntProperties, szName,iValue); @@ -996,8 +1019,9 @@ bool Importer::SetPropertyInteger(const char* szName, int iValue) // ------------------------------------------------------------------------------------------------ // Set a configuration property -bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) -{ +bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) { + ai_assert(nullptr != pimpl); + bool existing; ASSIMP_BEGIN_EXCEPTION_REGION(); existing = SetGenericProperty(pimpl->mFloatProperties, szName,iValue); @@ -1007,8 +1031,9 @@ bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) // ------------------------------------------------------------------------------------------------ // Set a configuration property -bool Importer::SetPropertyString(const char* szName, const std::string& value) -{ +bool Importer::SetPropertyString(const char* szName, const std::string& value) { + ai_assert(nullptr != pimpl); + bool existing; ASSIMP_BEGIN_EXCEPTION_REGION(); existing = SetGenericProperty(pimpl->mStringProperties, szName,value); @@ -1018,8 +1043,9 @@ bool Importer::SetPropertyString(const char* szName, const std::string& value) // ------------------------------------------------------------------------------------------------ // Set a configuration property -bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) -{ +bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) { + ai_assert(nullptr != pimpl); + bool existing; ASSIMP_BEGIN_EXCEPTION_REGION(); existing = SetGenericProperty(pimpl->mMatrixProperties, szName,value); @@ -1029,40 +1055,43 @@ bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) // ------------------------------------------------------------------------------------------------ // Get a configuration property -int Importer::GetPropertyInteger(const char* szName, - int iErrorReturn /*= 0xffffffff*/) const -{ +int Importer::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const { + ai_assert(nullptr != pimpl); + return GetGenericProperty(pimpl->mIntProperties,szName,iErrorReturn); } // ------------------------------------------------------------------------------------------------ // Get a configuration property -ai_real Importer::GetPropertyFloat(const char* szName, - ai_real iErrorReturn /*= 10e10*/) const -{ +ai_real Importer::GetPropertyFloat(const char* szName, ai_real iErrorReturn /*= 10e10*/) const { + ai_assert(nullptr != pimpl); + return GetGenericProperty(pimpl->mFloatProperties,szName,iErrorReturn); } // ------------------------------------------------------------------------------------------------ // Get a configuration property -const std::string Importer::GetPropertyString(const char* szName, - const std::string& iErrorReturn /*= ""*/) const -{ +std::string Importer::GetPropertyString(const char* szName, const std::string& iErrorReturn /*= ""*/) const { + ai_assert(nullptr != pimpl); + return GetGenericProperty(pimpl->mStringProperties,szName,iErrorReturn); } // ------------------------------------------------------------------------------------------------ // Get a configuration property -const aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName, - const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const -{ +aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName, const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const { + ai_assert(nullptr != pimpl); + return GetGenericProperty(pimpl->mMatrixProperties,szName,iErrorReturn); } // ------------------------------------------------------------------------------------------------ // Get the memory requirements of a single node -inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) -{ +inline +void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) { + if ( nullptr == pcNode ) { + return; + } iScene += sizeof(aiNode); iScene += sizeof(unsigned int) * pcNode->mNumMeshes; iScene += sizeof(void*) * pcNode->mNumChildren; @@ -1074,21 +1103,20 @@ inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) // ------------------------------------------------------------------------------------------------ // Get the memory requirements of the scene -void Importer::GetMemoryRequirements(aiMemoryInfo& in) const -{ +void Importer::GetMemoryRequirements(aiMemoryInfo& in) const { + ai_assert(nullptr != pimpl); + in = aiMemoryInfo(); aiScene* mScene = pimpl->mScene; // return if we have no scene loaded - if (!pimpl->mScene) + if (!mScene) return; - in.total = sizeof(aiScene); // add all meshes - for (unsigned int i = 0; i < mScene->mNumMeshes;++i) - { + for (unsigned int i = 0; i < mScene->mNumMeshes;++i) { in.meshes += sizeof(aiMesh); if (mScene->mMeshes[i]->HasPositions()) { in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices; @@ -1105,14 +1133,16 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS;++a) { if (mScene->mMeshes[i]->HasVertexColors(a)) { in.meshes += sizeof(aiColor4D) * mScene->mMeshes[i]->mNumVertices; + } else { + break; } - else break; } for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) { if (mScene->mMeshes[i]->HasTextureCoords(a)) { in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices; + } else { + break; } - else break; } if (mScene->mMeshes[i]->HasBones()) { in.meshes += sizeof(void*) * mScene->mMeshes[i]->mNumBones; @@ -1131,8 +1161,9 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const in.textures += sizeof(aiTexture); if (pc->mHeight) { in.textures += 4 * pc->mHeight * pc->mWidth; + } else { + in.textures += pc->mWidth; } - else in.textures += pc->mWidth; } in.total += in.textures; @@ -1170,5 +1201,6 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const in.materials += pc->mProperties[a]->mDataLength; } } + in.total += in.materials; } diff --git a/Engine/lib/assimp/code/Common/Importer.h b/Engine/lib/assimp/code/Common/Importer.h index a439d99c2..c31f67caa 100644 --- a/Engine/lib/assimp/code/Common/Importer.h +++ b/Engine/lib/assimp/code/Common/Importer.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/ImporterRegistry.cpp b/Engine/lib/assimp/code/Common/ImporterRegistry.cpp index b9f28f035..41aa21979 100644 --- a/Engine/lib/assimp/code/Common/ImporterRegistry.cpp +++ b/Engine/lib/assimp/code/Common/ImporterRegistry.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Common/PolyTools.h b/Engine/lib/assimp/code/Common/PolyTools.h index fbbda0e7d..1b8972877 100644 --- a/Engine/lib/assimp/code/Common/PolyTools.h +++ b/Engine/lib/assimp/code/Common/PolyTools.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/PostStepRegistry.cpp b/Engine/lib/assimp/code/Common/PostStepRegistry.cpp index 8ff4af040..19382165f 100644 --- a/Engine/lib/assimp/code/Common/PostStepRegistry.cpp +++ b/Engine/lib/assimp/code/Common/PostStepRegistry.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team @@ -123,7 +123,7 @@ corresponding preprocessor flag to selectively disable steps. # include "PostProcessing/OptimizeGraph.h" #endif #ifndef ASSIMP_BUILD_NO_SPLITBYBONECOUNT_PROCESS -# include "Common/SplitByBoneCountProcess.h" +# include "PostProcessing/SplitByBoneCountProcess.h" #endif #ifndef ASSIMP_BUILD_NO_DEBONE_PROCESS # include "PostProcessing/DeboneProcess.h" diff --git a/Engine/lib/assimp/code/Common/RemoveComments.cpp b/Engine/lib/assimp/code/Common/RemoveComments.cpp index 91700a769..f7e735c16 100644 --- a/Engine/lib/assimp/code/Common/RemoveComments.cpp +++ b/Engine/lib/assimp/code/Common/RemoveComments.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/SGSpatialSort.cpp b/Engine/lib/assimp/code/Common/SGSpatialSort.cpp index 120070b0a..35ffaae58 100644 --- a/Engine/lib/assimp/code/Common/SGSpatialSort.cpp +++ b/Engine/lib/assimp/code/Common/SGSpatialSort.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Common/SceneCombiner.cpp b/Engine/lib/assimp/code/Common/SceneCombiner.cpp index f7b13cc95..29b6082a8 100644 --- a/Engine/lib/assimp/code/Common/SceneCombiner.cpp +++ b/Engine/lib/assimp/code/Common/SceneCombiner.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -1312,7 +1312,6 @@ void SceneCombiner::Copy(aiMetadata** _dest, const aiMetadata* src) { aiMetadata* dest = *_dest = aiMetadata::Alloc( src->mNumProperties ); std::copy(src->mKeys, src->mKeys + src->mNumProperties, dest->mKeys); - dest->mValues = new aiMetadataEntry[src->mNumProperties]; for (unsigned int i = 0; i < src->mNumProperties; ++i) { aiMetadataEntry& in = src->mValues[i]; aiMetadataEntry& out = dest->mValues[i]; diff --git a/Engine/lib/assimp/code/Common/ScenePreprocessor.cpp b/Engine/lib/assimp/code/Common/ScenePreprocessor.cpp index 432a3d766..606590519 100644 --- a/Engine/lib/assimp/code/Common/ScenePreprocessor.cpp +++ b/Engine/lib/assimp/code/Common/ScenePreprocessor.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -217,6 +217,7 @@ void ScenePreprocessor::ProcessAnimation (aiAnimation* anim) // No rotation keys? Generate a dummy track if (!channel->mNumRotationKeys) { + ai_assert(!channel->mRotationKeys); channel->mNumRotationKeys = 1; channel->mRotationKeys = new aiQuatKey[1]; aiQuatKey& q = channel->mRotationKeys[0]; @@ -225,10 +226,13 @@ void ScenePreprocessor::ProcessAnimation (aiAnimation* anim) q.mValue = rotation; ASSIMP_LOG_DEBUG("ScenePreprocessor: Dummy rotation track has been generated"); + } else { + ai_assert(channel->mRotationKeys); } // No scaling keys? Generate a dummy track if (!channel->mNumScalingKeys) { + ai_assert(!channel->mScalingKeys); channel->mNumScalingKeys = 1; channel->mScalingKeys = new aiVectorKey[1]; aiVectorKey& q = channel->mScalingKeys[0]; @@ -237,10 +241,13 @@ void ScenePreprocessor::ProcessAnimation (aiAnimation* anim) q.mValue = scaling; ASSIMP_LOG_DEBUG("ScenePreprocessor: Dummy scaling track has been generated"); + } else { + ai_assert(channel->mScalingKeys); } // No position keys? Generate a dummy track if (!channel->mNumPositionKeys) { + ai_assert(!channel->mPositionKeys); channel->mNumPositionKeys = 1; channel->mPositionKeys = new aiVectorKey[1]; aiVectorKey& q = channel->mPositionKeys[0]; @@ -249,6 +256,8 @@ void ScenePreprocessor::ProcessAnimation (aiAnimation* anim) q.mValue = position; ASSIMP_LOG_DEBUG("ScenePreprocessor: Dummy position track has been generated"); + } else { + ai_assert(channel->mPositionKeys); } } } diff --git a/Engine/lib/assimp/code/Common/ScenePreprocessor.h b/Engine/lib/assimp/code/Common/ScenePreprocessor.h index 3f4c8d7c3..e059d1c95 100644 --- a/Engine/lib/assimp/code/Common/ScenePreprocessor.h +++ b/Engine/lib/assimp/code/Common/ScenePreprocessor.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/ScenePrivate.h b/Engine/lib/assimp/code/Common/ScenePrivate.h index f336aafc9..f66f48856 100644 --- a/Engine/lib/assimp/code/Common/ScenePrivate.h +++ b/Engine/lib/assimp/code/Common/ScenePrivate.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/SkeletonMeshBuilder.cpp b/Engine/lib/assimp/code/Common/SkeletonMeshBuilder.cpp index 06cfe034e..724359f99 100644 --- a/Engine/lib/assimp/code/Common/SkeletonMeshBuilder.cpp +++ b/Engine/lib/assimp/code/Common/SkeletonMeshBuilder.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/SpatialSort.cpp b/Engine/lib/assimp/code/Common/SpatialSort.cpp index a4f3a4e4b..604b086b7 100644 --- a/Engine/lib/assimp/code/Common/SpatialSort.cpp +++ b/Engine/lib/assimp/code/Common/SpatialSort.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Common/StandardShapes.cpp b/Engine/lib/assimp/code/Common/StandardShapes.cpp index 2e5100130..d474c6129 100644 --- a/Engine/lib/assimp/code/Common/StandardShapes.cpp +++ b/Engine/lib/assimp/code/Common/StandardShapes.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/StdOStreamLogStream.h b/Engine/lib/assimp/code/Common/StdOStreamLogStream.h index 893e261a2..4f5999775 100644 --- a/Engine/lib/assimp/code/Common/StdOStreamLogStream.h +++ b/Engine/lib/assimp/code/Common/StdOStreamLogStream.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Common/Subdivision.cpp b/Engine/lib/assimp/code/Common/Subdivision.cpp index 60c54939f..08408f867 100644 --- a/Engine/lib/assimp/code/Common/Subdivision.cpp +++ b/Engine/lib/assimp/code/Common/Subdivision.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/TargetAnimation.cpp b/Engine/lib/assimp/code/Common/TargetAnimation.cpp index b8062499f..3c61d2176 100644 --- a/Engine/lib/assimp/code/Common/TargetAnimation.cpp +++ b/Engine/lib/assimp/code/Common/TargetAnimation.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/TargetAnimation.h b/Engine/lib/assimp/code/Common/TargetAnimation.h index 91634ab5a..5b9c1881d 100644 --- a/Engine/lib/assimp/code/Common/TargetAnimation.h +++ b/Engine/lib/assimp/code/Common/TargetAnimation.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/Version.cpp b/Engine/lib/assimp/code/Common/Version.cpp index cf1da7d5b..f04d12233 100644 --- a/Engine/lib/assimp/code/Common/Version.cpp +++ b/Engine/lib/assimp/code/Common/Version.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -55,7 +55,7 @@ static const char* LEGAL_INFORMATION = "Open Asset Import Library (Assimp).\n" "A free C/C++ library to import various 3D file formats into applications\n\n" -"(c) 2006-2019, assimp team\n" +"(c) 2006-2020, assimp team\n" "License under the terms and conditions of the 3-clause BSD license\n" "http://assimp.org\n" ; @@ -66,6 +66,12 @@ ASSIMP_API const char* aiGetLegalString () { return LEGAL_INFORMATION; } +// ------------------------------------------------------------------------------------------------ +// Get Assimp patch version +ASSIMP_API unsigned int aiGetVersionPatch() { + return VER_PATCH; +} + // ------------------------------------------------------------------------------------------------ // Get Assimp minor version ASSIMP_API unsigned int aiGetVersionMinor () { diff --git a/Engine/lib/assimp/code/Common/VertexTriangleAdjacency.cpp b/Engine/lib/assimp/code/Common/VertexTriangleAdjacency.cpp index 7cfd1a350..e588dc2a4 100644 --- a/Engine/lib/assimp/code/Common/VertexTriangleAdjacency.cpp +++ b/Engine/lib/assimp/code/Common/VertexTriangleAdjacency.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team @@ -58,7 +58,7 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces, { // compute the number of referenced vertices if it wasn't specified by the caller const aiFace* const pcFaceEnd = pcFaces + iNumFaces; - if (!iNumVertices) { + if (0 == iNumVertices) { for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) { ai_assert( nullptr != pcFace ); ai_assert(3 == pcFace->mNumIndices); @@ -68,7 +68,7 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces, } } - mNumVertices = iNumVertices; + mNumVertices = iNumVertices + 1; unsigned int* pi; diff --git a/Engine/lib/assimp/code/Common/VertexTriangleAdjacency.h b/Engine/lib/assimp/code/Common/VertexTriangleAdjacency.h index f3be47612..2226fc1c4 100644 --- a/Engine/lib/assimp/code/Common/VertexTriangleAdjacency.h +++ b/Engine/lib/assimp/code/Common/VertexTriangleAdjacency.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/Win32DebugLogStream.h b/Engine/lib/assimp/code/Common/Win32DebugLogStream.h index a6063a261..3a9d89c73 100644 --- a/Engine/lib/assimp/code/Common/Win32DebugLogStream.h +++ b/Engine/lib/assimp/code/Common/Win32DebugLogStream.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Common/ZipArchiveIOSystem.cpp b/Engine/lib/assimp/code/Common/ZipArchiveIOSystem.cpp index 7c37a05f9..8d00da912 100644 --- a/Engine/lib/assimp/code/Common/ZipArchiveIOSystem.cpp +++ b/Engine/lib/assimp/code/Common/ZipArchiveIOSystem.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -343,8 +343,6 @@ namespace Assimp { } ZipArchiveIOSystem::Implement::~Implement() { - m_ArchiveMap.clear(); - if (m_ZipFileHandle != nullptr) { unzClose(m_ZipFileHandle); m_ZipFileHandle = nullptr; diff --git a/Engine/lib/assimp/code/Common/assbin_chunks.h b/Engine/lib/assimp/code/Common/assbin_chunks.h index 15e4af5e7..822df5198 100644 --- a/Engine/lib/assimp/code/Common/assbin_chunks.h +++ b/Engine/lib/assimp/code/Common/assbin_chunks.h @@ -37,7 +37,7 @@ The ASSBIN file format is composed of chunks to represent the hierarchical aiSce This makes the format extensible and allows backward-compatibility with future data structure versions. The <root>/code/assbin_chunks.h header contains some magic constants for use by stand-alone ASSBIN loaders. Also, Assimp's own file writer can be found -in <root>/tools/assimp_cmd/WriteDumb.cpp (yes, the 'b' is no typo ...). +in <root>/tools/assimp_cmd/WriteDump.cpp (yes, the 'b' is no typo ...). @verbatim diff --git a/Engine/lib/assimp/code/Common/material.cpp b/Engine/lib/assimp/code/Common/material.cpp new file mode 100644 index 000000000..f4a29dacf --- /dev/null +++ b/Engine/lib/assimp/code/Common/material.cpp @@ -0,0 +1,97 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +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. + +---------------------------------------------------------------------- +*/ + +/// @file material.cpp +/** Implement common material related functions. */ + +#include +#include + +// ------------------------------------------------------------------------------- +const char* TextureTypeToString(aiTextureType in) +{ + switch (in) + { + case aiTextureType_NONE: + return "n/a"; + case aiTextureType_DIFFUSE: + return "Diffuse"; + case aiTextureType_SPECULAR: + return "Specular"; + case aiTextureType_AMBIENT: + return "Ambient"; + case aiTextureType_EMISSIVE: + return "Emissive"; + case aiTextureType_OPACITY: + return "Opacity"; + case aiTextureType_NORMALS: + return "Normals"; + case aiTextureType_HEIGHT: + return "Height"; + case aiTextureType_SHININESS: + return "Shininess"; + case aiTextureType_DISPLACEMENT: + return "Displacement"; + case aiTextureType_LIGHTMAP: + return "Lightmap"; + case aiTextureType_REFLECTION: + return "Reflection"; + case aiTextureType_BASE_COLOR: + return "BaseColor"; + case aiTextureType_NORMAL_CAMERA: + return "NormalCamera"; + case aiTextureType_EMISSION_COLOR: + return "EmissionColor"; + case aiTextureType_METALNESS: + return "Metalness"; + case aiTextureType_DIFFUSE_ROUGHNESS: + return "DiffuseRoughness"; + case aiTextureType_AMBIENT_OCCLUSION: + return "AmbientOcclusion"; + case aiTextureType_UNKNOWN: + return "Unknown"; + default: + break; + } + ai_assert(false); + return "BUG"; +} diff --git a/Engine/lib/assimp/code/Common/scene.cpp b/Engine/lib/assimp/code/Common/scene.cpp index d15619acf..f56562b1c 100644 --- a/Engine/lib/assimp/code/Common/scene.cpp +++ b/Engine/lib/assimp/code/Common/scene.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Common/simd.cpp b/Engine/lib/assimp/code/Common/simd.cpp index 04615f408..305445970 100644 --- a/Engine/lib/assimp/code/Common/simd.cpp +++ b/Engine/lib/assimp/code/Common/simd.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Common/simd.h b/Engine/lib/assimp/code/Common/simd.h index 3eecdd458..17856fe72 100644 --- a/Engine/lib/assimp/code/Common/simd.h +++ b/Engine/lib/assimp/code/Common/simd.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/DXF/DXFHelper.h b/Engine/lib/assimp/code/DXF/DXFHelper.h index 0ec8e130b..8140d00c6 100644 --- a/Engine/lib/assimp/code/DXF/DXFHelper.h +++ b/Engine/lib/assimp/code/DXF/DXFHelper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/DXF/DXFLoader.cpp b/Engine/lib/assimp/code/DXF/DXFLoader.cpp index baf315485..ea877a484 100644 --- a/Engine/lib/assimp/code/DXF/DXFLoader.cpp +++ b/Engine/lib/assimp/code/DXF/DXFLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/DXF/DXFLoader.h b/Engine/lib/assimp/code/DXF/DXFLoader.h index 044cf6bcb..5c4f1787e 100644 --- a/Engine/lib/assimp/code/DXF/DXFLoader.h +++ b/Engine/lib/assimp/code/DXF/DXFLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXAnimation.cpp b/Engine/lib/assimp/code/FBX/FBXAnimation.cpp index 874914431..9a54f61a0 100644 --- a/Engine/lib/assimp/code/FBX/FBXAnimation.cpp +++ b/Engine/lib/assimp/code/FBX/FBXAnimation.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXBinaryTokenizer.cpp b/Engine/lib/assimp/code/FBX/FBXBinaryTokenizer.cpp index a4a2bc8e7..7faa0518b 100644 --- a/Engine/lib/assimp/code/FBX/FBXBinaryTokenizer.cpp +++ b/Engine/lib/assimp/code/FBX/FBXBinaryTokenizer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXCommon.h b/Engine/lib/assimp/code/FBX/FBXCommon.h index b28601c74..7f70eb784 100644 --- a/Engine/lib/assimp/code/FBX/FBXCommon.h +++ b/Engine/lib/assimp/code/FBX/FBXCommon.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXCompileConfig.h b/Engine/lib/assimp/code/FBX/FBXCompileConfig.h index 03536a182..5cdaa6960 100644 --- a/Engine/lib/assimp/code/FBX/FBXCompileConfig.h +++ b/Engine/lib/assimp/code/FBX/FBXCompileConfig.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXConverter.cpp b/Engine/lib/assimp/code/FBX/FBXConverter.cpp index d8a22d9f7..22616a480 100644 --- a/Engine/lib/assimp/code/FBX/FBXConverter.cpp +++ b/Engine/lib/assimp/code/FBX/FBXConverter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -60,6 +60,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include +#include #include #include @@ -1562,7 +1564,7 @@ namespace Assimp { bone_map.clear(); } - catch (std::exception&e) { + catch (std::exception&) { std::for_each(bones.begin(), bones.end(), Util::delete_fun()); throw; } @@ -1597,12 +1599,11 @@ namespace Assimp { aiBone *bone = nullptr; if (bone_map.count(deformer_name)) { - std::cout << "retrieved bone from lookup " << bone_name.C_Str() << ". Deformer: " << deformer_name - << std::endl; - bone = bone_map[deformer_name]; - } else { - std::cout << "created new bone " << bone_name.C_Str() << ". Deformer: " << deformer_name << std::endl; - bone = new aiBone(); + ASSIMP_LOG_DEBUG_F("retrieved bone from lookup ", bone_name.C_Str(), ". Deformer:", deformer_name); + bone = bone_map[deformer_name]; + } else { + ASSIMP_LOG_DEBUG_F("created new bone ", bone_name.C_Str(), ". Deformer: ", deformer_name); + bone = new aiBone(); bone->mName = bone_name; // store local transform link for post processing @@ -1648,7 +1649,7 @@ namespace Assimp { bone_map.insert(std::pair(deformer_name, bone)); } - std::cout << "bone research: Indicies size: " << out_indices.size() << std::endl; + ASSIMP_LOG_DEBUG_F("bone research: Indicies size: ", out_indices.size()); // lookup must be populated in case something goes wrong // this also allocates bones to mesh instance outside @@ -2087,7 +2088,14 @@ namespace Assimp { TrySetTextureProperties(out_mat, textures, "Maya|TEX_emissive_map|file", aiTextureType_EMISSION_COLOR, mesh); TrySetTextureProperties(out_mat, textures, "Maya|TEX_metallic_map|file", aiTextureType_METALNESS, mesh); TrySetTextureProperties(out_mat, textures, "Maya|TEX_roughness_map|file", aiTextureType_DIFFUSE_ROUGHNESS, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|TEX_ao_map|file", aiTextureType_AMBIENT_OCCLUSION, mesh); + TrySetTextureProperties(out_mat, textures, "Maya|TEX_ao_map|file", aiTextureType_AMBIENT_OCCLUSION, mesh); + + // 3DSMax PBR + TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|base_color_map", aiTextureType_BASE_COLOR, mesh); + TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|bump_map", aiTextureType_NORMAL_CAMERA, mesh); + TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|emission_map", aiTextureType_EMISSION_COLOR, mesh); + TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|metalness_map", aiTextureType_METALNESS, mesh); + TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|roughness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh); } void FBXConverter::SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh) @@ -3604,7 +3612,9 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa return; } - out->mMetaData = aiMetadata::Alloc(15); + const bool hasGenerator = !doc.Creator().empty(); + + out->mMetaData = aiMetadata::Alloc(16 + (hasGenerator ? 1 : 0)); out->mMetaData->Set(0, "UpAxis", doc.GlobalSettings().UpAxis()); out->mMetaData->Set(1, "UpAxisSign", doc.GlobalSettings().UpAxisSign()); out->mMetaData->Set(2, "FrontAxis", doc.GlobalSettings().FrontAxis()); @@ -3620,6 +3630,11 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa out->mMetaData->Set(12, "TimeSpanStart", doc.GlobalSettings().TimeSpanStart()); out->mMetaData->Set(13, "TimeSpanStop", doc.GlobalSettings().TimeSpanStop()); out->mMetaData->Set(14, "CustomFrameRate", doc.GlobalSettings().CustomFrameRate()); + out->mMetaData->Set(15, AI_METADATA_SOURCE_FORMAT_VERSION, aiString(to_string(doc.FBXVersion()))); + if (hasGenerator) + { + out->mMetaData->Set(16, AI_METADATA_SOURCE_GENERATOR, aiString(doc.Creator())); + } } void FBXConverter::TransferDataToScene() diff --git a/Engine/lib/assimp/code/FBX/FBXConverter.h b/Engine/lib/assimp/code/FBX/FBXConverter.h index 46693bdca..c5ad47059 100644 --- a/Engine/lib/assimp/code/FBX/FBXConverter.h +++ b/Engine/lib/assimp/code/FBX/FBXConverter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -421,6 +421,8 @@ private: double& minTime, Model::RotOrder order); + // ------------------------------------------------------------------------------------------------ + // Copy global geometric data and some information about the source asset into scene metadata. void ConvertGlobalSettings(); // ------------------------------------------------------------------------------------------------ diff --git a/Engine/lib/assimp/code/FBX/FBXDeformer.cpp b/Engine/lib/assimp/code/FBX/FBXDeformer.cpp index 692755345..4b76cd0fa 100644 --- a/Engine/lib/assimp/code/FBX/FBXDeformer.cpp +++ b/Engine/lib/assimp/code/FBX/FBXDeformer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXDocument.cpp b/Engine/lib/assimp/code/FBX/FBXDocument.cpp index 506fd978d..ddb971b3f 100644 --- a/Engine/lib/assimp/code/FBX/FBXDocument.cpp +++ b/Engine/lib/assimp/code/FBX/FBXDocument.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXDocument.h b/Engine/lib/assimp/code/FBX/FBXDocument.h index a60d7d9ef..8984b3df7 100644 --- a/Engine/lib/assimp/code/FBX/FBXDocument.h +++ b/Engine/lib/assimp/code/FBX/FBXDocument.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXDocumentUtil.cpp b/Engine/lib/assimp/code/FBX/FBXDocumentUtil.cpp index f84691479..7178e9f26 100644 --- a/Engine/lib/assimp/code/FBX/FBXDocumentUtil.cpp +++ b/Engine/lib/assimp/code/FBX/FBXDocumentUtil.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXDocumentUtil.h b/Engine/lib/assimp/code/FBX/FBXDocumentUtil.h index 2450109e5..2d76ee031 100644 --- a/Engine/lib/assimp/code/FBX/FBXDocumentUtil.h +++ b/Engine/lib/assimp/code/FBX/FBXDocumentUtil.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/FBX/FBXExportNode.cpp b/Engine/lib/assimp/code/FBX/FBXExportNode.cpp index 9b29995cc..53aa719f4 100644 --- a/Engine/lib/assimp/code/FBX/FBXExportNode.cpp +++ b/Engine/lib/assimp/code/FBX/FBXExportNode.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXExportNode.h b/Engine/lib/assimp/code/FBX/FBXExportNode.h index ef3bc781a..2e8f491a1 100644 --- a/Engine/lib/assimp/code/FBX/FBXExportNode.h +++ b/Engine/lib/assimp/code/FBX/FBXExportNode.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXExportProperty.cpp b/Engine/lib/assimp/code/FBX/FBXExportProperty.cpp index f2a63b72b..11ee35003 100644 --- a/Engine/lib/assimp/code/FBX/FBXExportProperty.cpp +++ b/Engine/lib/assimp/code/FBX/FBXExportProperty.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXExportProperty.h b/Engine/lib/assimp/code/FBX/FBXExportProperty.h index d692fe6ee..6baae8b69 100644 --- a/Engine/lib/assimp/code/FBX/FBXExportProperty.h +++ b/Engine/lib/assimp/code/FBX/FBXExportProperty.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXExporter.cpp b/Engine/lib/assimp/code/FBX/FBXExporter.cpp index 9767f9a0a..594951e78 100644 --- a/Engine/lib/assimp/code/FBX/FBXExporter.cpp +++ b/Engine/lib/assimp/code/FBX/FBXExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -1860,6 +1860,7 @@ void FBXExporter::WriteObjects () sdnode.AddChild("Version", int32_t(100)); sdnode.AddChild("UserData", "", ""); + std::set setWeightedVertex; // add indices and weights, if any if (b) { std::vector subdef_indices; @@ -1867,7 +1868,8 @@ void FBXExporter::WriteObjects () int32_t last_index = -1; for (size_t wi = 0; wi < b->mNumWeights; ++wi) { int32_t vi = vertex_indices[b->mWeights[wi].mVertexId]; - if (vi == last_index) { + bool bIsWeightedAlready = (setWeightedVertex.find(vi) != setWeightedVertex.end()); + if (vi == last_index || bIsWeightedAlready) { // only for vertices we exported to fbx // TODO, FIXME: this assumes identically-located vertices // will always deform in the same way. @@ -1877,6 +1879,7 @@ void FBXExporter::WriteObjects () // identical vertex. continue; } + setWeightedVertex.insert(vi); subdef_indices.push_back(vi); subdef_weights.push_back(b->mWeights[wi].mWeight); last_index = vi; diff --git a/Engine/lib/assimp/code/FBX/FBXExporter.h b/Engine/lib/assimp/code/FBX/FBXExporter.h index 1ae727eda..eb8bfaf3b 100644 --- a/Engine/lib/assimp/code/FBX/FBXExporter.h +++ b/Engine/lib/assimp/code/FBX/FBXExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXImportSettings.h b/Engine/lib/assimp/code/FBX/FBXImportSettings.h index 1a4c80f8b..974931b4c 100644 --- a/Engine/lib/assimp/code/FBX/FBXImportSettings.h +++ b/Engine/lib/assimp/code/FBX/FBXImportSettings.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXImporter.cpp b/Engine/lib/assimp/code/FBX/FBXImporter.cpp index afcc1ddc7..571f60883 100644 --- a/Engine/lib/assimp/code/FBX/FBXImporter.cpp +++ b/Engine/lib/assimp/code/FBX/FBXImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXImporter.h b/Engine/lib/assimp/code/FBX/FBXImporter.h index c365b2cdd..63375e40d 100644 --- a/Engine/lib/assimp/code/FBX/FBXImporter.h +++ b/Engine/lib/assimp/code/FBX/FBXImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXMaterial.cpp b/Engine/lib/assimp/code/FBX/FBXMaterial.cpp index f43a8b84b..88ac9db16 100644 --- a/Engine/lib/assimp/code/FBX/FBXMaterial.cpp +++ b/Engine/lib/assimp/code/FBX/FBXMaterial.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXMeshGeometry.cpp b/Engine/lib/assimp/code/FBX/FBXMeshGeometry.cpp index 1386e2383..4a3de9f99 100644 --- a/Engine/lib/assimp/code/FBX/FBXMeshGeometry.cpp +++ b/Engine/lib/assimp/code/FBX/FBXMeshGeometry.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -446,14 +446,19 @@ void ResolveVertexDataArray(std::vector& data_out, const Scope& source, return; } std::vector tempData; - ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); + ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); + + if (tempData.size() != mapping_offsets.size()) { + FBXImporter::LogError(Formatter::format("length of input data unexpected for ByVertice mapping: ") + << tempData.size() << ", expected " << mapping_offsets.size()); + return; + } data_out.resize(vertex_count); - for (size_t i = 0, e = tempData.size(); i < e; ++i) { - + for (size_t i = 0, e = tempData.size(); i < e; ++i) { const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i]; for (unsigned int j = istart; j < iend; ++j) { - data_out[mappings[j]] = tempData[i]; + data_out[mappings[j]] = tempData[i]; } } } @@ -461,10 +466,17 @@ void ResolveVertexDataArray(std::vector& data_out, const Scope& source, std::vector tempData; ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); - data_out.resize(vertex_count); - std::vector uvIndices; ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName)); + + if (uvIndices.size() != vertex_count) { + FBXImporter::LogError(Formatter::format("length of input data unexpected for ByVertice mapping: ") + << uvIndices.size() << ", expected " << vertex_count); + return; + } + + data_out.resize(vertex_count); + for (size_t i = 0, e = uvIndices.size(); i < e; ++i) { const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i]; @@ -493,16 +505,17 @@ void ResolveVertexDataArray(std::vector& data_out, const Scope& source, std::vector tempData; ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); - data_out.resize(vertex_count); - std::vector uvIndices; ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName)); if (uvIndices.size() != vertex_count) { - FBXImporter::LogError("length of input data unexpected for ByPolygonVertex mapping"); + FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygonVertex mapping: ") + << uvIndices.size() << ", expected " << vertex_count); return; } + data_out.resize(vertex_count); + const T empty; unsigned int next = 0; for(int i : uvIndices) { diff --git a/Engine/lib/assimp/code/FBX/FBXMeshGeometry.h b/Engine/lib/assimp/code/FBX/FBXMeshGeometry.h index d6d451217..97265e4b2 100644 --- a/Engine/lib/assimp/code/FBX/FBXMeshGeometry.h +++ b/Engine/lib/assimp/code/FBX/FBXMeshGeometry.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXModel.cpp b/Engine/lib/assimp/code/FBX/FBXModel.cpp index 589af36ac..e34f3a610 100644 --- a/Engine/lib/assimp/code/FBX/FBXModel.cpp +++ b/Engine/lib/assimp/code/FBX/FBXModel.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXNodeAttribute.cpp b/Engine/lib/assimp/code/FBX/FBXNodeAttribute.cpp index b72e5637e..2ebf917e3 100644 --- a/Engine/lib/assimp/code/FBX/FBXNodeAttribute.cpp +++ b/Engine/lib/assimp/code/FBX/FBXNodeAttribute.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXParser.cpp b/Engine/lib/assimp/code/FBX/FBXParser.cpp index 4a9346040..aef59d60c 100644 --- a/Engine/lib/assimp/code/FBX/FBXParser.cpp +++ b/Engine/lib/assimp/code/FBX/FBXParser.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -367,9 +367,13 @@ float ParseTokenAsFloat(const Token& t, const char*& err_out) // first - next in the fbx token stream comes ',', // which fast_atof could interpret as decimal point. #define MAX_FLOAT_LENGTH 31 - char temp[MAX_FLOAT_LENGTH + 1]; const size_t length = static_cast(t.end()-t.begin()); - std::copy(t.begin(),t.end(),temp); + if (length > MAX_FLOAT_LENGTH) { + return 0.f; + } + + char temp[MAX_FLOAT_LENGTH + 1]; + std::copy(t.begin(), t.end(), temp); temp[std::min(static_cast(MAX_FLOAT_LENGTH),length)] = '\0'; return fast_atof(temp); diff --git a/Engine/lib/assimp/code/FBX/FBXParser.h b/Engine/lib/assimp/code/FBX/FBXParser.h index 7b0cf7203..5d8d00307 100644 --- a/Engine/lib/assimp/code/FBX/FBXParser.h +++ b/Engine/lib/assimp/code/FBX/FBXParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXProperties.cpp b/Engine/lib/assimp/code/FBX/FBXProperties.cpp index 8d7036b6a..f6b804894 100644 --- a/Engine/lib/assimp/code/FBX/FBXProperties.cpp +++ b/Engine/lib/assimp/code/FBX/FBXProperties.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXProperties.h b/Engine/lib/assimp/code/FBX/FBXProperties.h index 58755542f..209d5e940 100644 --- a/Engine/lib/assimp/code/FBX/FBXProperties.h +++ b/Engine/lib/assimp/code/FBX/FBXProperties.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXTokenizer.cpp b/Engine/lib/assimp/code/FBX/FBXTokenizer.cpp index 252cce355..831c40061 100644 --- a/Engine/lib/assimp/code/FBX/FBXTokenizer.cpp +++ b/Engine/lib/assimp/code/FBX/FBXTokenizer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXTokenizer.h b/Engine/lib/assimp/code/FBX/FBXTokenizer.h index afa588a47..cadc82770 100644 --- a/Engine/lib/assimp/code/FBX/FBXTokenizer.h +++ b/Engine/lib/assimp/code/FBX/FBXTokenizer.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXUtil.cpp b/Engine/lib/assimp/code/FBX/FBXUtil.cpp index c10e057c8..50dd78a4c 100644 --- a/Engine/lib/assimp/code/FBX/FBXUtil.cpp +++ b/Engine/lib/assimp/code/FBX/FBXUtil.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXUtil.h b/Engine/lib/assimp/code/FBX/FBXUtil.h index b63441885..77bb0ad30 100644 --- a/Engine/lib/assimp/code/FBX/FBXUtil.h +++ b/Engine/lib/assimp/code/FBX/FBXUtil.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/HMP/HMPFileData.h b/Engine/lib/assimp/code/HMP/HMPFileData.h index ab4100174..bad8dde5c 100644 --- a/Engine/lib/assimp/code/HMP/HMPFileData.h +++ b/Engine/lib/assimp/code/HMP/HMPFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/HMP/HMPLoader.cpp b/Engine/lib/assimp/code/HMP/HMPLoader.cpp index d5469181e..0d1334fdd 100644 --- a/Engine/lib/assimp/code/HMP/HMPLoader.cpp +++ b/Engine/lib/assimp/code/HMP/HMPLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/HMP/HMPLoader.h b/Engine/lib/assimp/code/HMP/HMPLoader.h index 421826c91..0371a608b 100644 --- a/Engine/lib/assimp/code/HMP/HMPLoader.h +++ b/Engine/lib/assimp/code/HMP/HMPLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/HMP/HalfLifeFileData.h b/Engine/lib/assimp/code/HMP/HalfLifeFileData.h index ef328edf8..d7db1476c 100644 --- a/Engine/lib/assimp/code/HMP/HalfLifeFileData.h +++ b/Engine/lib/assimp/code/HMP/HalfLifeFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCBoolean.cpp b/Engine/lib/assimp/code/Importer/IFC/IFCBoolean.cpp index 10e7bf3af..01fd43cd2 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCBoolean.cpp +++ b/Engine/lib/assimp/code/Importer/IFC/IFCBoolean.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2010, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCCurve.cpp b/Engine/lib/assimp/code/Importer/IFC/IFCCurve.cpp index a817b4f9f..b16df9c5c 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCCurve.cpp +++ b/Engine/lib/assimp/code/Importer/IFC/IFCCurve.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -323,7 +323,7 @@ public: // oh well. bool have_param = false, have_point = false; IfcVector3 point; - for(const Entry sel :entity.Trim1) { + for(const Entry& sel :entity.Trim1) { if (const ::Assimp::STEP::EXPRESS::REAL* const r = sel->ToPtr<::Assimp::STEP::EXPRESS::REAL>()) { range.first = *r; have_param = true; @@ -340,7 +340,7 @@ public: } } have_param = false, have_point = false; - for(const Entry sel :entity.Trim2) { + for(const Entry& sel :entity.Trim2) { if (const ::Assimp::STEP::EXPRESS::REAL* const r = sel->ToPtr<::Assimp::STEP::EXPRESS::REAL>()) { range.second = *r; have_param = true; diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCGeometry.cpp b/Engine/lib/assimp/code/Importer/IFC/IFCGeometry.cpp index d1c7aee19..bb4d74758 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCGeometry.cpp +++ b/Engine/lib/assimp/code/Importer/IFC/IFCGeometry.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2010, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -138,8 +138,9 @@ void ProcessPolygonBoundaries(TempMesh& result, const TempMesh& inmesh, size_t m } } } - - ai_assert(outer_polygon_it != end); + if (outer_polygon_it == end) { + return; + } const size_t outer_polygon_size = *outer_polygon_it; const IfcVector3& master_normal = normals[std::distance(begin, outer_polygon_it)]; diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCLoader.cpp b/Engine/lib/assimp/code/Importer/IFC/IFCLoader.cpp index 5c705c256..5dd19f320 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCLoader.cpp +++ b/Engine/lib/assimp/code/Importer/IFC/IFCLoader.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCLoader.h b/Engine/lib/assimp/code/Importer/IFC/IFCLoader.h index 678c60343..4abfe00f1 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCLoader.h +++ b/Engine/lib/assimp/code/Importer/IFC/IFCLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCMaterial.cpp b/Engine/lib/assimp/code/Importer/IFC/IFCMaterial.cpp index 5fda0a1de..832712cd4 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCMaterial.cpp +++ b/Engine/lib/assimp/code/Importer/IFC/IFCMaterial.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCOpenings.cpp b/Engine/lib/assimp/code/Importer/IFC/IFCOpenings.cpp index d6c40b383..2c6754287 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCOpenings.cpp +++ b/Engine/lib/assimp/code/Importer/IFC/IFCOpenings.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2010, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCProfile.cpp b/Engine/lib/assimp/code/Importer/IFC/IFCProfile.cpp index daafc9afe..a1a1b3967 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCProfile.cpp +++ b/Engine/lib/assimp/code/Importer/IFC/IFCProfile.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen1_2x3.cpp b/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen1_2x3.cpp index f4dbed1d1..58ff47113 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen1_2x3.cpp +++ b/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen1_2x3.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2010, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen2_2x3.cpp b/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen2_2x3.cpp index 7dabe278e..e6687014d 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen2_2x3.cpp +++ b/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen2_2x3.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2010, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_2x3.h b/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_2x3.h index 8b39ccdc2..4605b94cf 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_2x3.h +++ b/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_2x3.h @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2010, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_4.cpp b/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_4.cpp index fdefedb18..9eb3e2446 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_4.cpp +++ b/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_4.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2010, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_4.h b/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_4.h index ccfcb6ea0..0f184cd02 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_4.h +++ b/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_4.h @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2010, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCUtil.cpp b/Engine/lib/assimp/code/Importer/IFC/IFCUtil.cpp index f6bca91f5..3557b4baa 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCUtil.cpp +++ b/Engine/lib/assimp/code/Importer/IFC/IFCUtil.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCUtil.h b/Engine/lib/assimp/code/Importer/IFC/IFCUtil.h index 32ae1e07f..cf8c94293 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCUtil.h +++ b/Engine/lib/assimp/code/Importer/IFC/IFCUtil.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Importer/STEPParser/STEPFileEncoding.cpp b/Engine/lib/assimp/code/Importer/STEPParser/STEPFileEncoding.cpp index 101dcdfd7..d917c28f3 100644 --- a/Engine/lib/assimp/code/Importer/STEPParser/STEPFileEncoding.cpp +++ b/Engine/lib/assimp/code/Importer/STEPParser/STEPFileEncoding.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Importer/STEPParser/STEPFileEncoding.h b/Engine/lib/assimp/code/Importer/STEPParser/STEPFileEncoding.h index 09f16ba33..a076d1ce9 100644 --- a/Engine/lib/assimp/code/Importer/STEPParser/STEPFileEncoding.h +++ b/Engine/lib/assimp/code/Importer/STEPParser/STEPFileEncoding.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Importer/STEPParser/STEPFileReader.cpp b/Engine/lib/assimp/code/Importer/STEPParser/STEPFileReader.cpp index f099d2be7..72f882d6e 100644 --- a/Engine/lib/assimp/code/Importer/STEPParser/STEPFileReader.cpp +++ b/Engine/lib/assimp/code/Importer/STEPParser/STEPFileReader.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Importer/STEPParser/STEPFileReader.h b/Engine/lib/assimp/code/Importer/STEPParser/STEPFileReader.h index 9c4b77241..62292792a 100644 --- a/Engine/lib/assimp/code/Importer/STEPParser/STEPFileReader.h +++ b/Engine/lib/assimp/code/Importer/STEPParser/STEPFileReader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Importer/StepFile/StepFileGen1.cpp b/Engine/lib/assimp/code/Importer/StepFile/StepFileGen1.cpp index 50c54818e..234300700 100644 --- a/Engine/lib/assimp/code/Importer/StepFile/StepFileGen1.cpp +++ b/Engine/lib/assimp/code/Importer/StepFile/StepFileGen1.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Importer/StepFile/StepFileGen2.cpp b/Engine/lib/assimp/code/Importer/StepFile/StepFileGen2.cpp index eca09e4e1..a80bb69ef 100644 --- a/Engine/lib/assimp/code/Importer/StepFile/StepFileGen2.cpp +++ b/Engine/lib/assimp/code/Importer/StepFile/StepFileGen2.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2010, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Importer/StepFile/StepFileGen3.cpp b/Engine/lib/assimp/code/Importer/StepFile/StepFileGen3.cpp index d8d81141f..2f25683a8 100644 --- a/Engine/lib/assimp/code/Importer/StepFile/StepFileGen3.cpp +++ b/Engine/lib/assimp/code/Importer/StepFile/StepFileGen3.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2010, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Importer/StepFile/StepFileImporter.cpp b/Engine/lib/assimp/code/Importer/StepFile/StepFileImporter.cpp index 26c456ac9..28744c785 100644 --- a/Engine/lib/assimp/code/Importer/StepFile/StepFileImporter.cpp +++ b/Engine/lib/assimp/code/Importer/StepFile/StepFileImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Importer/StepFile/StepFileImporter.h b/Engine/lib/assimp/code/Importer/StepFile/StepFileImporter.h index 70f65fdcf..c6ac08bb6 100644 --- a/Engine/lib/assimp/code/Importer/StepFile/StepFileImporter.h +++ b/Engine/lib/assimp/code/Importer/StepFile/StepFileImporter.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Importer/StepFile/StepReaderGen.h b/Engine/lib/assimp/code/Importer/StepFile/StepReaderGen.h index 9eb86c332..cb1034e2b 100644 --- a/Engine/lib/assimp/code/Importer/StepFile/StepReaderGen.h +++ b/Engine/lib/assimp/code/Importer/StepFile/StepReaderGen.h @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Irr/IRRLoader.cpp b/Engine/lib/assimp/code/Irr/IRRLoader.cpp index e94fd85a4..4361d578a 100644 --- a/Engine/lib/assimp/code/Irr/IRRLoader.cpp +++ b/Engine/lib/assimp/code/Irr/IRRLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Irr/IRRLoader.h b/Engine/lib/assimp/code/Irr/IRRLoader.h index b3ad81a7d..fc6f77031 100644 --- a/Engine/lib/assimp/code/Irr/IRRLoader.h +++ b/Engine/lib/assimp/code/Irr/IRRLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Irr/IRRMeshLoader.cpp b/Engine/lib/assimp/code/Irr/IRRMeshLoader.cpp index 057218464..13db70e91 100644 --- a/Engine/lib/assimp/code/Irr/IRRMeshLoader.cpp +++ b/Engine/lib/assimp/code/Irr/IRRMeshLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Irr/IRRMeshLoader.h b/Engine/lib/assimp/code/Irr/IRRMeshLoader.h index d8b42d78d..f0d249f71 100644 --- a/Engine/lib/assimp/code/Irr/IRRMeshLoader.h +++ b/Engine/lib/assimp/code/Irr/IRRMeshLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Irr/IRRShared.cpp b/Engine/lib/assimp/code/Irr/IRRShared.cpp index ecac031ab..5dacc2ae1 100644 --- a/Engine/lib/assimp/code/Irr/IRRShared.cpp +++ b/Engine/lib/assimp/code/Irr/IRRShared.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/LWO/LWOAnimation.cpp b/Engine/lib/assimp/code/LWO/LWOAnimation.cpp index 3a0d2c392..ae9c4c13b 100644 --- a/Engine/lib/assimp/code/LWO/LWOAnimation.cpp +++ b/Engine/lib/assimp/code/LWO/LWOAnimation.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/LWO/LWOAnimation.h b/Engine/lib/assimp/code/LWO/LWOAnimation.h index dd29695cc..a46787965 100644 --- a/Engine/lib/assimp/code/LWO/LWOAnimation.h +++ b/Engine/lib/assimp/code/LWO/LWOAnimation.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/LWO/LWOBLoader.cpp b/Engine/lib/assimp/code/LWO/LWOBLoader.cpp index b24957072..fe542df1b 100644 --- a/Engine/lib/assimp/code/LWO/LWOBLoader.cpp +++ b/Engine/lib/assimp/code/LWO/LWOBLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/LWO/LWOFileData.h b/Engine/lib/assimp/code/LWO/LWOFileData.h index 7d1f6b1df..33fac8c39 100644 --- a/Engine/lib/assimp/code/LWO/LWOFileData.h +++ b/Engine/lib/assimp/code/LWO/LWOFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/LWO/LWOLoader.cpp b/Engine/lib/assimp/code/LWO/LWOLoader.cpp index 1e5b92c32..cb581f7f5 100644 --- a/Engine/lib/assimp/code/LWO/LWOLoader.cpp +++ b/Engine/lib/assimp/code/LWO/LWOLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team @@ -586,7 +586,6 @@ void LWOImporter::GenerateNodeGraph(std::map& apcNodes) root->mName.Set(""); //Set parent of all children, inserting pivots - //std::cout << "Set parent of all children" << std::endl; std::map mapPivot; for (auto itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) { @@ -618,7 +617,6 @@ void LWOImporter::GenerateNodeGraph(std::map& apcNodes) } //Merge pivot map into node map - //std::cout << "Merge pivot map into node map" << std::endl; for (auto itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end(); ++itMapPivot) { apcNodes[itMapPivot->first] = itMapPivot->second; } diff --git a/Engine/lib/assimp/code/LWO/LWOLoader.h b/Engine/lib/assimp/code/LWO/LWOLoader.h index 05b958fd2..680f82923 100644 --- a/Engine/lib/assimp/code/LWO/LWOLoader.h +++ b/Engine/lib/assimp/code/LWO/LWOLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/LWO/LWOMaterial.cpp b/Engine/lib/assimp/code/LWO/LWOMaterial.cpp index b54c21c26..b2304a6be 100644 --- a/Engine/lib/assimp/code/LWO/LWOMaterial.cpp +++ b/Engine/lib/assimp/code/LWO/LWOMaterial.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/LWS/LWSLoader.cpp b/Engine/lib/assimp/code/LWS/LWSLoader.cpp index b52cafa6d..4a9cec4ec 100644 --- a/Engine/lib/assimp/code/LWS/LWSLoader.cpp +++ b/Engine/lib/assimp/code/LWS/LWSLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/LWS/LWSLoader.h b/Engine/lib/assimp/code/LWS/LWSLoader.h index eed0491f3..c1321af37 100644 --- a/Engine/lib/assimp/code/LWS/LWSLoader.h +++ b/Engine/lib/assimp/code/LWS/LWSLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/M3D/M3DExporter.cpp b/Engine/lib/assimp/code/M3D/M3DExporter.cpp index c22943396..08a0e4ad8 100644 --- a/Engine/lib/assimp/code/M3D/M3DExporter.cpp +++ b/Engine/lib/assimp/code/M3D/M3DExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team Copyright (c) 2019 bzt All rights reserved. @@ -45,7 +45,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define M3D_IMPLEMENTATION #define M3D_NOIMPORTER #define M3D_EXPORTER -#define M3D_ASCII #ifndef ASSIMP_BUILD_NO_M3D_IMPORTER #define M3D_NODUP #endif @@ -55,15 +54,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include // aiGetVersion -#include -#include -#include -#include // StreamWriterLE #include // DeadlyExportError +#include // StreamWriterLE #include // aiTextureType -#include #include +#include +#include // aiGetVersion +#include +#include +#include + +#include "M3DWrapper.h" #include "M3DExporter.h" #include "M3DMaterials.h" @@ -80,316 +81,357 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - aiAnimation -> m3d_action (frame with timestamp and list of bone id, position, orientation * triplets, instead of per bone timestamp + lists) */ -using namespace Assimp; - -namespace Assimp { - - // --------------------------------------------------------------------- - // Worker function for exporting a scene to binary M3D. - // Prototyped and registered in Exporter.cpp - void ExportSceneM3D ( - const char* pFile, - IOSystem* pIOSystem, - const aiScene* pScene, - const ExportProperties* pProperties - ){ - // initialize the exporter - M3DExporter exporter(pScene, pProperties); - - // perform binary export - exporter.doExport(pFile, pIOSystem, false); - } - - // --------------------------------------------------------------------- - // Worker function for exporting a scene to ASCII A3D. - // Prototyped and registered in Exporter.cpp - void ExportSceneA3D ( - const char* pFile, - IOSystem* pIOSystem, - const aiScene* pScene, - const ExportProperties* pProperties - - ){ - // initialize the exporter - M3DExporter exporter(pScene, pProperties); - - // perform ascii export - exporter.doExport(pFile, pIOSystem, true); - } - -} // end of namespace Assimp // ------------------------------------------------------------------------------------------------ -M3DExporter::M3DExporter ( const aiScene* pScene, const ExportProperties* pProperties ) -: mScene(pScene) -, mProperties(pProperties) -, outfile() -, m3d(nullptr) { } - +// Conversion functions // ------------------------------------------------------------------------------------------------ -void M3DExporter::doExport ( - const char* pFile, - IOSystem* pIOSystem, - bool toAscii -){ - // TODO: convert mProperties into M3D_EXP_* flags - (void)mProperties; - - // open the indicated file for writing (in binary / ASCII mode) - outfile.reset(pIOSystem->Open(pFile, toAscii ? "wt" : "wb")); - if (!outfile) { - throw DeadlyExportError( "could not open output .m3d file: " + std::string(pFile) ); - } - - // use malloc() here because m3d_free() will call free() - m3d = (m3d_t*)calloc(1, sizeof(m3d_t)); - if(!m3d) { - throw DeadlyExportError( "memory allocation error" ); - } - m3d->name = _m3d_safestr((char*)&mScene->mRootNode->mName.data, 2); - - // Create a model from assimp structures - aiMatrix4x4 m; - NodeWalk(mScene->mRootNode, m); - - // serialize the structures - unsigned int size; - unsigned char *output = m3d_save(m3d, M3D_EXP_FLOAT, - M3D_EXP_EXTRA | (toAscii ? M3D_EXP_ASCII : 0), &size); - m3d_free(m3d); - if(!output || size < 8) { - throw DeadlyExportError( "unable to serialize into Model 3D" ); - } - - // Write out serialized model - outfile->Write(output, size, 1); - - // explicitly release file pointer, - // so we don't have to rely on class destruction. - outfile.reset(); +// helper to add a vertex (private to NodeWalk) +m3dv_t *AddVrtx(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx) { + if (v->x == (M3D_FLOAT)-0.0) v->x = (M3D_FLOAT)0.0; + if (v->y == (M3D_FLOAT)-0.0) v->y = (M3D_FLOAT)0.0; + if (v->z == (M3D_FLOAT)-0.0) v->z = (M3D_FLOAT)0.0; + if (v->w == (M3D_FLOAT)-0.0) v->w = (M3D_FLOAT)0.0; + vrtx = (m3dv_t *)M3D_REALLOC(vrtx, ((*numvrtx) + 1) * sizeof(m3dv_t)); + memcpy(&vrtx[*numvrtx], v, sizeof(m3dv_t)); + *idx = *numvrtx; + (*numvrtx)++; + return vrtx; } // ------------------------------------------------------------------------------------------------ -// recursive node walker -void M3DExporter::NodeWalk(const aiNode* pNode, aiMatrix4x4 m) -{ - aiMatrix4x4 nm = m * pNode->mTransformation; - - for(unsigned int i = 0; i < pNode->mNumMeshes; i++) { - const aiMesh *mesh = mScene->mMeshes[pNode->mMeshes[i]]; - unsigned int mi = (M3D_INDEX)-1U; - if(mScene->mMaterials) { - // get the material for this mesh - mi = addMaterial(mScene->mMaterials[mesh->mMaterialIndex]); - } - // iterate through the mesh faces - for(unsigned int j = 0; j < mesh->mNumFaces; j++) { - unsigned int n; - const aiFace* face = &(mesh->mFaces[j]); - // only triangle meshes supported for now - if(face->mNumIndices != 3) { - throw DeadlyExportError( "use aiProcess_Triangulate before export" ); - } - // add triangle to the output - n = m3d->numface++; - m3d->face = (m3df_t*)M3D_REALLOC(m3d->face, - m3d->numface * sizeof(m3df_t)); - if(!m3d->face) { - throw DeadlyExportError( "memory allocation error" ); - } - /* set all index to -1 by default */ - m3d->face[n].vertex[0] = m3d->face[n].vertex[1] = m3d->face[n].vertex[2] = - m3d->face[n].normal[0] = m3d->face[n].normal[1] = m3d->face[n].normal[2] = - m3d->face[n].texcoord[0] = m3d->face[n].texcoord[1] = m3d->face[n].texcoord[2] = -1U; - m3d->face[n].materialid = mi; - for(unsigned int k = 0; k < face->mNumIndices; k++) { - // get the vertex's index - unsigned int l = face->mIndices[k]; - unsigned int idx; - m3dv_t vertex; - m3dti_t ti; - // multiply the position vector by the transformation matrix - aiVector3D v = mesh->mVertices[l]; - v *= nm; - vertex.x = v.x; - vertex.y = v.y; - vertex.z = v.z; - vertex.w = 1.0; - vertex.color = 0; - vertex.skinid = -1U; - // add color if defined - if(mesh->HasVertexColors(0)) - vertex.color = mkColor(&mesh->mColors[0][l]); - // save the vertex to the output - m3d->vertex = _m3d_addvrtx(m3d->vertex, &m3d->numvertex, - &vertex, &idx); - m3d->face[n].vertex[k] = (M3D_INDEX)idx; - // do we have texture coordinates? - if(mesh->HasTextureCoords(0)) { - ti.u = mesh->mTextureCoords[0][l].x; - ti.v = mesh->mTextureCoords[0][l].y; - m3d->tmap = _m3d_addtmap(m3d->tmap, &m3d->numtmap, &ti, - &idx); - m3d->face[n].texcoord[k] = (M3D_INDEX)idx; - } - // do we have normal vectors? - if(mesh->HasNormals()) { - vertex.color = 0; - vertex.x = mesh->mNormals[l].x; - vertex.y = mesh->mNormals[l].y; - vertex.z = mesh->mNormals[l].z; - m3d->vertex = _m3d_addnorm(m3d->vertex, &m3d->numvertex, - &vertex, &idx); - m3d->face[n].normal[k] = (M3D_INDEX)idx; - } - } - } - } - // repeat for the children nodes - for (unsigned int i = 0; i < pNode->mNumChildren; i++) { - NodeWalk(pNode->mChildren[i], nm); - } +// helper to add a tmap (private to NodeWalk) +m3dti_t *AddTmap(m3dti_t *tmap, uint32_t *numtmap, m3dti_t *ti, uint32_t *idx) { + tmap = (m3dti_t *)M3D_REALLOC(tmap, ((*numtmap) + 1) * sizeof(m3dti_t)); + memcpy(&tmap[*numtmap], ti, sizeof(m3dti_t)); + *idx = *numtmap; + (*numtmap)++; + return tmap; } // ------------------------------------------------------------------------------------------------ // convert aiColor4D into uint32_t -uint32_t M3DExporter::mkColor(aiColor4D* c) -{ - return ((uint8_t)(c->a*255) << 24L) | - ((uint8_t)(c->b*255) << 16L) | - ((uint8_t)(c->g*255) << 8L) | - ((uint8_t)(c->r*255) << 0L); -} - -// ------------------------------------------------------------------------------------------------ -// add a material to the output -M3D_INDEX M3DExporter::addMaterial(const aiMaterial *mat) -{ - unsigned int mi = -1U; - aiColor4D c; - aiString name; - ai_real f; - char *fn; - - if(mat && mat->Get(AI_MATKEY_NAME, name) == AI_SUCCESS && name.length && - strcmp((char*)&name.data, AI_DEFAULT_MATERIAL_NAME)) { - // check if we have saved a material by this name. This has to be done - // because only the referenced materials should be added to the output - for(unsigned int i = 0; i < m3d->nummaterial; i++) - if(!strcmp((char*)&name.data, m3d->material[i].name)) { - mi = i; - break; - } - // if not found, add the material to the output - if(mi == -1U) { - unsigned int k; - mi = m3d->nummaterial++; - m3d->material = (m3dm_t*)M3D_REALLOC(m3d->material, m3d->nummaterial - * sizeof(m3dm_t)); - if(!m3d->material) { - throw DeadlyExportError( "memory allocation error" ); - } - m3d->material[mi].name = _m3d_safestr((char*)&name.data, 0); - m3d->material[mi].numprop = 0; - m3d->material[mi].prop = NULL; - // iterate through the material property table and see what we got - for(k = 0; k < 15; k++) { - unsigned int j; - if(m3d_propertytypes[k].format == m3dpf_map) - continue; - if(aiProps[k].pKey) { - switch(m3d_propertytypes[k].format) { - case m3dpf_color: - if(mat->Get(aiProps[k].pKey, aiProps[k].type, - aiProps[k].index, c) == AI_SUCCESS) - addProp(&m3d->material[mi], - m3d_propertytypes[k].id, mkColor(&c)); - break; - case m3dpf_float: - if(mat->Get(aiProps[k].pKey, aiProps[k].type, - aiProps[k].index, f) == AI_SUCCESS) - addProp(&m3d->material[mi], - m3d_propertytypes[k].id, - /* not (uint32_t)f, because we don't want to convert - * it, we want to see it as 32 bits of memory */ - *((uint32_t*)&f)); - break; - case m3dpf_uint8: - if(mat->Get(aiProps[k].pKey, aiProps[k].type, - aiProps[k].index, j) == AI_SUCCESS) { - // special conversion for illumination model property - if(m3d_propertytypes[k].id == m3dp_il) { - switch(j) { - case aiShadingMode_NoShading: j = 0; break; - case aiShadingMode_Phong: j = 2; break; - default: j = 1; break; - } - } - addProp(&m3d->material[mi], - m3d_propertytypes[k].id, j); - } - break; - default: - if(mat->Get(aiProps[k].pKey, aiProps[k].type, - aiProps[k].index, j) == AI_SUCCESS) - addProp(&m3d->material[mi], - m3d_propertytypes[k].id, j); - break; - } - } - if(aiTxProps[k].pKey && - mat->GetTexture((aiTextureType)aiTxProps[k].type, - aiTxProps[k].index, &name, NULL, NULL, NULL, - NULL, NULL) == AI_SUCCESS) { - unsigned int i; - for(j = name.length-1; j > 0 && name.data[j]!='.'; j++); - if(j && name.data[j]=='.' && - (name.data[j+1]=='p' || name.data[j+1]=='P') && - (name.data[j+1]=='n' || name.data[j+1]=='N') && - (name.data[j+1]=='g' || name.data[j+1]=='G')) - name.data[j]=0; - // do we have this texture saved already? - fn = _m3d_safestr((char*)&name.data, 0); - for(j = 0, i = -1U; j < m3d->numtexture; j++) - if(!strcmp(fn, m3d->texture[j].name)) { - i = j; - free(fn); - break; - } - if(i == -1U) { - i = m3d->numtexture++; - m3d->texture = (m3dtx_t*)M3D_REALLOC( - m3d->texture, - m3d->numtexture * sizeof(m3dtx_t)); - if(!m3d->texture) { - throw DeadlyExportError( "memory allocation error" ); - } - // we don't need the texture itself, only its name - m3d->texture[i].name = fn; - m3d->texture[i].w = 0; - m3d->texture[i].h = 0; - m3d->texture[i].d = NULL; - } - addProp(&m3d->material[mi], - m3d_propertytypes[k].id + 128, i); - } - } - } - } - return mi; +uint32_t mkColor(aiColor4D *c) { + return ((uint8_t)(c->a * 255) << 24L) | + ((uint8_t)(c->b * 255) << 16L) | + ((uint8_t)(c->g * 255) << 8L) | + ((uint8_t)(c->r * 255) << 0L); } // ------------------------------------------------------------------------------------------------ // add a material property to the output -void M3DExporter::addProp(m3dm_t *m, uint8_t type, uint32_t value) -{ - unsigned int i; - i = m->numprop++; - m->prop = (m3dp_t*)M3D_REALLOC(m->prop, m->numprop * sizeof(m3dp_t)); - if(!m->prop) { throw DeadlyExportError( "memory allocation error" ); } - m->prop[i].type = type; - m->prop[i].value.num = value; +void addProp(m3dm_t *m, uint8_t type, uint32_t value) { + unsigned int i; + i = m->numprop++; + m->prop = (m3dp_t *)M3D_REALLOC(m->prop, m->numprop * sizeof(m3dp_t)); + if (!m->prop) { + throw DeadlyExportError("memory allocation error"); + } + m->prop[i].type = type; + m->prop[i].value.num = value; } +// ------------------------------------------------------------------------------------------------ +// convert aiString to identifier safe C string. This is a duplication of _m3d_safestr +char *SafeStr(aiString str, bool isStrict) +{ + char *s = (char *)&str.data; + char *d, *ret; + int i, len; + + for(len = str.length + 1; *s && (*s == ' ' || *s == '\t'); s++, len--); + if(len > 255) len = 255; + ret = (char *)M3D_MALLOC(len + 1); + if (!ret) { + throw DeadlyExportError("memory allocation error"); + } + for(i = 0, d = ret; i < len && *s && *s != '\r' && *s != '\n'; s++, d++, i++) { + *d = isStrict && (*s == ' ' || *s == '\t' || *s == '/' || *s == '\\') ? '_' : (*s == '\t' ? ' ' : *s); + } + for(; d > ret && (*(d-1) == ' ' || *(d-1) == '\t'); d--); + *d = 0; + return ret; +} + +// ------------------------------------------------------------------------------------------------ +// add a material to the output +M3D_INDEX addMaterial(const Assimp::M3DWrapper &m3d, const aiMaterial *mat) { + unsigned int mi = M3D_NOTDEFINED; + aiColor4D c; + aiString name; + ai_real f; + char *fn; + + if (mat && mat->Get(AI_MATKEY_NAME, name) == AI_SUCCESS && name.length && + strcmp((char *)&name.data, AI_DEFAULT_MATERIAL_NAME)) { + // check if we have saved a material by this name. This has to be done + // because only the referenced materials should be added to the output + for (unsigned int i = 0; i < m3d->nummaterial; i++) + if (!strcmp((char *)&name.data, m3d->material[i].name)) { + mi = i; + break; + } + // if not found, add the material to the output + if (mi == M3D_NOTDEFINED) { + unsigned int k; + mi = m3d->nummaterial++; + m3d->material = (m3dm_t *)M3D_REALLOC(m3d->material, m3d->nummaterial * sizeof(m3dm_t)); + if (!m3d->material) { + throw DeadlyExportError("memory allocation error"); + } + m3d->material[mi].name = SafeStr(name, true); + m3d->material[mi].numprop = 0; + m3d->material[mi].prop = NULL; + // iterate through the material property table and see what we got + for (k = 0; k < 15; k++) { + unsigned int j; + if (m3d_propertytypes[k].format == m3dpf_map) + continue; + if (aiProps[k].pKey) { + switch (m3d_propertytypes[k].format) { + case m3dpf_color: + if (mat->Get(aiProps[k].pKey, aiProps[k].type, + aiProps[k].index, c) == AI_SUCCESS) + addProp(&m3d->material[mi], + m3d_propertytypes[k].id, mkColor(&c)); + break; + case m3dpf_float: + if (mat->Get(aiProps[k].pKey, aiProps[k].type, + aiProps[k].index, f) == AI_SUCCESS) + addProp(&m3d->material[mi], + m3d_propertytypes[k].id, + /* not (uint32_t)f, because we don't want to convert + * it, we want to see it as 32 bits of memory */ + *((uint32_t *)&f)); + break; + case m3dpf_uint8: + if (mat->Get(aiProps[k].pKey, aiProps[k].type, + aiProps[k].index, j) == AI_SUCCESS) { + // special conversion for illumination model property + if (m3d_propertytypes[k].id == m3dp_il) { + switch (j) { + case aiShadingMode_NoShading: j = 0; break; + case aiShadingMode_Phong: j = 2; break; + default: j = 1; break; + } + } + addProp(&m3d->material[mi], + m3d_propertytypes[k].id, j); + } + break; + default: + if (mat->Get(aiProps[k].pKey, aiProps[k].type, + aiProps[k].index, j) == AI_SUCCESS) + addProp(&m3d->material[mi], + m3d_propertytypes[k].id, j); + break; + } + } + if (aiTxProps[k].pKey && + mat->GetTexture((aiTextureType)aiTxProps[k].type, + aiTxProps[k].index, &name, NULL, NULL, NULL, + NULL, NULL) == AI_SUCCESS) { + unsigned int i; + for (j = name.length - 1; j > 0 && name.data[j] != '.'; j++) + ; + if (j && name.data[j] == '.' && + (name.data[j + 1] == 'p' || name.data[j + 1] == 'P') && + (name.data[j + 1] == 'n' || name.data[j + 1] == 'N') && + (name.data[j + 1] == 'g' || name.data[j + 1] == 'G')) + name.data[j] = 0; + // do we have this texture saved already? + fn = SafeStr(name, true); + for (j = 0, i = M3D_NOTDEFINED; j < m3d->numtexture; j++) + if (!strcmp(fn, m3d->texture[j].name)) { + i = j; + free(fn); + break; + } + if (i == M3D_NOTDEFINED) { + i = m3d->numtexture++; + m3d->texture = (m3dtx_t *)M3D_REALLOC( + m3d->texture, + m3d->numtexture * sizeof(m3dtx_t)); + if (!m3d->texture) { + throw DeadlyExportError("memory allocation error"); + } + // we don't need the texture itself, only its name + m3d->texture[i].name = fn; + m3d->texture[i].w = 0; + m3d->texture[i].h = 0; + m3d->texture[i].d = NULL; + } + addProp(&m3d->material[mi], + m3d_propertytypes[k].id + 128, i); + } + } + } + } + return mi; +} + +namespace Assimp { + +// --------------------------------------------------------------------- +// Worker function for exporting a scene to binary M3D. +// Prototyped and registered in Exporter.cpp +void ExportSceneM3D( + const char *pFile, + IOSystem *pIOSystem, + const aiScene *pScene, + const ExportProperties *pProperties) { + // initialize the exporter + M3DExporter exporter(pScene, pProperties); + + // perform binary export + exporter.doExport(pFile, pIOSystem, false); +} + +// --------------------------------------------------------------------- +// Worker function for exporting a scene to ASCII A3D. +// Prototyped and registered in Exporter.cpp +void ExportSceneM3DA( + const char *pFile, + IOSystem *pIOSystem, + const aiScene *pScene, + const ExportProperties *pProperties + +) { +#ifdef M3D_ASCII + // initialize the exporter + M3DExporter exporter(pScene, pProperties); + + // perform ascii export + exporter.doExport(pFile, pIOSystem, true); +#else + throw DeadlyExportError("Assimp configured without M3D_ASCII support"); +#endif +} + +// ------------------------------------------------------------------------------------------------ +M3DExporter::M3DExporter(const aiScene *pScene, const ExportProperties *pProperties) : + mScene(pScene), + mProperties(pProperties), + outfile() {} + +// ------------------------------------------------------------------------------------------------ +void M3DExporter::doExport( + const char *pFile, + IOSystem *pIOSystem, + bool toAscii) { + // TODO: convert mProperties into M3D_EXP_* flags + (void)mProperties; + + // open the indicated file for writing (in binary / ASCII mode) + outfile.reset(pIOSystem->Open(pFile, toAscii ? "wt" : "wb")); + if (!outfile) { + throw DeadlyExportError("could not open output .m3d file: " + std::string(pFile)); + } + + M3DWrapper m3d; + if (!m3d) { + throw DeadlyExportError("memory allocation error"); + } + m3d->name = SafeStr(mScene->mRootNode->mName, false); + + // Create a model from assimp structures + aiMatrix4x4 m; + NodeWalk(m3d, mScene->mRootNode, m); + + // serialize the structures + unsigned int size; + unsigned char *output = m3d.Save(M3D_EXP_FLOAT, M3D_EXP_EXTRA | (toAscii ? M3D_EXP_ASCII : 0), size); + + if (!output || size < 8) { + throw DeadlyExportError("unable to serialize into Model 3D"); + } + + // Write out serialized model + outfile->Write(output, size, 1); + + // explicitly release file pointer, + // so we don't have to rely on class destruction. + outfile.reset(); +} + +// ------------------------------------------------------------------------------------------------ +// recursive node walker +void M3DExporter::NodeWalk(const M3DWrapper &m3d, const aiNode *pNode, aiMatrix4x4 m) { + aiMatrix4x4 nm = m * pNode->mTransformation; + + for (unsigned int i = 0; i < pNode->mNumMeshes; i++) { + const aiMesh *mesh = mScene->mMeshes[pNode->mMeshes[i]]; + unsigned int mi = M3D_NOTDEFINED; + if (mScene->mMaterials) { + // get the material for this mesh + mi = addMaterial(m3d, mScene->mMaterials[mesh->mMaterialIndex]); + } + // iterate through the mesh faces + for (unsigned int j = 0; j < mesh->mNumFaces; j++) { + unsigned int n; + const aiFace *face = &(mesh->mFaces[j]); + // only triangle meshes supported for now + if (face->mNumIndices != 3) { + throw DeadlyExportError("use aiProcess_Triangulate before export"); + } + // add triangle to the output + n = m3d->numface++; + m3d->face = (m3df_t *)M3D_REALLOC(m3d->face, + m3d->numface * sizeof(m3df_t)); + if (!m3d->face) { + throw DeadlyExportError("memory allocation error"); + } + /* set all index to -1 by default */ + m3d->face[n].vertex[0] = m3d->face[n].vertex[1] = m3d->face[n].vertex[2] = + m3d->face[n].normal[0] = m3d->face[n].normal[1] = m3d->face[n].normal[2] = + m3d->face[n].texcoord[0] = m3d->face[n].texcoord[1] = m3d->face[n].texcoord[2] = M3D_UNDEF; + m3d->face[n].materialid = mi; + for (unsigned int k = 0; k < face->mNumIndices; k++) { + // get the vertex's index + unsigned int l = face->mIndices[k]; + unsigned int idx; + m3dv_t vertex; + m3dti_t ti; + // multiply the position vector by the transformation matrix + aiVector3D v = mesh->mVertices[l]; + v *= nm; + vertex.x = v.x; + vertex.y = v.y; + vertex.z = v.z; + vertex.w = 1.0; + vertex.color = 0; + vertex.skinid = M3D_UNDEF; + // add color if defined + if (mesh->HasVertexColors(0)) + vertex.color = mkColor(&mesh->mColors[0][l]); + // save the vertex to the output + m3d->vertex = AddVrtx(m3d->vertex, &m3d->numvertex, + &vertex, &idx); + m3d->face[n].vertex[k] = (M3D_INDEX)idx; + // do we have texture coordinates? + if (mesh->HasTextureCoords(0)) { + ti.u = mesh->mTextureCoords[0][l].x; + ti.v = mesh->mTextureCoords[0][l].y; + m3d->tmap = AddTmap(m3d->tmap, &m3d->numtmap, &ti, &idx); + m3d->face[n].texcoord[k] = (M3D_INDEX)idx; + } + // do we have normal vectors? + if (mesh->HasNormals()) { + vertex.x = mesh->mNormals[l].x; + vertex.y = mesh->mNormals[l].y; + vertex.z = mesh->mNormals[l].z; + vertex.color = 0; + m3d->vertex = AddVrtx(m3d->vertex, &m3d->numvertex, &vertex, &idx); + m3d->face[n].normal[k] = (M3D_INDEX)idx; + } + } + } + } + // repeat for the children nodes + for (unsigned int i = 0; i < pNode->mNumChildren; i++) { + NodeWalk(m3d, pNode->mChildren[i], nm); + } +} +} // namespace Assimp + #endif // ASSIMP_BUILD_NO_M3D_EXPORTER #endif // ASSIMP_BUILD_NO_EXPORT diff --git a/Engine/lib/assimp/code/M3D/M3DExporter.h b/Engine/lib/assimp/code/M3D/M3DExporter.h index dfcff8bc9..40fce44d0 100644 --- a/Engine/lib/assimp/code/M3D/M3DExporter.h +++ b/Engine/lib/assimp/code/M3D/M3DExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team Copyright (c) 2019 bzt All rights reserved. @@ -48,8 +48,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_M3D_EXPORTER -#include "m3d.h" - #include //#include #include // StreamWriterLE @@ -68,6 +66,8 @@ namespace Assimp class IOStream; class ExportProperties; + class M3DWrapper; + // --------------------------------------------------------------------- /** Helper class to export a given scene to an M3D file. */ // --------------------------------------------------------------------- @@ -83,13 +83,9 @@ namespace Assimp const aiScene* mScene; // the scene to export const ExportProperties* mProperties; // currently unused std::shared_ptr outfile; // file to write to - m3d_t *m3d; // model for the C library to convert to // helper to do the recursive walking - void NodeWalk(const aiNode* pNode, aiMatrix4x4 m); - uint32_t mkColor(aiColor4D* c); - M3D_INDEX addMaterial(const aiMaterial *mat); - void addProp(m3dm_t *m, uint8_t type, uint32_t value); + void NodeWalk(const M3DWrapper &m3d, const aiNode* pNode, aiMatrix4x4 m); }; } diff --git a/Engine/lib/assimp/code/M3D/M3DImporter.cpp b/Engine/lib/assimp/code/M3D/M3DImporter.cpp index fcff49df7..9aee14f75 100644 --- a/Engine/lib/assimp/code/M3D/M3DImporter.cpp +++ b/Engine/lib/assimp/code/M3D/M3DImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team Copyright (c) 2019 bzt All rights reserved. @@ -43,16 +43,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_M3D_IMPORTER #define M3D_IMPLEMENTATION -#define M3D_ASCII +#define M3D_NONORMALS /* leave the post-processing to Assimp */ +#define M3D_NOWEIGHTS +#define M3D_NOANIMATION -#include -#include #include -#include -#include +#include #include -#include #include +#include +#include +#include +#include + +#include "M3DWrapper.h" #include "M3DImporter.h" #include "M3DMaterials.h" @@ -82,656 +86,721 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ static const aiImporterDesc desc = { - "Model 3D Importer", - "", - "", - "", - aiImporterFlags_SupportBinaryFlavour, - 0, - 0, - 0, - 0, - "m3d a3d" + "Model 3D Importer", + "", + "", + "", + aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour, + 0, + 0, + 0, + 0, +#ifdef M3D_ASCII + "m3d a3d" +#else + "m3d" +#endif }; -// workaround: the SDK expects a C callback, but we want to use Assimp::IOSystem to implement that -extern "C" { - void* m3dimporter_pIOHandler; - - unsigned char *m3dimporter_readfile(char *fn, unsigned int *size) { - ai_assert( nullptr != fn ); - ai_assert( nullptr != size ); - std::string file(fn); - std::unique_ptr pStream( - (reinterpret_cast(m3dimporter_pIOHandler))->Open( file, "rb")); - size_t fileSize = pStream->FileSize(); - // should be allocated with malloc(), because the library will call free() to deallocate - unsigned char *data = (unsigned char*)malloc(fileSize); - if( !data || !pStream.get() || !fileSize || fileSize != pStream->Read(data,1,fileSize)) { - pStream.reset(); - *size = 0; - // don't throw a deadly exception, it's not fatal if we can't read an external asset - return nullptr; - } - pStream.reset(); - *size = (int)fileSize; - return data; - } -} - namespace Assimp { using namespace std; // ------------------------------------------------------------------------------------------------ // Default constructor -M3DImporter::M3DImporter() -: mScene(nullptr) -, m3d(nullptr) { } - -// ------------------------------------------------------------------------------------------------ -// Destructor. -M3DImporter::~M3DImporter() {} +M3DImporter::M3DImporter() : + mScene(nullptr) { + // empty + } // ------------------------------------------------------------------------------------------------ // Returns true, if file is a binary or ASCII Model 3D file. -bool M3DImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler , bool checkSig) const { - const std::string extension = GetExtension(pFile); +bool M3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { + const std::string extension = GetExtension(pFile); - if (extension == "m3d" || extension == "a3d") - return true; - else if (!extension.length() || checkSig) { - if (!pIOHandler) { - return true; - } - /* + if (extension == "m3d" +#ifdef M3D_ASCII + || extension == "a3d" +#endif + ) + return true; + else if (!extension.length() || checkSig) { + if (!pIOHandler) { + return true; + } + /* * don't use CheckMagicToken because that checks with swapped bytes too, leading to false * positives. This magic is not uint32_t, but char[4], so memcmp is the best way const char* tokens[] = {"3DMO", "3dmo"}; return CheckMagicToken(pIOHandler,pFile,tokens,2,0,4); */ - std::unique_ptr pStream (pIOHandler->Open(pFile, "rb")); - unsigned char data[4]; - if(4 != pStream->Read(data,1,4)) { - return false; - } - return !memcmp(data, "3DMO", 4) /* bin */ || !memcmp(data, "3dmo", 4) /* ASCII */; - } - return false; + std::unique_ptr pStream(pIOHandler->Open(pFile, "rb")); + unsigned char data[4]; + if (4 != pStream->Read(data, 1, 4)) { + return false; + } + return !memcmp(data, "3DMO", 4) /* bin */ +#ifdef M3D_ASCII + || !memcmp(data, "3dmo", 4) /* ASCII */ +#endif + ; + } + return false; } // ------------------------------------------------------------------------------------------------ -const aiImporterDesc* M3DImporter::GetInfo() const { - return &desc; +const aiImporterDesc *M3DImporter::GetInfo() const { + return &desc; } // ------------------------------------------------------------------------------------------------ // Model 3D import implementation -void M3DImporter::InternReadFile( const std::string &file, aiScene* pScene, IOSystem* pIOHandler) { - // Read file into memory - std::unique_ptr pStream( pIOHandler->Open( file, "rb")); - if( !pStream.get() ) { - throw DeadlyImportError( "Failed to open file " + file + "." ); - } +void M3DImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSystem *pIOHandler) { + // Read file into memory + std::unique_ptr pStream(pIOHandler->Open(file, "rb")); + if (!pStream.get()) { + throw DeadlyImportError("Failed to open file " + file + "."); + } - // Get the file-size and validate it, throwing an exception when fails - size_t fileSize = pStream->FileSize(); - if( fileSize < 8 ) { - throw DeadlyImportError( "M3D-file " + file + " is too small." ); - } - std::unique_ptr _buffer (new unsigned char[fileSize]); - unsigned char *data( _buffer.get() ); - if(fileSize != pStream->Read(data,1,fileSize)) { - throw DeadlyImportError( "Failed to read the file " + file + "." ); - } + // Get the file-size and validate it, throwing an exception when fails + size_t fileSize = pStream->FileSize(); + if (fileSize < 8) { + throw DeadlyImportError("M3D-file " + file + " is too small."); + } + std::vector buffer(fileSize); + if (fileSize != pStream->Read(buffer.data(), 1, fileSize)) { + throw DeadlyImportError("Failed to read the file " + file + "."); + } + // extra check for binary format's first 8 bytes. Not done for the ASCII variant + if(!memcmp(buffer.data(), "3DMO", 4) && memcmp(buffer.data() + 4, &fileSize, 4)) { + throw DeadlyImportError("Bad binary header in file " + file + "."); + } +#ifdef M3D_ASCII + // make sure there's a terminator zero character, as input must be ASCIIZ + if(!memcmp(buffer.data(), "3dmo", 4)) { + buffer.push_back(0); + } +#endif - // Get the path for external assets - std::string folderName( "./" ); - std::string::size_type pos = file.find_last_of( "\\/" ); - if ( pos != std::string::npos ) { - folderName = file.substr( 0, pos ); - if ( !folderName.empty() ) { - pIOHandler->PushDirectory( folderName ); - } - } - // pass this IOHandler to the C callback - m3dimporter_pIOHandler = pIOHandler; + // Get the path for external assets + std::string folderName("./"); + std::string::size_type pos = file.find_last_of("\\/"); + if (pos != std::string::npos) { + folderName = file.substr(0, pos); + if (!folderName.empty()) { + pIOHandler->PushDirectory(folderName); + } + } //DefaultLogger::create("/dev/stderr", Logger::VERBOSE); - ASSIMP_LOG_DEBUG_F("M3D: loading ", file); + ASSIMP_LOG_DEBUG_F("M3D: loading ", file); - // let the C SDK do the hard work for us - m3d = m3d_load(&data[0], m3dimporter_readfile, free, nullptr); - m3dimporter_pIOHandler = nullptr; - if( !m3d ) { - throw DeadlyImportError( "Unable to parse " + file + " as M3D." ); - } + // let the C SDK do the hard work for us + M3DWrapper m3d(pIOHandler, buffer); - // create the root node - pScene->mRootNode = new aiNode; - pScene->mRootNode->mName = aiString(std::string(std::string(m3d->name))); - pScene->mRootNode->mTransformation = aiMatrix4x4(); - pScene->mRootNode->mNumChildren = 0; - mScene = pScene; + if (!m3d) { + throw DeadlyImportError("Unable to parse " + file + " as M3D."); + } - ASSIMP_LOG_DEBUG("M3D: root node " + std::string(m3d->name)); + // create the root node + pScene->mRootNode = new aiNode; + pScene->mRootNode->mName = aiString(m3d.Name()); + pScene->mRootNode->mTransformation = aiMatrix4x4(); + pScene->mRootNode->mNumChildren = 0; + mScene = pScene; - // now we just have to fill up the Assimp structures in pScene - importMaterials(); - importTextures(); - importBones(-1U, pScene->mRootNode); - importMeshes(); - importAnimations(); + ASSIMP_LOG_DEBUG("M3D: root node " + m3d.Name()); - // we don't need the SDK's version any more - m3d_free(m3d); + // now we just have to fill up the Assimp structures in pScene + importMaterials(m3d); + importTextures(m3d); + importBones(m3d, M3D_NOTDEFINED, pScene->mRootNode); + importMeshes(m3d); + importAnimations(m3d); - // Pop directory stack - if ( pIOHandler->StackSize() > 0 ) { - pIOHandler->PopDirectory(); - } + // Pop directory stack + if (pIOHandler->StackSize() > 0) { + pIOHandler->PopDirectory(); + } } // ------------------------------------------------------------------------------------------------ // convert materials. properties are converted using a static table in M3DMaterials.h -void M3DImporter::importMaterials() -{ - unsigned int i, j, k, l, n; - m3dm_t *m; - aiString name = aiString(AI_DEFAULT_MATERIAL_NAME); - aiColor4D c; - ai_real f; +void M3DImporter::importMaterials(const M3DWrapper &m3d) { + unsigned int i, j, k, l, n; + m3dm_t *m; + aiString name = aiString(AI_DEFAULT_MATERIAL_NAME); + aiColor4D c; + ai_real f; - ai_assert(mScene != nullptr); - ai_assert(m3d != nullptr); + ai_assert(mScene != nullptr); + ai_assert(m3d); - mScene->mNumMaterials = m3d->nummaterial + 1; - mScene->mMaterials = new aiMaterial*[ m3d->nummaterial + 1 ]; + mScene->mNumMaterials = m3d->nummaterial + 1; + mScene->mMaterials = new aiMaterial *[mScene->mNumMaterials]; - ASSIMP_LOG_DEBUG_F("M3D: importMaterials ", mScene->mNumMaterials); + ASSIMP_LOG_DEBUG_F("M3D: importMaterials ", mScene->mNumMaterials); - // add a default material as first - aiMaterial* mat = new aiMaterial; - mat->AddProperty( &name, AI_MATKEY_NAME ); - c.a = 1.0; c.b = c.g = c.r = 0.6; - mat->AddProperty( &c, 1, AI_MATKEY_COLOR_DIFFUSE); - mScene->mMaterials[0] = mat; + // add a default material as first + aiMaterial *mat = new aiMaterial; + mat->AddProperty(&name, AI_MATKEY_NAME); + c.a = 1.0f; + c.b = c.g = c.r = 0.6f; + mat->AddProperty(&c, 1, AI_MATKEY_COLOR_DIFFUSE); + mScene->mMaterials[0] = mat; - for(i = 0; i < m3d->nummaterial; i++) { - m = &m3d->material[i]; - aiMaterial* mat = new aiMaterial; - name.Set(std::string(m->name)); - mat->AddProperty( &name, AI_MATKEY_NAME ); - for(j = 0; j < m->numprop; j++) { - // look up property type - // 0 - 127 scalar values, - // 128 - 255 the same properties but for texture maps - k = 256; - for(l = 0; l < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); l++) - if(m->prop[j].type == m3d_propertytypes[l].id || - m->prop[j].type == m3d_propertytypes[l].id + 128) { - k = l; - break; - } - // should never happen, but be safe than sorry - if(k == 256) continue; + if (!m3d->nummaterial || !m3d->material) { + return; + } - // scalar properties - if(m->prop[j].type < 128 && aiProps[k].pKey) { - switch(m3d_propertytypes[k].format) { - case m3dpf_color: - c = mkColor(m->prop[j].value.color); - mat->AddProperty(&c, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index); - break; - case m3dpf_float: - f = m->prop[j].value.fnum; - mat->AddProperty(&f, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index); - break; - default: - n = m->prop[j].value.num; - if(m->prop[j].type == m3dp_il) { - switch(n) { - case 0: n = aiShadingMode_NoShading; break; - case 2: n = aiShadingMode_Phong; break; - default: n = aiShadingMode_Gouraud; break; - } - } - mat->AddProperty(&n, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index); - break; - } - } - // texture map properties - if(m->prop[j].type >= 128 && aiTxProps[k].pKey && - // extra check, should never happen, do we have the refered texture? - m->prop[j].value.textureid < m3d->numtexture && - m3d->texture[m->prop[j].value.textureid].name) { - name.Set(std::string(std::string(m3d->texture[m->prop[j].value.textureid].name) + ".png")); - mat->AddProperty(&name, aiProps[k].pKey, aiProps[k].type, aiProps[k].index); - n = 0; - mat->AddProperty(&n, 1, _AI_MATKEY_UVWSRC_BASE, aiProps[k].type, aiProps[k].index); - } - } - mScene->mMaterials[i + 1] = mat; - } + for (i = 0; i < m3d->nummaterial; i++) { + m = &m3d->material[i]; + aiMaterial *mat = new aiMaterial; + name.Set(std::string(m->name)); + mat->AddProperty(&name, AI_MATKEY_NAME); + for (j = 0; j < m->numprop; j++) { + // look up property type + // 0 - 127 scalar values, + // 128 - 255 the same properties but for texture maps + k = 256; + for (l = 0; l < sizeof(m3d_propertytypes) / sizeof(m3d_propertytypes[0]); l++) + if (m->prop[j].type == m3d_propertytypes[l].id || + m->prop[j].type == m3d_propertytypes[l].id + 128) { + k = l; + break; + } + // should never happen, but be safe than sorry + if (k == 256) continue; + + // scalar properties + if (m->prop[j].type < 128 && aiProps[k].pKey) { + switch (m3d_propertytypes[k].format) { + case m3dpf_color: + c = mkColor(m->prop[j].value.color); + mat->AddProperty(&c, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index); + break; + case m3dpf_float: + f = m->prop[j].value.fnum; + mat->AddProperty(&f, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index); + break; + default: + n = m->prop[j].value.num; + if (m->prop[j].type == m3dp_il) { + switch (n) { + case 0: n = aiShadingMode_NoShading; break; + case 2: n = aiShadingMode_Phong; break; + default: n = aiShadingMode_Gouraud; break; + } + } + mat->AddProperty(&n, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index); + break; + } + } + // texture map properties + if (m->prop[j].type >= 128 && aiTxProps[k].pKey && + // extra check, should never happen, do we have the refered texture? + m->prop[j].value.textureid < m3d->numtexture && + m3d->texture[m->prop[j].value.textureid].name) { + name.Set(std::string(std::string(m3d->texture[m->prop[j].value.textureid].name) + ".png")); + mat->AddProperty(&name, aiTxProps[k].pKey, aiTxProps[k].type, aiTxProps[k].index); + n = 0; + mat->AddProperty(&n, 1, _AI_MATKEY_UVWSRC_BASE, aiProps[k].type, aiProps[k].index); + } + } + mScene->mMaterials[i + 1] = mat; + } } // ------------------------------------------------------------------------------------------------ // import textures, this is the simplest of all -void M3DImporter::importTextures() -{ - unsigned int i; - m3dtx_t *t; +void M3DImporter::importTextures(const M3DWrapper &m3d) { + unsigned int i; + const char *formatHint[] = { + "rgba0800", + "rgba0808", + "rgba8880", + "rgba8888" + }; + m3dtx_t *t; - ai_assert(mScene != nullptr); - ai_assert(m3d != nullptr); + ai_assert(mScene != nullptr); + ai_assert(m3d); - mScene->mNumTextures = m3d->numtexture; - ASSIMP_LOG_DEBUG_F("M3D: importTextures ", mScene->mNumTextures); + mScene->mNumTextures = m3d->numtexture; + ASSIMP_LOG_DEBUG_F("M3D: importTextures ", mScene->mNumTextures); - if(!m3d->numtexture) - return; + if (!m3d->numtexture || !m3d->texture) { + return; + } - mScene->mTextures = new aiTexture*[m3d->numtexture]; - for(i = 0; i < m3d->numtexture; i++) { - t = &m3d->texture[i]; - aiTexture *tx = new aiTexture; - strcpy(tx->achFormatHint, "rgba8888"); - tx->mFilename = aiString(std::string(t->name) + ".png"); - tx->mWidth = t->w; - tx->mHeight = t->h; - tx->pcData = new aiTexel[ tx->mWidth*tx->mHeight ]; - memcpy(tx->pcData, t->d, tx->mWidth*tx->mHeight*4); - mScene->mTextures[i] = tx; - } + mScene->mTextures = new aiTexture *[m3d->numtexture]; + for (i = 0; i < m3d->numtexture; i++) { + unsigned int j, k; + t = &m3d->texture[i]; + aiTexture *tx = new aiTexture; + tx->mFilename = aiString(std::string(t->name) + ".png"); + if (!t->w || !t->h || !t->f || !t->d) { + /* without ASSIMP_USE_M3D_READFILECB, we only have the filename, but no texture data ever */ + tx->mWidth = 0; + tx->mHeight = 0; + memcpy(tx->achFormatHint, "png\000", 4); + tx->pcData = nullptr; + } else { + /* if we have the texture loaded, set format hint and pcData too */ + tx->mWidth = t->w; + tx->mHeight = t->h; + strcpy(tx->achFormatHint, formatHint[t->f - 1]); + tx->pcData = new aiTexel[tx->mWidth * tx->mHeight]; + for (j = k = 0; j < tx->mWidth * tx->mHeight; j++) { + switch (t->f) { + case 1: tx->pcData[j].g = t->d[k++]; break; + case 2: + tx->pcData[j].g = t->d[k++]; + tx->pcData[j].a = t->d[k++]; + break; + case 3: + tx->pcData[j].r = t->d[k++]; + tx->pcData[j].g = t->d[k++]; + tx->pcData[j].b = t->d[k++]; + tx->pcData[j].a = 255; + break; + case 4: + tx->pcData[j].r = t->d[k++]; + tx->pcData[j].g = t->d[k++]; + tx->pcData[j].b = t->d[k++]; + tx->pcData[j].a = t->d[k++]; + break; + } + } + } + mScene->mTextures[i] = tx; + } } // ------------------------------------------------------------------------------------------------ // this is tricky. M3D has a global vertex and UV list, and faces are indexing them // individually. In assimp there're per mesh vertex and UV lists, and they must be // indexed simultaneously. -void M3DImporter::importMeshes() -{ - unsigned int i, j, k, l, numpoly = 3, lastMat = -2U; - std::vector *meshes = new std::vector(); - std::vector *faces = nullptr; - std::vector *vertices = nullptr; - std::vector *normals = nullptr; - std::vector *texcoords = nullptr; - std::vector *colors = nullptr; - std::vector *vertexids = nullptr; - aiMesh *pMesh = nullptr; +void M3DImporter::importMeshes(const M3DWrapper &m3d) { + ASSIMP_LOG_DEBUG_F("M3D: importMeshes ", m3d->numface); - ai_assert(mScene != nullptr); - ai_assert(m3d != nullptr); - ai_assert(mScene->mRootNode != nullptr); + if (!m3d->numface || !m3d->face || !m3d->numvertex || !m3d->vertex) { + return; + } - ASSIMP_LOG_DEBUG_F("M3D: importMeshes ", m3d->numface); + unsigned int i, j, k, l, numpoly = 3, lastMat = M3D_INDEXMAX; + std::vector *meshes = new std::vector(); + std::vector *faces = nullptr; + std::vector *vertices = nullptr; + std::vector *normals = nullptr; + std::vector *texcoords = nullptr; + std::vector *colors = nullptr; + std::vector *vertexids = nullptr; + aiMesh *pMesh = nullptr; - for(i = 0; i < m3d->numface; i++) { - // we must switch mesh if material changes - if(lastMat != m3d->face[i].materialid) { - lastMat = m3d->face[i].materialid; - if(pMesh && vertices->size() && faces->size()) { - populateMesh(pMesh, faces, vertices, normals, texcoords, colors, vertexids); - meshes->push_back(pMesh); - delete vertexids; // this is not stored in pMesh, just to collect bone vertices - } - pMesh = new aiMesh; - pMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; - pMesh->mMaterialIndex = lastMat + 1; - faces = new std::vector(); - vertices = new std::vector(); - normals = new std::vector(); - texcoords = new std::vector(); - colors = new std::vector(); - vertexids = new std::vector(); - } - // add a face to temporary vector - aiFace *pFace = new aiFace; - pFace->mNumIndices = numpoly; - pFace->mIndices = new unsigned int[numpoly]; - for(j = 0; j < numpoly; j++) { - aiVector3D pos, uv, norm; - k = vertices->size(); - pFace->mIndices[j] = k; - l = m3d->face[i].vertex[j]; - pos.x = m3d->vertex[l].x; - pos.y = m3d->vertex[l].y; - pos.z = m3d->vertex[l].z; - vertices->push_back(pos); - colors->push_back(mkColor(m3d->vertex[l].color)); - // add a bone to temporary vector - if(m3d->vertex[l].skinid != -1U &&m3d->vertex[l].skinid != -2U && m3d->skin && m3d->bone) { - // this is complicated, because M3D stores a list of bone id / weight pairs per - // vertex but assimp uses lists of local vertex id/weight pairs per local bone list - vertexids->push_back(l); - } - l = m3d->face[i].texcoord[j]; - if(l != -1U) { - uv.x = m3d->tmap[l].u; - uv.y = m3d->tmap[l].v; - uv.z = 0.0; - texcoords->push_back(uv); - } - l = m3d->face[i].normal[j]; - if(l != -1U) { - norm.x = m3d->vertex[l].x; - norm.y = m3d->vertex[l].y; - norm.z = m3d->vertex[l].z; - normals->push_back(norm); - } - } - faces->push_back(*pFace); - delete pFace; - } - // if there's data left in the temporary vectors, flush them - if(pMesh && vertices->size() && faces->size()) { - populateMesh(pMesh, faces, vertices, normals, texcoords, colors, vertexids); - meshes->push_back(pMesh); - } + ai_assert(mScene != nullptr); + ai_assert(m3d); + ai_assert(mScene->mRootNode != nullptr); - // create global mesh list in scene - mScene->mNumMeshes = meshes->size(); - mScene->mMeshes = new aiMesh*[mScene->mNumMeshes]; - std::copy(meshes->begin(), meshes->end(), mScene->mMeshes); - // create mesh indeces in root node - mScene->mRootNode->mNumMeshes = meshes->size(); - mScene->mRootNode->mMeshes = new unsigned int[meshes->size()]; - for(i = 0; i < meshes->size(); i++) { - mScene->mRootNode->mMeshes[i] = i; - } + for (i = 0; i < m3d->numface; i++) { + // we must switch mesh if material changes + if (lastMat != m3d->face[i].materialid) { + lastMat = m3d->face[i].materialid; + if (pMesh && vertices && vertices->size() && faces && faces->size()) { + populateMesh(m3d, pMesh, faces, vertices, normals, texcoords, colors, vertexids); + meshes->push_back(pMesh); + delete faces; + delete vertices; + delete normals; + delete texcoords; + delete colors; + delete vertexids; // this is not stored in pMesh, just to collect bone vertices + } + pMesh = new aiMesh; + pMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; + pMesh->mMaterialIndex = lastMat + 1; + faces = new std::vector(); + vertices = new std::vector(); + normals = new std::vector(); + texcoords = new std::vector(); + colors = new std::vector(); + vertexids = new std::vector(); + } + // add a face to temporary vector + aiFace *pFace = new aiFace; + pFace->mNumIndices = numpoly; + pFace->mIndices = new unsigned int[numpoly]; + for (j = 0; j < numpoly; j++) { + aiVector3D pos, uv, norm; + k = static_cast(vertices->size()); + pFace->mIndices[j] = k; + l = m3d->face[i].vertex[j]; + if(l >= m3d->numvertex) continue; + pos.x = m3d->vertex[l].x; + pos.y = m3d->vertex[l].y; + pos.z = m3d->vertex[l].z; + vertices->push_back(pos); + colors->push_back(mkColor(m3d->vertex[l].color)); + // add a bone to temporary vector + if (m3d->vertex[l].skinid != M3D_UNDEF && m3d->vertex[l].skinid != M3D_INDEXMAX && m3d->skin && m3d->bone) { + // this is complicated, because M3D stores a list of bone id / weight pairs per + // vertex but assimp uses lists of local vertex id/weight pairs per local bone list + vertexids->push_back(l); + } + l = m3d->face[i].texcoord[j]; + if (l != M3D_UNDEF && l < m3d->numtmap) { + uv.x = m3d->tmap[l].u; + uv.y = m3d->tmap[l].v; + uv.z = 0.0; + texcoords->push_back(uv); + } + l = m3d->face[i].normal[j]; + if (l != M3D_UNDEF && l < m3d->numvertex) { + norm.x = m3d->vertex[l].x; + norm.y = m3d->vertex[l].y; + norm.z = m3d->vertex[l].z; + normals->push_back(norm); + } + } + faces->push_back(*pFace); + delete pFace; + } + // if there's data left in the temporary vectors, flush them + if (pMesh && vertices->size() && faces->size()) { + populateMesh(m3d, pMesh, faces, vertices, normals, texcoords, colors, vertexids); + meshes->push_back(pMesh); + } - delete meshes; - if(faces) delete faces; - if(vertices) delete vertices; - if(normals) delete normals; - if(texcoords) delete texcoords; - if(colors) delete colors; - if(vertexids) delete vertexids; + // create global mesh list in scene + mScene->mNumMeshes = static_cast(meshes->size()); + mScene->mMeshes = new aiMesh *[mScene->mNumMeshes]; + std::copy(meshes->begin(), meshes->end(), mScene->mMeshes); + + // create mesh indeces in root node + mScene->mRootNode->mNumMeshes = static_cast(meshes->size()); + mScene->mRootNode->mMeshes = new unsigned int[meshes->size()]; + for (i = 0; i < meshes->size(); i++) { + mScene->mRootNode->mMeshes[i] = i; + } + + delete meshes; + if (faces) delete faces; + if (vertices) delete vertices; + if (normals) delete normals; + if (texcoords) delete texcoords; + if (colors) delete colors; + if (vertexids) delete vertexids; } // ------------------------------------------------------------------------------------------------ // a reentrant node parser. Otherwise this is simple -void M3DImporter::importBones(unsigned int parentid, aiNode *pParent) -{ - unsigned int i, n; +void M3DImporter::importBones(const M3DWrapper &m3d, unsigned int parentid, aiNode *pParent) { + unsigned int i, n; - ai_assert(pParent != nullptr); - ai_assert(mScene != nullptr); - ai_assert(m3d != nullptr); + ai_assert(pParent != nullptr); + ai_assert(mScene != nullptr); + ai_assert(m3d); - ASSIMP_LOG_DEBUG_F("M3D: importBones ", m3d->numbone, " parentid ", (int)parentid); + ASSIMP_LOG_DEBUG_F("M3D: importBones ", m3d->numbone, " parentid ", (int)parentid); - for(n = 0, i = parentid + 1; i < m3d->numbone; i++) - if(m3d->bone[i].parent == parentid) n++; - pParent->mChildren = new aiNode*[n]; + if (!m3d->numbone || !m3d->bone) { + return; + } - for(i = parentid + 1; i < m3d->numbone; i++) { - if(m3d->bone[i].parent == parentid) { - aiNode *pChild = new aiNode; - pChild->mParent = pParent; - pChild->mName = aiString(std::string(m3d->bone[i].name)); - convertPose(&pChild->mTransformation, m3d->bone[i].pos, m3d->bone[i].ori); - pChild->mNumChildren = 0; - pParent->mChildren[pParent->mNumChildren] = pChild; - pParent->mNumChildren++; - importBones(i, pChild); - } - } + for (n = 0, i = parentid + 1; i < m3d->numbone; i++) { + if (m3d->bone[i].parent == parentid) { + n++; + } + } + pParent->mChildren = new aiNode *[n]; + + for (i = parentid + 1; i < m3d->numbone; i++) { + if (m3d->bone[i].parent == parentid) { + aiNode *pChild = new aiNode; + pChild->mParent = pParent; + pChild->mName = aiString(std::string(m3d->bone[i].name)); + convertPose(m3d, &pChild->mTransformation, m3d->bone[i].pos, m3d->bone[i].ori); + pChild->mNumChildren = 0; + pParent->mChildren[pParent->mNumChildren] = pChild; + pParent->mNumChildren++; + importBones(m3d, i, pChild); + } + } } // ------------------------------------------------------------------------------------------------ // this is another headache. M3D stores list of changed bone id/position/orientation triplets and // a timestamp per frame, but assimp needs timestamp and lists of position, orientation lists per // bone, so we have to convert between the two conceptually different representation forms -void M3DImporter::importAnimations() -{ - unsigned int i, j, k, l, pos, ori; - double t; - m3da_t *a; +void M3DImporter::importAnimations(const M3DWrapper &m3d) { + unsigned int i, j, k, l, pos, ori; + double t; + m3da_t *a; - ai_assert(mScene != nullptr); - ai_assert(m3d != nullptr); + ai_assert(mScene != nullptr); + ai_assert(m3d); - mScene->mNumAnimations = m3d->numaction; + mScene->mNumAnimations = m3d->numaction; - ASSIMP_LOG_DEBUG_F("M3D: importAnimations ", mScene->mNumAnimations); + ASSIMP_LOG_DEBUG_F("M3D: importAnimations ", mScene->mNumAnimations); - if(!m3d->numaction || !m3d->numbone) - return; + if (!m3d->numaction || !m3d->action || !m3d->numbone || !m3d->bone || !m3d->vertex) { + return; + } - mScene->mAnimations = new aiAnimation*[m3d->numaction]; - for(i = 0; i < m3d->numaction; i++) { - a = &m3d->action[i]; - aiAnimation *pAnim = new aiAnimation; - pAnim->mName = aiString(std::string(a->name)); - pAnim->mDuration = ((double)a->durationmsec) / 10; - pAnim->mTicksPerSecond = 100; - // now we know how many bones are referenced in this animation - pAnim->mNumChannels = m3d->numbone; - pAnim->mChannels = new aiNodeAnim*[pAnim->mNumChannels]; - for(l = 0; l < m3d->numbone; l++) { - unsigned int n; - pAnim->mChannels[l] = new aiNodeAnim; - pAnim->mChannels[l]->mNodeName = aiString(std::string(m3d->bone[l].name)); - // now n is the size of positions / orientations arrays - pAnim->mChannels[l]->mNumPositionKeys = pAnim->mChannels[l]->mNumRotationKeys = a->numframe; - pAnim->mChannels[l]->mPositionKeys = new aiVectorKey[a->numframe]; - pAnim->mChannels[l]->mRotationKeys = new aiQuatKey[a->numframe]; - pos = m3d->bone[l].pos; - ori = m3d->bone[l].ori; - for(j = n = 0; j < a->numframe; j++) { - t = ((double)a->frame[j].msec) / 10; - for(k = 0; k < a->frame[j].numtransform; k++) { - if(a->frame[j].transform[k].boneid == l) { - pos = a->frame[j].transform[k].pos; - ori = a->frame[j].transform[k].ori; - } - } - m3dv_t *v = &m3d->vertex[pos]; - m3dv_t *q = &m3d->vertex[ori]; - pAnim->mChannels[l]->mPositionKeys[j].mTime = t; - pAnim->mChannels[l]->mPositionKeys[j].mValue.x = v->x; - pAnim->mChannels[l]->mPositionKeys[j].mValue.y = v->y; - pAnim->mChannels[l]->mPositionKeys[j].mValue.z = v->z; - pAnim->mChannels[l]->mRotationKeys[j].mTime = t; - pAnim->mChannels[l]->mRotationKeys[j].mValue.w = q->w; - pAnim->mChannels[l]->mRotationKeys[j].mValue.x = q->x; - pAnim->mChannels[l]->mRotationKeys[j].mValue.y = q->y; - pAnim->mChannels[l]->mRotationKeys[j].mValue.z = q->z; - }// foreach frame - }// foreach bones - mScene->mAnimations[i] = pAnim; - } + mScene->mAnimations = new aiAnimation *[m3d->numaction]; + for (i = 0; i < m3d->numaction; i++) { + a = &m3d->action[i]; + aiAnimation *pAnim = new aiAnimation; + pAnim->mName = aiString(std::string(a->name)); + pAnim->mDuration = ((double)a->durationmsec) / 10; + pAnim->mTicksPerSecond = 100; + // now we know how many bones are referenced in this animation + pAnim->mNumChannels = m3d->numbone; + pAnim->mChannels = new aiNodeAnim *[pAnim->mNumChannels]; + for (l = 0; l < m3d->numbone; l++) { + unsigned int n; + pAnim->mChannels[l] = new aiNodeAnim; + pAnim->mChannels[l]->mNodeName = aiString(std::string(m3d->bone[l].name)); + // now n is the size of positions / orientations arrays + pAnim->mChannels[l]->mNumPositionKeys = pAnim->mChannels[l]->mNumRotationKeys = a->numframe; + pAnim->mChannels[l]->mPositionKeys = new aiVectorKey[a->numframe]; + pAnim->mChannels[l]->mRotationKeys = new aiQuatKey[a->numframe]; + pos = m3d->bone[l].pos; + ori = m3d->bone[l].ori; + for (j = n = 0; j < a->numframe; j++) { + t = ((double)a->frame[j].msec) / 10; + for (k = 0; k < a->frame[j].numtransform; k++) { + if (a->frame[j].transform[k].boneid == l) { + pos = a->frame[j].transform[k].pos; + ori = a->frame[j].transform[k].ori; + } + } + if(pos >= m3d->numvertex || ori >= m3d->numvertex) continue; + m3dv_t *v = &m3d->vertex[pos]; + m3dv_t *q = &m3d->vertex[ori]; + pAnim->mChannels[l]->mPositionKeys[j].mTime = t; + pAnim->mChannels[l]->mPositionKeys[j].mValue.x = v->x; + pAnim->mChannels[l]->mPositionKeys[j].mValue.y = v->y; + pAnim->mChannels[l]->mPositionKeys[j].mValue.z = v->z; + pAnim->mChannels[l]->mRotationKeys[j].mTime = t; + pAnim->mChannels[l]->mRotationKeys[j].mValue.w = q->w; + pAnim->mChannels[l]->mRotationKeys[j].mValue.x = q->x; + pAnim->mChannels[l]->mRotationKeys[j].mValue.y = q->y; + pAnim->mChannels[l]->mRotationKeys[j].mValue.z = q->z; + } // foreach frame + } // foreach bones + mScene->mAnimations[i] = pAnim; + } } // ------------------------------------------------------------------------------------------------ // convert uint32_t into aiColor4D aiColor4D M3DImporter::mkColor(uint32_t c) { - aiColor4D color; - color.a = ((float)((c >> 24)&0xff)) / 255; - color.b = ((float)((c >> 16)&0xff)) / 255; - color.g = ((float)((c >> 8)&0xff)) / 255; - color.r = ((float)((c >> 0)&0xff)) / 255; - return color; + aiColor4D color; + color.a = ((float)((c >> 24) & 0xff)) / 255; + color.b = ((float)((c >> 16) & 0xff)) / 255; + color.g = ((float)((c >> 8) & 0xff)) / 255; + color.r = ((float)((c >> 0) & 0xff)) / 255; + return color; } // ------------------------------------------------------------------------------------------------ // convert a position id and orientation id into a 4 x 4 transformation matrix -void M3DImporter::convertPose(aiMatrix4x4 *m, unsigned int posid, unsigned int orientid) -{ - ai_assert(m != nullptr); - ai_assert(m3d != nullptr); - ai_assert(posid != -1U && posid < m3d->numvertex); - ai_assert(orientid != -1U && orientid < m3d->numvertex); - m3dv_t *p = &m3d->vertex[posid]; - m3dv_t *q = &m3d->vertex[orientid]; +void M3DImporter::convertPose(const M3DWrapper &m3d, aiMatrix4x4 *m, unsigned int posid, unsigned int orientid) { + ai_assert(m != nullptr); + ai_assert(m3d); + ai_assert(posid != M3D_UNDEF && posid < m3d->numvertex); + ai_assert(orientid != M3D_UNDEF && orientid < m3d->numvertex); + if (!m3d->numvertex || !m3d->vertex) + return; + m3dv_t *p = &m3d->vertex[posid]; + m3dv_t *q = &m3d->vertex[orientid]; - /* quaternion to matrix. Do NOT use aiQuaternion to aiMatrix3x3, gives bad results */ - if(q->x == 0.0 && q->y == 0.0 && q->z >= 0.7071065 && q->z <= 0.7071075 && q->w == 0.0) { - m->a2 = m->a3 = m->b1 = m->b3 = m->c1 = m->c2 = 0.0; - m->a1 = m->b2 = m->c3 = -1.0; - } else { - m->a1 = 1 - 2 * (q->y * q->y + q->z * q->z); if(m->a1 > -1e-7 && m->a1 < 1e-7) m->a1 = 0.0; - m->a2 = 2 * (q->x * q->y - q->z * q->w); if(m->a2 > -1e-7 && m->a2 < 1e-7) m->a2 = 0.0; - m->a3 = 2 * (q->x * q->z + q->y * q->w); if(m->a3 > -1e-7 && m->a3 < 1e-7) m->a3 = 0.0; - m->b1 = 2 * (q->x * q->y + q->z * q->w); if(m->b1 > -1e-7 && m->b1 < 1e-7) m->b1 = 0.0; - m->b2 = 1 - 2 * (q->x * q->x + q->z * q->z); if(m->b2 > -1e-7 && m->b2 < 1e-7) m->b2 = 0.0; - m->b3 = 2 * (q->y * q->z - q->x * q->w); if(m->b3 > -1e-7 && m->b3 < 1e-7) m->b3 = 0.0; - m->c1 = 2 * (q->x * q->z - q->y * q->w); if(m->c1 > -1e-7 && m->c1 < 1e-7) m->c1 = 0.0; - m->c2 = 2 * (q->y * q->z + q->x * q->w); if(m->c2 > -1e-7 && m->c2 < 1e-7) m->c2 = 0.0; - m->c3 = 1 - 2 * (q->x * q->x + q->y * q->y); if(m->c3 > -1e-7 && m->c3 < 1e-7) m->c3 = 0.0; - } + /* quaternion to matrix. Do NOT use aiQuaternion to aiMatrix3x3, gives bad results */ + if (q->x == 0.0 && q->y == 0.0 && q->z >= 0.7071065 && q->z <= 0.7071075 && q->w == 0.0) { + m->a2 = m->a3 = m->b1 = m->b3 = m->c1 = m->c2 = 0.0; + m->a1 = m->b2 = m->c3 = -1.0; + } else { + m->a1 = 1 - 2 * (q->y * q->y + q->z * q->z); + if (m->a1 > -M3D_EPSILON && m->a1 < M3D_EPSILON) m->a1 = 0.0; + m->a2 = 2 * (q->x * q->y - q->z * q->w); + if (m->a2 > -M3D_EPSILON && m->a2 < M3D_EPSILON) m->a2 = 0.0; + m->a3 = 2 * (q->x * q->z + q->y * q->w); + if (m->a3 > -M3D_EPSILON && m->a3 < M3D_EPSILON) m->a3 = 0.0; + m->b1 = 2 * (q->x * q->y + q->z * q->w); + if (m->b1 > -M3D_EPSILON && m->b1 < M3D_EPSILON) m->b1 = 0.0; + m->b2 = 1 - 2 * (q->x * q->x + q->z * q->z); + if (m->b2 > -M3D_EPSILON && m->b2 < M3D_EPSILON) m->b2 = 0.0; + m->b3 = 2 * (q->y * q->z - q->x * q->w); + if (m->b3 > -M3D_EPSILON && m->b3 < M3D_EPSILON) m->b3 = 0.0; + m->c1 = 2 * (q->x * q->z - q->y * q->w); + if (m->c1 > -M3D_EPSILON && m->c1 < M3D_EPSILON) m->c1 = 0.0; + m->c2 = 2 * (q->y * q->z + q->x * q->w); + if (m->c2 > -M3D_EPSILON && m->c2 < M3D_EPSILON) m->c2 = 0.0; + m->c3 = 1 - 2 * (q->x * q->x + q->y * q->y); + if (m->c3 > -M3D_EPSILON && m->c3 < M3D_EPSILON) m->c3 = 0.0; + } - /* set translation */ - m->a4 = p->x; m->b4 = p->y; m->c4 = p->z; + /* set translation */ + m->a4 = p->x; + m->b4 = p->y; + m->c4 = p->z; - m->d1 = 0; m->d2 = 0; m->d3 = 0; m->d4 = 1; + m->d1 = 0; + m->d2 = 0; + m->d3 = 0; + m->d4 = 1; } // ------------------------------------------------------------------------------------------------ // find a node by name -aiNode *M3DImporter::findNode(aiNode *pNode, aiString name) -{ - unsigned int i; +aiNode *M3DImporter::findNode(aiNode *pNode, aiString name) { + ai_assert(pNode != nullptr); + ai_assert(mScene != nullptr); - ai_assert(pNode != nullptr); - ai_assert(mScene != nullptr); + if (pNode->mName == name) { + return pNode; + } - if(pNode->mName == name) - return pNode; - for(i = 0; i < pNode->mNumChildren; i++) { - aiNode *pChild = findNode(pNode->mChildren[i], name); - if(pChild) return pChild; - } - return nullptr; + for (unsigned int i = 0; i < pNode->mNumChildren; i++) { + aiNode *pChild = findNode(pNode->mChildren[i], name); + if (pChild) { + return pChild; + } + } + return nullptr; } // ------------------------------------------------------------------------------------------------ // fills up offsetmatrix in mBones -void M3DImporter::calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m) -{ - ai_assert(pNode != nullptr); - ai_assert(mScene != nullptr); +void M3DImporter::calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m) { + ai_assert(pNode != nullptr); + ai_assert(mScene != nullptr); - if(pNode->mParent) { - calculateOffsetMatrix(pNode->mParent, m); - *m *= pNode->mTransformation; - } else { - *m = pNode->mTransformation; - } + if (pNode->mParent) { + calculateOffsetMatrix(pNode->mParent, m); + *m *= pNode->mTransformation; + } else { + *m = pNode->mTransformation; + } } // ------------------------------------------------------------------------------------------------ // because M3D has a global mesh, global vertex ids and stores materialid on the face, we need // temporary lists to collect data for an aiMesh, which requires local arrays and local indeces // this function fills up an aiMesh with those temporary lists -void M3DImporter::populateMesh(aiMesh *pMesh, std::vector *faces, std::vector *vertices, - std::vector *normals, std::vector *texcoords, std::vector *colors, - std::vector *vertexids) { +void M3DImporter::populateMesh(const M3DWrapper &m3d, aiMesh *pMesh, std::vector *faces, std::vector *vertices, + std::vector *normals, std::vector *texcoords, std::vector *colors, + std::vector *vertexids) { - ai_assert(pMesh != nullptr); - ai_assert(faces != nullptr); - ai_assert(vertices != nullptr); - ai_assert(normals != nullptr); - ai_assert(texcoords != nullptr); - ai_assert(colors != nullptr); - ai_assert(vertexids != nullptr); - ai_assert(m3d != nullptr); + ai_assert(pMesh != nullptr); + ai_assert(faces != nullptr); + ai_assert(vertices != nullptr); + ai_assert(normals != nullptr); + ai_assert(texcoords != nullptr); + ai_assert(colors != nullptr); + ai_assert(vertexids != nullptr); + ai_assert(m3d); - ASSIMP_LOG_DEBUG_F("M3D: populateMesh numvertices ", vertices->size(), " numfaces ", faces->size(), - " numnormals ", normals->size(), " numtexcoord ", texcoords->size(), " numbones ", m3d->numbone); + ASSIMP_LOG_DEBUG_F("M3D: populateMesh numvertices ", vertices->size(), " numfaces ", faces->size(), + " numnormals ", normals->size(), " numtexcoord ", texcoords->size(), " numbones ", m3d->numbone); - if(vertices->size() && faces->size()) { - pMesh->mNumFaces = faces->size(); - pMesh->mFaces = new aiFace[pMesh->mNumFaces]; - std::copy(faces->begin(), faces->end(), pMesh->mFaces); - pMesh->mNumVertices = vertices->size(); - pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; - std::copy(vertices->begin(), vertices->end(), pMesh->mVertices); - if(normals->size() == vertices->size()) { - pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; - std::copy(normals->begin(), normals->end(), pMesh->mNormals); - } - if(texcoords->size() == vertices->size()) { - pMesh->mTextureCoords[0] = new aiVector3D[pMesh->mNumVertices]; - std::copy(texcoords->begin(), texcoords->end(), pMesh->mTextureCoords[0]); - pMesh->mNumUVComponents[0] = 2; - } - if(colors->size() == vertices->size()) { - pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices]; - std::copy(colors->begin(), colors->end(), pMesh->mColors[0]); - } - // this is complicated, because M3D stores a list of bone id / weight pairs per - // vertex but assimp uses lists of local vertex id/weight pairs per local bone list - pMesh->mNumBones = m3d->numbone; - /* we need aiBone with mOffsetMatrix for bones without weights as well */ - if(pMesh->mNumBones) { - pMesh->mBones = new aiBone*[pMesh->mNumBones]; - for(unsigned int i = 0; i < m3d->numbone; i++) { - aiNode *pNode; - pMesh->mBones[i] = new aiBone; - pMesh->mBones[i]->mName = aiString(std::string(m3d->bone[i].name)); - pMesh->mBones[i]->mNumWeights = 0; - pNode = findNode(mScene->mRootNode, pMesh->mBones[i]->mName); - if(pNode) { - calculateOffsetMatrix(pNode, &pMesh->mBones[i]->mOffsetMatrix); - pMesh->mBones[i]->mOffsetMatrix.Inverse(); - } else - pMesh->mBones[i]->mOffsetMatrix = aiMatrix4x4(); - } - if(vertexids->size()) { - unsigned int i, j; - // first count how many vertices we have per bone - for(i = 0; i < vertexids->size(); i++) { - unsigned int s = m3d->vertex[vertexids->at(i)].skinid; - if(s != -1U && s!= -2U) { - for(unsigned int k = 0; k < M3D_NUMBONE && m3d->skin[s].weight[k] > 0.0; k++) { - aiString name = aiString(std::string(m3d->bone[m3d->skin[s].boneid[k]].name)); - for(j = 0; j < pMesh->mNumBones; j++) { - if(pMesh->mBones[j]->mName == name) { - pMesh->mBones[j]->mNumWeights++; - break; - } - } - } - } - } - // allocate mWeights - for(j = 0; j < pMesh->mNumBones; j++) { - aiBone *pBone = pMesh->mBones[j]; - if(pBone->mNumWeights) { - pBone->mWeights = new aiVertexWeight[pBone->mNumWeights]; - pBone->mNumWeights = 0; - } - } - // fill up with data - for(i = 0; i < vertexids->size(); i++) { - unsigned int s = m3d->vertex[vertexids->at(i)].skinid; - if(s != -1U && s!= -2U) { - for(unsigned int k = 0; k < M3D_NUMBONE && m3d->skin[s].weight[k] > 0.0; k++) { - aiString name = aiString(std::string(m3d->bone[m3d->skin[s].boneid[k]].name)); - for(j = 0; j < pMesh->mNumBones; j++) { - if(pMesh->mBones[j]->mName == name) { - aiBone *pBone = pMesh->mBones[j]; - pBone->mWeights[pBone->mNumWeights].mVertexId = i; - pBone->mWeights[pBone->mNumWeights].mWeight = m3d->skin[s].weight[k]; - pBone->mNumWeights++; - break; - } - } - } // foreach skin - } - } // foreach vertexids - } - } - } + if (vertices->size() && faces->size()) { + pMesh->mNumFaces = static_cast(faces->size()); + pMesh->mFaces = new aiFace[pMesh->mNumFaces]; + std::copy(faces->begin(), faces->end(), pMesh->mFaces); + pMesh->mNumVertices = static_cast(vertices->size()); + pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; + std::copy(vertices->begin(), vertices->end(), pMesh->mVertices); + if (normals->size() == vertices->size()) { + pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; + std::copy(normals->begin(), normals->end(), pMesh->mNormals); + } + if (texcoords->size() == vertices->size()) { + pMesh->mTextureCoords[0] = new aiVector3D[pMesh->mNumVertices]; + std::copy(texcoords->begin(), texcoords->end(), pMesh->mTextureCoords[0]); + pMesh->mNumUVComponents[0] = 2; + } + if (colors->size() == vertices->size()) { + pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices]; + std::copy(colors->begin(), colors->end(), pMesh->mColors[0]); + } + // this is complicated, because M3D stores a list of bone id / weight pairs per + // vertex but assimp uses lists of local vertex id/weight pairs per local bone list + pMesh->mNumBones = m3d->numbone; + // we need aiBone with mOffsetMatrix for bones without weights as well + if (pMesh->mNumBones && m3d->numbone && m3d->bone) { + pMesh->mBones = new aiBone *[pMesh->mNumBones]; + for (unsigned int i = 0; i < m3d->numbone; i++) { + aiNode *pNode; + pMesh->mBones[i] = new aiBone; + pMesh->mBones[i]->mName = aiString(std::string(m3d->bone[i].name)); + pMesh->mBones[i]->mNumWeights = 0; + pNode = findNode(mScene->mRootNode, pMesh->mBones[i]->mName); + if (pNode) { + calculateOffsetMatrix(pNode, &pMesh->mBones[i]->mOffsetMatrix); + pMesh->mBones[i]->mOffsetMatrix.Inverse(); + } else + pMesh->mBones[i]->mOffsetMatrix = aiMatrix4x4(); + } + if (vertexids->size() && m3d->numvertex && m3d->vertex && m3d->numskin && m3d->skin) { + unsigned int i, j; + // first count how many vertices we have per bone + for (i = 0; i < vertexids->size(); i++) { + if(vertexids->at(i) >= m3d->numvertex) { + continue; + } + unsigned int s = m3d->vertex[vertexids->at(i)].skinid; + if (s != M3D_UNDEF && s != M3D_INDEXMAX) { + for (unsigned int k = 0; k < M3D_NUMBONE && m3d->skin[s].weight[k] > 0.0; k++) { + aiString name = aiString(std::string(m3d->bone[m3d->skin[s].boneid[k]].name)); + for (j = 0; j < pMesh->mNumBones; j++) { + if (pMesh->mBones[j]->mName == name) { + pMesh->mBones[j]->mNumWeights++; + break; + } + } + } + } + } + // allocate mWeights + for (j = 0; j < pMesh->mNumBones; j++) { + aiBone *pBone = pMesh->mBones[j]; + if (pBone->mNumWeights) { + pBone->mWeights = new aiVertexWeight[pBone->mNumWeights]; + pBone->mNumWeights = 0; + } + } + // fill up with data + for (i = 0; i < vertexids->size(); i++) { + if(vertexids->at(i) >= m3d->numvertex) continue; + unsigned int s = m3d->vertex[vertexids->at(i)].skinid; + if (s != M3D_UNDEF && s != M3D_INDEXMAX && s < m3d->numskin) { + for (unsigned int k = 0; k < M3D_NUMBONE && m3d->skin[s].weight[k] > 0.0; k++) { + if(m3d->skin[s].boneid[k] >= m3d->numbone) continue; + aiString name = aiString(std::string(m3d->bone[m3d->skin[s].boneid[k]].name)); + for (j = 0; j < pMesh->mNumBones; j++) { + if (pMesh->mBones[j]->mName == name) { + aiBone *pBone = pMesh->mBones[j]; + pBone->mWeights[pBone->mNumWeights].mVertexId = i; + pBone->mWeights[pBone->mNumWeights].mWeight = m3d->skin[s].weight[k]; + pBone->mNumWeights++; + break; + } + } + } // foreach skin + } + } // foreach vertexids + } + } + } } // ------------------------------------------------------------------------------------------------ -} // Namespace Assimp +} // Namespace Assimp #endif // !! ASSIMP_BUILD_NO_M3D_IMPORTER diff --git a/Engine/lib/assimp/code/M3D/M3DImporter.h b/Engine/lib/assimp/code/M3D/M3DImporter.h index 06cc757b6..5c9d4fad8 100644 --- a/Engine/lib/assimp/code/M3D/M3DImporter.h +++ b/Engine/lib/assimp/code/M3D/M3DImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team Copyright (c) 2019 bzt All rights reserved. @@ -48,7 +48,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_M3D_IMPORTER -#include "m3d.h" #include #include #include @@ -60,43 +59,41 @@ struct aiFace; namespace Assimp { +class M3DWrapper; + class M3DImporter : public BaseImporter { public: - /// \brief Default constructor - M3DImporter(); - - /// \brief Destructor - ~M3DImporter(); + /// \brief Default constructor + M3DImporter(); public: - /// \brief Returns whether the class can handle the format of the given file. - /// \remark See BaseImporter::CanRead() for details. - bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const; + /// \brief Returns whether the class can handle the format of the given file. + /// \remark See BaseImporter::CanRead() for details. + bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const; private: - aiScene* mScene; // the scene to import to - m3d_t *m3d; // model for the C library to convert from + aiScene *mScene = nullptr; // the scene to import to - //! \brief Appends the supported extension. - const aiImporterDesc* GetInfo () const; + //! \brief Appends the supported extension. + const aiImporterDesc *GetInfo() const; - //! \brief File import implementation. - void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); + //! \brief File import implementation. + void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler); - void importMaterials(); - void importTextures(); - void importMeshes(); - void importBones(unsigned int parentid, aiNode *pParent); - void importAnimations(); + void importMaterials(const M3DWrapper &m3d); + void importTextures(const M3DWrapper &m3d); + void importMeshes(const M3DWrapper &m3d); + void importBones(const M3DWrapper &m3d, unsigned int parentid, aiNode *pParent); + void importAnimations(const M3DWrapper &m3d); - // helper functions - aiColor4D mkColor(uint32_t c); - void convertPose(aiMatrix4x4 *m, unsigned int posid, unsigned int orientid); - aiNode *findNode(aiNode *pNode, aiString name); - void calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m); - void populateMesh(aiMesh *pMesh, std::vector *faces, std::vector *verteces, - std::vector *normals, std::vector *texcoords, std::vector *colors, - std::vector *vertexids); + // helper functions + aiColor4D mkColor(uint32_t c); + void convertPose(const M3DWrapper &m3d, aiMatrix4x4 *m, unsigned int posid, unsigned int orientid); + aiNode *findNode(aiNode *pNode, aiString name); + void calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m); + void populateMesh(const M3DWrapper &m3d, aiMesh *pMesh, std::vector *faces, std::vector *verteces, + std::vector *normals, std::vector *texcoords, std::vector *colors, + std::vector *vertexids); }; } // Namespace Assimp diff --git a/Engine/lib/assimp/code/M3D/M3DMaterials.h b/Engine/lib/assimp/code/M3D/M3DMaterials.h index fa02cf42b..469ddf52b 100644 --- a/Engine/lib/assimp/code/M3D/M3DMaterials.h +++ b/Engine/lib/assimp/code/M3D/M3DMaterials.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team Copyright (c) 2019 bzt All rights reserved. @@ -75,7 +75,7 @@ static const aiMatProp aiProps[] = { { AI_MATKEY_REFLECTIVITY }, /* m3dp_Pm */ { NULL, 0, 0 }, /* m3dp_Ps */ { AI_MATKEY_REFRACTI }, /* m3dp_Ni */ - { NULL, 0, 0 }, + { NULL, 0, 0 }, /* m3dp_Nt */ { NULL, 0, 0 }, { NULL, 0, 0 }, { NULL, 0, 0 } @@ -84,20 +84,20 @@ static const aiMatProp aiProps[] = { /* --- Texture Map Properties --- !!!!! must match m3d_propertytypes !!!!! */ static const aiMatProp aiTxProps[] = { { AI_MATKEY_TEXTURE_DIFFUSE(0) }, /* m3dp_map_Kd */ - { AI_MATKEY_TEXTURE_AMBIENT(0) }, /* m3dp_map_Ka */ + { AI_MATKEY_TEXTURE(aiTextureType_AMBIENT_OCCLUSION,0) },/* m3dp_map_Ka */ { AI_MATKEY_TEXTURE_SPECULAR(0) }, /* m3dp_map_Ks */ { AI_MATKEY_TEXTURE_SHININESS(0) }, /* m3dp_map_Ns */ { AI_MATKEY_TEXTURE_EMISSIVE(0) }, /* m3dp_map_Ke */ { NULL, 0, 0 }, /* m3dp_map_Tf */ { AI_MATKEY_TEXTURE_HEIGHT(0) }, /* m3dp_bump */ { AI_MATKEY_TEXTURE_OPACITY(0) }, /* m3dp_map_d */ - { AI_MATKEY_TEXTURE_REFLECTION(0) }, /* m3dp_refl */ + { AI_MATKEY_TEXTURE_NORMALS(0) }, /* m3dp_map_N */ { AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE_ROUGHNESS,0) },/* m3dp_map_Pr */ { AI_MATKEY_TEXTURE(aiTextureType_METALNESS,0) }, /* m3dp_map_Pm */ { NULL, 0, 0 }, /* m3dp_map_Ps */ - { AI_MATKEY_TEXTURE(aiTextureType_AMBIENT_OCCLUSION,0) },/* m3dp_map_Ni */ - { NULL, 0, 0 }, + { AI_MATKEY_TEXTURE(aiTextureType_REFLECTION,0) }, /* m3dp_map_Ni */ + { NULL, 0, 0 }, /* m3dp_map_Nt */ { NULL, 0, 0 }, { NULL, 0, 0 }, { NULL, 0, 0 } diff --git a/Engine/lib/assimp/code/M3D/M3DWrapper.cpp b/Engine/lib/assimp/code/M3D/M3DWrapper.cpp new file mode 100644 index 000000000..6ab59b2f0 --- /dev/null +++ b/Engine/lib/assimp/code/M3D/M3DWrapper.cpp @@ -0,0 +1,142 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team +Copyright (c) 2019 bzt + +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. + +---------------------------------------------------------------------- +*/ + +#if !(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER) || !ASSIMP_BUILD_NO_M3D_IMPORTER + +#include "M3DWrapper.h" + +#include +#include +#include + +#ifdef ASSIMP_USE_M3D_READFILECB + +# if (__cplusplus >= 201103L) || !defined(_MSC_VER) || (_MSC_VER >= 1900) // C++11 and MSVC 2015 onwards +# define threadlocal thread_local +# else +# if defined(_MSC_VER) && (_MSC_VER >= 1800) // there's an alternative for MSVC 2013 +# define threadlocal __declspec(thread) +# else +# define threadlocal +# endif +# endif + +extern "C" { + +// workaround: the M3D SDK expects a C callback, but we want to use Assimp::IOSystem to implement that +threadlocal void *m3dimporter_pIOHandler; + +unsigned char *m3dimporter_readfile(char *fn, unsigned int *size) { + ai_assert(nullptr != fn); + ai_assert(nullptr != size); + std::string file(fn); + std::unique_ptr pStream( + (reinterpret_cast(m3dimporter_pIOHandler))->Open(file, "rb")); + size_t fileSize = 0; + unsigned char *data = NULL; + // sometimes pStream is nullptr in a single-threaded scenario too for some reason + // (should be an empty object returning nothing I guess) + if (pStream) { + fileSize = pStream->FileSize(); + // should be allocated with malloc(), because the library will call free() to deallocate + data = (unsigned char *)malloc(fileSize); + if (!data || !pStream.get() || !fileSize || fileSize != pStream->Read(data, 1, fileSize)) { + pStream.reset(); + *size = 0; + // don't throw a deadly exception, it's not fatal if we can't read an external asset + return nullptr; + } + pStream.reset(); + } + *size = (int)fileSize; + return data; +} +} +#endif + +namespace Assimp { +M3DWrapper::M3DWrapper() { + // use malloc() here because m3d_free() will call free() + m3d_ = (m3d_t *)calloc(1, sizeof(m3d_t)); +} + +M3DWrapper::M3DWrapper(IOSystem *pIOHandler, const std::vector &buffer) { +#ifdef ASSIMP_USE_M3D_READFILECB + // pass this IOHandler to the C callback in a thread-local pointer + m3dimporter_pIOHandler = pIOHandler; + m3d_ = m3d_load(const_cast(buffer.data()), m3dimporter_readfile, free, nullptr); + // Clear the C callback + m3dimporter_pIOHandler = nullptr; +#else + m3d_ = m3d_load(const_cast(buffer.data()), nullptr, nullptr, nullptr); +#endif +} + +M3DWrapper::~M3DWrapper() { + reset(); +} + +void M3DWrapper::reset() { + ClearSave(); + if (m3d_) + m3d_free(m3d_); + m3d_ = nullptr; +} + +unsigned char *M3DWrapper::Save(int quality, int flags, unsigned int &size) { +#if (!(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER)) + ClearSave(); + saved_output_ = m3d_save(m3d_, quality, flags, &size); + return saved_output_; +#else + return nullptr; +#endif +} + +void M3DWrapper::ClearSave() { + if (saved_output_) + M3D_FREE(saved_output_); + saved_output_ = nullptr; +} +} // namespace Assimp + +#endif diff --git a/Engine/lib/assimp/code/M3D/M3DWrapper.h b/Engine/lib/assimp/code/M3D/M3DWrapper.h new file mode 100644 index 000000000..bf3ab7bc9 --- /dev/null +++ b/Engine/lib/assimp/code/M3D/M3DWrapper.h @@ -0,0 +1,101 @@ +#pragma once +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team +Copyright (c) 2019 bzt + +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. + +---------------------------------------------------------------------- +*/ + +/** @file M3DWrapper.h +* @brief Declares a class to wrap the C m3d SDK +*/ +#ifndef AI_M3DWRAPPER_H_INC +#define AI_M3DWRAPPER_H_INC +#if !(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER) || !ASSIMP_BUILD_NO_M3D_IMPORTER + +#include +#include +#include + +// Assimp specific M3D configuration. Comment out these defines to remove functionality +//#define ASSIMP_USE_M3D_READFILECB +//#define M3D_ASCII + +#include "m3d.h" + +namespace Assimp { +class IOSystem; + +class M3DWrapper { + m3d_t *m3d_ = nullptr; + unsigned char *saved_output_ = nullptr; + +public: + // Construct an empty M3D model + explicit M3DWrapper(); + + // Construct an M3D model from provided buffer + // NOTE: The m3d.h SDK function does not mark the data as const. Have assumed it does not write. + // BUG: SECURITY: The m3d.h SDK cannot be informed of the buffer size. BUFFER OVERFLOW IS CERTAIN + explicit M3DWrapper(IOSystem *pIOHandler, const std::vector &buffer); + + ~M3DWrapper(); + + void reset(); + + // Name + inline std::string Name() const { + if (m3d_) return std::string(m3d_->name); + return std::string(); + } + + // Execute a save + unsigned char *Save(int quality, int flags, unsigned int &size); + void ClearSave(); + + inline explicit operator bool() const { return m3d_ != nullptr; } + + // Allow direct access to M3D API + inline m3d_t *operator->() const { return m3d_; } + inline m3d_t *M3D() const { return m3d_; } +}; +} // namespace Assimp + +#endif + +#endif // AI_M3DWRAPPER_H_INC diff --git a/Engine/lib/assimp/code/M3D/m3d.h b/Engine/lib/assimp/code/M3D/m3d.h index 9ace802ef..d09348497 100644 --- a/Engine/lib/assimp/code/M3D/m3d.h +++ b/Engine/lib/assimp/code/M3D/m3d.h @@ -58,16 +58,26 @@ extern "C" { #define M3D_APIVERSION 0x0100 #ifndef M3D_DOUBLE typedef float M3D_FLOAT; +#ifndef M3D_EPSILON +/* carefully choosen for IEEE 754 don't change */ +#define M3D_EPSILON ((M3D_FLOAT)1e-7) +#endif #else typedef double M3D_FLOAT; +#ifndef M3D_EPSILON +#define M3D_EPSILON ((M3D_FLOAT)1e-14) +#endif #endif #if !defined(M3D_SMALLINDEX) typedef uint32_t M3D_INDEX; +#define M3D_UNDEF 0xffffffff #define M3D_INDEXMAX 0xfffffffe #else typedef uint16_t M3D_INDEX; +#define M3D_UNDEF 0xffff #define M3D_INDEXMAX 0xfffe #endif +#define M3D_NOTDEFINED 0xffffffff #ifndef M3D_NUMBONE #define M3D_NUMBONE 4 #endif @@ -81,7 +91,7 @@ typedef uint16_t M3D_INDEX; #else #define _inline #define _pack -#define _unused +#define _unused __pragma(warning(suppress:4100)) #endif #ifndef __cplusplus #define _register register @@ -96,23 +106,35 @@ typedef uint16_t M3D_INDEX; * 3DMO m3dchunk_t file header chunk, may followed by compressed data * HEAD m3dhdr_t model header chunk * n x m3dchunk_t more chunks follow + * PRVW preview chunk (optional) * CMAP color map chunk (optional) * TMAP texture map chunk (optional) * VRTS vertex data chunk (optional if it's a material library) * BONE bind-pose skeleton, bone hierarchy chunk (optional) * n x m3db_t contains propably more, but at least one bone + * n x m3ds_t skin group records * MTRL* material chunk(s), can be more (optional) * n x m3dp_t each material contains propapbly more, but at least one property * the properties are configurable with a static array, see m3d_propertytypes * n x m3dchunk_t at least one, but maybe more face chunks * PROC* procedural face, or - * MESH* triangle mesh (vertex index list) + * MESH* triangle mesh (vertex index list) or + * SHPE* mathematical shapes like parameterized surfaces + * LBLS* annotation label chunks, can be more (optional) * ACTN* action chunk(s), animation-pose skeletons, can be more (optional) * n x m3dfr_t each action contains probably more, but at least one frame * n x m3dtr_t each frame contains probably more, but at least one transformation * ASET* inlined asset chunk(s), can be more (optional) * OMD3 end chunk + * + * Typical chunks for a game engine: 3DMO, HEAD, CMAP, TMAP, VRTS, BONE, MTRL, MESH, ACTN, OMD3 + * Typical chunks for CAD software: 3DMO, HEAD, PRVW, CMAP, TMAP, VRTS, MTRL, SHPE, LBLS, OMD3 */ +#ifdef _MSC_VER +#pragma pack(push) +#pragma pack(1) +#endif + typedef struct { char magic[4]; uint32_t length; @@ -125,6 +147,10 @@ typedef struct { uint32_t length; } _pack m3dchunk_t; +#ifdef _MSC_VER +#pragma pack(pop) +#endif + /*** in-memory model structure ***/ /* textmap entry */ @@ -132,19 +158,23 @@ typedef struct { M3D_FLOAT u; M3D_FLOAT v; } m3dti_t; +#define m3d_textureindex_t m3dti_t /* texture */ typedef struct { char *name; /* texture name */ - uint32_t *d; /* pixels data */ + uint8_t *d; /* pixels data */ uint16_t w; /* width */ uint16_t h; /* height */ -} _pack m3dtx_t; + uint8_t f; /* format, 1 = grayscale, 2 = grayscale+alpha, 3 = rgb, 4 = rgba */ +} m3dtx_t; +#define m3d_texturedata_t m3dtx_t typedef struct { M3D_INDEX vertexid; M3D_FLOAT weight; } m3dw_t; +#define m3d_weight_t m3dw_t /* bone entry */ typedef struct { @@ -156,12 +186,14 @@ typedef struct { m3dw_t *weight; /* weights for those vertices */ M3D_FLOAT mat4[16]; /* transformation matrix */ } m3db_t; +#define m3d_bone_t m3db_t /* skin: bone per vertex entry */ typedef struct { M3D_INDEX boneid[M3D_NUMBONE]; M3D_FLOAT weight[M3D_NUMBONE]; } m3ds_t; +#define m3d_skin_t m3ds_t /* vertex entry */ typedef struct { @@ -171,7 +203,11 @@ typedef struct { M3D_FLOAT w; uint32_t color; /* default vertex color */ M3D_INDEX skinid; /* skin index */ +#ifdef M3D_VERTEXTYPE + uint8_t type; +#endif } m3dv_t; +#define m3d_vertex_t m3dv_t /* material property formats */ enum { @@ -210,6 +246,7 @@ enum { m3dp_Pm, m3dp_Ps, m3dp_Ni, + m3dp_Nt, m3dp_map_Kd = 128, /* textured display map properties */ m3dp_map_Ka, @@ -219,15 +256,17 @@ enum { m3dp_map_Tf, m3dp_map_Km, /* bump map */ m3dp_map_D, - m3dp_map_il, /* reflection map */ + m3dp_map_N, /* normal map */ m3dp_map_Pr = 192, /* textured physical map properties */ m3dp_map_Pm, m3dp_map_Ps, - m3dp_map_Ni + m3dp_map_Ni, + m3dp_map_Nt }; enum { /* aliases */ m3dp_bump = m3dp_map_Km, + m3dp_map_il = m3dp_map_N, m3dp_refl = m3dp_map_Pm }; @@ -241,6 +280,7 @@ typedef struct { M3D_INDEX textureid; /* if value is a texture, m3dpf_map */ } value; } m3dp_t; +#define m3d_property_t m3dp_t /* material entry */ typedef struct { @@ -248,6 +288,7 @@ typedef struct { uint8_t numprop; /* number of properties */ m3dp_t *prop; /* properties array */ } m3dm_t; +#define m3d_material_t m3dm_t /* face entry */ typedef struct { @@ -256,6 +297,108 @@ typedef struct { M3D_INDEX normal[3]; /* normal vectors */ M3D_INDEX texcoord[3]; /* UV coordinates */ } m3df_t; +#define m3d_face_t m3df_t + +/* shape command types. must match the row in m3d_commandtypes */ +enum { + /* special commands */ + m3dc_use = 0, /* use material */ + m3dc_inc, /* include another shape */ + m3dc_mesh, /* include part of polygon mesh */ + /* approximations */ + m3dc_div, /* subdivision by constant resolution for both u, v */ + m3dc_sub, /* subdivision by constant, different for u and v */ + m3dc_len, /* spacial subdivision by maxlength */ + m3dc_dist, /* subdivision by maxdistance and maxangle */ + /* modifiers */ + m3dc_degu, /* degree for both u, v */ + m3dc_deg, /* separate degree for u and v */ + m3dc_rangeu, /* range for u */ + m3dc_range, /* range for u and v */ + m3dc_paru, /* u parameters (knots) */ + m3dc_parv, /* v parameters */ + m3dc_trim, /* outer trimming curve */ + m3dc_hole, /* inner trimming curve */ + m3dc_scrv, /* spacial curve */ + m3dc_sp, /* special points */ + /* helper curves */ + m3dc_bez1, /* Bezier 1D */ + m3dc_bsp1, /* B-spline 1D */ + m3dc_bez2, /* bezier 2D */ + m3dc_bsp2, /* B-spline 2D */ + /* surfaces */ + m3dc_bezun, /* Bezier 3D with control, UV, normal */ + m3dc_bezu, /* with control and UV */ + m3dc_bezn, /* with control and normal */ + m3dc_bez, /* control points only */ + m3dc_nurbsun, /* B-spline 3D */ + m3dc_nurbsu, + m3dc_nurbsn, + m3dc_nurbs, + m3dc_conn, /* connect surfaces */ + /* geometrical */ + m3dc_line, + m3dc_polygon, + m3dc_circle, + m3dc_cylinder, + m3dc_shpere, + m3dc_torus, + m3dc_cone, + m3dc_cube +}; + +/* shape command argument types */ +enum { + m3dcp_mi_t = 1, /* material index */ + m3dcp_hi_t, /* shape index */ + m3dcp_fi_t, /* face index */ + m3dcp_ti_t, /* texture map index */ + m3dcp_vi_t, /* vertex index */ + m3dcp_qi_t, /* vertex index for quaternions */ + m3dcp_vc_t, /* coordinate or radius, float scalar */ + m3dcp_i1_t, /* int8 scalar */ + m3dcp_i2_t, /* int16 scalar */ + m3dcp_i4_t, /* int32 scalar */ + m3dcp_va_t /* variadic arguments */ +}; + +#define M3D_CMDMAXARG 8 /* if you increase this, add more arguments to the macro below */ +typedef struct { +#ifdef M3D_ASCII +#define M3D_CMDDEF(t,n,p,a,b,c,d,e,f,g,h) { (char*)(n), (p), { (a), (b), (c), (d), (e), (f), (g), (h) } } + char *key; +#else +#define M3D_CMDDEF(t,n,p,a,b,c,d,e,f,g,h) { (p), { (a), (b), (c), (d), (e), (f), (g), (h) } } +#endif + uint8_t p; + uint8_t a[M3D_CMDMAXARG]; +} m3dcd_t; + +/* shape command */ +typedef struct { + uint16_t type; /* shape type */ + uint32_t *arg; /* arguments array */ +} m3dc_t; +#define m3d_shapecommand_t m3dc_t + +/* shape entry */ +typedef struct { + char *name; /* name of the mathematical shape */ + M3D_INDEX group; /* group this shape belongs to or -1 */ + uint32_t numcmd; /* number of commands */ + m3dc_t *cmd; /* commands array */ +} m3dh_t; +#define m3d_shape_t m3dh_t + +/* label entry */ +typedef struct { + char *name; /* name of the annotation layer or NULL */ + char *lang; /* language code or NULL */ + char *text; /* the label text */ + uint32_t color; /* color */ + M3D_INDEX vertexid; /* the vertex the label refers to */ +} m3dl_t; +#define m3d_label_t m3dl_t /* frame transformations / working copy skeleton entry */ typedef struct { @@ -263,6 +406,7 @@ typedef struct { M3D_INDEX pos; /* vertex index new position */ M3D_INDEX ori; /* vertex index new orientation (quaternion) */ } m3dtr_t; +#define m3d_transform_t m3dtr_t /* animation frame entry */ typedef struct { @@ -270,6 +414,7 @@ typedef struct { M3D_INDEX numtransform; /* number of transformations in this frame */ m3dtr_t *transform; /* transformations */ } m3dfr_t; +#define m3d_frame_t m3dfr_t /* model action entry */ typedef struct { @@ -278,6 +423,7 @@ typedef struct { M3D_INDEX numframe; /* number of frames in this animation */ m3dfr_t *frame; /* frames array */ } m3da_t; +#define m3d_action_t m3da_t /* inlined asset */ typedef struct { @@ -285,17 +431,19 @@ typedef struct { uint8_t *data; /* compressed asset data */ uint32_t length; /* compressed data length */ } m3di_t; +#define m3d_inlinedasset_t m3di_t /*** in-memory model structure ***/ #define M3D_FLG_FREERAW (1<<0) #define M3D_FLG_FREESTR (1<<1) #define M3D_FLG_MTLLIB (1<<2) +#define M3D_FLG_GENNORM (1<<3) typedef struct { m3dhdr_t *raw; /* pointer to raw data */ char flags; /* internal flags */ - char errcode; /* returned error code */ - char vc_s, vi_s, si_s, ci_s, ti_s, bi_s, nb_s, sk_s, fi_s; /* decoded sizes for types */ + signed char errcode; /* returned error code */ + char vc_s, vi_s, si_s, ci_s, ti_s, bi_s, nb_s, sk_s, fc_s, hi_s,fi_s; /* decoded sizes for types */ char *name; /* name of the model, like "Utah teapot" */ char *license; /* usage condition or license, like "MIT", "LGPL" or "BSD-3clause" */ char *author; /* nickname, email, homepage or github URL etc. */ @@ -316,13 +464,18 @@ typedef struct { M3D_INDEX nummaterial; m3dm_t *material; /* material list */ M3D_INDEX numface; - m3df_t *face; /* model face, triangle mesh */ + m3df_t *face; /* model face, polygon (triangle) mesh */ + M3D_INDEX numshape; + m3dh_t *shape; /* model face, shape commands */ + M3D_INDEX numlabel; + m3dl_t *label; /* annotation labels */ M3D_INDEX numaction; m3da_t *action; /* action animations */ M3D_INDEX numinlined; m3di_t *inlined; /* inlined assets */ - M3D_INDEX numunknown; - m3dchunk_t **unknown; /* unknown chunks, application / engine specific data probably */ + M3D_INDEX numextra; + m3dchunk_t **extra; /* unknown chunks, application / engine specific data probably */ + m3di_t preview; /* preview chunk */ } m3d_t; /*** export parameters ***/ @@ -355,12 +508,14 @@ typedef struct { #define M3D_ERR_UNKMESH -67 #define M3D_ERR_UNKIMG -68 #define M3D_ERR_UNKFRAME -69 -#define M3D_ERR_TRUNC -70 -#define M3D_ERR_CMAP -71 -#define M3D_ERR_TMAP -72 -#define M3D_ERR_VRTS -73 -#define M3D_ERR_BONE -74 -#define M3D_ERR_MTRL -75 +#define M3D_ERR_UNKCMD -70 +#define M3D_ERR_TRUNC -71 +#define M3D_ERR_CMAP -72 +#define M3D_ERR_TMAP -73 +#define M3D_ERR_VRTS -74 +#define M3D_ERR_BONE -75 +#define M3D_ERR_MTRL -76 +#define M3D_ERR_SHPE -77 #define M3D_ERR_ISFATAL(x) ((x) < 0 && (x) > -65) @@ -381,8 +536,6 @@ m3dtr_t *m3d_frame(m3d_t *model, M3D_INDEX actionid, M3D_INDEX frameid, m3dtr_t m3db_t *m3d_pose(m3d_t *model, M3D_INDEX actionid, uint32_t msec); /* private prototypes used by both importer and exporter */ -m3ds_t *_m3d_addskin(m3ds_t *skin, uint32_t *numskin, m3ds_t *s, uint32_t *idx); -m3dv_t *_m3d_addnorm(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx); char *_m3d_safestr(char *in, int morelines); /*** C implementation ***/ @@ -404,11 +557,60 @@ static m3dpd_t m3d_propertytypes[] = { M3D_PROPERTYDEF(m3dpf_float, m3dp_Pm, "Pm"), /* metallic, also reflection */ M3D_PROPERTYDEF(m3dpf_float, m3dp_Ps, "Ps"), /* sheen */ M3D_PROPERTYDEF(m3dpf_float, m3dp_Ni, "Ni"), /* index of refraction (optical density) */ + M3D_PROPERTYDEF(m3dpf_float, m3dp_Nt, "Nt"), /* thickness of face in millimeter, for printing */ /* aliases, note that "map_*" aliases are handled automatically */ M3D_PROPERTYDEF(m3dpf_map, m3dp_map_Km, "bump"), + M3D_PROPERTYDEF(m3dpf_map, m3dp_map_N, "map_N"),/* as normal map has no scalar version, it's counterpart is 'il' */ M3D_PROPERTYDEF(m3dpf_map, m3dp_map_Pm, "refl") }; +/* shape command definitions. if more commands start with the same string, the longer must come first */ +static m3dcd_t m3d_commandtypes[] = { + /* technical */ + M3D_CMDDEF(m3dc_use, "use", 1, m3dcp_mi_t, 0, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_inc, "inc", 3, m3dcp_hi_t, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vi_t, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_mesh, "mesh", 1, m3dcp_fi_t, m3dcp_fi_t, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vi_t, 0, 0, 0), + /* approximations */ + M3D_CMDDEF(m3dc_div, "div", 1, m3dcp_vc_t, 0, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_sub, "sub", 2, m3dcp_vc_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_len, "len", 1, m3dcp_vc_t, 0, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_dist, "dist", 2, m3dcp_vc_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0), + /* modifiers */ + M3D_CMDDEF(m3dc_degu, "degu", 1, m3dcp_i1_t, 0, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_deg, "deg", 2, m3dcp_i1_t, m3dcp_i1_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_rangeu, "rangeu", 1, m3dcp_ti_t, 0, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_range, "range", 2, m3dcp_ti_t, m3dcp_ti_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_paru, "paru", 2, m3dcp_va_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_parv, "parv", 2, m3dcp_va_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_trim, "trim", 3, m3dcp_va_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_hole, "hole", 3, m3dcp_va_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_scrv, "scrv", 3, m3dcp_va_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_sp, "sp", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), + /* helper curves */ + M3D_CMDDEF(m3dc_bez1, "bez1", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_bsp1, "bsp1", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_bez2, "bez2", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_bsp2, "bsp2", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), + /* surfaces */ + M3D_CMDDEF(m3dc_bezun, "bezun", 4, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, m3dcp_vi_t, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_bezu, "bezu", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_bezn, "bezn", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_bez, "bez", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_nurbsun, "nurbsun", 4, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, m3dcp_vi_t, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_nurbsu, "nurbsu", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_nurbsn, "nurbsn", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_nurbs, "nurbs", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_conn, "conn", 6, m3dcp_i2_t, m3dcp_ti_t, m3dcp_i2_t, m3dcp_i2_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0), + /* geometrical */ + M3D_CMDDEF(m3dc_line, "line", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_polygon, "polygon", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_circle, "circle", 3, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_cylinder,"cylinder",6, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, 0, 0), + M3D_CMDDEF(m3dc_shpere, "shpere", 2, m3dcp_vi_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_torus, "torus", 4, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, m3dcp_vc_t, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_cone, "cone", 3, m3dcp_vi_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_cube, "cube", 3, m3dcp_vi_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0) +}; #endif #include @@ -419,7 +621,7 @@ static m3dpd_t m3d_propertytypes[] = { stb_image - v2.23 - public domain image loader - http://nothings.org/stb_image.h */ -static const char *stbi__g_failure_reason; +static const char *_m3dstbi__g_failure_reason; enum { @@ -438,57 +640,56 @@ enum STBI__SCAN_header }; -typedef unsigned char stbi_uc; -typedef unsigned short stbi_us; +typedef unsigned short _m3dstbi_us; -typedef uint16_t stbi__uint16; -typedef int16_t stbi__int16; -typedef uint32_t stbi__uint32; -typedef int32_t stbi__int32; +typedef uint16_t _m3dstbi__uint16; +typedef int16_t _m3dstbi__int16; +typedef uint32_t _m3dstbi__uint32; +typedef int32_t _m3dstbi__int32; typedef struct { - stbi__uint32 img_x, img_y; + _m3dstbi__uint32 img_x, img_y; int img_n, img_out_n; void *io_user_data; int read_from_callbacks; int buflen; - stbi_uc buffer_start[128]; + unsigned char buffer_start[128]; - stbi_uc *img_buffer, *img_buffer_end; - stbi_uc *img_buffer_original, *img_buffer_original_end; -} stbi__context; + unsigned char *img_buffer, *img_buffer_end; + unsigned char *img_buffer_original, *img_buffer_original_end; +} _m3dstbi__context; typedef struct { int bits_per_channel; int num_channels; int channel_order; -} stbi__result_info; +} _m3dstbi__result_info; #define STBI_ASSERT(v) #define STBI_NOTUSED(v) (void)sizeof(v) -#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) +#define STBI__BYTECAST(x) ((unsigned char) ((x) & 255)) #define STBI_MALLOC(sz) M3D_MALLOC(sz) #define STBI_REALLOC(p,newsz) M3D_REALLOC(p,newsz) #define STBI_FREE(p) M3D_FREE(p) #define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) -_inline static stbi_uc stbi__get8(stbi__context *s) +_inline static unsigned char _m3dstbi__get8(_m3dstbi__context *s) { if (s->img_buffer < s->img_buffer_end) return *s->img_buffer++; return 0; } -_inline static int stbi__at_eof(stbi__context *s) +_inline static int _m3dstbi__at_eof(_m3dstbi__context *s) { return s->img_buffer >= s->img_buffer_end; } -static void stbi__skip(stbi__context *s, int n) +static void _m3dstbi__skip(_m3dstbi__context *s, int n) { if (n < 0) { s->img_buffer = s->img_buffer_end; @@ -497,7 +698,7 @@ static void stbi__skip(stbi__context *s, int n) s->img_buffer += n; } -static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) +static int _m3dstbi__getn(_m3dstbi__context *s, unsigned char *buffer, int n) { if (s->img_buffer+n <= s->img_buffer_end) { memcpy(buffer, s->img_buffer, n); @@ -507,72 +708,72 @@ static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) return 0; } -static int stbi__get16be(stbi__context *s) +static int _m3dstbi__get16be(_m3dstbi__context *s) { - int z = stbi__get8(s); - return (z << 8) + stbi__get8(s); + int z = _m3dstbi__get8(s); + return (z << 8) + _m3dstbi__get8(s); } -static stbi__uint32 stbi__get32be(stbi__context *s) +static _m3dstbi__uint32 _m3dstbi__get32be(_m3dstbi__context *s) { - stbi__uint32 z = stbi__get16be(s); - return (z << 16) + stbi__get16be(s); + _m3dstbi__uint32 z = _m3dstbi__get16be(s); + return (z << 16) + _m3dstbi__get16be(s); } -#define stbi__err(x,y) stbi__errstr(y) -static int stbi__errstr(const char *str) +#define _m3dstbi__err(x,y) _m3dstbi__errstr(y) +static int _m3dstbi__errstr(const char *str) { - stbi__g_failure_reason = str; + _m3dstbi__g_failure_reason = str; return 0; } -_inline static void *stbi__malloc(size_t size) +_inline static void *_m3dstbi__malloc(size_t size) { return STBI_MALLOC(size); } -static int stbi__addsizes_valid(int a, int b) +static int _m3dstbi__addsizes_valid(int a, int b) { if (b < 0) return 0; return a <= 2147483647 - b; } -static int stbi__mul2sizes_valid(int a, int b) +static int _m3dstbi__mul2sizes_valid(int a, int b) { if (a < 0 || b < 0) return 0; if (b == 0) return 1; return a <= 2147483647/b; } -static int stbi__mad2sizes_valid(int a, int b, int add) +static int _m3dstbi__mad2sizes_valid(int a, int b, int add) { - return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); + return _m3dstbi__mul2sizes_valid(a, b) && _m3dstbi__addsizes_valid(a*b, add); } -static int stbi__mad3sizes_valid(int a, int b, int c, int add) +static int _m3dstbi__mad3sizes_valid(int a, int b, int c, int add) { - return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && - stbi__addsizes_valid(a*b*c, add); + return _m3dstbi__mul2sizes_valid(a, b) && _m3dstbi__mul2sizes_valid(a*b, c) && + _m3dstbi__addsizes_valid(a*b*c, add); } -static void *stbi__malloc_mad2(int a, int b, int add) +static void *_m3dstbi__malloc_mad2(int a, int b, int add) { - if (!stbi__mad2sizes_valid(a, b, add)) return NULL; - return stbi__malloc(a*b + add); + if (!_m3dstbi__mad2sizes_valid(a, b, add)) return NULL; + return _m3dstbi__malloc(a*b + add); } -static void *stbi__malloc_mad3(int a, int b, int c, int add) +static void *_m3dstbi__malloc_mad3(int a, int b, int c, int add) { - if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; - return stbi__malloc(a*b*c + add); + if (!_m3dstbi__mad3sizes_valid(a, b, c, add)) return NULL; + return _m3dstbi__malloc(a*b*c + add); } -static stbi_uc stbi__compute_y(int r, int g, int b) +static unsigned char _m3dstbi__compute_y(int r, int g, int b) { - return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); + return (unsigned char) (((r*77) + (g*150) + (29*b)) >> 8); } -static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +static unsigned char *_m3dstbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) { int i,j; unsigned char *good; @@ -580,10 +781,10 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r if (req_comp == img_n) return data; STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); + good = (unsigned char *) _m3dstbi__malloc_mad3(req_comp, x, y, 0); if (good == NULL) { STBI_FREE(data); - stbi__err("outofmem", "Out of memory"); + _m3dstbi__err("outofmem", "Out of memory"); return NULL; } @@ -601,10 +802,10 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; } break; - STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break; - STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break; + STBI__CASE(3,1) { dest[0]=_m3dstbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=_m3dstbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break; + STBI__CASE(4,1) { dest[0]=_m3dstbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=_m3dstbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break; STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; default: STBI_ASSERT(0); } @@ -615,29 +816,29 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r return good; } -static stbi__uint16 stbi__compute_y_16(int r, int g, int b) +static _m3dstbi__uint16 _m3dstbi__compute_y_16(int r, int g, int b) { - return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); + return (_m3dstbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); } -static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) +static _m3dstbi__uint16 *_m3dstbi__convert_format16(_m3dstbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) { int i,j; - stbi__uint16 *good; + _m3dstbi__uint16 *good; if (req_comp == img_n) return data; STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); + good = (_m3dstbi__uint16 *) _m3dstbi__malloc(req_comp * x * y * 2); if (good == NULL) { STBI_FREE(data); - stbi__err("outofmem", "Out of memory"); + _m3dstbi__err("outofmem", "Out of memory"); return NULL; } for (j=0; j < (int) y; ++j) { - stbi__uint16 *src = data + j * x * img_n ; - stbi__uint16 *dest = good + j * x * req_comp; + _m3dstbi__uint16 *src = data + j * x * img_n ; + _m3dstbi__uint16 *dest = good + j * x * req_comp; #define STBI__COMBO(a,b) ((a)*8+(b)) #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) @@ -649,10 +850,10 @@ static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int r STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=0xffff; } break; - STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break; - STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break; + STBI__CASE(3,1) { dest[0]=_m3dstbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=_m3dstbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break; + STBI__CASE(4,1) { dest[0]=_m3dstbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=_m3dstbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break; STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; default: STBI_ASSERT(0); } @@ -668,15 +869,15 @@ static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int r typedef struct { - stbi__uint16 fast[1 << STBI__ZFAST_BITS]; - stbi__uint16 firstcode[16]; + _m3dstbi__uint16 fast[1 << STBI__ZFAST_BITS]; + _m3dstbi__uint16 firstcode[16]; int maxcode[17]; - stbi__uint16 firstsymbol[16]; - stbi_uc size[288]; - stbi__uint16 value[288]; -} stbi__zhuffman; + _m3dstbi__uint16 firstsymbol[16]; + unsigned char size[288]; + _m3dstbi__uint16 value[288]; +} _m3dstbi__zhuffman; -_inline static int stbi__bitreverse16(int n) +_inline static int _m3dstbi__bitreverse16(int n) { n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); @@ -685,13 +886,13 @@ _inline static int stbi__bitreverse16(int n) return n; } -_inline static int stbi__bit_reverse(int v, int bits) +_inline static int _m3dstbi__bit_reverse(int v, int bits) { STBI_ASSERT(bits <= 16); - return stbi__bitreverse16(v) >> (16-bits); + return _m3dstbi__bitreverse16(v) >> (16-bits); } -static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) +static int _m3dstbi__zbuild_huffman(_m3dstbi__zhuffman *z, unsigned char *sizelist, int num) { int i,k=0; int code, next_code[16], sizes[17]; @@ -703,15 +904,15 @@ static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) sizes[0] = 0; for (i=1; i < 16; ++i) if (sizes[i] > (1 << i)) - return stbi__err("bad sizes", "Corrupt PNG"); + return _m3dstbi__err("bad sizes", "Corrupt PNG"); code = 0; for (i=1; i < 16; ++i) { next_code[i] = code; - z->firstcode[i] = (stbi__uint16) code; - z->firstsymbol[i] = (stbi__uint16) k; + z->firstcode[i] = (_m3dstbi__uint16) code; + z->firstsymbol[i] = (_m3dstbi__uint16) k; code = (code + sizes[i]); if (sizes[i]) - if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); + if (code-1 >= (1 << i)) return _m3dstbi__err("bad codelengths","Corrupt PNG"); z->maxcode[i] = code << (16-i); code <<= 1; k += sizes[i]; @@ -721,11 +922,11 @@ static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) int s = sizelist[i]; if (s) { int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; - stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); - z->size [c] = (stbi_uc ) s; - z->value[c] = (stbi__uint16) i; + _m3dstbi__uint16 fastv = (_m3dstbi__uint16) ((s << 9) | i); + z->size [c] = (unsigned char ) s; + z->value[c] = (_m3dstbi__uint16) i; if (s <= STBI__ZFAST_BITS) { - int j = stbi__bit_reverse(next_code[s],s); + int j = _m3dstbi__bit_reverse(next_code[s],s); while (j < (1 << STBI__ZFAST_BITS)) { z->fast[j] = fastv; j += (1 << s); @@ -739,47 +940,47 @@ static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) typedef struct { - stbi_uc *zbuffer, *zbuffer_end; + unsigned char *zbuffer, *zbuffer_end; int num_bits; - stbi__uint32 code_buffer; + _m3dstbi__uint32 code_buffer; char *zout; char *zout_start; char *zout_end; int z_expandable; - stbi__zhuffman z_length, z_distance; -} stbi__zbuf; + _m3dstbi__zhuffman z_length, z_distance; +} _m3dstbi__zbuf; -_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +_inline static unsigned char _m3dstbi__zget8(_m3dstbi__zbuf *z) { if (z->zbuffer >= z->zbuffer_end) return 0; return *z->zbuffer++; } -static void stbi__fill_bits(stbi__zbuf *z) +static void _m3dstbi__fill_bits(_m3dstbi__zbuf *z) { do { STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); - z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->code_buffer |= (unsigned int) _m3dstbi__zget8(z) << z->num_bits; z->num_bits += 8; } while (z->num_bits <= 24); } -_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +_inline static unsigned int _m3dstbi__zreceive(_m3dstbi__zbuf *z, int n) { unsigned int k; - if (z->num_bits < n) stbi__fill_bits(z); + if (z->num_bits < n) _m3dstbi__fill_bits(z); k = z->code_buffer & ((1 << n) - 1); z->code_buffer >>= n; z->num_bits -= n; return k; } -static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +static int _m3dstbi__zhuffman_decode_slowpath(_m3dstbi__zbuf *a, _m3dstbi__zhuffman *z) { int b,s,k; - k = stbi__bit_reverse(a->code_buffer, 16); + k = _m3dstbi__bit_reverse(a->code_buffer, 16); for (s=STBI__ZFAST_BITS+1; ; ++s) if (k < z->maxcode[s]) break; @@ -791,10 +992,10 @@ static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) return z->value[b]; } -_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +_inline static int _m3dstbi__zhuffman_decode(_m3dstbi__zbuf *a, _m3dstbi__zhuffman *z) { int b,s; - if (a->num_bits < 16) stbi__fill_bits(a); + if (a->num_bits < 16) _m3dstbi__fill_bits(a); b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; if (b) { s = b >> 9; @@ -802,76 +1003,76 @@ _inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) a->num_bits -= s; return b & 511; } - return stbi__zhuffman_decode_slowpath(a, z); + return _m3dstbi__zhuffman_decode_slowpath(a, z); } -static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) +static int _m3dstbi__zexpand(_m3dstbi__zbuf *z, char *zout, int n) { char *q; int cur, limit, old_limit; z->zout = zout; - if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + if (!z->z_expandable) return _m3dstbi__err("output buffer limit","Corrupt PNG"); cur = (int) (z->zout - z->zout_start); limit = old_limit = (int) (z->zout_end - z->zout_start); while (cur + n > limit) limit *= 2; q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); STBI_NOTUSED(old_limit); - if (q == NULL) return stbi__err("outofmem", "Out of memory"); + if (q == NULL) return _m3dstbi__err("outofmem", "Out of memory"); z->zout_start = q; z->zout = q + cur; z->zout_end = q + limit; return 1; } -static int stbi__zlength_base[31] = { +static int _m3dstbi__zlength_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; -static int stbi__zlength_extra[31]= +static int _m3dstbi__zlength_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; -static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +static int _m3dstbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; -static int stbi__zdist_extra[32] = +static int _m3dstbi__zdist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; -static int stbi__parse_huffman_block(stbi__zbuf *a) +static int _m3dstbi__parse_huffman_block(_m3dstbi__zbuf *a) { char *zout = a->zout; for(;;) { - int z = stbi__zhuffman_decode(a, &a->z_length); + int z = _m3dstbi__zhuffman_decode(a, &a->z_length); if (z < 256) { - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + if (z < 0) return _m3dstbi__err("bad huffman code","Corrupt PNG"); if (zout >= a->zout_end) { - if (!stbi__zexpand(a, zout, 1)) return 0; + if (!_m3dstbi__zexpand(a, zout, 1)) return 0; zout = a->zout; } *zout++ = (char) z; } else { - stbi_uc *p; + unsigned char *p; int len,dist; if (z == 256) { a->zout = zout; return 1; } z -= 257; - len = stbi__zlength_base[z]; - if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); - z = stbi__zhuffman_decode(a, &a->z_distance); - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); - dist = stbi__zdist_base[z]; - if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); - if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + len = _m3dstbi__zlength_base[z]; + if (_m3dstbi__zlength_extra[z]) len += _m3dstbi__zreceive(a, _m3dstbi__zlength_extra[z]); + z = _m3dstbi__zhuffman_decode(a, &a->z_distance); + if (z < 0) return _m3dstbi__err("bad huffman code","Corrupt PNG"); + dist = _m3dstbi__zdist_base[z]; + if (_m3dstbi__zdist_extra[z]) dist += _m3dstbi__zreceive(a, _m3dstbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return _m3dstbi__err("bad dist","Corrupt PNG"); if (zout + len > a->zout_end) { - if (!stbi__zexpand(a, zout, len)) return 0; + if (!_m3dstbi__zexpand(a, zout, len)) return 0; zout = a->zout; } - p = (stbi_uc *) (zout - dist); + p = (unsigned char *) (zout - dist); if (dist == 1) { - stbi_uc v = *p; + unsigned char v = *p; if (len) { do *zout++ = v; while (--len); } } else { if (len) { do *zout++ = *p++; while (--len); } @@ -880,152 +1081,151 @@ static int stbi__parse_huffman_block(stbi__zbuf *a) } } -static int stbi__compute_huffman_codes(stbi__zbuf *a) +static int _m3dstbi__compute_huffman_codes(_m3dstbi__zbuf *a) { - static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; - stbi__zhuffman z_codelength; - stbi_uc lencodes[286+32+137]; - stbi_uc codelength_sizes[19]; + static unsigned char length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + _m3dstbi__zhuffman z_codelength; + unsigned char lencodes[286+32+137]; + unsigned char codelength_sizes[19]; int i,n; - int hlit = stbi__zreceive(a,5) + 257; - int hdist = stbi__zreceive(a,5) + 1; - int hclen = stbi__zreceive(a,4) + 4; + int hlit = _m3dstbi__zreceive(a,5) + 257; + int hdist = _m3dstbi__zreceive(a,5) + 1; + int hclen = _m3dstbi__zreceive(a,4) + 4; int ntot = hlit + hdist; memset(codelength_sizes, 0, sizeof(codelength_sizes)); for (i=0; i < hclen; ++i) { - int s = stbi__zreceive(a,3); - codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + int s = _m3dstbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (unsigned char) s; } - if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + if (!_m3dstbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; n = 0; while (n < ntot) { - int c = stbi__zhuffman_decode(a, &z_codelength); - if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + int c = _m3dstbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return _m3dstbi__err("bad codelengths", "Corrupt PNG"); if (c < 16) - lencodes[n++] = (stbi_uc) c; + lencodes[n++] = (unsigned char) c; else { - stbi_uc fill = 0; + unsigned char fill = 0; if (c == 16) { - c = stbi__zreceive(a,2)+3; - if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + c = _m3dstbi__zreceive(a,2)+3; + if (n == 0) return _m3dstbi__err("bad codelengths", "Corrupt PNG"); fill = lencodes[n-1]; } else if (c == 17) - c = stbi__zreceive(a,3)+3; + c = _m3dstbi__zreceive(a,3)+3; else { STBI_ASSERT(c == 18); - c = stbi__zreceive(a,7)+11; + c = _m3dstbi__zreceive(a,7)+11; } - if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + if (ntot - n < c) return _m3dstbi__err("bad codelengths", "Corrupt PNG"); memset(lencodes+n, fill, c); n += c; } } - if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); - if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; - if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + if (n != ntot) return _m3dstbi__err("bad codelengths","Corrupt PNG"); + if (!_m3dstbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!_m3dstbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; return 1; } -_inline static int stbi__parse_uncompressed_block(stbi__zbuf *a) +_inline static int _m3dstbi__parse_uncompressed_block(_m3dstbi__zbuf *a) { - stbi_uc header[4]; + unsigned char header[4]; int len,nlen,k; if (a->num_bits & 7) - stbi__zreceive(a, a->num_bits & 7); + _m3dstbi__zreceive(a, a->num_bits & 7); k = 0; while (a->num_bits > 0) { - header[k++] = (stbi_uc) (a->code_buffer & 255); + header[k++] = (unsigned char) (a->code_buffer & 255); a->code_buffer >>= 8; a->num_bits -= 8; } STBI_ASSERT(a->num_bits == 0); while (k < 4) - header[k++] = stbi__zget8(a); + header[k++] = _m3dstbi__zget8(a); len = header[1] * 256 + header[0]; nlen = header[3] * 256 + header[2]; - if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); - if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (nlen != (len ^ 0xffff)) return _m3dstbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return _m3dstbi__err("read past buffer","Corrupt PNG"); if (a->zout + len > a->zout_end) - if (!stbi__zexpand(a, a->zout, len)) return 0; + if (!_m3dstbi__zexpand(a, a->zout, len)) return 0; memcpy(a->zout, a->zbuffer, len); a->zbuffer += len; a->zout += len; return 1; } -static int stbi__parse_zlib_header(stbi__zbuf *a) +static int _m3dstbi__parse_zlib_header(_m3dstbi__zbuf *a) { - int cmf = stbi__zget8(a); + int cmf = _m3dstbi__zget8(a); int cm = cmf & 15; /* int cinfo = cmf >> 4; */ - int flg = stbi__zget8(a); - if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); - if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); - if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); + int flg = _m3dstbi__zget8(a); + if ((cmf*256+flg) % 31 != 0) return _m3dstbi__err("bad zlib header","Corrupt PNG"); + if (flg & 32) return _m3dstbi__err("no preset dict","Corrupt PNG"); + if (cm != 8) return _m3dstbi__err("bad compression","Corrupt PNG"); return 1; } -static stbi_uc stbi__zdefault_length[288], stbi__zdefault_distance[32]; -static void stbi__init_zdefaults(void) +static unsigned char _m3dstbi__zdefault_length[288], _m3dstbi__zdefault_distance[32]; +static void _m3dstbi__init_zdefaults(void) { int i; - for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; - for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; - for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; - for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + for (i=0; i <= 143; ++i) _m3dstbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) _m3dstbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) _m3dstbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) _m3dstbi__zdefault_length[i] = 8; - for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; + for (i=0; i <= 31; ++i) _m3dstbi__zdefault_distance[i] = 5; } -static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +static int _m3dstbi__parse_zlib(_m3dstbi__zbuf *a, int parse_header) { int final, type; if (parse_header) - if (!stbi__parse_zlib_header(a)) return 0; + if (!_m3dstbi__parse_zlib_header(a)) return 0; a->num_bits = 0; a->code_buffer = 0; do { - final = stbi__zreceive(a,1); - type = stbi__zreceive(a,2); + final = _m3dstbi__zreceive(a,1); + type = _m3dstbi__zreceive(a,2); if (type == 0) { - if (!stbi__parse_uncompressed_block(a)) return 0; + if (!_m3dstbi__parse_uncompressed_block(a)) return 0; } else if (type == 3) { return 0; } else { if (type == 1) { - if (!stbi__zdefault_distance[31]) stbi__init_zdefaults(); - if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; - if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + if (!_m3dstbi__zbuild_huffman(&a->z_length , _m3dstbi__zdefault_length , 288)) return 0; + if (!_m3dstbi__zbuild_huffman(&a->z_distance, _m3dstbi__zdefault_distance, 32)) return 0; } else { - if (!stbi__compute_huffman_codes(a)) return 0; + if (!_m3dstbi__compute_huffman_codes(a)) return 0; } - if (!stbi__parse_huffman_block(a)) return 0; + if (!_m3dstbi__parse_huffman_block(a)) return 0; } } while (!final); return 1; } -static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) +static int _m3dstbi__do_zlib(_m3dstbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) { a->zout_start = obuf; a->zout = obuf; a->zout_end = obuf + olen; a->z_expandable = exp; - - return stbi__parse_zlib(a, parse_header); + _m3dstbi__init_zdefaults(); + return _m3dstbi__parse_zlib(a, parse_header); } -char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +char *_m3dstbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) { - stbi__zbuf a; - char *p = (char *) stbi__malloc(initial_size); + _m3dstbi__zbuf a; + char *p = (char *) _m3dstbi__malloc(initial_size); if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer + len; - if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + a.zbuffer = (unsigned char *) buffer; + a.zbuffer_end = (unsigned char *) buffer + len; + if (_m3dstbi__do_zlib(&a, p, initial_size, 1, parse_header)) { if (outlen) *outlen = (int) (a.zout - a.zout_start); return a.zout_start; } else { @@ -1036,33 +1236,33 @@ char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, typedef struct { - stbi__uint32 length; - stbi__uint32 type; -} stbi__pngchunk; + _m3dstbi__uint32 length; + _m3dstbi__uint32 type; +} _m3dstbi__pngchunk; -static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +static _m3dstbi__pngchunk _m3dstbi__get_chunk_header(_m3dstbi__context *s) { - stbi__pngchunk c; - c.length = stbi__get32be(s); - c.type = stbi__get32be(s); + _m3dstbi__pngchunk c; + c.length = _m3dstbi__get32be(s); + c.type = _m3dstbi__get32be(s); return c; } -_inline static int stbi__check_png_header(stbi__context *s) +_inline static int _m3dstbi__check_png_header(_m3dstbi__context *s) { - static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + static unsigned char png_sig[8] = { 137,80,78,71,13,10,26,10 }; int i; for (i=0; i < 8; ++i) - if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + if (_m3dstbi__get8(s) != png_sig[i]) return _m3dstbi__err("bad png sig","Not a PNG"); return 1; } typedef struct { - stbi__context *s; - stbi_uc *idata, *expanded, *out; + _m3dstbi__context *s; + unsigned char *idata, *expanded, *out; int depth; -} stbi__png; +} _m3dstbi__png; enum { @@ -1075,7 +1275,7 @@ enum { STBI__F_paeth_first }; -static stbi_uc first_row_filter[5] = +static unsigned char first_row_filter[5] = { STBI__F_none, STBI__F_sub, @@ -1084,7 +1284,7 @@ static stbi_uc first_row_filter[5] = STBI__F_paeth_first }; -static int stbi__paeth(int a, int b, int c) +static int _m3dstbi__paeth(int a, int b, int c) { int p = a + b - c; int pa = abs(p-a); @@ -1095,14 +1295,14 @@ static int stbi__paeth(int a, int b, int c) return c; } -static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; +static unsigned char _m3dstbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; -static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) +static int _m3dstbi__create_png_image_raw(_m3dstbi__png *a, unsigned char *raw, _m3dstbi__uint32 raw_len, int out_n, _m3dstbi__uint32 x, _m3dstbi__uint32 y, int depth, int color) { int bytes = (depth == 16? 2 : 1); - stbi__context *s = a->s; - stbi__uint32 i,j,stride = x*out_n*bytes; - stbi__uint32 img_len, img_width_bytes; + _m3dstbi__context *s = a->s; + _m3dstbi__uint32 i,j,stride = x*out_n*bytes; + _m3dstbi__uint32 img_len, img_width_bytes; int k; int img_n = s->img_n; @@ -1111,24 +1311,25 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r int width = x; STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); - a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); - if (!a->out) return stbi__err("outofmem", "Out of memory"); + a->out = (unsigned char *) _m3dstbi__malloc_mad3(x, y, output_bytes, 0); + if (!a->out) return _m3dstbi__err("outofmem", "Out of memory"); + if (!_m3dstbi__mad3sizes_valid(img_n, x, depth, 7)) return _m3dstbi__err("too large", "Corrupt PNG"); img_width_bytes = (((img_n * x * depth) + 7) >> 3); img_len = (img_width_bytes + 1) * y; if (s->img_x == x && s->img_y == y) { - if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG"); + if (raw_len != img_len) return _m3dstbi__err("not enough pixels","Corrupt PNG"); } else { - if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + if (raw_len < img_len) return _m3dstbi__err("not enough pixels","Corrupt PNG"); } for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *prior = cur - stride; + unsigned char *cur = a->out + stride*j; + unsigned char *prior = cur - stride; int filter = *raw++; if (filter > 4) - return stbi__err("invalid filter","Corrupt PNG"); + return _m3dstbi__err("invalid filter","Corrupt PNG"); if (depth < 8) { STBI_ASSERT(img_width_bytes <= x); @@ -1136,6 +1337,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r filter_bytes = 1; width = img_width_bytes; } + prior = cur - stride; if (j == 0) filter = first_row_filter[filter]; @@ -1145,7 +1347,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r case STBI__F_sub : cur[k] = raw[k]; break; case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; - case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; + case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(0,prior[k],0)); break; case STBI__F_avg_first : cur[k] = raw[k]; break; case STBI__F_paeth_first: cur[k] = raw[k]; break; } @@ -1181,9 +1383,9 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(cur[k-filter_bytes],0,0)); } break; } #undef STBI__CASE raw += nk; @@ -1198,9 +1400,9 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(cur[k- output_bytes],0,0)); } break; } #undef STBI__CASE @@ -1215,9 +1417,9 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r if (depth < 8) { for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; - stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; + unsigned char *cur = a->out + stride*j; + unsigned char *in = a->out + stride*j + x*out_n - img_width_bytes; + unsigned char scale = (color == 0) ? _m3dstbi__depth_scale_table[depth] : 1; if (depth == 4) { for (k=x*img_n; k >= 2; k-=2, ++in) { @@ -1274,8 +1476,8 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r } } } else if (depth == 16) { - stbi_uc *cur = a->out; - stbi__uint16 *cur16 = (stbi__uint16*)cur; + unsigned char *cur = a->out; + _m3dstbi__uint16 *cur16 = (_m3dstbi__uint16*)cur; for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { *cur16 = (cur[0] << 8) | cur[1]; @@ -1285,16 +1487,16 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r return 1; } -static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) +static int _m3dstbi__create_png_image(_m3dstbi__png *a, unsigned char *image_data, _m3dstbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) { int bytes = (depth == 16 ? 2 : 1); int out_bytes = out_n * bytes; - stbi_uc *final; + unsigned char *final; int p; if (!interlaced) - return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + return _m3dstbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); - final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + final = (unsigned char *) _m3dstbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); for (p=0; p < 7; ++p) { int xorig[] = { 0,4,0,2,0,1,0 }; int yorig[] = { 0,0,4,0,2,0,1 }; @@ -1304,8 +1506,8 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint3 x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; if (x && y) { - stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; - if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + _m3dstbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!_m3dstbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { STBI_FREE(final); return 0; } @@ -1327,11 +1529,11 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint3 return 1; } -static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +static int _m3dstbi__compute_transparency(_m3dstbi__png *z, unsigned char tc[3], int out_n) { - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi_uc *p = z->out; + _m3dstbi__context *s = z->s; + _m3dstbi__uint32 i, pixel_count = s->img_x * s->img_y; + unsigned char *p = z->out; STBI_ASSERT(out_n == 2 || out_n == 4); @@ -1350,11 +1552,11 @@ static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) return 1; } -static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) +static int _m3dstbi__compute_transparency16(_m3dstbi__png *z, _m3dstbi__uint16 tc[3], int out_n) { - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi__uint16 *p = (stbi__uint16*) z->out; + _m3dstbi__context *s = z->s; + _m3dstbi__uint32 i, pixel_count = s->img_x * s->img_y; + _m3dstbi__uint16 *p = (_m3dstbi__uint16*) z->out; STBI_ASSERT(out_n == 2 || out_n == 4); @@ -1373,13 +1575,13 @@ static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int ou return 1; } -static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +static int _m3dstbi__expand_png_palette(_m3dstbi__png *a, unsigned char *palette, int len, int pal_img_n) { - stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; - stbi_uc *p, *temp_out, *orig = a->out; + _m3dstbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + unsigned char *p, *temp_out, *orig = a->out; - p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); - if (p == NULL) return stbi__err("outofmem", "Out of memory"); + p = (unsigned char *) _m3dstbi__malloc_mad2(pixel_count, pal_img_n, 0); + if (p == NULL) return _m3dstbi__err("outofmem", "Out of memory"); temp_out = p; @@ -1409,228 +1611,177 @@ static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int return 1; } -static int stbi__unpremultiply_on_load = 0; -static int stbi__de_iphone_flag = 0; +#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) -void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +static int _m3dstbi__parse_png_file(_m3dstbi__png *z, int scan, int req_comp) { - stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; -} - -void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) -{ - stbi__de_iphone_flag = flag_true_if_should_convert; -} - -static void stbi__de_iphone(stbi__png *z) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi_uc *p = z->out; - - if (s->img_out_n == 3) { - for (i=0; i < pixel_count; ++i) { - stbi_uc t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 3; - } - } else { - STBI_ASSERT(s->img_out_n == 4); - if (stbi__unpremultiply_on_load) { - for (i=0; i < pixel_count; ++i) { - stbi_uc a = p[3]; - stbi_uc t = p[0]; - if (a) { - p[0] = p[2] * 255 / a; - p[1] = p[1] * 255 / a; - p[2] = t * 255 / a; - } else { - p[0] = p[2]; - p[2] = t; - } - p += 4; - } - } else { - for (i=0; i < pixel_count; ++i) { - stbi_uc t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 4; - } - } - } -} - -#define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) - -static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) -{ - stbi_uc palette[1024], pal_img_n=0; - stbi_uc has_trans=0, tc[3]; - stbi__uint16 tc16[3]; - stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; - int first=1,k,interlace=0, color=0, is_iphone=0; - stbi__context *s = z->s; + unsigned char palette[1024], pal_img_n=0; + unsigned char has_trans=0, tc[3]; + _m3dstbi__uint16 tc16[3]; + _m3dstbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0; + _m3dstbi__context *s = z->s; z->expanded = NULL; z->idata = NULL; z->out = NULL; - if (!stbi__check_png_header(s)) return 0; + if (!_m3dstbi__check_png_header(s)) return 0; if (scan == STBI__SCAN_type) return 1; for (;;) { - stbi__pngchunk c = stbi__get_chunk_header(s); + _m3dstbi__pngchunk c = _m3dstbi__get_chunk_header(s); switch (c.type) { case STBI__PNG_TYPE('C','g','B','I'): - is_iphone = 1; - stbi__skip(s, c.length); + _m3dstbi__skip(s, c.length); break; case STBI__PNG_TYPE('I','H','D','R'): { int comp,filter; - if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + if (!first) return _m3dstbi__err("multiple IHDR","Corrupt PNG"); first = 0; - if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); - s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); - color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); - comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); - filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); - interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); - if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); + if (c.length != 13) return _m3dstbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = _m3dstbi__get32be(s); if (s->img_x > (1 << 24)) return _m3dstbi__err("too large","Very large image (corrupt?)"); + s->img_y = _m3dstbi__get32be(s); if (s->img_y > (1 << 24)) return _m3dstbi__err("too large","Very large image (corrupt?)"); + z->depth = _m3dstbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return _m3dstbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); + color = _m3dstbi__get8(s); if (color > 6) return _m3dstbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) return _m3dstbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return _m3dstbi__err("bad ctype","Corrupt PNG"); + comp = _m3dstbi__get8(s); if (comp) return _m3dstbi__err("bad comp method","Corrupt PNG"); + filter= _m3dstbi__get8(s); if (filter) return _m3dstbi__err("bad filter method","Corrupt PNG"); + interlace = _m3dstbi__get8(s); if (interlace>1) return _m3dstbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return _m3dstbi__err("0-pixel image","Corrupt PNG"); if (!pal_img_n) { s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); - if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return _m3dstbi__err("too large", "Image too large to decode"); if (scan == STBI__SCAN_header) return 1; } else { s->img_n = 1; - if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + if ((1 << 30) / s->img_x / 4 < s->img_y) return _m3dstbi__err("too large","Corrupt PNG"); } break; } case STBI__PNG_TYPE('P','L','T','E'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return _m3dstbi__err("invalid PLTE","Corrupt PNG"); pal_len = c.length / 3; - if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + if (pal_len * 3 != c.length) return _m3dstbi__err("invalid PLTE","Corrupt PNG"); for (i=0; i < pal_len; ++i) { - palette[i*4+0] = stbi__get8(s); - palette[i*4+1] = stbi__get8(s); - palette[i*4+2] = stbi__get8(s); + palette[i*4+0] = _m3dstbi__get8(s); + palette[i*4+1] = _m3dstbi__get8(s); + palette[i*4+2] = _m3dstbi__get8(s); palette[i*4+3] = 255; } break; } case STBI__PNG_TYPE('t','R','N','S'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return _m3dstbi__err("tRNS after IDAT","Corrupt PNG"); if (pal_img_n) { if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } - if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); - if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + if (pal_len == 0) return _m3dstbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return _m3dstbi__err("bad tRNS len","Corrupt PNG"); pal_img_n = 4; for (i=0; i < c.length; ++i) - palette[i*4+3] = stbi__get8(s); + palette[i*4+3] = _m3dstbi__get8(s); } else { - if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); - if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + if (!(s->img_n & 1)) return _m3dstbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (_m3dstbi__uint32) s->img_n*2) return _m3dstbi__err("bad tRNS len","Corrupt PNG"); has_trans = 1; if (z->depth == 16) { - for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); + for (k = 0; k < s->img_n; ++k) tc16[k] = (_m3dstbi__uint16)_m3dstbi__get16be(s); } else { - for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; + for (k = 0; k < s->img_n; ++k) tc[k] = (unsigned char)(_m3dstbi__get16be(s) & 255) * _m3dstbi__depth_scale_table[z->depth]; } } break; } case STBI__PNG_TYPE('I','D','A','T'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return _m3dstbi__err("no PLTE","Corrupt PNG"); if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } if ((int)(ioff + c.length) < (int)ioff) return 0; if (ioff + c.length > idata_limit) { - stbi__uint32 idata_limit_old = idata_limit; - stbi_uc *p; + _m3dstbi__uint32 idata_limit_old = idata_limit; + unsigned char *p; if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; while (ioff + c.length > idata_limit) idata_limit *= 2; STBI_NOTUSED(idata_limit_old); - p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + p = (unsigned char *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return _m3dstbi__err("outofmem", "Out of memory"); z->idata = p; } - if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + if (!_m3dstbi__getn(s, z->idata+ioff,c.length)) return _m3dstbi__err("outofdata","Corrupt PNG"); ioff += c.length; break; } case STBI__PNG_TYPE('I','E','N','D'): { - stbi__uint32 raw_len, bpl; - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + _m3dstbi__uint32 raw_len, bpl; + if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG"); if (scan != STBI__SCAN_load) return 1; - if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + if (z->idata == NULL) return _m3dstbi__err("no IDAT","Corrupt PNG"); bpl = (s->img_x * z->depth + 7) / 8; raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; - z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + z->expanded = (unsigned char *) _m3dstbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, 1); if (z->expanded == NULL) return 0; STBI_FREE(z->idata); z->idata = NULL; if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) s->img_out_n = s->img_n+1; else s->img_out_n = s->img_n; - if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; + if (!_m3dstbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; if (has_trans) { if (z->depth == 16) { - if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; + if (!_m3dstbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; } else { - if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + if (!_m3dstbi__compute_transparency(z, tc, s->img_out_n)) return 0; } } - if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) - stbi__de_iphone(z); if (pal_img_n) { s->img_n = pal_img_n; s->img_out_n = pal_img_n; if (req_comp >= 3) s->img_out_n = req_comp; - if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + if (!_m3dstbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) return 0; + } else if (has_trans) { + ++s->img_n; } STBI_FREE(z->expanded); z->expanded = NULL; return 1; } default: - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG"); if ((c.type & (1 << 29)) == 0) { - return stbi__err("invalid_chunk", "PNG not supported: unknown PNG chunk type"); + return _m3dstbi__err("invalid_chunk", "PNG not supported: unknown PNG chunk type"); } - stbi__skip(s, c.length); + _m3dstbi__skip(s, c.length); break; } - stbi__get32be(s); + _m3dstbi__get32be(s); } } -static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) +static void *_m3dstbi__do_png(_m3dstbi__png *p, int *x, int *y, int *n, int req_comp, _m3dstbi__result_info *ri) { void *result=NULL; - if (req_comp < 0 || req_comp > 4) { stbi__err("bad req_comp", "Internal error"); return NULL; } - if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { - ri->bits_per_channel = p->depth; + if (req_comp < 0 || req_comp > 4) { _m3dstbi__err("bad req_comp", "Internal error"); return NULL; } + if (_m3dstbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if (p->depth < 8) + ri->bits_per_channel = 8; + else + ri->bits_per_channel = p->depth; result = p->out; p->out = NULL; if (req_comp && req_comp != p->s->img_out_n) { if (ri->bits_per_channel == 8) - result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + result = _m3dstbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); else - result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + result = _m3dstbi__convert_format16((_m3dstbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); p->s->img_out_n = req_comp; if (result == NULL) return result; } @@ -1645,12 +1796,16 @@ static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, st return result; } -static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +static void *_m3dstbi__png_load(_m3dstbi__context *s, int *x, int *y, int *comp, int req_comp, _m3dstbi__result_info *ri) { - stbi__png p; + _m3dstbi__png p; p.s = s; - return stbi__do_png(&p, x,y,comp,req_comp, ri); + return _m3dstbi__do_png(&p, x,y,comp,req_comp, ri); } +#define stbi__context _m3dstbi__context +#define stbi__result_info _m3dstbi__result_info +#define stbi__png_load _m3dstbi__png_load +#define stbi_zlib_decode_malloc_guesssize_headerflag _m3dstbi_zlib_decode_malloc_guesssize_headerflag #endif #if defined(M3D_EXPORTER) && !defined(INCLUDE_STB_IMAGE_WRITE_H) @@ -1658,13 +1813,13 @@ static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req stb_image_write - v1.13 - public domain - http://nothings.org/stb/stb_image_write.h */ -typedef unsigned char stbiw_uc; -typedef unsigned short stbiw_us; +typedef unsigned char _m3dstbiw__uc; +typedef unsigned short _m3dstbiw__us; -typedef uint16_t stbiw_uint16; -typedef int16_t stbiw_int16; -typedef uint32_t stbiw_uint32; -typedef int32_t stbiw_int32; +typedef uint16_t _m3dstbiw__uint16; +typedef int16_t _m3dstbiw__int16; +typedef uint32_t _m3dstbiw__uint32; +typedef int32_t _m3dstbiw__int32; #define STBIW_MALLOC(s) M3D_MALLOC(s) #define STBIW_REALLOC(p,ns) M3D_REALLOC(p,ns) @@ -1673,42 +1828,42 @@ typedef int32_t stbiw_int32; #define STBIW_MEMMOVE memmove #define STBIW_UCHAR (uint8_t) #define STBIW_ASSERT(x) -#define stbiw__sbraw(a) ((int *) (a) - 2) -#define stbiw__sbm(a) stbiw__sbraw(a)[0] -#define stbiw__sbn(a) stbiw__sbraw(a)[1] +#define _m3dstbiw___sbraw(a) ((int *) (a) - 2) +#define _m3dstbiw___sbm(a) _m3dstbiw___sbraw(a)[0] +#define _m3dstbiw___sbn(a) _m3dstbiw___sbraw(a)[1] -#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) -#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) -#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) +#define _m3dstbiw___sbneedgrow(a,n) ((a)==0 || _m3dstbiw___sbn(a)+n >= _m3dstbiw___sbm(a)) +#define _m3dstbiw___sbmaybegrow(a,n) (_m3dstbiw___sbneedgrow(a,(n)) ? _m3dstbiw___sbgrow(a,n) : 0) +#define _m3dstbiw___sbgrow(a,n) _m3dstbiw___sbgrowf((void **) &(a), (n), sizeof(*(a))) -#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) -#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) -#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) +#define _m3dstbiw___sbpush(a, v) (_m3dstbiw___sbmaybegrow(a,1), (a)[_m3dstbiw___sbn(a)++] = (v)) +#define _m3dstbiw___sbcount(a) ((a) ? _m3dstbiw___sbn(a) : 0) +#define _m3dstbiw___sbfree(a) ((a) ? STBIW_FREE(_m3dstbiw___sbraw(a)),0 : 0) -static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) +static void *_m3dstbiw___sbgrowf(void **arr, int increment, int itemsize) { - int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; - void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); + int m = *arr ? 2*_m3dstbiw___sbm(*arr)+increment : increment+1; + void *p = STBIW_REALLOC_SIZED(*arr ? _m3dstbiw___sbraw(*arr) : 0, *arr ? (_m3dstbiw___sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); STBIW_ASSERT(p); if (p) { if (!*arr) ((int *) p)[1] = 0; *arr = (void *) ((int *) p + 2); - stbiw__sbm(*arr) = m; + _m3dstbiw___sbm(*arr) = m; } return *arr; } -static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) +static unsigned char *_m3dstbiw___zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) { while (*bitcount >= 8) { - stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); + _m3dstbiw___sbpush(data, STBIW_UCHAR(*bitbuffer)); *bitbuffer >>= 8; *bitcount -= 8; } return data; } -static int stbiw__zlib_bitrev(int code, int codebits) +static int _m3dstbiw___zlib_bitrev(int code, int codebits) { int res=0; while (codebits--) { @@ -1718,7 +1873,7 @@ static int stbiw__zlib_bitrev(int code, int codebits) return res; } -static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) +static unsigned int _m3dstbiw___zlib_countm(unsigned char *a, unsigned char *b, int limit) { int i; for (i=0; i < limit && i < 258; ++i) @@ -1726,9 +1881,9 @@ static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int l return i; } -static unsigned int stbiw__zhash(unsigned char *data) +static unsigned int _m3dstbiw___zhash(unsigned char *data) { - stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); + _m3dstbiw__uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); hash ^= hash << 3; hash += hash >> 5; hash ^= hash << 4; @@ -1738,20 +1893,20 @@ static unsigned int stbiw__zhash(unsigned char *data) return hash; } -#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) -#define stbiw__zlib_add(code,codebits) \ - (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) -#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) -#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) -#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) -#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) -#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) -#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) -#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) +#define _m3dstbiw___zlib_flush() (out = _m3dstbiw___zlib_flushf(out, &bitbuf, &bitcount)) +#define _m3dstbiw___zlib_add(code,codebits) \ + (bitbuf |= (code) << bitcount, bitcount += (codebits), _m3dstbiw___zlib_flush()) +#define _m3dstbiw___zlib_huffa(b,c) _m3dstbiw___zlib_add(_m3dstbiw___zlib_bitrev(b,c),c) +#define _m3dstbiw___zlib_huff1(n) _m3dstbiw___zlib_huffa(0x30 + (n), 8) +#define _m3dstbiw___zlib_huff2(n) _m3dstbiw___zlib_huffa(0x190 + (n)-144, 9) +#define _m3dstbiw___zlib_huff3(n) _m3dstbiw___zlib_huffa(0 + (n)-256,7) +#define _m3dstbiw___zlib_huff4(n) _m3dstbiw___zlib_huffa(0xc0 + (n)-280,8) +#define _m3dstbiw___zlib_huff(n) ((n) <= 143 ? _m3dstbiw___zlib_huff1(n) : (n) <= 255 ? _m3dstbiw___zlib_huff2(n) : (n) <= 279 ? _m3dstbiw___zlib_huff3(n) : _m3dstbiw___zlib_huff4(n)) +#define _m3dstbiw___zlib_huffb(n) ((n) <= 143 ? _m3dstbiw___zlib_huff1(n) : _m3dstbiw___zlib_huff2(n)) -#define stbiw__ZHASH 16384 +#define _m3dstbiw___ZHASH 16384 -unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) +unsigned char * _m3dstbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) { static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; @@ -1760,42 +1915,44 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l unsigned int bitbuf=0; int i,j, bitcount=0; unsigned char *out = NULL; - unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**)); + unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(_m3dstbiw___ZHASH * sizeof(char**)); + if (hash_table == NULL) + return NULL; if (quality < 5) quality = 5; - stbiw__sbpush(out, 0x78); - stbiw__sbpush(out, 0x5e); - stbiw__zlib_add(1,1); - stbiw__zlib_add(1,2); + _m3dstbiw___sbpush(out, 0x78); + _m3dstbiw___sbpush(out, 0x5e); + _m3dstbiw___zlib_add(1,1); + _m3dstbiw___zlib_add(1,2); - for (i=0; i < stbiw__ZHASH; ++i) + for (i=0; i < _m3dstbiw___ZHASH; ++i) hash_table[i] = NULL; i=0; while (i < data_len-3) { - int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; + int h = _m3dstbiw___zhash(data+i)&(_m3dstbiw___ZHASH-1), best=3; unsigned char *bestloc = 0; unsigned char **hlist = hash_table[h]; - int n = stbiw__sbcount(hlist); + int n = _m3dstbiw___sbcount(hlist); for (j=0; j < n; ++j) { if (hlist[j]-data > i-32768) { - int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); + int d = _m3dstbiw___zlib_countm(hlist[j], data+i, data_len-i); if (d >= best) best=d,bestloc=hlist[j]; } } - if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { + if (hash_table[h] && _m3dstbiw___sbn(hash_table[h]) == 2*quality) { STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); - stbiw__sbn(hash_table[h]) = quality; + _m3dstbiw___sbn(hash_table[h]) = quality; } - stbiw__sbpush(hash_table[h],data+i); + _m3dstbiw___sbpush(hash_table[h],data+i); if (bestloc) { - h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); + h = _m3dstbiw___zhash(data+i+1)&(_m3dstbiw___ZHASH-1); hlist = hash_table[h]; - n = stbiw__sbcount(hlist); + n = _m3dstbiw___sbcount(hlist); for (j=0; j < n; ++j) { if (hlist[j]-data > i-32767) { - int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); + int e = _m3dstbiw___zlib_countm(hlist[j], data+i+1, data_len-i-1); if (e > best) { bestloc = NULL; break; @@ -1808,25 +1965,25 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l int d = (int) (data+i - bestloc); STBIW_ASSERT(d <= 32767 && best <= 258); for (j=0; best > lengthc[j+1]-1; ++j); - stbiw__zlib_huff(j+257); - if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); + _m3dstbiw___zlib_huff(j+257); + if (lengtheb[j]) _m3dstbiw___zlib_add(best - lengthc[j], lengtheb[j]); for (j=0; d > distc[j+1]-1; ++j); - stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); - if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); + _m3dstbiw___zlib_add(_m3dstbiw___zlib_bitrev(j,5),5); + if (disteb[j]) _m3dstbiw___zlib_add(d - distc[j], disteb[j]); i += best; } else { - stbiw__zlib_huffb(data[i]); + _m3dstbiw___zlib_huffb(data[i]); ++i; } } for (;i < data_len; ++i) - stbiw__zlib_huffb(data[i]); - stbiw__zlib_huff(256); + _m3dstbiw___zlib_huffb(data[i]); + _m3dstbiw___zlib_huff(256); while (bitcount) - stbiw__zlib_add(0,1); + _m3dstbiw___zlib_add(0,1); - for (i=0; i < stbiw__ZHASH; ++i) - (void) stbiw__sbfree(hash_table[i]); + for (i=0; i < _m3dstbiw___ZHASH; ++i) + (void) _m3dstbiw___sbfree(hash_table[i]); STBIW_FREE(hash_table); { @@ -1839,15 +1996,18 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l j += blocklen; blocklen = 5552; } - stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); - stbiw__sbpush(out, STBIW_UCHAR(s2)); - stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); - stbiw__sbpush(out, STBIW_UCHAR(s1)); + _m3dstbiw___sbpush(out, STBIW_UCHAR(s2 >> 8)); + _m3dstbiw___sbpush(out, STBIW_UCHAR(s2)); + _m3dstbiw___sbpush(out, STBIW_UCHAR(s1 >> 8)); + _m3dstbiw___sbpush(out, STBIW_UCHAR(s1)); } - *out_len = stbiw__sbn(out); - STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); - return (unsigned char *) stbiw__sbraw(out); + *out_len = _m3dstbiw___sbn(out); + STBIW_MEMMOVE(_m3dstbiw___sbraw(out), out, *out_len); + return (unsigned char *) _m3dstbiw___sbraw(out); } +#define stbi_zlib_compress _m3dstbi_zlib_compress +#else +unsigned char * _m3dstbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality); #endif #define M3D_CHUNKMAGIC(m, a,b,c,d) ((m)[0]==(a) && (m)[1]==(b) && (m)[2]==(c) && (m)[3]==(d)) @@ -1856,6 +2016,9 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l #include /* get sprintf */ #include /* sprintf and strtod cares about number locale */ #endif +#ifdef M3D_PROFILING +#include +#endif #if !defined(M3D_NOIMPORTER) && defined(M3D_ASCII) /* helper functions for the ASCII parser */ @@ -1885,7 +2048,7 @@ static char *_m3d_gethex(char *s, uint32_t *ret) static char *_m3d_getint(char *s, uint32_t *ret) { char *e = s; - if(!s || !*s) return s; + if(!s || !*s || *s == '\r' || *s == '\n') return s; for(; *e >= '0' && *e <= '9'; e++); *ret = atoi(s); return e; @@ -1893,54 +2056,13 @@ static char *_m3d_getint(char *s, uint32_t *ret) static char *_m3d_getfloat(char *s, M3D_FLOAT *ret) { char *e = s; - if(!s || !*s) return s; + if(!s || !*s || *s == '\r' || *s == '\n') return s; for(; *e == '-' || *e == '+' || *e == '.' || (*e >= '0' && *e <= '9') || *e == 'e' || *e == 'E'; e++); *ret = (M3D_FLOAT)strtod(s, NULL); return _m3d_findarg(e); } #endif -#if !defined(M3D_NODUP) && (!defined(M3D_NONORMALS) || defined(M3D_EXPORTER)) -/* add vertex to list, only compare x,y,z */ -m3dv_t *_m3d_addnorm(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx) -{ - uint32_t i; - if(v->x == (M3D_FLOAT)-0.0) v->x = (M3D_FLOAT)0.0; - if(v->y == (M3D_FLOAT)-0.0) v->y = (M3D_FLOAT)0.0; - if(v->z == (M3D_FLOAT)-0.0) v->z = (M3D_FLOAT)0.0; - if(v->w == (M3D_FLOAT)-0.0) v->w = (M3D_FLOAT)0.0; - if(vrtx) { - for(i = 0; i < *numvrtx; i++) - if(vrtx[i].x == v->x && vrtx[i].y == v->y && vrtx[i].z == v->z) { *idx = i; return vrtx; } - } - vrtx = (m3dv_t*)M3D_REALLOC(vrtx, ((*numvrtx) + 1) * sizeof(m3dv_t)); - memcpy(&vrtx[*numvrtx], v, sizeof(m3dv_t)); - vrtx[*numvrtx].color = 0; - vrtx[*numvrtx].w = (M3D_FLOAT)1.0; - *idx = *numvrtx; - (*numvrtx)++; - return vrtx; -} -#endif -#if !defined(M3D_NODUP) && (defined(M3D_ASCII) || defined(M3D_EXPORTER)) -m3ds_t *_m3d_addskin(m3ds_t *skin, uint32_t *numskin, m3ds_t *s, uint32_t *idx) -{ - uint32_t i; - M3D_FLOAT w = (M3D_FLOAT)0.0; - for(i = 0; i < M3D_NUMBONE && s->weight[i] > (M3D_FLOAT)0.0; i++) - w += s->weight[i]; - if(w != (M3D_FLOAT)1.0 && w != (M3D_FLOAT)0.0) - for(i = 0; i < M3D_NUMBONE && s->weight[i] > (M3D_FLOAT)0.0; i++) - s->weight[i] /= w; - if(skin) { - for(i = 0; i < *numskin; i++) - if(!memcmp(&skin[i], s, sizeof(m3ds_t))) { *idx = i; return skin; } - } - skin = (m3ds_t*)M3D_REALLOC(skin, ((*numskin) + 1) * sizeof(m3ds_t)); - memcpy(&skin[*numskin], s, sizeof(m3ds_t)); - *idx = *numskin; - (*numskin)++; - return skin; -} +#if !defined(M3D_NODUP) && (!defined(M3D_NOIMPORTER) || defined(M3D_ASCII) || defined(M3D_EXPORTER)) /* helper function to create safe strings */ char *_m3d_safestr(char *in, int morelines) { @@ -1973,7 +2095,7 @@ char *_m3d_safestr(char *in, int morelines) } for(; o > out && (*(o-1) == ' ' || *(o-1) == '\t' || *(o-1) == '\r' || *(o-1) == '\n'); o--); *o = 0; - out = (char*)M3D_REALLOC(out, (uint64_t)o - (uint64_t)out + 1); + out = (char*)M3D_REALLOC(out, (uintptr_t)o - (uintptr_t)out + 1); } return out; } @@ -1982,28 +2104,20 @@ char *_m3d_safestr(char *in, int morelines) /* helper function to load and decode/generate a texture */ M3D_INDEX _m3d_gettx(m3d_t *model, m3dread_t readfilecb, m3dfree_t freecb, char *fn) { - unsigned int i, len = 0, w, h; + unsigned int i, len = 0; unsigned char *buff = NULL; char *fn2; +#ifdef STBI__PNG_TYPE + unsigned int w, h; stbi__context s; stbi__result_info ri; +#endif + /* do we have loaded this texture already? */ for(i = 0; i < model->numtexture; i++) if(!strcmp(fn, model->texture[i].name)) return i; - if(readfilecb) { - i = strlen(fn); - if(i < 5 || fn[i - 4] != '.') { - fn2 = (char*)M3D_MALLOC(i + 5); - if(!fn2) { model->errcode = M3D_ERR_ALLOC; return (M3D_INDEX)-1U; } - memcpy(fn2, fn, i); - memcpy(fn2+i, ".png", 5); - buff = (*readfilecb)(fn2, &len); - M3D_FREE(fn2); - } - if(!buff) - buff = (*readfilecb)(fn, &len); - } - if(!buff && model->inlined) { + /* see if it's inlined in the model */ + if(model->inlined) { for(i = 0; i < model->numinlined; i++) if(!strcmp(fn, model->inlined[i].name)) { buff = model->inlined[i].data; @@ -2012,42 +2126,61 @@ M3D_INDEX _m3d_gettx(m3d_t *model, m3dread_t readfilecb, m3dfree_t freecb, char break; } } - if(!buff) return (M3D_INDEX)-1U; + /* try to load from external source */ + if(!buff && readfilecb) { + i = (unsigned int)strlen(fn); + if(i < 5 || fn[i - 4] != '.') { + fn2 = (char*)M3D_MALLOC(i + 5); + if(!fn2) { model->errcode = M3D_ERR_ALLOC; return M3D_UNDEF; } + memcpy(fn2, fn, i); + memcpy(fn2+i, ".png", 5); + buff = (*readfilecb)(fn2, &len); + M3D_FREE(fn2); + } + if(!buff) { + buff = (*readfilecb)(fn, &len); + if(!buff) return M3D_UNDEF; + } + } + /* add to textures array */ i = model->numtexture++; model->texture = (m3dtx_t*)M3D_REALLOC(model->texture, model->numtexture * sizeof(m3dtx_t)); if(!model->texture) { - if(freecb) (*freecb)(buff); - model->errcode = M3D_ERR_ALLOC; return (M3D_INDEX)-1U; - } - model->texture[i].w = model->texture[i].h = 0; model->texture[i].d = NULL; - if(buff[0] == 0x89 && buff[1] == 'P' && buff[2] == 'N' && buff[3] == 'G') { - s.read_from_callbacks = 0; - s.img_buffer = s.img_buffer_original = (stbi_uc *) buff; - s.img_buffer_end = s.img_buffer_original_end = (stbi_uc *) buff+len; - /* don't use model->texture[i].w directly, it's a uint16_t */ - w = h = 0; - model->texture[i].d = (uint32_t*)stbi__png_load(&s, (int*)&w, (int*)&h, (int*)&len, STBI_rgb_alpha, &ri); - model->texture[i].w = w; - model->texture[i].h = h; - } else { -#ifdef M3D_TX_INTERP - if((model->errcode = M3D_TX_INTERP(fn, buff, len, &model->texture[i])) != M3D_SUCCESS) { - M3D_LOG("Unable to generate texture"); - M3D_LOG(fn); - } -#else - M3D_LOG("Unimplemented interpreter"); - M3D_LOG(fn); -#endif - } - if(freecb) (*freecb)(buff); - if(!model->texture[i].d) { - M3D_FREE(model->texture[i].d); - model->errcode = M3D_ERR_UNKIMG; - model->numtexture--; - return (M3D_INDEX)-1U; + if(buff && freecb) (*freecb)(buff); + model->errcode = M3D_ERR_ALLOC; + return M3D_UNDEF; } model->texture[i].name = fn; + model->texture[i].w = model->texture[i].h = 0; model->texture[i].d = NULL; + if(buff) { + if(buff[0] == 0x89 && buff[1] == 'P' && buff[2] == 'N' && buff[3] == 'G') { +#ifdef STBI__PNG_TYPE + s.read_from_callbacks = 0; + s.img_buffer = s.img_buffer_original = (unsigned char *) buff; + s.img_buffer_end = s.img_buffer_original_end = (unsigned char *) buff+len; + /* don't use model->texture[i].w directly, it's a uint16_t */ + w = h = len = 0; + ri.bits_per_channel = 8; + model->texture[i].d = (uint8_t*)stbi__png_load(&s, (int*)&w, (int*)&h, (int*)&len, 0, &ri); + model->texture[i].w = w; + model->texture[i].h = h; + model->texture[i].f = (uint8_t)len; +#endif + } else { +#ifdef M3D_TX_INTERP + if((model->errcode = M3D_TX_INTERP(fn, buff, len, &model->texture[i])) != M3D_SUCCESS) { + M3D_LOG("Unable to generate texture"); + M3D_LOG(fn); + } +#else + M3D_LOG("Unimplemented interpreter"); + M3D_LOG(fn); +#endif + } + if(freecb) (*freecb)(buff); + } + if(!model->texture[i].d) + model->errcode = M3D_ERR_UNKIMG; return i; } @@ -2074,6 +2207,9 @@ void _m3d_getpr(m3d_t *model, _unused m3dread_t readfilecb, _unused m3dfree_t f } if(freecb && buff) (*freecb)(buff); #else + (void)readfilecb; + (void)freecb; + (void)fn; M3D_LOG("Unimplemented interpreter"); M3D_LOG(fn); model->errcode = M3D_ERR_UNIMPL; @@ -2085,8 +2221,8 @@ _inline static unsigned char *_m3d_getidx(unsigned char *data, char type, M3D_IN { switch(type) { case 1: *idx = data[0] > 253 ? (int8_t)data[0] : data[0]; data++; break; - case 2: *idx = (uint16_t)((data[1]<<8)|data[0]) > 65533 ? (int16_t)((data[1]<<8)|data[0]) : (uint16_t)((data[1]<<8)|data[0]); data += 2; break; - case 4: *idx = (int32_t)((data[3]<<24)|(data[2]<<16)|(data[1]<<8)|data[0]); data += 4; break; + case 2: *idx = *((uint16_t*)data) > 65533 ? *((int16_t*)data) : *((uint16_t*)data); data += 2; break; + case 4: *idx = *((int32_t*)data); data += 4; break; } return data; } @@ -2144,10 +2280,6 @@ void _m3d_inv(M3D_FLOAT *m) memcpy(m, &r, sizeof(r)); } /* compose a coloumn major 4 x 4 matrix from vec3 position and vec4 orientation/rotation quaternion */ -#ifndef M3D_EPSILON -/* carefully choosen for IEEE 754 don't change */ -#define M3D_EPSILON ((M3D_FLOAT)1e-7) -#endif void _m3d_mat(M3D_FLOAT *r, m3dv_t *p, m3dv_t *q) { if(q->x == (M3D_FLOAT)0.0 && q->y == (M3D_FLOAT)0.0 && q->z >=(M3D_FLOAT) 0.7071065 && q->z <= (M3D_FLOAT)0.7071075 && @@ -2170,7 +2302,7 @@ void _m3d_mat(M3D_FLOAT *r, m3dv_t *p, m3dv_t *q) } #endif #if !defined(M3D_NOANIMATION) || !defined(M3D_NONORMALS) -/* fast inverse square root calculation. returns 1/sqrt(x) */ +/* portable fast inverse square root calculation. returns 1/sqrt(x) */ static M3D_FLOAT _m3d_rsq(M3D_FLOAT x) { #ifdef M3D_DOUBLE @@ -2190,30 +2322,40 @@ static M3D_FLOAT _m3d_rsq(M3D_FLOAT x) m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d_t *mtllib) { unsigned char *end, *chunk, *buff, weights[8]; - unsigned int i, j, k, n, am, len = 0, reclen, offs; - char *material; -#ifndef M3D_NONORMALS - unsigned int numnorm = 0; - m3dv_t *norm = NULL, *v0, *v1, *v2, va, vb, vn; - M3D_INDEX *ni = NULL, *vi = NULL; -#endif + unsigned int i, j, k, l, n, am, len = 0, reclen, offs; + char *name, *lang; + float f; m3d_t *model; M3D_INDEX mi; M3D_FLOAT w; + m3dcd_t *cd; + m3dtx_t *tx; + m3dh_t *h; + m3dm_t *m; + m3da_t *a; + m3di_t *t; +#ifndef M3D_NONORMALS + char neednorm = 0; + m3dv_t *norm = NULL, *v0, *v1, *v2, va, vb; +#endif #ifndef M3D_NOANIMATION M3D_FLOAT r[16]; #endif - m3dtx_t *tx; - m3dm_t *m; - m3da_t *a; +#if !defined(M3D_NOWEIGHTS) || !defined(M3D_NOANIMATION) m3db_t *b; - m3di_t *t; +#endif +#ifndef M3D_NOWEIGHTS m3ds_t *sk; +#endif #ifdef M3D_ASCII m3ds_t s; M3D_INDEX bi[M3D_BONEMAXLEVEL+1], level; const char *ol; - char *ptr, *pe; + char *ptr, *pe, *fn; +#endif +#ifdef M3D_PROFILING + struct timeval tv0, tv1, tvd; + gettimeofday(&tv0, NULL); #endif if(!data || (!M3D_CHUNKMAGIC(data, '3','D','M','O') @@ -2250,13 +2392,14 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d pe = _m3d_findnl(ptr); model->scale = (float)strtod(ptr, NULL); ptr = pe; if(model->scale <= (M3D_FLOAT)0.0) model->scale = (M3D_FLOAT)1.0; - model->name = _m3d_safestr(ptr, 0); ptr = _m3d_findnl(ptr); + model->name = _m3d_safestr(ptr, 2); ptr = _m3d_findnl(ptr); if(!*ptr) goto asciiend; model->license = _m3d_safestr(ptr, 2); ptr = _m3d_findnl(ptr); if(!*ptr) goto asciiend; model->author = _m3d_safestr(ptr, 2); ptr = _m3d_findnl(ptr); if(!*ptr) goto asciiend; - model->desc = _m3d_safestr(ptr, 3); + if(*ptr != '\r' && *ptr != '\n') + model->desc = _m3d_safestr(ptr, 3); while(*ptr) { while(*ptr && *ptr!='\n') ptr++; ptr++; if(*ptr=='\r') ptr++; @@ -2270,6 +2413,17 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d /* make sure there's at least one data row */ pe = ptr; ptr = _m3d_findnl(ptr); if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; + /* Preview chunk */ + if(!memcmp(pe, "Preview", 7)) { + if(readfilecb) { + pe = _m3d_safestr(ptr, 0); + if(!pe || !*pe) goto asciiend; + model->preview.data = (*readfilecb)(pe, &model->preview.length); + M3D_FREE(pe); + } + while(*ptr && *ptr != '\r' && *ptr != '\n') + ptr = _m3d_findnl(ptr); + } else /* texture map chunk */ if(!memcmp(pe, "Textmap", 7)) { if(model->tmap) { M3D_LOG("More texture map chunks, should be unique"); goto asciiend; } @@ -2279,8 +2433,7 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d if(!model->tmap) goto memerr; ptr = _m3d_getfloat(ptr, &model->tmap[i].u); if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - ptr = _m3d_getfloat(ptr, &model->tmap[i].v); - if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; + _m3d_getfloat(ptr, &model->tmap[i].v); ptr = _m3d_findnl(ptr); } } else @@ -2291,8 +2444,10 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d i = model->numvertex++; model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, model->numvertex * sizeof(m3dv_t)); if(!model->vertex) goto memerr; - model->vertex[i].skinid = (M3D_INDEX)-1U; + memset(&model->vertex[i], 0, sizeof(m3dv_t)); + model->vertex[i].skinid = M3D_UNDEF; model->vertex[i].color = 0; + model->vertex[i].w = (M3D_FLOAT)1.0; ptr = _m3d_getfloat(ptr, &model->vertex[i].x); if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; ptr = _m3d_getfloat(ptr, &model->vertex[i].y); @@ -2300,7 +2455,6 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d ptr = _m3d_getfloat(ptr, &model->vertex[i].z); if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; ptr = _m3d_getfloat(ptr, &model->vertex[i].w); - if(model->vertex[i].w != 1.0) model->vertex[i].skinid = (M3D_INDEX)-2U; if(!*ptr) goto asciiend; if(*ptr == '#') { ptr = _m3d_gethex(ptr, &model->vertex[i].color); @@ -2308,7 +2462,7 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d } /* parse skin */ memset(&s, 0, sizeof(m3ds_t)); - for(j = 0; j < M3D_NUMBONE && *ptr && *ptr != '\r' && *ptr != '\n'; j++) { + for(j = 0, w = (M3D_FLOAT)0.0; j < M3D_NUMBONE && *ptr && *ptr != '\r' && *ptr != '\n'; j++) { ptr = _m3d_findarg(ptr); if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; ptr = _m3d_getint(ptr, &k); @@ -2316,12 +2470,25 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d if(*ptr == ':') { ptr++; ptr = _m3d_getfloat(ptr, &s.weight[j]); + w += s.weight[j]; } else if(!j) s.weight[j] = (M3D_FLOAT)1.0; if(!*ptr) goto asciiend; } - if(s.boneid[0] != (M3D_INDEX)-1U && s.weight[0] > (M3D_FLOAT)0.0) { - model->skin = _m3d_addskin(model->skin, &model->numskin, &s, &k); + if(s.boneid[0] != M3D_UNDEF && s.weight[0] > (M3D_FLOAT)0.0) { + if(w != (M3D_FLOAT)1.0 && w != (M3D_FLOAT)0.0) + for(j = 0; j < M3D_NUMBONE && s.weight[j] > (M3D_FLOAT)0.0; j++) + s.weight[j] /= w; + k = M3D_NOTDEFINED; + if(model->skin) { + for(j = 0; j < model->numskin; j++) + if(!memcmp(&model->skin[j], &s, sizeof(m3ds_t))) { k = j; break; } + } + if(k == M3D_NOTDEFINED) { + k = model->numskin++; + model->skin = (m3ds_t*)M3D_REALLOC(model->skin, model->numskin * sizeof(m3ds_t)); + memcpy(&model->skin[k], &s, sizeof(m3ds_t)); + } model->vertex[i].skinid = (M3D_INDEX)k; } ptr = _m3d_findnl(ptr); @@ -2330,7 +2497,7 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d /* Skeleton, bone hierarchy */ if(!memcmp(pe, "Bones", 5)) { if(model->bone) { M3D_LOG("More bones chunks, should be unique"); goto asciiend; } - bi[0] = (M3D_INDEX)-1U; + bi[0] = M3D_UNDEF; while(*ptr && *ptr != '\r' && *ptr != '\n') { i = model->numbone++; model->bone = (m3db_t*)M3D_REALLOC(model->bone, model->numbone * sizeof(m3db_t)); @@ -2349,6 +2516,7 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d ptr = _m3d_findarg(ptr); if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; model->bone[i].ori = (M3D_INDEX)k; + model->vertex[k].skinid = M3D_INDEXMAX; pe = _m3d_safestr(ptr, 0); if(!pe || !*pe) goto asciiend; model->bone[i].name = pe; @@ -2410,7 +2578,7 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d j = m->numprop++; m->prop = (m3dp_t*)M3D_REALLOC(m->prop, m->numprop * sizeof(m3dp_t)); if(!m->prop) goto memerr; - m->prop[j].type = n; + m->prop[j].type = n + (k == m3dpf_map && n < 128 ? 128 : 0); switch(k) { case m3dpf_color: ptr = _m3d_gethex(ptr, &m->prop[j].value.color); break; case m3dpf_uint8: @@ -2422,7 +2590,8 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d if(!pe || !*pe) goto asciiend; m->prop[j].value.textureid = _m3d_gettx(model, readfilecb, freecb, pe); if(model->errcode == M3D_ERR_ALLOC) { M3D_FREE(pe); goto memerr; } - if(m->prop[j].value.textureid == (M3D_INDEX)-1U) { + /* this error code only returned if readfilecb was specified */ + if(m->prop[j].value.textureid == M3D_UNDEF) { M3D_LOG("Texture not found"); M3D_LOG(pe); m->numprop--; @@ -2439,7 +2608,7 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d } if(!m->numprop) model->nummaterial--; } else - /* procedural, not implemented yet, skip chunk */ + /* procedural */ if(!memcmp(pe, "Procedural", 10)) { pe = _m3d_safestr(ptr, 0); _m3d_getpr(model, readfilecb, freecb, pe); @@ -2448,21 +2617,26 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d } else /* mesh */ if(!memcmp(pe, "Mesh", 4)) { - mi = (M3D_INDEX)-1U; + mi = M3D_UNDEF; while(*ptr && *ptr != '\r' && *ptr != '\n') { if(*ptr == 'u') { ptr = _m3d_findarg(ptr); if(!*ptr) goto asciiend; - mi = (M3D_INDEX)-1U; + mi = M3D_UNDEF; if(*ptr != '\r' && *ptr != '\n') { pe = _m3d_safestr(ptr, 0); if(!pe || !*pe) goto asciiend; for(j = 0; j < model->nummaterial; j++) - if(!strcmp(pe, model->material[j].name)) { - mi = (M3D_INDEX)j; - break; - } - M3D_FREE(pe); + if(!strcmp(pe, model->material[j].name)) { mi = (M3D_INDEX)j; break; } + if(mi == M3D_UNDEF && !(model->flags & M3D_FLG_MTLLIB)) { + mi = model->nummaterial++; + model->material = (m3dm_t*)M3D_REALLOC(model->material, model->nummaterial * sizeof(m3dm_t)); + if(!model->material) goto memerr; + model->material[mi].name = pe; + model->material[mi].numprop = 1; + model->material[mi].prop = NULL; + } else + M3D_FREE(pe); } } else { i = model->numface++; @@ -2492,12 +2666,146 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d if(!*ptr) goto asciiend; } } +#ifndef M3D_NONORMALS + if(model->face[i].normal[j] == M3D_UNDEF) neednorm = 1; +#endif ptr = _m3d_findarg(ptr); } } ptr = _m3d_findnl(ptr); } } else + /* mathematical shape */ + if(!memcmp(pe, "Shape", 5)) { + pe = _m3d_findarg(pe); + if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; + pe = _m3d_safestr(pe, 0); + if(!pe || !*pe) goto asciiend; + i = model->numshape++; + model->shape = (m3dh_t*)M3D_REALLOC(model->shape, model->numshape * sizeof(m3ds_t)); + if(!model->shape) goto memerr; + h = &model->shape[i]; + h->name = pe; + h->group = M3D_UNDEF; + h->numcmd = 0; + h->cmd = NULL; + while(*ptr && *ptr != '\r' && *ptr != '\n') { + if(!memcmp(ptr, "group", 5)) { + ptr = _m3d_findarg(ptr); + ptr = _m3d_getint(ptr, &h->group); + ptr = _m3d_findnl(ptr); + if(h->group != M3D_UNDEF && h->group >= model->numbone) { + M3D_LOG("Unknown bone id as shape group in shape"); + M3D_LOG(pe); + h->group = M3D_UNDEF; + model->errcode = M3D_ERR_SHPE; + } + continue; + } + for(cd = NULL, k = 0; k < (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0])); k++) { + j = (unsigned int)strlen(m3d_commandtypes[k].key); + if(!memcmp(ptr, m3d_commandtypes[k].key, j) && (ptr[j] == ' ' || ptr[j] == '\r' || ptr[j] == '\n')) + { cd = &m3d_commandtypes[k]; break; } + } + if(cd) { + j = h->numcmd++; + h->cmd = (m3dc_t*)M3D_REALLOC(h->cmd, h->numcmd * sizeof(m3dc_t)); + if(!h->cmd) goto memerr; + h->cmd[j].type = k; + h->cmd[j].arg = (uint32_t*)M3D_MALLOC(cd->p * sizeof(uint32_t)); + if(!h->cmd[j].arg) goto memerr; + memset(h->cmd[j].arg, 0, cd->p * sizeof(uint32_t)); + for(k = n = 0, l = cd->p; k < l; k++) { + ptr = _m3d_findarg(ptr); + if(!*ptr) goto asciiend; + if(*ptr == '[') { + ptr = _m3d_findarg(ptr + 1); + if(!*ptr) goto asciiend; + } + if(*ptr == ']' || *ptr == '\r' || *ptr == '\n') break; + switch(cd->a[((k - n) % (cd->p - n)) + n]) { + case m3dcp_mi_t: + mi = M3D_UNDEF; + if(*ptr != '\r' && *ptr != '\n') { + pe = _m3d_safestr(ptr, 0); + if(!pe || !*pe) goto asciiend; + for(n = 0; n < model->nummaterial; n++) + if(!strcmp(pe, model->material[n].name)) { mi = (M3D_INDEX)n; break; } + if(mi == M3D_UNDEF && !(model->flags & M3D_FLG_MTLLIB)) { + mi = model->nummaterial++; + model->material = (m3dm_t*)M3D_REALLOC(model->material, + model->nummaterial * sizeof(m3dm_t)); + if(!model->material) goto memerr; + model->material[mi].name = pe; + model->material[mi].numprop = 1; + model->material[mi].prop = NULL; + } else + M3D_FREE(pe); + } + h->cmd[j].arg[k] = mi; + break; + case m3dcp_vc_t: + _m3d_getfloat(ptr, &w); + h->cmd[j].arg[k] = *((uint32_t*)&w); + break; + case m3dcp_va_t: + ptr = _m3d_getint(ptr, &h->cmd[j].arg[k]); + n = k + 1; l += (h->cmd[j].arg[k] - 1) * (cd->p - k - 1); + h->cmd[j].arg = (uint32_t*)M3D_REALLOC(h->cmd[j].arg, l * sizeof(uint32_t)); + if(!h->cmd[j].arg) goto memerr; + memset(&h->cmd[j].arg[k + 1], 0, (l - k - 1) * sizeof(uint32_t)); + break; + case m3dcp_qi_t: + ptr = _m3d_getint(ptr, &h->cmd[j].arg[k]); + model->vertex[h->cmd[i].arg[k]].skinid = M3D_INDEXMAX; + break; + default: + ptr = _m3d_getint(ptr, &h->cmd[j].arg[k]); + break; + } + } + } else { + M3D_LOG("Unknown shape command in"); + M3D_LOG(h->name); + model->errcode = M3D_ERR_UNKCMD; + } + ptr = _m3d_findnl(ptr); + } + if(!h->numcmd) model->numshape--; + } else + /* annotation labels */ + if(!memcmp(pe, "Labels", 6)) { + pe = _m3d_findarg(pe); + if(!*pe) goto asciiend; + if(*pe == '\r' || *pe == '\n') pe = NULL; + else pe = _m3d_safestr(pe, 0); + k = 0; fn = NULL; + while(*ptr && *ptr != '\r' && *ptr != '\n') { + if(*ptr == 'c') { + ptr = _m3d_findarg(ptr); + if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; + ptr = _m3d_gethex(ptr, &k); + } else + if(*ptr == 'l') { + ptr = _m3d_findarg(ptr); + if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; + fn = _m3d_safestr(ptr, 2); + } else { + i = model->numlabel++; + model->label = (m3dl_t*)M3D_REALLOC(model->label, model->numlabel * sizeof(m3dl_t)); + if(!model->label) goto memerr; + model->label[i].name = pe; + model->label[i].lang = fn; + model->label[i].color = k; + ptr = _m3d_getint(ptr, &j); + model->label[i].vertexid = (M3D_INDEX)j; + ptr = _m3d_findarg(ptr); + if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; + model->label[i].text = _m3d_safestr(ptr, 2); + } + ptr = _m3d_findnl(ptr); + } + } else /* action */ if(!memcmp(pe, "Action", 6)) { pe = _m3d_findarg(pe); @@ -2548,6 +2856,33 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d ptr = _m3d_getint(ptr, &k); if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; a->frame[i].transform[j].ori = (M3D_INDEX)k; + model->vertex[k].skinid = M3D_INDEXMAX; + } + ptr = _m3d_findnl(ptr); + } + } else + /* inlined assets chunk */ + if(!memcmp(pe, "Assets", 6)) { + while(*ptr && *ptr != '\r' && *ptr != '\n') { + if(readfilecb) { + pe = _m3d_safestr(ptr, 2); + if(!pe || !*pe) goto asciiend; + i = model->numinlined++; + model->inlined = (m3di_t*)M3D_REALLOC(model->inlined, model->numinlined * sizeof(m3di_t)); + if(!model->inlined) goto memerr; + t = &model->inlined[i]; + model->inlined[i].data = (*readfilecb)(pe, &model->inlined[i].length); + if(model->inlined[i].data) { + fn = strrchr(pe, '.'); + if(fn && (fn[1] == 'p' || fn[1] == 'P') && (fn[2] == 'n' || fn[2] == 'N') && + (fn[3] == 'g' || fn[3] == 'G')) *fn = 0; + fn = strrchr(pe, '/'); + if(!fn) fn = strrchr(pe, '\\'); + if(!fn) fn = pe; else fn++; + model->inlined[i].name = _m3d_safestr(fn, 0); + } else + model->numinlined--; + M3D_FREE(pe); } ptr = _m3d_findnl(ptr); } @@ -2557,19 +2892,19 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d pe = _m3d_findarg(pe); if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; buff = (unsigned char*)_m3d_findnl(ptr); - k = ((uint32_t)((uint64_t)buff - (uint64_t)ptr) / 3) + 1; - i = model->numunknown++; - model->unknown = (m3dchunk_t**)M3D_REALLOC(model->unknown, model->numunknown * sizeof(m3dchunk_t*)); - if(!model->unknown) goto memerr; - model->unknown[i] = (m3dchunk_t*)M3D_MALLOC(k + sizeof(m3dchunk_t)); - if(!model->unknown[i]) goto memerr; - memcpy(&model->unknown[i]->magic, pe, 4); - model->unknown[i]->length = sizeof(m3dchunk_t); - pe = (char*)model->unknown[i] + sizeof(m3dchunk_t); + k = ((uint32_t)((uintptr_t)buff - (uintptr_t)ptr) / 3) + 1; + i = model->numextra++; + model->extra = (m3dchunk_t**)M3D_REALLOC(model->extra, model->numextra * sizeof(m3dchunk_t*)); + if(!model->extra) goto memerr; + model->extra[i] = (m3dchunk_t*)M3D_MALLOC(k + sizeof(m3dchunk_t)); + if(!model->extra[i]) goto memerr; + memcpy(&model->extra[i]->magic, pe, 4); + model->extra[i]->length = sizeof(m3dchunk_t); + pe = (char*)model->extra[i] + sizeof(m3dchunk_t); while(*ptr && *ptr != '\r' && *ptr != '\n') { ptr = _m3d_gethex(ptr, &k); *pe++ = (uint8_t)k; - model->unknown[i]->length++; + model->extra[i]->length++; } } else goto asciiend; @@ -2579,14 +2914,12 @@ asciiend: setlocale(LC_NUMERIC, ol); goto postprocess; } - /* Binary variant */ #endif + /* Binary variant */ if(!M3D_CHUNKMAGIC(data + 8, 'H','E','A','D')) { - stbi__g_failure_reason = "Corrupt file"; buff = (unsigned char *)stbi_zlib_decode_malloc_guesssize_headerflag((const char*)data+8, ((m3dchunk_t*)data)->length-8, 4096, (int*)&len, 1); if(!buff || !len || !M3D_CHUNKMAGIC(buff, 'H','E','A','D')) { - M3D_LOG(stbi__g_failure_reason); if(buff) M3D_FREE(buff); M3D_FREE(model); return NULL; @@ -2594,6 +2927,14 @@ asciiend: buff = (unsigned char*)M3D_REALLOC(buff, len); model->flags |= M3D_FLG_FREERAW; /* mark that we have to free the raw buffer */ data = buff; +#ifdef M3D_PROFILING + gettimeofday(&tv1, NULL); + tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; + tvd.tv_usec = tv1.tv_usec - tv0.tv_usec; + if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } + printf(" Deflate model %ld.%06ld sec\n", tvd.tv_sec, tvd.tv_usec); + memcpy(&tv0, &tv1, sizeof(struct timeval)); +#endif } else { len = ((m3dhdr_t*)data)->length; data += 8; @@ -2622,11 +2963,15 @@ asciiend: model->bi_s = 1 << ((model->raw->types >>10) & 3); /* bone index size */ model->nb_s = 1 << ((model->raw->types >>12) & 3); /* number of bones per vertex */ model->sk_s = 1 << ((model->raw->types >>14) & 3); /* skin index size */ - model->fi_s = 1 << ((model->raw->types >>16) & 3); /* frame counter size */ + model->fc_s = 1 << ((model->raw->types >>16) & 3); /* frame counter size */ + model->hi_s = 1 << ((model->raw->types >>18) & 3); /* shape index size */ + model->fi_s = 1 << ((model->raw->types >>20) & 3); /* face index size */ if(model->ci_s == 8) model->ci_s = 0; /* optional indices */ if(model->ti_s == 8) model->ti_s = 0; if(model->bi_s == 8) model->bi_s = 0; if(model->sk_s == 8) model->sk_s = 0; + if(model->fc_s == 8) model->fc_s = 0; + if(model->hi_s == 8) model->hi_s = 0; if(model->fi_s == 8) model->fi_s = 0; /* variable limit checks */ @@ -2635,7 +2980,7 @@ asciiend: model->errcode = M3D_ERR_TRUNC; } if(sizeof(M3D_INDEX) == 2 && (model->vi_s > 2 || model->si_s > 2 || model->ci_s > 2 || model->ti_s > 2 || - model->bi_s > 2 || model->sk_s > 2 || model->fi_s > 2)) { + model->bi_s > 2 || model->sk_s > 2 || model->fc_s > 2 || model->hi_s > 2 || model->fi_s > 2)) { M3D_LOG("32 bit indices not supported, unable to load model"); M3D_FREE(model); return NULL; @@ -2646,7 +2991,7 @@ asciiend: return NULL; } if(model->nb_s > M3D_NUMBONE) { - M3D_LOG("Model has more bones per vertex than importer supports"); + M3D_LOG("Model has more bones per vertex than what importer was configured to support"); model->errcode = M3D_ERR_TRUNC; } @@ -2655,11 +3000,11 @@ asciiend: while(buff < end && !M3D_CHUNKMAGIC(buff, 'O','M','D','3')) { data = buff; len = ((m3dchunk_t*)data)->length; - if(len < sizeof(m3dchunk_t)) { + buff += len; + if(len < sizeof(m3dchunk_t) || buff >= end) { M3D_LOG("Invalid chunk size"); break; } - buff += len; len -= sizeof(m3dchunk_t) + model->si_s; /* inlined assets */ @@ -2685,13 +3030,18 @@ memerr: M3D_LOG("Out of memory"); while(chunk < end && !M3D_CHUNKMAGIC(chunk, 'O','M','D','3')) { data = chunk; len = ((m3dchunk_t*)chunk)->length; - if(len < sizeof(m3dchunk_t)) { + chunk += len; + if(len < sizeof(m3dchunk_t) || chunk >= end) { M3D_LOG("Invalid chunk size"); break; } - chunk += len; len -= sizeof(m3dchunk_t); + /* preview chunk */ + if(M3D_CHUNKMAGIC(data, 'P','R','V','W') && len > 0) { + model->preview.length = len; + model->preview.data = data + sizeof(m3dchunk_t); + } else /* color map */ if(M3D_CHUNKMAGIC(data, 'C','M','A','P')) { M3D_LOG("Color map"); @@ -2712,12 +3062,12 @@ memerr: M3D_LOG("Out of memory"); for(i = 0, data += sizeof(m3dchunk_t); data < chunk; i++) { switch(model->vc_s) { case 1: - model->tmap[i].u = (M3D_FLOAT)(data[0]) / 255; - model->tmap[i].v = (M3D_FLOAT)(data[1]) / 255; + model->tmap[i].u = (M3D_FLOAT)(data[0]) / (M3D_FLOAT)255.0; + model->tmap[i].v = (M3D_FLOAT)(data[1]) / (M3D_FLOAT)255.0; break; case 2: - model->tmap[i].u = (M3D_FLOAT)(*((int16_t*)(data+0))) / 65535; - model->tmap[i].v = (M3D_FLOAT)(*((int16_t*)(data+2))) / 65535; + model->tmap[i].u = (M3D_FLOAT)(*((int16_t*)(data+0))) / (M3D_FLOAT)65535.0; + model->tmap[i].v = (M3D_FLOAT)(*((int16_t*)(data+2))) / (M3D_FLOAT)65535.0; break; case 4: model->tmap[i].u = (M3D_FLOAT)(*((float*)(data+0))); @@ -2744,17 +3094,17 @@ memerr: M3D_LOG("Out of memory"); for(i = 0, data += sizeof(m3dchunk_t); data < chunk && i < model->numvertex; i++) { switch(model->vc_s) { case 1: - model->vertex[i].x = (M3D_FLOAT)((int8_t)data[0]) / 127; - model->vertex[i].y = (M3D_FLOAT)((int8_t)data[1]) / 127; - model->vertex[i].z = (M3D_FLOAT)((int8_t)data[2]) / 127; - model->vertex[i].w = (M3D_FLOAT)((int8_t)data[3]) / 127; + model->vertex[i].x = (M3D_FLOAT)((int8_t)data[0]) / (M3D_FLOAT)127.0; + model->vertex[i].y = (M3D_FLOAT)((int8_t)data[1]) / (M3D_FLOAT)127.0; + model->vertex[i].z = (M3D_FLOAT)((int8_t)data[2]) / (M3D_FLOAT)127.0; + model->vertex[i].w = (M3D_FLOAT)((int8_t)data[3]) / (M3D_FLOAT)127.0; data += 4; break; case 2: - model->vertex[i].x = (M3D_FLOAT)((int16_t)((data[1]<<8)|data[0])) / 32767; - model->vertex[i].y = (M3D_FLOAT)((int16_t)((data[3]<<8)|data[2])) / 32767; - model->vertex[i].z = (M3D_FLOAT)((int16_t)((data[5]<<8)|data[4])) / 32767; - model->vertex[i].w = (M3D_FLOAT)((int16_t)((data[7]<<8)|data[6])) / 32767; + model->vertex[i].x = (M3D_FLOAT)(*((int16_t*)(data+0))) / (M3D_FLOAT)32767.0; + model->vertex[i].y = (M3D_FLOAT)(*((int16_t*)(data+2))) / (M3D_FLOAT)32767.0; + model->vertex[i].z = (M3D_FLOAT)(*((int16_t*)(data+4))) / (M3D_FLOAT)32767.0; + model->vertex[i].w = (M3D_FLOAT)(*((int16_t*)(data+6))) / (M3D_FLOAT)32767.0; data += 8; break; case 4: @@ -2778,7 +3128,7 @@ memerr: M3D_LOG("Out of memory"); case 4: model->vertex[i].color = *((uint32_t*)data); data += 4; break; /* case 8: break; */ } - model->vertex[i].skinid = (M3D_INDEX)-1U; + model->vertex[i].skinid = M3D_UNDEF; data = _m3d_getidx(data, model->sk_s, &model->vertex[i].skinid); } } else @@ -2797,15 +3147,6 @@ memerr: M3D_LOG("Out of memory"); } model->numskin = 0; data = _m3d_getidx(data, model->sk_s, &model->numskin); - if(model->numskin) { - model->skin = (m3ds_t*)M3D_MALLOC(model->numskin * sizeof(m3ds_t)); - if(!model->skin) goto memerr; - for(i = 0; i < model->numskin; i++) - for(j = 0; j < M3D_NUMBONE; j++) { - model->skin[i].boneid[j] = (M3D_INDEX)-1U; - model->skin[i].weight[j] = (M3D_FLOAT)0.0; - } - } /* read bone hierarchy */ for(i = 0; i < model->numbone; i++) { data = _m3d_getidx(data, model->bi_s, &model->bone[i].parent); @@ -2816,41 +3157,55 @@ memerr: M3D_LOG("Out of memory"); model->bone[i].weight = NULL; } /* read skin definitions */ - for(i = 0; data < chunk && i < model->numskin; i++) { - memset(&weights, 0, sizeof(weights)); - if(model->nb_s == 1) weights[0] = 255; - else { - memcpy(&weights, data, model->nb_s); - data += model->nb_s; - } - for(j = 0; j < (unsigned int)model->nb_s; j++) { - if(weights[j]) { - if(j >= M3D_NUMBONE) - data += model->bi_s; - else { - model->skin[i].weight[j] = (M3D_FLOAT)(weights[j]) / 255; - data = _m3d_getidx(data, model->bi_s, &model->skin[i].boneid[j]); + if(model->numskin) { + model->skin = (m3ds_t*)M3D_MALLOC(model->numskin * sizeof(m3ds_t)); + if(!model->skin) goto memerr; + for(i = 0; data < chunk && i < model->numskin; i++) { + for(j = 0; j < M3D_NUMBONE; j++) { + model->skin[i].boneid[j] = M3D_UNDEF; + model->skin[i].weight[j] = (M3D_FLOAT)0.0; + } + memset(&weights, 0, sizeof(weights)); + if(model->nb_s == 1) weights[0] = 255; + else { + memcpy(&weights, data, model->nb_s); + data += model->nb_s; + } + for(j = 0, w = (M3D_FLOAT)0.0; j < (unsigned int)model->nb_s; j++) { + if(weights[j]) { + if(j >= M3D_NUMBONE) + data += model->bi_s; + else { + model->skin[i].weight[j] = (M3D_FLOAT)(weights[j]) / (M3D_FLOAT)255.0; + w += model->skin[i].weight[j]; + data = _m3d_getidx(data, model->bi_s, &model->skin[i].boneid[j]); + } } } + /* this can occur if model has more bones than what the importer is configured to handle */ + if(w != (M3D_FLOAT)1.0 && w != (M3D_FLOAT)0.0) { + for(j = 0; j < M3D_NUMBONE; j++) + model->skin[i].weight[j] /= w; + } } } } else /* material */ if(M3D_CHUNKMAGIC(data, 'M','T','R','L')) { data += sizeof(m3dchunk_t); - M3D_GETSTR(material); + M3D_GETSTR(name); M3D_LOG("Material"); - M3D_LOG(material); + M3D_LOG(name); if(model->ci_s < 4 && !model->numcmap) model->errcode = M3D_ERR_CMAP; for(i = 0; i < model->nummaterial; i++) - if(!strcmp(material, model->material[i].name)) { + if(!strcmp(name, model->material[i].name)) { model->errcode = M3D_ERR_MTRL; M3D_LOG("Multiple definitions for material"); - M3D_LOG(material); - material = NULL; + M3D_LOG(name); + name = NULL; break; } - if(material) { + if(name) { i = model->nummaterial++; if(model->flags & M3D_FLG_MTLLIB) { m = model->material; @@ -2870,9 +3225,8 @@ memerr: M3D_LOG("Out of memory"); } m = &model->material[i]; m->numprop = 0; - m->prop = NULL; - m->name = material; - m->prop = (m3dp_t*)M3D_REALLOC(m->prop, (len / 2) * sizeof(m3dp_t)); + m->name = name; + m->prop = (m3dp_t*)M3D_MALLOC((len / 2) * sizeof(m3dp_t)); if(!m->prop) goto memerr; while(data < chunk) { i = m->numprop++; @@ -2899,12 +3253,13 @@ memerr: M3D_LOG("Out of memory"); case m3dpf_float: m->prop[i].value.fnum = *((float*)data); data += 4; break; case m3dpf_map: - M3D_GETSTR(material); - m->prop[i].value.textureid = _m3d_gettx(model, readfilecb, freecb, material); + M3D_GETSTR(name); + m->prop[i].value.textureid = _m3d_gettx(model, readfilecb, freecb, name); if(model->errcode == M3D_ERR_ALLOC) goto memerr; - if(m->prop[i].value.textureid == (M3D_INDEX)-1U) { + /* this error code only returned if readfilecb was specified */ + if(m->prop[i].value.textureid == M3D_UNDEF) { M3D_LOG("Texture not found"); - M3D_LOG(material); + M3D_LOG(m->name); m->numprop--; } break; @@ -2924,16 +3279,16 @@ memerr: M3D_LOG("Out of memory"); /* face */ if(M3D_CHUNKMAGIC(data, 'P','R','O','C')) { /* procedural surface */ - M3D_GETSTR(material); + M3D_GETSTR(name); M3D_LOG("Procedural surface"); - M3D_LOG(material); - _m3d_getpr(model, readfilecb, freecb, material); + M3D_LOG(name); + _m3d_getpr(model, readfilecb, freecb, name); } else if(M3D_CHUNKMAGIC(data, 'M','E','S','H')) { M3D_LOG("Mesh data"); /* mesh */ data += sizeof(m3dchunk_t); - mi = (M3D_INDEX)-1U; + mi = M3D_UNDEF; am = model->numface; while(data < chunk) { k = *data++; @@ -2941,15 +3296,15 @@ memerr: M3D_LOG("Out of memory"); k &= 15; if(!n) { /* use material */ - mi = (M3D_INDEX)-1U; - M3D_GETSTR(material); - if(material) { + mi = M3D_UNDEF; + M3D_GETSTR(name); + if(name) { for(j = 0; j < model->nummaterial; j++) - if(!strcmp(material, model->material[j].name)) { + if(!strcmp(name, model->material[j].name)) { mi = (M3D_INDEX)j; break; } - if(mi == (M3D_INDEX)-1U) model->errcode = M3D_ERR_MTRL; + if(mi == M3D_UNDEF) model->errcode = M3D_ERR_MTRL; } continue; } @@ -2971,10 +3326,124 @@ memerr: M3D_LOG("Out of memory"); /* normal */ if(k & 2) data = _m3d_getidx(data, model->vi_s, &model->face[i].normal[j]); +#ifndef M3D_NONORMALS + if(model->face[i].normal[j] == M3D_UNDEF) neednorm = 1; +#endif } } model->face = (m3df_t*)M3D_REALLOC(model->face, model->numface * sizeof(m3df_t)); } else + if(M3D_CHUNKMAGIC(data, 'S','H','P','E')) { + /* mathematical shape */ + data += sizeof(m3dchunk_t); + M3D_GETSTR(name); + M3D_LOG("Mathematical Shape"); + M3D_LOG(name); + i = model->numshape++; + model->shape = (m3dh_t*)M3D_REALLOC(model->shape, model->numshape * sizeof(m3dh_t)); + if(!model->shape) goto memerr; + h = &model->shape[i]; + h->numcmd = 0; + h->cmd = NULL; + h->name = name; + h->group = M3D_UNDEF; + data = _m3d_getidx(data, model->bi_s, &h->group); + if(h->group != M3D_UNDEF && h->group >= model->numbone) { + M3D_LOG("Unknown bone id as shape group in shape"); + M3D_LOG(name); + h->group = M3D_UNDEF; + model->errcode = M3D_ERR_SHPE; + } + while(data < chunk) { + i = h->numcmd++; + h->cmd = (m3dc_t*)M3D_REALLOC(h->cmd, h->numcmd * sizeof(m3dc_t)); + if(!h->cmd) goto memerr; + h->cmd[i].type = *data++; + if(h->cmd[i].type & 0x80) { + h->cmd[i].type &= 0x7F; + h->cmd[i].type |= (*data++ << 7); + } + if(h->cmd[i].type >= (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0]))) { + M3D_LOG("Unknown shape command in"); + M3D_LOG(h->name); + model->errcode = M3D_ERR_UNKCMD; + break; + } + cd = &m3d_commandtypes[h->cmd[i].type]; + h->cmd[i].arg = (uint32_t*)M3D_MALLOC(cd->p * sizeof(uint32_t)); + if(!h->cmd[i].arg) goto memerr; + memset(h->cmd[i].arg, 0, cd->p * sizeof(uint32_t)); + for(k = n = 0, l = cd->p; k < l; k++) + switch(cd->a[((k - n) % (cd->p - n)) + n]) { + case m3dcp_mi_t: + h->cmd[i].arg[k] = M3D_NOTDEFINED; + M3D_GETSTR(name); + if(name) { + for(n = 0; n < model->nummaterial; n++) + if(!strcmp(name, model->material[n].name)) { + h->cmd[i].arg[k] = n; + break; + } + if(h->cmd[i].arg[k] == M3D_NOTDEFINED) model->errcode = M3D_ERR_MTRL; + } + break; + case m3dcp_vc_t: + f = 0.0f; + switch(model->vc_s) { + case 1: f = (float)((int8_t)data[0]) / 127; break; + case 2: f = (float)(*((int16_t*)(data+0))) / 32767; break; + case 4: f = (float)(*((float*)(data+0))); break; + case 8: f = (float)(*((double*)(data+0))); break; + } + h->cmd[i].arg[k] = *((uint32_t*)&f); + data += model->vc_s; + break; + case m3dcp_hi_t: data = _m3d_getidx(data, model->hi_s, &h->cmd[i].arg[k]); break; + case m3dcp_fi_t: data = _m3d_getidx(data, model->fi_s, &h->cmd[i].arg[k]); break; + case m3dcp_ti_t: data = _m3d_getidx(data, model->ti_s, &h->cmd[i].arg[k]); break; + case m3dcp_qi_t: + case m3dcp_vi_t: data = _m3d_getidx(data, model->vi_s, &h->cmd[i].arg[k]); break; + case m3dcp_i1_t: data = _m3d_getidx(data, 1, &h->cmd[i].arg[k]); break; + case m3dcp_i2_t: data = _m3d_getidx(data, 2, &h->cmd[i].arg[k]); break; + case m3dcp_i4_t: data = _m3d_getidx(data, 4, &h->cmd[i].arg[k]); break; + case m3dcp_va_t: data = _m3d_getidx(data, 4, &h->cmd[i].arg[k]); + n = k + 1; l += (h->cmd[i].arg[k] - 1) * (cd->p - k - 1); + h->cmd[i].arg = (uint32_t*)M3D_REALLOC(h->cmd[i].arg, l * sizeof(uint32_t)); + if(!h->cmd[i].arg) goto memerr; + memset(&h->cmd[i].arg[k + 1], 0, (l - k - 1) * sizeof(uint32_t)); + break; + } + } + } else + /* annotation label list */ + if(M3D_CHUNKMAGIC(data, 'L','B','L','S')) { + data += sizeof(m3dchunk_t); + M3D_GETSTR(name); + M3D_GETSTR(lang); + M3D_LOG("Label list"); + if(name) { M3D_LOG(name); } + if(lang) { M3D_LOG(lang); } + if(model->ci_s && model->ci_s < 4 && !model->cmap) model->errcode = M3D_ERR_CMAP; + k = 0; + switch(model->ci_s) { + case 1: k = model->cmap ? model->cmap[data[0]] : 0; data++; break; + case 2: k = model->cmap ? model->cmap[*((uint16_t*)data)] : 0; data += 2; break; + case 4: k = *((uint32_t*)data); data += 4; break; + /* case 8: break; */ + } + reclen = model->vi_s + model->si_s; + i = model->numlabel; model->numlabel += len / reclen; + model->label = (m3dl_t*)M3D_REALLOC(model->label, model->numlabel * sizeof(m3dl_t)); + if(!model->label) goto memerr; + memset(&model->label[i], 0, (model->numlabel - i) * sizeof(m3dl_t)); + for(; data < chunk && i < model->numlabel; i++) { + model->label[i].name = name; + model->label[i].lang = lang; + model->label[i].color = k; + data = _m3d_getidx(data, model->vi_s, &model->label[i].vertexid); + M3D_GETSTR(model->label[i].text); + } + } else /* action */ if(M3D_CHUNKMAGIC(data, 'A','C','T','N')) { M3D_LOG("Action"); @@ -2995,7 +3464,7 @@ memerr: M3D_LOG("Out of memory"); for(i = 0; data < chunk && i < a->numframe; i++) { a->frame[i].msec = *((uint32_t*)data); data += 4; a->frame[i].numtransform = 0; a->frame[i].transform = NULL; - data = _m3d_getidx(data, model->fi_s, &a->frame[i].numtransform); + data = _m3d_getidx(data, model->fc_s, &a->frame[i].numtransform); if(a->frame[i].numtransform > 0) { a->frame[i].transform = (m3dtr_t*)M3D_MALLOC(a->frame[i].numtransform * sizeof(m3dtr_t)); for(j = 0; j < a->frame[i].numtransform; j++) { @@ -3007,10 +3476,10 @@ memerr: M3D_LOG("Out of memory"); } } } else { - i = model->numunknown++; - model->unknown = (m3dchunk_t**)M3D_REALLOC(model->unknown, model->numunknown * sizeof(m3dchunk_t*)); - if(!model->unknown) goto memerr; - model->unknown[i] = (m3dchunk_t*)data; + i = model->numextra++; + model->extra = (m3dchunk_t**)M3D_REALLOC(model->extra, model->numextra * sizeof(m3dchunk_t*)); + if(!model->extra) goto memerr; + model->extra[i] = (m3dchunk_t*)data; } } /* calculate normals, normalize skin weights, create bone/vertex cross-references and calculate transform matrices */ @@ -3018,64 +3487,69 @@ memerr: M3D_LOG("Out of memory"); postprocess: #endif if(model) { + M3D_LOG("Post-process"); +#ifdef M3D_PROFILING + gettimeofday(&tv1, NULL); + tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; + tvd.tv_usec = tv1.tv_usec - tv0.tv_usec; + if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } + printf(" Parsing chunks %ld.%06ld sec\n", tvd.tv_sec, tvd.tv_usec); +#endif #ifndef M3D_NONORMALS - if(model->numface && model->face) { - memset(&vn, 0, sizeof(m3dv_t)); + if(model->numface && model->face && neednorm) { /* if they are missing, calculate triangle normals into a temporary buffer */ - for(i = numnorm = 0; i < model->numface; i++) - if(model->face[i].normal[0] == -1U) { - v0 = &model->vertex[model->face[i].vertex[0]]; v1 = &model->vertex[model->face[i].vertex[1]]; + norm = (m3dv_t*)M3D_MALLOC(model->numface * sizeof(m3dv_t)); + if(!norm) goto memerr; + for(i = 0, n = model->numvertex; i < model->numface; i++) + if(model->face[i].normal[0] == M3D_UNDEF) { + v0 = &model->vertex[model->face[i].vertex[0]]; + v1 = &model->vertex[model->face[i].vertex[1]]; v2 = &model->vertex[model->face[i].vertex[2]]; va.x = v1->x - v0->x; va.y = v1->y - v0->y; va.z = v1->z - v0->z; vb.x = v2->x - v0->x; vb.y = v2->y - v0->y; vb.z = v2->z - v0->z; - vn.x = (va.y * vb.z) - (va.z * vb.y); - vn.y = (va.z * vb.x) - (va.x * vb.z); - vn.z = (va.x * vb.y) - (va.y * vb.x); - w = _m3d_rsq((vn.x * vn.x) + (vn.y * vn.y) + (vn.z * vn.z)); - vn.x *= w; vn.y *= w; vn.z *= w; - norm = _m3d_addnorm(norm, &numnorm, &vn, &j); - if(!ni) { - ni = (M3D_INDEX*)M3D_MALLOC(model->numface * sizeof(M3D_INDEX)); - if(!ni) goto memerr; - } - ni[i] = j; + v0 = &norm[i]; + v0->x = (va.y * vb.z) - (va.z * vb.y); + v0->y = (va.z * vb.x) - (va.x * vb.z); + v0->z = (va.x * vb.y) - (va.y * vb.x); + w = _m3d_rsq((v0->x * v0->x) + (v0->y * v0->y) + (v0->z * v0->z)); + v0->x *= w; v0->y *= w; v0->z *= w; + model->face[i].normal[0] = model->face[i].vertex[0] + n; + model->face[i].normal[1] = model->face[i].vertex[1] + n; + model->face[i].normal[2] = model->face[i].vertex[2] + n; } - if(ni && norm) { - vi = (M3D_INDEX*)M3D_MALLOC(model->numvertex * sizeof(M3D_INDEX)); - if(!vi) goto memerr; - /* for each vertex, take the average of the temporary normals and use that */ - for(i = 0, n = model->numvertex; i < n; i++) { - memset(&vn, 0, sizeof(m3dv_t)); - for(j = 0; j < model->numface; j++) - for(k = 0; k < 3; k++) - if(model->face[j].vertex[k] == i) { - vn.x += norm[ni[j]].x; - vn.y += norm[ni[j]].y; - vn.z += norm[ni[j]].z; - } - w = _m3d_rsq((vn.x * vn.x) + (vn.y * vn.y) + (vn.z * vn.z)); - vn.x *= w; vn.y *= w; vn.z *= w; - vn.skinid = -1U; - model->vertex = _m3d_addnorm(model->vertex, &model->numvertex, &vn, &vi[i]); + /* this is the fast way, we don't care if a normal is repeated in model->vertex */ + M3D_LOG("Generating normals"); + model->flags |= M3D_FLG_GENNORM; + model->numvertex <<= 1; + model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, model->numvertex * sizeof(m3dv_t)); + if(!model->vertex) goto memerr; + memset(&model->vertex[n], 0, n * sizeof(m3dv_t)); + for(i = 0; i < model->numface; i++) + for(j = 0; j < 3; j++) { + v0 = &model->vertex[model->face[i].vertex[j] + n]; + v0->x += norm[i].x; + v0->y += norm[i].y; + v0->z += norm[i].z; } - for(j = 0; j < model->numface; j++) - for(k = 0; k < 3; k++) - model->face[j].normal[k] = vi[model->face[j].vertex[k]]; - M3D_FREE(norm); - M3D_FREE(ni); - M3D_FREE(vi); + /* for each vertex, take the average of the temporary normals and use that */ + for(i = 0, v0 = &model->vertex[n]; i < n; i++, v0++) { + w = _m3d_rsq((v0->x * v0->x) + (v0->y * v0->y) + (v0->z * v0->z)); + v0->x *= w; v0->y *= w; v0->z *= w; + v0->skinid = M3D_UNDEF; } + M3D_FREE(norm); } #endif if(model->numbone && model->bone && model->numskin && model->skin && model->numvertex && model->vertex) { #ifndef M3D_NOWEIGHTS + M3D_LOG("Generating weight cross-reference"); for(i = 0; i < model->numvertex; i++) { - if(model->vertex[i].skinid < M3D_INDEXMAX) { + if(model->vertex[i].skinid < model->numskin) { sk = &model->skin[model->vertex[i].skinid]; w = (M3D_FLOAT)0.0; - for(j = 0; j < M3D_NUMBONE && sk->boneid[j] != (M3D_INDEX)-1U && sk->weight[j] > (M3D_FLOAT)0.0; j++) + for(j = 0; j < M3D_NUMBONE && sk->boneid[j] != M3D_UNDEF && sk->weight[j] > (M3D_FLOAT)0.0; j++) w += sk->weight[j]; - for(j = 0; j < M3D_NUMBONE && sk->boneid[j] != (M3D_INDEX)-1U && sk->weight[j] > (M3D_FLOAT)0.0; j++) { + for(j = 0; j < M3D_NUMBONE && sk->boneid[j] != M3D_UNDEF && sk->weight[j] > (M3D_FLOAT)0.0; j++) { sk->weight[j] /= w; b = &model->bone[sk->boneid[j]]; k = b->numweight++; @@ -3088,9 +3562,10 @@ postprocess: } #endif #ifndef M3D_NOANIMATION + M3D_LOG("Calculating bone transformation matrices"); for(i = 0; i < model->numbone; i++) { b = &model->bone[i]; - if(model->bone[i].parent == (M3D_INDEX)-1U) { + if(model->bone[i].parent == M3D_UNDEF) { _m3d_mat((M3D_FLOAT*)&b->mat4, &model->vertex[b->pos], &model->vertex[b->ori]); } else { _m3d_mat((M3D_FLOAT*)&r, &model->vertex[b->pos], &model->vertex[b->ori]); @@ -3101,6 +3576,13 @@ postprocess: _m3d_inv((M3D_FLOAT*)&model->bone[i].mat4); #endif } +#ifdef M3D_PROFILING + gettimeofday(&tv0, NULL); + tvd.tv_sec = tv0.tv_sec - tv1.tv_sec; + tvd.tv_usec = tv0.tv_usec - tv1.tv_usec; + if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } + printf(" Post-process %ld.%06ld sec\n", tvd.tv_sec, tvd.tv_usec); +#endif } return model; } @@ -3114,7 +3596,7 @@ m3dtr_t *m3d_frame(m3d_t *model, M3D_INDEX actionid, M3D_INDEX frameid, m3dtr_t M3D_INDEX s = frameid; m3dfr_t *fr; - if(!model || !model->numbone || !model->bone || (actionid != (M3D_INDEX)-1U && (!model->action || + if(!model || !model->numbone || !model->bone || (actionid != M3D_UNDEF && (!model->action || actionid >= model->numaction || frameid >= model->action[actionid].numframe))) { model->errcode = M3D_ERR_UNKFRAME; return skeleton; @@ -3128,7 +3610,7 @@ m3dtr_t *m3d_frame(m3d_t *model, M3D_INDEX actionid, M3D_INDEX frameid, m3dtr_t } goto gen; } - if(actionid == (M3D_INDEX)-1U || !frameid) { + if(actionid == M3D_UNDEF || !frameid) { gen: s = 0; for(i = 0; i < model->numbone; i++) { skeleton[i].boneid = i; @@ -3155,7 +3637,7 @@ gen: s = 0; m3db_t *m3d_pose(m3d_t *model, M3D_INDEX actionid, uint32_t msec) { unsigned int i, j, l; - M3D_FLOAT r[16], t, d; + M3D_FLOAT r[16], t, c, d, s; m3db_t *ret; m3dv_t *v, *p, *f; m3dtr_t *tmp; @@ -3208,7 +3690,7 @@ m3db_t *m3d_pose(m3d_t *model, M3D_INDEX actionid, uint32_t msec) tmp[fr->transform[i].boneid].ori = fr->transform[i].ori; } for(i = 0, j = model->numvertex; i < model->numbone; i++) { - /* LERP interpolation of position */ + /* interpolation of position */ if(ret[i].pos != tmp[i].pos) { p = &model->vertex[ret[i].pos]; f = &model->vertex[tmp[i].pos]; @@ -3218,18 +3700,33 @@ m3db_t *m3d_pose(m3d_t *model, M3D_INDEX actionid, uint32_t msec) v->z = p->z + t * (f->z - p->z); ret[i].pos = j++; } - /* NLERP interpolation of orientation (could have used SLERP, that's nicer, but slower) */ + /* interpolation of orientation */ if(ret[i].ori != tmp[i].ori) { p = &model->vertex[ret[i].ori]; f = &model->vertex[tmp[i].ori]; v = &model->vertex[j]; - d = (p->w * f->w + p->x * f->x + p->y * f->y + p->z * f->z < 0) ? (M3D_FLOAT)-1.0 : (M3D_FLOAT)1.0; - v->x = p->x + t * (d*f->x - p->x); - v->y = p->y + t * (d*f->y - p->y); - v->z = p->z + t * (d*f->z - p->z); - v->w = p->w + t * (d*f->w - p->w); + d = p->w * f->w + p->x * f->x + p->y * f->y + p->z * f->z; + if(d < 0) { d = -d; s = (M3D_FLOAT)-1.0; } else s = (M3D_FLOAT)1.0; +#if 0 + /* don't use SLERP, requires two more variables, libm linkage and it is slow (but nice) */ + a = (M3D_FLOAT)1.0 - t; b = t; + if(d < (M3D_FLOAT)0.999999) { c = acosf(d); b = 1 / sinf(c); a = sinf(a * c) * b; b *= sinf(t * c) * s; } + v->x = p->x * a + f->x * b; + v->y = p->y * a + f->y * b; + v->z = p->z * a + f->z * b; + v->w = p->w * a + f->w * b; +#else + /* approximated NLERP, original approximation by Arseny Kapoulkine, heavily optimized by me */ + c = t - (M3D_FLOAT)0.5; t += t * c * (t - (M3D_FLOAT)1.0) * (((M3D_FLOAT)1.0904 + d * ((M3D_FLOAT)-3.2452 + + d * ((M3D_FLOAT)3.55645 - d * (M3D_FLOAT)1.43519))) * c * c + ((M3D_FLOAT)0.848013 + d * + ((M3D_FLOAT)-1.06021 + d * (M3D_FLOAT)0.215638))); + v->x = p->x + t * (s * f->x - p->x); + v->y = p->y + t * (s * f->y - p->y); + v->z = p->z + t * (s * f->z - p->z); + v->w = p->w + t * (s * f->w - p->w); d = _m3d_rsq(v->w * v->w + v->x * v->x + v->y * v->y + v->z * v->z); v->x *= d; v->y *= d; v->z *= d; v->w *= d; +#endif ret[i].ori = j++; } } @@ -3237,7 +3734,7 @@ m3db_t *m3d_pose(m3d_t *model, M3D_INDEX actionid, uint32_t msec) } } for(i = 0; i < model->numbone; i++) { - if(ret[i].parent == (M3D_INDEX)-1U) { + if(ret[i].parent == M3D_UNDEF) { _m3d_mat((M3D_FLOAT*)&ret[i].mat4, &model->vertex[ret[i].pos], &model->vertex[ret[i].ori]); } else { _m3d_mat((M3D_FLOAT*)&r, &model->vertex[ret[i].pos], &model->vertex[ret[i].ori]); @@ -3271,6 +3768,10 @@ void m3d_free(m3d_t *model) for(i = 0; i < model->numbone; i++) if(model->bone[i].name) M3D_FREE(model->bone[i].name); + if(model->shape) + for(i = 0; i < model->numshape; i++) + if(model->shape[i].name) + M3D_FREE(model->shape[i].name); if(model->material) for(i = 0; i < model->nummaterial; i++) if(model->material[i].name) @@ -3283,10 +3784,36 @@ void m3d_free(m3d_t *model) for(i = 0; i < model->numtexture; i++) if(model->texture[i].name) M3D_FREE(model->texture[i].name); - if(model->unknown) - for(i = 0; i < model->numunknown; i++) - if(model->unknown[i]) - M3D_FREE(model->unknown[i]); + if(model->inlined) + for(i = 0; i < model->numinlined; i++) { + if(model->inlined[i].name) + M3D_FREE(model->inlined[i].name); + if(model->inlined[i].data) + M3D_FREE(model->inlined[i].data); + } + if(model->extra) + for(i = 0; i < model->numextra; i++) + if(model->extra[i]) + M3D_FREE(model->extra[i]); + if(model->label) + for(i = 0; i < model->numlabel; i++) { + if(model->label[i].name) { + for(j = i + 1; j < model->numlabel; j++) + if(model->label[j].name == model->label[i].name) + model->label[j].name = NULL; + M3D_FREE(model->label[i].name); + } + if(model->label[i].lang) { + for(j = i + 1; j < model->numlabel; j++) + if(model->label[j].lang == model->label[i].lang) + model->label[j].lang = NULL; + M3D_FREE(model->label[i].lang); + } + if(model->label[i].text) + M3D_FREE(model->label[i].text); + } + if(model->preview.data) + M3D_FREE(model->preview.data); } #endif if(model->flags & M3D_FLG_FREERAW) M3D_FREE(model->raw); @@ -3301,6 +3828,16 @@ void m3d_free(m3d_t *model) if(model->skin) M3D_FREE(model->skin); if(model->vertex) M3D_FREE(model->vertex); if(model->face) M3D_FREE(model->face); + if(model->shape) { + for(i = 0; i < model->numshape; i++) { + if(model->shape[i].cmd) { + for(j = 0; j < model->shape[i].numcmd; j++) + if(model->shape[i].cmd[j].arg) M3D_FREE(model->shape[i].cmd[j].arg); + M3D_FREE(model->shape[i].cmd); + } + } + M3D_FREE(model->shape); + } if(model->material && !(model->flags & M3D_FLG_MTLLIB)) { for(i = 0; i < model->nummaterial; i++) if(model->material[i].prop) M3D_FREE(model->material[i].prop); @@ -3321,8 +3858,9 @@ void m3d_free(m3d_t *model) } M3D_FREE(model->action); } + if(model->label) M3D_FREE(model->label); if(model->inlined) M3D_FREE(model->inlined); - if(model->unknown) M3D_FREE(model->unknown); + if(model->extra) M3D_FREE(model->extra); free(model); } #endif @@ -3333,6 +3871,31 @@ typedef struct { uint32_t offs; } m3dstr_t; +typedef struct { + m3dti_t data; + M3D_INDEX oldidx; + M3D_INDEX newidx; +} m3dtisave_t; + +typedef struct { + m3dv_t data; + M3D_INDEX oldidx; + M3D_INDEX newidx; + unsigned char norm; +} m3dvsave_t; + +typedef struct { + m3ds_t data; + M3D_INDEX oldidx; + M3D_INDEX newidx; +} m3dssave_t; + +typedef struct { + m3df_t data; + int group; + uint8_t opacity; +} m3dfsave_t; + /* create unique list of strings */ static m3dstr_t *_m3d_addstr(m3dstr_t *str, uint32_t *numstr, char *s) { @@ -3354,7 +3917,7 @@ m3dhdr_t *_m3d_addhdr(m3dhdr_t *h, m3dstr_t *s) { int i; char *safe = _m3d_safestr(s->str, 0); - i = strlen(safe); + i = (int)strlen(safe); h = (m3dhdr_t*)M3D_REALLOC(h, h->length + i+1); if(!h) { M3D_FREE(safe); return NULL; } memcpy((uint8_t*)h + h->length, safe, i+1); @@ -3387,6 +3950,41 @@ static uint32_t _m3d_stridx(m3dstr_t *str, uint32_t numstr, char *s) return 0; } +/* compare to faces by their material */ +static int _m3d_facecmp(const void *a, const void *b) { + const m3dfsave_t *A = (const m3dfsave_t*)a, *B = (const m3dfsave_t*)b; + return A->group != B->group ? A->group - B->group : (A->opacity != B->opacity ? (int)B->opacity - (int)A->opacity : + (int)A->data.materialid - (int)B->data.materialid); +} +/* compare face groups */ +static int _m3d_grpcmp(const void *a, const void *b) { return *((uint32_t*)a) - *((uint32_t*)b); } +/* compare UVs */ +static int _m3d_ticmp(const void *a, const void *b) { return memcmp(a, b, sizeof(m3dti_t)); } +/* compare skin groups */ +static int _m3d_skincmp(const void *a, const void *b) { return memcmp(a, b, sizeof(m3ds_t)); } +/* compare vertices */ +static int _m3d_vrtxcmp(const void *a, const void *b) { + int c = memcmp(a, b, 3 * sizeof(M3D_FLOAT)); + if(c) return c; + c = ((m3dvsave_t*)a)->norm - ((m3dvsave_t*)b)->norm; + if(c) return c; + return memcmp(a, b, sizeof(m3dv_t)); +} +/* compare labels */ +static _inline int _m3d_strcmp(char *a, char *b) +{ + if(a == NULL && b != NULL) return -1; + if(a != NULL && b == NULL) return 1; + if(a == NULL && b == NULL) return 0; + return strcmp(a, b); +} +static int _m3d_lblcmp(const void *a, const void *b) { + const m3dl_t *A = (const m3dl_t*)a, *B = (const m3dl_t*)b; + int c = _m3d_strcmp(A->lang, B->lang); + if(!c) c = _m3d_strcmp(A->name, B->name); + if(!c) c = _m3d_strcmp(A->text, B->text); + return c; +} /* compare two colors by HSV value */ _inline static int _m3d_cmapcmp(const void *a, const void *b) { @@ -3421,60 +4019,13 @@ static uint32_t *_m3d_addcmap(uint32_t *cmap, uint32_t *numcmap, uint32_t color) static uint32_t _m3d_cmapidx(uint32_t *cmap, uint32_t numcmap, uint32_t color) { uint32_t i; + if(numcmap >= 65536) + return color; for(i = 0; i < numcmap; i++) if(cmap[i] == color) return i; return 0; } -/* add vertex to list */ -static m3dv_t *_m3d_addvrtx(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx) -{ - uint32_t i; - if(v->x == (M3D_FLOAT)-0.0) v->x = (M3D_FLOAT)0.0; - if(v->y == (M3D_FLOAT)-0.0) v->y = (M3D_FLOAT)0.0; - if(v->z == (M3D_FLOAT)-0.0) v->z = (M3D_FLOAT)0.0; - if(v->w == (M3D_FLOAT)-0.0) v->w = (M3D_FLOAT)0.0; - if(vrtx) { - for(i = 0; i < *numvrtx; i++) - if(!memcmp(&vrtx[i], v, sizeof(m3dv_t))) { *idx = i; return vrtx; } - } - vrtx = (m3dv_t*)M3D_REALLOC(vrtx, ((*numvrtx) + 1) * sizeof(m3dv_t)); - memcpy(&vrtx[*numvrtx], v, sizeof(m3dv_t)); - *idx = *numvrtx; - (*numvrtx)++; - return vrtx; -} - -/* add texture map to list */ -static m3dti_t *_m3d_addtmap(m3dti_t *tmap, uint32_t *numtmap, m3dti_t *t, uint32_t *idx) -{ - uint32_t i; - if(tmap) { - for(i = 0; i < *numtmap; i++) - if(!memcmp(&tmap[i], t, sizeof(m3dti_t))) { *idx = i; return tmap; } - } - tmap = (m3dti_t*)M3D_REALLOC(tmap, ((*numtmap) + 1) * sizeof(m3dti_t)); - memcpy(&tmap[*numtmap], t, sizeof(m3dti_t)); - *idx = *numtmap; - (*numtmap)++; - return tmap; -} - -/* add material to list */ -static m3dm_t **_m3d_addmtrl(m3dm_t **mtrl, uint32_t *nummtrl, m3dm_t *m, uint32_t *idx) -{ - uint32_t i; - if(mtrl) { - for(i = 0; i < *nummtrl; i++) - if(mtrl[i]->name == m->name || !strcmp(mtrl[i]->name, m->name)) { *idx = i; return mtrl; } - } - mtrl = (m3dm_t**)M3D_REALLOC(mtrl, ((*nummtrl) + 1) * sizeof(m3dm_t*)); - mtrl[*nummtrl] = m; - *idx = *nummtrl; - (*nummtrl)++; - return mtrl; -} - /* add index to output */ static unsigned char *_m3d_addidx(unsigned char *out, char type, uint32_t idx) { switch(type) { @@ -3495,23 +4046,27 @@ static void _m3d_round(int quality, m3dv_t *src, m3dv_t *dst) /* round according to quality */ switch(quality) { case M3D_EXP_INT8: - t = src->x * 127; dst->x = (M3D_FLOAT)t / 127; - t = src->y * 127; dst->y = (M3D_FLOAT)t / 127; - t = src->z * 127; dst->z = (M3D_FLOAT)t / 127; - t = src->w * 127; dst->w = (M3D_FLOAT)t / 127; + t = (int)(src->x * 127 + (src->x >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->x = (M3D_FLOAT)t / (M3D_FLOAT)127.0; + t = (int)(src->y * 127 + (src->y >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->y = (M3D_FLOAT)t / (M3D_FLOAT)127.0; + t = (int)(src->z * 127 + (src->z >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->z = (M3D_FLOAT)t / (M3D_FLOAT)127.0; + t = (int)(src->w * 127 + (src->w >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->w = (M3D_FLOAT)t / (M3D_FLOAT)127.0; break; case M3D_EXP_INT16: - t = src->x * 32767; dst->x = (M3D_FLOAT)t / 32767; - t = src->y * 32767; dst->y = (M3D_FLOAT)t / 32767; - t = src->z * 32767; dst->z = (M3D_FLOAT)t / 32767; - t = src->w * 32767; dst->w = (M3D_FLOAT)t / 32767; + t = (int)(src->x * 32767 + (src->x >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->x = (M3D_FLOAT)t / (M3D_FLOAT)32767.0; + t = (int)(src->y * 32767 + (src->y >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->y = (M3D_FLOAT)t / (M3D_FLOAT)32767.0; + t = (int)(src->z * 32767 + (src->z >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->z = (M3D_FLOAT)t / (M3D_FLOAT)32767.0; + t = (int)(src->w * 32767 + (src->w >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->w = (M3D_FLOAT)t / (M3D_FLOAT)32767.0; break; } + if(dst->x == (M3D_FLOAT)-0.0) dst->x = (M3D_FLOAT)0.0; + if(dst->y == (M3D_FLOAT)-0.0) dst->y = (M3D_FLOAT)0.0; + if(dst->z == (M3D_FLOAT)-0.0) dst->z = (M3D_FLOAT)0.0; + if(dst->w == (M3D_FLOAT)-0.0) dst->w = (M3D_FLOAT)0.0; } #ifdef M3D_ASCII /* add a bone to ascii output */ -static char *_m3d_prtbone(char *ptr, m3db_t *bone, M3D_INDEX numbone, M3D_INDEX parent, uint32_t level) +static char *_m3d_prtbone(char *ptr, m3db_t *bone, M3D_INDEX numbone, M3D_INDEX parent, uint32_t level, M3D_INDEX *vrtxidx) { uint32_t i, j; char *sn; @@ -3521,9 +4076,9 @@ static char *_m3d_prtbone(char *ptr, m3db_t *bone, M3D_INDEX numbone, M3D_INDEX if(bone[i].parent == parent) { for(j = 0; j < level; j++) *ptr++ = '/'; sn = _m3d_safestr(bone[i].name, 0); - ptr += sprintf(ptr, "%d %d %s\r\n", bone[i].pos, bone[i].ori, sn); + ptr += sprintf(ptr, "%d %d %s\r\n", vrtxidx[bone[i].pos], vrtxidx[bone[i].ori], sn); M3D_FREE(sn); - ptr = _m3d_prtbone(ptr, bone, numbone, i, level + 1); + ptr = _m3d_prtbone(ptr, bone, numbone, i, level + 1, vrtxidx); } } return ptr; @@ -3539,23 +4094,25 @@ unsigned char *m3d_save(m3d_t *model, int quality, int flags, unsigned int *size const char *ol; char *ptr; #endif - char vc_s, vi_s, si_s, ci_s, ti_s, bi_s, nb_s, sk_s, fi_s; + char vc_s, vi_s, si_s, ci_s, ti_s, bi_s, nb_s, sk_s, fc_s, hi_s, fi_s; char *sn = NULL, *sl = NULL, *sa = NULL, *sd = NULL; - unsigned char *out = NULL, *z = NULL, weights[M3D_NUMBONE]; - unsigned int i, j, k, l, len, chunklen, *length; - float scale = 0.0f, min_x, max_x, min_y, max_y, min_z, max_z; - uint32_t idx, numcmap = 0, *cmap = NULL, numvrtx = 0, numtmap = 0, numbone = 0; - uint32_t numskin = 0, numactn = 0, *actn = NULL, numstr = 0, nummtrl = 0, maxt = 0; + unsigned char *out = NULL, *z = NULL, weights[M3D_NUMBONE], *norm = NULL; + unsigned int i, j, k, l, n, len, chunklen, *length; + M3D_FLOAT scale = (M3D_FLOAT)0.0, min_x, max_x, min_y, max_y, min_z, max_z; + M3D_INDEX last, *vrtxidx = NULL, *mtrlidx = NULL, *tmapidx = NULL, *skinidx = NULL; + uint32_t idx, numcmap = 0, *cmap = NULL, numvrtx = 0, maxvrtx = 0, numtmap = 0, maxtmap = 0, numproc = 0; + uint32_t numskin = 0, maxskin = 0, numstr = 0, maxt = 0, maxbone = 0, numgrp = 0, maxgrp = 0, *grpidx = NULL; + uint8_t *opa; + m3dcd_t *cd; + m3dc_t *cmd; m3dstr_t *str = NULL; - m3dv_t *vrtx = NULL, vertex; - m3dti_t *tmap = NULL, tcoord; - m3db_t *bone = NULL; - m3ds_t *skin = NULL; - m3df_t *face = NULL; + m3dvsave_t *vrtx = NULL, vertex; + m3dtisave_t *tmap = NULL, tcoord; + m3dssave_t *skin = NULL, sk; + m3dfsave_t *face = NULL; m3dhdr_t *h = NULL; - m3dm_t *m, **mtrl = NULL; + m3dm_t *m; m3da_t *a; - M3D_INDEX last; if(!model) { if(size) *size = 0; @@ -3565,235 +4122,417 @@ unsigned char *m3d_save(m3d_t *model, int quality, int flags, unsigned int *size #ifdef M3D_ASCII if(flags & M3D_EXP_ASCII) quality = M3D_EXP_DOUBLE; #endif - /* collect array elements that are actually referenced */ - if(model->numface && model->face && !(flags & M3D_EXP_NOFACE)) { - face = (m3df_t*)M3D_MALLOC(model->numface * sizeof(m3df_t)); - if(!face) goto memerr; - memset(face, 255, model->numface * sizeof(m3df_t)); - last = (M3D_INDEX)-1U; - for(i = 0; i < model->numface; i++) { - face[i].materialid = (M3D_INDEX)-1U; - if(!(flags & M3D_EXP_NOMATERIAL) && model->face[i].materialid != last) { - last = model->face[i].materialid; - if(last < model->nummaterial) { - mtrl = _m3d_addmtrl(mtrl, &nummtrl, &model->material[last], &face[i].materialid); - if(!mtrl) goto memerr; + vrtxidx = (M3D_INDEX*)M3D_MALLOC(model->numvertex * sizeof(M3D_INDEX)); + if(!vrtxidx) goto memerr; + memset(vrtxidx, 255, model->numvertex * sizeof(M3D_INDEX)); + if(model->numvertex && !(flags & M3D_EXP_NONORMAL)){ + norm = (unsigned char*)M3D_MALLOC(model->numvertex * sizeof(unsigned char)); + if(!norm) goto memerr; + memset(norm, 0, model->numvertex * sizeof(unsigned char)); + } + if(model->nummaterial && !(flags & M3D_EXP_NOMATERIAL)) { + mtrlidx = (M3D_INDEX*)M3D_MALLOC(model->nummaterial * sizeof(M3D_INDEX)); + if(!mtrlidx) goto memerr; + memset(mtrlidx, 255, model->nummaterial * sizeof(M3D_INDEX)); + opa = (uint8_t*)M3D_MALLOC(model->nummaterial * 2 * sizeof(M3D_INDEX)); + if(!opa) goto memerr; + memset(opa, 255, model->nummaterial * 2 * sizeof(M3D_INDEX)); + } + if(model->numtmap && !(flags & M3D_EXP_NOTXTCRD)) { + tmapidx = (M3D_INDEX*)M3D_MALLOC(model->numtmap * sizeof(M3D_INDEX)); + if(!tmapidx) goto memerr; + memset(tmapidx, 255, model->numtmap * sizeof(M3D_INDEX)); + } + /** collect array elements that are actually referenced **/ + if(!(flags & M3D_EXP_NOFACE)) { + /* face */ + if(model->numface && model->face) { + M3D_LOG("Processing mesh face"); + face = (m3dfsave_t*)M3D_MALLOC(model->numface * sizeof(m3dfsave_t)); + if(!face) goto memerr; + for(i = 0; i < model->numface; i++) { + memcpy(&face[i].data, &model->face[i], sizeof(m3df_t)); + face[i].group = 0; + face[i].opacity = 255; + if(!(flags & M3D_EXP_NOMATERIAL) && model->face[i].materialid < model->nummaterial) { + if(model->material[model->face[i].materialid].numprop) { + mtrlidx[model->face[i].materialid] = 0; + if(opa[model->face[i].materialid * 2]) { + m = &model->material[model->face[i].materialid]; + for(j = 0; j < m->numprop; j++) + if(m->prop[j].type == m3dp_Kd) { + opa[model->face[i].materialid * 2 + 1] = ((uint8_t*)&m->prop[j].value.color)[3]; + break; + } + for(j = 0; j < m->numprop; j++) + if(m->prop[j].type == m3dp_d) { + opa[model->face[i].materialid * 2 + 1] = (uint8_t)(m->prop[j].value.fnum * 255); + break; + } + opa[model->face[i].materialid * 2] = 0; + } + face[i].opacity = opa[model->face[i].materialid * 2 + 1]; + } else + face[i].data.materialid = M3D_UNDEF; + } + for(j = 0; j < 3; j++) { + k = model->face[i].vertex[j]; + if(k < model->numvertex) + vrtxidx[k] = 0; + if(!(flags & M3D_EXP_NOCMAP)) { + cmap = _m3d_addcmap(cmap, &numcmap, model->vertex[k].color); + if(!cmap) goto memerr; + } + k = model->face[i].normal[j]; + if(k < model->numvertex && !(flags & M3D_EXP_NONORMAL)) { + vrtxidx[k] = 0; + norm[k] = 1; + } + k = model->face[i].texcoord[j]; + if(k < model->numtmap && !(flags & M3D_EXP_NOTXTCRD)) + tmapidx[k] = 0; + } + /* convert from CW to CCW */ + if(flags & M3D_EXP_IDOSUCK) { + j = face[i].data.vertex[1]; + face[i].data.vertex[1] = face[i].data.vertex[2]; + face[i].data.vertex[2] = face[i].data.vertex[1]; + j = face[i].data.normal[1]; + face[i].data.normal[1] = face[i].data.normal[2]; + face[i].data.normal[2] = face[i].data.normal[1]; + j = face[i].data.texcoord[1]; + face[i].data.texcoord[1] = face[i].data.texcoord[2]; + face[i].data.texcoord[2] = face[i].data.texcoord[1]; } } - for(j = 0; j < 3; j++) { - k = model->face[i].vertex[j]; - if(quality < M3D_EXP_FLOAT) { - _m3d_round(quality, &model->vertex[k], &vertex); - vrtx = _m3d_addvrtx(vrtx, &numvrtx, &vertex, &idx); - } else - vrtx = _m3d_addvrtx(vrtx, &numvrtx, &model->vertex[k], &idx); - if(!vrtx) goto memerr; - face[i].vertex[j] = (M3D_INDEX)idx; + } + if(model->numshape && model->shape) { + M3D_LOG("Processing shape face"); + for(i = 0; i < model->numshape; i++) { + if(!model->shape[i].numcmd) continue; + str = _m3d_addstr(str, &numstr, model->shape[i].name); + if(!str) goto memerr; + for(j = 0; j < model->shape[i].numcmd; j++) { + cmd = &model->shape[i].cmd[j]; + if(cmd->type >= (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0])) || !cmd->arg) + continue; + if(cmd->type == m3dc_mesh) { + if(numgrp + 2 < maxgrp) { + maxgrp += 1024; + grpidx = (uint32_t*)realloc(grpidx, maxgrp * sizeof(uint32_t)); + if(!grpidx) goto memerr; + if(!numgrp) { + grpidx[0] = 0; + grpidx[1] = model->numface; + numgrp += 2; + } + } + grpidx[numgrp + 0] = cmd->arg[0]; + grpidx[numgrp + 1] = cmd->arg[0] + cmd->arg[1]; + numgrp += 2; + } + cd = &m3d_commandtypes[cmd->type]; + for(k = n = 0, l = cd->p; k < l; k++) + switch(cd->a[((k - n) % (cd->p - n)) + n]) { + case m3dcp_mi_t: + if(!(flags & M3D_EXP_NOMATERIAL) && cmd->arg[k] < model->nummaterial) + mtrlidx[cmd->arg[k]] = 0; + break; + case m3dcp_ti_t: + if(!(flags & M3D_EXP_NOTXTCRD) && cmd->arg[k] < model->numtmap) + tmapidx[cmd->arg[k]] = 0; + break; + case m3dcp_qi_t: + case m3dcp_vi_t: + if(cmd->arg[k] < model->numvertex) + vrtxidx[cmd->arg[k]] = 0; + break; + case m3dcp_va_t: + n = k + 1; l += (cmd->arg[k] - 1) * (cd->p - k - 1); + break; + } + } + } + } + if(model->numface && face) { + if(numgrp && grpidx) { + qsort(grpidx, numgrp, sizeof(uint32_t), _m3d_grpcmp); + for(i = j = 0; i < model->numface && j < numgrp; i++) { + while(j < numgrp && grpidx[j] < i) j++; + face[i].group = j; + } + } + qsort(face, model->numface, sizeof(m3dfsave_t), _m3d_facecmp); + } + if(grpidx) { M3D_FREE(grpidx); grpidx = NULL; } + if(model->numlabel && model->label) { + M3D_LOG("Processing annotation labels"); + for(i = 0; i < model->numlabel; i++) { + str = _m3d_addstr(str, &numstr, model->label[i].name); + str = _m3d_addstr(str, &numstr, model->label[i].lang); + str = _m3d_addstr(str, &numstr, model->label[i].text); if(!(flags & M3D_EXP_NOCMAP)) { - cmap = _m3d_addcmap(cmap, &numcmap, model->vertex[k].color); + cmap = _m3d_addcmap(cmap, &numcmap, model->label[i].color); if(!cmap) goto memerr; } - k = model->face[i].normal[j]; - if(k < model->numvertex && !(flags & M3D_EXP_NONORMAL)) { - if(quality < M3D_EXP_FLOAT) { - _m3d_round(quality, &model->vertex[k], &vertex); - vrtx = _m3d_addnorm(vrtx, &numvrtx, &vertex, &idx); - } else - vrtx = _m3d_addnorm(vrtx, &numvrtx, &model->vertex[k], &idx); - if(!vrtx) goto memerr; - face[i].normal[j] = (M3D_INDEX)idx; - } - k = model->face[i].texcoord[j]; - if(k < model->numtmap) { - switch(quality) { - case M3D_EXP_INT8: - l = model->tmap[k].u * 255; tcoord.u = (M3D_FLOAT)l / 255; - l = model->tmap[k].v * 255; tcoord.v = (M3D_FLOAT)l / 255; - break; - case M3D_EXP_INT16: - l = model->tmap[k].u * 65535; tcoord.u = (M3D_FLOAT)l / 65535; - l = model->tmap[k].v * 65535; tcoord.v = (M3D_FLOAT)l / 65535; - break; - default: - tcoord.u = model->tmap[k].u; - tcoord.v = model->tmap[k].v; - break; - } - if(flags & M3D_EXP_FLIPTXTCRD) - tcoord.v = (M3D_FLOAT)1.0 - tcoord.v; - tmap = _m3d_addtmap(tmap, &numtmap, &tcoord, &idx); - if(!tmap) goto memerr; - face[i].texcoord[j] = (M3D_INDEX)idx; - } - } - /* convert from CW to CCW */ - if(flags & M3D_EXP_IDOSUCK) { - j = face[i].vertex[1]; - face[i].vertex[1] = face[i].vertex[2]; - face[i].vertex[2] = face[i].vertex[1]; - j = face[i].normal[1]; - face[i].normal[1] = face[i].normal[2]; - face[i].normal[2] = face[i].normal[1]; - j = face[i].texcoord[1]; - face[i].texcoord[1] = face[i].texcoord[2]; - face[i].texcoord[2] = face[i].texcoord[1]; + if(model->label[i].vertexid < model->numvertex) + vrtxidx[model->label[i].vertexid] = 0; } + qsort(model->label, model->numlabel, sizeof(m3dl_t), _m3d_lblcmp); } } else if(!(flags & M3D_EXP_NOMATERIAL)) { /* without a face, simply add all materials, because it can be an mtllib */ - nummtrl = model->nummaterial; + for(i = 0; i < model->nummaterial; i++) + mtrlidx[i] = i; } - /* add colors to color map and texture names to string table */ - for(i = 0; i < nummtrl; i++) { - m = !mtrl ? &model->material[i] : mtrl[i]; - str = _m3d_addstr(str, &numstr, m->name); - if(!str) goto memerr; - for(j = 0; j < mtrl[i]->numprop; j++) { - if(!(flags & M3D_EXP_NOCMAP) && m->prop[j].type < 128) { - for(l = 0; l < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); l++) { - if(m->prop[j].type == m3d_propertytypes[l].id && m3d_propertytypes[l].format == m3dpf_color) { - cmap = _m3d_addcmap(cmap, &numcmap, m->prop[j].value.color); - if(!cmap) goto memerr; - break; - } - } - } - if(m->prop[j].type >= 128 && m->prop[j].value.textureid < model->numtexture && - model->texture[m->prop[j].value.textureid].name) { - str = _m3d_addstr(str, &numstr, model->texture[m->prop[j].value.textureid].name); - if(!str) goto memerr; - } - } - } - /* get bind-pose skeleton and skin */ + /* bind-pose skeleton */ if(model->numbone && model->bone && !(flags & M3D_EXP_NOBONE)) { - numbone = model->numbone; - bone = (m3db_t*)M3D_MALLOC(model->numbone * sizeof(m3db_t)); - if(!bone) goto memerr; - memset(bone, 0, model->numbone * sizeof(m3db_t)); + M3D_LOG("Processing bones"); for(i = 0; i < model->numbone; i++) { - bone[i].parent = model->bone[i].parent; - bone[i].name = model->bone[i].name; - str = _m3d_addstr(str, &numstr, bone[i].name); + str = _m3d_addstr(str, &numstr, model->bone[i].name); if(!str) goto memerr; - if(quality < M3D_EXP_FLOAT) { - _m3d_round(quality, &model->vertex[model->bone[i].pos], &vertex); - vrtx = _m3d_addvrtx(vrtx, &numvrtx, &vertex, &k); - } else - vrtx = _m3d_addvrtx(vrtx, &numvrtx, &model->vertex[model->bone[i].pos], &k); - if(!vrtx) goto memerr; - bone[i].pos = (M3D_INDEX)k; - if(quality < M3D_EXP_FLOAT) { - _m3d_round(quality, &model->vertex[model->bone[i].ori], &vertex); - vrtx = _m3d_addvrtx(vrtx, &numvrtx, &vertex, &k); - } else - vrtx = _m3d_addvrtx(vrtx, &numvrtx, &model->vertex[model->bone[i].ori], &k); - if(!vrtx) goto memerr; - bone[i].ori = (M3D_INDEX)k; + k = model->bone[i].pos; + if(k < model->numvertex) + vrtxidx[k] = 0; + k = model->bone[i].ori; + if(k < model->numvertex) + vrtxidx[k] = 0; } } /* actions, animated skeleton poses */ if(model->numaction && model->action && !(flags & M3D_EXP_NOACTION)) { + M3D_LOG("Processing action list"); for(j = 0; j < model->numaction; j++) { a = &model->action[j]; str = _m3d_addstr(str, &numstr, a->name); if(!str) goto memerr; if(a->numframe > 65535) a->numframe = 65535; for(i = 0; i < a->numframe; i++) { - l = numactn; - numactn += (a->frame[i].numtransform * 2); - if(a->frame[i].numtransform > maxt) - maxt = a->frame[i].numtransform; - actn = (uint32_t*)M3D_REALLOC(actn, numactn * sizeof(uint32_t)); - if(!actn) goto memerr; - for(k = 0; k < a->frame[i].numtransform; k++) { - if(quality < M3D_EXP_FLOAT) { - _m3d_round(quality, &model->vertex[a->frame[i].transform[k].pos], &vertex); - vrtx = _m3d_addvrtx(vrtx, &numvrtx, &vertex, &actn[l++]); - if(!vrtx) goto memerr; - _m3d_round(quality, &model->vertex[a->frame[i].transform[k].ori], &vertex); - vrtx = _m3d_addvrtx(vrtx, &numvrtx, &vertex, &actn[l++]); - } else { - vrtx = _m3d_addvrtx(vrtx, &numvrtx, &model->vertex[a->frame[i].transform[k].pos], &actn[l++]); - if(!vrtx) goto memerr; - vrtx = _m3d_addvrtx(vrtx, &numvrtx, &model->vertex[a->frame[i].transform[k].ori], &actn[l++]); - } - if(!vrtx) goto memerr; + for(l = 0; l < a->frame[i].numtransform; l++) { + k = a->frame[i].transform[l].pos; + if(k < model->numvertex) + vrtxidx[k] = 0; + k = a->frame[i].transform[l].ori; + if(k < model->numvertex) + vrtxidx[k] = 0; } + if(l > maxt) maxt = l; } } } - /* normalize bounding cube and collect referenced skin records */ - if(numvrtx) { - min_x = min_y = min_z = 1e10; - max_x = max_y = max_z = -1e10; - j = model->numskin && model->skin && !(flags & M3D_EXP_NOBONE); - for(i = 0; i < numvrtx; i++) { - if(j && model->numskin && model->skin && vrtx[i].skinid < M3D_INDEXMAX) { - skin = _m3d_addskin(skin, &numskin, &model->skin[vrtx[i].skinid], &idx); - if(!skin) goto memerr; - vrtx[i].skinid = idx; - } - if(vrtx[i].skinid == (M3D_INDEX)-2U) continue; - if(vrtx[i].x > max_x) max_x = vrtx[i].x; - if(vrtx[i].x < min_x) min_x = vrtx[i].x; - if(vrtx[i].y > max_y) max_y = vrtx[i].y; - if(vrtx[i].y < min_y) min_y = vrtx[i].y; - if(vrtx[i].z > max_z) max_z = vrtx[i].z; - if(vrtx[i].z < min_z) min_z = vrtx[i].z; + /* add colors to color map and texture names to string table */ + if(!(flags & M3D_EXP_NOMATERIAL)) { + M3D_LOG("Processing materials"); + for(i = k = 0; i < model->nummaterial; i++) { + if(mtrlidx[i] == M3D_UNDEF || !model->material[i].numprop) continue; + mtrlidx[i] = k++; + m = &model->material[i]; + str = _m3d_addstr(str, &numstr, m->name); + if(!str) goto memerr; + if(m->prop) + for(j = 0; j < m->numprop; j++) { + if(!(flags & M3D_EXP_NOCMAP) && m->prop[j].type < 128) { + for(l = 0; l < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); l++) { + if(m->prop[j].type == m3d_propertytypes[l].id && m3d_propertytypes[l].format == m3dpf_color) { + ((uint8_t*)&m->prop[j].value.color)[3] = opa[i * 2 + 1]; + cmap = _m3d_addcmap(cmap, &numcmap, m->prop[j].value.color); + if(!cmap) goto memerr; + break; + } + } + } + if(m->prop[j].type >= 128 && m->prop[j].value.textureid < model->numtexture && + model->texture[m->prop[j].value.textureid].name) { + str = _m3d_addstr(str, &numstr, model->texture[m->prop[j].value.textureid].name); + if(!str) goto memerr; + } + } } - if(min_x < 0.0f) min_x = -min_x; - if(max_x < 0.0f) max_x = -max_x; - if(min_y < 0.0f) min_y = -min_y; - if(max_y < 0.0f) max_y = -max_y; - if(min_z < 0.0f) min_z = -min_z; - if(max_z < 0.0f) max_z = -max_z; + } + /* if there's only one black color, don't store it */ + if(numcmap == 1 && cmap && !cmap[0]) numcmap = 0; + + /** compress lists **/ + if(model->numtmap && !(flags & M3D_EXP_NOTXTCRD)) { + M3D_LOG("Compressing tmap"); + tmap = (m3dtisave_t*)M3D_MALLOC(model->numtmap * sizeof(m3dtisave_t)); + if(!tmap) goto memerr; + for(i = 0; i < model->numtmap; i++) { + if(tmapidx[i] == M3D_UNDEF) continue; + switch(quality) { + case M3D_EXP_INT8: + l = (unsigned int)(model->tmap[i].u * 255); tcoord.data.u = (M3D_FLOAT)l / (M3D_FLOAT)255.0; + l = (unsigned int)(model->tmap[i].v * 255); tcoord.data.v = (M3D_FLOAT)l / (M3D_FLOAT)255.0; + break; + case M3D_EXP_INT16: + l = (unsigned int)(model->tmap[i].u * 65535); tcoord.data.u = (M3D_FLOAT)l / (M3D_FLOAT)65535.0; + l = (unsigned int)(model->tmap[i].v * 65535); tcoord.data.v = (M3D_FLOAT)l / (M3D_FLOAT)65535.0; + break; + default: + tcoord.data.u = model->tmap[i].u; + tcoord.data.v = model->tmap[i].v; + break; + } + if(flags & M3D_EXP_FLIPTXTCRD) + tcoord.data.v = (M3D_FLOAT)1.0 - tcoord.data.v; + tcoord.oldidx = i; + memcpy(&tmap[numtmap++], &tcoord, sizeof(m3dtisave_t)); + } + if(numtmap) { + qsort(tmap, numtmap, sizeof(m3dtisave_t), _m3d_ticmp); + memcpy(&tcoord.data, &tmap[0], sizeof(m3dti_t)); + for(i = 0; i < numtmap; i++) { + if(memcmp(&tcoord.data, &tmap[i].data, sizeof(m3dti_t))) { + memcpy(&tcoord.data, &tmap[i].data, sizeof(m3dti_t)); + maxtmap++; + } + tmap[i].newidx = maxtmap; + tmapidx[tmap[i].oldidx] = maxtmap; + } + maxtmap++; + } + } + if(model->numskin && model->skin && !(flags & M3D_EXP_NOBONE)) { + M3D_LOG("Compressing skin"); + skinidx = (M3D_INDEX*)M3D_MALLOC(model->numskin * sizeof(M3D_INDEX)); + if(!skinidx) goto memerr; + skin = (m3dssave_t*)M3D_MALLOC(model->numskin * sizeof(m3dssave_t)); + if(!skin) goto memerr; + memset(skinidx, 255, model->numskin * sizeof(M3D_INDEX)); + for(i = 0; i < model->numvertex; i++) { + if(vrtxidx[i] != M3D_UNDEF && model->vertex[i].skinid < model->numskin) + skinidx[model->vertex[i].skinid] = 0; + } + for(i = 0; i < model->numskin; i++) { + if(skinidx[i] == M3D_UNDEF) continue; + memset(&sk, 0, sizeof(m3dssave_t)); + for(j = 0, min_x = (M3D_FLOAT)0.0; j < M3D_NUMBONE && model->skin[i].boneid[j] != M3D_UNDEF && + model->skin[i].weight[j] > (M3D_FLOAT)0.0; j++) { + sk.data.boneid[j] = model->skin[i].boneid[j]; + sk.data.weight[j] = model->skin[i].weight[j]; + min_x += sk.data.weight[j]; + } + if(j > maxbone) maxbone = j; + if(min_x != (M3D_FLOAT)1.0 && min_x != (M3D_FLOAT)0.0) + for(j = 0; j < M3D_NUMBONE && sk.data.weight[j] > (M3D_FLOAT)0.0; j++) + sk.data.weight[j] /= min_x; + sk.oldidx = i; + memcpy(&skin[numskin++], &sk, sizeof(m3dssave_t)); + } + if(numskin) { + qsort(skin, numskin, sizeof(m3dssave_t), _m3d_skincmp); + memcpy(&sk.data, &skin[0].data, sizeof(m3ds_t)); + for(i = 0; i < numskin; i++) { + if(memcmp(&sk.data, &skin[i].data, sizeof(m3ds_t))) { + memcpy(&sk.data, &skin[i].data, sizeof(m3ds_t)); + maxskin++; + } + skin[i].newidx = maxskin; + skinidx[skin[i].oldidx] = maxskin; + } + maxskin++; + } + } + + M3D_LOG("Compressing vertex list"); + min_x = min_y = min_z = (M3D_FLOAT)1e10; + max_x = max_y = max_z = (M3D_FLOAT)-1e10; + if(vrtxidx) { + vrtx = (m3dvsave_t*)M3D_MALLOC(model->numvertex * sizeof(m3dvsave_t)); + if(!vrtx) goto memerr; + for(i = numvrtx = 0; i < model->numvertex; i++) { + if(vrtxidx[i] == M3D_UNDEF) continue; + _m3d_round(quality, &model->vertex[i], &vertex.data); + vertex.norm = norm ? norm[i] : 0; + if(vertex.data.skinid != M3D_INDEXMAX && !vertex.norm) { + vertex.data.skinid = vertex.data.skinid != M3D_UNDEF && skinidx ? skinidx[vertex.data.skinid] : M3D_UNDEF; + if(vertex.data.x > max_x) max_x = vertex.data.x; + if(vertex.data.x < min_x) min_x = vertex.data.x; + if(vertex.data.y > max_y) max_y = vertex.data.y; + if(vertex.data.y < min_y) min_y = vertex.data.y; + if(vertex.data.z > max_z) max_z = vertex.data.z; + if(vertex.data.z < min_z) min_z = vertex.data.z; + } +#ifdef M3D_VERTEXTYPE + vertex.data.type = 0; +#endif + vertex.oldidx = i; + memcpy(&vrtx[numvrtx++], &vertex, sizeof(m3dvsave_t)); + } + if(numvrtx) { + qsort(vrtx, numvrtx, sizeof(m3dvsave_t), _m3d_vrtxcmp); + memcpy(&vertex.data, &vrtx[0].data, sizeof(m3dv_t)); + for(i = 0; i < numvrtx; i++) { + if(memcmp(&vertex.data, &vrtx[i].data, vrtx[i].norm ? 3 * sizeof(M3D_FLOAT) : sizeof(m3dv_t))) { + memcpy(&vertex.data, &vrtx[i].data, sizeof(m3dv_t)); + maxvrtx++; + } + vrtx[i].newidx = maxvrtx; + vrtxidx[vrtx[i].oldidx] = maxvrtx; + } + maxvrtx++; + } + } + if(skinidx) { M3D_FREE(skinidx); skinidx = NULL; } + if(norm) { M3D_FREE(norm); norm = NULL; } + + /* normalize to bounding cube */ + if(numvrtx && !(flags & M3D_EXP_NORECALC)) { + M3D_LOG("Normalizing coordinates"); + if(min_x < (M3D_FLOAT)0.0) min_x = -min_x; + if(max_x < (M3D_FLOAT)0.0) max_x = -max_x; + if(min_y < (M3D_FLOAT)0.0) min_y = -min_y; + if(max_y < (M3D_FLOAT)0.0) max_y = -max_y; + if(min_z < (M3D_FLOAT)0.0) min_z = -min_z; + if(max_z < (M3D_FLOAT)0.0) max_z = -max_z; scale = min_x; if(max_x > scale) scale = max_x; if(min_y > scale) scale = min_y; if(max_y > scale) scale = max_y; if(min_z > scale) scale = min_z; if(max_z > scale) scale = max_z; - if(scale == 0.0f) scale = 1.0f; - if(scale != 1.0f && !(flags & M3D_EXP_NORECALC)) { + if(scale == (M3D_FLOAT)0.0) scale = (M3D_FLOAT)1.0; + if(scale != (M3D_FLOAT)1.0) { for(i = 0; i < numvrtx; i++) { - if(vrtx[i].skinid == (M3D_INDEX)-2U) continue; - vrtx[i].x /= scale; - vrtx[i].y /= scale; - vrtx[i].z /= scale; + if(vrtx[i].data.skinid == M3D_INDEXMAX) continue; + vrtx[i].data.x /= scale; + vrtx[i].data.y /= scale; + vrtx[i].data.z /= scale; } } } - /* if there's only one black color, don't store it */ - if(numcmap == 1 && cmap && !cmap[0]) numcmap = 0; - /* at least 3 UV coordinate required for texture mapping */ - if(numtmap < 3 && tmap) numtmap = 0; + if(model->scale > (M3D_FLOAT)0.0) scale = model->scale; + if(scale <= (M3D_FLOAT)0.0) scale = (M3D_FLOAT)1.0; + /* meta info */ sn = _m3d_safestr(model->name && *model->name ? model->name : (char*)"(noname)", 2); sl = _m3d_safestr(model->license ? model->license : (char*)"MIT", 2); sa = _m3d_safestr(model->author ? model->author : getenv("LOGNAME"), 2); if(!sn || !sl || !sa) { -memerr: if(face) M3D_FREE(face); +memerr: if(vrtxidx) M3D_FREE(vrtxidx); + if(mtrlidx) M3D_FREE(mtrlidx); + if(tmapidx) M3D_FREE(tmapidx); + if(skinidx) M3D_FREE(skinidx); + if(grpidx) M3D_FREE(grpidx); + if(norm) M3D_FREE(norm); + if(face) M3D_FREE(face); if(cmap) M3D_FREE(cmap); if(tmap) M3D_FREE(tmap); - if(mtrl) M3D_FREE(mtrl); - if(vrtx) M3D_FREE(vrtx); - if(bone) M3D_FREE(bone); if(skin) M3D_FREE(skin); - if(actn) M3D_FREE(actn); + if(str) M3D_FREE(str); + if(vrtx) M3D_FREE(vrtx); if(sn) M3D_FREE(sn); if(sl) M3D_FREE(sl); if(sa) M3D_FREE(sa); if(sd) M3D_FREE(sd); if(out) M3D_FREE(out); - if(str) M3D_FREE(str); if(h) M3D_FREE(h); M3D_LOG("Out of memory"); model->errcode = M3D_ERR_ALLOC; return NULL; } - if(model->scale > (M3D_FLOAT)0.0) scale = (float)model->scale; - if(scale <= 0.0f) scale = 1.0f; + + M3D_LOG("Serializing model"); #ifdef M3D_ASCII if(flags & M3D_EXP_ASCII) { /* use CRLF to make model creators on Win happy... */ @@ -3802,74 +4541,93 @@ memerr: if(face) M3D_FREE(face); ol = setlocale(LC_NUMERIC, NULL); setlocale(LC_NUMERIC, "C"); /* header */ - len = 64 + strlen(sn) + strlen(sl) + strlen(sa) + strlen(sd); + len = 64 + (unsigned int)(strlen(sn) + strlen(sl) + strlen(sa) + strlen(sd)); out = (unsigned char*)M3D_MALLOC(len); if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr = (char*)out; ptr += sprintf(ptr, "3dmodel %g\r\n%s\r\n%s\r\n%s\r\n%s\r\n\r\n", scale, sn, sl, sa, sd); - M3D_FREE(sn); M3D_FREE(sl); M3D_FREE(sa); M3D_FREE(sd); - sn = sl = sa = sd = NULL; + M3D_FREE(sl); M3D_FREE(sa); M3D_FREE(sd); + sl = sa = sd = NULL; + /* preview chunk */ + if(model->preview.data && model->preview.length) { + sl = _m3d_safestr(sn, 0); + if(sl) { + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)20); + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; + if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } + ptr += sprintf(ptr, "Preview\r\n%s.png\r\n\r\n", sl); + M3D_FREE(sl); sl = NULL; + } + } + M3D_FREE(sn); sn = NULL; /* texture map */ if(numtmap && tmap && !(flags & M3D_EXP_NOTXTCRD) && !(flags & M3D_EXP_NOFACE)) { - ptr -= (uint64_t)out; len = (uint64_t)ptr + numtmap * 32 + 12; - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)(maxtmap * 32) + (uintptr_t)12); + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Textmap\r\n"); - for(i = 0; i < numtmap; i++) - ptr += sprintf(ptr, "%g %g\r\n", tmap[i].u, tmap[i].v); + last = M3D_UNDEF; + for(i = 0; i < numtmap; i++) { + if(tmap[i].newidx == last) continue; + last = tmap[i].newidx; + ptr += sprintf(ptr, "%g %g\r\n", tmap[i].data.u, tmap[i].data.v); + } ptr += sprintf(ptr, "\r\n"); } /* vertex chunk */ if(numvrtx && vrtx && !(flags & M3D_EXP_NOFACE)) { - ptr -= (uint64_t)out; len = (uint64_t)ptr + numvrtx * 128 + 10; - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)(maxvrtx * 128) + (uintptr_t)10); + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Vertex\r\n"); + last = M3D_UNDEF; for(i = 0; i < numvrtx; i++) { - ptr += sprintf(ptr, "%g %g %g %g", vrtx[i].x, vrtx[i].y, vrtx[i].z, vrtx[i].w); - if(!(flags & M3D_EXP_NOCMAP) && vrtx[i].color) - ptr += sprintf(ptr, " #%08x", vrtx[i].color); - if(!(flags & M3D_EXP_NOBONE) && numbone && numskin && vrtx[i].skinid != (M3D_INDEX)-1U && - vrtx[i].skinid != (M3D_INDEX)-2U) { - if(skin[vrtx[i].skinid].weight[0] == (M3D_FLOAT)1.0) - ptr += sprintf(ptr, " %d", skin[vrtx[i].skinid].boneid[0]); + if(vrtx[i].newidx == last) continue; + last = vrtx[i].newidx; + ptr += sprintf(ptr, "%g %g %g %g", vrtx[i].data.x, vrtx[i].data.y, vrtx[i].data.z, vrtx[i].data.w); + if(!(flags & M3D_EXP_NOCMAP) && vrtx[i].data.color) + ptr += sprintf(ptr, " #%08x", vrtx[i].data.color); + if(!(flags & M3D_EXP_NOBONE) && model->numbone && maxskin && vrtx[i].data.skinid < M3D_INDEXMAX) { + if(skin[vrtx[i].data.skinid].data.weight[0] == (M3D_FLOAT)1.0) + ptr += sprintf(ptr, " %d", skin[vrtx[i].data.skinid].data.boneid[0]); else - for(j = 0; j < M3D_NUMBONE && skin[vrtx[i].skinid].boneid[j] != (M3D_INDEX)-1U && - skin[vrtx[i].skinid].weight[j] > (M3D_FLOAT)0.0; j++) - ptr += sprintf(ptr, " %d:%g", skin[vrtx[i].skinid].boneid[j], - skin[vrtx[i].skinid].weight[j]); + for(j = 0; j < M3D_NUMBONE && skin[vrtx[i].data.skinid].data.boneid[j] != M3D_UNDEF && + skin[vrtx[i].data.skinid].data.weight[j] > (M3D_FLOAT)0.0; j++) + ptr += sprintf(ptr, " %d:%g", skin[vrtx[i].data.skinid].data.boneid[j], + skin[vrtx[i].data.skinid].data.weight[j]); } ptr += sprintf(ptr, "\r\n"); } ptr += sprintf(ptr, "\r\n"); } /* bones chunk */ - if(numbone && bone && !(flags & M3D_EXP_NOBONE)) { - ptr -= (uint64_t)out; len = (uint64_t)ptr + 9; - for(i = 0; i < numbone; i++) { - len += strlen(bone[i].name) + 128; + if(model->numbone && model->bone && !(flags & M3D_EXP_NOBONE)) { + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)9); + for(i = 0; i < model->numbone; i++) { + len += (unsigned int)strlen(model->bone[i].name) + 128; } - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Bones\r\n"); - ptr = _m3d_prtbone(ptr, bone, numbone, (M3D_INDEX)-1U, 0); + ptr = _m3d_prtbone(ptr, model->bone, model->numbone, M3D_UNDEF, 0, vrtxidx); ptr += sprintf(ptr, "\r\n"); } /* materials */ - if(nummtrl && !(flags & M3D_EXP_NOMATERIAL)) { - for(j = 0; j < nummtrl; j++) { - m = !mtrl ? &model->material[j] : mtrl[j]; + if(model->nummaterial && !(flags & M3D_EXP_NOMATERIAL)) { + for(j = 0; j < model->nummaterial; j++) { + if(mtrlidx[j] == M3D_UNDEF || !model->material[j].numprop || !model->material[j].prop) continue; + m = &model->material[j]; sn = _m3d_safestr(m->name, 0); if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr -= (uint64_t)out; len = (uint64_t)ptr + strlen(sn) + 12; + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)strlen(sn) + (uintptr_t)12); for(i = 0; i < m->numprop; i++) { if(m->prop[i].type < 128) len += 32; else if(m->prop[i].value.textureid < model->numtexture && model->texture[m->prop[i].value.textureid].name) - len += strlen(model->texture[m->prop[i].value.textureid].name) + 16; + len += (unsigned int)strlen(model->texture[m->prop[i].value.textureid].name) + 16; } - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Material %s\r\n", sn); M3D_FREE(sn); sn = NULL; @@ -3918,28 +4676,50 @@ memerr: if(face) M3D_FREE(face); ptr += sprintf(ptr, "\r\n"); } } + /* procedural face */ + if(model->numinlined && model->inlined && !(flags & M3D_EXP_NOFACE)) { + /* all inlined assets which are not textures should be procedural surfaces */ + for(j = 0; j < model->numinlined; j++) { + if(!model->inlined[j].name || !*model->inlined[j].name || !model->inlined[j].length || !model->inlined[j].data || + (model->inlined[j].data[1] == 'P' && model->inlined[j].data[2] == 'N' && model->inlined[j].data[3] == 'G')) + continue; + for(i = k = 0; i < model->numtexture; i++) { + if(!strcmp(model->inlined[j].name, model->texture[i].name)) { k = 1; break; } + } + if(k) continue; + sn = _m3d_safestr(model->inlined[j].name, 0); + if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)strlen(sn) + (uintptr_t)18); + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; + if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } + ptr += sprintf(ptr, "Procedural\r\n%s\r\n\r\n", sn); + M3D_FREE(sn); sn = NULL; + } + } /* mesh face */ if(model->numface && face && !(flags & M3D_EXP_NOFACE)) { - ptr -= (uint64_t)out; len = (uint64_t)ptr + model->numface * 128 + 6; - last = (M3D_INDEX)-1U; + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)(model->numface * 128) + (uintptr_t)6); + last = M3D_UNDEF; if(!(flags & M3D_EXP_NOMATERIAL)) for(i = 0; i < model->numface; i++) { - if(face[i].materialid != last) { - last = face[i].materialid; - if(last < nummtrl) - len += strlen(mtrl[last]->name); + j = face[i].data.materialid < model->nummaterial ? face[i].data.materialid : M3D_UNDEF; + if(j != last) { + last = j; + if(last < model->nummaterial) + len += (unsigned int)strlen(model->material[last].name); len += 6; } } - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Mesh\r\n"); - last = (M3D_INDEX)-1U; + last = M3D_UNDEF; for(i = 0; i < model->numface; i++) { - if(!(flags & M3D_EXP_NOMATERIAL) && face[i].materialid != last) { - last = face[i].materialid; - if(last < nummtrl) { - sn = _m3d_safestr(mtrl[last]->name, 0); + j = face[i].data.materialid < model->nummaterial ? face[i].data.materialid : M3D_UNDEF; + if(!(flags & M3D_EXP_NOMATERIAL) && j != last) { + last = j; + if(last < model->nummaterial) { + sn = _m3d_safestr(model->material[last].name, 0); if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "use %s\r\n", sn); M3D_FREE(sn); sn = NULL; @@ -3948,63 +4728,165 @@ memerr: if(face) M3D_FREE(face); } /* hardcoded triangles. Should be repeated as many times as the number of edges in polygon */ for(j = 0; j < 3; j++) { - ptr += sprintf(ptr, "%s%d", j?" ":"", face[i].vertex[j]); - if(!(flags & M3D_EXP_NOTXTCRD) && (face[i].texcoord[j] != (M3D_INDEX)-1U)) - ptr += sprintf(ptr, "/%d", face[i].texcoord[j]); - if(!(flags & M3D_EXP_NONORMAL) && (face[i].normal[j] != (M3D_INDEX)-1U)) - ptr += sprintf(ptr, "%s/%d", - (flags & M3D_EXP_NOTXTCRD) || (face[i].texcoord[j] == (M3D_INDEX)-1U)? "/" : "", - face[i].normal[j]); + ptr += sprintf(ptr, "%s%d", j?" ":"", vrtxidx[face[i].data.vertex[j]]); + k = M3D_NOTDEFINED; + if(!(flags & M3D_EXP_NOTXTCRD) && (face[i].data.texcoord[j] != M3D_UNDEF) && + (tmapidx[face[i].data.texcoord[j]] != M3D_UNDEF)) { + k = tmapidx[face[i].data.texcoord[j]]; + ptr += sprintf(ptr, "/%d", k); + } + if(!(flags & M3D_EXP_NONORMAL) && (face[i].data.normal[j] != M3D_UNDEF)) + ptr += sprintf(ptr, "%s/%d", k == M3D_NOTDEFINED? "/" : "", vrtxidx[face[i].data.normal[j]]); } ptr += sprintf(ptr, "\r\n"); } ptr += sprintf(ptr, "\r\n"); } + /* mathematical shapes face */ + if(model->numshape && model->numshape && !(flags & M3D_EXP_NOFACE)) { + for(j = 0; j < model->numshape; j++) { + sn = _m3d_safestr(model->shape[j].name, 0); + if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)strlen(sn) + (uintptr_t)33); + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; + if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } + ptr += sprintf(ptr, "Shape %s\r\n", sn); + M3D_FREE(sn); sn = NULL; + if(model->shape[j].group != M3D_UNDEF && !(flags & M3D_EXP_NOBONE)) + ptr += sprintf(ptr, "group %d\r\n", model->shape[j].group); + for(i = 0; i < model->shape[j].numcmd; i++) { + cmd = &model->shape[j].cmd[i]; + if(cmd->type >= (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0])) || !cmd->arg) + continue; + cd = &m3d_commandtypes[cmd->type]; + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)strlen(cd->key) + (uintptr_t)3); + for(k = 0; k < cd->p; k++) + switch(cd->a[k]) { + case m3dcp_mi_t: if(cmd->arg[k] != M3D_NOTDEFINED) { len += (unsigned int)strlen(model->material[cmd->arg[k]].name) + 1; } break; + case m3dcp_va_t: len += cmd->arg[k] * (cd->p - k - 1) * 16; k = cd->p; break; + default: len += 16; break; + } + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; + if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } + ptr += sprintf(ptr, "%s", cd->key); + for(k = n = 0, l = cd->p; k < l; k++) { + switch(cd->a[((k - n) % (cd->p - n)) + n]) { + case m3dcp_mi_t: + if(cmd->arg[k] != M3D_NOTDEFINED) { + sn = _m3d_safestr(model->material[cmd->arg[k]].name, 0); + if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } + ptr += sprintf(ptr, " %s", sn); + M3D_FREE(sn); sn = NULL; + } + break; + case m3dcp_vc_t: ptr += sprintf(ptr, " %g", *((float*)&cmd->arg[k])); break; + case m3dcp_va_t: ptr += sprintf(ptr, " %d[", cmd->arg[k]); + n = k + 1; l += (cmd->arg[k] - 1) * (cd->p - k - 1); + break; + default: ptr += sprintf(ptr, " %d", cmd->arg[k]); break; + } + } + ptr += sprintf(ptr, "%s\r\n", l > cd->p ? " ]" : ""); + } + ptr += sprintf(ptr, "\r\n"); + } + } + /* annotation labels */ + if(model->numlabel && model->label && !(flags & M3D_EXP_NOFACE)) { + for(i = 0, j = 3, length = NULL; i < model->numlabel; i++) { + if(model->label[i].name) j += (unsigned int)strlen(model->label[i].name); + if(model->label[i].lang) j += (unsigned int)strlen(model->label[i].lang); + if(model->label[i].text) j += (unsigned int)strlen(model->label[i].text); + j += 40; + } + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)j); + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; + if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } + for(i = 0; i < model->numlabel; i++) { + if(!i || _m3d_strcmp(sl, model->label[i].lang) || _m3d_strcmp(sn, model->label[i].name)) { + sl = model->label[i].lang; + sn = model->label[i].name; + sd = _m3d_safestr(sn, 0); + if(!sd) { setlocale(LC_NUMERIC, ol); sn = sl = NULL; goto memerr; } + if(i) ptr += sprintf(ptr, "\r\n"); + ptr += sprintf(ptr, "Labels %s\r\n", sd); + M3D_FREE(sd); sd = NULL; + if(model->label[i].color) + ptr += sprintf(ptr, "color #0x%08x\r\n", model->label[i].color); + if(sl && *sl) { + sd = _m3d_safestr(sl, 0); + if(!sd) { setlocale(LC_NUMERIC, ol); sn = sl = NULL; goto memerr; } + ptr += sprintf(ptr, "lang %s\r\n", sd); + M3D_FREE(sd); sd = NULL; + } + } + sd = _m3d_safestr(model->label[i].text, 2); + if(!sd) { setlocale(LC_NUMERIC, ol); sn = sl = NULL; goto memerr; } + ptr += sprintf(ptr, "%d %s\r\n", model->label[i].vertexid, sd); + M3D_FREE(sd); sd = NULL; + } + ptr += sprintf(ptr, "\r\n"); + sn = sl = NULL; + } /* actions */ - if(model->numaction && model->action && numactn && actn && !(flags & M3D_EXP_NOACTION)) { - l = 0; + if(model->numaction && model->action && !(flags & M3D_EXP_NOACTION)) { for(j = 0; j < model->numaction; j++) { a = &model->action[j]; sn = _m3d_safestr(a->name, 0); if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr -= (uint64_t)out; len = (uint64_t)ptr + strlen(sn) + 48; + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)strlen(sn) + (uintptr_t)48); for(i = 0; i < a->numframe; i++) len += a->frame[i].numtransform * 128 + 8; - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Action %d %s\r\n", a->durationmsec, sn); M3D_FREE(sn); sn = NULL; - if(a->numframe > 65535) a->numframe = 65535; for(i = 0; i < a->numframe; i++) { ptr += sprintf(ptr, "frame %d\r\n", a->frame[i].msec); for(k = 0; k < a->frame[i].numtransform; k++) { - ptr += sprintf(ptr, "%d %d %d\r\n", a->frame[i].transform[k].boneid, actn[l], actn[l + 1]); - l += 2; + ptr += sprintf(ptr, "%d %d %d\r\n", a->frame[i].transform[k].boneid, + vrtxidx[a->frame[i].transform[k].pos], vrtxidx[a->frame[i].transform[k].ori]); } } ptr += sprintf(ptr, "\r\n"); } } + /* inlined assets */ + if(model->numinlined && model->inlined) { + for(i = j = 0; i < model->numinlined; i++) + if(model->inlined[i].name) + j += (unsigned int)strlen(model->inlined[i].name) + 6; + if(j > 0) { + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)j + (uintptr_t)16); + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; + if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } + ptr += sprintf(ptr, "Assets\r\n"); + for(i = 0; i < model->numinlined; i++) + if(model->inlined[i].name) + ptr += sprintf(ptr, "%s%s\r\n", model->inlined[i].name, strrchr(model->inlined[i].name, '.') ? "" : ".png"); + ptr += sprintf(ptr, "\r\n"); + } + } /* extra info */ - if(model->numunknown && (flags & M3D_EXP_EXTRA)) { - for(i = 0; i < model->numunknown; i++) { - if(model->unknown[i]->length < 9) continue; - ptr -= (uint64_t)out; len = (uint64_t)ptr + 17 + model->unknown[i]->length * 3; - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + if(model->numextra && (flags & M3D_EXP_EXTRA)) { + for(i = 0; i < model->numextra; i++) { + if(model->extra[i]->length < 9) continue; + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)17 + (uintptr_t)(model->extra[i]->length * 3)); + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Extra %c%c%c%c\r\n", - model->unknown[i]->magic[0] > ' ' ? model->unknown[i]->magic[0] : '_', - model->unknown[i]->magic[1] > ' ' ? model->unknown[i]->magic[1] : '_', - model->unknown[i]->magic[2] > ' ' ? model->unknown[i]->magic[2] : '_', - model->unknown[i]->magic[3] > ' ' ? model->unknown[i]->magic[3] : '_'); - for(j = 0; j < model->unknown[i]->length; j++) - ptr += sprintf(ptr, "%02x ", *((unsigned char *)model->unknown + sizeof(m3dchunk_t) + j)); + model->extra[i]->magic[0] > ' ' ? model->extra[i]->magic[0] : '_', + model->extra[i]->magic[1] > ' ' ? model->extra[i]->magic[1] : '_', + model->extra[i]->magic[2] > ' ' ? model->extra[i]->magic[2] : '_', + model->extra[i]->magic[3] > ' ' ? model->extra[i]->magic[3] : '_'); + for(j = 0; j < model->extra[i]->length; j++) + ptr += sprintf(ptr, "%02x ", *((unsigned char *)model->extra + sizeof(m3dchunk_t) + j)); ptr--; ptr += sprintf(ptr, "\r\n\r\n"); } } setlocale(LC_NUMERIC, ol); - len = (uint64_t)ptr - (uint64_t)out; + len = (unsigned int)((uintptr_t)ptr - (uintptr_t)out); out = (unsigned char*)M3D_REALLOC(out, len + 1); if(!out) goto memerr; out[len] = 0; @@ -4020,21 +4902,11 @@ memerr: if(face) M3D_FREE(face); memcpy((uint8_t*)h, "HEAD", 4); h->length = sizeof(m3dhdr_t); h->scale = scale; - i = strlen(sn); memcpy((uint8_t*)h + h->length, sn, i+1); h->length += i+1; M3D_FREE(sn); - i = strlen(sl); memcpy((uint8_t*)h + h->length, sl, i+1); h->length += i+1; M3D_FREE(sl); - i = strlen(sa); memcpy((uint8_t*)h + h->length, sa, i+1); h->length += i+1; M3D_FREE(sa); - i = strlen(sd); memcpy((uint8_t*)h + h->length, sd, i+1); h->length += i+1; M3D_FREE(sd); + i = (unsigned int)strlen(sn); memcpy((uint8_t*)h + h->length, sn, i+1); h->length += i+1; M3D_FREE(sn); + i = (unsigned int)strlen(sl); memcpy((uint8_t*)h + h->length, sl, i+1); h->length += i+1; M3D_FREE(sl); + i = (unsigned int)strlen(sa); memcpy((uint8_t*)h + h->length, sa, i+1); h->length += i+1; M3D_FREE(sa); + i = (unsigned int)strlen(sd); memcpy((uint8_t*)h + h->length, sd, i+1); h->length += i+1; M3D_FREE(sd); sn = sl = sa = sd = NULL; - len = 0; - if(!bone) numbone = 0; - if(skin) - for(i = 0; i < numskin; i++) { - for(j = k = 0; j < M3D_NUMBONE; j++) - if(skin[i].boneid[j] != (M3D_INDEX)-1U && skin[i].weight[j] > (M3D_FLOAT)0.0) k++; - if(k > len) len = k; - } - else - numskin = 0; if(model->inlined) for(i = 0; i < model->numinlined; i++) { if(model->inlined[i].name && *model->inlined[i].name && model->inlined[i].length > 0) { @@ -4048,14 +4920,19 @@ memerr: if(face) M3D_FREE(face); if(!h) goto memerr; } vc_s = quality == M3D_EXP_INT8? 1 : (quality == M3D_EXP_INT16? 2 : (quality == M3D_EXP_DOUBLE? 8 : 4)); - vi_s = numvrtx < 254 ? 1 : (numvrtx < 65534 ? 2 : 4); + vi_s = maxvrtx < 254 ? 1 : (maxvrtx < 65534 ? 2 : 4); si_s = h->length - 16 < 254 ? 1 : (h->length - 16 < 65534 ? 2 : 4); ci_s = !numcmap || !cmap ? 0 : (numcmap < 254 ? 1 : (numcmap < 65534 ? 2 : 4)); - ti_s = !numtmap || !tmap ? 0 : (numtmap < 254 ? 1 : (numtmap < 65534 ? 2 : 4)); - bi_s = !numbone || !bone ? 0 : (numbone < 254 ? 1 : (numbone < 65534 ? 2 : 4)); - nb_s = len < 2 ? 1 : (len == 2 ? 2 : (len <= 4 ? 4 : 8)); - sk_s = !numbone || !numskin ? 0 : (numskin < 254 ? 1 : (numskin < 65534 ? 2 : 4)); - fi_s = maxt < 254 ? 1 : (maxt < 65534 ? 2 : 4); + ti_s = !maxtmap || !tmap ? 0 : (maxtmap < 254 ? 1 : (maxtmap < 65534 ? 2 : 4)); + bi_s = !model->numbone || !model->bone || (flags & M3D_EXP_NOBONE)? 0 : (model->numbone < 254 ? 1 : + (model->numbone < 65534 ? 2 : 4)); + nb_s = maxbone < 2 ? 1 : (maxbone == 2 ? 2 : (maxbone <= 4 ? 4 : 8)); + sk_s = !bi_s || !maxskin || !skin ? 0 : (maxskin < 254 ? 1 : (maxskin < 65534 ? 2 : 4)); + fc_s = maxt < 254 ? 1 : (maxt < 65534 ? 2 : 4); + hi_s = !model->numshape || !model->shape || (flags & M3D_EXP_NOFACE)? 0 : (model->numshape < 254 ? 1 : + (model->numshape < 65534 ? 2 : 4)); + fi_s = !model->numface || !model->face || (flags & M3D_EXP_NOFACE)? 0 : (model->numface < 254 ? 1 : + (model->numface < 65534 ? 2 : 4)); h->types = (vc_s == 8 ? (3<<0) : (vc_s == 2 ? (1<<0) : (vc_s == 1 ? (0<<0) : (2<<0)))) | (vi_s == 2 ? (1<<2) : (vi_s == 1 ? (0<<2) : (2<<2))) | (si_s == 2 ? (1<<4) : (si_s == 1 ? (0<<4) : (2<<4))) | @@ -4064,8 +4941,20 @@ memerr: if(face) M3D_FREE(face); (bi_s == 2 ? (1<<10): (bi_s == 1 ? (0<<10): (bi_s == 4 ? (2<<10) : (3<<10)))) | (nb_s == 2 ? (1<<12): (nb_s == 1 ? (0<<12): (2<<12))) | (sk_s == 2 ? (1<<14): (sk_s == 1 ? (0<<14): (sk_s == 4 ? (2<<14) : (3<<14)))) | - (fi_s == 2 ? (1<<16): (fi_s == 1 ? (0<<16): (2<<16))) ; + (fc_s == 2 ? (1<<16): (fc_s == 1 ? (0<<16): (2<<16))) | + (hi_s == 2 ? (1<<18): (hi_s == 1 ? (0<<18): (hi_s == 4 ? (2<<18) : (3<<18)))) | + (fi_s == 2 ? (1<<20): (fi_s == 1 ? (0<<20): (fi_s == 4 ? (2<<20) : (3<<20)))); len = h->length; + /* preview image chunk, must be the first if exists */ + if(model->preview.data && model->preview.length) { + chunklen = 8 + model->preview.length; + h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); + if(!h) goto memerr; + memcpy((uint8_t*)h + len, "PRVW", 4); + *((uint32_t*)((uint8_t*)h + len + 4)) = chunklen; + memcpy((uint8_t*)h + len + 8, model->preview.data, model->preview.length); + len += chunklen; + } /* color map */ if(numcmap && cmap && ci_s < 4 && !(flags & M3D_EXP_NOCMAP)) { chunklen = 8 + numcmap * sizeof(uint32_t); @@ -4078,116 +4967,127 @@ memerr: if(face) M3D_FREE(face); } else numcmap = 0; /* texture map */ if(numtmap && tmap && !(flags & M3D_EXP_NOTXTCRD) && !(flags & M3D_EXP_NOFACE)) { - chunklen = 8 + numtmap * vc_s * 2; + chunklen = 8 + maxtmap * vc_s * 2; h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); if(!h) goto memerr; memcpy((uint8_t*)h + len, "TMAP", 4); - *((uint32_t*)((uint8_t*)h + len + 4)) = chunklen; + length = (uint32_t*)((uint8_t*)h + len + 4); out = (uint8_t*)h + len + 8; + last = M3D_UNDEF; for(i = 0; i < numtmap; i++) { + if(tmap[i].newidx == last) continue; + last = tmap[i].newidx; switch(vc_s) { - case 1: *out++ = (uint8_t)(tmap[i].u * 255); *out++ = (uint8_t)(tmap[i].v * 255); break; + case 1: *out++ = (uint8_t)(tmap[i].data.u * 255); *out++ = (uint8_t)(tmap[i].data.v * 255); break; case 2: - *((uint16_t*)out) = (uint16_t)(tmap[i].u * 65535); out += 2; - *((uint16_t*)out) = (uint16_t)(tmap[i].v * 65535); out += 2; + *((uint16_t*)out) = (uint16_t)(tmap[i].data.u * 65535); out += 2; + *((uint16_t*)out) = (uint16_t)(tmap[i].data.v * 65535); out += 2; break; - case 4: *((float*)out) = tmap[i].u; out += 4; *((float*)out) = tmap[i].v; out += 4; break; - case 8: *((double*)out) = tmap[i].u; out += 8; *((double*)out) = tmap[i].v; out += 8; break; + case 4: *((float*)out) = tmap[i].data.u; out += 4; *((float*)out) = tmap[i].data.v; out += 4; break; + case 8: *((double*)out) = tmap[i].data.u; out += 8; *((double*)out) = tmap[i].data.v; out += 8; break; } } + *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); out = NULL; - len += chunklen; + len += *length; } /* vertex */ if(numvrtx && vrtx) { - chunklen = 8 + numvrtx * (ci_s + sk_s + 4 * vc_s); + chunklen = 8 + maxvrtx * (ci_s + sk_s + 4 * vc_s); h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); if(!h) goto memerr; memcpy((uint8_t*)h + len, "VRTS", 4); - *((uint32_t*)((uint8_t*)h + len + 4)) = chunklen; + length = (uint32_t*)((uint8_t*)h + len + 4); out = (uint8_t*)h + len + 8; + last = M3D_UNDEF; for(i = 0; i < numvrtx; i++) { + if(vrtx[i].newidx == last) continue; + last = vrtx[i].newidx; switch(vc_s) { case 1: - *out++ = (int8_t)(vrtx[i].x * 127); - *out++ = (int8_t)(vrtx[i].y * 127); - *out++ = (int8_t)(vrtx[i].z * 127); - *out++ = (int8_t)(vrtx[i].w * 127); + *out++ = (int8_t)(vrtx[i].data.x * 127); + *out++ = (int8_t)(vrtx[i].data.y * 127); + *out++ = (int8_t)(vrtx[i].data.z * 127); + *out++ = (int8_t)(vrtx[i].data.w * 127); break; case 2: - *((int16_t*)out) = (int16_t)(vrtx[i].x * 32767); out += 2; - *((int16_t*)out) = (int16_t)(vrtx[i].y * 32767); out += 2; - *((int16_t*)out) = (int16_t)(vrtx[i].z * 32767); out += 2; - *((int16_t*)out) = (int16_t)(vrtx[i].w * 32767); out += 2; + *((int16_t*)out) = (int16_t)(vrtx[i].data.x * 32767); out += 2; + *((int16_t*)out) = (int16_t)(vrtx[i].data.y * 32767); out += 2; + *((int16_t*)out) = (int16_t)(vrtx[i].data.z * 32767); out += 2; + *((int16_t*)out) = (int16_t)(vrtx[i].data.w * 32767); out += 2; break; case 4: - *((float*)out) = vrtx[i].x; out += 4; - *((float*)out) = vrtx[i].y; out += 4; - *((float*)out) = vrtx[i].z; out += 4; - *((float*)out) = vrtx[i].w; out += 4; + *((float*)out) = vrtx[i].data.x; out += 4; + *((float*)out) = vrtx[i].data.y; out += 4; + *((float*)out) = vrtx[i].data.z; out += 4; + *((float*)out) = vrtx[i].data.w; out += 4; break; case 8: - *((double*)out) = vrtx[i].x; out += 8; - *((double*)out) = vrtx[i].y; out += 8; - *((double*)out) = vrtx[i].z; out += 8; - *((double*)out) = vrtx[i].w; out += 8; + *((double*)out) = vrtx[i].data.x; out += 8; + *((double*)out) = vrtx[i].data.y; out += 8; + *((double*)out) = vrtx[i].data.z; out += 8; + *((double*)out) = vrtx[i].data.w; out += 8; break; } - idx = _m3d_cmapidx(cmap, numcmap, vrtx[i].color); + idx = _m3d_cmapidx(cmap, numcmap, vrtx[i].data.color); switch(ci_s) { case 1: *out++ = (uint8_t)(idx); break; case 2: *((uint16_t*)out) = (uint16_t)(idx); out += 2; break; - case 4: *((uint32_t*)out) = vrtx[i].color; out += 4; break; + case 4: *((uint32_t*)out) = vrtx[i].data.color; out += 4; break; } - out = _m3d_addidx(out, sk_s, numbone && numskin ? vrtx[i].skinid : -1U); + out = _m3d_addidx(out, sk_s, vrtx[i].data.skinid); } + *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); out = NULL; - len += chunklen; + len += *length; } /* bones chunk */ - if(numbone && bone && !(flags & M3D_EXP_NOBONE)) { - i = 8 + bi_s + sk_s + numbone * (bi_s + si_s + 2*vi_s); + if(model->numbone && model->bone && !(flags & M3D_EXP_NOBONE)) { + i = 8 + bi_s + sk_s + model->numbone * (bi_s + si_s + 2*vi_s); chunklen = i + numskin * nb_s * (bi_s + 1); h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); if(!h) goto memerr; memcpy((uint8_t*)h + len, "BONE", 4); length = (uint32_t*)((uint8_t*)h + len + 4); out = (uint8_t*)h + len + 8; - out = _m3d_addidx(out, bi_s, numbone); - out = _m3d_addidx(out, sk_s, numskin); - for(i = 0; i < numbone; i++) { - out = _m3d_addidx(out, bi_s, bone[i].parent); - out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, bone[i].name)); - out = _m3d_addidx(out, vi_s, bone[i].pos); - out = _m3d_addidx(out, vi_s, bone[i].ori); + out = _m3d_addidx(out, bi_s, model->numbone); + out = _m3d_addidx(out, sk_s, maxskin); + for(i = 0; i < model->numbone; i++) { + out = _m3d_addidx(out, bi_s, model->bone[i].parent); + out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->bone[i].name)); + out = _m3d_addidx(out, vi_s, vrtxidx[model->bone[i].pos]); + out = _m3d_addidx(out, vi_s, vrtxidx[model->bone[i].ori]); } if(numskin && skin && sk_s) { + last = M3D_UNDEF; for(i = 0; i < numskin; i++) { + if(skin[i].newidx == last) continue; + last = skin[i].newidx; memset(&weights, 0, nb_s); - for(j = 0; j < (uint32_t)nb_s && skin[i].boneid[j] != (M3D_INDEX)-1U && - skin[i].weight[j] > (M3D_FLOAT)0.0; j++) - weights[j] = (uint8_t)(skin[i].weight[j] * 255); + for(j = 0; j < (uint32_t)nb_s && skin[i].data.boneid[j] != M3D_UNDEF && + skin[i].data.weight[j] > (M3D_FLOAT)0.0; j++) + weights[j] = (uint8_t)(skin[i].data.weight[j] * 255); switch(nb_s) { case 1: weights[0] = 255; break; case 2: *((uint16_t*)out) = *((uint16_t*)&weights[0]); out += 2; break; case 4: *((uint32_t*)out) = *((uint32_t*)&weights[0]); out += 4; break; case 8: *((uint64_t*)out) = *((uint64_t*)&weights[0]); out += 8; break; } - for(j = 0; j < (uint32_t)nb_s && skin[i].boneid[j] != (M3D_INDEX)-1U && - skin[i].weight[j] > (M3D_FLOAT)0.0; j++) { - out = _m3d_addidx(out, bi_s, skin[i].boneid[j]); + for(j = 0; j < (uint32_t)nb_s && skin[i].data.boneid[j] != M3D_UNDEF && weights[j]; j++) { + out = _m3d_addidx(out, bi_s, skin[i].data.boneid[j]); *length += bi_s; } } } - *length = (uint64_t)out - (uint64_t)((uint8_t*)h + len); + *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); out = NULL; len += *length; } /* materials */ - if(nummtrl && !(flags & M3D_EXP_NOMATERIAL)) { - for(j = 0; j < nummtrl; j++) { - m = !mtrl ? &model->material[j] : mtrl[j]; + if(model->nummaterial && !(flags & M3D_EXP_NOMATERIAL)) { + for(j = 0; j < model->nummaterial; j++) { + if(mtrlidx[j] == M3D_UNDEF || !model->material[j].numprop || !model->material[j].prop) continue; + m = &model->material[j]; chunklen = 12 + si_s + m->numprop * 5; h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); if(!h) goto memerr; @@ -4228,11 +5128,35 @@ memerr: if(face) M3D_FREE(face); break; } } - *length = (uint64_t)out - (uint64_t)((uint8_t*)h + len); + *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); len += *length; out = NULL; } } + /* procedural face */ + if(model->numinlined && model->inlined && !(flags & M3D_EXP_NOFACE)) { + /* all inlined assets which are not textures should be procedural surfaces */ + for(j = 0; j < model->numinlined; j++) { + if(!model->inlined[j].name || !model->inlined[j].name[0] || model->inlined[j].length < 4 || + !model->inlined[j].data || (model->inlined[j].data[1] == 'P' && model->inlined[j].data[2] == 'N' && + model->inlined[j].data[3] == 'G')) + continue; + for(i = k = 0; i < model->numtexture; i++) { + if(!strcmp(model->inlined[j].name, model->texture[i].name)) { k = 1; break; } + } + if(k) continue; + numproc++; + chunklen = 8 + si_s; + h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); + if(!h) goto memerr; + memcpy((uint8_t*)h + len, "PROC", 4); + *((uint32_t*)((uint8_t*)h + len + 4)) = chunklen; + out = (uint8_t*)h + len + 8; + out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->inlined[j].name)); + out = NULL; + len += chunklen; + } + } /* mesh face */ if(model->numface && face && !(flags & M3D_EXP_NOFACE)) { chunklen = 8 + si_s + model->numface * (6 * vi_s + 3 * ti_s + si_s + 1); @@ -4241,43 +5165,125 @@ memerr: if(face) M3D_FREE(face); memcpy((uint8_t*)h + len, "MESH", 4); length = (uint32_t*)((uint8_t*)h + len + 4); out = (uint8_t*)h + len + 8; - last = (M3D_INDEX)-1U; + last = M3D_UNDEF; for(i = 0; i < model->numface; i++) { - if(!(flags & M3D_EXP_NOMATERIAL) && face[i].materialid != last) { - last = face[i].materialid; - if(last < nummtrl) { - idx = _m3d_stridx(str, numstr, !mtrl ? model->material[last].name : mtrl[last]->name); - if(idx) { - *out++ = 0; - out = _m3d_addidx(out, si_s, idx); - } - } + if(!(flags & M3D_EXP_NOMATERIAL) && face[i].data.materialid != last) { + last = face[i].data.materialid; + idx = last < model->nummaterial ? _m3d_stridx(str, numstr, model->material[last].name) : 0; + *out++ = 0; + out = _m3d_addidx(out, si_s, idx); } /* hardcoded triangles. */ k = (3 << 4) | - (((flags & M3D_EXP_NOTXTCRD) || ti_s == 8 || (face[i].texcoord[0] == (M3D_INDEX)-1U && - face[i].texcoord[1] == (M3D_INDEX)-1U && face[i].texcoord[2] == (M3D_INDEX)-1U)) ? 0 : 1) | - (((flags & M3D_EXP_NONORMAL) || (face[i].normal[0] == (M3D_INDEX)-1U && - face[i].normal[1] == (M3D_INDEX)-1U && face[i].normal[2] == (M3D_INDEX)-1U)) ? 0 : 2); + (((flags & M3D_EXP_NOTXTCRD) || !ti_s || face[i].data.texcoord[0] == M3D_UNDEF || + face[i].data.texcoord[1] == M3D_UNDEF || face[i].data.texcoord[2] == M3D_UNDEF) ? 0 : 1) | + (((flags & M3D_EXP_NONORMAL) || face[i].data.normal[0] == M3D_UNDEF || + face[i].data.normal[1] == M3D_UNDEF || face[i].data.normal[2] == M3D_UNDEF) ? 0 : 2); *out++ = k; for(j = 0; j < 3; j++) { - out = _m3d_addidx(out, vi_s, face[i].vertex[j]); + out = _m3d_addidx(out, vi_s, vrtxidx[face[i].data.vertex[j]]); if(k & 1) - out = _m3d_addidx(out, ti_s, face[i].texcoord[j]); + out = _m3d_addidx(out, ti_s, tmapidx[face[i].data.texcoord[j]]); if(k & 2) - out = _m3d_addidx(out, vi_s, face[i].normal[j]); + out = _m3d_addidx(out, vi_s, vrtxidx[face[i].data.normal[j]]); } } - *length = (uint64_t)out - (uint64_t)((uint8_t*)h + len); + *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); len += *length; out = NULL; } + /* mathematical shapes face */ + if(model->numshape && model->shape && !(flags & M3D_EXP_NOFACE)) { + for(j = 0; j < model->numshape; j++) { + chunklen = 12 + si_s + model->shape[j].numcmd * (M3D_CMDMAXARG + 1) * 4; + h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); + if(!h) goto memerr; + memcpy((uint8_t*)h + len, "SHPE", 4); + length = (uint32_t*)((uint8_t*)h + len + 4); + out = (uint8_t*)h + len + 8; + out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->shape[j].name)); + out = _m3d_addidx(out, bi_s, model->shape[j].group); + for(i = 0; i < model->shape[j].numcmd; i++) { + cmd = &model->shape[j].cmd[i]; + if(cmd->type >= (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0])) || !cmd->arg) + continue; + cd = &m3d_commandtypes[cmd->type]; + *out++ = (cmd->type & 0x7F) | (cmd->type > 127 ? 0x80 : 0); + if(cmd->type > 127) *out++ = (cmd->type >> 7) & 0xff; + for(k = n = 0, l = cd->p; k < l; k++) { + switch(cd->a[((k - n) % (cd->p - n)) + n]) { + case m3dcp_mi_t: + out = _m3d_addidx(out, si_s, cmd->arg[k] < model->nummaterial ? + _m3d_stridx(str, numstr, model->material[cmd->arg[k]].name) : 0); + break; + case m3dcp_vc_t: + min_x = *((float*)&cmd->arg[k]); + switch(vc_s) { + case 1: *out++ = (int8_t)(min_x * 127); break; + case 2: *((int16_t*)out) = (int16_t)(min_x * 32767); out += 2; break; + case 4: *((float*)out) = min_x; out += 4; break; + case 8: *((double*)out) = min_x; out += 8; break; + } + break; + case m3dcp_hi_t: out = _m3d_addidx(out, hi_s, cmd->arg[k]); break; + case m3dcp_fi_t: out = _m3d_addidx(out, fi_s, cmd->arg[k]); break; + case m3dcp_ti_t: out = _m3d_addidx(out, ti_s, cmd->arg[k]); break; + case m3dcp_qi_t: + case m3dcp_vi_t: out = _m3d_addidx(out, vi_s, cmd->arg[k]); break; + case m3dcp_i1_t: out = _m3d_addidx(out, 1, cmd->arg[k]); break; + case m3dcp_i2_t: out = _m3d_addidx(out, 2, cmd->arg[k]); break; + case m3dcp_i4_t: out = _m3d_addidx(out, 4, cmd->arg[k]); break; + case m3dcp_va_t: out = _m3d_addidx(out, 4, cmd->arg[k]); + n = k + 1; l += (cmd->arg[k] - 1) * (cd->p - k - 1); + break; + } + } + } + *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); + len += *length; + out = NULL; + } + } + /* annotation labels */ + if(model->numlabel && model->label) { + for(i = 0, length = NULL; i < model->numlabel; i++) { + if(!i || _m3d_strcmp(sl, model->label[i].lang) || _m3d_strcmp(sn, model->label[i].name)) { + sl = model->label[i].lang; + sn = model->label[i].name; + if(length) { + *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); + len += *length; + } + chunklen = 8 + 2 * si_s + ci_s + model->numlabel * (vi_s + si_s); + h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); + if(!h) { sn = NULL; sl = NULL; goto memerr; } + memcpy((uint8_t*)h + len, "LBLS", 4); + length = (uint32_t*)((uint8_t*)h + len + 4); + out = (uint8_t*)h + len + 8; + out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->label[l].name)); + out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->label[l].lang)); + idx = _m3d_cmapidx(cmap, numcmap, model->label[i].color); + switch(ci_s) { + case 1: *out++ = (uint8_t)(idx); break; + case 2: *((uint16_t*)out) = (uint16_t)(idx); out += 2; break; + case 4: *((uint32_t*)out) = model->label[i].color; out += 4; break; + } + } + out = _m3d_addidx(out, vi_s, vrtxidx[model->label[i].vertexid]); + out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->label[l].text)); + } + if(length) { + *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); + len += *length; + } + out = NULL; + sn = sl = NULL; + } /* actions */ - if(model->numaction && model->action && numactn && actn && numbone && bone && !(flags & M3D_EXP_NOACTION)) { - l = 0; + if(model->numaction && model->action && model->numbone && model->bone && !(flags & M3D_EXP_NOACTION)) { for(j = 0; j < model->numaction; j++) { a = &model->action[j]; - chunklen = 14 + si_s + a->numframe * (4 + fi_s + maxt * (bi_s + 2 * vi_s)); + chunklen = 14 + si_s + a->numframe * (4 + fc_s + maxt * (bi_s + 2 * vi_s)); h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); if(!h) goto memerr; memcpy((uint8_t*)h + len, "ACTN", 4); @@ -4288,23 +5294,31 @@ memerr: if(face) M3D_FREE(face); *((uint32_t*)out) = (uint32_t)(a->durationmsec); out += 4; for(i = 0; i < a->numframe; i++) { *((uint32_t*)out) = (uint32_t)(a->frame[i].msec); out += 4; - out = _m3d_addidx(out, fi_s, a->frame[i].numtransform); + out = _m3d_addidx(out, fc_s, a->frame[i].numtransform); for(k = 0; k < a->frame[i].numtransform; k++) { out = _m3d_addidx(out, bi_s, a->frame[i].transform[k].boneid); - out = _m3d_addidx(out, vi_s, actn[l++]); - out = _m3d_addidx(out, vi_s, actn[l++]); + out = _m3d_addidx(out, vi_s, vrtxidx[a->frame[i].transform[k].pos]); + out = _m3d_addidx(out, vi_s, vrtxidx[a->frame[i].transform[k].ori]); } } - *length = (uint64_t)out - (uint64_t)((uint8_t*)h + len); + *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); len += *length; out = NULL; } } /* inlined assets */ - if(model->numinlined && model->inlined && (flags & M3D_EXP_INLINE)) { + if(model->numinlined && model->inlined && (numproc || (flags & M3D_EXP_INLINE))) { for(j = 0; j < model->numinlined; j++) { - if(!model->inlined[j].name || !*model->inlined[j].name || !model->inlined[j].length) + if(!model->inlined[j].name || !model->inlined[j].name[0] || model->inlined[j].length<4 || !model->inlined[j].data) continue; + if(!(flags & M3D_EXP_INLINE)) { + if(model->inlined[j].data[1] == 'P' && model->inlined[j].data[2] == 'N' && model->inlined[j].data[3] == 'G') + continue; + for(i = k = 0; i < model->numtexture; i++) { + if(!strcmp(model->inlined[j].name, model->texture[i].name)) { k = 1; break; } + } + if(k) continue; + } chunklen = 8 + si_s + model->inlined[j].length; h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); if(!h) goto memerr; @@ -4318,14 +5332,14 @@ memerr: if(face) M3D_FREE(face); } } /* extra chunks */ - if(model->numunknown && model->unknown && (flags & M3D_EXP_EXTRA)) { - for(j = 0; j < model->numunknown; j++) { - if(!model->unknown[j] || model->unknown[j]->length < 8) + if(model->numextra && model->extra && (flags & M3D_EXP_EXTRA)) { + for(j = 0; j < model->numextra; j++) { + if(!model->extra[j] || model->extra[j]->length < 8) continue; - chunklen = model->unknown[j]->length; + chunklen = model->extra[j]->length; h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); if(!h) goto memerr; - memcpy((uint8_t*)h + len, model->unknown[j], chunklen); + memcpy((uint8_t*)h + len, model->extra[j], chunklen); len += chunklen; } } @@ -4336,6 +5350,7 @@ memerr: if(face) M3D_FREE(face); len += 4; /* zlib compress */ if(!(flags & M3D_EXP_NOZLIB)) { + M3D_LOG("Deflating chunks"); z = stbi_zlib_compress((unsigned char *)h, len, (int*)&l, 9); if(z && l > 0 && l < len) { len = l; M3D_FREE(h); h = (m3dhdr_t*)z; } } @@ -4348,15 +5363,17 @@ memerr: if(face) M3D_FREE(face); memcpy(out + 8, h, len - 8); } if(size) *size = out ? len : 0; + if(vrtxidx) M3D_FREE(vrtxidx); + if(mtrlidx) M3D_FREE(mtrlidx); + if(tmapidx) M3D_FREE(tmapidx); + if(skinidx) M3D_FREE(skinidx); + if(norm) M3D_FREE(norm); if(face) M3D_FREE(face); if(cmap) M3D_FREE(cmap); if(tmap) M3D_FREE(tmap); - if(mtrl) M3D_FREE(mtrl); - if(vrtx) M3D_FREE(vrtx); - if(bone) M3D_FREE(bone); if(skin) M3D_FREE(skin); - if(actn) M3D_FREE(actn); if(str) M3D_FREE(str); + if(vrtx) M3D_FREE(vrtx); if(h) M3D_FREE(h); return out; } @@ -4397,6 +5414,14 @@ namespace M3D { this->model = m3d_load((unsigned char *)&data[0], ReadFileCB, FreeCB, mtllib.model); #else Model(); +#endif + } + Model(_unused const unsigned char *data, _unused m3dread_t ReadFileCB, + _unused m3dfree_t FreeCB, _unused M3D::Model mtllib) { +#ifndef M3D_NOIMPORTER + this->model = m3d_load((unsigned char*)data, ReadFileCB, FreeCB, mtllib.model); +#else + Model(); #endif } ~Model() { m3d_free(this->model); } @@ -4413,6 +5438,9 @@ namespace M3D { void setDescription(std::string desc) { this->model->desc = (char*)desc.c_str(); } float getScale() { return this->model->scale; } void setScale(float scale) { this->model->scale = scale; } + std::vector getPreview() { return this->model->preview.data ? + std::vector(this->model->preview.data, this->model->preview.data + this->model->preview.length) : + std::vector(); } std::vector getColorMap() { return this->model->cmap ? std::vector(this->model->cmap, this->model->cmap + this->model->numcmap) : std::vector(); } std::vector getTextureMap() { return this->model->tmap ? std::vector(this->model->tmap, @@ -4462,6 +5490,18 @@ namespace M3D { this->model->vertex + this->model->numvertex) : std::vector(); } std::vector getFace() { return this->model->face ? std::vector(this->model->face, this->model->face + this->model->numface) : std::vector(); } + std::vector getShape() { return this->model->shape ? std::vector(this->model->shape, + this->model->shape + this->model->numshape) : std::vector(); } + std::string getShapeName(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numshape && + this->model->shape[idx].name && this->model->shape[idx].name[0] ? + std::string(this->model->shape[idx].name) : nullptr; } + unsigned int getShapeGroup(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numshape ? + this->model->shape[idx].group : 0xFFFFFFFF; } + std::vector getShapeCommands(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numshape && + this->model->shape[idx].cmd ? std::vector(this->model->shape[idx].cmd, this->model->shape[idx].cmd + + this->model->shape[idx].numcmd) : std::vector(); } + std::vector getAnnotationLabels() { return this->model->label ? std::vector(this->model->label, + this->model->label + this->model->numlabel) : std::vector(); } std::vector getSkin() { return this->model->skin ? std::vector(this->model->skin, this->model->skin + this->model->numskin) : std::vector(); } std::vector getActions() { return this->model->action ? std::vector(this->model->action, @@ -4491,9 +5531,9 @@ namespace M3D { return std::vector(pose, pose + this->model->numbone); } std::vector getInlinedAssets() { return this->model->inlined ? std::vector(this->model->inlined, this->model->inlined + this->model->numinlined) : std::vector(); } - std::vector> getUnknowns() { return this->model->unknown ? - std::vector>(this->model->unknown, - this->model->unknown + this->model->numunknown) : std::vector>(); } + std::vector> getExtras() { return this->model->extra ? + std::vector>(this->model->extra, + this->model->extra + this->model->numextra) : std::vector>(); } std::vector Save(_unused int quality, _unused int flags) { #ifdef M3D_EXPORTER unsigned int size; @@ -4513,6 +5553,7 @@ namespace M3D { public: Model(const std::string &data, m3dread_t ReadFileCB, m3dfree_t FreeCB); Model(const std::vector data, m3dread_t ReadFileCB, m3dfree_t FreeCB); + Model(const unsigned char *data, m3dread_t ReadFileCB, m3dfree_t FreeCB); Model(); ~Model(); @@ -4528,6 +5569,7 @@ namespace M3D { void setDescription(std::string desc); float getScale(); void setScale(float scale); + std::vector getPreview(); std::vector getColorMap(); std::vector getTextureMap(); std::vector getTextures(); @@ -4542,6 +5584,11 @@ namespace M3D { m3dtx_t* getMaterialPropertyMap(int idx, int type); std::vector getVertices(); std::vector getFace(); + std::vector getShape(); + std::string getShapeName(int idx); + unsigned int getShapeGroup(int idx); + std::vector getShapeCommands(int idx); + std::vector getAnnotationLabels(); std::vector getSkin(); std::vector getActions(); std::string getActionName(int aidx); @@ -4552,7 +5599,7 @@ namespace M3D { std::vector getActionFrame(int aidx, int fidx, std::vector skeleton); std::vector getActionPose(int aidx, unsigned int msec); std::vector getInlinedAssets(); - std::vector> getUnknowns(); + std::vector> getExtras(); std::vector Save(int quality, int flags); }; diff --git a/Engine/lib/assimp/code/MD2/MD2FileData.h b/Engine/lib/assimp/code/MD2/MD2FileData.h index 9fcb8b0e2..911cd4b98 100644 --- a/Engine/lib/assimp/code/MD2/MD2FileData.h +++ b/Engine/lib/assimp/code/MD2/MD2FileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/MD2/MD2Loader.cpp b/Engine/lib/assimp/code/MD2/MD2Loader.cpp index 7023c0fa3..473ab99bc 100644 --- a/Engine/lib/assimp/code/MD2/MD2Loader.cpp +++ b/Engine/lib/assimp/code/MD2/MD2Loader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/MD2/MD2Loader.h b/Engine/lib/assimp/code/MD2/MD2Loader.h index a3863f366..cbebc90a4 100644 --- a/Engine/lib/assimp/code/MD2/MD2Loader.h +++ b/Engine/lib/assimp/code/MD2/MD2Loader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/MD2/MD2NormalTable.h b/Engine/lib/assimp/code/MD2/MD2NormalTable.h index f82b57683..c5c790872 100644 --- a/Engine/lib/assimp/code/MD2/MD2NormalTable.h +++ b/Engine/lib/assimp/code/MD2/MD2NormalTable.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/MD3/MD3FileData.h b/Engine/lib/assimp/code/MD3/MD3FileData.h index 2acd6631f..a98af199c 100644 --- a/Engine/lib/assimp/code/MD3/MD3FileData.h +++ b/Engine/lib/assimp/code/MD3/MD3FileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/MD3/MD3Loader.cpp b/Engine/lib/assimp/code/MD3/MD3Loader.cpp index 1e78b6e05..2051ecdda 100644 --- a/Engine/lib/assimp/code/MD3/MD3Loader.cpp +++ b/Engine/lib/assimp/code/MD3/MD3Loader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team @@ -973,7 +973,7 @@ void MD3Importer::InternReadFile( const std::string& pFile, aiScene* pScene, IOS AI_SWAP2( pcVertices[i].Z ); AI_SWAP4( pcUVs[i].U ); - AI_SWAP4( pcUVs[i].U ); + AI_SWAP4( pcUVs[i].V ); } for (uint32_t i = 0; i < pcSurfaces->NUM_TRIANGLES;++i) { AI_SWAP4(pcTriangles[i].INDEXES[0]); diff --git a/Engine/lib/assimp/code/MD3/MD3Loader.h b/Engine/lib/assimp/code/MD3/MD3Loader.h index 01b840228..8d8304345 100644 --- a/Engine/lib/assimp/code/MD3/MD3Loader.h +++ b/Engine/lib/assimp/code/MD3/MD3Loader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/MD4/MD4FileData.h b/Engine/lib/assimp/code/MD4/MD4FileData.h index ed3dc65e7..880df3230 100644 --- a/Engine/lib/assimp/code/MD4/MD4FileData.h +++ b/Engine/lib/assimp/code/MD4/MD4FileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2010, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/MD5/MD5Loader.cpp b/Engine/lib/assimp/code/MD5/MD5Loader.cpp index a4aed8d70..8c41794e7 100644 --- a/Engine/lib/assimp/code/MD5/MD5Loader.cpp +++ b/Engine/lib/assimp/code/MD5/MD5Loader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/MD5/MD5Loader.h b/Engine/lib/assimp/code/MD5/MD5Loader.h index e15cc3fb9..196ffb69a 100644 --- a/Engine/lib/assimp/code/MD5/MD5Loader.h +++ b/Engine/lib/assimp/code/MD5/MD5Loader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/MD5/MD5Parser.cpp b/Engine/lib/assimp/code/MD5/MD5Parser.cpp index 37490212f..0d3b9c74a 100644 --- a/Engine/lib/assimp/code/MD5/MD5Parser.cpp +++ b/Engine/lib/assimp/code/MD5/MD5Parser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/MD5/MD5Parser.h b/Engine/lib/assimp/code/MD5/MD5Parser.h index f7ff5303f..692cb72ba 100644 --- a/Engine/lib/assimp/code/MD5/MD5Parser.h +++ b/Engine/lib/assimp/code/MD5/MD5Parser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/MDC/MDCFileData.h b/Engine/lib/assimp/code/MDC/MDCFileData.h index 052473158..9ec73c170 100644 --- a/Engine/lib/assimp/code/MDC/MDCFileData.h +++ b/Engine/lib/assimp/code/MDC/MDCFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/MDC/MDCLoader.cpp b/Engine/lib/assimp/code/MDC/MDCLoader.cpp index 084ec6024..db4cdef54 100644 --- a/Engine/lib/assimp/code/MDC/MDCLoader.cpp +++ b/Engine/lib/assimp/code/MDC/MDCLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team @@ -355,7 +355,7 @@ void MDCImporter::InternReadFile( // swap all texture coordinates for (unsigned int i = 0; i < pcSurface->ulNumVertices;++i) { - AI_SWAP4( pcUVs->v ); + AI_SWAP4( pcUVs->u ); AI_SWAP4( pcUVs->v ); } diff --git a/Engine/lib/assimp/code/MDC/MDCLoader.h b/Engine/lib/assimp/code/MDC/MDCLoader.h index a21b8a55a..abd23bb19 100644 --- a/Engine/lib/assimp/code/MDC/MDCLoader.h +++ b/Engine/lib/assimp/code/MDC/MDCLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/MDL/HalfLife/HL1FileData.h b/Engine/lib/assimp/code/MDL/HalfLife/HL1FileData.h new file mode 100644 index 000000000..a3cbb3439 --- /dev/null +++ b/Engine/lib/assimp/code/MDL/HalfLife/HL1FileData.h @@ -0,0 +1,600 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +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. +--------------------------------------------------------------------------- +*/ + +/** @file HL1FileData.h + * @brief Definition of in-memory structures for the + * Half-Life 1 MDL file format. + */ + +#ifndef AI_HL1FILEDATA_INCLUDED +#define AI_HL1FILEDATA_INCLUDED + +#include "HalfLifeMDLBaseHeader.h" + +#include +#include + +namespace Assimp { +namespace MDL { +namespace HalfLife { + +using vec3_t = float[3]; + +/** \struct Header_HL1 + * \brief Data structure for the HL1 MDL file header. + */ +struct Header_HL1 : HalfLifeMDLBaseHeader { + //! The model name. + char name[64]; + + //! The total file size in bytes. + int32_t length; + + //! Ideal eye position. + vec3_t eyeposition; + + //! Ideal movement hull size. + vec3_t min; + vec3_t max; + + //! Clipping bounding box. + vec3_t bbmin; + vec3_t bbmax; + + //! Was "flags". + int32_t unused; + + //! The number of bones. + int32_t numbones; + + //! Offset to the first bone chunk. + int32_t boneindex; + + //! The number of bone controllers. + int32_t numbonecontrollers; + + //! Offset to the first bone controller chunk. + int32_t bonecontrollerindex; + + //! The number of hitboxes. + int32_t numhitboxes; + + //! Offset to the first hitbox chunk. + int32_t hitboxindex; + + //! The number of sequences. + int32_t numseq; + + //! Offset to the first sequence description chunk. + int32_t seqindex; + + //! The number of sequence groups. + int32_t numseqgroups; + + //! Offset to the first sequence group chunk. + int32_t seqgroupindex; + + //! The number of textures. + int32_t numtextures; + + //! Offset to the first texture chunk. + int32_t textureindex; + + //! Offset to the first texture's image data. + int32_t texturedataindex; + + //! The number of replaceable textures. + int32_t numskinref; + + //! The number of skin families. + int32_t numskinfamilies; + + //! Offset to the first replaceable texture. + int32_t skinindex; + + //! The number of bodyparts. + int32_t numbodyparts; + + //! Offset the the first bodypart. + int32_t bodypartindex; + + //! The number of attachments. + int32_t numattachments; + + //! Offset the the first attachment chunk. + int32_t attachmentindex; + + //! Was "soundtable". + int32_t unused2; + + //! Was "soundindex". + int32_t unused3; + + //! Was "soundgroups". + int32_t unused4; + + //! Was "soundgroupindex". + int32_t unused5; + + //! The number of nodes in the sequence transition graph. + int32_t numtransitions; + + //! Offset the the first sequence transition. + int32_t transitionindex; +} PACK_STRUCT; + +/** \struct SequenceHeader_HL1 + * \brief Data structure for the file header of a demand loaded + * HL1 MDL sequence group file. + */ +struct SequenceHeader_HL1 : HalfLifeMDLBaseHeader { + //! The sequence group file name. + char name[64]; + + //! The total file size in bytes. + int32_t length; +} PACK_STRUCT; + +/** \struct Bone_HL1 + * \brief Data structure for a bone in HL1 MDL files. + */ +struct Bone_HL1 { + //! The bone name. + char name[32]; + + //! The parent bone index. (-1) If it has no parent. + int32_t parent; + + //! Was "flags". + int32_t unused; + + //! Available bone controller per motion type. + //! (-1) if no controller is available. + int32_t bonecontroller[6]; + + /*! Default position and rotation values where + * scale[0] = position.X + * scale[1] = position.Y + * scale[2] = position.Z + * scale[3] = rotation.X + * scale[4] = rotation.Y + * scale[5] = rotation.Z + */ + float value[6]; + + /*! Compressed scale values where + * scale[0] = position.X scale + * scale[1] = position.Y scale + * scale[2] = position.Z scale + * scale[3] = rotation.X scale + * scale[4] = rotation.Y scale + * scale[5] = rotation.Z scale + */ + float scale[6]; +} PACK_STRUCT; + +/** \struct BoneController_HL1 + * \brief Data structure for a bone controller in HL1 MDL files. + */ +struct BoneController_HL1 { + //! Bone affected by this controller. + int32_t bone; + + //! The motion type. + int32_t type; + + //! The minimum and maximum values. + float start; + float end; + + // Was "rest". + int32_t unused; + + // The bone controller channel. + int32_t index; +} PACK_STRUCT; + +/** \struct Hitbox_HL1 + * \brief Data structure for a hitbox in HL1 MDL files. + */ +struct Hitbox_HL1 { + //! The bone this hitbox follows. + int32_t bone; + + //! The hit group. + int32_t group; + + //! The hitbox minimum and maximum extents. + vec3_t bbmin; + vec3_t bbmax; +} PACK_STRUCT; + +/** \struct SequenceGroup_HL1 + * \brief Data structure for a sequence group in HL1 MDL files. + */ +struct SequenceGroup_HL1 { + //! A textual name for this sequence group. + char label[32]; + + //! The file name. + char name[64]; + + //! Was "cache". + int32_t unused; + + //! Was "data". + int32_t unused2; +} PACK_STRUCT; + +//! The type of blending for a sequence. +enum SequenceBlendMode_HL1 { + NoBlend = 1, + TwoWayBlending = 2, + FourWayBlending = 4, +}; + +/** \struct SequenceDesc_HL1 + * \brief Data structure for a sequence description in HL1 MDL files. + */ +struct SequenceDesc_HL1 { + //! The sequence name. + char label[32]; + + //! Frames per second. + float fps; + + //! looping/non-looping flags. + int32_t flags; + + //! The sequence activity. + int32_t activity; + + //! The sequence activity weight. + int32_t actweight; + + //! The number of animation events. + int32_t numevents; + + //! Offset the the first animation event chunk. + int32_t eventindex; + + //! The number of frames in the sequence. + int32_t numframes; + + //! Was "numpivots". + int32_t unused; + + //! Was "pivotindex". + int32_t unused2; + + //! Linear motion type. + int32_t motiontype; + + //! Linear motion bone. + int32_t motionbone; + + //! Linear motion. + vec3_t linearmovement; + + //! Was "automoveposindex". + int32_t unused3; + + //! Was "automoveangleindex". + int32_t unused4; + + //! The sequence minimum and maximum extents. + vec3_t bbmin; + vec3_t bbmax; + + //! The number of blend animations. + int32_t numblends; + + //! Offset to first the AnimValueOffset_HL1 chunk. + //! This offset is relative to the SequenceHeader_HL1 of the file + //! that contains the animation data. + int32_t animindex; + + //! The motion type of each blend controller. + int32_t blendtype[2]; + + //! The starting value of each blend controller. + float blendstart[2]; + + //! The ending value of each blend controller. + float blendend[2]; + + //! Was "blendparent". + int32_t unused5; + + //! The sequence group. + int32_t seqgroup; + + //! The node at entry in the sequence transition graph. + int32_t entrynode; + + //! The node at exit in the sequence transition graph. + int32_t exitnode; + + //! Transition rules. + int32_t nodeflags; + + //! Was "nextseq" + int32_t unused6; +} PACK_STRUCT; + +/** \struct AnimEvent_HL1 + * \brief Data structure for an animation event in HL1 MDL files. + */ +struct AnimEvent_HL1 { + //! The frame at which this animation event occurs. + int32_t frame; + + //! The script event type. + int32_t event; + + //! was "type" + int32_t unused; + + //! Options. Could be path to sound WAVE files. + char options[64]; +} PACK_STRUCT; + +/** \struct Attachment_HL1 + * \brief Data structure for an attachment in HL1 MDL files. + */ +struct Attachment_HL1 { + //! Was "name". + char unused[32]; + + //! Was "type". + int32_t unused2; + + //! The bone this attachment follows. + int32_t bone; + + //! The attachment origin. + vec3_t org; + + //! Was "vectors" + vec3_t unused3[3]; +} PACK_STRUCT; + +/** \struct AnimValueOffset_HL1 + * \brief Data structure to hold offsets (one per motion type) + * to the first animation frame value for a single bone + * in HL1 MDL files. + */ +struct AnimValueOffset_HL1 { + unsigned short offset[6]; +} PACK_STRUCT; + +/** \struct AnimValue_HL1 + * \brief Data structure for an animation frame in HL1 MDL files. + */ +union AnimValue_HL1 { + struct { + uint8_t valid; + uint8_t total; + } num; + short value; +} PACK_STRUCT; + +/** \struct Bodypart_HL1 + * \brief Data structure for a bodypart in HL1 MDL files. + */ +struct Bodypart_HL1 { + //! The bodypart name. + char name[64]; + + //! The number of available models for this bodypart. + int32_t nummodels; + + //! Used to convert from a global model index + //! to a local bodypart model index. + int32_t base; + + //! The offset to the first model chunk. + int32_t modelindex; +} PACK_STRUCT; + +/** \struct Texture_HL1 + * \brief Data structure for a texture in HL1 MDL files. + */ +struct Texture_HL1 { + //! Texture file name. + char name[64]; + + //! Texture flags. + int32_t flags; + + //! Texture width in pixels. + int32_t width; + + //! Texture height in pixels. + int32_t height; + + //! Offset to the image data. + //! This offset is relative to the texture file header. + int32_t index; +} PACK_STRUCT; + +/** \struct Model_HL1 + * \brief Data structure for a model in HL1 MDL files. + */ +struct Model_HL1 { + //! Model name. + char name[64]; + + //! Was "type". + int32_t unused; + + //! Was "boundingradius". + float unused2; + + //! The number of meshes in the model. + int32_t nummesh; + + //! Offset to the first mesh chunk. + int32_t meshindex; + + //! The number of unique vertices. + int32_t numverts; + + //! Offset to the vertex bone array. + int32_t vertinfoindex; + + //! Offset to the vertex array. + int32_t vertindex; + + //! The number of unique normals. + int32_t numnorms; + + //! Offset to the normal bone array. + int32_t norminfoindex; + + //! Offset to the normal array. + int32_t normindex; + + //! Was "numgroups". + int32_t unused3; + + //! Was "groupindex". + int32_t unused4; +} PACK_STRUCT; + +/** \struct Mesh_HL1 + * \brief Data structure for a mesh in HL1 MDL files. + */ +struct Mesh_HL1 { + //! Can be interpreted as the number of triangles in the mesh. + int32_t numtris; + + //! Offset to the start of the tris sequence. + int32_t triindex; + + //! The skin index. + int32_t skinref; + + //! The number of normals in the mesh. + int32_t numnorms; + + //! Was "normindex". + int32_t unused; +} PACK_STRUCT; + +/** \struct Trivert + * \brief Data structure for a trivert in HL1 MDL files. + */ +struct Trivert { + //! Index into Model_HL1 vertex array. + short vertindex; + + //! Index into Model_HL1 normal array. + short normindex; + + //! Texture coordinates in absolute space (unnormalized). + short s, t; +} PACK_STRUCT; + +#include + +#if (!defined AI_MDL_HL1_VERSION) +#define AI_MDL_HL1_VERSION 10 +#endif +#if (!defined AI_MDL_HL1_MAX_TRIANGLES) +#define AI_MDL_HL1_MAX_TRIANGLES 20000 +#endif +#if (!defined AI_MDL_HL1_MAX_VERTICES) +#define AI_MDL_HL1_MAX_VERTICES 2048 +#endif +#if (!defined AI_MDL_HL1_MAX_SEQUENCES) +#define AI_MDL_HL1_MAX_SEQUENCES 2048 +#endif +#if (!defined AI_MDL_HL1_MAX_SEQUENCE_GROUPS) +#define AI_MDL_HL1_MAX_SEQUENCE_GROUPS 32 +#endif +#if (!defined AI_MDL_HL1_MAX_TEXTURES) +#define AI_MDL_HL1_MAX_TEXTURES 100 +#endif +#if (!defined AI_MDL_HL1_MAX_SKIN_FAMILIES) +#define AI_MDL_HL1_MAX_SKIN_FAMILIES 100 +#endif +#if (!defined AI_MDL_HL1_MAX_BONES) +#define AI_MDL_HL1_MAX_BONES 128 +#endif +#if (!defined AI_MDL_HL1_MAX_BODYPARTS) +#define AI_MDL_HL1_MAX_BODYPARTS 32 +#endif +#if (!defined AI_MDL_HL1_MAX_MODELS) +#define AI_MDL_HL1_MAX_MODELS 32 +#endif +#if (!defined AI_MDL_HL1_MAX_MESHES) +#define AI_MDL_HL1_MAX_MESHES 256 +#endif +#if (!defined AI_MDL_HL1_MAX_EVENTS) +#define AI_MDL_HL1_MAX_EVENTS 1024 +#endif +#if (!defined AI_MDL_HL1_MAX_BONE_CONTROLLERS) +#define AI_MDL_HL1_MAX_BONE_CONTROLLERS 8 +#endif +#if (!defined AI_MDL_HL1_MAX_ATTACHMENTS) +#define AI_MDL_HL1_MAX_ATTACHMENTS 512 +#endif + +// lighting options +#if (!defined AI_MDL_HL1_STUDIO_NF_FLATSHADE) +#define AI_MDL_HL1_STUDIO_NF_FLATSHADE 0x0001 +#endif +#if (!defined AI_MDL_HL1_STUDIO_NF_CHROME) +#define AI_MDL_HL1_STUDIO_NF_CHROME 0x0002 +#endif +#if (!defined AI_MDL_HL1_STUDIO_NF_ADDITIVE) +#define AI_MDL_HL1_STUDIO_NF_ADDITIVE 0x0020 +#endif +#if (!defined AI_MDL_HL1_STUDIO_NF_MASKED) +#define AI_MDL_HL1_STUDIO_NF_MASKED 0x0040 +#endif + +} // namespace HalfLife +} // namespace MDL +} // namespace Assimp + +#endif // AI_HL1FILEDATA_INCLUDED diff --git a/Engine/lib/assimp/code/MDL/HalfLife/HL1ImportDefinitions.h b/Engine/lib/assimp/code/MDL/HalfLife/HL1ImportDefinitions.h new file mode 100644 index 000000000..29b1cdceb --- /dev/null +++ b/Engine/lib/assimp/code/MDL/HalfLife/HL1ImportDefinitions.h @@ -0,0 +1,64 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +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. +--------------------------------------------------------------------------- +*/ + +/** @file HL1ImportDefinitions.h + * @brief HL1 MDL loader specific definitions. + */ + +#ifndef AI_MDL_HL1_IMPORT_DEFINITIONS_INCLUDED +#define AI_MDL_HL1_IMPORT_DEFINITIONS_INCLUDED + +#define AI_MDL_HL1_NODE_ROOT "" +#define AI_MDL_HL1_NODE_BODYPARTS "" +#define AI_MDL_HL1_NODE_BONES "" +#define AI_MDL_HL1_NODE_BONE_CONTROLLERS "" +#define AI_MDL_HL1_NODE_SEQUENCE_INFOS "" +#define AI_MDL_HL1_NODE_SEQUENCE_GROUPS "" +#define AI_MDL_HL1_NODE_SEQUENCE_TRANSITION_GRAPH "" +#define AI_MDL_HL1_NODE_ATTACHMENTS "" +#define AI_MDL_HL1_NODE_HITBOXES "" +#define AI_MDL_HL1_NODE_GLOBAL_INFO "" +#define AI_MDL_HL1_NODE_ANIMATION_EVENTS "AnimationEvents" +#define AI_MDL_HL1_NODE_BLEND_CONTROLLERS "BlendControllers" + +#define AI_MDL_HL1_MATKEY_CHROME(type, N) "$mat.HL1.chrome", type, N + +#endif // AI_MDL_HL1_IMPORT_DEFINITIONS_INCLUDED diff --git a/Engine/lib/assimp/code/MDL/HalfLife/HL1ImportSettings.h b/Engine/lib/assimp/code/MDL/HalfLife/HL1ImportSettings.h new file mode 100644 index 000000000..50be1f366 --- /dev/null +++ b/Engine/lib/assimp/code/MDL/HalfLife/HL1ImportSettings.h @@ -0,0 +1,85 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +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. +--------------------------------------------------------------------------- +*/ + +/** @file HL1ImportSettings.h + * @brief Half-Life 1 MDL loader configuration settings. + */ + +#ifndef AI_HL1IMPORTSETTINGS_INCLUDED +#define AI_HL1IMPORTSETTINGS_INCLUDED + +#include + +namespace Assimp { +namespace MDL { +namespace HalfLife { + +struct HL1ImportSettings { + HL1ImportSettings() : + read_animations(false), + read_animation_events(false), + read_blend_controllers(false), + read_sequence_groups_info(false), + read_sequence_transitions(false), + read_attachments(false), + read_bone_controllers(false), + read_hitboxes(false), + read_textures(false), + read_misc_global_info(false) { + } + + bool read_animations; + bool read_animation_events; + bool read_blend_controllers; + bool read_sequence_groups_info; + bool read_sequence_transitions; + bool read_attachments; + bool read_bone_controllers; + bool read_hitboxes; + bool read_textures; + bool read_misc_global_info; +}; + +} // namespace HalfLife +} // namespace MDL +} // namespace Assimp + +#endif // AI_HL1IMPORTSETTINGS_INCLUDED diff --git a/Engine/lib/assimp/code/MDL/HalfLife/HL1MDLLoader.cpp b/Engine/lib/assimp/code/MDL/HalfLife/HL1MDLLoader.cpp new file mode 100644 index 000000000..c18528e59 --- /dev/null +++ b/Engine/lib/assimp/code/MDL/HalfLife/HL1MDLLoader.cpp @@ -0,0 +1,1348 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +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. +--------------------------------------------------------------------------- +*/ + +/** @file HL1MDLLoader.cpp + * @brief Implementation for the Half-Life 1 MDL loader. + */ + +#include "HL1MDLLoader.h" +#include "HL1ImportDefinitions.h" +#include "HL1MeshTrivert.h" +#include "UniqueNameGenerator.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef MDL_HALFLIFE_LOG_WARN_HEADER +#undef MDL_HALFLIFE_LOG_WARN_HEADER +#endif +#define MDL_HALFLIFE_LOG_HEADER "[Half-Life 1 MDL] " +#include "LogFunctions.h" + +namespace Assimp { +namespace MDL { +namespace HalfLife { + +// ------------------------------------------------------------------------------------------------ +HL1MDLLoader::HL1MDLLoader( + aiScene *scene, + IOSystem *io, + const unsigned char *buffer, + const std::string &file_path, + const HL1ImportSettings &import_settings) : + scene_(scene), + io_(io), + buffer_(buffer), + file_path_(file_path), + import_settings_(import_settings), + header_(nullptr), + texture_header_(nullptr), + anim_headers_(nullptr), + texture_buffer_(nullptr), + anim_buffers_(nullptr), + num_sequence_groups_(0), + rootnode_children_(), + unique_name_generator_(), + unique_sequence_names_(), + unique_sequence_groups_names_(), + temp_bones_(), + num_blend_controllers_(0), + total_models_(0) { + load_file(); +} + +// ------------------------------------------------------------------------------------------------ +HL1MDLLoader::~HL1MDLLoader() { + release_resources(); +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::release_resources() { + if (buffer_ != texture_buffer_) { + delete[] texture_buffer_; + texture_buffer_ = nullptr; + } + + if (num_sequence_groups_ && anim_buffers_) { + for (int i = 1; i < num_sequence_groups_; ++i) { + if (anim_buffers_[i]) { + delete[] anim_buffers_[i]; + anim_buffers_[i] = nullptr; + } + } + + delete[] anim_buffers_; + anim_buffers_ = nullptr; + } + + if (anim_headers_) { + delete[] anim_headers_; + anim_headers_ = nullptr; + } + + // Root has some children nodes. so let's proceed them + if (!rootnode_children_.empty()) { + // Here, it means that the nodes were not added to the + // scene root node. We still have to delete them. + for (auto it = rootnode_children_.begin(); it != rootnode_children_.end(); ++it) { + if (*it) { + delete *it; + } + } + // Ensure this happens only once. + rootnode_children_.clear(); + } +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::load_file() { + try { + header_ = (const Header_HL1 *)buffer_; + validate_header(header_, false); + + // Create the root scene node. + scene_->mRootNode = new aiNode(AI_MDL_HL1_NODE_ROOT); + + load_texture_file(); + + if (import_settings_.read_animations) { + load_sequence_groups_files(); + } + + read_textures(); + read_skins(); + + read_bones(); + read_meshes(); + + if (import_settings_.read_animations) { + read_sequence_groups_info(); + read_animations(); + read_sequence_infos(); + if (import_settings_.read_sequence_transitions) + read_sequence_transitions(); + } + + if (import_settings_.read_attachments) { + read_attachments(); + } + + if (import_settings_.read_hitboxes) { + read_hitboxes(); + } + + if (import_settings_.read_bone_controllers) { + read_bone_controllers(); + } + + read_global_info(); + + if (!header_->numbodyparts) { + // This could be an MDL external texture file. In this case, + // add this flag to allow the scene to be loaded even if it + // has no meshes. + scene_->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; + } + + // Append children to root node. + if (rootnode_children_.size()) { + scene_->mRootNode->addChildren( + static_cast(rootnode_children_.size()), + rootnode_children_.data()); + + // Clear the list of nodes so they will not be destroyed + // when resources are released. + rootnode_children_.clear(); + } + + release_resources(); + + } catch (...) { + release_resources(); + throw; + } +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::validate_header(const Header_HL1 *header, bool is_texture_header) { + if (is_texture_header) { + // Every single Half-Life model is assumed to have at least one texture. + if (!header->numtextures) { + throw DeadlyImportError(MDL_HALFLIFE_LOG_HEADER "There are no textures in the file"); + } + + if (header->numtextures > AI_MDL_HL1_MAX_TEXTURES) { + log_warning_limit_exceeded(header->numtextures, "textures"); + } + + if (header->numskinfamilies > AI_MDL_HL1_MAX_SKIN_FAMILIES) { + log_warning_limit_exceeded(header->numskinfamilies, "skin families"); + } + + } else { + + if (header->numbodyparts > AI_MDL_HL1_MAX_BODYPARTS) { + log_warning_limit_exceeded(header->numbodyparts, "bodyparts"); + } + + if (header->numbones > AI_MDL_HL1_MAX_BONES) { + log_warning_limit_exceeded(header->numbones, "bones"); + } + + if (header->numbonecontrollers > AI_MDL_HL1_MAX_BONE_CONTROLLERS) { + log_warning_limit_exceeded(header->numbonecontrollers, "bone controllers"); + } + + if (header->numseq > AI_MDL_HL1_MAX_SEQUENCES) { + log_warning_limit_exceeded(header->numseq, "sequences"); + } + + if (header->numseqgroups > AI_MDL_HL1_MAX_SEQUENCE_GROUPS) { + log_warning_limit_exceeded(header->numseqgroups, "sequence groups"); + } + + if (header->numattachments > AI_MDL_HL1_MAX_ATTACHMENTS) { + log_warning_limit_exceeded(header->numattachments, "attachments"); + } + } +} + +// ------------------------------------------------------------------------------------------------ +/* + Load textures. + + There are two ways for textures to be stored in a Half-Life model: + + 1. Directly in the MDL file (filePath) or + 2. In an external MDL file. + + Due to the way StudioMDL works (tool used to compile SMDs into MDLs), + it is assumed that an external texture file follows the naming + convention: T.mdl. Note the extra (T) at the end of the + model name. + + .e.g For a given model named MyModel.mdl + + The external texture file name would be MyModelT.mdl +*/ +void HL1MDLLoader::load_texture_file() { + if (header_->numtextures == 0) { + // Load an external MDL texture file. + std::string texture_file_path = + DefaultIOSystem::absolutePath(file_path_) + io_->getOsSeparator() + + DefaultIOSystem::completeBaseName(file_path_) + "T." + + BaseImporter::GetExtension(file_path_); + + load_file_into_buffer(texture_file_path, texture_buffer_); + } else { + // Model has no external texture file. This means the texture is stored inside the main MDL file. + texture_buffer_ = const_cast(buffer_); + } + + texture_header_ = (const Header_HL1 *)texture_buffer_; + + // Validate texture header. + validate_header(texture_header_, true); +} + +// ------------------------------------------------------------------------------------------------ +/* + Load sequence group files if any. + + Due to the way StudioMDL works (tool used to compile SMDs into MDLs), + it is assumed that a sequence group file follows the naming + convention: 0X.mdl. Note the extra (0X) at the end of + the model name, where (X) is the sequence group. + + .e.g For a given model named MyModel.mdl + + Sequence group 1 => MyModel01.mdl + Sequence group 2 => MyModel02.mdl + Sequence group X => MyModel0X.mdl + +*/ +void HL1MDLLoader::load_sequence_groups_files() { + if (header_->numseqgroups <= 1) { + return; + } + + num_sequence_groups_ = header_->numseqgroups; + + anim_buffers_ = new unsigned char *[num_sequence_groups_]; + anim_headers_ = new SequenceHeader_HL1 *[num_sequence_groups_]; + for (int i = 0; i < num_sequence_groups_; ++i) { + anim_buffers_[i] = nullptr; + anim_headers_[i] = nullptr; + } + + std::string file_path_without_extension = + DefaultIOSystem::absolutePath(file_path_) + + io_->getOsSeparator() + + DefaultIOSystem::completeBaseName(file_path_); + + for (int i = 1; i < num_sequence_groups_; ++i) { + std::stringstream ss; + ss << file_path_without_extension; + ss << std::setw(2) << std::setfill('0') << i; + ss << '.' << BaseImporter::GetExtension(file_path_); + + std::string sequence_file_path = ss.str(); + + load_file_into_buffer(sequence_file_path, anim_buffers_[i]); + + anim_headers_[i] = (SequenceHeader_HL1 *)anim_buffers_[i]; + } +} + +// ------------------------------------------------------------------------------------------------ +// Read an MDL texture. +void HL1MDLLoader::read_texture(const Texture_HL1 *ptexture, + uint8_t *data, uint8_t *pal, aiTexture *pResult, + aiColor3D &last_palette_color) { + pResult->mFilename = ptexture->name; + pResult->mWidth = static_cast(ptexture->width); + pResult->mHeight = static_cast(ptexture->height); + pResult->achFormatHint[0] = 'r'; + pResult->achFormatHint[1] = 'g'; + pResult->achFormatHint[2] = 'b'; + pResult->achFormatHint[3] = 'a'; + pResult->achFormatHint[4] = '8'; + pResult->achFormatHint[5] = '8'; + pResult->achFormatHint[6] = '8'; + pResult->achFormatHint[7] = '8'; + pResult->achFormatHint[8] = '\0'; + + const size_t num_pixels = pResult->mWidth * pResult->mHeight; + aiTexel *out = pResult->pcData = new aiTexel[num_pixels]; + + // Convert indexed 8 bit to 32 bit RGBA. + for (size_t i = 0; i < num_pixels; ++i, ++out) { + out->r = pal[data[i] * 3]; + out->g = pal[data[i] * 3 + 1]; + out->b = pal[data[i] * 3 + 2]; + out->a = 255; + } + + // Get the last palette color. + last_palette_color.r = pal[255 * 3]; + last_palette_color.g = pal[255 * 3 + 1]; + last_palette_color.b = pal[255 * 3 + 2]; +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::read_textures() { + const Texture_HL1 *ptexture = (const Texture_HL1 *)((uint8_t *)texture_header_ + texture_header_->textureindex); + unsigned char *pin = texture_buffer_; + + scene_->mNumTextures = scene_->mNumMaterials = texture_header_->numtextures; + scene_->mTextures = new aiTexture *[scene_->mNumTextures]; + scene_->mMaterials = new aiMaterial *[scene_->mNumMaterials]; + + for (int i = 0; i < texture_header_->numtextures; ++i) { + scene_->mTextures[i] = new aiTexture(); + + aiColor3D last_palette_color; + read_texture(&ptexture[i], + pin + ptexture[i].index, + pin + ptexture[i].width * ptexture[i].height + ptexture[i].index, + scene_->mTextures[i], + last_palette_color); + + aiMaterial *scene_material = scene_->mMaterials[i] = new aiMaterial(); + + const aiTextureType texture_type = aiTextureType_DIFFUSE; + aiString texture_name(ptexture[i].name); + scene_material->AddProperty(&texture_name, AI_MATKEY_TEXTURE(texture_type, 0)); + + // Is this a chrome texture? + int chrome = ptexture[i].flags & AI_MDL_HL1_STUDIO_NF_CHROME ? 1 : 0; + scene_material->AddProperty(&chrome, 1, AI_MDL_HL1_MATKEY_CHROME(texture_type, 0)); + + if (ptexture[i].flags & AI_MDL_HL1_STUDIO_NF_FLATSHADE) { + // Flat shading. + const aiShadingMode shading_mode = aiShadingMode_Flat; + scene_material->AddProperty(&shading_mode, 1, AI_MATKEY_SHADING_MODEL); + } + + if (ptexture[i].flags & AI_MDL_HL1_STUDIO_NF_ADDITIVE) { + // Additive texture. + const aiBlendMode blend_mode = aiBlendMode_Additive; + scene_material->AddProperty(&blend_mode, 1, AI_MATKEY_BLEND_FUNC); + } else if (ptexture[i].flags & AI_MDL_HL1_STUDIO_NF_MASKED) { + // Texture with 1 bit alpha test. + const aiTextureFlags use_alpha = aiTextureFlags_UseAlpha; + scene_material->AddProperty(&use_alpha, 1, AI_MATKEY_TEXFLAGS(texture_type, 0)); + scene_material->AddProperty(&last_palette_color, 1, AI_MATKEY_COLOR_TRANSPARENT); + } + } +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::read_skins() { + // Read skins, if any. + if (texture_header_->numskinfamilies <= 1) { + return; + } + + // Pointer to base texture index. + short *default_skin_ptr = (short *)((uint8_t *)texture_header_ + texture_header_->skinindex); + + // Start at first replacement skin. + short *replacement_skin_ptr = default_skin_ptr + texture_header_->numskinref; + + for (int i = 1; i < texture_header_->numskinfamilies; ++i, replacement_skin_ptr += texture_header_->numskinref) { + for (int j = 0; j < texture_header_->numskinref; ++j) { + if (default_skin_ptr[j] != replacement_skin_ptr[j]) { + // Save replacement textures. + aiString skinMaterialId(scene_->mTextures[replacement_skin_ptr[j]]->mFilename); + scene_->mMaterials[default_skin_ptr[j]]->AddProperty(&skinMaterialId, AI_MATKEY_TEXTURE_DIFFUSE(i)); + } + } + } +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::read_bones() { + if (!header_->numbones) { + return; + } + + const Bone_HL1 *pbone = (const Bone_HL1 *)((uint8_t *)header_ + header_->boneindex); + + std::vector unique_bones_names(header_->numbones); + for (int i = 0; i < header_->numbones; ++i) { + unique_bones_names[i] = pbone[i].name; + } + + // Ensure bones have unique names. + unique_name_generator_.set_template_name("Bone"); + unique_name_generator_.make_unique(unique_bones_names); + + temp_bones_.resize(header_->numbones); + + aiNode *bones_node = new aiNode(AI_MDL_HL1_NODE_BONES); + rootnode_children_.push_back(bones_node); + bones_node->mNumChildren = static_cast(header_->numbones); + bones_node->mChildren = new aiNode *[bones_node->mNumChildren]; + + // Create bone matrices in local space. + for (int i = 0; i < header_->numbones; ++i) { + aiNode *bone_node = temp_bones_[i].node = bones_node->mChildren[i] = new aiNode(unique_bones_names[i]); + + aiVector3D angles(pbone[i].value[3], pbone[i].value[4], pbone[i].value[5]); + temp_bones_[i].absolute_transform = bone_node->mTransformation = + aiMatrix4x4(aiVector3D(1), aiQuaternion(angles.y, angles.z, angles.x), + aiVector3D(pbone[i].value[0], pbone[i].value[1], pbone[i].value[2])); + + if (pbone[i].parent == -1) { + bone_node->mParent = scene_->mRootNode; + } else { + bone_node->mParent = bones_node->mChildren[pbone[i].parent]; + + temp_bones_[i].absolute_transform = + temp_bones_[pbone[i].parent].absolute_transform * bone_node->mTransformation; + } + + temp_bones_[i].offset_matrix = temp_bones_[i].absolute_transform; + temp_bones_[i].offset_matrix.Inverse(); + } +} + +// ------------------------------------------------------------------------------------------------ +/* + Read meshes. + + Half-Life MDLs are structured such that each MDL + contains one or more 'bodypart(s)', which contain one + or more 'model(s)', which contains one or more mesh(es). + + * Bodyparts are used to group models that may be replaced + in the game .e.g a character could have a 'heads' group, + 'torso' group, 'shoes' group, with each group containing + different 'model(s)'. + + * Models, also called 'sub models', contain vertices as + well as a reference to each mesh used by the sub model. + + * Meshes contain a list of tris, also known as 'triverts'. + Each tris contains the following information: + + 1. The index of the position to use for the vertex. + 2. The index of the normal to use for the vertex. + 3. The S coordinate to use for the vertex UV. + 4. The T coordinate ^ + + These tris represent the way to represent the triangles + for each mesh. Depending on how the tool compiled the MDL, + those triangles were saved as strips and or fans. + + NOTE: Each tris is NOT unique. This means that you + might encounter the same vertex index but with a different + normal index, S coordinate, T coordinate. + + In addition, each mesh contains the texture's index. + + ------------------------------------------------------ + With the details above, there are several things to + take into consideration. + + * The Half-Life models store the vertices by sub model + rather than by mesh. Due to Assimp's structure, it + is necessary to remap each model vertex to be used + per mesh. Unfortunately, this has the consequence + to duplicate vertices. + + * Because the mesh triangles are comprised of strips and + fans, it is necessary to convert each primitive to + triangles, respectively (3 indices per face). +*/ +void HL1MDLLoader::read_meshes() { + if (!header_->numbodyparts) { + return; + } + + int total_verts = 0; + int total_triangles = 0; + total_models_ = 0; + + const Bodypart_HL1 *pbodypart = (const Bodypart_HL1 *)((uint8_t *)header_ + header_->bodypartindex); + const Model_HL1 *pmodel = nullptr; + const Mesh_HL1 *pmesh = nullptr; + + const Texture_HL1 *ptexture = (const Texture_HL1 *)((uint8_t *)texture_header_ + texture_header_->textureindex); + short *pskinref = (short *)((uint8_t *)texture_header_ + texture_header_->skinindex); + + scene_->mNumMeshes = 0; + + std::vector unique_bodyparts_names; + unique_bodyparts_names.resize(header_->numbodyparts); + + // Count the number of meshes. + + for (int i = 0; i < header_->numbodyparts; ++i, ++pbodypart) { + unique_bodyparts_names[i] = pbodypart->name; + + pmodel = (Model_HL1 *)((uint8_t *)header_ + pbodypart->modelindex); + for (int j = 0; j < pbodypart->nummodels; ++j, ++pmodel) { + scene_->mNumMeshes += pmodel->nummesh; + total_verts += pmodel->numverts; + } + + total_models_ += pbodypart->nummodels; + } + + // Display limit infos. + if (total_verts > AI_MDL_HL1_MAX_VERTICES) { + log_warning_limit_exceeded(total_verts, "vertices"); + } + + if (scene_->mNumMeshes > AI_MDL_HL1_MAX_MESHES) { + log_warning_limit_exceeded(scene_->mNumMeshes, "meshes"); + } + + if (total_models_ > AI_MDL_HL1_MAX_MODELS) { + log_warning_limit_exceeded(total_models_, "models"); + } + + // Ensure bodyparts have unique names. + unique_name_generator_.set_template_name("Bodypart"); + unique_name_generator_.make_unique(unique_bodyparts_names); + + // Now do the same for each model. + pbodypart = (const Bodypart_HL1 *)((uint8_t *)header_ + header_->bodypartindex); + + // Prepare template name for bodypart models. + std::vector unique_models_names; + unique_models_names.resize(total_models_); + + unsigned int model_index = 0; + + for (int i = 0; i < header_->numbodyparts; ++i, ++pbodypart) { + pmodel = (Model_HL1 *)((uint8_t *)header_ + pbodypart->modelindex); + for (int j = 0; j < pbodypart->nummodels; ++j, ++pmodel, ++model_index) + unique_models_names[model_index] = pmodel->name; + } + + unique_name_generator_.set_template_name("Model"); + unique_name_generator_.make_unique(unique_models_names); + + unsigned int mesh_index = 0; + + scene_->mMeshes = new aiMesh *[scene_->mNumMeshes]; + + pbodypart = (const Bodypart_HL1 *)((uint8_t *)header_ + header_->bodypartindex); + + /* Create a node that will represent the mesh hierarchy. + + + | + +-- bodypart --+-- model -- [mesh index, mesh index, ...] + | | + | +-- model -- [mesh index, mesh index, ...] + | | + | ... + | + |-- bodypart -- ... + | + ... + */ + aiNode *bodyparts_node = new aiNode(AI_MDL_HL1_NODE_BODYPARTS); + rootnode_children_.push_back(bodyparts_node); + bodyparts_node->mNumChildren = static_cast(header_->numbodyparts); + bodyparts_node->mChildren = new aiNode *[bodyparts_node->mNumChildren]; + aiNode **bodyparts_node_ptr = bodyparts_node->mChildren; + + // The following variables are defined here so they don't have + // to be recreated every iteration. + + // Model_HL1 vertices, in bind pose space. + std::vector bind_pose_vertices; + + // Model_HL1 normals, in bind pose space. + std::vector bind_pose_normals; + + // Used to contain temporary information for building a mesh. + std::vector triverts; + + std::vector tricmds; + + // Which triverts to use for the mesh. + std::vector mesh_triverts_indices; + + std::vector mesh_faces; + + /* triverts that have the same vertindex, but have different normindex,s,t values. + Similar triverts are mapped from vertindex to a list of similar triverts. */ + std::map> triverts_similars; + + // triverts per bone. + std::map> bone_triverts; + + /** This function adds a trivert index to the list of triverts per bone. + * \param[in] bone The bone that affects the trivert at index \p trivert_index. + * \param[in] trivert_index The trivert index. + */ + auto AddTrivertToBone = [&](int bone, short trivert_index) { + if (bone_triverts.count(bone) == 0) + bone_triverts.insert({ bone, std::set{ trivert_index }}); + else + bone_triverts[bone].insert(trivert_index); + }; + + /** This function creates and appends a new trivert to the list of triverts. + * \param[in] trivert The trivert to use as a prototype. + * \param[in] bone The bone that affects \p trivert. + */ + auto AddSimilarTrivert = [&](const Trivert &trivert, const int bone) { + HL1MeshTrivert new_trivert(trivert); + new_trivert.localindex = static_cast(mesh_triverts_indices.size()); + + short new_trivert_index = static_cast(triverts.size()); + + if (triverts_similars.count(trivert.vertindex) == 0) + triverts_similars.insert({ trivert.vertindex, std::set{ new_trivert_index }}); + else + triverts_similars[trivert.vertindex].insert(new_trivert_index); + + triverts.push_back(new_trivert); + + mesh_triverts_indices.push_back(new_trivert_index); + tricmds.push_back(new_trivert.localindex); + AddTrivertToBone(bone, new_trivert.localindex); + }; + + model_index = 0; + + for (int i = 0; i < header_->numbodyparts; ++i, ++pbodypart, ++bodyparts_node_ptr) { + pmodel = (const Model_HL1 *)((uint8_t *)header_ + pbodypart->modelindex); + + // Create bodypart node for the mesh tree hierarchy. + aiNode *bodypart_node = (*bodyparts_node_ptr) = new aiNode(unique_bodyparts_names[i]); + bodypart_node->mParent = bodyparts_node; + bodypart_node->mMetaData = aiMetadata::Alloc(1); + bodypart_node->mMetaData->Set(0, "Base", pbodypart->base); + + bodypart_node->mNumChildren = static_cast(pbodypart->nummodels); + bodypart_node->mChildren = new aiNode *[bodypart_node->mNumChildren]; + aiNode **bodypart_models_ptr = bodypart_node->mChildren; + + for (int j = 0; j < pbodypart->nummodels; + ++j, ++pmodel, ++bodypart_models_ptr, ++model_index) { + + pmesh = (const Mesh_HL1 *)((uint8_t *)header_ + pmodel->meshindex); + + uint8_t *pvertbone = ((uint8_t *)header_ + pmodel->vertinfoindex); + uint8_t *pnormbone = ((uint8_t *)header_ + pmodel->norminfoindex); + vec3_t *pstudioverts = (vec3_t *)((uint8_t *)header_ + pmodel->vertindex); + vec3_t *pstudionorms = (vec3_t *)((uint8_t *)header_ + pmodel->normindex); + + // Each vertex and normal is in local space, so transform + // each of them to bring them in bind pose. + bind_pose_vertices.resize(pmodel->numverts); + bind_pose_normals.resize(pmodel->numnorms); + for (size_t k = 0; k < bind_pose_vertices.size(); ++k) { + const vec3_t &vert = pstudioverts[k]; + bind_pose_vertices[k] = temp_bones_[pvertbone[k]].absolute_transform * aiVector3D(vert[0], vert[1], vert[2]); + } + for (size_t k = 0; k < bind_pose_normals.size(); ++k) { + const vec3_t &norm = pstudionorms[k]; + // Compute the normal matrix to transform the normal into bind pose, + // without affecting its length. + const aiMatrix4x4 normal_matrix = aiMatrix4x4(temp_bones_[pnormbone[k]].absolute_transform).Inverse().Transpose(); + bind_pose_normals[k] = normal_matrix * aiVector3D(norm[0], norm[1], norm[2]); + } + + // Create model node for the mesh tree hierarchy. + aiNode *model_node = (*bodypart_models_ptr) = new aiNode(unique_models_names[model_index]); + model_node->mParent = bodypart_node; + model_node->mNumMeshes = static_cast(pmodel->nummesh); + model_node->mMeshes = new unsigned int[model_node->mNumMeshes]; + unsigned int *model_meshes_ptr = model_node->mMeshes; + + for (int k = 0; k < pmodel->nummesh; ++k, ++pmesh, ++mesh_index, ++model_meshes_ptr) { + *model_meshes_ptr = mesh_index; + + // Read triverts. + short *ptricmds = (short *)((uint8_t *)header_ + pmesh->triindex); + float texcoords_s_scale = 1.0f / (float)ptexture[pskinref[pmesh->skinref]].width; + float texcoords_t_scale = 1.0f / (float)ptexture[pskinref[pmesh->skinref]].height; + + // Reset the data for the upcoming mesh. + triverts.clear(); + triverts.resize(pmodel->numverts); + mesh_triverts_indices.clear(); + mesh_faces.clear(); + triverts_similars.clear(); + bone_triverts.clear(); + + int l; + while ((l = *(ptricmds++))) { + bool is_triangle_fan = false; + + if (l < 0) { + l = -l; + is_triangle_fan = true; + } + + // Clear the list of tris for the upcoming tris. + tricmds.clear(); + + for (; l > 0; l--, ptricmds += 4) { + const Trivert *input_trivert = reinterpret_cast(ptricmds); + const int bone = pvertbone[input_trivert->vertindex]; + + HL1MeshTrivert *private_trivert = &triverts[input_trivert->vertindex]; + if (private_trivert->localindex == -1) { + // First time referenced. + *private_trivert = *input_trivert; + private_trivert->localindex = static_cast(mesh_triverts_indices.size()); + mesh_triverts_indices.push_back(input_trivert->vertindex); + tricmds.push_back(private_trivert->localindex); + AddTrivertToBone(bone, private_trivert->localindex); + } else if (*private_trivert == *input_trivert) { + // Exists and is the same. + tricmds.push_back(private_trivert->localindex); + } else { + // No similar trivert associated to the trivert currently processed. + if (triverts_similars.count(input_trivert->vertindex) == 0) + AddSimilarTrivert(*input_trivert, bone); + else { + // Search in the list of similar triverts to see if the + // trivert in process is already registered. + short similar_index = -1; + for (auto it = triverts_similars[input_trivert->vertindex].cbegin(); + similar_index == -1 && it != triverts_similars[input_trivert->vertindex].cend(); + ++it) { + if (triverts[*it] == *input_trivert) + similar_index = *it; + } + + // If a similar trivert has been found, reuse it. + // Otherwise, add it. + if (similar_index == -1) + AddSimilarTrivert(*input_trivert, bone); + else + tricmds.push_back(triverts[similar_index].localindex); + } + } + } + + // Build mesh faces. + const int num_faces = static_cast(tricmds.size() - 2); + mesh_faces.reserve(num_faces); + + if (is_triangle_fan) { + for (int i = 0; i < num_faces; ++i) { + mesh_faces.push_back(HL1MeshFace{ + tricmds[0], + tricmds[i + 1], + tricmds[i + 2] }); + } + } else { + for (int i = 0; i < num_faces; ++i) { + if (i & 1) { + // Preserve winding order. + mesh_faces.push_back(HL1MeshFace{ + tricmds[i + 1], + tricmds[i], + tricmds[i + 2] }); + } else { + mesh_faces.push_back(HL1MeshFace{ + tricmds[i], + tricmds[i + 1], + tricmds[i + 2] }); + } + } + } + + total_triangles += num_faces; + } + + // Create the scene mesh. + aiMesh *scene_mesh = scene_->mMeshes[mesh_index] = new aiMesh(); + scene_mesh->mPrimitiveTypes = aiPrimitiveType::aiPrimitiveType_TRIANGLE; + scene_mesh->mMaterialIndex = pskinref[pmesh->skinref]; + + scene_mesh->mNumVertices = static_cast(mesh_triverts_indices.size()); + + if (scene_mesh->mNumVertices) { + scene_mesh->mVertices = new aiVector3D[scene_mesh->mNumVertices]; + scene_mesh->mNormals = new aiVector3D[scene_mesh->mNumVertices]; + + scene_mesh->mNumUVComponents[0] = 2; + scene_mesh->mTextureCoords[0] = new aiVector3D[scene_mesh->mNumVertices]; + + // Add vertices. + for (unsigned int v = 0; v < scene_mesh->mNumVertices; ++v) { + const HL1MeshTrivert *pTrivert = &triverts[mesh_triverts_indices[v]]; + scene_mesh->mVertices[v] = bind_pose_vertices[pTrivert->vertindex]; + scene_mesh->mNormals[v] = bind_pose_normals[pTrivert->normindex]; + scene_mesh->mTextureCoords[0][v] = aiVector3D( + pTrivert->s * texcoords_s_scale, + pTrivert->t * texcoords_t_scale, 0); + } + + // Add face and indices. + scene_mesh->mNumFaces = static_cast(mesh_faces.size()); + scene_mesh->mFaces = new aiFace[scene_mesh->mNumFaces]; + + for (unsigned int f = 0; f < scene_mesh->mNumFaces; ++f) { + aiFace *face = &scene_mesh->mFaces[f]; + face->mNumIndices = 3; + face->mIndices = new unsigned int[3]; + face->mIndices[0] = mesh_faces[f].v0; + face->mIndices[1] = mesh_faces[f].v1; + face->mIndices[2] = mesh_faces[f].v2; + } + + // Add mesh bones. + scene_mesh->mNumBones = static_cast(bone_triverts.size()); + scene_mesh->mBones = new aiBone *[scene_mesh->mNumBones]; + + aiBone **scene_bone_ptr = scene_mesh->mBones; + + for (auto bone_it = bone_triverts.cbegin(); + bone_it != bone_triverts.cend(); + ++bone_it, ++scene_bone_ptr) { + const int bone_index = bone_it->first; + + aiBone *scene_bone = (*scene_bone_ptr) = new aiBone(); + scene_bone->mName = temp_bones_[bone_index].node->mName; + + scene_bone->mOffsetMatrix = temp_bones_[bone_index].offset_matrix; + + auto vertex_ids = bone_triverts.at(bone_index); + + // Add vertex weight per bone. + scene_bone->mNumWeights = static_cast(vertex_ids.size()); + aiVertexWeight *vertex_weight_ptr = scene_bone->mWeights = new aiVertexWeight[scene_bone->mNumWeights]; + + for (auto vertex_it = vertex_ids.begin(); + vertex_it != vertex_ids.end(); + ++vertex_it, ++vertex_weight_ptr) { + vertex_weight_ptr->mVertexId = *vertex_it; + vertex_weight_ptr->mWeight = 1.0f; + } + } + } + } + } + } + + if (total_triangles > AI_MDL_HL1_MAX_TRIANGLES) { + log_warning_limit_exceeded(total_triangles, "triangles"); + } +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::read_animations() { + if (!header_->numseq) { + return; + } + + const SequenceDesc_HL1 *pseqdesc = (const SequenceDesc_HL1 *)((uint8_t *)header_ + header_->seqindex); + const SequenceGroup_HL1 *pseqgroup = nullptr; + const AnimValueOffset_HL1 *panim = nullptr; + const AnimValue_HL1 *panimvalue = nullptr; + + unique_sequence_names_.resize(header_->numseq); + for (int i = 0; i < header_->numseq; ++i) + unique_sequence_names_[i] = pseqdesc[i].label; + + // Ensure sequences have unique names. + unique_name_generator_.set_template_name("Sequence"); + unique_name_generator_.make_unique(unique_sequence_names_); + + scene_->mNumAnimations = 0; + + int highest_num_blend_animations = SequenceBlendMode_HL1::NoBlend; + + // Count the total number of animations. + for (int i = 0; i < header_->numseq; ++i, ++pseqdesc) { + scene_->mNumAnimations += pseqdesc->numblends; + highest_num_blend_animations = std::max(pseqdesc->numblends, highest_num_blend_animations); + } + + // Get the number of available blend controllers for global info. + get_num_blend_controllers(highest_num_blend_animations, num_blend_controllers_); + + pseqdesc = (const SequenceDesc_HL1 *)((uint8_t *)header_ + header_->seqindex); + + aiAnimation **scene_animations_ptr = scene_->mAnimations = new aiAnimation *[scene_->mNumAnimations]; + + for (int sequence = 0; sequence < header_->numseq; ++sequence, ++pseqdesc) { + pseqgroup = (const SequenceGroup_HL1 *)((uint8_t *)header_ + header_->seqgroupindex) + pseqdesc->seqgroup; + + if (pseqdesc->seqgroup == 0) { + panim = (const AnimValueOffset_HL1 *)((uint8_t *)header_ + pseqgroup->unused2 + pseqdesc->animindex); + } else { + panim = (const AnimValueOffset_HL1 *)((uint8_t *)anim_headers_[pseqdesc->seqgroup] + pseqdesc->animindex); + } + + for (int blend = 0; blend < pseqdesc->numblends; ++blend, ++scene_animations_ptr) { + + const Bone_HL1 *pbone = (const Bone_HL1 *)((uint8_t *)header_ + header_->boneindex); + + aiAnimation *scene_animation = (*scene_animations_ptr) = new aiAnimation(); + + scene_animation->mName = unique_sequence_names_[sequence]; + scene_animation->mTicksPerSecond = pseqdesc->fps; + scene_animation->mDuration = static_cast(pseqdesc->fps) * pseqdesc->numframes; + scene_animation->mNumChannels = static_cast(header_->numbones); + scene_animation->mChannels = new aiNodeAnim *[scene_animation->mNumChannels]; + + for (int bone = 0; bone < header_->numbones; bone++, ++pbone, ++panim) { + aiNodeAnim *node_anim = scene_animation->mChannels[bone] = new aiNodeAnim(); + node_anim->mNodeName = temp_bones_[bone].node->mName; + + node_anim->mNumPositionKeys = pseqdesc->numframes; + node_anim->mNumRotationKeys = node_anim->mNumPositionKeys; + node_anim->mNumScalingKeys = 0; + + node_anim->mPositionKeys = new aiVectorKey[node_anim->mNumPositionKeys]; + node_anim->mRotationKeys = new aiQuatKey[node_anim->mNumRotationKeys]; + + for (int frame = 0; frame < pseqdesc->numframes; ++frame) { + aiVectorKey *position_key = &node_anim->mPositionKeys[frame]; + aiQuatKey *rotation_key = &node_anim->mRotationKeys[frame]; + + aiVector3D angle1; + for (int j = 0; j < 3; ++j) { + if (panim->offset[j + 3] != 0) { + // Read compressed rotation delta. + panimvalue = (const AnimValue_HL1 *)((uint8_t *)panim + panim->offset[j + 3]); + extract_anim_value(panimvalue, frame, pbone->scale[j + 3], angle1[j]); + } + + // Add the default rotation value. + angle1[j] += pbone->value[j + 3]; + + if (panim->offset[j] != 0) { + // Read compressed position delta. + panimvalue = (const AnimValue_HL1 *)((uint8_t *)panim + panim->offset[j]); + extract_anim_value(panimvalue, frame, pbone->scale[j], position_key->mValue[j]); + } + + // Add the default position value. + position_key->mValue[j] += pbone->value[j]; + } + + position_key->mTime = rotation_key->mTime = static_cast(frame); + /* The Half-Life engine uses X as forward, Y as left, Z as up. Therefore, + pitch,yaw,roll is represented as (YZX). */ + rotation_key->mValue = aiQuaternion(angle1.y, angle1.z, angle1.x); + rotation_key->mValue.Normalize(); + } + } + } + } +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::read_sequence_groups_info() { + if (!header_->numseqgroups) { + return; + } + + aiNode *sequence_groups_node = new aiNode(AI_MDL_HL1_NODE_SEQUENCE_GROUPS); + rootnode_children_.push_back(sequence_groups_node); + + sequence_groups_node->mNumChildren = static_cast(header_->numseqgroups); + sequence_groups_node->mChildren = new aiNode *[sequence_groups_node->mNumChildren]; + + const SequenceGroup_HL1 *pseqgroup = (const SequenceGroup_HL1 *)((uint8_t *)header_ + header_->seqgroupindex); + + unique_sequence_groups_names_.resize(header_->numseqgroups); + for (int i = 0; i < header_->numseqgroups; ++i) { + unique_sequence_groups_names_[i] = pseqgroup[i].label; + } + + // Ensure sequence groups have unique names. + unique_name_generator_.set_template_name("SequenceGroup"); + unique_name_generator_.make_unique(unique_sequence_groups_names_); + + for (int i = 0; i < header_->numseqgroups; ++i, ++pseqgroup) { + aiNode *sequence_group_node = sequence_groups_node->mChildren[i] = new aiNode(unique_sequence_groups_names_[i]); + sequence_group_node->mParent = sequence_groups_node; + + aiMetadata *md = sequence_group_node->mMetaData = aiMetadata::Alloc(1); + if (i == 0) { + /* StudioMDL does not write the file name for the default sequence group, + so we will write it. */ + md->Set(0, "File", aiString(file_path_)); + } else { + md->Set(0, "File", aiString(pseqgroup->name)); + } + } +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::read_sequence_infos() { + if (!header_->numseq) { + return; + } + + const SequenceDesc_HL1 *pseqdesc = (const SequenceDesc_HL1 *)((uint8_t *)header_ + header_->seqindex); + + aiNode *sequence_infos_node = new aiNode(AI_MDL_HL1_NODE_SEQUENCE_INFOS); + rootnode_children_.push_back(sequence_infos_node); + + sequence_infos_node->mNumChildren = static_cast(header_->numseq); + sequence_infos_node->mChildren = new aiNode *[sequence_infos_node->mNumChildren]; + + std::vector sequence_info_node_children; + + int animation_index = 0; + for (int i = 0; i < header_->numseq; ++i, ++pseqdesc) { + // Clear the list of children for the upcoming sequence info node. + sequence_info_node_children.clear(); + + aiNode *sequence_info_node = sequence_infos_node->mChildren[i] = new aiNode(unique_sequence_names_[i]); + sequence_info_node->mParent = sequence_infos_node; + + // Setup sequence info node Metadata. + aiMetadata *md = sequence_info_node->mMetaData = aiMetadata::Alloc(16); + md->Set(0, "AnimationIndex", animation_index); + animation_index += pseqdesc->numblends; + + // Reference the sequence group by name. This allows us to search a particular + // sequence group by name using aiNode(s). + md->Set(1, "SequenceGroup", aiString(unique_sequence_groups_names_[pseqdesc->seqgroup])); + md->Set(2, "FramesPerSecond", pseqdesc->fps); + md->Set(3, "NumFrames", pseqdesc->numframes); + md->Set(4, "NumBlends", pseqdesc->numblends); + md->Set(5, "Activity", pseqdesc->activity); + md->Set(6, "ActivityWeight", pseqdesc->actweight); + md->Set(7, "MotionFlags", pseqdesc->motiontype); + md->Set(8, "MotionBone", temp_bones_[pseqdesc->motionbone].node->mName); + md->Set(9, "LinearMovement", aiVector3D(pseqdesc->linearmovement[0], pseqdesc->linearmovement[1], pseqdesc->linearmovement[2])); + md->Set(10, "BBMin", aiVector3D(pseqdesc->bbmin[0], pseqdesc->bbmin[1], pseqdesc->bbmin[2])); + md->Set(11, "BBMax", aiVector3D(pseqdesc->bbmax[0], pseqdesc->bbmax[1], pseqdesc->bbmax[2])); + md->Set(12, "EntryNode", pseqdesc->entrynode); + md->Set(13, "ExitNode", pseqdesc->exitnode); + md->Set(14, "NodeFlags", pseqdesc->nodeflags); + md->Set(15, "Flags", pseqdesc->flags); + + if (import_settings_.read_blend_controllers) { + int num_blend_controllers; + if (get_num_blend_controllers(pseqdesc->numblends, num_blend_controllers) && num_blend_controllers) { + // Read blend controllers info. + aiNode *blend_controllers_node = new aiNode(AI_MDL_HL1_NODE_BLEND_CONTROLLERS); + sequence_info_node_children.push_back(blend_controllers_node); + blend_controllers_node->mParent = sequence_info_node; + blend_controllers_node->mNumChildren = static_cast(num_blend_controllers); + blend_controllers_node->mChildren = new aiNode *[blend_controllers_node->mNumChildren]; + + for (unsigned int j = 0; j < blend_controllers_node->mNumChildren; ++j) { + aiNode *blend_controller_node = blend_controllers_node->mChildren[j] = new aiNode(); + blend_controller_node->mParent = blend_controllers_node; + + aiMetadata *md = blend_controller_node->mMetaData = aiMetadata::Alloc(3); + md->Set(0, "Start", pseqdesc->blendstart[j]); + md->Set(1, "End", pseqdesc->blendend[j]); + md->Set(2, "MotionFlags", pseqdesc->blendtype[j]); + } + } + } + + if (import_settings_.read_animation_events && pseqdesc->numevents) { + // Read animation events. + + if (pseqdesc->numevents > AI_MDL_HL1_MAX_EVENTS) { + log_warning_limit_exceeded( + "Sequence " + std::string(pseqdesc->label), + pseqdesc->numevents, "animation events"); + } + + const AnimEvent_HL1 *pevent = (const AnimEvent_HL1 *)((uint8_t *)header_ + pseqdesc->eventindex); + + aiNode *pEventsNode = new aiNode(AI_MDL_HL1_NODE_ANIMATION_EVENTS); + sequence_info_node_children.push_back(pEventsNode); + pEventsNode->mParent = sequence_info_node; + pEventsNode->mNumChildren = static_cast(pseqdesc->numevents); + pEventsNode->mChildren = new aiNode *[pEventsNode->mNumChildren]; + + for (unsigned int j = 0; j < pEventsNode->mNumChildren; ++j, ++pevent) { + aiNode *pEvent = pEventsNode->mChildren[j] = new aiNode(); + pEvent->mParent = pEventsNode; + + aiMetadata *md = pEvent->mMetaData = aiMetadata::Alloc(3); + md->Set(0, "Frame", pevent->frame); + md->Set(1, "ScriptEvent", pevent->event); + md->Set(2, "Options", aiString(pevent->options)); + } + } + + if (sequence_info_node_children.size()) { + sequence_info_node->addChildren( + static_cast(sequence_info_node_children.size()), + sequence_info_node_children.data()); + } + } +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::read_sequence_transitions() { + if (!header_->numtransitions) { + return; + } + + // Read sequence transition graph. + aiNode *transition_graph_node = new aiNode(AI_MDL_HL1_NODE_SEQUENCE_TRANSITION_GRAPH); + rootnode_children_.push_back(transition_graph_node); + + uint8_t *ptransitions = ((uint8_t *)header_ + header_->transitionindex); + aiMetadata *md = transition_graph_node->mMetaData = aiMetadata::Alloc(header_->numtransitions * header_->numtransitions); + for (unsigned int i = 0; i < md->mNumProperties; ++i) + md->Set(i, std::to_string(i), static_cast(ptransitions[i])); +} + +void HL1MDLLoader::read_attachments() { + if (!header_->numattachments) { + return; + } + + const Attachment_HL1 *pattach = (const Attachment_HL1 *)((uint8_t *)header_ + header_->attachmentindex); + + aiNode *attachments_node = new aiNode(AI_MDL_HL1_NODE_ATTACHMENTS); + rootnode_children_.push_back(attachments_node); + attachments_node->mNumChildren = static_cast(header_->numattachments); + attachments_node->mChildren = new aiNode *[attachments_node->mNumChildren]; + + for (int i = 0; i < header_->numattachments; ++i, ++pattach) { + aiNode *attachment_node = attachments_node->mChildren[i] = new aiNode(); + attachment_node->mParent = attachments_node; + attachment_node->mMetaData = aiMetadata::Alloc(2); + attachment_node->mMetaData->Set(0, "Position", aiVector3D(pattach->org[0], pattach->org[1], pattach->org[2])); + // Reference the bone by name. This allows us to search a particular + // bone by name using aiNode(s). + attachment_node->mMetaData->Set(1, "Bone", temp_bones_[pattach->bone].node->mName); + } +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::read_hitboxes() { + if (!header_->numhitboxes) { + return; + } + + const Hitbox_HL1 *phitbox = (const Hitbox_HL1 *)((uint8_t *)header_ + header_->hitboxindex); + + aiNode *hitboxes_node = new aiNode(AI_MDL_HL1_NODE_HITBOXES); + rootnode_children_.push_back(hitboxes_node); + hitboxes_node->mNumChildren = static_cast(header_->numhitboxes); + hitboxes_node->mChildren = new aiNode *[hitboxes_node->mNumChildren]; + + for (int i = 0; i < header_->numhitboxes; ++i, ++phitbox) { + aiNode *hitbox_node = hitboxes_node->mChildren[i] = new aiNode(); + hitbox_node->mParent = hitboxes_node; + + aiMetadata *md = hitbox_node->mMetaData = aiMetadata::Alloc(4); + // Reference the bone by name. This allows us to search a particular + // bone by name using aiNode(s). + md->Set(0, "Bone", temp_bones_[phitbox->bone].node->mName); + md->Set(1, "HitGroup", phitbox->group); + md->Set(2, "BBMin", aiVector3D(phitbox->bbmin[0], phitbox->bbmin[1], phitbox->bbmin[2])); + md->Set(3, "BBMax", aiVector3D(phitbox->bbmax[0], phitbox->bbmax[1], phitbox->bbmax[2])); + } +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::read_bone_controllers() { + if (!header_->numbonecontrollers) { + return; + } + + const BoneController_HL1 *pbonecontroller = (const BoneController_HL1 *)((uint8_t *)header_ + header_->bonecontrollerindex); + + aiNode *bones_controller_node = new aiNode(AI_MDL_HL1_NODE_BONE_CONTROLLERS); + rootnode_children_.push_back(bones_controller_node); + bones_controller_node->mNumChildren = static_cast(header_->numbonecontrollers); + bones_controller_node->mChildren = new aiNode *[bones_controller_node->mNumChildren]; + + for (int i = 0; i < header_->numbonecontrollers; ++i, ++pbonecontroller) { + aiNode *bone_controller_node = bones_controller_node->mChildren[i] = new aiNode(); + bone_controller_node->mParent = bones_controller_node; + + aiMetadata *md = bone_controller_node->mMetaData = aiMetadata::Alloc(5); + // Reference the bone by name. This allows us to search a particular + // bone by name using aiNode(s). + md->Set(0, "Bone", temp_bones_[pbonecontroller->bone].node->mName); + md->Set(1, "MotionFlags", pbonecontroller->type); + md->Set(2, "Start", pbonecontroller->start); + md->Set(3, "End", pbonecontroller->end); + md->Set(4, "Channel", pbonecontroller->index); + } +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::read_global_info() { + aiNode *global_info_node = new aiNode(AI_MDL_HL1_NODE_GLOBAL_INFO); + rootnode_children_.push_back(global_info_node); + + aiMetadata *md = global_info_node->mMetaData = aiMetadata::Alloc(import_settings_.read_misc_global_info ? 16 : 11); + md->Set(0, "Version", AI_MDL_HL1_VERSION); + md->Set(1, "NumBodyparts", header_->numbodyparts); + md->Set(2, "NumModels", total_models_); + md->Set(3, "NumBones", header_->numbones); + md->Set(4, "NumAttachments", import_settings_.read_attachments ? header_->numattachments : 0); + md->Set(5, "NumSkinFamilies", texture_header_->numskinfamilies); + md->Set(6, "NumHitboxes", import_settings_.read_hitboxes ? header_->numhitboxes : 0); + md->Set(7, "NumBoneControllers", import_settings_.read_bone_controllers ? header_->numbonecontrollers : 0); + md->Set(8, "NumSequences", import_settings_.read_animations ? header_->numseq : 0); + md->Set(9, "NumBlendControllers", import_settings_.read_blend_controllers ? num_blend_controllers_ : 0); + md->Set(10, "NumTransitionNodes", import_settings_.read_sequence_transitions ? header_->numtransitions : 0); + + if (import_settings_.read_misc_global_info) { + md->Set(11, "EyePosition", aiVector3D(header_->eyeposition[0], header_->eyeposition[1], header_->eyeposition[2])); + md->Set(12, "HullMin", aiVector3D(header_->min[0], header_->min[1], header_->min[2])); + md->Set(13, "HullMax", aiVector3D(header_->max[0], header_->max[1], header_->max[2])); + md->Set(14, "CollisionMin", aiVector3D(header_->bbmin[0], header_->bbmin[1], header_->bbmin[2])); + md->Set(15, "CollisionMax", aiVector3D(header_->bbmax[0], header_->bbmax[1], header_->bbmax[2])); + } +} + +// ------------------------------------------------------------------------------------------------ +/** @brief This method reads a compressed anim value. +* +* @note The structure of this method is taken from HL2 source code. +* Although this is from HL2, it's implementation is almost identical +* to code found in HL1 SDK. See HL1 and HL2 SDKs for more info. +* +* source: +* HL1 source code. +* file: studio_render.cpp +* function(s): CalcBoneQuaternion and CalcBonePosition +* +* HL2 source code. +* file: bone_setup.cpp +* function(s): ExtractAnimValue +*/ +void HL1MDLLoader::extract_anim_value( + const AnimValue_HL1 *panimvalue, + int frame, float bone_scale, float &value) { + int k = frame; + + // find span of values that includes the frame we want + while (panimvalue->num.total <= k) { + k -= panimvalue->num.total; + panimvalue += panimvalue->num.valid + 1; + } + + // Bah, missing blend! + if (panimvalue->num.valid > k) { + value = panimvalue[k + 1].value * bone_scale; + } else { + value = panimvalue[panimvalue->num.valid].value * bone_scale; + } +} + +// ------------------------------------------------------------------------------------------------ +// Get the number of blend controllers. +bool HL1MDLLoader::get_num_blend_controllers(const int num_blend_animations, int &num_blend_controllers) { + + switch (num_blend_animations) { + case SequenceBlendMode_HL1::NoBlend: + num_blend_controllers = 0; + return true; + case SequenceBlendMode_HL1::TwoWayBlending: + num_blend_controllers = 1; + return true; + case SequenceBlendMode_HL1::FourWayBlending: + num_blend_controllers = 2; + return true; + default: + num_blend_controllers = 0; + ASSIMP_LOG_WARN(MDL_HALFLIFE_LOG_HEADER "Unsupported number of blend animations (" + std::to_string(num_blend_animations) + ")"); + return false; + } +} + +} // namespace HalfLife +} // namespace MDL +} // namespace Assimp diff --git a/Engine/lib/assimp/code/MDL/HalfLife/HL1MDLLoader.h b/Engine/lib/assimp/code/MDL/HalfLife/HL1MDLLoader.h new file mode 100644 index 000000000..c4293259c --- /dev/null +++ b/Engine/lib/assimp/code/MDL/HalfLife/HL1MDLLoader.h @@ -0,0 +1,241 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +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. +--------------------------------------------------------------------------- +*/ + +/** @file HL1MDLLoader.h + * @brief Declaration of the Half-Life 1 MDL loader. + */ + +#ifndef AI_HL1MDLLOADER_INCLUDED +#define AI_HL1MDLLOADER_INCLUDED + +#include "HL1FileData.h" +#include "HL1ImportSettings.h" +#include "UniqueNameGenerator.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace Assimp { +namespace MDL { +namespace HalfLife { + +class HL1MDLLoader { +public: + HL1MDLLoader() = delete; + HL1MDLLoader(const HL1MDLLoader &) = delete; + + /** See variables descriptions at the end for more details. */ + HL1MDLLoader( + aiScene *scene, + IOSystem *io, + const unsigned char *buffer, + const std::string &file_path, + const HL1ImportSettings &import_settings); + + ~HL1MDLLoader(); + + void load_file(); + +protected: + /** \brief Validate the header data structure of a Half-Life 1 MDL file. + * \param[in] header Input header to be validated. + * \param[in] is_texture_header Whether or not we are reading an MDL + * texture file. + */ + void validate_header(const Header_HL1 *header, bool is_texture_header); + + void load_texture_file(); + void load_sequence_groups_files(); + void read_textures(); + void read_skins(); + void read_bones(); + void read_meshes(); + void read_animations(); + void read_sequence_groups_info(); + void read_sequence_infos(); + void read_sequence_transitions(); + void read_attachments(); + void read_hitboxes(); + void read_bone_controllers(); + void read_global_info(); + +private: + void release_resources(); + + /** \brief Load a file and copy it's content to a buffer. + * \param file_path The path to the file to be loaded. + * \param buffer A pointer to a buffer to receive the data. + */ + template + void load_file_into_buffer(const std::string &file_path, unsigned char *&buffer); + + /** \brief Read an MDL texture. + * \param[in] ptexture A pointer to an MDL texture. + * \param[in] data A pointer to the data from \p ptexture. + * \param[in] pal A pointer to the texture palette from \p ptexture. + * \param[in,out] pResult A pointer to the output resulting Assimp texture. + * \param[in,out] last_palette_color The last color from the image palette. + */ + void read_texture(const Texture_HL1 *ptexture, + uint8_t *data, uint8_t *pal, aiTexture *pResult, + aiColor3D &last_palette_color); + + /** \brief This method reads a compressed anim value. + * \param[in] panimvalue A pointer to the animation data. + * \param[in] frame The frame to look for. + * \param[in] bone_scale The current bone scale to apply to the compressed value. + * \param[in,out] value The decompressed anim value at \p frame. + */ + void extract_anim_value(const AnimValue_HL1 *panimvalue, + int frame, float bone_scale, float &value); + + /** + * \brief Given the number of blend animations, determine the number of blend controllers. + * + * \param[in] num_blend_animations The number of blend animations. + * \param[out] num_blend_controllers The number of blend controllers. + * \return True if the number of blend controllers was determined. False otherwise. + */ + static bool get_num_blend_controllers(const int num_blend_animations, int &num_blend_controllers); + + /** Output scene to be filled */ + aiScene *scene_; + + /** Output I/O handler. Required for additional IO operations. */ + IOSystem *io_; + + /** Buffer from MDLLoader class. */ + const unsigned char *buffer_; + + /** The full file path to the MDL file we are trying to load. + * Used to locate other MDL files since MDL may store resources + * in external MDL files. */ + const std::string &file_path_; + + /** Configuration for HL1 MDL */ + const HL1ImportSettings &import_settings_; + + /** Main MDL header. */ + const Header_HL1 *header_; + + /** External MDL texture header. */ + const Header_HL1 *texture_header_; + + /** External MDL animation headers. + * One for each loaded animation file. */ + SequenceHeader_HL1 **anim_headers_; + + /** Texture file data. */ + unsigned char *texture_buffer_; + + /** Animation files data. */ + unsigned char **anim_buffers_; + + /** The number of sequence groups. */ + int num_sequence_groups_; + + /** The list of children to be appended to the scene's root node. */ + std::vector rootnode_children_; + + /** A unique name generator. Used to generate names for MDL values + * that may have empty/duplicate names. */ + UniqueNameGenerator unique_name_generator_; + + /** The list of unique sequence names. */ + std::vector unique_sequence_names_; + + /** The list of unique sequence groups names. */ + std::vector unique_sequence_groups_names_; + + /** Structure to store temporary bone information. */ + struct TempBone { + + TempBone() : + node(nullptr), + absolute_transform(), + offset_matrix() {} + + aiNode *node; + aiMatrix4x4 absolute_transform; + aiMatrix4x4 offset_matrix; + }; + + std::vector temp_bones_; + + /** The number of available bone controllers in the model. */ + int num_blend_controllers_; + + /** Self explanatory. */ + int total_models_; +}; + +// ------------------------------------------------------------------------------------------------ +template +void HL1MDLLoader::load_file_into_buffer(const std::string &file_path, unsigned char *&buffer) { + if (!io_->Exists(file_path)) + throw DeadlyImportError("Missing file " + DefaultIOSystem::fileName(file_path) + "."); + + std::unique_ptr file(io_->Open(file_path)); + + if (file.get() == NULL) + throw DeadlyImportError("Failed to open MDL file " + DefaultIOSystem::fileName(file_path) + "."); + + const size_t file_size = file->FileSize(); + if (file_size < sizeof(MDLFileHeader)) + throw DeadlyImportError("MDL file is too small."); + + buffer = new unsigned char[1 + file_size]; + file->Read((void *)buffer, 1, file_size); + buffer[file_size] = '\0'; +} + +} // namespace HalfLife +} // namespace MDL +} // namespace Assimp + +#endif // AI_HL1MDLLOADER_INCLUDED diff --git a/Engine/lib/assimp/code/MDL/HalfLife/HL1MeshTrivert.h b/Engine/lib/assimp/code/MDL/HalfLife/HL1MeshTrivert.h new file mode 100644 index 000000000..b61765663 --- /dev/null +++ b/Engine/lib/assimp/code/MDL/HalfLife/HL1MeshTrivert.h @@ -0,0 +1,127 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +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. +--------------------------------------------------------------------------- +*/ + +/** @file HL1MeshTrivert.h + * @brief This file contains the class declaration for the + * HL1 mesh trivert class. + */ + +#ifndef AI_HL1MESHTRIVERT_INCLUDED +#define AI_HL1MESHTRIVERT_INCLUDED + +#include "HL1FileData.h" + +namespace Assimp { +namespace MDL { +namespace HalfLife { + +/* A class to help map model triverts to mesh triverts. */ +struct HL1MeshTrivert { + HL1MeshTrivert() : + vertindex(-1), + normindex(-1), + s(0), + t(0), + localindex(-1) { + } + + HL1MeshTrivert(short vertindex, short normindex, short s, short t, short localindex) : + vertindex(vertindex), + normindex(normindex), + s(s), + t(t), + localindex() { + } + + HL1MeshTrivert(const Trivert &a) : + vertindex(a.vertindex), + normindex(a.normindex), + s(a.s), + t(a.t), + localindex(-1) { + } + + inline bool operator==(const Trivert &a) const { + return vertindex == a.vertindex && + normindex == a.normindex && + s == a.s && + t == a.t; + } + + inline bool operator!=(const Trivert &a) const { + return !(*this == a); + } + + inline bool operator==(const HL1MeshTrivert &a) const { + return localindex == a.localindex && + vertindex == a.vertindex && + normindex == a.normindex && + s == a.s && + t == a.t; + } + + inline bool operator!=(const HL1MeshTrivert &a) const { + return !(*this == a); + } + + inline HL1MeshTrivert &operator=(const Trivert &other) { + vertindex = other.vertindex; + normindex = other.normindex; + s = other.s; + t = other.t; + return *this; + } + + short vertindex; + short normindex; + short s, t; + short localindex; +}; + +struct HL1MeshFace { + short v0, v1, v2; +}; + +} // namespace HalfLife +} // namespace MDL +} // namespace Assimp + +#endif // AI_HL1MESHTRIVERT_INCLUDED diff --git a/Engine/lib/assimp/code/MDL/HalfLife/HalfLifeMDLBaseHeader.h b/Engine/lib/assimp/code/MDL/HalfLife/HalfLifeMDLBaseHeader.h new file mode 100644 index 000000000..f26f8735d --- /dev/null +++ b/Engine/lib/assimp/code/MDL/HalfLife/HalfLifeMDLBaseHeader.h @@ -0,0 +1,67 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +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. +--------------------------------------------------------------------------- +*/ + +/** @file HalfLifeMDLBaseHeader.h */ + +#ifndef AI_HALFLIFEMDLBASEHEADER_INCLUDED +#define AI_HALFLIFEMDLBASEHEADER_INCLUDED + +#include + +namespace Assimp { +namespace MDL { +namespace HalfLife { + +/** Used to interface different Valve MDL formats. */ +struct HalfLifeMDLBaseHeader +{ + //! Magic number: "IDST"/"IDSQ" + char ident[4]; + + //! The file format version. + int32_t version; +}; + +} +} +} + +#endif // AI_HALFLIFEMDLBASEHEADER_INCLUDED diff --git a/Engine/lib/assimp/code/MDL/HalfLife/LogFunctions.h b/Engine/lib/assimp/code/MDL/HalfLife/LogFunctions.h new file mode 100644 index 000000000..5e18a8df7 --- /dev/null +++ b/Engine/lib/assimp/code/MDL/HalfLife/LogFunctions.h @@ -0,0 +1,95 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +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. +--------------------------------------------------------------------------- +*/ + +/** @file LogFunctions.h */ + +#ifndef AI_MDL_HALFLIFE_LOGFUNCTIONS_INCLUDED +#define AI_MDL_HALFLIFE_LOGFUNCTIONS_INCLUDED + +#include +#include + +namespace Assimp { +namespace MDL { +namespace HalfLife { + +/** + * \brief A function to log precise messages regarding limits exceeded. + * + * \param[in] subject Subject. + * \param[in] current_amount Current amount. + * \param[in] direct_object Direct object. + * LIMIT Limit constant. + * + * Example: Model has 100 textures, which exceeds the limit (50) + * + * where \p subject is 'Model' + * \p current_amount is '100' + * \p direct_object is 'textures' + * LIMIT is '50' + */ +template +static inline void log_warning_limit_exceeded( + const std::string &subject, int current_amount, + const std::string &direct_object) { + + ASSIMP_LOG_WARN(MDL_HALFLIFE_LOG_HEADER + + subject + + " has " + + std::to_string(current_amount) + " " + + direct_object + + ", which exceeds the limit (" + + std::to_string(LIMIT) + + ")"); +} + +/** \brief Same as above, but uses 'Model' as the subject. */ +template +static inline void log_warning_limit_exceeded(int current_amount, + const std::string &direct_object) { + log_warning_limit_exceeded("Model", current_amount, direct_object); +} + +} // namespace HalfLife +} // namespace MDL +} // namespace Assimp + +#endif // AI_MDL_HALFLIFE_LOGFUNCTIONS_INCLUDED diff --git a/Engine/lib/assimp/code/MDL/HalfLife/UniqueNameGenerator.cpp b/Engine/lib/assimp/code/MDL/HalfLife/UniqueNameGenerator.cpp new file mode 100644 index 000000000..417a6baef --- /dev/null +++ b/Engine/lib/assimp/code/MDL/HalfLife/UniqueNameGenerator.cpp @@ -0,0 +1,180 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +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. +--------------------------------------------------------------------------- +*/ + +/** @file UniqueNameGenerator.cpp + * @brief Implementation for the unique name generator. + */ + +#include "UniqueNameGenerator.h" +#include +#include +#include +#include + +namespace Assimp { +namespace MDL { +namespace HalfLife { + +UniqueNameGenerator::UniqueNameGenerator() : + template_name_("unnamed"), + separator_("_") { +} + +UniqueNameGenerator::UniqueNameGenerator(const char *template_name) : + template_name_(template_name), + separator_("_") { +} + +UniqueNameGenerator::UniqueNameGenerator(const char *template_name, const char *separator) : + template_name_(template_name), + separator_(separator) { +} + +UniqueNameGenerator::~UniqueNameGenerator() { +} + +void UniqueNameGenerator::make_unique(std::vector &names) { + struct DuplicateInfo { + DuplicateInfo() : + indices(), + next_id(0) { + } + + std::list indices; + size_t next_id; + }; + + std::vector empty_names_indices; + std::vector template_name_duplicates; + std::map names_to_duplicates; + + const std::string template_name_with_separator(template_name_ + separator_); + + auto format_name = [&](const std::string &base_name, size_t id) -> std::string { + return base_name + separator_ + std::to_string(id); + }; + + auto generate_unique_name = [&](const std::string &base_name) -> std::string { + auto *duplicate_info = &names_to_duplicates[base_name]; + + std::string new_name = ""; + + bool found_identical_name; + bool tried_with_base_name_only = false; + do { + // Assume that no identical name exists. + found_identical_name = false; + + if (!tried_with_base_name_only) { + // First try with only the base name. + new_name = base_name; + } else { + // Create the name expected to be unique. + new_name = format_name(base_name, duplicate_info->next_id); + } + + // Check in the list of duplicates for an identical name. + for (size_t i = 0; + i < names.size() && + !found_identical_name; + ++i) { + if (new_name == names[i]) + found_identical_name = true; + } + + if (tried_with_base_name_only) + ++duplicate_info->next_id; + + tried_with_base_name_only = true; + + } while (found_identical_name); + + return new_name; + }; + + for (size_t i = 0; i < names.size(); ++i) { + // Check for empty names. + if (names[i].find_first_not_of(' ') == std::string::npos) { + empty_names_indices.push_back(i); + continue; + } + + /* Check for potential duplicate. + a) Either if this name is the same as the template name or + b)