convert exporter from tools/assimp_cmd

pull/327/head
Gargaj 2014-08-05 22:54:45 +02:00
parent 3d5e1b5cbc
commit 2592ff0796
1 changed files with 688 additions and 0 deletions

View File

@ -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 <typename T>
size_t Write(const T& v)
{
return Write( &v, sizeof(T), 1 );
}
// -----------------------------------------------------------------------------------
// Serialize an aiString
template <>
inline uint32_t Write<aiString>(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<unsigned int>(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<uint16_t>(const uint16_t& w)
{
Write(&w,2,1);
return 2;
}
// -----------------------------------------------------------------------------------
// Serialize a float
template <>
inline uint32_t Write<float>(const float& f)
{
BOOST_STATIC_ASSERT(sizeof(float)==4);
Write(&f,4,1);
return 4;
}
// -----------------------------------------------------------------------------------
// Serialize a double
template <>
inline uint32_t Write<double>(const double& f)
{
BOOST_STATIC_ASSERT(sizeof(double)==8);
Write(&f,8,1);
return 8;
}
// -----------------------------------------------------------------------------------
// Serialize a vec3
template <>
inline uint32_t Write<aiVector3D>(const aiVector3D& v)
{
uint32_t t = Write<float>(v.x);
t += Write<float>(v.y);
t += Write<float>(v.z);
return t;
}
// -----------------------------------------------------------------------------------
// Serialize a color value
template <>
inline uint32_t Write<aiColor4D>(const aiColor4D& v)
{
uint32_t t = Write<float>(v.r);
t += Write<float>(v.g);
t += Write<float>(v.b);
t += Write<float>(v.a);
return t;
}
// -----------------------------------------------------------------------------------
// Serialize a quaternion
template <>
inline uint32_t Write<aiQuaternion>(const aiQuaternion& v)
{
uint32_t t = Write<float>(v.w);
t += Write<float>(v.x);
t += Write<float>(v.y);
t += Write<float>(v.z);
return 16;
}
// -----------------------------------------------------------------------------------
// Serialize a vertex weight
template <>
inline uint32_t Write<aiVertexWeight>(const aiVertexWeight& v)
{
uint32_t t = Write<unsigned int>(v.mVertexId);
return t+Write<float>(v.mWeight);
}
// -----------------------------------------------------------------------------------
// Serialize a mat4x4
template <>
inline uint32_t Write<aiMatrix4x4>(const aiMatrix4x4& m)
{
for (unsigned int i = 0; i < 4;++i) {
for (unsigned int i2 = 0; i2 < 4;++i2) {
Write<float>(m[i][i2]);
}
}
return 64;
}
// -----------------------------------------------------------------------------------
// Serialize an aiVectorKey
template <>
inline uint32_t Write<aiVectorKey>(const aiVectorKey& v)
{
const uint32_t t = Write<double>(v.mTime);
return t + Write<aiVector3D>(v.mValue);
}
// -----------------------------------------------------------------------------------
// Serialize an aiQuatKey
template <>
inline uint32_t Write<aiQuatKey>(const aiQuatKey& v)
{
const uint32_t t = Write<double>(v.mTime);
return t + Write<aiQuaternion>(v.mValue);
}
template <typename T>
inline uint32_t WriteBounds(const T* in, unsigned int size)
{
T minc,maxc;
ArrayBounds(in,size,minc,maxc);
const uint32_t t = Write<T>(minc);
return t + Write<T>(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 <typename T>
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<aiString>(node->mName);
chunk.Write<aiMatrix4x4>(node->mTransformation);
chunk.Write<unsigned int>(node->mNumChildren);
chunk.Write<unsigned int>(node->mNumMeshes);
for (unsigned int i = 0; i < node->mNumMeshes;++i) {
chunk.Write<unsigned int>(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<unsigned int>(tex->mWidth);
chunk.Write<unsigned int>(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<aiString>(b->mName);
chunk.Write<unsigned int>(b->mNumWeights);
chunk.Write<aiMatrix4x4>(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<unsigned int>(mesh->mPrimitiveTypes);
chunk.Write<unsigned int>(mesh->mNumVertices);
chunk.Write<unsigned int>(mesh->mNumFaces);
chunk.Write<unsigned int>(mesh->mNumBones);
chunk.Write<unsigned int>(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<unsigned int>(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<unsigned int>(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<const char*>(&tmp),sizeof tmp,hash);
for (unsigned int i = 0; i < f.mNumIndices; ++i) {
BOOST_STATIC_ASSERT(AI_MAX_VERTICES <= 0xffffffff);
tmp = static_cast<uint32_t>( f.mIndices[i] );
hash = SuperFastHash(reinterpret_cast<const char*>(&tmp),sizeof tmp,hash);
}
}
chunk.Write<unsigned int>(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<uint16_t>(f.mNumIndices);
for (unsigned int a = 0; a < f.mNumIndices;++a) {
if (mesh->mNumVertices < (1u<<16)) {
chunk.Write<uint16_t>(f.mIndices[a]);
}
else chunk.Write<unsigned int>(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<aiString>(prop->mKey);
chunk.Write<unsigned int>(prop->mSemantic);
chunk.Write<unsigned int>(prop->mIndex);
chunk.Write<unsigned int>(prop->mDataLength);
chunk.Write<unsigned int>((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<unsigned int>(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<aiString>(nd->mNodeName);
chunk.Write<unsigned int>(nd->mNumPositionKeys);
chunk.Write<unsigned int>(nd->mNumRotationKeys);
chunk.Write<unsigned int>(nd->mNumScalingKeys);
chunk.Write<unsigned int>(nd->mPreState);
chunk.Write<unsigned int>(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<aiString> (anim->mName);
chunk.Write<double> (anim->mDuration);
chunk.Write<double> (anim->mTicksPerSecond);
chunk.Write<unsigned int>(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<aiString>(l->mName);
chunk.Write<unsigned int>(l->mType);
if (l->mType != aiLightSource_DIRECTIONAL) {
chunk.Write<float>(l->mAttenuationConstant);
chunk.Write<float>(l->mAttenuationLinear);
chunk.Write<float>(l->mAttenuationQuadratic);
}
chunk.Write<aiVector3D>((const aiVector3D&)l->mColorDiffuse);
chunk.Write<aiVector3D>((const aiVector3D&)l->mColorSpecular);
chunk.Write<aiVector3D>((const aiVector3D&)l->mColorAmbient);
if (l->mType == aiLightSource_SPOT) {
chunk.Write<float>(l->mAngleInnerCone);
chunk.Write<float>(l->mAngleOuterCone);
}
}
// -----------------------------------------------------------------------------------
void WriteBinaryCamera( IOStream * container, const aiCamera* cam )
{
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AICAMERA );
chunk.Write<aiString>(cam->mName);
chunk.Write<aiVector3D>(cam->mPosition);
chunk.Write<aiVector3D>(cam->mLookAt);
chunk.Write<aiVector3D>(cam->mUp);
chunk.Write<float>(cam->mHorizontalFOV);
chunk.Write<float>(cam->mClipPlaneNear);
chunk.Write<float>(cam->mClipPlaneFar);
chunk.Write<float>(cam->mAspect);
}
// -----------------------------------------------------------------------------------
void WriteBinaryScene( IOStream * container, const aiScene* scene)
{
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AISCENE );
// basic scene information
chunk.Write<unsigned int>(scene->mFlags);
chunk.Write<unsigned int>(scene->mNumMeshes);
chunk.Write<unsigned int>(scene->mNumMaterials);
chunk.Write<unsigned int>(scene->mNumAnimations);
chunk.Write<unsigned int>(scene->mNumTextures);
chunk.Write<unsigned int>(scene->mNumLights);
chunk.Write<unsigned int>(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<unsigned int>( out, ASSBIN_VERSION_MAJOR );
Write<unsigned int>( out, ASSBIN_VERSION_MINOR );
Write<unsigned int>( out, aiGetVersionRevision() );
Write<unsigned int>( out, aiGetCompileFlags() );
Write<uint16_t>( out, shortened );
Write<uint16_t>( 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