From 2592ff07967b72d7e3d9f13dc3d88a73806ec0e1 Mon Sep 17 00:00:00 2001 From: Gargaj Date: Tue, 5 Aug 2014 22:54:45 +0200 Subject: [PATCH] convert exporter from tools/assimp_cmd --- code/AssbinExporter.cpp | 688 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 688 insertions(+) diff --git a/code/AssbinExporter.cpp b/code/AssbinExporter.cpp index 2f5e885c0..b3dfd082e 100644 --- a/code/AssbinExporter.cpp +++ b/code/AssbinExporter.cpp @@ -41,6 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AssimpPCH.h" #include "assbin_chunks.h" #include "./../include/assimp/version.h" +#include "ProcessHelper.h" #ifndef ASSIMP_BUILD_NO_EXPORT #ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER @@ -49,8 +50,695 @@ using namespace Assimp; namespace Assimp { + class AssbinChunkWriter : public IOStream + { + private: + + uint8_t* buffer; + uint32_t magic; + IOStream * container; + uint32_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) + : initial(initial), buffer(NULL), cur_size(0), cursor(0), container(container), magic(magic) + { + } + + 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; + } + + // ------------------------------------------------------------------- + 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 0; }; + virtual void Flush() { }; + + 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; + } + + template + size_t Write(const T& v) + { + return Write( &v, sizeof(T), 1 ); + } + + // ----------------------------------------------------------------------------------- + // Serialize an aiString + template <> + inline uint32_t Write(const aiString& s) + { + const uint32_t s2 = (uint32_t)s.length; + Write(&s,4,1); + Write(s.data,s2,1); + return s2+4; + } + + // ----------------------------------------------------------------------------------- + // Serialize an unsigned int as uint32_t + template <> + inline uint32_t Write(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 + printf("loss of data due to 64 -> 32 bit integer conversion"); + } + + Write(&t,4,1); + return 4; + } + + // ----------------------------------------------------------------------------------- + // Serialize an unsigned int as uint16_t + template <> + inline uint32_t Write(const uint16_t& w) + { + Write(&w,2,1); + return 2; + } + + // ----------------------------------------------------------------------------------- + // Serialize a float + template <> + inline uint32_t Write(const float& f) + { + BOOST_STATIC_ASSERT(sizeof(float)==4); + Write(&f,4,1); + return 4; + } + + // ----------------------------------------------------------------------------------- + // Serialize a double + template <> + inline uint32_t Write(const double& f) + { + BOOST_STATIC_ASSERT(sizeof(double)==8); + Write(&f,8,1); + return 8; + } + + // ----------------------------------------------------------------------------------- + // Serialize a vec3 + template <> + inline uint32_t Write(const aiVector3D& v) + { + uint32_t t = Write(v.x); + t += Write(v.y); + t += Write(v.z); + return t; + } + + // ----------------------------------------------------------------------------------- + // Serialize a color value + template <> + inline uint32_t Write(const aiColor4D& v) + { + uint32_t t = Write(v.r); + t += Write(v.g); + t += Write(v.b); + t += Write(v.a); + return t; + } + + // ----------------------------------------------------------------------------------- + // Serialize a quaternion + template <> + inline uint32_t Write(const aiQuaternion& v) + { + uint32_t t = Write(v.w); + t += Write(v.x); + t += Write(v.y); + t += Write(v.z); + return 16; + } + + + // ----------------------------------------------------------------------------------- + // Serialize a vertex weight + template <> + inline uint32_t Write(const aiVertexWeight& v) + { + uint32_t t = Write(v.mVertexId); + return t+Write(v.mWeight); + } + + // ----------------------------------------------------------------------------------- + // Serialize a mat4x4 + template <> + inline uint32_t Write(const aiMatrix4x4& m) + { + for (unsigned int i = 0; i < 4;++i) { + for (unsigned int i2 = 0; i2 < 4;++i2) { + Write(m[i][i2]); + } + } + return 64; + } + + // ----------------------------------------------------------------------------------- + // Serialize an aiVectorKey + template <> + inline uint32_t Write(const aiVectorKey& v) + { + const uint32_t t = Write(v.mTime); + return t + Write(v.mValue); + } + + // ----------------------------------------------------------------------------------- + // Serialize an aiQuatKey + template <> + inline uint32_t Write(const aiQuatKey& v) + { + const uint32_t t = Write(v.mTime); + return t + Write(v.mValue); + } + + template + inline uint32_t WriteBounds(const T* in, unsigned int size) + { + T minc,maxc; + ArrayBounds(in,size,minc,maxc); + + const uint32_t t = Write(minc); + return t + Write(maxc); + } + + + }; + +/* + class AssbinChunkWriter + { + AssbinStream stream; + uint32_t magic; + public: + AssbinChunkWriter( uint32_t _magic ) + { + magic = _magic; + } + void AppendToStream( AssbinStream & _stream ) + { + uint32_t s = stream.FileSize(); + _stream.Write( &magic, sizeof(uint32_t), 1 ); + _stream.Write( &s, sizeof(uint32_t), 1 ); + _stream.Write( stream.GetBuffer(), stream.FileSize(), 1 ); + } + void AppendToStream( AssbinChunkWriter & _stream ) + { + uint32_t s = stream.FileSize(); + _stream.WriteRaw( &magic, sizeof(uint32_t) ); + _stream.WriteRaw( &s, sizeof(uint32_t) ); + _stream.WriteRaw( stream.GetBuffer(), stream.FileSize() ); + } + + }; +*/ + + class AssbinExport + { + private: + bool shortened; + bool compressed; + //AssbinStream stream; + + protected: + template + size_t Write( IOStream * container, const T& v) + { + return container->Write( &v, sizeof(T), 1 ); + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryNode( IOStream * container, const aiNode* node) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODE ); + + chunk.Write(node->mName); + chunk.Write(node->mTransformation); + chunk.Write(node->mNumChildren); + chunk.Write(node->mNumMeshes); + + for (unsigned int i = 0; i < node->mNumMeshes;++i) { + chunk.Write(node->mMeshes[i]); + } + + for (unsigned int i = 0; i < node->mNumChildren;++i) { + WriteBinaryNode( &chunk, node->mChildren[i] ); + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryTexture(IOStream * container, const aiTexture* tex) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AITEXTURE ); + + chunk.Write(tex->mWidth); + chunk.Write(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 ); + + chunk.Write(b->mName); + chunk.Write(b->mNumWeights); + chunk.Write(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) { + chunk.WriteBounds(b->mWeights,b->mNumWeights); + } // else write as usual + else chunk.Write(b->mWeights,1,b->mNumWeights*sizeof(aiVertexWeight)); + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryMesh(IOStream * container, const aiMesh* mesh) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMESH ); + + chunk.Write(mesh->mPrimitiveTypes); + chunk.Write(mesh->mNumVertices); + chunk.Write(mesh->mNumFaces); + chunk.Write(mesh->mNumBones); + chunk.Write(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); + } + chunk.Write(c); + + aiVector3D minVec, maxVec; + if (mesh->mVertices) { + if (shortened) { + chunk.WriteBounds(mesh->mVertices,mesh->mNumVertices); + } // else write as usual + else chunk.Write(mesh->mVertices,1,12*mesh->mNumVertices); + } + if (mesh->mNormals) { + if (shortened) { + chunk.WriteBounds(mesh->mNormals,mesh->mNumVertices); + } // else write as usual + else chunk.Write(mesh->mNormals,1,12*mesh->mNumVertices); + } + if (mesh->mTangents && mesh->mBitangents) { + if (shortened) { + chunk.WriteBounds(mesh->mTangents,mesh->mNumVertices); + chunk.WriteBounds(mesh->mBitangents,mesh->mNumVertices); + } // else write as usual + else { + chunk.Write(mesh->mTangents,1,12*mesh->mNumVertices); + chunk.Write(mesh->mBitangents,1,12*mesh->mNumVertices); + } + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { + if (!mesh->mColors[n]) + break; + + if (shortened) { + chunk.WriteBounds(mesh->mColors[n],mesh->mNumVertices); + } // else write as usual + else chunk.Write(mesh->mColors[n],16*mesh->mNumVertices,1); + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { + if (!mesh->mTextureCoords[n]) + break; + + // write number of UV components + chunk.Write(mesh->mNumUVComponents[n]); + + if (shortened) { + chunk.WriteBounds(mesh->mTextureCoords[n],mesh->mNumVertices); + } // else write as usual + else chunk.Write(mesh->mTextureCoords[n],12*mesh->mNumVertices,1); + } + + // 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) { + BOOST_STATIC_ASSERT(AI_MAX_VERTICES <= 0xffffffff); + tmp = static_cast( f.mIndices[i] ); + hash = SuperFastHash(reinterpret_cast(&tmp),sizeof tmp,hash); + } + } + chunk.Write(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]; + + BOOST_STATIC_ASSERT(AI_MAX_FACE_INDICES <= 0xffff); + chunk.Write(f.mNumIndices); + + for (unsigned int a = 0; a < f.mNumIndices;++a) { + if (mesh->mNumVertices < (1u<<16)) { + chunk.Write(f.mIndices[a]); + } + else chunk.Write(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 ); + + chunk.Write(prop->mKey); + chunk.Write(prop->mSemantic); + chunk.Write(prop->mIndex); + + chunk.Write(prop->mDataLength); + chunk.Write((unsigned int)prop->mType); + chunk.Write(prop->mData,1,prop->mDataLength); + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryMaterial(IOStream * container, const aiMaterial* mat) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIAL); + + chunk.Write(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 ); + + chunk.Write(nd->mNodeName); + chunk.Write(nd->mNumPositionKeys); + chunk.Write(nd->mNumRotationKeys); + chunk.Write(nd->mNumScalingKeys); + chunk.Write(nd->mPreState); + chunk.Write(nd->mPostState); + + if (nd->mPositionKeys) { + if (shortened) { + chunk.WriteBounds(nd->mPositionKeys,nd->mNumPositionKeys); + + } // else write as usual + else chunk.Write(nd->mPositionKeys,1,nd->mNumPositionKeys*sizeof(aiVectorKey)); + } + if (nd->mRotationKeys) { + if (shortened) { + chunk.WriteBounds(nd->mRotationKeys,nd->mNumRotationKeys); + + } // else write as usual + else chunk.Write(nd->mRotationKeys,1,nd->mNumRotationKeys*sizeof(aiQuatKey)); + } + if (nd->mScalingKeys) { + if (shortened) { + chunk.WriteBounds(nd->mScalingKeys,nd->mNumScalingKeys); + + } // else write as usual + else chunk.Write(nd->mScalingKeys,1,nd->mNumScalingKeys*sizeof(aiVectorKey)); + } + } + + + // ----------------------------------------------------------------------------------- + void WriteBinaryAnim( IOStream * container, const aiAnimation* anim ) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIANIMATION ); + + chunk.Write (anim->mName); + chunk.Write (anim->mDuration); + chunk.Write (anim->mTicksPerSecond); + chunk.Write(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 ); + + chunk.Write(l->mName); + chunk.Write(l->mType); + + if (l->mType != aiLightSource_DIRECTIONAL) { + chunk.Write(l->mAttenuationConstant); + chunk.Write(l->mAttenuationLinear); + chunk.Write(l->mAttenuationQuadratic); + } + + chunk.Write((const aiVector3D&)l->mColorDiffuse); + chunk.Write((const aiVector3D&)l->mColorSpecular); + chunk.Write((const aiVector3D&)l->mColorAmbient); + + if (l->mType == aiLightSource_SPOT) { + chunk.Write(l->mAngleInnerCone); + chunk.Write(l->mAngleOuterCone); + } + + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryCamera( IOStream * container, const aiCamera* cam ) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AICAMERA ); + + chunk.Write(cam->mName); + chunk.Write(cam->mPosition); + chunk.Write(cam->mLookAt); + chunk.Write(cam->mUp); + chunk.Write(cam->mHorizontalFOV); + chunk.Write(cam->mClipPlaneNear); + chunk.Write(cam->mClipPlaneFar); + chunk.Write(cam->mAspect); + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryScene( IOStream * container, const aiScene* scene) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AISCENE ); + + // basic scene information + chunk.Write(scene->mFlags); + chunk.Write(scene->mNumMeshes); + chunk.Write(scene->mNumMaterials); + chunk.Write(scene->mNumAnimations); + chunk.Write(scene->mNumTextures); + chunk.Write(scene->mNumLights); + chunk.Write(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; + } + + // ----------------------------------------------------------------------------------- + // 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); + tm* p = gmtime(&tt); + + // header + char s[64]; + memset( s, 0, 64 ); +#if _MSC_VER >= 1400 + sprintf_s(s,"ASSIMP.binary-dump.%s",asctime(p)); +#else + 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 + + //todo + + 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. + WriteBinaryScene( out, pScene ); + + pIOSystem->Close( out ); + } + }; + void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene) { + AssbinExport exporter; + exporter.WriteBinaryDump( pFile, pIOSystem, pScene ); } } // end of namespace Assimp