2010-04-10, 09:24 PM
[code=SomFileHelper.cpp]
/** @file Implementation of the Sword of Moonlight MDL/MDO helper routines */
#include "AssimpPCH.h"
#ifndef max
#define max(a, b) (((a) > (b)) ? (a) : (b))
#endif
// internal headers
#include "SomFileHelper.h"
using namespace Assimp;
using namespace Assimp_x;
namespace Assimp_x{ //! experimental
enum aiParameterType
{
aiParameterType_VERTEX = 0x1,
aiParameterType_NORMAL = 0x2,
aiParameterType_COLOR = 0x4,
//! or aiParameterType_TEXTURECOORD?
aiParameterType_TEXTURECOORDS = 0x8,
_aiParameterType_Force32Bit = 0x9fffffff
}; //! enum aiParameterType
enum aiFaceFeature
{
aiFaceFeature_NORMAL = 0x1,
aiFaceFeature_COLOR = 0x2,
_aiFaceFeature_Force32Bit = 0x9fffffff
}; //! enum aiFaceFeature
struct aiFace2 : public aiFace
{
/** Bitwise combination of the members of the #aiFaceFeature enum.
* aiFaceFeature_NORMAL: mIndices[0] is face normal index
* aiFaceFeature_COLOR: mIndices[1] is face color index
*/
unsigned int mFaceFeatures;
/** Bitwise combination of the members of the #aiParameterType enum.
* This specifies whether the corresponding index looks in the mIndices
* array when the bits are not set or into another aiFace2 when set.
*/
unsigned int mParameterModes;
//! one parameter exists per corner per type
unsigned int mNumCorners;
//! offset between like parameter indices
unsigned int mStride;
/** first vertex index into mIndices.
* mIndices[0] is reserved for the face normal.
* Therefore if mVertices, mNormals, etc, is 0
* (and the corresponding mParameterModes bit is unset)
* the parameter data is taken not to exist.
*/
unsigned int mVertices;
//! tangents and bitangents overlap
unsigned int mNormals;
//! color channels overlap
unsigned int mColors;
//! uv channels overlap
unsigned int mTextureCoords;
//! overrides mesh mMaterialIndex member
unsigned int mMaterialIndex;
#ifdef __cplusplus
//! Default constructor
aiFace2()
{
mFaceFeatures = 0x00000000;
mParameterModes = 0x00000000;
mNumCorners = mStride = 0;
mVertices = mNormals = mColors = mTextureCoords = 0;
mMaterialIndex = 0;
}
#endif // __cplusplus
};
struct aiMesh2 : public aiMesh
{
//! tangents and bitangents overlap
unsigned int mNumNormals;
//! color channels overlap
unsigned int mNumColors;
//! uv channels overlap
unsigned int mNumTextureCoords;
C_STRUCT aiFace2* mFaces2;
/** Number of mFaces2 materials
* Used to pad aiScene::mNumMeshes
* so aiNode::mMeshes can reference
* both aiMeshes and aiMeshes2.
*/
unsigned int mNumMaterials;
/** Parameters shared across meshes
* If set this should be a mesh in the
* scene mMeshes2 member. To see how
* it works see GetPosition() below.
* Not meant to be recursive.
*/
C_STRUCT aiMesh2* mSharedParameters;
#define _AIMESH2_GETPARAMETER(Ps,Ns)\
\
if(mSharedParameters)\
{\
if(pIndex<mSharedParameters->mNum##Ns)\
{\
if(mSharedParameters->m##Ps==NULL) return false;\
\
*pOut = mSharedParameters->m##Ps[pIndex]; return true;\
}\
else pIndex-=mSharedParameters->mNum##Ns;\
}\
else if(m##Ps==NULL||pIndex>=mNum##Ns) return false;\
\
*pOut = m##Ps[pIndex]; return true;
bool GetPosition(unsigned int pIndex, aiVector3D* pOut)const
{ _AIMESH2_GETPARAMETER(Vertices,Vertices) }
bool GetNormal(unsigned int pIndex, aiVector3D* pOut)const
{ _AIMESH2_GETPARAMETER(Normals,Normals) }
bool GetTangent(unsigned int pIndex, aiVector3D* pOut)const
{ _AIMESH2_GETPARAMETER(Tangents,Normals) }
bool GetBitangent(unsigned int pIndex, aiVector3D* pOut)const
{ _AIMESH2_GETPARAMETER(Bitangents,Normals) }
bool GetVertexColor(unsigned int pChannel, unsigned int pIndex, aiColor4D* pOut)const
{
if(pChannel>=AI_MAX_NUMBER_OF_COLOR_SETS) return false;
_AIMESH2_GETPARAMETER(Colors[pChannel],Colors)
}
//! GetTextureCoords or GetTextureCoord?
bool GetTextureCoord(unsigned int pChannel, unsigned int pIndex, aiVector3D* pOut)const
{
if(pChannel>=AI_MAX_NUMBER_OF_TEXTURECOORDS) return false;
_AIMESH2_GETPARAMETER(TextureCoords[pChannel],TextureCoords)
}
#undef _AIMESH2_GETPARAMETER
/** Find face for shared parameter indices
* The shared faces are logically mapped to the parameter space
* but do not constitute part of the mesh. That is they are for
* referencing parameters only.
*/
aiFace2 *FindFace2(unsigned int pIndex)const
{
if(mSharedParameters)
{
if(pIndex<mSharedParameters->mNumFaces)
{
if(mSharedParameters->mFaces2==NULL) return NULL;
return mSharedParameters->mFaces2+pIndex;
}
else pIndex-=mSharedParameters->mNumFaces;
}
else if(pIndex>mNumFaces||!mFaces2==NULL) return NULL;
return mFaces2+pIndex;
}
#ifdef __cplusplus
//! Default constructor. Initializes all members to 0
aiMesh2()
{
mNumNormals = mNumColors = mNumTextureCoords = 0;
mFaces2 = NULL; mNumMaterials = 0;
mSharedParameters = NULL;
}
~aiMesh2()
{
if(mFaces2) delete [] mFaces2;
}
#endif // __cplusplus
#define _AIMESH2_HASPARAMETERS(TEST,F)\
\
if(TEST) return true; if(mSharedParameters==NULL) return false;\
\
return mSharedParameters->Has##F;
inline bool HasPositions()const
{ _AIMESH2_HASPARAMETERS(mVertices!=NULL&&mNumVertices>0,Positions()) }
//! instead of this use hasFaces2()
inline bool HasFaces()const{ return false; }
inline bool HasFaces2()const
{ _AIMESH2_HASPARAMETERS(mFaces2!=NULL&&mNumFaces>0,Faces2()) }
inline bool HasNormals()const
{ _AIMESH2_HASPARAMETERS(mNormals!=NULL&&mNumNormals>0,Normals()) }
inline bool HasTangentsAndBitangents()const
{ _AIMESH2_HASPARAMETERS(mTangents!=NULL&&mBitangents!=NULL&&mNumNormals>0,TangentsAndBitangents()) }
inline bool HasVertexColors(unsigned int pIndex)const
{
if(pIndex>=AI_MAX_NUMBER_OF_COLOR_SETS) return false;
_AIMESH2_HASPARAMETERS(mColors[pIndex]!=NULL&&mNumColors>0,VertexColors(pIndex))
}
inline bool HasTextureCoords(unsigned int pIndex)const
{
if(pIndex>=AI_MAX_NUMBER_OF_TEXTURECOORDS) return false;
_AIMESH2_HASPARAMETERS(mTextureCoords[pIndex]!=NULL&&mNumTextureCoords>0,TextureCoords(pIndex))
}
#undef _AIMESH2_HASPARAMETERS
};
#define AI_SCENE_FLAGS2_INCOMPLETE 0x1
struct aiScene2 : public aiScene
{
unsigned int mFlags2;
/** The array of meshes.
*
* Use the indices given in the aiNode structure to access
* this array. The array is mNumMeshes in size.
*/
C_STRUCT aiMesh2** mMeshes2;
/**Populates aiScene members of pScene with own data and deletes self
* Equivalent to PopulateSceneSublevel() when out is 'this'.
*/
aiScene *TransferSceneDownLevel(aiScene *out = NULL);
/*Populates aiScene base members reflecting aiScene2 members*/
bool PopulateSceneSubLevel()
{
return TransferSceneDownLevel(this)!=NULL?true:false;
}
#ifdef __cplusplus
/** Constructor */
aiScene2(aiScene *cp) : aiScene(*cp)
{
mFlags2 = 0x00000000; mMeshes2 = NULL;
}
#endif // __cplusplus
};
} //end namespace Assimp_x
class DownLevelProcess
{
struct ProcessMeshHelper2;
public:
static int ProcessMesh2(const aiMesh2 *pIn, aiMesh** pOut, int iMaxOut)
{
return ProcessMeshHelper2(pIn,pOut,iMaxOut);
}
private:
struct ProcessMeshHelper2
{
/** The input will be decomposed into separate
* materials upto iMaxOut count. Any remaining meshes
* will not be carried over.
*/
ProcessMeshHelper2(const aiMesh2 *pIn, aiMesh** pOut, int iMaxOut);
~ProcessMeshHelper2();
inline operator int(){ return iCompleted; }
protected:
struct Parameters
{
union
{
//! omitted indices are presently -1
unsigned int mIndices[5];
struct //! for sake of clarity
{
unsigned int mMaterial;
unsigned int mVertex;
unsigned int mNormal;
unsigned int mColor;
unsigned int mTextureCoords; //or mTextureCoord?
};
};
bool mIsUnique;
bool mIsAssigned;
unsigned int mNewIndex;
Parameters *mMoreByVertexIndex;
inline bool operator==(const Parameters &o)
{
return memcmp(mIndices,o.mIndices,5*sizeof(int))==0;
}
inline bool operator!=(const Parameters &o)
{
return memcmp(mIndices,o.mIndices,5*sizeof(int))!=0;
}
Parameters()
{
mMaterial = 0;
for(int i=1;i<5;i++) mIndices[i] = -1;
mIsUnique = mIsAssigned = false;
mNewIndex = -1;
}
};
struct Material
{
aiMesh *mAssignedSubMesh;
unsigned int mMaterialIndex;
unsigned int mNumFacesApplicable;
Material *mNextInLoop;
Material(unsigned int iMatIndex, Material *pNext = NULL)
{
mAssignedSubMesh = NULL;
mMaterialIndex = iMatIndex;
mNextInLoop = pNext?pNext:this;
mNumFacesApplicable = 0;
}
};
unsigned int mNumBuffered;
Parameters* mBuffer;
unsigned int mNumIndexed;
Parameters** mIndex;
Material* mMaterials; //STL might be safer
Material* GetMaterial(unsigned int iMatIndex)
{
if(mMaterials==NULL) return mMaterials = new Material(iMatIndex);
if(mMaterials->mMaterialIndex==iMatIndex) return mMaterials;
Material *pOut = mMaterials->mNextInLoop;
while(pOut!=mMaterials&&pOut->mMaterialIndex!=iMatIndex)
pOut = pOut->mNextInLoop;
if(pOut==mMaterials)
pOut = pOut->mNextInLoop = new Material(iMatIndex,mMaterials);
//order could be optimized for meshes with many materials
return mMaterials = pOut;
}
Parameters* AddParameters(Parameters *pParams)
{
//! do not add to index if position parameter is omitted
if((signed)pParams->mVertex==-1) return pParams;
for(Parameters *pIter=mIndex[pParams->mVertex];
pIter&&pIter->mIsUnique;pIter++)
{
if(pIter->mIsUnique==false) break; //reached duplicate so this is unique
if(*pParams==*pIter)
{
while(pIter->mMoreByVertexIndex&&
pIter->mMoreByVertexIndex->mIsUnique)
pIter = pIter->mMoreByVertexIndex;
ai_assert(pParams->mIsUnique==false);
pParams->mMoreByVertexIndex = pIter->mMoreByVertexIndex;
return pIter->mMoreByVertexIndex = pParams;
}
}
pParams->mIsUnique = true;
pParams->mMoreByVertexIndex = mIndex[pParams->mVertex];
return mIndex[pParams->mVertex] = pParams;
}
const aiMesh2* pInput;
aiMesh** pOutput;
int iMaxOutput;
int iCompleted;
};
};
DownLevelProcess::
ProcessMeshHelper2::ProcessMeshHelper2(const aiMesh2 *pIn, aiMesh** pOut, int iMaxOut)
{
memset(this,0x00,sizeof(ProcessMeshHelper2));
if(pIn==NULL||pOut==NULL||iMaxOut<=0) return;
pInput = pIn; pOutput = pOut; iMaxOutput = iMaxOut;
mNumIndexed = pIn->mNumVertices; mNumBuffered = 0;
for(unsigned int i=0;i<pIn->mNumFaces;i++)
mNumBuffered+=pIn->mFaces2[i].mNumCorners;
if(pIn->mSharedParameters)
{
mNumIndexed+=pIn->mSharedParameters->mNumVertices;
for(unsigned int i=0;i<pIn->mSharedParameters->mNumFaces;i++)
mNumBuffered+=pIn->mSharedParameters->mFaces2[i].mNumCorners;
}
mBuffer = new ProcessMeshHelper2::Parameters[mNumBuffered];
mIndex = new ProcessMeshHelper2::Parameters*[mNumIndexed];
memset(mBuffer,0x00,mNumBuffered*sizeof(ProcessMeshHelper2::Parameters*));
memset(mIndex,0x00,mNumIndexed*sizeof(void*));
unsigned int iCurParameters = 0;
for(unsigned int i=0;i<pIn->mNumFaces;i++)
{
ProcessMeshHelper2::Parameters *pParams = mBuffer+iCurParameters;
const aiFace2* pFace = pIn->mFaces2+i; //! MATERIAL
GetMaterial(pFace->mMaterialIndex)->mNumFacesApplicable++;
int iNumCorners = pFace->mNumCorners;
for(unsigned int j=0;j<iNumCorners;j++)
pParams[j].mMaterial = pFace->mMaterialIndex;
#define _AI_SAFE_FINDFACE2(Ps)\
{ pFace = pIn->FindFace2(pFace->m##Ps); ai_assert(pFace&&pFace->mNumCorners==iNumCorners); }
pFace = pIn->mFaces2+i; //! VERTICES
if(pFace->mParameterModes&aiParameterType_VERTEX) _AI_SAFE_FINDFACE2(Vertices)
if(pFace->mVertices!=0) for(unsigned int j=0;j<iNumCorners;j++)
pParams[j].mVertex = pFace->mIndices[pFace->mVertices+pFace->mStride*j];
pFace = pIn->mFaces2+i; //! NORMALS
if(pFace->mParameterModes&aiParameterType_NORMAL) _AI_SAFE_FINDFACE2(Normals)
if(pFace->mFaceFeatures&aiFaceFeature_NORMAL)
for(unsigned int j=0;j<iNumCorners;j++) pParams[j].mNormal = pFace->mIndices[0];
else if(pFace->mNormals!=0) for(unsigned int j=0;j<iNumCorners;j++)
pParams[j].mNormal = pFace->mIndices[pFace->mNormals+pFace->mStride*j];
pFace = pIn->mFaces2+i; //! COLORS
if(pFace->mParameterModes&aiParameterType_COLOR) _AI_SAFE_FINDFACE2(Colors)
if(pFace->mParameterModes&aiParameterType_COLOR)
for(unsigned int j=0;j<iNumCorners;j++) pParams[j].mColor = pFace->mIndices[1];
else if(pFace->mColors!=0) for(unsigned int j=0;j<iNumCorners;j++)
pParams[j].mColor = pFace->mIndices[pFace->mColors+pFace->mStride*j];
pFace = pIn->mFaces2+i; //! TEXTURECOORDS
if(pFace->mParameterModes&aiParameterType_TEXTURECOORDS) _AI_SAFE_FINDFACE2(TextureCoords)
if(pFace->mTextureCoords!=0) for(unsigned int j=0;j<iNumCorners;j++)
pParams[j].mTextureCoords = pFace->mIndices[pFace->mTextureCoords+pFace->mStride*j];
#undef _AI_SAFE_FINDFACE2
for(unsigned int j=0;j<iNumCorners;j++) AddParameters(pParams+j);
iCurParameters+=iNumCorners;
}
if(mMaterials==NULL) GetMaterial(pIn->mMaterialIndex);
Material *pIter = mMaterials;
for(unsigned int i=0;i<iMaxOut;i++)
{
pIter->mAssignedSubMesh = pOut[i] = new aiMesh;
pOut[i]->mPrimitiveTypes = pIn->mPrimitiveTypes;
pOut[i]->mFaces = new aiFace[pIter->mNumFacesApplicable];
for(unsigned int j=0;j<AI_MAX_NUMBER_OF_COLOR_SETS;j++)
pOut[i]->mNumUVComponents[j] = pIn->mNumUVComponents[j];
for(unsigned int j=0;j<AI_MAX_NUMBER_OF_TEXTURECOORDS;j++)
pOut[i]->mNumUVComponents[j] = pIn->mNumUVComponents[j];
pOut[i]->mMaterialIndex = pIter->mMaterialIndex;
unsigned int iNumVertices = 0;
for(unsigned int j=0;j<mNumBuffered;j++)
if(mBuffer[j].mMaterial==pIter->mMaterialIndex&&
mBuffer[j].mIsUnique==true)
iNumVertices++;
if(pIn->HasPositions())
pOut[i]->mVertices = new aiVector3D[iNumVertices];
if(pIn->HasNormals())
pOut[i]->mNormals = new aiVector3D[iNumVertices];
if(pIn->HasTangentsAndBitangents())
{ pOut[i]->mTangents = new aiVector3D[iNumVertices];
pOut[i]->mBitangents = new aiVector3D[iNumVertices]; }
int iNumChs = pIn->GetNumColorChannels();
for(unsigned int j=0;j<iNumChs;j++)
pOut[i]->mColors[j] = new aiColor4D[iNumVertices];
iNumChs = pIn->GetNumUVChannels();
for(unsigned int j=0;j<iNumChs;j++)
pOut[i]->mTextureCoords[j] = new aiVector3D[iNumVertices];
if(pIter->mNextInLoop==mMaterials) break;
}
//! Break out the non-unique vertices
for(unsigned int j=0;j<mNumBuffered;j++)
if(mBuffer[j].mIsUnique==true&&
mBuffer[j].mMoreByVertexIndex!=NULL&&
mBuffer[j].mMoreByVertexIndex->mIsUnique==false)
mBuffer[j].mMoreByVertexIndex = NULL;
iCurParameters = 0;
for(unsigned int i=0;i<pIn->mNumFaces;i++)
{
const aiFace2* pFace = pIn->mFaces2+i;
aiMesh *pSubMesh = GetMaterial(pFace->mMaterialIndex)->mAssignedSubMesh;
aiFace* pNewFace = pSubMesh->mFaces+pSubMesh->mNumFaces;
ProcessMeshHelper2::Parameters *pParams = mBuffer+iCurParameters;
iCurParameters+=pFace->mNumCorners;
if((signed)pParams->mVertex==-1) continue;
pNewFace->mIndices = new unsigned int[pNewFace->mNumIndices];
for(unsigned int j=0;j<pFace->mNumCorners;j++)
{
Parameters *pCmp = mIndex[pParams[j].mVertex];
while(pCmp&&*pCmp!=pParams[j]) pCmp++; ai_assert(pCmp!=NULL);
if(pCmp->mIsAssigned==false)
{
int iThisVert = pSubMesh->mNumVertices++;
if(pSubMesh->mVertices)
ai_assert(pIn->GetPosition(pCmp->mVertex,pSubMesh->mVertices+iThisVert));
if(pSubMesh->mNormals)
ai_assert(pIn->GetNormal(pCmp->mNormal,pSubMesh->mNormals+iThisVert));
if(pSubMesh->mTangents)
ai_assert(pIn->GetTangent(pCmp->mNormal,pSubMesh->mTangents+iThisVert));
if(pSubMesh->mBitangents)
ai_assert(pIn->GetBitangent(pCmp->mNormal,pSubMesh->mBitangents+iThisVert));
int iNumChs = pIn->GetNumColorChannels();
for(unsigned int k=0;k<iNumChs;k++)
ai_assert(pIn->GetVertexColor(k,pCmp->mColor,pSubMesh->mColors[k]+iThisVert));
iNumChs = pIn->GetNumUVChannels();
for(unsigned int k=0;k<iNumChs;k++)
ai_assert(pIn->GetTextureCoord(k,pCmp->mTextureCoords,
pSubMesh->mTextureCoords[k]+iThisVert));
pCmp->mNewIndex = iThisVert;
pCmp->mIsAssigned = true;
}
pNewFace->mIndices[j] = pCmp->mNewIndex;
}
pNewFace->mNumIndices = pFace->mNumCorners;
pSubMesh->mNumFaces++;
}
while(pOut[iCompleted]&&++iCompleted<iMaxOut);
}
DownLevelProcess::
ProcessMeshHelper2::~ProcessMeshHelper2()
{
if(mBuffer) delete [] mBuffer;
if(mIndex) delete [] mIndex;
if(mMaterials==NULL) return;
Material *pIter = mMaterials->mNextInLoop;
while(pIter!=mMaterials)
{
Material *pDtor = pIter; pIter = pIter->mNextInLoop;
delete pDtor;
}
delete mMaterials;
}
aiScene *aiScene2::TransferSceneDownLevel(aiScene *out)
{
//TODO: validate mMeshes fitness / mMeshes2
unsigned int n = mNumMeshes; aiMesh2 **m2 = mMeshes2;
aiMesh** m = NULL; if(n) m = new aiMesh*[n];
memset(m,0x00,sizeof(void*)*n);
unsigned int *mats = NULL;
for(unsigned int i=0,j=0;i<n;i++) if(m2[i])
{
for(j=1;j<m2[i]->mNumMaterials;j++)
if(j>=n||mMeshes2[j]!=NULL) goto failure;
if(DownLevelProcess::ProcessMesh2(m2[i],m+i,j)==0)
goto failure;
}
goto success;
failure:
for(unsigned int i=0;i<n;i++) if(m[i]) delete m[i];
if(m) delete [] m; if(mats) delete [] mats;
return NULL;
success:
//! same as PopulateSceneSublevel()
if(out==this) return this;
if(out==NULL) out = new aiScene;
mNumMeshes = 0; mMeshes2 = NULL;
memcpy(out,this,sizeof(aiScene));
memcpy(this,0x00,sizeof(aiScene));
for(unsigned int i=0;i<n;i++) if(m2[i]) delete m2[i];
delete [] m2; delete this;
out->mMeshes = m; out->mNumMeshes = n;
return out;
}
SomFileHelper::SomFileHelper(const void *eof, aiScene *out)
{
pcEof = eof; pAssimp = out;
pAssimp2 = NULL; if(pAssimp==NULL) return;
pAssimp2 = new aiScene2(out);
}
SomFileHelper::~SomFileHelper()
{
if(pAssimp==NULL) return;
pAssimp2->TransferSceneDownLevel(pAssimp);
}
bool SomFileHelper::detect(const MDL::Header_SOM *in)const
{
#ifdef NDEBUG
return false; //work in progress
#endif
ai_assert(pcEof!=NULL);
if(!in->num_parts)
{
if(pAssimp) throw new ImportErrorException("[Sword of Moonlight MDL] A MDL must contain at least one model");
return false;
}
if(!pAssimp) return true;
ai_assert(pAssimp2->mNumMeshes==0);
pAssimp2->mNumMeshes = 1+AI_BE(in->num_parts)*AI_BE(in->num_skins);
pAssimp2->mMeshes2 = new aiMesh2*[pAssimp2->mNumMeshes];
memset(pAssimp2->mMeshes2,0x00,sizeof(void*)*pAssimp2->mNumMeshes);
MaterialHelper *pMatDefault = new MaterialHelper;
const int iMode = (int)aiShadingMode_Gouraud;
pMatDefault->AddProperty<int>(&iMode,1,AI_MATKEY_SHADING_MODEL);
pAssimp2->mNumMaterials = max(AI_BE(in->num_skins),1);
pAssimp2->mMaterials = new aiMaterial*[pAssimp2->mNumMaterials];
for(unsigned int i=0;i<pAssimp2->mNumMaterials;i++)
pAssimp2->mMaterials[i] = pMatDefault;
return true; //TODO: flesh out
}
const int32_t *SomFileHelper::offset(const MDL::Header_SOM *in, int cc, int pt)const
{
return (const int32_t*)(in?(const char*)in+in->offset(cc,pt)*4:NULL);
}
bool SomFileHelper::unpack(const MDL::Header_SOM *in,
const MDL::Packet_SOM **inout, int cc, int pt)const
{
ai_assert(pAssimp&&pcEof);
const MDL::Packet_SOM *p = *inout;
pAssimp2->mFlags2|=AI_SCENE_FLAGS2_INCOMPLETE;
unsigned int iPart = 1+pt*AI_BE(in->num_skins);
ai_assert(pAssimp2!=NULL&&pAssimp2->mNumMeshes>=iPart);
aiMesh2 *pPart = pAssimp2->mMeshes2[iPart];
if(pPart==NULL) switch(cc)
{
case 'face': case 'vert': case 'norm':
pPart = pAssimp2->mMeshes2[iPart] = new aiMesh2;
pPart->mPrimitiveTypes =
aiPrimitiveType_TRIANGLE|aiPrimitiveType_POLYGON;
pPart->mSharedParameters = pAssimp2->mMeshes2[0];
pPart->mNumMaterials = AI_BE(in->num_skins);
}
switch(cc)
{
case 'base': //! shared parameters block (uv components more or less)
{
int iShared = AI_BE(p->lo); if(iShared==0) return false; //block is empty
sizecheck((const char*)p+4+iShared*12); //! expected end of block
ai_assert(pAssimp2->mNumMeshes==0&&pAssimp2->mMeshes2!=NULL);
int iCurMaterial = AI_BE(p->hi); int iCurIndex = 0;
aiMesh2 *pShared = pAssimp2->mMeshes2[0] = new aiMesh2; //shared mesh
pShared->mNumMaterials = 1; pShared->mMaterialIndex = iCurMaterial;
pShared->mNumUVComponents[0] = 2;
pShared->mTextureCoords[0] = new aiVector3D[pShared->mNumTextureCoords=iShared*4];
for(int i=0;i<iShared;i++) if((++p)->hi==0)
{
aiFace2 *pFace2 = pShared->mFaces2+i;
pFace2->mMaterialIndex = iCurMaterial;
pFace2->mIndices = new unsigned int[pFace2->mNumIndices=5];
memset(pFace2->mIndices,0x00,5*sizeof(int));
pFace2->mNumCorners = 4; pFace2->mStride = 1;
pFace2->mTextureCoords = 1;
pShared->mTextureCoords[0][iCurIndex] = aiVector3D(p->s,p->t,0.0f); //lo
pFace2->mIndices[1] = iCurIndex++; p++;
pShared->mTextureCoords[0][iCurIndex] = aiVector3D(p->s,p->t,0.0f); //lo
//! Note that the hi 16bits here house potentially meaningful flags
pFace2->mIndices[2] = iCurIndex++; p++;
pShared->mTextureCoords[0][iCurIndex] = aiVector3D(p->s,p->t,0.0f); //lo
pFace2->mIndices[3] = iCurIndex++;
pShared->mTextureCoords[0][iCurIndex] = aiVector3D(p->u,p->v,0.0f); //hi
pFace2->mIndices[4] = iCurIndex++;
}
else
{
DefaultLogger::get()->warn("Sword of Moonlight MDL shared texture mapping block not as expected. Block left incomplete");
return false;
}
break;
}
case 'face': //! face packets block
{
int iFaces = AI_BE(in->parts[pt].num_faces);
if(iFaces==0||p->lo==0) return false; //faces absent
pPart->mFaces2 = new aiFace2[pPart->mNumFaces=iFaces];
for(int i=0;i<iFaces;i++) if((++p+1)->hi==0)
{
aiFace2 *pFace2 = pPart->mFaces2+i;
//TODO: tomorrow.........................
}
break;
}
case 'vert': //! vertex packets block
{
int iVerts = AI_BE(in->parts[pt].num_verts);
if(iVerts==0) return false; //vertices absent
sizecheck((const char*)p+iVerts*8); //expected end of block
pPart->mVertices = new aiVector3D[pPart->mNumVertices=iVerts];
for(int i=0;i<iVerts;i++) if((p+1)->hi==0)
{
pPart->mVertices[i].x = (int16_t)AI_BE(p->lo);
pPart->mVertices[i].y = (int16_t)AI_BE(p->hi); p++;
pPart->mVertices[i].z = (int16_t)AI_BE(p->lo);
}
else
{
DefaultLogger::get()->warn("Sword of Moonlight MDL high 16bits of 2nd packet in vertex block non-zero. Block left incomplete");
return false;
}
break;
}
case 'norm': //! normal packets block
{
int iNorms = AI_BE(in->parts[pt].num_norms);
if(iNorms==0) return false; //normals absent
sizecheck((const char*)p+iNorms*8); //expected end of block
pPart->mNormals = new aiVector3D[pPart->mNumNormals=iNorms];
for(int i=0;i<iNorms;i++) if((p+1)->hi==0)
{
pPart->mNormals[i].x = (int16_t)AI_BE(p->lo);
pPart->mNormals[i].y = (int16_t)AI_BE(p->hi); p++;
pPart->mNormals[i].z = (int16_t)AI_BE(p->lo);
}
else
{
DefaultLogger::get()->warn("Sword of Moonlight MDL high 16bits of 2nd packet in normals block non-zero. Block left incomplete");
return false;
}
break;
}
case 'anim': //! reference frame (skeletal) animation block
{
if(in->num_anims==0||in->add_anims==0) return false; //animation absent
return false; //unimplemented thus far
}
case 'stop': //! stop-motion (deformer) animation block
{
if(in->num_stops==0||in->add_stops==0) return false; //animation absent
return false; //unimplemented thus far
}
default: return false;
}
pAssimp2->mFlags2&=~AI_SCENE_FLAGS2_INCOMPLETE;
*inout = p; return false;
}
static void TIMpixelmode2(aiTexel *inout, uint16_t pm2)
{
inout->r = (pm2&0x1F)*8; inout->g = ((pm2&0x3E0)>>8)*8;
inout->b = ((pm2&0x7C00)>>8)*8; inout->a = 0;
}
bool SomFileHelper::bitmap(const MDL::Header_SOM *in, const MDL::Bitmap_SOM **inout)const
{
ai_assert(pAssimp&&pcEof);
if(in->num_skins==0) return false;
const MDL::Bitmap_SOM *p = *inout;
if(p->id!=0x10)
{
DefaultLogger::get()->warn("Sword of Moonlight MDL texture appears not to be TIM bitmap format. Ignoring further texture data");
return false;
}
const MDL::Bitmap_SOM::BLOCK *clut = p->clut_block();
const MDL::Bitmap_SOM::BLOCK *data = p->data_block();
if(p->pmode<0x02&&clut==0)
{
DefaultLogger::get()->warn("Sword of Moonlight MDL texture appears to contain paletted data but is missing a color lookup table. Ignoring further texture data");
return false;
}
sizecheck((const char*)data+AI_BE(data->bnum));
sizecheck((const char*)data+2*AI_BE(data->w)*AI_BE(data->h)+12);
if(clut) sizecheck((const char*)clut+AI_BE(clut->bnum));
if(clut) sizecheck((const char*)clut+2*AI_BE(clut->w)*AI_BE(clut->h)+12);
if(pAssimp2->mNumTextures>=in->num_skins)
{
DefaultLogger::get()->warn("Sword of Moonlight MDL texture appears to have exceeded the ammount indicated by the header. Ignoring further texture data");
return false;
}
if(!pAssimp2->mNumTextures) pAssimp2->mTextures = new aiTexture*[in->num_skins];
aiTexture *q = pAssimp2->mTextures[pAssimp2->mNumTextures] = new aiTexture;
float fWidth = AI_BE(data->w);
switch(p->pmode)
{
case 0x00: fWidth*=4.0f; break;
case 0x01: fWidth*=2.0f; break;
case 0x02: break;
case 0x03:
case 0x04: fWidth = fWidth/3.0f*2.0f;
}
if(fWidth-int(fWidth)!=0.0f)
{
DefaultLogger::get()->warn("Sword of Moonlight MDL texture width appears not to comply with TIM Pixel mode specification. Ignoring further textures");
return false;
}
q->mWidth = (unsigned int)fWidth; q->mHeight = AI_BE(data->h);
aiTexel *d = q->pcData = new aiTexel[q->mWidth*q->mHeight];
if(p->pmode==0x04) DefaultLogger::get()->warn("Sword of Moonlight MDL texture appears to be \"mixed\" mode. Interpreting as 24bit color");
int h = AI_BE(data->h), w = AI_BE(data->w);
for(int i=0;i<h;i++) for(int j=0;j<w;j++)
{
uint16_t e = data->data[i*w+j]; AI_SWAP2(e);
switch(p->pmode)
{
case 0x00:
TIMpixelmode2(d++,clut->data[(e&&0x000F)>>0]);
TIMpixelmode2(d++,clut->data[(e&&0x00F0)>>4]);
TIMpixelmode2(d++,clut->data[(e&&0x0F00)>>8]);
TIMpixelmode2(d++,clut->data[(e&&0xF000)>>12]); break;
case 0x01:
TIMpixelmode2(d++,clut->data[(e&&0x00FF)>>0]);
TIMpixelmode2(d++,clut->data[(e&&0xFF00)>>8]); break;
case 0x02: TIMpixelmode2(d,e); break;
case 0x03: case 0x04:
d->r = e&0xFF; d->g = (e&0xFF00)>>8;
e = data->data[i*w+++j]; AI_SWAP2(e);
d->b = e&0xFF; d->a = 0;
++d->r = (e&0xFF00)>>8;
e = data->data[i*w+++j]; AI_SWAP2(e);
d->g = e&0xFF; d->b = (e&0xFF00)>>8;
d->a = 0; d++;
}
}
pAssimp2->mNumTextures++;
int next = sizeof(MDL::Bitmap_SOM)+data->bnum;
if(clut) next+=clut->bnum;
*(char**)inout+=next;
if(pAssimp2->mNumTextures>=in->num_skins) return false;
return true;
}
[/code]
EDITED: I was getting a maximum of something like 300000 characters (plus or minus a figure) so I was going to add the cpp file as an attachment but the second shot (minus just the license header) little did I know must've gone thru.
Let Todd decide if the character limit seems practical or not.
/** @file Implementation of the Sword of Moonlight MDL/MDO helper routines */
#include "AssimpPCH.h"
#ifndef max
#define max(a, b) (((a) > (b)) ? (a) : (b))
#endif
// internal headers
#include "SomFileHelper.h"
using namespace Assimp;
using namespace Assimp_x;
namespace Assimp_x{ //! experimental
enum aiParameterType
{
aiParameterType_VERTEX = 0x1,
aiParameterType_NORMAL = 0x2,
aiParameterType_COLOR = 0x4,
//! or aiParameterType_TEXTURECOORD?
aiParameterType_TEXTURECOORDS = 0x8,
_aiParameterType_Force32Bit = 0x9fffffff
}; //! enum aiParameterType
enum aiFaceFeature
{
aiFaceFeature_NORMAL = 0x1,
aiFaceFeature_COLOR = 0x2,
_aiFaceFeature_Force32Bit = 0x9fffffff
}; //! enum aiFaceFeature
struct aiFace2 : public aiFace
{
/** Bitwise combination of the members of the #aiFaceFeature enum.
* aiFaceFeature_NORMAL: mIndices[0] is face normal index
* aiFaceFeature_COLOR: mIndices[1] is face color index
*/
unsigned int mFaceFeatures;
/** Bitwise combination of the members of the #aiParameterType enum.
* This specifies whether the corresponding index looks in the mIndices
* array when the bits are not set or into another aiFace2 when set.
*/
unsigned int mParameterModes;
//! one parameter exists per corner per type
unsigned int mNumCorners;
//! offset between like parameter indices
unsigned int mStride;
/** first vertex index into mIndices.
* mIndices[0] is reserved for the face normal.
* Therefore if mVertices, mNormals, etc, is 0
* (and the corresponding mParameterModes bit is unset)
* the parameter data is taken not to exist.
*/
unsigned int mVertices;
//! tangents and bitangents overlap
unsigned int mNormals;
//! color channels overlap
unsigned int mColors;
//! uv channels overlap
unsigned int mTextureCoords;
//! overrides mesh mMaterialIndex member
unsigned int mMaterialIndex;
#ifdef __cplusplus
//! Default constructor
aiFace2()
{
mFaceFeatures = 0x00000000;
mParameterModes = 0x00000000;
mNumCorners = mStride = 0;
mVertices = mNormals = mColors = mTextureCoords = 0;
mMaterialIndex = 0;
}
#endif // __cplusplus
};
struct aiMesh2 : public aiMesh
{
//! tangents and bitangents overlap
unsigned int mNumNormals;
//! color channels overlap
unsigned int mNumColors;
//! uv channels overlap
unsigned int mNumTextureCoords;
C_STRUCT aiFace2* mFaces2;
/** Number of mFaces2 materials
* Used to pad aiScene::mNumMeshes
* so aiNode::mMeshes can reference
* both aiMeshes and aiMeshes2.
*/
unsigned int mNumMaterials;
/** Parameters shared across meshes
* If set this should be a mesh in the
* scene mMeshes2 member. To see how
* it works see GetPosition() below.
* Not meant to be recursive.
*/
C_STRUCT aiMesh2* mSharedParameters;
#define _AIMESH2_GETPARAMETER(Ps,Ns)\
\
if(mSharedParameters)\
{\
if(pIndex<mSharedParameters->mNum##Ns)\
{\
if(mSharedParameters->m##Ps==NULL) return false;\
\
*pOut = mSharedParameters->m##Ps[pIndex]; return true;\
}\
else pIndex-=mSharedParameters->mNum##Ns;\
}\
else if(m##Ps==NULL||pIndex>=mNum##Ns) return false;\
\
*pOut = m##Ps[pIndex]; return true;
bool GetPosition(unsigned int pIndex, aiVector3D* pOut)const
{ _AIMESH2_GETPARAMETER(Vertices,Vertices) }
bool GetNormal(unsigned int pIndex, aiVector3D* pOut)const
{ _AIMESH2_GETPARAMETER(Normals,Normals) }
bool GetTangent(unsigned int pIndex, aiVector3D* pOut)const
{ _AIMESH2_GETPARAMETER(Tangents,Normals) }
bool GetBitangent(unsigned int pIndex, aiVector3D* pOut)const
{ _AIMESH2_GETPARAMETER(Bitangents,Normals) }
bool GetVertexColor(unsigned int pChannel, unsigned int pIndex, aiColor4D* pOut)const
{
if(pChannel>=AI_MAX_NUMBER_OF_COLOR_SETS) return false;
_AIMESH2_GETPARAMETER(Colors[pChannel],Colors)
}
//! GetTextureCoords or GetTextureCoord?
bool GetTextureCoord(unsigned int pChannel, unsigned int pIndex, aiVector3D* pOut)const
{
if(pChannel>=AI_MAX_NUMBER_OF_TEXTURECOORDS) return false;
_AIMESH2_GETPARAMETER(TextureCoords[pChannel],TextureCoords)
}
#undef _AIMESH2_GETPARAMETER
/** Find face for shared parameter indices
* The shared faces are logically mapped to the parameter space
* but do not constitute part of the mesh. That is they are for
* referencing parameters only.
*/
aiFace2 *FindFace2(unsigned int pIndex)const
{
if(mSharedParameters)
{
if(pIndex<mSharedParameters->mNumFaces)
{
if(mSharedParameters->mFaces2==NULL) return NULL;
return mSharedParameters->mFaces2+pIndex;
}
else pIndex-=mSharedParameters->mNumFaces;
}
else if(pIndex>mNumFaces||!mFaces2==NULL) return NULL;
return mFaces2+pIndex;
}
#ifdef __cplusplus
//! Default constructor. Initializes all members to 0
aiMesh2()
{
mNumNormals = mNumColors = mNumTextureCoords = 0;
mFaces2 = NULL; mNumMaterials = 0;
mSharedParameters = NULL;
}
~aiMesh2()
{
if(mFaces2) delete [] mFaces2;
}
#endif // __cplusplus
#define _AIMESH2_HASPARAMETERS(TEST,F)\
\
if(TEST) return true; if(mSharedParameters==NULL) return false;\
\
return mSharedParameters->Has##F;
inline bool HasPositions()const
{ _AIMESH2_HASPARAMETERS(mVertices!=NULL&&mNumVertices>0,Positions()) }
//! instead of this use hasFaces2()
inline bool HasFaces()const{ return false; }
inline bool HasFaces2()const
{ _AIMESH2_HASPARAMETERS(mFaces2!=NULL&&mNumFaces>0,Faces2()) }
inline bool HasNormals()const
{ _AIMESH2_HASPARAMETERS(mNormals!=NULL&&mNumNormals>0,Normals()) }
inline bool HasTangentsAndBitangents()const
{ _AIMESH2_HASPARAMETERS(mTangents!=NULL&&mBitangents!=NULL&&mNumNormals>0,TangentsAndBitangents()) }
inline bool HasVertexColors(unsigned int pIndex)const
{
if(pIndex>=AI_MAX_NUMBER_OF_COLOR_SETS) return false;
_AIMESH2_HASPARAMETERS(mColors[pIndex]!=NULL&&mNumColors>0,VertexColors(pIndex))
}
inline bool HasTextureCoords(unsigned int pIndex)const
{
if(pIndex>=AI_MAX_NUMBER_OF_TEXTURECOORDS) return false;
_AIMESH2_HASPARAMETERS(mTextureCoords[pIndex]!=NULL&&mNumTextureCoords>0,TextureCoords(pIndex))
}
#undef _AIMESH2_HASPARAMETERS
};
#define AI_SCENE_FLAGS2_INCOMPLETE 0x1
struct aiScene2 : public aiScene
{
unsigned int mFlags2;
/** The array of meshes.
*
* Use the indices given in the aiNode structure to access
* this array. The array is mNumMeshes in size.
*/
C_STRUCT aiMesh2** mMeshes2;
/**Populates aiScene members of pScene with own data and deletes self
* Equivalent to PopulateSceneSublevel() when out is 'this'.
*/
aiScene *TransferSceneDownLevel(aiScene *out = NULL);
/*Populates aiScene base members reflecting aiScene2 members*/
bool PopulateSceneSubLevel()
{
return TransferSceneDownLevel(this)!=NULL?true:false;
}
#ifdef __cplusplus
/** Constructor */
aiScene2(aiScene *cp) : aiScene(*cp)
{
mFlags2 = 0x00000000; mMeshes2 = NULL;
}
#endif // __cplusplus
};
} //end namespace Assimp_x
class DownLevelProcess
{
struct ProcessMeshHelper2;
public:
static int ProcessMesh2(const aiMesh2 *pIn, aiMesh** pOut, int iMaxOut)
{
return ProcessMeshHelper2(pIn,pOut,iMaxOut);
}
private:
struct ProcessMeshHelper2
{
/** The input will be decomposed into separate
* materials upto iMaxOut count. Any remaining meshes
* will not be carried over.
*/
ProcessMeshHelper2(const aiMesh2 *pIn, aiMesh** pOut, int iMaxOut);
~ProcessMeshHelper2();
inline operator int(){ return iCompleted; }
protected:
struct Parameters
{
union
{
//! omitted indices are presently -1
unsigned int mIndices[5];
struct //! for sake of clarity
{
unsigned int mMaterial;
unsigned int mVertex;
unsigned int mNormal;
unsigned int mColor;
unsigned int mTextureCoords; //or mTextureCoord?
};
};
bool mIsUnique;
bool mIsAssigned;
unsigned int mNewIndex;
Parameters *mMoreByVertexIndex;
inline bool operator==(const Parameters &o)
{
return memcmp(mIndices,o.mIndices,5*sizeof(int))==0;
}
inline bool operator!=(const Parameters &o)
{
return memcmp(mIndices,o.mIndices,5*sizeof(int))!=0;
}
Parameters()
{
mMaterial = 0;
for(int i=1;i<5;i++) mIndices[i] = -1;
mIsUnique = mIsAssigned = false;
mNewIndex = -1;
}
};
struct Material
{
aiMesh *mAssignedSubMesh;
unsigned int mMaterialIndex;
unsigned int mNumFacesApplicable;
Material *mNextInLoop;
Material(unsigned int iMatIndex, Material *pNext = NULL)
{
mAssignedSubMesh = NULL;
mMaterialIndex = iMatIndex;
mNextInLoop = pNext?pNext:this;
mNumFacesApplicable = 0;
}
};
unsigned int mNumBuffered;
Parameters* mBuffer;
unsigned int mNumIndexed;
Parameters** mIndex;
Material* mMaterials; //STL might be safer
Material* GetMaterial(unsigned int iMatIndex)
{
if(mMaterials==NULL) return mMaterials = new Material(iMatIndex);
if(mMaterials->mMaterialIndex==iMatIndex) return mMaterials;
Material *pOut = mMaterials->mNextInLoop;
while(pOut!=mMaterials&&pOut->mMaterialIndex!=iMatIndex)
pOut = pOut->mNextInLoop;
if(pOut==mMaterials)
pOut = pOut->mNextInLoop = new Material(iMatIndex,mMaterials);
//order could be optimized for meshes with many materials
return mMaterials = pOut;
}
Parameters* AddParameters(Parameters *pParams)
{
//! do not add to index if position parameter is omitted
if((signed)pParams->mVertex==-1) return pParams;
for(Parameters *pIter=mIndex[pParams->mVertex];
pIter&&pIter->mIsUnique;pIter++)
{
if(pIter->mIsUnique==false) break; //reached duplicate so this is unique
if(*pParams==*pIter)
{
while(pIter->mMoreByVertexIndex&&
pIter->mMoreByVertexIndex->mIsUnique)
pIter = pIter->mMoreByVertexIndex;
ai_assert(pParams->mIsUnique==false);
pParams->mMoreByVertexIndex = pIter->mMoreByVertexIndex;
return pIter->mMoreByVertexIndex = pParams;
}
}
pParams->mIsUnique = true;
pParams->mMoreByVertexIndex = mIndex[pParams->mVertex];
return mIndex[pParams->mVertex] = pParams;
}
const aiMesh2* pInput;
aiMesh** pOutput;
int iMaxOutput;
int iCompleted;
};
};
DownLevelProcess::
ProcessMeshHelper2::ProcessMeshHelper2(const aiMesh2 *pIn, aiMesh** pOut, int iMaxOut)
{
memset(this,0x00,sizeof(ProcessMeshHelper2));
if(pIn==NULL||pOut==NULL||iMaxOut<=0) return;
pInput = pIn; pOutput = pOut; iMaxOutput = iMaxOut;
mNumIndexed = pIn->mNumVertices; mNumBuffered = 0;
for(unsigned int i=0;i<pIn->mNumFaces;i++)
mNumBuffered+=pIn->mFaces2[i].mNumCorners;
if(pIn->mSharedParameters)
{
mNumIndexed+=pIn->mSharedParameters->mNumVertices;
for(unsigned int i=0;i<pIn->mSharedParameters->mNumFaces;i++)
mNumBuffered+=pIn->mSharedParameters->mFaces2[i].mNumCorners;
}
mBuffer = new ProcessMeshHelper2::Parameters[mNumBuffered];
mIndex = new ProcessMeshHelper2::Parameters*[mNumIndexed];
memset(mBuffer,0x00,mNumBuffered*sizeof(ProcessMeshHelper2::Parameters*));
memset(mIndex,0x00,mNumIndexed*sizeof(void*));
unsigned int iCurParameters = 0;
for(unsigned int i=0;i<pIn->mNumFaces;i++)
{
ProcessMeshHelper2::Parameters *pParams = mBuffer+iCurParameters;
const aiFace2* pFace = pIn->mFaces2+i; //! MATERIAL
GetMaterial(pFace->mMaterialIndex)->mNumFacesApplicable++;
int iNumCorners = pFace->mNumCorners;
for(unsigned int j=0;j<iNumCorners;j++)
pParams[j].mMaterial = pFace->mMaterialIndex;
#define _AI_SAFE_FINDFACE2(Ps)\
{ pFace = pIn->FindFace2(pFace->m##Ps); ai_assert(pFace&&pFace->mNumCorners==iNumCorners); }
pFace = pIn->mFaces2+i; //! VERTICES
if(pFace->mParameterModes&aiParameterType_VERTEX) _AI_SAFE_FINDFACE2(Vertices)
if(pFace->mVertices!=0) for(unsigned int j=0;j<iNumCorners;j++)
pParams[j].mVertex = pFace->mIndices[pFace->mVertices+pFace->mStride*j];
pFace = pIn->mFaces2+i; //! NORMALS
if(pFace->mParameterModes&aiParameterType_NORMAL) _AI_SAFE_FINDFACE2(Normals)
if(pFace->mFaceFeatures&aiFaceFeature_NORMAL)
for(unsigned int j=0;j<iNumCorners;j++) pParams[j].mNormal = pFace->mIndices[0];
else if(pFace->mNormals!=0) for(unsigned int j=0;j<iNumCorners;j++)
pParams[j].mNormal = pFace->mIndices[pFace->mNormals+pFace->mStride*j];
pFace = pIn->mFaces2+i; //! COLORS
if(pFace->mParameterModes&aiParameterType_COLOR) _AI_SAFE_FINDFACE2(Colors)
if(pFace->mParameterModes&aiParameterType_COLOR)
for(unsigned int j=0;j<iNumCorners;j++) pParams[j].mColor = pFace->mIndices[1];
else if(pFace->mColors!=0) for(unsigned int j=0;j<iNumCorners;j++)
pParams[j].mColor = pFace->mIndices[pFace->mColors+pFace->mStride*j];
pFace = pIn->mFaces2+i; //! TEXTURECOORDS
if(pFace->mParameterModes&aiParameterType_TEXTURECOORDS) _AI_SAFE_FINDFACE2(TextureCoords)
if(pFace->mTextureCoords!=0) for(unsigned int j=0;j<iNumCorners;j++)
pParams[j].mTextureCoords = pFace->mIndices[pFace->mTextureCoords+pFace->mStride*j];
#undef _AI_SAFE_FINDFACE2
for(unsigned int j=0;j<iNumCorners;j++) AddParameters(pParams+j);
iCurParameters+=iNumCorners;
}
if(mMaterials==NULL) GetMaterial(pIn->mMaterialIndex);
Material *pIter = mMaterials;
for(unsigned int i=0;i<iMaxOut;i++)
{
pIter->mAssignedSubMesh = pOut[i] = new aiMesh;
pOut[i]->mPrimitiveTypes = pIn->mPrimitiveTypes;
pOut[i]->mFaces = new aiFace[pIter->mNumFacesApplicable];
for(unsigned int j=0;j<AI_MAX_NUMBER_OF_COLOR_SETS;j++)
pOut[i]->mNumUVComponents[j] = pIn->mNumUVComponents[j];
for(unsigned int j=0;j<AI_MAX_NUMBER_OF_TEXTURECOORDS;j++)
pOut[i]->mNumUVComponents[j] = pIn->mNumUVComponents[j];
pOut[i]->mMaterialIndex = pIter->mMaterialIndex;
unsigned int iNumVertices = 0;
for(unsigned int j=0;j<mNumBuffered;j++)
if(mBuffer[j].mMaterial==pIter->mMaterialIndex&&
mBuffer[j].mIsUnique==true)
iNumVertices++;
if(pIn->HasPositions())
pOut[i]->mVertices = new aiVector3D[iNumVertices];
if(pIn->HasNormals())
pOut[i]->mNormals = new aiVector3D[iNumVertices];
if(pIn->HasTangentsAndBitangents())
{ pOut[i]->mTangents = new aiVector3D[iNumVertices];
pOut[i]->mBitangents = new aiVector3D[iNumVertices]; }
int iNumChs = pIn->GetNumColorChannels();
for(unsigned int j=0;j<iNumChs;j++)
pOut[i]->mColors[j] = new aiColor4D[iNumVertices];
iNumChs = pIn->GetNumUVChannels();
for(unsigned int j=0;j<iNumChs;j++)
pOut[i]->mTextureCoords[j] = new aiVector3D[iNumVertices];
if(pIter->mNextInLoop==mMaterials) break;
}
//! Break out the non-unique vertices
for(unsigned int j=0;j<mNumBuffered;j++)
if(mBuffer[j].mIsUnique==true&&
mBuffer[j].mMoreByVertexIndex!=NULL&&
mBuffer[j].mMoreByVertexIndex->mIsUnique==false)
mBuffer[j].mMoreByVertexIndex = NULL;
iCurParameters = 0;
for(unsigned int i=0;i<pIn->mNumFaces;i++)
{
const aiFace2* pFace = pIn->mFaces2+i;
aiMesh *pSubMesh = GetMaterial(pFace->mMaterialIndex)->mAssignedSubMesh;
aiFace* pNewFace = pSubMesh->mFaces+pSubMesh->mNumFaces;
ProcessMeshHelper2::Parameters *pParams = mBuffer+iCurParameters;
iCurParameters+=pFace->mNumCorners;
if((signed)pParams->mVertex==-1) continue;
pNewFace->mIndices = new unsigned int[pNewFace->mNumIndices];
for(unsigned int j=0;j<pFace->mNumCorners;j++)
{
Parameters *pCmp = mIndex[pParams[j].mVertex];
while(pCmp&&*pCmp!=pParams[j]) pCmp++; ai_assert(pCmp!=NULL);
if(pCmp->mIsAssigned==false)
{
int iThisVert = pSubMesh->mNumVertices++;
if(pSubMesh->mVertices)
ai_assert(pIn->GetPosition(pCmp->mVertex,pSubMesh->mVertices+iThisVert));
if(pSubMesh->mNormals)
ai_assert(pIn->GetNormal(pCmp->mNormal,pSubMesh->mNormals+iThisVert));
if(pSubMesh->mTangents)
ai_assert(pIn->GetTangent(pCmp->mNormal,pSubMesh->mTangents+iThisVert));
if(pSubMesh->mBitangents)
ai_assert(pIn->GetBitangent(pCmp->mNormal,pSubMesh->mBitangents+iThisVert));
int iNumChs = pIn->GetNumColorChannels();
for(unsigned int k=0;k<iNumChs;k++)
ai_assert(pIn->GetVertexColor(k,pCmp->mColor,pSubMesh->mColors[k]+iThisVert));
iNumChs = pIn->GetNumUVChannels();
for(unsigned int k=0;k<iNumChs;k++)
ai_assert(pIn->GetTextureCoord(k,pCmp->mTextureCoords,
pSubMesh->mTextureCoords[k]+iThisVert));
pCmp->mNewIndex = iThisVert;
pCmp->mIsAssigned = true;
}
pNewFace->mIndices[j] = pCmp->mNewIndex;
}
pNewFace->mNumIndices = pFace->mNumCorners;
pSubMesh->mNumFaces++;
}
while(pOut[iCompleted]&&++iCompleted<iMaxOut);
}
DownLevelProcess::
ProcessMeshHelper2::~ProcessMeshHelper2()
{
if(mBuffer) delete [] mBuffer;
if(mIndex) delete [] mIndex;
if(mMaterials==NULL) return;
Material *pIter = mMaterials->mNextInLoop;
while(pIter!=mMaterials)
{
Material *pDtor = pIter; pIter = pIter->mNextInLoop;
delete pDtor;
}
delete mMaterials;
}
aiScene *aiScene2::TransferSceneDownLevel(aiScene *out)
{
//TODO: validate mMeshes fitness / mMeshes2
unsigned int n = mNumMeshes; aiMesh2 **m2 = mMeshes2;
aiMesh** m = NULL; if(n) m = new aiMesh*[n];
memset(m,0x00,sizeof(void*)*n);
unsigned int *mats = NULL;
for(unsigned int i=0,j=0;i<n;i++) if(m2[i])
{
for(j=1;j<m2[i]->mNumMaterials;j++)
if(j>=n||mMeshes2[j]!=NULL) goto failure;
if(DownLevelProcess::ProcessMesh2(m2[i],m+i,j)==0)
goto failure;
}
goto success;
failure:
for(unsigned int i=0;i<n;i++) if(m[i]) delete m[i];
if(m) delete [] m; if(mats) delete [] mats;
return NULL;
success:
//! same as PopulateSceneSublevel()
if(out==this) return this;
if(out==NULL) out = new aiScene;
mNumMeshes = 0; mMeshes2 = NULL;
memcpy(out,this,sizeof(aiScene));
memcpy(this,0x00,sizeof(aiScene));
for(unsigned int i=0;i<n;i++) if(m2[i]) delete m2[i];
delete [] m2; delete this;
out->mMeshes = m; out->mNumMeshes = n;
return out;
}
SomFileHelper::SomFileHelper(const void *eof, aiScene *out)
{
pcEof = eof; pAssimp = out;
pAssimp2 = NULL; if(pAssimp==NULL) return;
pAssimp2 = new aiScene2(out);
}
SomFileHelper::~SomFileHelper()
{
if(pAssimp==NULL) return;
pAssimp2->TransferSceneDownLevel(pAssimp);
}
bool SomFileHelper::detect(const MDL::Header_SOM *in)const
{
#ifdef NDEBUG
return false; //work in progress
#endif
ai_assert(pcEof!=NULL);
if(!in->num_parts)
{
if(pAssimp) throw new ImportErrorException("[Sword of Moonlight MDL] A MDL must contain at least one model");
return false;
}
if(!pAssimp) return true;
ai_assert(pAssimp2->mNumMeshes==0);
pAssimp2->mNumMeshes = 1+AI_BE(in->num_parts)*AI_BE(in->num_skins);
pAssimp2->mMeshes2 = new aiMesh2*[pAssimp2->mNumMeshes];
memset(pAssimp2->mMeshes2,0x00,sizeof(void*)*pAssimp2->mNumMeshes);
MaterialHelper *pMatDefault = new MaterialHelper;
const int iMode = (int)aiShadingMode_Gouraud;
pMatDefault->AddProperty<int>(&iMode,1,AI_MATKEY_SHADING_MODEL);
pAssimp2->mNumMaterials = max(AI_BE(in->num_skins),1);
pAssimp2->mMaterials = new aiMaterial*[pAssimp2->mNumMaterials];
for(unsigned int i=0;i<pAssimp2->mNumMaterials;i++)
pAssimp2->mMaterials[i] = pMatDefault;
return true; //TODO: flesh out
}
const int32_t *SomFileHelper::offset(const MDL::Header_SOM *in, int cc, int pt)const
{
return (const int32_t*)(in?(const char*)in+in->offset(cc,pt)*4:NULL);
}
bool SomFileHelper::unpack(const MDL::Header_SOM *in,
const MDL::Packet_SOM **inout, int cc, int pt)const
{
ai_assert(pAssimp&&pcEof);
const MDL::Packet_SOM *p = *inout;
pAssimp2->mFlags2|=AI_SCENE_FLAGS2_INCOMPLETE;
unsigned int iPart = 1+pt*AI_BE(in->num_skins);
ai_assert(pAssimp2!=NULL&&pAssimp2->mNumMeshes>=iPart);
aiMesh2 *pPart = pAssimp2->mMeshes2[iPart];
if(pPart==NULL) switch(cc)
{
case 'face': case 'vert': case 'norm':
pPart = pAssimp2->mMeshes2[iPart] = new aiMesh2;
pPart->mPrimitiveTypes =
aiPrimitiveType_TRIANGLE|aiPrimitiveType_POLYGON;
pPart->mSharedParameters = pAssimp2->mMeshes2[0];
pPart->mNumMaterials = AI_BE(in->num_skins);
}
switch(cc)
{
case 'base': //! shared parameters block (uv components more or less)
{
int iShared = AI_BE(p->lo); if(iShared==0) return false; //block is empty
sizecheck((const char*)p+4+iShared*12); //! expected end of block
ai_assert(pAssimp2->mNumMeshes==0&&pAssimp2->mMeshes2!=NULL);
int iCurMaterial = AI_BE(p->hi); int iCurIndex = 0;
aiMesh2 *pShared = pAssimp2->mMeshes2[0] = new aiMesh2; //shared mesh
pShared->mNumMaterials = 1; pShared->mMaterialIndex = iCurMaterial;
pShared->mNumUVComponents[0] = 2;
pShared->mTextureCoords[0] = new aiVector3D[pShared->mNumTextureCoords=iShared*4];
for(int i=0;i<iShared;i++) if((++p)->hi==0)
{
aiFace2 *pFace2 = pShared->mFaces2+i;
pFace2->mMaterialIndex = iCurMaterial;
pFace2->mIndices = new unsigned int[pFace2->mNumIndices=5];
memset(pFace2->mIndices,0x00,5*sizeof(int));
pFace2->mNumCorners = 4; pFace2->mStride = 1;
pFace2->mTextureCoords = 1;
pShared->mTextureCoords[0][iCurIndex] = aiVector3D(p->s,p->t,0.0f); //lo
pFace2->mIndices[1] = iCurIndex++; p++;
pShared->mTextureCoords[0][iCurIndex] = aiVector3D(p->s,p->t,0.0f); //lo
//! Note that the hi 16bits here house potentially meaningful flags
pFace2->mIndices[2] = iCurIndex++; p++;
pShared->mTextureCoords[0][iCurIndex] = aiVector3D(p->s,p->t,0.0f); //lo
pFace2->mIndices[3] = iCurIndex++;
pShared->mTextureCoords[0][iCurIndex] = aiVector3D(p->u,p->v,0.0f); //hi
pFace2->mIndices[4] = iCurIndex++;
}
else
{
DefaultLogger::get()->warn("Sword of Moonlight MDL shared texture mapping block not as expected. Block left incomplete");
return false;
}
break;
}
case 'face': //! face packets block
{
int iFaces = AI_BE(in->parts[pt].num_faces);
if(iFaces==0||p->lo==0) return false; //faces absent
pPart->mFaces2 = new aiFace2[pPart->mNumFaces=iFaces];
for(int i=0;i<iFaces;i++) if((++p+1)->hi==0)
{
aiFace2 *pFace2 = pPart->mFaces2+i;
//TODO: tomorrow.........................
}
break;
}
case 'vert': //! vertex packets block
{
int iVerts = AI_BE(in->parts[pt].num_verts);
if(iVerts==0) return false; //vertices absent
sizecheck((const char*)p+iVerts*8); //expected end of block
pPart->mVertices = new aiVector3D[pPart->mNumVertices=iVerts];
for(int i=0;i<iVerts;i++) if((p+1)->hi==0)
{
pPart->mVertices[i].x = (int16_t)AI_BE(p->lo);
pPart->mVertices[i].y = (int16_t)AI_BE(p->hi); p++;
pPart->mVertices[i].z = (int16_t)AI_BE(p->lo);
}
else
{
DefaultLogger::get()->warn("Sword of Moonlight MDL high 16bits of 2nd packet in vertex block non-zero. Block left incomplete");
return false;
}
break;
}
case 'norm': //! normal packets block
{
int iNorms = AI_BE(in->parts[pt].num_norms);
if(iNorms==0) return false; //normals absent
sizecheck((const char*)p+iNorms*8); //expected end of block
pPart->mNormals = new aiVector3D[pPart->mNumNormals=iNorms];
for(int i=0;i<iNorms;i++) if((p+1)->hi==0)
{
pPart->mNormals[i].x = (int16_t)AI_BE(p->lo);
pPart->mNormals[i].y = (int16_t)AI_BE(p->hi); p++;
pPart->mNormals[i].z = (int16_t)AI_BE(p->lo);
}
else
{
DefaultLogger::get()->warn("Sword of Moonlight MDL high 16bits of 2nd packet in normals block non-zero. Block left incomplete");
return false;
}
break;
}
case 'anim': //! reference frame (skeletal) animation block
{
if(in->num_anims==0||in->add_anims==0) return false; //animation absent
return false; //unimplemented thus far
}
case 'stop': //! stop-motion (deformer) animation block
{
if(in->num_stops==0||in->add_stops==0) return false; //animation absent
return false; //unimplemented thus far
}
default: return false;
}
pAssimp2->mFlags2&=~AI_SCENE_FLAGS2_INCOMPLETE;
*inout = p; return false;
}
static void TIMpixelmode2(aiTexel *inout, uint16_t pm2)
{
inout->r = (pm2&0x1F)*8; inout->g = ((pm2&0x3E0)>>8)*8;
inout->b = ((pm2&0x7C00)>>8)*8; inout->a = 0;
}
bool SomFileHelper::bitmap(const MDL::Header_SOM *in, const MDL::Bitmap_SOM **inout)const
{
ai_assert(pAssimp&&pcEof);
if(in->num_skins==0) return false;
const MDL::Bitmap_SOM *p = *inout;
if(p->id!=0x10)
{
DefaultLogger::get()->warn("Sword of Moonlight MDL texture appears not to be TIM bitmap format. Ignoring further texture data");
return false;
}
const MDL::Bitmap_SOM::BLOCK *clut = p->clut_block();
const MDL::Bitmap_SOM::BLOCK *data = p->data_block();
if(p->pmode<0x02&&clut==0)
{
DefaultLogger::get()->warn("Sword of Moonlight MDL texture appears to contain paletted data but is missing a color lookup table. Ignoring further texture data");
return false;
}
sizecheck((const char*)data+AI_BE(data->bnum));
sizecheck((const char*)data+2*AI_BE(data->w)*AI_BE(data->h)+12);
if(clut) sizecheck((const char*)clut+AI_BE(clut->bnum));
if(clut) sizecheck((const char*)clut+2*AI_BE(clut->w)*AI_BE(clut->h)+12);
if(pAssimp2->mNumTextures>=in->num_skins)
{
DefaultLogger::get()->warn("Sword of Moonlight MDL texture appears to have exceeded the ammount indicated by the header. Ignoring further texture data");
return false;
}
if(!pAssimp2->mNumTextures) pAssimp2->mTextures = new aiTexture*[in->num_skins];
aiTexture *q = pAssimp2->mTextures[pAssimp2->mNumTextures] = new aiTexture;
float fWidth = AI_BE(data->w);
switch(p->pmode)
{
case 0x00: fWidth*=4.0f; break;
case 0x01: fWidth*=2.0f; break;
case 0x02: break;
case 0x03:
case 0x04: fWidth = fWidth/3.0f*2.0f;
}
if(fWidth-int(fWidth)!=0.0f)
{
DefaultLogger::get()->warn("Sword of Moonlight MDL texture width appears not to comply with TIM Pixel mode specification. Ignoring further textures");
return false;
}
q->mWidth = (unsigned int)fWidth; q->mHeight = AI_BE(data->h);
aiTexel *d = q->pcData = new aiTexel[q->mWidth*q->mHeight];
if(p->pmode==0x04) DefaultLogger::get()->warn("Sword of Moonlight MDL texture appears to be \"mixed\" mode. Interpreting as 24bit color");
int h = AI_BE(data->h), w = AI_BE(data->w);
for(int i=0;i<h;i++) for(int j=0;j<w;j++)
{
uint16_t e = data->data[i*w+j]; AI_SWAP2(e);
switch(p->pmode)
{
case 0x00:
TIMpixelmode2(d++,clut->data[(e&&0x000F)>>0]);
TIMpixelmode2(d++,clut->data[(e&&0x00F0)>>4]);
TIMpixelmode2(d++,clut->data[(e&&0x0F00)>>8]);
TIMpixelmode2(d++,clut->data[(e&&0xF000)>>12]); break;
case 0x01:
TIMpixelmode2(d++,clut->data[(e&&0x00FF)>>0]);
TIMpixelmode2(d++,clut->data[(e&&0xFF00)>>8]); break;
case 0x02: TIMpixelmode2(d,e); break;
case 0x03: case 0x04:
d->r = e&0xFF; d->g = (e&0xFF00)>>8;
e = data->data[i*w+++j]; AI_SWAP2(e);
d->b = e&0xFF; d->a = 0;
++d->r = (e&0xFF00)>>8;
e = data->data[i*w+++j]; AI_SWAP2(e);
d->g = e&0xFF; d->b = (e&0xFF00)>>8;
d->a = 0; d++;
}
}
pAssimp2->mNumTextures++;
int next = sizeof(MDL::Bitmap_SOM)+data->bnum;
if(clut) next+=clut->bnum;
*(char**)inout+=next;
if(pAssimp2->mNumTextures>=in->num_skins) return false;
return true;
}
[/code]
EDITED: I was getting a maximum of something like 300000 characters (plus or minus a figure) so I was going to add the cpp file as an attachment but the second shot (minus just the license header) little did I know must've gone thru.
Let Todd decide if the character limit seems practical or not.