Merge remote-tracking branch 'official/master' into contrib
This commit is contained in:
@@ -61,6 +61,8 @@ ASSIMP_API size_t aiGetExportFormatCount(void)
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t pIndex)
|
||||
{
|
||||
// Note: this is valid as the index always pertains to a builtin exporter,
|
||||
// for which the returned structure is guaranteed to be of static storage duration.
|
||||
return Exporter().GetExportFormatDescription(pIndex);
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Include our stdint.h replacement header for MSVC, take the global header for gcc/mingw
|
||||
#if defined( _MSC_VER) && (_MSC_VER < 1600)
|
||||
# include "pstdint.h"
|
||||
# include "../include/assimp/Compiler/pstdint.h"
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
@@ -248,6 +248,15 @@ void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, co
|
||||
}
|
||||
}
|
||||
|
||||
// Only reverse the winding order if an odd number of axes were mirrored.
|
||||
if (xs * ys * zs < 0) {
|
||||
for( unsigned int i = 0; i < mesh->mNumFaces; i++) {
|
||||
aiFace& face = mesh->mFaces[i];
|
||||
for( unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi)
|
||||
std::swap( face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]);
|
||||
}
|
||||
}
|
||||
|
||||
conv_data.meshes->push_back(mesh);
|
||||
}
|
||||
unsigned int* nind = new unsigned int[out.mNumMeshes*2];
|
||||
|
||||
@@ -10,7 +10,7 @@ SET( HEADER_PATH ../include/assimp )
|
||||
SET( COMPILER_HEADERS
|
||||
${HEADER_PATH}/Compiler/pushpack1.h
|
||||
${HEADER_PATH}/Compiler/poppack1.h
|
||||
pstdint.h
|
||||
${HEADER_PATH}/Compiler/pstdint.h
|
||||
)
|
||||
SOURCE_GROUP( Compiler FILES ${COMPILER_HEADERS})
|
||||
|
||||
@@ -187,7 +187,7 @@ SET( Collada_SRCS
|
||||
ColladaParser.cpp
|
||||
ColladaParser.h
|
||||
ColladaExporter.h
|
||||
ColladaExporter.cpp
|
||||
ColladaExporter.cpp
|
||||
)
|
||||
SOURCE_GROUP( Collada FILES ${Collada_SRCS})
|
||||
|
||||
@@ -322,11 +322,15 @@ SOURCE_GROUP( Obj FILES ${Obj_SRCS})
|
||||
|
||||
SET( Ogre_SRCS
|
||||
OgreImporter.h
|
||||
OgreStructs.h
|
||||
OgreParsingUtils.h
|
||||
OgreBinarySerializer.h
|
||||
OgreXmlSerializer.h
|
||||
OgreImporter.cpp
|
||||
OgreStructs.cpp
|
||||
OgreBinarySerializer.cpp
|
||||
OgreXmlSerializer.cpp
|
||||
OgreMaterial.cpp
|
||||
OgreMesh.cpp
|
||||
OgreSkeleton.cpp
|
||||
)
|
||||
SOURCE_GROUP( Ogre FILES ${Ogre_SRCS})
|
||||
|
||||
@@ -539,6 +543,8 @@ SET( XFile_SRCS
|
||||
XFileImporter.h
|
||||
XFileParser.cpp
|
||||
XFileParser.h
|
||||
XFileExporter.h
|
||||
XFileExporter.cpp
|
||||
)
|
||||
SOURCE_GROUP( XFile FILES ${XFile_SRCS})
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace Assimp
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp
|
||||
void ExportSceneCollada(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene)
|
||||
void ExportSceneCollada(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene)
|
||||
{
|
||||
std::string path = "";
|
||||
std::string file = pFile;
|
||||
@@ -124,7 +124,7 @@ ColladaExporter::~ColladaExporter()
|
||||
void ColladaExporter::WriteFile()
|
||||
{
|
||||
// write the DTD
|
||||
mOutput << "<?xml version=\"1.0\"?>" << endstr;
|
||||
mOutput << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>" << endstr;
|
||||
// COLLADA element start
|
||||
mOutput << "<COLLADA xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.4.1\">" << endstr;
|
||||
PushTag();
|
||||
@@ -151,7 +151,7 @@ void ColladaExporter::WriteFile()
|
||||
// Writes the asset header
|
||||
void ColladaExporter::WriteHeader()
|
||||
{
|
||||
static const float epsilon = 0.000001f;
|
||||
static const float epsilon = 0.00001f;
|
||||
static const aiQuaternion x_rot(aiMatrix3x3(
|
||||
0, -1, 0,
|
||||
1, 0, 0,
|
||||
@@ -176,6 +176,7 @@ void ColladaExporter::WriteHeader()
|
||||
aiQuaternion rotation;
|
||||
aiVector3D position;
|
||||
mScene->mRootNode->mTransformation.Decompose(scaling, rotation, position);
|
||||
rotation.Normalize();
|
||||
|
||||
bool add_root_node = false;
|
||||
|
||||
@@ -229,8 +230,22 @@ void ColladaExporter::WriteHeader()
|
||||
PushTag();
|
||||
mOutput << startstr << "<contributor>" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<author>Assimp</author>" << endstr;
|
||||
mOutput << startstr << "<authoring_tool>Assimp Collada Exporter</authoring_tool>" << endstr;
|
||||
|
||||
aiMetadata* meta = mScene->mRootNode->mMetaData;
|
||||
aiString value;
|
||||
if (!meta || !meta->Get("Author", value))
|
||||
mOutput << startstr << "<author>" << "Assimp" << "</author>" << endstr;
|
||||
else
|
||||
mOutput << startstr << "<author>" << value.C_Str() << "</author>" << endstr;
|
||||
|
||||
if (!meta || !meta->Get("AuthoringTool", value))
|
||||
mOutput << startstr << "<authoring_tool>" << "Assimp Exporter" << "</authoring_tool>" << endstr;
|
||||
else
|
||||
mOutput << startstr << "<authoring_tool>" << value.C_Str() << "</authoring_tool>" << endstr;
|
||||
|
||||
//mOutput << startstr << "<author>" << mScene->author.C_Str() << "</author>" << endstr;
|
||||
//mOutput << startstr << "<authoring_tool>" << mScene->authoringTool.C_Str() << "</authoring_tool>" << endstr;
|
||||
|
||||
PopTag();
|
||||
mOutput << startstr << "</contributor>" << endstr;
|
||||
mOutput << startstr << "<created>" << date_str << "</created>" << endstr;
|
||||
@@ -353,7 +368,8 @@ void ColladaExporter::WriteTextureColorEntry( const Surface& pSurface, const std
|
||||
if( pSurface.texture.empty() )
|
||||
{
|
||||
mOutput << startstr << "<color sid=\"" << pTypeName << "\">" << pSurface.color.r << " " << pSurface.color.g << " " << pSurface.color.b << " " << pSurface.color.a << "</color>" << endstr;
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
mOutput << startstr << "<texture texture=\"" << pImageName << "\" texcoord=\"CHANNEL" << pSurface.channel << "\" />" << endstr;
|
||||
}
|
||||
@@ -420,12 +436,12 @@ void ColladaExporter::WriteMaterials()
|
||||
|
||||
aiString name;
|
||||
if( mat->Get( AI_MATKEY_NAME, name) != aiReturn_SUCCESS )
|
||||
name = "mat";
|
||||
name = "mat";
|
||||
materials[a].name = std::string( "m") + boost::lexical_cast<std::string> (a) + name.C_Str();
|
||||
for( std::string::iterator it = materials[a].name.begin(); it != materials[a].name.end(); ++it ) {
|
||||
// isalnum on MSVC asserts for code points in [0,255]. Thus prevent unwanted promotion
|
||||
// of char to signed int and take the unsigned char value.
|
||||
if( !isalnum( static_cast<uint8_t>(*it) ) ) {
|
||||
if( !isalnum( static_cast<uint8_t>(*it) ) ) {
|
||||
*it = '_';
|
||||
}
|
||||
}
|
||||
@@ -630,26 +646,63 @@ void ColladaExporter::WriteGeometry( size_t pIndex)
|
||||
PopTag();
|
||||
mOutput << startstr << "</vertices>" << endstr;
|
||||
|
||||
// write face setup
|
||||
mOutput << startstr << "<polylist count=\"" << mesh->mNumFaces << "\" material=\"theresonlyone\">" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << idstr << "-vertices\" />" << endstr;
|
||||
|
||||
mOutput << startstr << "<vcount>";
|
||||
for( size_t a = 0; a < mesh->mNumFaces; ++a )
|
||||
mOutput << mesh->mFaces[a].mNumIndices << " ";
|
||||
mOutput << "</vcount>" << endstr;
|
||||
|
||||
mOutput << startstr << "<p>";
|
||||
// count the number of lines, triangles and polygon meshes
|
||||
int countLines = 0;
|
||||
int countPoly = 0;
|
||||
for( size_t a = 0; a < mesh->mNumFaces; ++a )
|
||||
{
|
||||
const aiFace& face = mesh->mFaces[a];
|
||||
for( size_t b = 0; b < face.mNumIndices; ++b )
|
||||
mOutput << face.mIndices[b] << " ";
|
||||
if (mesh->mFaces[a].mNumIndices == 2) countLines++;
|
||||
else if (mesh->mFaces[a].mNumIndices >= 3) countPoly++;
|
||||
}
|
||||
|
||||
// lines
|
||||
if (countLines)
|
||||
{
|
||||
mOutput << startstr << "<lines count=\"" << countLines << "\" material=\"defaultMaterial\">" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << idstr << "-vertices\" />" << endstr;
|
||||
mOutput << startstr << "<p>";
|
||||
for( size_t a = 0; a < mesh->mNumFaces; ++a )
|
||||
{
|
||||
const aiFace& face = mesh->mFaces[a];
|
||||
if (face.mNumIndices != 2) continue;
|
||||
for( size_t b = 0; b < face.mNumIndices; ++b )
|
||||
mOutput << face.mIndices[b] << " ";
|
||||
}
|
||||
mOutput << "</p>" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "</lines>" << endstr;
|
||||
}
|
||||
|
||||
// triangle - dont use it, because compatibility problems
|
||||
|
||||
// polygons
|
||||
if (countPoly)
|
||||
{
|
||||
mOutput << startstr << "<polylist count=\"" << countPoly << "\" material=\"defaultMaterial\">" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << idstr << "-vertices\" />" << endstr;
|
||||
|
||||
mOutput << startstr << "<vcount>";
|
||||
for( size_t a = 0; a < mesh->mNumFaces; ++a )
|
||||
{
|
||||
if (mesh->mFaces[a].mNumIndices < 3) continue;
|
||||
mOutput << mesh->mFaces[a].mNumIndices << " ";
|
||||
}
|
||||
mOutput << "</vcount>" << endstr;
|
||||
|
||||
mOutput << startstr << "<p>";
|
||||
for( size_t a = 0; a < mesh->mNumFaces; ++a )
|
||||
{
|
||||
const aiFace& face = mesh->mFaces[a];
|
||||
if (face.mNumIndices < 3) continue;
|
||||
for( size_t b = 0; b < face.mNumIndices; ++b )
|
||||
mOutput << face.mIndices[b] << " ";
|
||||
}
|
||||
mOutput << "</p>" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "</polylist>" << endstr;
|
||||
}
|
||||
mOutput << "</p>" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "</polylist>" << endstr;
|
||||
|
||||
// closing tags
|
||||
PopTag();
|
||||
@@ -770,8 +823,16 @@ void ColladaExporter::WriteSceneLibrary()
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Recursively writes the given node
|
||||
void ColladaExporter::WriteNode( const aiNode* pNode)
|
||||
void ColladaExporter::WriteNode(aiNode* pNode)
|
||||
{
|
||||
// the must have a name
|
||||
if (pNode->mName.length == 0)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Node_" << pNode;
|
||||
pNode->mName.Set(ss.str());
|
||||
}
|
||||
|
||||
mOutput << startstr << "<node id=\"" << pNode->mName.data << "\" name=\"" << pNode->mName.data << "\">" << endstr;
|
||||
PushTag();
|
||||
|
||||
@@ -799,7 +860,7 @@ void ColladaExporter::WriteNode( const aiNode* pNode)
|
||||
PushTag();
|
||||
mOutput << startstr << "<technique_common>" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<instance_material symbol=\"theresonlyone\" target=\"#" << materials[mesh->mMaterialIndex].name << "\" />" << endstr;
|
||||
mOutput << startstr << "<instance_material symbol=\"defaultMaterial\" target=\"#" << materials[mesh->mMaterialIndex].name << "\" />" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "</technique_common>" << endstr;
|
||||
PopTag();
|
||||
|
||||
@@ -92,7 +92,7 @@ protected:
|
||||
void WriteSceneLibrary();
|
||||
|
||||
/// Recursively writes the given node
|
||||
void WriteNode( const aiNode* pNode);
|
||||
void WriteNode( aiNode* pNode);
|
||||
|
||||
/// Enters a new xml element, which increases the indentation
|
||||
void PushTag() { startstr.append( " "); }
|
||||
|
||||
@@ -133,6 +133,7 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
|
||||
mLights.clear();
|
||||
mCameras.clear();
|
||||
mTextures.clear();
|
||||
mAnims.clear();
|
||||
|
||||
// parse the input file
|
||||
ColladaParser parser( pIOHandler, pFile);
|
||||
@@ -904,6 +905,8 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars
|
||||
pScene->mAnimations = new aiAnimation*[mAnims.size()];
|
||||
std::copy( mAnims.begin(), mAnims.end(), pScene->mAnimations);
|
||||
}
|
||||
|
||||
mAnims.clear();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -134,7 +134,7 @@ void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh)
|
||||
{
|
||||
pMesh->mVertices[a].z *= -1.0f;
|
||||
if( pMesh->HasNormals())
|
||||
pMesh->mNormals[a].z *= -1.0f;
|
||||
pMesh->mNormals[a].z *= -1.0f;
|
||||
if( pMesh->HasTangentsAndBitangents())
|
||||
{
|
||||
pMesh->mTangents[a].z *= -1.0f;
|
||||
|
||||
@@ -71,7 +71,9 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Exporter worker function prototypes. Should not be necessary to #ifndef them, it's just a prototype
|
||||
// do not use const, because some exporter need to convert the scene temporary
|
||||
void ExportSceneCollada(const char*,IOSystem*, const aiScene*);
|
||||
void ExportSceneXFile(const char*,IOSystem*, const aiScene*);
|
||||
void ExportSceneObj(const char*,IOSystem*, const aiScene*);
|
||||
void ExportSceneSTL(const char*,IOSystem*, const aiScene*);
|
||||
void ExportSceneSTLBinary(const char*,IOSystem*, const aiScene*);
|
||||
@@ -86,6 +88,11 @@ Exporter::ExportFormatEntry gExporters[] =
|
||||
Exporter::ExportFormatEntry( "collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_FXILE_EXPORTER
|
||||
Exporter::ExportFormatEntry( "x", "X Files", "x", &ExportSceneXFile,
|
||||
aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
|
||||
Exporter::ExportFormatEntry( "obj", "Wavefront OBJ format", "obj", &ExportSceneObj,
|
||||
aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */),
|
||||
@@ -436,6 +443,11 @@ const aiExportFormatDesc* Exporter :: GetExportFormatDescription( size_t pIndex
|
||||
if (pIndex >= GetExportFormatCount()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Return from static storage if the requested index is built-in.
|
||||
if (pIndex < sizeof(gExporters) / sizeof(gExporters[0])) {
|
||||
return &gExporters[pIndex].mDescription;
|
||||
}
|
||||
|
||||
return &pimpl->mExporters[pIndex].mDescription;
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ public:
|
||||
if(mat) {
|
||||
|
||||
if (materials_converted.find(mat) == materials_converted.end()) {
|
||||
ConvertMaterial(*mat);
|
||||
ConvertMaterial(*mat, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -767,7 +767,6 @@ private:
|
||||
|
||||
// find user defined properties (3ds Max)
|
||||
data->Set(index++, "UserProperties", aiString(PropertyGet<std::string>(props, "UDP3DSMAX", "")));
|
||||
unparsedProperties.erase("UDP3DSMAX");
|
||||
// preserve the info that a node was marked as Null node in the original file.
|
||||
data->Set(index++, "IsNull", model.IsNull() ? true : false);
|
||||
|
||||
@@ -783,8 +782,8 @@ private:
|
||||
data->Set(index++, prop.first, interpreted->Value());
|
||||
else if (const TypedProperty<float>* interpreted = prop.second->As<TypedProperty<float> >())
|
||||
data->Set(index++, prop.first, interpreted->Value());
|
||||
else if (const TypedProperty<aiString>* interpreted = prop.second->As<TypedProperty<aiString> >())
|
||||
data->Set(index++, prop.first, interpreted->Value());
|
||||
else if (const TypedProperty<std::string>* interpreted = prop.second->As<TypedProperty<std::string> >())
|
||||
data->Set(index++, prop.first, aiString(interpreted->Value()));
|
||||
else if (const TypedProperty<aiVector3D>* interpreted = prop.second->As<TypedProperty<aiVector3D> >())
|
||||
data->Set(index++, prop.first, interpreted->Value());
|
||||
else
|
||||
@@ -1381,7 +1380,7 @@ private:
|
||||
return;
|
||||
}
|
||||
|
||||
out->mMaterialIndex = ConvertMaterial(*mat);
|
||||
out->mMaterialIndex = ConvertMaterial(*mat, &geo);
|
||||
materials_converted[mat] = out->mMaterialIndex;
|
||||
}
|
||||
|
||||
@@ -1411,7 +1410,7 @@ private:
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Material -> aiMaterial
|
||||
unsigned int ConvertMaterial(const Material& material)
|
||||
unsigned int ConvertMaterial(const Material& material, const MeshGeometry* const mesh)
|
||||
{
|
||||
const PropertyTable& props = material.Props();
|
||||
|
||||
@@ -1440,8 +1439,8 @@ private:
|
||||
SetShadingPropertiesCommon(out_mat,props);
|
||||
|
||||
// texture assignments
|
||||
SetTextureProperties(out_mat,material.Textures());
|
||||
SetTextureProperties(out_mat,material.LayeredTextures());
|
||||
SetTextureProperties(out_mat,material.Textures(), mesh);
|
||||
SetTextureProperties(out_mat,material.LayeredTextures(), mesh);
|
||||
|
||||
return static_cast<unsigned int>(materials.size() - 1);
|
||||
}
|
||||
@@ -1450,7 +1449,7 @@ private:
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures,
|
||||
const std::string& propName,
|
||||
aiTextureType target)
|
||||
aiTextureType target, const MeshGeometry* const mesh)
|
||||
{
|
||||
TextureMap::const_iterator it = textures.find(propName);
|
||||
if(it == textures.end()) {
|
||||
@@ -1495,18 +1494,48 @@ private:
|
||||
std::find(materials.begin(),materials.end(),out_mat)
|
||||
));
|
||||
|
||||
uvIndex = -1;
|
||||
BOOST_FOREACH(const MeshMap::value_type& v,meshes_converted) {
|
||||
const MeshGeometry* const mesh = dynamic_cast<const MeshGeometry*> (v.first);
|
||||
if(!mesh) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const MatIndexArray& mats = mesh->GetMaterialIndices();
|
||||
if(std::find(mats.begin(),mats.end(),matIndex) == mats.end()) {
|
||||
continue;
|
||||
}
|
||||
uvIndex = -1;
|
||||
if (!mesh)
|
||||
{
|
||||
BOOST_FOREACH(const MeshMap::value_type& v,meshes_converted) {
|
||||
const MeshGeometry* const mesh = dynamic_cast<const MeshGeometry*> (v.first);
|
||||
if(!mesh) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const MatIndexArray& mats = mesh->GetMaterialIndices();
|
||||
if(std::find(mats.begin(),mats.end(),matIndex) == mats.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int index = -1;
|
||||
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
|
||||
if(mesh->GetTextureCoords(i).empty()) {
|
||||
break;
|
||||
}
|
||||
const std::string& name = mesh->GetTextureCoordChannelName(i);
|
||||
if(name == uvSet) {
|
||||
index = static_cast<int>(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(index == -1) {
|
||||
FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material");
|
||||
continue;
|
||||
}
|
||||
|
||||
if(uvIndex == -1) {
|
||||
uvIndex = index;
|
||||
}
|
||||
else {
|
||||
FBXImporter::LogWarn("the UV channel named " + uvSet +
|
||||
" appears at different positions in meshes, results will be wrong");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = -1;
|
||||
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
|
||||
if(mesh->GetTextureCoords(i).empty()) {
|
||||
@@ -1520,17 +1549,12 @@ private:
|
||||
}
|
||||
if(index == -1) {
|
||||
FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material");
|
||||
continue;
|
||||
}
|
||||
|
||||
if(uvIndex == -1) {
|
||||
uvIndex = index;
|
||||
}
|
||||
else {
|
||||
FBXImporter::LogWarn("the UV channel named " + uvSet +
|
||||
" appears at different positions in meshes, results will be wrong");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(uvIndex == -1) {
|
||||
FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel");
|
||||
@@ -1546,7 +1570,7 @@ private:
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TrySetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures,
|
||||
const std::string& propName,
|
||||
aiTextureType target)
|
||||
aiTextureType target, const MeshGeometry* const mesh)
|
||||
{
|
||||
LayeredTextureMap::const_iterator it = layeredTextures.find(propName);
|
||||
if(it == layeredTextures.end()) {
|
||||
@@ -1590,18 +1614,47 @@ private:
|
||||
std::find(materials.begin(),materials.end(),out_mat)
|
||||
));
|
||||
|
||||
uvIndex = -1;
|
||||
BOOST_FOREACH(const MeshMap::value_type& v,meshes_converted) {
|
||||
const MeshGeometry* const mesh = dynamic_cast<const MeshGeometry*> (v.first);
|
||||
if(!mesh) {
|
||||
continue;
|
||||
}
|
||||
uvIndex = -1;
|
||||
if (!mesh)
|
||||
{
|
||||
BOOST_FOREACH(const MeshMap::value_type& v,meshes_converted) {
|
||||
const MeshGeometry* const mesh = dynamic_cast<const MeshGeometry*> (v.first);
|
||||
if(!mesh) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const MatIndexArray& mats = mesh->GetMaterialIndices();
|
||||
if(std::find(mats.begin(),mats.end(),matIndex) == mats.end()) {
|
||||
continue;
|
||||
}
|
||||
const MatIndexArray& mats = mesh->GetMaterialIndices();
|
||||
if(std::find(mats.begin(),mats.end(),matIndex) == mats.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int index = -1;
|
||||
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
|
||||
if(mesh->GetTextureCoords(i).empty()) {
|
||||
break;
|
||||
}
|
||||
const std::string& name = mesh->GetTextureCoordChannelName(i);
|
||||
if(name == uvSet) {
|
||||
index = static_cast<int>(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(index == -1) {
|
||||
FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material");
|
||||
continue;
|
||||
}
|
||||
|
||||
if(uvIndex == -1) {
|
||||
uvIndex = index;
|
||||
}
|
||||
else {
|
||||
FBXImporter::LogWarn("the UV channel named " + uvSet +
|
||||
" appears at different positions in meshes, results will be wrong");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = -1;
|
||||
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
|
||||
if(mesh->GetTextureCoords(i).empty()) {
|
||||
@@ -1615,17 +1668,12 @@ private:
|
||||
}
|
||||
if(index == -1) {
|
||||
FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material");
|
||||
continue;
|
||||
}
|
||||
|
||||
if(uvIndex == -1) {
|
||||
uvIndex = index;
|
||||
}
|
||||
else {
|
||||
FBXImporter::LogWarn("the UV channel named " + uvSet +
|
||||
" appears at different positions in meshes, results will be wrong");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(uvIndex == -1) {
|
||||
FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel");
|
||||
@@ -1638,33 +1686,33 @@ private:
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SetTextureProperties(aiMaterial* out_mat, const TextureMap& textures)
|
||||
void SetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, const MeshGeometry* const mesh)
|
||||
{
|
||||
TrySetTextureProperties(out_mat, textures, "DiffuseColor", aiTextureType_DIFFUSE);
|
||||
TrySetTextureProperties(out_mat, textures, "AmbientColor", aiTextureType_AMBIENT);
|
||||
TrySetTextureProperties(out_mat, textures, "EmissiveColor", aiTextureType_EMISSIVE);
|
||||
TrySetTextureProperties(out_mat, textures, "SpecularColor", aiTextureType_SPECULAR);
|
||||
TrySetTextureProperties(out_mat, textures, "TransparentColor", aiTextureType_OPACITY);
|
||||
TrySetTextureProperties(out_mat, textures, "ReflectionColor", aiTextureType_REFLECTION);
|
||||
TrySetTextureProperties(out_mat, textures, "DisplacementColor", aiTextureType_DISPLACEMENT);
|
||||
TrySetTextureProperties(out_mat, textures, "NormalMap", aiTextureType_NORMALS);
|
||||
TrySetTextureProperties(out_mat, textures, "Bump", aiTextureType_HEIGHT);
|
||||
TrySetTextureProperties(out_mat, textures, "ShininessExponent", aiTextureType_SHININESS);
|
||||
TrySetTextureProperties(out_mat, textures, "DiffuseColor", aiTextureType_DIFFUSE, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "AmbientColor", aiTextureType_AMBIENT, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "EmissiveColor", aiTextureType_EMISSIVE, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "SpecularColor", aiTextureType_SPECULAR, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "TransparentColor", aiTextureType_OPACITY, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "ReflectionColor", aiTextureType_REFLECTION, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "NormalMap", aiTextureType_NORMALS, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "Bump", aiTextureType_HEIGHT, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "ShininessExponent", aiTextureType_SHININESS, mesh);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures)
|
||||
void SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh)
|
||||
{
|
||||
TrySetTextureProperties(out_mat, layeredTextures, "DiffuseColor", aiTextureType_DIFFUSE);
|
||||
TrySetTextureProperties(out_mat, layeredTextures, "AmbientColor", aiTextureType_AMBIENT);
|
||||
TrySetTextureProperties(out_mat, layeredTextures, "EmissiveColor", aiTextureType_EMISSIVE);
|
||||
TrySetTextureProperties(out_mat, layeredTextures, "SpecularColor", aiTextureType_SPECULAR);
|
||||
TrySetTextureProperties(out_mat, layeredTextures, "TransparentColor", aiTextureType_OPACITY);
|
||||
TrySetTextureProperties(out_mat, layeredTextures, "ReflectionColor", aiTextureType_REFLECTION);
|
||||
TrySetTextureProperties(out_mat, layeredTextures, "DisplacementColor", aiTextureType_DISPLACEMENT);
|
||||
TrySetTextureProperties(out_mat, layeredTextures, "NormalMap", aiTextureType_NORMALS);
|
||||
TrySetTextureProperties(out_mat, layeredTextures, "Bump", aiTextureType_HEIGHT);
|
||||
TrySetTextureProperties(out_mat, layeredTextures, "ShininessExponent", aiTextureType_SHININESS);
|
||||
TrySetTextureProperties(out_mat, layeredTextures, "DiffuseColor", aiTextureType_DIFFUSE, mesh);
|
||||
TrySetTextureProperties(out_mat, layeredTextures, "AmbientColor", aiTextureType_AMBIENT, mesh);
|
||||
TrySetTextureProperties(out_mat, layeredTextures, "EmissiveColor", aiTextureType_EMISSIVE, mesh);
|
||||
TrySetTextureProperties(out_mat, layeredTextures, "SpecularColor", aiTextureType_SPECULAR, mesh);
|
||||
TrySetTextureProperties(out_mat, layeredTextures, "TransparentColor", aiTextureType_OPACITY, mesh);
|
||||
TrySetTextureProperties(out_mat, layeredTextures, "ReflectionColor", aiTextureType_REFLECTION, mesh);
|
||||
TrySetTextureProperties(out_mat, layeredTextures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh);
|
||||
TrySetTextureProperties(out_mat, layeredTextures, "NormalMap", aiTextureType_NORMALS, mesh);
|
||||
TrySetTextureProperties(out_mat, layeredTextures, "Bump", aiTextureType_HEIGHT, mesh);
|
||||
TrySetTextureProperties(out_mat, layeredTextures, "ShininessExponent", aiTextureType_SHININESS, mesh);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ struct ImportSettings
|
||||
ImportSettings()
|
||||
: strictMode(true)
|
||||
, readAllLayers(true)
|
||||
, readAllMaterials()
|
||||
, readAllMaterials(false)
|
||||
, readMaterials(true)
|
||||
, readCameras(true)
|
||||
, readLights(true)
|
||||
|
||||
@@ -364,14 +364,24 @@ float ParseTokenAsFloat(const Token& t, const char*& err_out)
|
||||
}
|
||||
|
||||
if (data[0] == 'F') {
|
||||
ai_assert(t.end() - data == 5);
|
||||
// no byte swapping needed for ieee floats
|
||||
return *reinterpret_cast<const float*>(data+1);
|
||||
// Actual size validation happens during Tokenization so
|
||||
// this is valid as an assertion.
|
||||
ai_assert(t.end() - data == sizeof(float) + 1);
|
||||
// Initially, we did reinterpret_cast, breaking strict aliasing rules.
|
||||
// This actually caused trouble on Android, so let's be safe this time.
|
||||
// https://github.com/assimp/assimp/issues/24
|
||||
|
||||
float out_float;
|
||||
::memcpy(&out_float, data+1, sizeof(float));
|
||||
return out_float;
|
||||
}
|
||||
else {
|
||||
ai_assert(t.end() - data == 9);
|
||||
// no byte swapping needed for ieee floats
|
||||
return static_cast<float>(*reinterpret_cast<const double*>(data+1));
|
||||
ai_assert(t.end() - data == sizeof(double) + 1);
|
||||
|
||||
// Same
|
||||
double out_double;
|
||||
::memcpy(&out_double, data+1, sizeof(double));
|
||||
return static_cast<float>(out_double);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -199,7 +199,7 @@ void ObjExporter :: WriteGeometryFile()
|
||||
|
||||
// collect mesh geometry
|
||||
aiMatrix4x4 mBase;
|
||||
AddNode(pScene->mRootNode,mBase);
|
||||
AddNode(pScene->mRootNode, mBase);
|
||||
|
||||
// write vertex positions
|
||||
vpMap.getVectors(vp);
|
||||
@@ -228,7 +228,9 @@ void ObjExporter :: WriteGeometryFile()
|
||||
// now write all mesh instances
|
||||
BOOST_FOREACH(const MeshInstance& m, meshes) {
|
||||
mOutput << "# Mesh \'" << m.name << "\' with " << m.faces.size() << " faces" << endl;
|
||||
mOutput << "g " << m.name << endl;
|
||||
if (!m.name.empty()) {
|
||||
mOutput << "g " << m.name << endl;
|
||||
}
|
||||
mOutput << "usemtl " << m.matname << endl;
|
||||
|
||||
BOOST_FOREACH(const Face& f, m.faces) {
|
||||
@@ -243,11 +245,8 @@ void ObjExporter :: WriteGeometryFile()
|
||||
if (fv.vt) {
|
||||
mOutput << fv.vt;
|
||||
}
|
||||
if (f.kind == 'f') {
|
||||
mOutput << '/';
|
||||
if (fv.vn) {
|
||||
mOutput << fv.vn;
|
||||
}
|
||||
if (f.kind == 'f' && fv.vn) {
|
||||
mOutput << '/' << fv.vn;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -258,14 +257,12 @@ void ObjExporter :: WriteGeometryFile()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
int ObjExporter::vecIndexMap::getIndex(const aiVector3D& vec)
|
||||
{
|
||||
vecIndexMap::dataType::iterator vertIt = vecMap.find(vec);
|
||||
if(vertIt != vecMap.end()){// vertex already exists, so reference it
|
||||
vecIndexMap::dataType::iterator vertIt = vecMap.find(vec);
|
||||
// vertex already exists, so reference it
|
||||
if(vertIt != vecMap.end()){
|
||||
return vertIt->second;
|
||||
}
|
||||
vecMap[vec] = mNextIndex;
|
||||
@@ -274,6 +271,7 @@ int ObjExporter::vecIndexMap::getIndex(const aiVector3D& vec)
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ObjExporter::vecIndexMap::getVectors( std::vector<aiVector3D>& vecs )
|
||||
{
|
||||
vecs.resize(vecMap.size());
|
||||
@@ -282,14 +280,13 @@ void ObjExporter::vecIndexMap::getVectors( std::vector<aiVector3D>& vecs )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ObjExporter :: AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat)
|
||||
{
|
||||
meshes.push_back(MeshInstance());
|
||||
MeshInstance& mesh = meshes.back();
|
||||
|
||||
mesh.name = std::string(name.data,name.length) + (m->mName.length ? "_"+std::string(m->mName.data,m->mName.length) : "");
|
||||
mesh.name = std::string(name.data,name.length) + (m->mName.length ? "_" + std::string(m->mName.data,m->mName.length) : "");
|
||||
mesh.matname = GetMaterialName(m->mMaterialIndex);
|
||||
|
||||
mesh.faces.resize(m->mNumFaces);
|
||||
@@ -317,7 +314,8 @@ void ObjExporter :: AddMesh(const aiString& name, const aiMesh* m, const aiMatri
|
||||
face.indices[a].vp = vpMap.getIndex(vert);
|
||||
|
||||
if (m->mNormals) {
|
||||
face.indices[a].vn = vnMap.getIndex(m->mNormals[idx]);
|
||||
aiVector3D norm = aiMatrix3x3(mat) * m->mNormals[idx];
|
||||
face.indices[a].vn = vnMap.getIndex(norm);
|
||||
}
|
||||
else{
|
||||
face.indices[a].vn = 0;
|
||||
@@ -339,11 +337,11 @@ void ObjExporter :: AddNode(const aiNode* nd, const aiMatrix4x4& mParent)
|
||||
const aiMatrix4x4& mAbs = mParent * nd->mTransformation;
|
||||
|
||||
for(unsigned int i = 0; i < nd->mNumMeshes; ++i) {
|
||||
AddMesh(nd->mName, pScene->mMeshes[nd->mMeshes[i]],mAbs);
|
||||
AddMesh(nd->mName, pScene->mMeshes[nd->mMeshes[i]], mAbs);
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; i < nd->mNumChildren; ++i) {
|
||||
AddNode(nd->mChildren[i],mAbs);
|
||||
AddNode(nd->mChildren[i], mAbs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file ColladaExporter.h
|
||||
/** @file ObjExporter.h
|
||||
* Declares the exporter class to write a scene to a Collada file
|
||||
*/
|
||||
#ifndef AI_OBJEXPORTER_H_INC
|
||||
|
||||
@@ -139,7 +139,23 @@ void ObjFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||
{
|
||||
strModelName = pFile;
|
||||
}
|
||||
|
||||
|
||||
// process all '\'
|
||||
std::vector<char> ::iterator iter = m_Buffer.begin();
|
||||
while (iter != m_Buffer.end())
|
||||
{
|
||||
if (*iter == '\\')
|
||||
{
|
||||
// remove '\'
|
||||
iter = m_Buffer.erase(iter);
|
||||
// remove next character
|
||||
while (*iter == '\r' || *iter == '\n')
|
||||
iter = m_Buffer.erase(iter);
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
|
||||
// parse the file into a temporary representation
|
||||
ObjFileParser parser(m_Buffer, strModelName, pIOHandler);
|
||||
|
||||
|
||||
1110
code/OgreBinarySerializer.cpp
Normal file
1110
code/OgreBinarySerializer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
416
code/OgreBinarySerializer.h
Normal file
416
code/OgreBinarySerializer.h
Normal file
@@ -0,0 +1,416 @@
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2012, 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.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef AI_OGREBINARYSERIALIZER_H_INC
|
||||
#define AI_OGREBINARYSERIALIZER_H_INC
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
|
||||
#include "OgreStructs.h"
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
namespace Ogre
|
||||
{
|
||||
|
||||
typedef Assimp::StreamReaderLE MemoryStreamReader;
|
||||
typedef boost::shared_ptr<MemoryStreamReader> MemoryStreamReaderPtr;
|
||||
|
||||
class OgreBinarySerializer
|
||||
{
|
||||
public:
|
||||
/// Imports mesh and returns the result.
|
||||
/** @note Fatal unrecoverable errors will throw a DeadlyImportError. */
|
||||
static Mesh *ImportMesh(MemoryStreamReader *reader);
|
||||
|
||||
/// Imports skeleton to @c mesh into Mesh::skeleton.
|
||||
/** If mesh does not have a skeleton reference or the skeleton file
|
||||
cannot be found it is not a fatal DeadlyImportError.
|
||||
@return If skeleton import was successful. */
|
||||
static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh);
|
||||
static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh);
|
||||
|
||||
private:
|
||||
enum AssetMode
|
||||
{
|
||||
AM_Mesh,
|
||||
AM_Skeleton
|
||||
};
|
||||
|
||||
OgreBinarySerializer(MemoryStreamReader *reader, AssetMode mode) :
|
||||
m_reader(reader),
|
||||
m_currentLen(0),
|
||||
assetMode(mode)
|
||||
{
|
||||
}
|
||||
|
||||
static MemoryStreamReaderPtr OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename);
|
||||
|
||||
// Header
|
||||
|
||||
uint16_t ReadHeader(bool readLen = true);
|
||||
void RollbackHeader();
|
||||
|
||||
// Mesh
|
||||
|
||||
void ReadMesh(Mesh *mesh);
|
||||
void ReadMeshLodInfo(Mesh *mesh);
|
||||
void ReadMeshSkeletonLink(Mesh *mesh);
|
||||
void ReadMeshBounds(Mesh *mesh);
|
||||
void ReadMeshExtremes(Mesh *mesh);
|
||||
|
||||
void ReadSubMesh(Mesh *mesh);
|
||||
void ReadSubMeshNames(Mesh *mesh);
|
||||
void ReadSubMeshOperation(SubMesh *submesh);
|
||||
void ReadSubMeshTextureAlias(SubMesh *submesh);
|
||||
|
||||
void ReadBoneAssignment(VertexData *dest);
|
||||
|
||||
void ReadGeometry(VertexData *dest);
|
||||
void ReadGeometryVertexDeclaration(VertexData *dest);
|
||||
void ReadGeometryVertexElement(VertexData *dest);
|
||||
void ReadGeometryVertexBuffer(VertexData *dest);
|
||||
|
||||
void ReadEdgeList(Mesh *mesh);
|
||||
void ReadPoses(Mesh *mesh);
|
||||
void ReadPoseVertices(Pose *pose);
|
||||
|
||||
void ReadAnimations(Mesh *mesh);
|
||||
void ReadAnimation(Animation *anim);
|
||||
void ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *track);
|
||||
|
||||
void NormalizeBoneWeights(VertexData *vertexData) const;
|
||||
|
||||
// Skeleton
|
||||
|
||||
void ReadSkeleton(Skeleton *skeleton);
|
||||
|
||||
void ReadBone(Skeleton *skeleton);
|
||||
void ReadBoneParent(Skeleton *skeleton);
|
||||
|
||||
void ReadSkeletonAnimation(Skeleton *skeleton);
|
||||
void ReadSkeletonAnimationTrack(Skeleton *skeleton, Animation *dest);
|
||||
void ReadSkeletonAnimationKeyFrame(VertexAnimationTrack *dest);
|
||||
void ReadSkeletonAnimationLink(Skeleton *skeleton);
|
||||
|
||||
// Reader utils
|
||||
bool AtEnd() const;
|
||||
|
||||
template<typename T>
|
||||
inline T Read();
|
||||
|
||||
void ReadBytes(char *dest, size_t numBytes);
|
||||
void ReadBytes(uint8_t *dest, size_t numBytes);
|
||||
void ReadBytes(void *dest, size_t numBytes);
|
||||
uint8_t *ReadBytes(size_t numBytes);
|
||||
|
||||
void ReadVector(aiVector3D &vec);
|
||||
void ReadQuaternion(aiQuaternion &quat);
|
||||
|
||||
std::string ReadString(size_t len);
|
||||
std::string ReadLine();
|
||||
|
||||
void SkipBytes(size_t numBytes);
|
||||
|
||||
uint32_t m_currentLen;
|
||||
MemoryStreamReader *m_reader;
|
||||
|
||||
AssetMode assetMode;
|
||||
};
|
||||
|
||||
enum MeshChunkId
|
||||
{
|
||||
M_HEADER = 0x1000,
|
||||
// char* version : Version number check
|
||||
M_MESH = 0x3000,
|
||||
// bool skeletallyAnimated // important flag which affects h/w buffer policies
|
||||
// Optional M_GEOMETRY chunk
|
||||
M_SUBMESH = 0x4000,
|
||||
// char* materialName
|
||||
// bool useSharedVertices
|
||||
// unsigned int indexCount
|
||||
// bool indexes32Bit
|
||||
// unsigned int* faceVertexIndices (indexCount)
|
||||
// OR
|
||||
// unsigned short* faceVertexIndices (indexCount)
|
||||
// M_GEOMETRY chunk (Optional: present only if useSharedVertices = false)
|
||||
M_SUBMESH_OPERATION = 0x4010, // optional, trilist assumed if missing
|
||||
// unsigned short operationType
|
||||
M_SUBMESH_BONE_ASSIGNMENT = 0x4100,
|
||||
// Optional bone weights (repeating section)
|
||||
// unsigned int vertexIndex;
|
||||
// unsigned short boneIndex;
|
||||
// float weight;
|
||||
// Optional chunk that matches a texture name to an alias
|
||||
// a texture alias is sent to the submesh material to use this texture name
|
||||
// instead of the one in the texture unit with a matching alias name
|
||||
M_SUBMESH_TEXTURE_ALIAS = 0x4200, // Repeating section
|
||||
// char* aliasName;
|
||||
// char* textureName;
|
||||
|
||||
M_GEOMETRY = 0x5000, // NB this chunk is embedded within M_MESH and M_SUBMESH
|
||||
// unsigned int vertexCount
|
||||
M_GEOMETRY_VERTEX_DECLARATION = 0x5100,
|
||||
M_GEOMETRY_VERTEX_ELEMENT = 0x5110, // Repeating section
|
||||
// unsigned short source; // buffer bind source
|
||||
// unsigned short type; // VertexElementType
|
||||
// unsigned short semantic; // VertexElementSemantic
|
||||
// unsigned short offset; // start offset in buffer in bytes
|
||||
// unsigned short index; // index of the semantic (for colours and texture coords)
|
||||
M_GEOMETRY_VERTEX_BUFFER = 0x5200, // Repeating section
|
||||
// unsigned short bindIndex; // Index to bind this buffer to
|
||||
// unsigned short vertexSize; // Per-vertex size, must agree with declaration at this index
|
||||
M_GEOMETRY_VERTEX_BUFFER_DATA = 0x5210,
|
||||
// raw buffer data
|
||||
M_MESH_SKELETON_LINK = 0x6000,
|
||||
// Optional link to skeleton
|
||||
// char* skeletonName : name of .skeleton to use
|
||||
M_MESH_BONE_ASSIGNMENT = 0x7000,
|
||||
// Optional bone weights (repeating section)
|
||||
// unsigned int vertexIndex;
|
||||
// unsigned short boneIndex;
|
||||
// float weight;
|
||||
M_MESH_LOD = 0x8000,
|
||||
// Optional LOD information
|
||||
// string strategyName;
|
||||
// unsigned short numLevels;
|
||||
// bool manual; (true for manual alternate meshes, false for generated)
|
||||
M_MESH_LOD_USAGE = 0x8100,
|
||||
// Repeating section, ordered in increasing depth
|
||||
// NB LOD 0 (full detail from 0 depth) is omitted
|
||||
// LOD value - this is a distance, a pixel count etc, based on strategy
|
||||
// float lodValue;
|
||||
M_MESH_LOD_MANUAL = 0x8110,
|
||||
// Required if M_MESH_LOD section manual = true
|
||||
// String manualMeshName;
|
||||
M_MESH_LOD_GENERATED = 0x8120,
|
||||
// Required if M_MESH_LOD section manual = false
|
||||
// Repeating section (1 per submesh)
|
||||
// unsigned int indexCount;
|
||||
// bool indexes32Bit
|
||||
// unsigned short* faceIndexes; (indexCount)
|
||||
// OR
|
||||
// unsigned int* faceIndexes; (indexCount)
|
||||
M_MESH_BOUNDS = 0x9000,
|
||||
// float minx, miny, minz
|
||||
// float maxx, maxy, maxz
|
||||
// float radius
|
||||
|
||||
// Added By DrEvil
|
||||
// optional chunk that contains a table of submesh indexes and the names of
|
||||
// the sub-meshes.
|
||||
M_SUBMESH_NAME_TABLE = 0xA000,
|
||||
// Subchunks of the name table. Each chunk contains an index & string
|
||||
M_SUBMESH_NAME_TABLE_ELEMENT = 0xA100,
|
||||
// short index
|
||||
// char* name
|
||||
// Optional chunk which stores precomputed edge data
|
||||
M_EDGE_LISTS = 0xB000,
|
||||
// Each LOD has a separate edge list
|
||||
M_EDGE_LIST_LOD = 0xB100,
|
||||
// unsigned short lodIndex
|
||||
// bool isManual // If manual, no edge data here, loaded from manual mesh
|
||||
// bool isClosed
|
||||
// unsigned long numTriangles
|
||||
// unsigned long numEdgeGroups
|
||||
// Triangle* triangleList
|
||||
// unsigned long indexSet
|
||||
// unsigned long vertexSet
|
||||
// unsigned long vertIndex[3]
|
||||
// unsigned long sharedVertIndex[3]
|
||||
// float normal[4]
|
||||
|
||||
M_EDGE_GROUP = 0xB110,
|
||||
// unsigned long vertexSet
|
||||
// unsigned long triStart
|
||||
// unsigned long triCount
|
||||
// unsigned long numEdges
|
||||
// Edge* edgeList
|
||||
// unsigned long triIndex[2]
|
||||
// unsigned long vertIndex[2]
|
||||
// unsigned long sharedVertIndex[2]
|
||||
// bool degenerate
|
||||
// Optional poses section, referred to by pose keyframes
|
||||
M_POSES = 0xC000,
|
||||
M_POSE = 0xC100,
|
||||
// char* name (may be blank)
|
||||
// unsigned short target // 0 for shared geometry,
|
||||
// 1+ for submesh index + 1
|
||||
// bool includesNormals [1.8+]
|
||||
M_POSE_VERTEX = 0xC111,
|
||||
// unsigned long vertexIndex
|
||||
// float xoffset, yoffset, zoffset
|
||||
// float xnormal, ynormal, znormal (optional, 1.8+)
|
||||
// Optional vertex animation chunk
|
||||
M_ANIMATIONS = 0xD000,
|
||||
M_ANIMATION = 0xD100,
|
||||
// char* name
|
||||
// float length
|
||||
M_ANIMATION_BASEINFO = 0xD105,
|
||||
// [Optional] base keyframe information (pose animation only)
|
||||
// char* baseAnimationName (blank for self)
|
||||
// float baseKeyFrameTime
|
||||
M_ANIMATION_TRACK = 0xD110,
|
||||
// unsigned short type // 1 == morph, 2 == pose
|
||||
// unsigned short target // 0 for shared geometry,
|
||||
// 1+ for submesh index + 1
|
||||
M_ANIMATION_MORPH_KEYFRAME = 0xD111,
|
||||
// float time
|
||||
// bool includesNormals [1.8+]
|
||||
// float x,y,z // repeat by number of vertices in original geometry
|
||||
M_ANIMATION_POSE_KEYFRAME = 0xD112,
|
||||
// float time
|
||||
M_ANIMATION_POSE_REF = 0xD113, // repeat for number of referenced poses
|
||||
// unsigned short poseIndex
|
||||
// float influence
|
||||
// Optional submesh extreme vertex list chink
|
||||
M_TABLE_EXTREMES = 0xE000,
|
||||
// unsigned short submesh_index;
|
||||
// float extremes [n_extremes][3];
|
||||
};
|
||||
|
||||
static std::string MeshHeaderToString(MeshChunkId id)
|
||||
{
|
||||
switch(id)
|
||||
{
|
||||
case M_HEADER: return "HEADER";
|
||||
case M_MESH: return "MESH";
|
||||
case M_SUBMESH: return "SUBMESH";
|
||||
case M_SUBMESH_OPERATION: return "SUBMESH_OPERATION";
|
||||
case M_SUBMESH_BONE_ASSIGNMENT: return "SUBMESH_BONE_ASSIGNMENT";
|
||||
case M_SUBMESH_TEXTURE_ALIAS: return "SUBMESH_TEXTURE_ALIAS";
|
||||
case M_GEOMETRY: return "GEOMETRY";
|
||||
case M_GEOMETRY_VERTEX_DECLARATION: return "GEOMETRY_VERTEX_DECLARATION";
|
||||
case M_GEOMETRY_VERTEX_ELEMENT: return "GEOMETRY_VERTEX_ELEMENT";
|
||||
case M_GEOMETRY_VERTEX_BUFFER: return "GEOMETRY_VERTEX_BUFFER";
|
||||
case M_GEOMETRY_VERTEX_BUFFER_DATA: return "GEOMETRY_VERTEX_BUFFER_DATA";
|
||||
case M_MESH_SKELETON_LINK: return "MESH_SKELETON_LINK";
|
||||
case M_MESH_BONE_ASSIGNMENT: return "MESH_BONE_ASSIGNMENT";
|
||||
case M_MESH_LOD: return "MESH_LOD";
|
||||
case M_MESH_LOD_USAGE: return "MESH_LOD_USAGE";
|
||||
case M_MESH_LOD_MANUAL: return "MESH_LOD_MANUAL";
|
||||
case M_MESH_LOD_GENERATED: return "MESH_LOD_GENERATED";
|
||||
case M_MESH_BOUNDS: return "MESH_BOUNDS";
|
||||
case M_SUBMESH_NAME_TABLE: return "SUBMESH_NAME_TABLE";
|
||||
case M_SUBMESH_NAME_TABLE_ELEMENT: return "SUBMESH_NAME_TABLE_ELEMENT";
|
||||
case M_EDGE_LISTS: return "EDGE_LISTS";
|
||||
case M_EDGE_LIST_LOD: return "EDGE_LIST_LOD";
|
||||
case M_EDGE_GROUP: return "EDGE_GROUP";
|
||||
case M_POSES: return "POSES";
|
||||
case M_POSE: return "POSE";
|
||||
case M_POSE_VERTEX: return "POSE_VERTEX";
|
||||
case M_ANIMATIONS: return "ANIMATIONS";
|
||||
case M_ANIMATION: return "ANIMATION";
|
||||
case M_ANIMATION_BASEINFO: return "ANIMATION_BASEINFO";
|
||||
case M_ANIMATION_TRACK: return "ANIMATION_TRACK";
|
||||
case M_ANIMATION_MORPH_KEYFRAME: return "ANIMATION_MORPH_KEYFRAME";
|
||||
case M_ANIMATION_POSE_KEYFRAME: return "ANIMATION_POSE_KEYFRAME";
|
||||
case M_ANIMATION_POSE_REF: return "ANIMATION_POSE_REF";
|
||||
case M_TABLE_EXTREMES: return "TABLE_EXTREMES";
|
||||
}
|
||||
return "Unknown_MeshChunkId";
|
||||
}
|
||||
|
||||
enum SkeletonChunkId
|
||||
{
|
||||
SKELETON_HEADER = 0x1000,
|
||||
// char* version : Version number check
|
||||
SKELETON_BLENDMODE = 0x1010, // optional
|
||||
// unsigned short blendmode : SkeletonAnimationBlendMode
|
||||
SKELETON_BONE = 0x2000,
|
||||
// Repeating section defining each bone in the system.
|
||||
// Bones are assigned indexes automatically based on their order of declaration
|
||||
// starting with 0.
|
||||
// char* name : name of the bone
|
||||
// unsigned short handle : handle of the bone, should be contiguous & start at 0
|
||||
// Vector3 position : position of this bone relative to parent
|
||||
// Quaternion orientation : orientation of this bone relative to parent
|
||||
// Vector3 scale : scale of this bone relative to parent
|
||||
SKELETON_BONE_PARENT = 0x3000,
|
||||
// Record of the parent of a single bone, used to build the node tree
|
||||
// Repeating section, listed in Bone Index order, one per Bone
|
||||
// unsigned short handle : child bone
|
||||
// unsigned short parentHandle : parent bone
|
||||
SKELETON_ANIMATION = 0x4000,
|
||||
// A single animation for this skeleton
|
||||
// char* name : Name of the animation
|
||||
// float length : Length of the animation in seconds
|
||||
SKELETON_ANIMATION_BASEINFO = 0x4010,
|
||||
// [Optional] base keyframe information
|
||||
// char* baseAnimationName (blank for self)
|
||||
// float baseKeyFrameTime
|
||||
SKELETON_ANIMATION_TRACK = 0x4100,
|
||||
// A single animation track (relates to a single bone)
|
||||
// Repeating section (within SKELETON_ANIMATION)
|
||||
// unsigned short boneIndex : Index of bone to apply to
|
||||
SKELETON_ANIMATION_TRACK_KEYFRAME = 0x4110,
|
||||
// A single keyframe within the track
|
||||
// Repeating section
|
||||
// float time : The time position (seconds)
|
||||
// Quaternion rotate : Rotation to apply at this keyframe
|
||||
// Vector3 translate : Translation to apply at this keyframe
|
||||
// Vector3 scale : Scale to apply at this keyframe
|
||||
SKELETON_ANIMATION_LINK = 0x5000
|
||||
// Link to another skeleton, to re-use its animations
|
||||
// char* skeletonName : name of skeleton to get animations from
|
||||
// float scale : scale to apply to trans/scale keys
|
||||
};
|
||||
|
||||
static std::string SkeletonHeaderToString(SkeletonChunkId id)
|
||||
{
|
||||
switch(id)
|
||||
{
|
||||
case SKELETON_HEADER: return "HEADER";
|
||||
case SKELETON_BLENDMODE: return "BLENDMODE";
|
||||
case SKELETON_BONE: return "BONE";
|
||||
case SKELETON_BONE_PARENT: return "BONE_PARENT";
|
||||
case SKELETON_ANIMATION: return "ANIMATION";
|
||||
case SKELETON_ANIMATION_BASEINFO: return "ANIMATION_BASEINFO";
|
||||
case SKELETON_ANIMATION_TRACK: return "ANIMATION_TRACK";
|
||||
case SKELETON_ANIMATION_TRACK_KEYFRAME: return "ANIMATION_TRACK_KEYFRAME";
|
||||
case SKELETON_ANIMATION_LINK: return "ANIMATION_LINK";
|
||||
}
|
||||
return "Unknown_SkeletonChunkId";
|
||||
}
|
||||
} // Ogre
|
||||
} // Assimp
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
#endif // AI_OGREBINARYSERIALIZER_H_INC
|
||||
@@ -38,32 +38,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "AssimpPCH.h"
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include "AssimpPCH.h"
|
||||
|
||||
#include "OgreImporter.h"
|
||||
#include "TinyFormatter.h"
|
||||
#include "irrXMLWrapper.h"
|
||||
#include "OgreBinarySerializer.h"
|
||||
#include "OgreXmlSerializer.h"
|
||||
|
||||
static const aiImporterDesc desc = {
|
||||
"Ogre XML Mesh Importer",
|
||||
"Ogre3D Mesh Importer",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
aiImporterFlags_SupportTextFlavour,
|
||||
aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"mesh.xml"
|
||||
"mesh mesh.xml"
|
||||
};
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
namespace Ogre
|
||||
@@ -83,174 +78,67 @@ void OgreImporter::SetupProperties(const Importer* pImp)
|
||||
bool OgreImporter::CanRead(const std::string &pFile, Assimp::IOSystem *pIOHandler, bool checkSig) const
|
||||
{
|
||||
if (!checkSig) {
|
||||
return EndsWith(pFile, ".mesh.xml", false);
|
||||
return EndsWith(pFile, ".mesh.xml", false) || EndsWith(pFile, ".mesh", false);
|
||||
}
|
||||
|
||||
const char* tokens[] = { "<mesh>" };
|
||||
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
|
||||
if (EndsWith(pFile, ".mesh.xml", false))
|
||||
{
|
||||
const char* tokens[] = { "<mesh>" };
|
||||
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/// @todo Read and validate first header chunk?
|
||||
return EndsWith(pFile, ".mesh", false);
|
||||
}
|
||||
}
|
||||
|
||||
void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Assimp::IOSystem *pIOHandler)
|
||||
{
|
||||
// -------------------- Initial file and XML operations --------------------
|
||||
|
||||
// Open
|
||||
boost::scoped_ptr<IOStream> file(pIOHandler->Open(pFile));
|
||||
if (!file.get()) {
|
||||
// Open source file
|
||||
IOStream *f = pIOHandler->Open(pFile, "rb");
|
||||
if (!f) {
|
||||
throw DeadlyImportError("Failed to open file " + pFile);
|
||||
}
|
||||
|
||||
// Read
|
||||
boost::scoped_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(file.get()));
|
||||
boost::scoped_ptr<XmlReader> reader(irr::io::createIrrXMLReader(xmlStream.get()));
|
||||
if (!reader) {
|
||||
throw DeadlyImportError("Failed to create XML Reader for " + pFile);
|
||||
}
|
||||
|
||||
DefaultLogger::get()->debug("Opened a XML reader for " + pFile);
|
||||
|
||||
// Read root node
|
||||
NextNode(reader.get());
|
||||
if (!CurrentNodeNameEquals(reader.get(), "mesh")) {
|
||||
throw DeadlyImportError("Root node is not <mesh> but <" + string(reader->getNodeName()) + "> in " + pFile);
|
||||
}
|
||||
|
||||
// Node names
|
||||
const string nnSharedGeometry = "sharedgeometry";
|
||||
const string nnVertexBuffer = "vertexbuffer";
|
||||
const string nnSubMeshes = "submeshes";
|
||||
const string nnSubMesh = "submesh";
|
||||
const string nnSubMeshNames = "submeshnames";
|
||||
const string nnSkeletonLink = "skeletonlink";
|
||||
|
||||
// -------------------- Shared Geometry --------------------
|
||||
// This can be used to share geometry between submeshes
|
||||
|
||||
NextNode(reader.get());
|
||||
if (CurrentNodeNameEquals(reader.get(), nnSharedGeometry))
|
||||
// Binary .mesh import
|
||||
if (EndsWith(pFile, ".mesh", false))
|
||||
{
|
||||
DefaultLogger::get()->debug("Reading shared geometry");
|
||||
unsigned int NumVertices = GetAttribute<unsigned int>(reader.get(), "vertexcount");
|
||||
/// @note MemoryStreamReader takes ownership of f.
|
||||
MemoryStreamReader reader(f);
|
||||
|
||||
NextNode(reader.get());
|
||||
while(CurrentNodeNameEquals(reader.get(), nnVertexBuffer)) {
|
||||
ReadVertexBuffer(m_SharedGeometry, reader.get(), NumVertices);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------- Sub Meshes --------------------
|
||||
|
||||
if (!CurrentNodeNameEquals(reader.get(), nnSubMeshes)) {
|
||||
throw DeadlyImportError("Could not find <submeshes> node inside root <mesh> node");
|
||||
}
|
||||
|
||||
vector<boost::shared_ptr<SubMesh> > subMeshes;
|
||||
vector<aiMaterial*> materials;
|
||||
|
||||
NextNode(reader.get());
|
||||
while(CurrentNodeNameEquals(reader.get(), nnSubMesh))
|
||||
{
|
||||
SubMesh* submesh = new SubMesh();
|
||||
ReadSubMesh(subMeshes.size(), *submesh, reader.get());
|
||||
|
||||
// Just a index in a array, we add a mesh in each loop cycle, so we get indicies like 0, 1, 2 ... n;
|
||||
// so it is important to do this before pushing the mesh in the vector!
|
||||
/// @todo Not sure if this really is needed, refactor out if possible.
|
||||
submesh->MaterialIndex = subMeshes.size();
|
||||
|
||||
subMeshes.push_back(boost::shared_ptr<SubMesh>(submesh));
|
||||
|
||||
/** @todo What is the correct way of handling empty ref here.
|
||||
Does Assimp require there to be a valid material index for each mesh,
|
||||
even if its a dummy material. */
|
||||
aiMaterial* material = ReadMaterial(pFile, pIOHandler, submesh->MaterialName);
|
||||
materials.push_back(material);
|
||||
}
|
||||
|
||||
if (subMeshes.empty()) {
|
||||
throw DeadlyImportError("Could not find <submeshes> node inside root <mesh> node");
|
||||
}
|
||||
|
||||
// This is really a internal error if we failed to create dummy materials.
|
||||
if (subMeshes.size() != materials.size()) {
|
||||
throw DeadlyImportError("Internal Error: Material count does not match the submesh count");
|
||||
}
|
||||
|
||||
// Skip submesh names.
|
||||
/// @todo Should these be read to scene etc. metadata?
|
||||
if (CurrentNodeNameEquals(reader.get(), nnSubMeshNames))
|
||||
{
|
||||
NextNode(reader.get());
|
||||
while(CurrentNodeNameEquals(reader.get(), nnSubMesh)) {
|
||||
NextNode(reader.get());
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------- Skeleton --------------------
|
||||
|
||||
vector<Bone> Bones;
|
||||
vector<Animation> Animations;
|
||||
|
||||
if (CurrentNodeNameEquals(reader.get(), nnSkeletonLink))
|
||||
{
|
||||
string skeletonFile = GetAttribute<string>(reader.get(), "name");
|
||||
if (!skeletonFile.empty())
|
||||
{
|
||||
ReadSkeleton(pFile, pIOHandler, pScene, skeletonFile, Bones, Animations);
|
||||
}
|
||||
else
|
||||
{
|
||||
DefaultLogger::get()->debug("Found a unusual <" + nnSkeletonLink + "> with a empty file reference");
|
||||
}
|
||||
NextNode(reader.get());
|
||||
// Import mesh
|
||||
boost::scoped_ptr<Mesh> mesh(OgreBinarySerializer::ImportMesh(&reader));
|
||||
|
||||
// Import skeleton
|
||||
OgreBinarySerializer::ImportSkeleton(pIOHandler, mesh.get());
|
||||
|
||||
// Import mesh referenced materials
|
||||
ReadMaterials(pFile, pIOHandler, pScene, mesh.get());
|
||||
|
||||
// Convert to Assimp
|
||||
mesh->ConvertToAssimpScene(pScene);
|
||||
}
|
||||
// XML .mesh.xml import
|
||||
else
|
||||
{
|
||||
DefaultLogger::get()->debug("Mesh has no assigned skeleton with <" + nnSkeletonLink + ">");
|
||||
/// @note XmlReader does not take ownership of f, hence the scoped ptr.
|
||||
boost::scoped_ptr<IOStream> scopedFile(f);
|
||||
boost::scoped_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(scopedFile.get()));
|
||||
boost::scoped_ptr<XmlReader> reader(irr::io::createIrrXMLReader(xmlStream.get()));
|
||||
|
||||
// Import mesh
|
||||
boost::scoped_ptr<MeshXml> mesh(OgreXmlSerializer::ImportMesh(reader.get()));
|
||||
|
||||
// Import skeleton
|
||||
OgreXmlSerializer::ImportSkeleton(pIOHandler, mesh.get());
|
||||
|
||||
// Import mesh referenced materials
|
||||
ReadMaterials(pFile, pIOHandler, pScene, mesh.get());
|
||||
|
||||
// Convert to Assimp
|
||||
mesh->ConvertToAssimpScene(pScene);
|
||||
}
|
||||
|
||||
// Now there might be <boneassignments> for the shared geometry
|
||||
if (CurrentNodeNameEquals(reader.get(), "boneassignments")) {
|
||||
ReadBoneWeights(m_SharedGeometry, reader.get());
|
||||
}
|
||||
|
||||
// -------------------- Process Results --------------------
|
||||
BOOST_FOREACH(boost::shared_ptr<SubMesh> submesh, subMeshes)
|
||||
{
|
||||
ProcessSubMesh(*submesh.get(), m_SharedGeometry);
|
||||
}
|
||||
|
||||
// -------------------- Apply to aiScene --------------------
|
||||
|
||||
// Materials
|
||||
pScene->mMaterials = new aiMaterial*[materials.size()];
|
||||
pScene->mNumMaterials = materials.size();
|
||||
|
||||
for(size_t i=0, len=materials.size(); i<len; ++i) {
|
||||
pScene->mMaterials[i] = materials[i];
|
||||
}
|
||||
|
||||
// Meshes
|
||||
pScene->mMeshes = new aiMesh*[subMeshes.size()];
|
||||
pScene->mNumMeshes = subMeshes.size();
|
||||
|
||||
for(size_t i=0, len=subMeshes.size(); i<len; ++i)
|
||||
{
|
||||
boost::shared_ptr<SubMesh> submesh = subMeshes[i];
|
||||
pScene->mMeshes[i] = CreateAssimpSubMesh(pScene, *(submesh.get()), Bones);
|
||||
}
|
||||
|
||||
// Create the root node
|
||||
pScene->mRootNode = new aiNode();
|
||||
pScene->mRootNode->mMeshes = new unsigned int[subMeshes.size()];
|
||||
pScene->mRootNode->mNumMeshes = subMeshes.size();
|
||||
|
||||
for(size_t i=0, len=subMeshes.size(); i<len; ++i) {
|
||||
pScene->mRootNode->mMeshes[i] = static_cast<unsigned int>(i);
|
||||
}
|
||||
|
||||
// Skeleton and animations
|
||||
CreateAssimpSkeleton(pScene, Bones, Animations);
|
||||
}
|
||||
|
||||
} // Ogre
|
||||
|
||||
@@ -1,3 +1,42 @@
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2012, 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.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef AI_OGREIMPORTER_H_INC
|
||||
#define AI_OGREIMPORTER_H_INC
|
||||
@@ -5,6 +44,8 @@
|
||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
|
||||
#include "BaseImporter.h"
|
||||
|
||||
#include "OgreStructs.h"
|
||||
#include "OgreParsingUtils.h"
|
||||
|
||||
namespace Assimp
|
||||
@@ -12,58 +53,10 @@ namespace Assimp
|
||||
namespace Ogre
|
||||
{
|
||||
|
||||
struct Face;
|
||||
struct BoneWeight;
|
||||
struct Bone;
|
||||
struct Animation;
|
||||
|
||||
/// Ogre SubMesh
|
||||
struct SubMesh
|
||||
{
|
||||
bool UseSharedGeometry;
|
||||
bool Use32bitIndexes;
|
||||
|
||||
std::string Name;
|
||||
std::string MaterialName;
|
||||
|
||||
bool HasGeometry;
|
||||
bool HasPositions;
|
||||
bool HasNormals;
|
||||
bool HasTangents;
|
||||
|
||||
std::vector<Face> Faces;
|
||||
std::vector<aiVector3D> Positions;
|
||||
std::vector<aiVector3D> Normals;
|
||||
std::vector<aiVector3D> Tangents;
|
||||
|
||||
/// Arbitrary number of texcoords, they are nearly always 2d, but Assimp has always 3d texcoords, n vectors(outer) with texcoords for each vertex(inner).
|
||||
std::vector<std::vector<aiVector3D> > Uvs;
|
||||
|
||||
/// A list(inner) of bones for each vertex(outer).
|
||||
std::vector<std::vector<BoneWeight> > Weights;
|
||||
|
||||
/// The Index in the Assimp material array from the material witch is attached to this submesh.
|
||||
int MaterialIndex;
|
||||
|
||||
// The highest index of a bone from a bone weight, this is needed to create the Assimp bone struct. Converting from vertex-bones to bone-vertices.
|
||||
unsigned int BonesUsed;
|
||||
|
||||
SubMesh() :
|
||||
UseSharedGeometry(false),
|
||||
Use32bitIndexes(false),
|
||||
HasGeometry(false),
|
||||
HasPositions(false),
|
||||
HasNormals(false),
|
||||
HasTangents(false),
|
||||
MaterialIndex(-1),
|
||||
BonesUsed(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/** Importer for Ogre mesh, skeleton and material formats.
|
||||
@todo Support vertex colors
|
||||
@todo Support multiple TexCoords (this is already done??) */
|
||||
@todo Support vertex colors.
|
||||
@todo Support poses/animations from the mesh file.
|
||||
Currently only skeleton file animations are supported. */
|
||||
class OgreImporter : public BaseImporter
|
||||
{
|
||||
public:
|
||||
@@ -80,40 +73,11 @@ public:
|
||||
virtual void SetupProperties(const Importer *pImp);
|
||||
|
||||
private:
|
||||
//-------------------------------- OgreMesh.cpp -------------------------------
|
||||
|
||||
/// Helper Functions to read parts of the XML File.
|
||||
void ReadSubMesh(const unsigned int submeshIndex, SubMesh &submesh, XmlReader *reader);
|
||||
|
||||
/// Reads a single Vertexbuffer and writes its data in the Submesh.
|
||||
static void ReadVertexBuffer(SubMesh &submesh, XmlReader *reader, const unsigned int numVertices);
|
||||
|
||||
/// Reads bone weights are stores them into the given submesh.
|
||||
static void ReadBoneWeights(SubMesh &submesh, XmlReader *reader);
|
||||
|
||||
/// After Loading a SubMehs some work needs to be done (make all Vertexes unique, normalize weights).
|
||||
static void ProcessSubMesh(SubMesh &submesh, SubMesh &sharedGeometry);
|
||||
|
||||
/// Uses the bone data to convert a SubMesh into a aiMesh which will be created and returned.
|
||||
aiMesh *CreateAssimpSubMesh(aiScene *pScene, const SubMesh &submesh, const std::vector<Bone> &bones) const;
|
||||
|
||||
//-------------------------------- OgreSkeleton.cpp -------------------------------
|
||||
|
||||
/// Writes the results in Bones and Animations, Filename is not const, because its call-by-value and the function will change it!
|
||||
void ReadSkeleton(const std::string &pFile, Assimp::IOSystem *pIOHandler, const aiScene *pScene,
|
||||
const std::string &skeletonFile, std::vector<Bone> &Bones, std::vector<Animation> &Animations) const;
|
||||
|
||||
/// Converts the animations in aiAnimations and puts them into the scene.
|
||||
void PutAnimationsInScene(aiScene *pScene, const std::vector<Bone> &Bones, const std::vector<Animation> &Animations);
|
||||
|
||||
/// Creates the aiSkeleton in current scene.
|
||||
void CreateAssimpSkeleton(aiScene *pScene, const std::vector<Bone> &bones, const std::vector<Animation> &animations);
|
||||
|
||||
/// Recursively creates a filled aiNode from a given root bone.
|
||||
static aiNode* CreateNodeFromBone(int boneId, const std::vector<Bone> &bones, aiNode *parent);
|
||||
|
||||
//-------------------------------- OgreMaterial.cpp -------------------------------
|
||||
|
||||
/// Read materials referenced by the @c mesh to @c pScene.
|
||||
void ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, Mesh *mesh);
|
||||
void ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, MeshXml *mesh);
|
||||
void AssignMaterials(aiScene *pScene, std::vector<aiMaterial*> &materials);
|
||||
|
||||
/// Reads material
|
||||
aiMaterial* ReadMaterial(const std::string &pFile, Assimp::IOSystem *pIOHandler, const std::string MaterialName);
|
||||
|
||||
@@ -125,104 +89,8 @@ private:
|
||||
std::string m_userDefinedMaterialLibFile;
|
||||
bool m_detectTextureTypeFromFilename;
|
||||
|
||||
/// VertexBuffer for the sub meshes that use shader geometry.
|
||||
SubMesh m_SharedGeometry;
|
||||
|
||||
std::map<aiTextureType, unsigned int> m_textures;
|
||||
};
|
||||
|
||||
/// Simplified face.
|
||||
/** @todo Support other polygon types than just just triangles. Move to using aiFace. */
|
||||
struct Face
|
||||
{
|
||||
unsigned int VertexIndices[3];
|
||||
};
|
||||
|
||||
/// Ogre Bone assignment
|
||||
struct BoneAssignment
|
||||
{
|
||||
/// Bone ID from Ogre.
|
||||
unsigned int BoneId;
|
||||
// Bone name for Assimp.
|
||||
std::string BoneName;
|
||||
};
|
||||
|
||||
/// Ogre Bone weight
|
||||
struct BoneWeight
|
||||
{
|
||||
/// Bone Id
|
||||
unsigned int Id;
|
||||
/// BoneWeight
|
||||
float Value;
|
||||
};
|
||||
|
||||
|
||||
/// Ogre Bone
|
||||
struct Bone
|
||||
{
|
||||
std::string Name;
|
||||
|
||||
int Id;
|
||||
int ParentId;
|
||||
|
||||
aiVector3D Position;
|
||||
aiVector3D RotationAxis;
|
||||
float RotationAngle;
|
||||
|
||||
aiMatrix4x4 BoneToWorldSpace;
|
||||
|
||||
std::vector<int> Children;
|
||||
|
||||
Bone() :
|
||||
Id(-1),
|
||||
ParentId(-1),
|
||||
RotationAngle(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
/// Returns if this bone is parented.
|
||||
bool IsParented() const { return (ParentId != -1); }
|
||||
|
||||
/// This operator is needed to sort the bones by Id in a vector<Bone>.
|
||||
bool operator<(const Bone &other) const { return (Id < other.Id); }
|
||||
|
||||
/// This operator is needed to find a bone by its name in a vector<Bone>
|
||||
bool operator==(const std::string& other) const { return Name == other; }
|
||||
bool operator==(const aiString& other) const { return Name == std::string(other.data); }
|
||||
|
||||
/// @note Implemented in OgreSkeleton.cpp
|
||||
void CalculateBoneToWorldSpaceMatrix(std::vector<Bone>& Bones);
|
||||
};
|
||||
|
||||
/// Ogre animation key frame
|
||||
/** Transformations for a frame. */
|
||||
struct KeyFrame
|
||||
{
|
||||
float Time;
|
||||
aiVector3D Position;
|
||||
aiQuaternion Rotation;
|
||||
aiVector3D Scaling;
|
||||
};
|
||||
|
||||
/// Ogre animation track
|
||||
/** Keyframes for one bone. */
|
||||
struct Track
|
||||
{
|
||||
std::string BoneName;
|
||||
std::vector<KeyFrame> Keyframes;
|
||||
};
|
||||
|
||||
/// Ogre animation
|
||||
struct Animation
|
||||
{
|
||||
/// Name
|
||||
std::string Name;
|
||||
/// Length
|
||||
float Length;
|
||||
/// Tracks
|
||||
std::vector<Track> Tracks;
|
||||
};
|
||||
|
||||
} // Ogre
|
||||
} // Assimp
|
||||
|
||||
|
||||
@@ -42,12 +42,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
|
||||
#include "OgreImporter.h"
|
||||
#include "TinyFormatter.h"
|
||||
|
||||
#include "fast_atof.h"
|
||||
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Assimp
|
||||
@@ -59,11 +61,66 @@ static const string partComment = "//";
|
||||
static const string partBlockStart = "{";
|
||||
static const string partBlockEnd = "}";
|
||||
|
||||
void OgreImporter::ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, Mesh *mesh)
|
||||
{
|
||||
std::vector<aiMaterial*> materials;
|
||||
|
||||
// Create materials that can be found and parsed via the IOSystem.
|
||||
for (size_t i=0, len=mesh->NumSubMeshes(); i<len; ++i)
|
||||
{
|
||||
SubMesh *submesh = mesh->GetSubMesh(i);
|
||||
if (submesh && !submesh->materialRef.empty())
|
||||
{
|
||||
aiMaterial *material = ReadMaterial(pFile, pIOHandler, submesh->materialRef);
|
||||
if (material)
|
||||
{
|
||||
submesh->materialIndex = materials.size();
|
||||
materials.push_back(material);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AssignMaterials(pScene, materials);
|
||||
}
|
||||
|
||||
void OgreImporter::ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, MeshXml *mesh)
|
||||
{
|
||||
std::vector<aiMaterial*> materials;
|
||||
|
||||
// Create materials that can be found and parsed via the IOSystem.
|
||||
for (size_t i=0, len=mesh->NumSubMeshes(); i<len; ++i)
|
||||
{
|
||||
SubMeshXml *submesh = mesh->GetSubMesh(i);
|
||||
if (submesh && !submesh->materialRef.empty())
|
||||
{
|
||||
aiMaterial *material = ReadMaterial(pFile, pIOHandler, submesh->materialRef);
|
||||
if (material)
|
||||
{
|
||||
submesh->materialIndex = materials.size();
|
||||
materials.push_back(material);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AssignMaterials(pScene, materials);
|
||||
}
|
||||
|
||||
void OgreImporter::AssignMaterials(aiScene *pScene, std::vector<aiMaterial*> &materials)
|
||||
{
|
||||
pScene->mNumMaterials = materials.size();
|
||||
if (pScene->mNumMaterials > 0)
|
||||
{
|
||||
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
|
||||
for(size_t i=0;i<pScene->mNumMaterials; ++i) {
|
||||
pScene->mMaterials[i] = materials[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aiMaterial* OgreImporter::ReadMaterial(const std::string &pFile, Assimp::IOSystem *pIOHandler, const std::string materialName)
|
||||
{
|
||||
/// @todo Should we return null ptr here or a empty material?
|
||||
if (materialName.empty()) {
|
||||
return new aiMaterial();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Full reference and examples of Ogre Material Script
|
||||
@@ -117,17 +174,15 @@ aiMaterial* OgreImporter::ReadMaterial(const std::string &pFile, Assimp::IOSyste
|
||||
}
|
||||
if (!materialFile)
|
||||
{
|
||||
/// @todo Should we return null ptr here or a empty material?
|
||||
DefaultLogger::get()->error(Formatter::format() << "Failed to find source file for material '" << materialName << "'");
|
||||
return new aiMaterial();
|
||||
return 0;
|
||||
}
|
||||
|
||||
boost::scoped_ptr<IOStream> stream(materialFile);
|
||||
if (stream->FileSize() == 0)
|
||||
{
|
||||
/// @todo Should we return null ptr here or a empty material?
|
||||
DefaultLogger::get()->warn(Formatter::format() << "Source file for material '" << materialName << "' is empty (size is 0 bytes)");
|
||||
return new aiMaterial();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read bytes
|
||||
@@ -162,8 +217,7 @@ aiMaterial* OgreImporter::ReadMaterial(const std::string &pFile, Assimp::IOSyste
|
||||
// Skip commented lines
|
||||
if (linePart == partComment)
|
||||
{
|
||||
string postComment = NextAfterNewLine(ss, linePart);
|
||||
DefaultLogger::get()->debug("//" + postComment + " (comment line ignored)");
|
||||
NextAfterNewLine(ss, linePart);
|
||||
continue;
|
||||
}
|
||||
if (linePart != partMaterial)
|
||||
@@ -306,8 +360,7 @@ bool OgreImporter::ReadTechnique(const std::string &techniqueName, stringstream
|
||||
// Skip commented lines
|
||||
if (linePart == partComment)
|
||||
{
|
||||
string postComment = SkipLine(ss);
|
||||
DefaultLogger::get()->debug(" //" + postComment + " (comment line ignored)");
|
||||
SkipLine(ss);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -347,8 +400,7 @@ bool OgreImporter::ReadPass(const std::string &passName, stringstream &ss, aiMat
|
||||
// Skip commented lines
|
||||
if (linePart == partComment)
|
||||
{
|
||||
string postComment = SkipLine(ss);
|
||||
DefaultLogger::get()->debug(" //" + postComment + " (comment line ignored)");
|
||||
SkipLine(ss);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -416,8 +468,7 @@ bool OgreImporter::ReadTextureUnit(const std::string &textureUnitName, stringstr
|
||||
// Skip commented lines
|
||||
if (linePart == partComment)
|
||||
{
|
||||
string postComment = SkipLine(ss);
|
||||
DefaultLogger::get()->debug(" //" + postComment + " (comment line ignored)");
|
||||
SkipLine(ss);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,569 +0,0 @@
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2012, 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 "AssimpPCH.h"
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
|
||||
#include "OgreImporter.h"
|
||||
#include "TinyFormatter.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
namespace Ogre
|
||||
{
|
||||
|
||||
void OgreImporter::ReadSubMesh(const unsigned int submeshIndex, SubMesh &submesh, XmlReader *reader)
|
||||
{
|
||||
if (reader->getAttributeValue("material")) {
|
||||
submesh.MaterialName = GetAttribute<string>(reader, "material");
|
||||
}
|
||||
if (reader->getAttributeValue("use32bitindexes")) {
|
||||
submesh.Use32bitIndexes = GetAttribute<bool>(reader, "use32bitindexes");
|
||||
}
|
||||
if (reader->getAttributeValue("usesharedvertices")) {
|
||||
submesh.UseSharedGeometry = GetAttribute<bool>(reader, "usesharedvertices");
|
||||
}
|
||||
|
||||
DefaultLogger::get()->debug(Formatter::format() << "Reading submesh " << submeshIndex);
|
||||
DefaultLogger::get()->debug(Formatter::format() << " - Material '" << submesh.MaterialName << "'");
|
||||
DefaultLogger::get()->debug(Formatter::format() << " - Shader geometry = " << (submesh.UseSharedGeometry ? "true" : "false") <<
|
||||
", 32bit indexes = " << (submesh.Use32bitIndexes ? "true" : "false"));
|
||||
|
||||
//TODO: maybe we have alsways just 1 faces and 1 geometry and always in this order. this loop will only work correct, when the order
|
||||
//of faces and geometry changed, and not if we have more than one of one
|
||||
/// @todo Fix above comment with better read logic below
|
||||
|
||||
NextNode(reader);
|
||||
string currentNodeName = reader->getNodeName();
|
||||
|
||||
const string nnFaces = "faces";
|
||||
const string nnFace = "face";
|
||||
const string nnGeometry = "geometry";
|
||||
const string nnBoneAssignments = "boneassignments";
|
||||
const string nnVertexBuffer = "vertexbuffer";
|
||||
|
||||
bool quadWarned = false;
|
||||
|
||||
while(currentNodeName == nnFaces ||
|
||||
currentNodeName == nnGeometry ||
|
||||
currentNodeName == nnBoneAssignments)
|
||||
{
|
||||
if (currentNodeName == nnFaces)
|
||||
{
|
||||
unsigned int numFaces = GetAttribute<unsigned int>(reader, "count");
|
||||
|
||||
NextNode(reader);
|
||||
currentNodeName = reader->getNodeName();
|
||||
|
||||
while(currentNodeName == nnFace)
|
||||
{
|
||||
Face NewFace;
|
||||
NewFace.VertexIndices[0] = GetAttribute<int>(reader, "v1");
|
||||
NewFace.VertexIndices[1] = GetAttribute<int>(reader, "v2");
|
||||
NewFace.VertexIndices[2] = GetAttribute<int>(reader, "v3");
|
||||
|
||||
/// @todo Support quads
|
||||
if (!quadWarned && reader->getAttributeValue("v4")) {
|
||||
DefaultLogger::get()->warn("Submesh has quads, only triangles are supported at the moment!");
|
||||
}
|
||||
|
||||
submesh.Faces.push_back(NewFace);
|
||||
|
||||
// Advance
|
||||
NextNode(reader);
|
||||
currentNodeName = reader->getNodeName();
|
||||
}
|
||||
|
||||
if (submesh.Faces.size() == numFaces)
|
||||
{
|
||||
DefaultLogger::get()->debug(Formatter::format() << " - Faces " << numFaces);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw DeadlyImportError(Formatter::format() << "Read only " << submesh.Faces.size() << " faces when should have read " << numFaces);
|
||||
}
|
||||
}
|
||||
else if (currentNodeName == nnGeometry)
|
||||
{
|
||||
unsigned int numVertices = GetAttribute<int>(reader, "vertexcount");
|
||||
|
||||
NextNode(reader);
|
||||
while(string(reader->getNodeName()) == nnVertexBuffer) {
|
||||
ReadVertexBuffer(submesh, reader, numVertices);
|
||||
}
|
||||
}
|
||||
else if (reader->getNodeName() == nnBoneAssignments)
|
||||
{
|
||||
ReadBoneWeights(submesh, reader);
|
||||
}
|
||||
|
||||
currentNodeName = reader->getNodeName();
|
||||
}
|
||||
}
|
||||
|
||||
void OgreImporter::ReadVertexBuffer(SubMesh &submesh, XmlReader *reader, const unsigned int numVertices)
|
||||
{
|
||||
DefaultLogger::get()->debug(Formatter::format() << "Reading vertex buffer with " << numVertices << " vertices");
|
||||
|
||||
submesh.HasGeometry = true;
|
||||
|
||||
if (reader->getAttributeValue("positions") && GetAttribute<bool>(reader, "positions"))
|
||||
{
|
||||
submesh.HasPositions = true;
|
||||
submesh.Positions.reserve(numVertices);
|
||||
DefaultLogger::get()->debug(" - Has positions");
|
||||
}
|
||||
if (reader->getAttributeValue("normals") && GetAttribute<bool>(reader, "normals"))
|
||||
{
|
||||
submesh.HasNormals = true;
|
||||
submesh.Normals.reserve(numVertices);
|
||||
DefaultLogger::get()->debug(" - Has normals");
|
||||
}
|
||||
if (reader->getAttributeValue("tangents") && GetAttribute<bool>(reader, "tangents"))
|
||||
{
|
||||
submesh.HasTangents = true;
|
||||
submesh.Tangents.reserve(numVertices);
|
||||
DefaultLogger::get()->debug(" - Has tangents");
|
||||
}
|
||||
if (reader->getAttributeValue("texture_coords"))
|
||||
{
|
||||
submesh.Uvs.resize(GetAttribute<unsigned int>(reader, "texture_coords"));
|
||||
for(size_t i=0, len=submesh.Uvs.size(); i<len; ++i) {
|
||||
submesh.Uvs[i].reserve(numVertices);
|
||||
}
|
||||
DefaultLogger::get()->debug(Formatter::format() << " - Has " << submesh.Uvs.size() << " texture coords");
|
||||
}
|
||||
|
||||
if (!submesh.HasPositions) {
|
||||
throw DeadlyImportError("Vertex buffer does not contain positions!");
|
||||
}
|
||||
|
||||
const string nnVertex = "vertex";
|
||||
const string nnPosition = "position";
|
||||
const string nnNormal = "normal";
|
||||
const string nnTangent = "tangent";
|
||||
const string nnBinormal = "binormal";
|
||||
const string nnTexCoord = "texcoord";
|
||||
const string nnColorDiffuse = "colour_diffuse";
|
||||
const string nnColorSpecular = "colour_specular";
|
||||
|
||||
bool warnBinormal = true;
|
||||
bool warnColorDiffuse = true;
|
||||
bool warnColorSpecular = true;
|
||||
|
||||
NextNode(reader);
|
||||
string currentNodeName = reader->getNodeName();
|
||||
|
||||
/// @todo Make this loop nicer.
|
||||
while(currentNodeName == nnVertex ||
|
||||
currentNodeName == nnPosition ||
|
||||
currentNodeName == nnNormal ||
|
||||
currentNodeName == nnTangent ||
|
||||
currentNodeName == nnBinormal ||
|
||||
currentNodeName == nnTexCoord ||
|
||||
currentNodeName == nnColorDiffuse ||
|
||||
currentNodeName == nnColorSpecular)
|
||||
{
|
||||
if (currentNodeName == nnVertex)
|
||||
{
|
||||
NextNode(reader);
|
||||
currentNodeName = reader->getNodeName();
|
||||
}
|
||||
|
||||
/// @todo Implement nnBinormal, nnColorDiffuse and nnColorSpecular
|
||||
|
||||
if (submesh.HasPositions && currentNodeName == nnPosition)
|
||||
{
|
||||
aiVector3D NewPos;
|
||||
NewPos.x = GetAttribute<float>(reader, "x");
|
||||
NewPos.y = GetAttribute<float>(reader, "y");
|
||||
NewPos.z = GetAttribute<float>(reader, "z");
|
||||
submesh.Positions.push_back(NewPos);
|
||||
}
|
||||
else if (submesh.HasNormals && currentNodeName == nnNormal)
|
||||
{
|
||||
aiVector3D NewNormal;
|
||||
NewNormal.x = GetAttribute<float>(reader, "x");
|
||||
NewNormal.y = GetAttribute<float>(reader, "y");
|
||||
NewNormal.z = GetAttribute<float>(reader, "z");
|
||||
submesh.Normals.push_back(NewNormal);
|
||||
}
|
||||
else if (submesh.HasTangents && currentNodeName == nnTangent)
|
||||
{
|
||||
aiVector3D NewTangent;
|
||||
NewTangent.x = GetAttribute<float>(reader, "x");
|
||||
NewTangent.y = GetAttribute<float>(reader, "y");
|
||||
NewTangent.z = GetAttribute<float>(reader, "z");
|
||||
submesh.Tangents.push_back(NewTangent);
|
||||
}
|
||||
else if (submesh.Uvs.size() > 0 && currentNodeName == nnTexCoord)
|
||||
{
|
||||
for(size_t i=0, len=submesh.Uvs.size(); i<len; ++i)
|
||||
{
|
||||
if (currentNodeName != nnTexCoord) {
|
||||
throw DeadlyImportError("Vertex buffer declared more UVs than can be found in a vertex");
|
||||
}
|
||||
|
||||
aiVector3D NewUv;
|
||||
NewUv.x = GetAttribute<float>(reader, "u");
|
||||
NewUv.y = GetAttribute<float>(reader, "v") * (-1)+1; //flip the uv vertikal, blender exports them so! (ahem... @todo ????)
|
||||
submesh.Uvs[i].push_back(NewUv);
|
||||
|
||||
NextNode(reader);
|
||||
currentNodeName = reader->getNodeName();
|
||||
}
|
||||
// Continue main loop as above already read next node
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
/// @todo Remove this stuff once implemented. We only want to log warnings once per element.
|
||||
bool warn = true;
|
||||
if (currentNodeName == nnBinormal)
|
||||
{
|
||||
if (warnBinormal)
|
||||
{
|
||||
warnBinormal = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
warn = false;
|
||||
}
|
||||
}
|
||||
else if (currentNodeName == nnColorDiffuse)
|
||||
{
|
||||
if (warnColorDiffuse)
|
||||
{
|
||||
warnColorDiffuse = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
warn = false;
|
||||
}
|
||||
}
|
||||
else if (currentNodeName == nnColorSpecular)
|
||||
{
|
||||
if (warnColorSpecular)
|
||||
{
|
||||
warnColorSpecular = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
warn = false;
|
||||
}
|
||||
}
|
||||
if (warn) {
|
||||
DefaultLogger::get()->warn(string("Vertex buffer attribute read not implemented for element: ") + currentNodeName);
|
||||
}
|
||||
}
|
||||
|
||||
// Advance
|
||||
NextNode(reader);
|
||||
currentNodeName = reader->getNodeName();
|
||||
}
|
||||
|
||||
DefaultLogger::get()->debug(Formatter::format() <<
|
||||
" - Positions " << submesh.Positions.size() <<
|
||||
" Normals " << submesh.Normals.size() <<
|
||||
" TexCoords " << submesh.Uvs.size() <<
|
||||
" Tangents " << submesh.Tangents.size());
|
||||
|
||||
// Sanity checks
|
||||
if (submesh.HasNormals && submesh.Normals.size() != numVertices) {
|
||||
throw DeadlyImportError(Formatter::format() << "Read only " << submesh.Normals.size() << " normals when should have read " << numVertices);
|
||||
}
|
||||
if (submesh.HasTangents && submesh.Tangents.size() != numVertices) {
|
||||
throw DeadlyImportError(Formatter::format() << "Read only " << submesh.Tangents.size() << " tangents when should have read " << numVertices);
|
||||
}
|
||||
for(unsigned int i=0; i<submesh.Uvs.size(); ++i)
|
||||
{
|
||||
if (submesh.Uvs[i].size() != numVertices) {
|
||||
throw DeadlyImportError(Formatter::format() << "Read only " << submesh.Uvs[i].size()
|
||||
<< " uvs for uv index " << i << " when should have read " << numVertices);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OgreImporter::ReadBoneWeights(SubMesh &submesh, XmlReader *reader)
|
||||
{
|
||||
submesh.Weights.resize(submesh.Positions.size());
|
||||
|
||||
unsigned int numRead = 0;
|
||||
const string nnVertexBoneAssignment = "vertexboneassignment";
|
||||
|
||||
NextNode(reader);
|
||||
while(CurrentNodeNameEquals(reader, nnVertexBoneAssignment))
|
||||
{
|
||||
numRead++;
|
||||
|
||||
BoneWeight weight;
|
||||
weight.Id = GetAttribute<int>(reader, "boneindex");
|
||||
weight.Value = GetAttribute<float>(reader, "weight");
|
||||
|
||||
//calculate the number of bones used (this is the highest id +1 becuase bone ids start at 0)
|
||||
/// @todo This can probably be refactored to something else.
|
||||
submesh.BonesUsed = max(submesh.BonesUsed, weight.Id+1);
|
||||
|
||||
const unsigned int vertexId = GetAttribute<int>(reader, "vertexindex");
|
||||
submesh.Weights[vertexId].push_back(weight);
|
||||
|
||||
NextNode(reader);
|
||||
}
|
||||
DefaultLogger::get()->debug(Formatter::format() << " - Bone weights " << numRead);
|
||||
}
|
||||
|
||||
void OgreImporter::ProcessSubMesh(SubMesh &submesh, SubMesh &sharedGeometry)
|
||||
{
|
||||
// Make all vertexes unique. Required by Assimp.
|
||||
vector<Face> uniqueFaceList(submesh.Faces.size());
|
||||
unsigned int uniqueVertexCount = submesh.Faces.size() * 3;
|
||||
|
||||
vector<aiVector3D> uniquePositions(uniqueVertexCount);
|
||||
vector<aiVector3D> uniqueNormals(uniqueVertexCount);
|
||||
vector<aiVector3D> uniqueTangents(uniqueVertexCount);
|
||||
|
||||
vector<vector<BoneWeight> > uniqueWeights(uniqueVertexCount);
|
||||
vector<vector<aiVector3D> > uniqueUvs(submesh.UseSharedGeometry ? sharedGeometry.Uvs.size() : submesh.Uvs.size());
|
||||
|
||||
for(size_t uvi=0; uvi<uniqueUvs.size(); ++uvi) {
|
||||
uniqueUvs[uvi].resize(uniqueVertexCount);
|
||||
}
|
||||
|
||||
/* Support for shared geometry.
|
||||
We can use this loop to copy vertex informations from the shared data pool. In order to do so
|
||||
we just use a reference to a submodel instead of our submodel itself */
|
||||
SubMesh &vertexSource = (submesh.UseSharedGeometry ? sharedGeometry : submesh);
|
||||
if (submesh.UseSharedGeometry)
|
||||
{
|
||||
submesh.HasPositions = sharedGeometry.HasPositions;
|
||||
submesh.HasNormals = sharedGeometry.HasNormals;
|
||||
submesh.HasTangents = sharedGeometry.HasTangents;
|
||||
submesh.BonesUsed = sharedGeometry.BonesUsed;
|
||||
}
|
||||
|
||||
for (size_t i=0, flen=submesh.Faces.size(); i<flen; ++i)
|
||||
{
|
||||
const Face &face = submesh.Faces[i];
|
||||
|
||||
// We pre calculate the index values here,
|
||||
// because we need them in all vertex attributes.
|
||||
unsigned int v1 = face.VertexIndices[0];
|
||||
unsigned int v2 = face.VertexIndices[1];
|
||||
unsigned int v3 = face.VertexIndices[2];
|
||||
|
||||
size_t pos = i*3;
|
||||
|
||||
uniqueFaceList[i].VertexIndices[0] = pos;
|
||||
uniqueFaceList[i].VertexIndices[1] = pos + 1;
|
||||
uniqueFaceList[i].VertexIndices[2] = pos + 2;
|
||||
|
||||
uniquePositions[pos] = vertexSource.Positions[v1];
|
||||
uniquePositions[pos+1] = vertexSource.Positions[v2];
|
||||
uniquePositions[pos+2] = vertexSource.Positions[v3];
|
||||
|
||||
if (vertexSource.HasNormals)
|
||||
{
|
||||
uniqueNormals[pos ] = vertexSource.Normals[v1];
|
||||
uniqueNormals[pos+1] = vertexSource.Normals[v2];
|
||||
uniqueNormals[pos+2] = vertexSource.Normals[v3];
|
||||
}
|
||||
|
||||
if (vertexSource.HasTangents)
|
||||
{
|
||||
uniqueTangents[pos] = vertexSource.Tangents[v1];
|
||||
uniqueTangents[pos+1] = vertexSource.Tangents[v2];
|
||||
uniqueTangents[pos+2] = vertexSource.Tangents[v3];
|
||||
}
|
||||
|
||||
for(size_t uvi=0; uvi<uniqueUvs.size(); ++uvi)
|
||||
{
|
||||
const std::vector<aiVector3D> &uv = vertexSource.Uvs[uvi];
|
||||
uniqueUvs[uvi][pos] = uv[v1];
|
||||
uniqueUvs[uvi][pos+1] = uv[v2];
|
||||
uniqueUvs[uvi][pos+2] = uv[v3];
|
||||
}
|
||||
|
||||
if (!vertexSource.Weights.empty())
|
||||
{
|
||||
uniqueWeights[pos] = vertexSource.Weights[v1];
|
||||
uniqueWeights[pos+1] = vertexSource.Weights[v2];
|
||||
uniqueWeights[pos+2] = vertexSource.Weights[v3];
|
||||
}
|
||||
}
|
||||
|
||||
// Now we have the unique data, but want them in the SubMesh, so we swap all the containers.
|
||||
// If we don't have one of them, we just swap empty containers, so everything is ok.
|
||||
submesh.Faces.swap(uniqueFaceList);
|
||||
submesh.Positions.swap(uniquePositions);
|
||||
submesh.Normals.swap(uniqueNormals);
|
||||
submesh.Tangents.swap(uniqueTangents);
|
||||
submesh.Uvs.swap(uniqueUvs);
|
||||
submesh.Weights.swap(uniqueWeights);
|
||||
|
||||
// Normalize bone weights
|
||||
// For example the Blender exporter doesn't care about whether the sum of all bone
|
||||
// weights for a single vertex equals 1 or not, so validate here.
|
||||
for(size_t vertexId=0, wlen=submesh.Weights.size(); vertexId<wlen; ++vertexId)
|
||||
{
|
||||
std::vector<BoneWeight> &weights = submesh.Weights[vertexId];
|
||||
|
||||
float sum = 0.0f;
|
||||
for(size_t boneId=0, blen=weights.size(); boneId<blen; ++boneId) {
|
||||
sum += weights[boneId].Value;
|
||||
}
|
||||
|
||||
//check if the sum is too far away from 1
|
||||
if ((sum < (1.0f - 0.05f)) || (sum > (1.0f + 0.05f)))
|
||||
{
|
||||
for(size_t boneId=0, blen=weights.size(); boneId<blen; ++boneId) {
|
||||
weights[boneId].Value /= sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aiMesh *OgreImporter::CreateAssimpSubMesh(aiScene *pScene, const SubMesh& submesh, const vector<Bone>& bones) const
|
||||
{
|
||||
const size_t sizeVector3D = sizeof(aiVector3D);
|
||||
|
||||
aiMesh *dest = new aiMesh();
|
||||
|
||||
// Material
|
||||
dest->mMaterialIndex = submesh.MaterialIndex;
|
||||
|
||||
// Positions
|
||||
dest->mVertices = new aiVector3D[submesh.Positions.size()];
|
||||
dest->mNumVertices = submesh.Positions.size();
|
||||
memcpy(dest->mVertices, &submesh.Positions[0], submesh.Positions.size() * sizeVector3D);
|
||||
|
||||
// Normals
|
||||
if (submesh.HasNormals)
|
||||
{
|
||||
dest->mNormals = new aiVector3D[submesh.Normals.size()];
|
||||
memcpy(dest->mNormals, &submesh.Normals[0], submesh.Normals.size() * sizeVector3D);
|
||||
}
|
||||
|
||||
// Tangents
|
||||
// Until we have support for bitangents, no tangents will be written
|
||||
/// @todo Investigate why the above?
|
||||
if (submesh.HasTangents)
|
||||
{
|
||||
DefaultLogger::get()->warn("Tangents found from Ogre mesh but writing to Assimp mesh not yet supported!");
|
||||
//dest->mTangents = new aiVector3D[submesh.Tangents.size()];
|
||||
//memcpy(dest->mTangents, &submesh.Tangents[0], submesh.Tangents.size() * sizeVector3D);
|
||||
}
|
||||
|
||||
// UVs
|
||||
for (size_t i=0, len=submesh.Uvs.size(); i<len; ++i)
|
||||
{
|
||||
dest->mNumUVComponents[i] = 2;
|
||||
dest->mTextureCoords[i] = new aiVector3D[submesh.Uvs[i].size()];
|
||||
memcpy(dest->mTextureCoords[i], &(submesh.Uvs[i][0]), submesh.Uvs[i].size() * sizeVector3D);
|
||||
}
|
||||
|
||||
// Bone weights. Convert internal vertex-to-bone mapping to bone-to-vertex.
|
||||
vector<vector<aiVertexWeight> > assimpWeights(submesh.BonesUsed);
|
||||
for(size_t vertexId=0, len=submesh.Weights.size(); vertexId<len; ++vertexId)
|
||||
{
|
||||
const vector<BoneWeight> &vertexWeights = submesh.Weights[vertexId];
|
||||
for (size_t boneId=0, len=vertexWeights.size(); boneId<len; ++boneId)
|
||||
{
|
||||
const BoneWeight &ogreWeight = vertexWeights[boneId];
|
||||
assimpWeights[ogreWeight.Id].push_back(aiVertexWeight(vertexId, ogreWeight.Value));
|
||||
}
|
||||
}
|
||||
|
||||
// Bones.
|
||||
vector<aiBone*> assimpBones;
|
||||
assimpBones.reserve(submesh.BonesUsed);
|
||||
|
||||
for(size_t boneId=0, len=submesh.BonesUsed; boneId<len; ++boneId)
|
||||
{
|
||||
const vector<aiVertexWeight> &boneWeights = assimpWeights[boneId];
|
||||
if (boneWeights.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// @note The bones list is sorted by id's, this was done in LoadSkeleton.
|
||||
aiBone *assimpBone = new aiBone();
|
||||
assimpBone->mName = bones[boneId].Name;
|
||||
assimpBone->mOffsetMatrix = bones[boneId].BoneToWorldSpace;
|
||||
assimpBone->mNumWeights = boneWeights.size();
|
||||
assimpBone->mWeights = new aiVertexWeight[boneWeights.size()];
|
||||
memcpy(assimpBone->mWeights, &boneWeights[0], boneWeights.size() * sizeof(aiVertexWeight));
|
||||
|
||||
assimpBones.push_back(assimpBone);
|
||||
}
|
||||
|
||||
if (!assimpBones.empty())
|
||||
{
|
||||
dest->mBones = new aiBone*[assimpBones.size()];
|
||||
dest->mNumBones = assimpBones.size();
|
||||
|
||||
for(size_t i=0, len=assimpBones.size(); i<len; ++i) {
|
||||
dest->mBones[i] = assimpBones[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Faces
|
||||
dest->mFaces = new aiFace[submesh.Faces.size()];
|
||||
dest->mNumFaces = submesh.Faces.size();
|
||||
|
||||
for(size_t i=0, len=submesh.Faces.size(); i<len; ++i)
|
||||
{
|
||||
dest->mFaces[i].mNumIndices = 3;
|
||||
dest->mFaces[i].mIndices = new unsigned int[3];
|
||||
|
||||
const Face &f = submesh.Faces[i];
|
||||
dest->mFaces[i].mIndices[0] = f.VertexIndices[0];
|
||||
dest->mFaces[i].mIndices[1] = f.VertexIndices[1];
|
||||
dest->mFaces[i].mIndices[2] = f.VertexIndices[2];
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
} // Ogre
|
||||
} // Assimp
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
@@ -1,3 +1,42 @@
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2012, 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.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef AI_OGREPARSINGUTILS_H_INC
|
||||
#define AI_OGREPARSINGUTILS_H_INC
|
||||
@@ -5,144 +44,13 @@
|
||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
|
||||
#include "ParsingUtils.h"
|
||||
#include "irrXMLWrapper.h"
|
||||
#include "fast_atof.h"
|
||||
#include <functional>
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
namespace Ogre
|
||||
{
|
||||
|
||||
typedef irr::io::IrrXMLReader XmlReader;
|
||||
|
||||
static void ThrowAttibuteError(const XmlReader* reader, const std::string &name, const std::string &error = "")
|
||||
{
|
||||
if (!error.empty())
|
||||
{
|
||||
throw DeadlyImportError(error + " in node '" + std::string(reader->getNodeName()) + "' and attribute '" + name + "'");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw DeadlyImportError("Attribute '" + name + "' does not exist in node '" + std::string(reader->getNodeName()) + "'");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T GetAttribute(const XmlReader* reader, const std::string &name);
|
||||
|
||||
template<>
|
||||
inline int GetAttribute<int>(const XmlReader* reader, const std::string &name)
|
||||
{
|
||||
const char* value = reader->getAttributeValue(name.c_str());
|
||||
if (value)
|
||||
{
|
||||
return atoi(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrowAttibuteError(reader, name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
inline unsigned int GetAttribute<unsigned int>(const XmlReader* reader, const std::string &name)
|
||||
{
|
||||
const char* value = reader->getAttributeValue(name.c_str());
|
||||
if (value)
|
||||
{
|
||||
return static_cast<unsigned int>(atoi(value)); ///< @todo Find a better way...
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrowAttibuteError(reader, name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
inline float GetAttribute<float>(const XmlReader* reader, const std::string &name)
|
||||
{
|
||||
const char* value = reader->getAttributeValue(name.c_str());
|
||||
if (value)
|
||||
{
|
||||
return fast_atof(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrowAttibuteError(reader, name);
|
||||
return 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::string GetAttribute<std::string>(const XmlReader* reader, const std::string &name)
|
||||
{
|
||||
const char* value = reader->getAttributeValue(name.c_str());
|
||||
if (value)
|
||||
{
|
||||
return std::string(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrowAttibuteError(reader, name);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool GetAttribute<bool>(const XmlReader* reader, const std::string &name)
|
||||
{
|
||||
std::string value = GetAttribute<std::string>(reader, name);
|
||||
if (ASSIMP_stricmp(value, "true") == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (ASSIMP_stricmp(value, "false") == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrowAttibuteError(reader, name, "Boolean value is expected to be 'true' or 'false', encountered '" + value + "'");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool NextNode(XmlReader* reader)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (!reader->read()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while(reader->getNodeType() != irr::io::EXN_ELEMENT);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool CurrentNodeNameEquals(const XmlReader* reader, const std::string &name)
|
||||
{
|
||||
return (ASSIMP_stricmp(std::string(reader->getNodeName()), name) == 0);
|
||||
}
|
||||
|
||||
/// Skips a line from current @ss position until a newline. Returns the skipped part.
|
||||
static inline std::string SkipLine(std::stringstream &ss)
|
||||
{
|
||||
std::string skipped;
|
||||
getline(ss, skipped);
|
||||
return skipped;
|
||||
}
|
||||
|
||||
/// Skips a line and reads next element from @c ss to @c nextElement.
|
||||
/** @return Skipped line content until newline. */
|
||||
static inline std::string NextAfterNewLine(std::stringstream &ss, std::string &nextElement)
|
||||
{
|
||||
std::string skipped = SkipLine(ss);
|
||||
ss >> nextElement;
|
||||
return skipped;
|
||||
}
|
||||
|
||||
/// Returns a lower cased copy of @s.
|
||||
static inline std::string ToLower(std::string s)
|
||||
{
|
||||
@@ -207,6 +115,23 @@ static inline std::string &Trim(std::string &s, bool newlines = true)
|
||||
return TrimLeft(TrimRight(s, newlines), newlines);
|
||||
}
|
||||
|
||||
/// Skips a line from current @ss position until a newline. Returns the skipped part.
|
||||
static inline std::string SkipLine(std::stringstream &ss)
|
||||
{
|
||||
std::string skipped;
|
||||
getline(ss, skipped);
|
||||
return skipped;
|
||||
}
|
||||
|
||||
/// Skips a line and reads next element from @c ss to @c nextElement.
|
||||
/** @return Skipped line content until newline. */
|
||||
static inline std::string NextAfterNewLine(std::stringstream &ss, std::string &nextElement)
|
||||
{
|
||||
std::string skipped = SkipLine(ss);
|
||||
ss >> nextElement;
|
||||
return skipped;
|
||||
}
|
||||
|
||||
} // Ogre
|
||||
} // Assimp
|
||||
|
||||
|
||||
@@ -1,446 +0,0 @@
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2012, assimp team
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in aSource and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of aSource 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 "AssimpPCH.h"
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
|
||||
#include "OgreImporter.h"
|
||||
#include "TinyFormatter.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
namespace Ogre
|
||||
{
|
||||
|
||||
void OgreImporter::ReadSkeleton(const std::string &pFile, Assimp::IOSystem *pIOHandler, const aiScene *pScene,
|
||||
const std::string &skeletonFile, vector<Bone> &Bones, vector<Animation> &Animations) const
|
||||
{
|
||||
string filename = skeletonFile;
|
||||
if (EndsWith(filename, ".skeleton"))
|
||||
{
|
||||
DefaultLogger::get()->warn("Mesh is referencing a Ogre binary skeleton. Parsing binary Ogre assets is not supported at the moment. Trying to find .skeleton.xml file instead.");
|
||||
filename += ".xml";
|
||||
}
|
||||
|
||||
if (!pIOHandler->Exists(filename))
|
||||
{
|
||||
DefaultLogger::get()->error("Failed to find skeleton file '" + filename + "', skeleton will be missing.");
|
||||
return;
|
||||
}
|
||||
|
||||
boost::scoped_ptr<IOStream> file(pIOHandler->Open(filename));
|
||||
if (!file.get()) {
|
||||
throw DeadlyImportError("Failed to open skeleton file " + filename);
|
||||
}
|
||||
|
||||
boost::scoped_ptr<CIrrXML_IOStreamReader> stream(new CIrrXML_IOStreamReader(file.get()));
|
||||
XmlReader* reader = irr::io::createIrrXMLReader(stream.get());
|
||||
if (!reader) {
|
||||
throw DeadlyImportError("Failed to create XML reader for skeleton file " + filename);
|
||||
}
|
||||
|
||||
DefaultLogger::get()->debug("Reading skeleton '" + filename + "'");
|
||||
|
||||
// Root
|
||||
NextNode(reader);
|
||||
if (!CurrentNodeNameEquals(reader, "skeleton")) {
|
||||
throw DeadlyImportError("Root node is not <skeleton> but <" + string(reader->getNodeName()) + "> in " + filename);
|
||||
}
|
||||
|
||||
// Bones
|
||||
NextNode(reader);
|
||||
if (!CurrentNodeNameEquals(reader, "bones")) {
|
||||
throw DeadlyImportError("No <bones> node in skeleton " + skeletonFile);
|
||||
}
|
||||
|
||||
NextNode(reader);
|
||||
while(CurrentNodeNameEquals(reader, "bone"))
|
||||
{
|
||||
/** @todo Fix this mandatory ordering. Some exporters might just write rotation first etc.
|
||||
There is no technical reason this has to be so strict. */
|
||||
|
||||
Bone bone;
|
||||
bone.Id = GetAttribute<int>(reader, "id");
|
||||
bone.Name = GetAttribute<string>(reader, "name");
|
||||
|
||||
NextNode(reader);
|
||||
if (!CurrentNodeNameEquals(reader, "position")) {
|
||||
throw DeadlyImportError("Position is not first node in Bone!");
|
||||
}
|
||||
|
||||
bone.Position.x = GetAttribute<float>(reader, "x");
|
||||
bone.Position.y = GetAttribute<float>(reader, "y");
|
||||
bone.Position.z = GetAttribute<float>(reader, "z");
|
||||
|
||||
NextNode(reader);
|
||||
if (!CurrentNodeNameEquals(reader, "rotation")) {
|
||||
throw DeadlyImportError("Rotation is not the second node in Bone!");
|
||||
}
|
||||
|
||||
bone.RotationAngle = GetAttribute<float>(reader, "angle");
|
||||
|
||||
NextNode(reader);
|
||||
if (!CurrentNodeNameEquals(reader, "axis")) {
|
||||
throw DeadlyImportError("No axis specified for bone rotation!");
|
||||
}
|
||||
|
||||
bone.RotationAxis.x = GetAttribute<float>(reader, "x");
|
||||
bone.RotationAxis.y = GetAttribute<float>(reader, "y");
|
||||
bone.RotationAxis.z = GetAttribute<float>(reader, "z");
|
||||
|
||||
Bones.push_back(bone);
|
||||
|
||||
NextNode(reader);
|
||||
}
|
||||
|
||||
// Order bones by Id
|
||||
std::sort(Bones.begin(), Bones.end());
|
||||
|
||||
// Validate that bone indexes are not skipped.
|
||||
/** @note Left this from original authors code, but not sure if this is strictly necessary
|
||||
as per the Ogre skeleton spec. It might be more that other (later) code in this imported does not break. */
|
||||
for (size_t i=0, len=Bones.size(); i<len; ++i)
|
||||
{
|
||||
if (static_cast<int>(Bones[i].Id) != static_cast<int>(i)) {
|
||||
throw DeadlyImportError("Bone Ids are not in sequence in " + skeletonFile);
|
||||
}
|
||||
}
|
||||
|
||||
DefaultLogger::get()->debug(Formatter::format() << " - Bones " << Bones.size());
|
||||
|
||||
// Bone hierarchy
|
||||
if (!CurrentNodeNameEquals(reader, "bonehierarchy")) {
|
||||
throw DeadlyImportError("No <bonehierarchy> node found after <bones> in " + skeletonFile);
|
||||
}
|
||||
|
||||
NextNode(reader);
|
||||
while(CurrentNodeNameEquals(reader, "boneparent"))
|
||||
{
|
||||
string childName = GetAttribute<string>(reader, "bone");
|
||||
string parentName = GetAttribute<string>(reader, "parent");
|
||||
|
||||
vector<Bone>::iterator iterChild = find(Bones.begin(), Bones.end(), childName);
|
||||
vector<Bone>::iterator iterParent = find(Bones.begin(), Bones.end(), parentName);
|
||||
|
||||
if (iterChild != Bones.end() && iterParent != Bones.end())
|
||||
{
|
||||
iterChild->ParentId = iterParent->Id;
|
||||
iterParent->Children.push_back(iterChild->Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
DefaultLogger::get()->warn("Failed to find bones for parenting: Child " + childName + " Parent " + parentName);
|
||||
}
|
||||
|
||||
NextNode(reader);
|
||||
}
|
||||
|
||||
// Calculate bone matrices for root bones. Recursively does their children.
|
||||
BOOST_FOREACH(Bone &theBone, Bones)
|
||||
{
|
||||
if (!theBone.IsParented()) {
|
||||
theBone.CalculateBoneToWorldSpaceMatrix(Bones);
|
||||
}
|
||||
}
|
||||
|
||||
aiVector3D zeroVec(0.f, 0.f, 0.f);
|
||||
|
||||
// Animations
|
||||
if (CurrentNodeNameEquals(reader, "animations"))
|
||||
{
|
||||
DefaultLogger::get()->debug(" - Animations");
|
||||
|
||||
NextNode(reader);
|
||||
while(CurrentNodeNameEquals(reader, "animation"))
|
||||
{
|
||||
Animation animation;
|
||||
animation.Name = GetAttribute<string>(reader, "name");
|
||||
animation.Length = GetAttribute<float>(reader, "length");
|
||||
|
||||
// Tracks
|
||||
NextNode(reader);
|
||||
if (!CurrentNodeNameEquals(reader, "tracks")) {
|
||||
throw DeadlyImportError("No <tracks> node found in animation '" + animation.Name + "' in " + skeletonFile);
|
||||
}
|
||||
|
||||
NextNode(reader);
|
||||
while(CurrentNodeNameEquals(reader, "track"))
|
||||
{
|
||||
Track track;
|
||||
track.BoneName = GetAttribute<string>(reader, "bone");
|
||||
|
||||
// Keyframes
|
||||
NextNode(reader);
|
||||
if (!CurrentNodeNameEquals(reader, "keyframes")) {
|
||||
throw DeadlyImportError("No <keyframes> node found in a track in animation '" + animation.Name + "' in " + skeletonFile);
|
||||
}
|
||||
|
||||
NextNode(reader);
|
||||
while(CurrentNodeNameEquals(reader, "keyframe"))
|
||||
{
|
||||
KeyFrame keyFrame;
|
||||
keyFrame.Time = GetAttribute<float>(reader, "time");
|
||||
|
||||
NextNode(reader);
|
||||
while(CurrentNodeNameEquals(reader, "translate") || CurrentNodeNameEquals(reader, "rotate") || CurrentNodeNameEquals(reader, "scale"))
|
||||
{
|
||||
if (CurrentNodeNameEquals(reader, "translate"))
|
||||
{
|
||||
keyFrame.Position.x = GetAttribute<float>(reader, "x");
|
||||
keyFrame.Position.y = GetAttribute<float>(reader, "y");
|
||||
keyFrame.Position.z = GetAttribute<float>(reader, "z");
|
||||
}
|
||||
else if (CurrentNodeNameEquals(reader, "rotate"))
|
||||
{
|
||||
float angle = GetAttribute<float>(reader, "angle");
|
||||
|
||||
NextNode(reader);
|
||||
if (!CurrentNodeNameEquals(reader, "axis")) {
|
||||
throw DeadlyImportError("No axis for keyframe rotation in animation '" + animation.Name + "'");
|
||||
}
|
||||
|
||||
aiVector3D axis;
|
||||
axis.x = GetAttribute<float>(reader, "x");
|
||||
axis.y = GetAttribute<float>(reader, "y");
|
||||
axis.z = GetAttribute<float>(reader, "z");
|
||||
|
||||
if (axis.Equal(zeroVec))
|
||||
{
|
||||
axis.x = 1.0f;
|
||||
if (angle != 0) {
|
||||
DefaultLogger::get()->warn("Found invalid a key frame with a zero rotation axis in animation '" + animation.Name + "'");
|
||||
}
|
||||
}
|
||||
keyFrame.Rotation = aiQuaternion(axis, angle);
|
||||
}
|
||||
else if (CurrentNodeNameEquals(reader, "scale"))
|
||||
{
|
||||
keyFrame.Scaling.x = GetAttribute<float>(reader, "x");
|
||||
keyFrame.Scaling.y = GetAttribute<float>(reader, "y");
|
||||
keyFrame.Scaling.z = GetAttribute<float>(reader, "z");
|
||||
}
|
||||
NextNode(reader);
|
||||
}
|
||||
track.Keyframes.push_back(keyFrame);
|
||||
}
|
||||
animation.Tracks.push_back(track);
|
||||
}
|
||||
Animations.push_back(animation);
|
||||
|
||||
DefaultLogger::get()->debug(Formatter::format() << " " << animation.Name << " (" << animation.Length << " sec, " << animation.Tracks.size() << " tracks)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OgreImporter::CreateAssimpSkeleton(aiScene *pScene, const std::vector<Bone> &bones, const std::vector<Animation> &animations)
|
||||
{
|
||||
if (bones.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pScene->mRootNode) {
|
||||
throw DeadlyImportError("Creating Assimp skeleton: No root node created!");
|
||||
}
|
||||
if (pScene->mRootNode->mNumChildren > 0) {
|
||||
throw DeadlyImportError("Creating Assimp skeleton: Root node already has children!");
|
||||
}
|
||||
|
||||
// Bones
|
||||
vector<aiNode*> rootBones;
|
||||
BOOST_FOREACH(const Bone &bone, bones)
|
||||
{
|
||||
if (!bone.IsParented()) {
|
||||
rootBones.push_back(CreateNodeFromBone(bone.Id, bones, pScene->mRootNode));
|
||||
}
|
||||
}
|
||||
|
||||
if (!rootBones.empty())
|
||||
{
|
||||
pScene->mRootNode->mChildren = new aiNode*[rootBones.size()];
|
||||
pScene->mRootNode->mNumChildren = rootBones.size();
|
||||
|
||||
for(size_t i=0, len=rootBones.size(); i<len; ++i) {
|
||||
pScene->mRootNode->mChildren[i] = rootBones[i];
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Auf nicht vorhandene Animationskeys achten!
|
||||
// @todo Pay attention to non-existing animation Keys (google translated from above german comment)
|
||||
|
||||
// Animations
|
||||
if (!animations.empty())
|
||||
{
|
||||
pScene->mAnimations = new aiAnimation*[animations.size()];
|
||||
pScene->mNumAnimations = animations.size();
|
||||
|
||||
for(size_t ai=0, alen=animations.size(); ai<alen; ++ai)
|
||||
{
|
||||
const Animation &aSource = animations[ai];
|
||||
|
||||
aiAnimation *animation = new aiAnimation();
|
||||
animation->mName = aSource.Name;
|
||||
animation->mDuration = aSource.Length;
|
||||
animation->mTicksPerSecond = 1.0f;
|
||||
|
||||
// Tracks
|
||||
animation->mChannels = new aiNodeAnim*[aSource.Tracks.size()];
|
||||
animation->mNumChannels = aSource.Tracks.size();
|
||||
|
||||
for(size_t ti=0, tlen=aSource.Tracks.size(); ti<tlen; ++ti)
|
||||
{
|
||||
const Track &tSource = aSource.Tracks[ti];
|
||||
|
||||
aiNodeAnim *animationNode = new aiNodeAnim();
|
||||
animationNode->mNodeName = tSource.BoneName;
|
||||
|
||||
// We need this, to access the bones default pose.
|
||||
// Which we need to make keys absolute to the default bone pose.
|
||||
vector<Bone>::const_iterator boneIter = find(bones.begin(), bones.end(), tSource.BoneName);
|
||||
if (boneIter == bones.end())
|
||||
{
|
||||
for(size_t createdAnimationIndex=0; createdAnimationIndex<ai; createdAnimationIndex++) {
|
||||
delete pScene->mAnimations[createdAnimationIndex];
|
||||
}
|
||||
delete [] pScene->mAnimations;
|
||||
pScene->mAnimations = NULL;
|
||||
pScene->mNumAnimations = 0;
|
||||
|
||||
DefaultLogger::get()->error("Failed to find bone for name " + tSource.BoneName + " when creating animation " + aSource.Name +
|
||||
". This is a serious error, animations wont be imported.");
|
||||
return;
|
||||
}
|
||||
|
||||
aiMatrix4x4 t0, t1;
|
||||
aiMatrix4x4 defaultBonePose = aiMatrix4x4::Translation(boneIter->Position, t1) * aiMatrix4x4::Rotation(boneIter->RotationAngle, boneIter->RotationAxis, t0);
|
||||
|
||||
// Keyframes
|
||||
unsigned int numKeyframes = tSource.Keyframes.size();
|
||||
|
||||
animationNode->mPositionKeys = new aiVectorKey[numKeyframes];
|
||||
animationNode->mRotationKeys = new aiQuatKey[numKeyframes];
|
||||
animationNode->mScalingKeys = new aiVectorKey[numKeyframes];
|
||||
animationNode->mNumPositionKeys = numKeyframes;
|
||||
animationNode->mNumRotationKeys = numKeyframes;
|
||||
animationNode->mNumScalingKeys = numKeyframes;
|
||||
|
||||
//...and fill them
|
||||
for(size_t kfi=0; kfi<numKeyframes; ++kfi)
|
||||
{
|
||||
const KeyFrame &kfSource = tSource.Keyframes[kfi];
|
||||
|
||||
// Create a matrix to transform a vector from the bones
|
||||
// default pose to the bone bones in this animation key
|
||||
aiMatrix4x4 t2, t3;
|
||||
aiMatrix4x4 keyBonePose =
|
||||
aiMatrix4x4::Translation(kfSource.Position, t3) *
|
||||
aiMatrix4x4(kfSource.Rotation.GetMatrix()) *
|
||||
aiMatrix4x4::Scaling(kfSource.Scaling, t2);
|
||||
|
||||
// Calculate the complete transformation from world space to bone space
|
||||
aiMatrix4x4 CompleteTransform = defaultBonePose * keyBonePose;
|
||||
|
||||
aiVector3D kfPos; aiQuaternion kfRot; aiVector3D kfScale;
|
||||
CompleteTransform.Decompose(kfScale, kfRot, kfPos);
|
||||
|
||||
animationNode->mPositionKeys[kfi].mTime = static_cast<double>(kfSource.Time);
|
||||
animationNode->mRotationKeys[kfi].mTime = static_cast<double>(kfSource.Time);
|
||||
animationNode->mScalingKeys[kfi].mTime = static_cast<double>(kfSource.Time);
|
||||
|
||||
animationNode->mPositionKeys[kfi].mValue = kfPos;
|
||||
animationNode->mRotationKeys[kfi].mValue = kfRot;
|
||||
animationNode->mScalingKeys[kfi].mValue = kfScale;
|
||||
}
|
||||
animation->mChannels[ti] = animationNode;
|
||||
}
|
||||
pScene->mAnimations[ai] = animation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aiNode* OgreImporter::CreateNodeFromBone(int boneId, const std::vector<Bone> &bones, aiNode* parent)
|
||||
{
|
||||
aiMatrix4x4 t0,t1;
|
||||
const Bone &source = bones[boneId];
|
||||
|
||||
aiNode* boneNode = new aiNode(source.Name);
|
||||
boneNode->mParent = parent;
|
||||
boneNode->mTransformation = aiMatrix4x4::Translation(source.Position, t0) * aiMatrix4x4::Rotation(source.RotationAngle, source.RotationAxis, t1);
|
||||
|
||||
if (!source.Children.empty())
|
||||
{
|
||||
boneNode->mChildren = new aiNode*[source.Children.size()];
|
||||
boneNode->mNumChildren = source.Children.size();
|
||||
|
||||
for(size_t i=0, len=source.Children.size(); i<len; ++i) {
|
||||
boneNode->mChildren[i] = CreateNodeFromBone(source.Children[i], bones, boneNode);
|
||||
}
|
||||
}
|
||||
|
||||
return boneNode;
|
||||
}
|
||||
|
||||
void Bone::CalculateBoneToWorldSpaceMatrix(vector<Bone> &Bones)
|
||||
{
|
||||
aiMatrix4x4 t0, t1;
|
||||
aiMatrix4x4 transform = aiMatrix4x4::Rotation(-RotationAngle, RotationAxis, t1) * aiMatrix4x4::Translation(-Position, t0);
|
||||
|
||||
if (!IsParented())
|
||||
{
|
||||
BoneToWorldSpace = transform;
|
||||
}
|
||||
else
|
||||
{
|
||||
BoneToWorldSpace = transform * Bones[ParentId].BoneToWorldSpace;
|
||||
}
|
||||
|
||||
// Recursively for all children now that the parent matrix has been calculated.
|
||||
BOOST_FOREACH(int childId, Children)
|
||||
{
|
||||
Bones[childId].CalculateBoneToWorldSpaceMatrix(Bones);
|
||||
}
|
||||
}
|
||||
|
||||
} // Ogre
|
||||
} // Assimp
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
1193
code/OgreStructs.cpp
Normal file
1193
code/OgreStructs.cpp
Normal file
File diff suppressed because it is too large
Load Diff
681
code/OgreStructs.h
Normal file
681
code/OgreStructs.h
Normal file
@@ -0,0 +1,681 @@
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2012, 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.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef AI_OGRESTRUCTS_H_INC
|
||||
#define AI_OGRESTRUCTS_H_INC
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
|
||||
#include "AssimpPCH.h"
|
||||
#include "MemoryIOWrapper.h"
|
||||
|
||||
/** @note Parts of this implementation, for example enums, deserialization constants and logic
|
||||
has been copied directly with minor modifications from the MIT licensed Ogre3D code base.
|
||||
See more from https://bitbucket.org/sinbad/ogre. */
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
namespace Ogre
|
||||
{
|
||||
|
||||
// Forward decl
|
||||
class Mesh;
|
||||
class MeshXml;
|
||||
class SubMesh;
|
||||
class SubMeshXml;
|
||||
class Skeleton;
|
||||
|
||||
#define OGRE_SAFE_DELETE(p) delete p; p=0;
|
||||
|
||||
// Typedefs
|
||||
typedef Assimp::MemoryIOStream MemoryStream;
|
||||
typedef boost::shared_ptr<MemoryStream> MemoryStreamPtr;
|
||||
typedef std::map<uint16_t, MemoryStreamPtr> VertexBufferBindings;
|
||||
|
||||
// Ogre Vertex Element
|
||||
class VertexElement
|
||||
{
|
||||
public:
|
||||
/// Vertex element semantics, used to identify the meaning of vertex buffer contents
|
||||
enum Semantic {
|
||||
/// Position, 3 reals per vertex
|
||||
VES_POSITION = 1,
|
||||
/// Blending weights
|
||||
VES_BLEND_WEIGHTS = 2,
|
||||
/// Blending indices
|
||||
VES_BLEND_INDICES = 3,
|
||||
/// Normal, 3 reals per vertex
|
||||
VES_NORMAL = 4,
|
||||
/// Diffuse colours
|
||||
VES_DIFFUSE = 5,
|
||||
/// Specular colours
|
||||
VES_SPECULAR = 6,
|
||||
/// Texture coordinates
|
||||
VES_TEXTURE_COORDINATES = 7,
|
||||
/// Binormal (Y axis if normal is Z)
|
||||
VES_BINORMAL = 8,
|
||||
/// Tangent (X axis if normal is Z)
|
||||
VES_TANGENT = 9,
|
||||
/// The number of VertexElementSemantic elements (note - the first value VES_POSITION is 1)
|
||||
VES_COUNT = 9
|
||||
};
|
||||
|
||||
/// Vertex element type, used to identify the base types of the vertex contents
|
||||
enum Type
|
||||
{
|
||||
VET_FLOAT1 = 0,
|
||||
VET_FLOAT2 = 1,
|
||||
VET_FLOAT3 = 2,
|
||||
VET_FLOAT4 = 3,
|
||||
/// alias to more specific colour type - use the current rendersystem's colour packing
|
||||
VET_COLOUR = 4,
|
||||
VET_SHORT1 = 5,
|
||||
VET_SHORT2 = 6,
|
||||
VET_SHORT3 = 7,
|
||||
VET_SHORT4 = 8,
|
||||
VET_UBYTE4 = 9,
|
||||
/// D3D style compact colour
|
||||
VET_COLOUR_ARGB = 10,
|
||||
/// GL style compact colour
|
||||
VET_COLOUR_ABGR = 11,
|
||||
VET_DOUBLE1 = 12,
|
||||
VET_DOUBLE2 = 13,
|
||||
VET_DOUBLE3 = 14,
|
||||
VET_DOUBLE4 = 15,
|
||||
VET_USHORT1 = 16,
|
||||
VET_USHORT2 = 17,
|
||||
VET_USHORT3 = 18,
|
||||
VET_USHORT4 = 19,
|
||||
VET_INT1 = 20,
|
||||
VET_INT2 = 21,
|
||||
VET_INT3 = 22,
|
||||
VET_INT4 = 23,
|
||||
VET_UINT1 = 24,
|
||||
VET_UINT2 = 25,
|
||||
VET_UINT3 = 26,
|
||||
VET_UINT4 = 27
|
||||
};
|
||||
|
||||
VertexElement();
|
||||
|
||||
/// Size of the vertex element in bytes.
|
||||
size_t Size() const;
|
||||
|
||||
/// Count of components in this element, eg. VET_FLOAT3 return 3.
|
||||
size_t ComponentCount() const;
|
||||
|
||||
/// Type as string.
|
||||
std::string TypeToString();
|
||||
|
||||
/// Semantic as string.
|
||||
std::string SemanticToString();
|
||||
|
||||
static size_t TypeSize(Type type);
|
||||
static size_t ComponentCount(Type type);
|
||||
static std::string TypeToString(Type type);
|
||||
static std::string SemanticToString(Semantic semantic);
|
||||
|
||||
uint16_t index;
|
||||
uint16_t source;
|
||||
uint16_t offset;
|
||||
Type type;
|
||||
Semantic semantic;
|
||||
};
|
||||
typedef std::vector<VertexElement> VertexElementList;
|
||||
|
||||
/// Ogre Vertex Bone Assignment
|
||||
struct VertexBoneAssignment
|
||||
{
|
||||
uint32_t vertexIndex;
|
||||
uint16_t boneIndex;
|
||||
float weight;
|
||||
};
|
||||
typedef std::vector<VertexBoneAssignment> VertexBoneAssignmentList;
|
||||
typedef std::map<uint32_t, VertexBoneAssignmentList > VertexBoneAssignmentsMap;
|
||||
typedef std::map<uint16_t, std::vector<aiVertexWeight> > AssimpVertexBoneWeightList;
|
||||
|
||||
// Ogre Vertex Data interface, inherited by the binary and XML implementations.
|
||||
class IVertexData
|
||||
{
|
||||
public:
|
||||
IVertexData();
|
||||
|
||||
/// Returns if bone assignments are available.
|
||||
bool HasBoneAssignments() const;
|
||||
|
||||
/// Add vertex mapping from old to new index.
|
||||
void AddVertexMapping(uint32_t oldIndex, uint32_t newIndex);
|
||||
|
||||
/// Returns re-mapped bone assignments.
|
||||
/** @note Uses mappings added via AddVertexMapping. */
|
||||
AssimpVertexBoneWeightList AssimpBoneWeights(size_t vertices);
|
||||
|
||||
/// Returns a set of bone indexes that are referenced by bone assignments (weights).
|
||||
std::set<uint16_t> ReferencedBonesByWeights() const;
|
||||
|
||||
/// Vertex count.
|
||||
uint32_t count;
|
||||
|
||||
/// Bone assignments.
|
||||
VertexBoneAssignmentList boneAssignments;
|
||||
|
||||
private:
|
||||
void BoneAssignmentsForVertex(uint32_t currentIndex, uint32_t newIndex, VertexBoneAssignmentList &dest) const;
|
||||
|
||||
std::map<uint32_t, std::vector<uint32_t> > vertexIndexMapping;
|
||||
VertexBoneAssignmentsMap boneAssignmentsMap;
|
||||
};
|
||||
|
||||
// Ogre Vertex Data
|
||||
class VertexData : public IVertexData
|
||||
{
|
||||
public:
|
||||
VertexData();
|
||||
~VertexData();
|
||||
|
||||
/// Releases all memory that this data structure owns.
|
||||
void Reset();
|
||||
|
||||
/// Get vertex size for @c source.
|
||||
uint32_t VertexSize(uint16_t source) const;
|
||||
|
||||
/// Get vertex buffer for @c source.
|
||||
MemoryStream *VertexBuffer(uint16_t source);
|
||||
|
||||
/// Get vertex element for @c semantic for @c index.
|
||||
VertexElement *GetVertexElement(VertexElement::Semantic semantic, uint16_t index = 0);
|
||||
|
||||
/// Vertex elements.
|
||||
VertexElementList vertexElements;
|
||||
|
||||
/// Vertex buffers mapped to bind index.
|
||||
VertexBufferBindings vertexBindings;
|
||||
};
|
||||
|
||||
// Ogre Index Data
|
||||
class IndexData
|
||||
{
|
||||
public:
|
||||
IndexData();
|
||||
~IndexData();
|
||||
|
||||
/// Releases all memory that this data structure owns.
|
||||
void Reset();
|
||||
|
||||
/// Index size in bytes.
|
||||
size_t IndexSize() const;
|
||||
|
||||
/// Face size in bytes.
|
||||
size_t FaceSize() const;
|
||||
|
||||
/// Index count.
|
||||
uint32_t count;
|
||||
|
||||
/// Face count.
|
||||
uint32_t faceCount;
|
||||
|
||||
/// If has 32-bit indexes.
|
||||
bool is32bit;
|
||||
|
||||
/// Index buffer.
|
||||
MemoryStreamPtr buffer;
|
||||
};
|
||||
|
||||
/// Ogre Pose
|
||||
class Pose
|
||||
{
|
||||
public:
|
||||
struct Vertex
|
||||
{
|
||||
uint32_t index;
|
||||
aiVector3D offset;
|
||||
aiVector3D normal;
|
||||
};
|
||||
typedef std::map<uint32_t, Vertex> PoseVertexMap;
|
||||
|
||||
Pose() : target(0), hasNormals(false) {}
|
||||
|
||||
/// Name.
|
||||
std::string name;
|
||||
|
||||
/// Target.
|
||||
uint16_t target;
|
||||
|
||||
/// Does vertices map have normals.
|
||||
bool hasNormals;
|
||||
|
||||
/// Vertex offset and normals.
|
||||
PoseVertexMap vertices;
|
||||
};
|
||||
typedef std::vector<Pose*> PoseList;
|
||||
|
||||
/// Ogre Pose Key Frame Ref
|
||||
struct PoseRef
|
||||
{
|
||||
uint16_t index;
|
||||
float influence;
|
||||
};
|
||||
typedef std::vector<PoseRef> PoseRefList;
|
||||
|
||||
/// Ogre Pose Key Frame
|
||||
struct PoseKeyFrame
|
||||
{
|
||||
/// Time position in the animation.
|
||||
float timePos;
|
||||
|
||||
PoseRefList references;
|
||||
};
|
||||
typedef std::vector<PoseKeyFrame> PoseKeyFrameList;
|
||||
|
||||
/// Ogre Morph Key Frame
|
||||
struct MorphKeyFrame
|
||||
{
|
||||
/// Time position in the animation.
|
||||
float timePos;
|
||||
|
||||
MemoryStreamPtr buffer;
|
||||
};
|
||||
typedef std::vector<MorphKeyFrame> MorphKeyFrameList;
|
||||
|
||||
/// Ogre animation key frame
|
||||
struct TransformKeyFrame
|
||||
{
|
||||
TransformKeyFrame();
|
||||
|
||||
aiMatrix4x4 Transform();
|
||||
|
||||
float timePos;
|
||||
|
||||
aiQuaternion rotation;
|
||||
aiVector3D position;
|
||||
aiVector3D scale;
|
||||
};
|
||||
typedef std::vector<TransformKeyFrame> TransformKeyFrameList;
|
||||
|
||||
/// Ogre Animation Track
|
||||
struct VertexAnimationTrack
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
/// No animation
|
||||
VAT_NONE = 0,
|
||||
/// Morph animation is made up of many interpolated snapshot keyframes
|
||||
VAT_MORPH = 1,
|
||||
/// Pose animation is made up of a single delta pose keyframe
|
||||
VAT_POSE = 2,
|
||||
/// Keyframe that has its on pos, rot and scale for a time position
|
||||
VAT_TRANSFORM = 3
|
||||
};
|
||||
|
||||
VertexAnimationTrack();
|
||||
|
||||
/// Convert to Assimp node animation.
|
||||
aiNodeAnim *ConvertToAssimpAnimationNode(Skeleton *skeleton);
|
||||
|
||||
// Animation type.
|
||||
Type type;
|
||||
|
||||
/// Vertex data target.
|
||||
/** 0 == shared geometry
|
||||
>0 == submesh index + 1 */
|
||||
uint16_t target;
|
||||
|
||||
/// Only valid for VAT_TRANSFORM.
|
||||
std::string boneName;
|
||||
|
||||
/// Only one of these will contain key frames, depending on the type enum.
|
||||
PoseKeyFrameList poseKeyFrames;
|
||||
MorphKeyFrameList morphKeyFrames;
|
||||
TransformKeyFrameList transformKeyFrames;
|
||||
};
|
||||
typedef std::vector<VertexAnimationTrack> VertexAnimationTrackList;
|
||||
|
||||
/// Ogre Animation
|
||||
class Animation
|
||||
{
|
||||
public:
|
||||
Animation(Skeleton *parent);
|
||||
Animation(Mesh *parent);
|
||||
|
||||
/// Returns the associated vertex data for a track in this animation.
|
||||
/** @note Only valid to call when parent Mesh is set. */
|
||||
VertexData *AssociatedVertexData(VertexAnimationTrack *track) const;
|
||||
|
||||
/// Convert to Assimp animation.
|
||||
aiAnimation *ConvertToAssimpAnimation();
|
||||
|
||||
/// Parent mesh.
|
||||
/** @note Set only when animation is read from a mesh. */
|
||||
Mesh *parentMesh;
|
||||
|
||||
/// Parent skeleton.
|
||||
/** @note Set only when animation is read from a skeleton. */
|
||||
Skeleton *parentSkeleton;
|
||||
|
||||
/// Animation name.
|
||||
std::string name;
|
||||
|
||||
/// Base animation name.
|
||||
std::string baseName;
|
||||
|
||||
/// Length in seconds.
|
||||
float length;
|
||||
|
||||
/// Base animation key time.
|
||||
float baseTime;
|
||||
|
||||
/// Animation tracks.
|
||||
VertexAnimationTrackList tracks;
|
||||
};
|
||||
typedef std::vector<Animation*> AnimationList;
|
||||
|
||||
/// Ogre Bone
|
||||
class Bone
|
||||
{
|
||||
public:
|
||||
Bone();
|
||||
|
||||
/// Returns if this bone is parented.
|
||||
bool IsParented() const;
|
||||
|
||||
/// Parent index as uint16_t. Internally int32_t as -1 means unparented.
|
||||
uint16_t ParentId() const;
|
||||
|
||||
/// Add child bone.
|
||||
void AddChild(Bone *bone);
|
||||
|
||||
/// Calculates the world matrix for bone and its children.
|
||||
void CalculateWorldMatrixAndDefaultPose(Skeleton *skeleton);
|
||||
|
||||
/// Convert to Assimp node (animation nodes).
|
||||
aiNode *ConvertToAssimpNode(Skeleton *parent, aiNode *parentNode = 0);
|
||||
|
||||
/// Convert to Assimp bone (mesh bones).
|
||||
aiBone *ConvertToAssimpBone(Skeleton *parent, const std::vector<aiVertexWeight> &boneWeights);
|
||||
|
||||
uint16_t id;
|
||||
std::string name;
|
||||
|
||||
Bone *parent;
|
||||
int32_t parentId;
|
||||
std::vector<uint16_t> children;
|
||||
|
||||
aiVector3D position;
|
||||
aiQuaternion rotation;
|
||||
aiVector3D scale;
|
||||
|
||||
aiMatrix4x4 worldMatrix;
|
||||
aiMatrix4x4 defaultPose;
|
||||
};
|
||||
typedef std::vector<Bone*> BoneList;
|
||||
|
||||
/// Ogre Skeleton
|
||||
class Skeleton
|
||||
{
|
||||
public:
|
||||
enum BlendMode
|
||||
{
|
||||
/// Animations are applied by calculating a weighted average of all animations
|
||||
ANIMBLEND_AVERAGE = 0,
|
||||
/// Animations are applied by calculating a weighted cumulative total
|
||||
ANIMBLEND_CUMULATIVE = 1
|
||||
};
|
||||
|
||||
Skeleton();
|
||||
~Skeleton();
|
||||
|
||||
/// Releases all memory that this data structure owns.
|
||||
void Reset();
|
||||
|
||||
/// Returns unparented root bones.
|
||||
BoneList RootBones() const;
|
||||
|
||||
/// Returns number of unparented root bones.
|
||||
size_t NumRootBones() const;
|
||||
|
||||
/// Get bone by name.
|
||||
Bone *BoneByName(const std::string &name) const;
|
||||
|
||||
/// Get bone by id.
|
||||
Bone *BoneById(uint16_t id) const;
|
||||
|
||||
BoneList bones;
|
||||
AnimationList animations;
|
||||
|
||||
/// @todo Take blend mode into account, but where?
|
||||
BlendMode blendMode;
|
||||
};
|
||||
|
||||
/// Ogre Sub Mesh interface, inherited by the binary and XML implementations.
|
||||
class ISubMesh
|
||||
{
|
||||
public:
|
||||
/// @note Full list of Ogre types, not all of them are supported and exposed to Assimp.
|
||||
enum OperationType
|
||||
{
|
||||
/// A list of points, 1 vertex per point
|
||||
OT_POINT_LIST = 1,
|
||||
/// A list of lines, 2 vertices per line
|
||||
OT_LINE_LIST = 2,
|
||||
/// A strip of connected lines, 1 vertex per line plus 1 start vertex
|
||||
OT_LINE_STRIP = 3,
|
||||
/// A list of triangles, 3 vertices per triangle
|
||||
OT_TRIANGLE_LIST = 4,
|
||||
/// A strip of triangles, 3 vertices for the first triangle, and 1 per triangle after that
|
||||
OT_TRIANGLE_STRIP = 5,
|
||||
/// A fan of triangles, 3 vertices for the first triangle, and 1 per triangle after that
|
||||
OT_TRIANGLE_FAN = 6
|
||||
};
|
||||
|
||||
ISubMesh();
|
||||
|
||||
/// SubMesh index.
|
||||
unsigned int index;
|
||||
|
||||
/// SubMesh name.
|
||||
std::string name;
|
||||
|
||||
/// Material used by this submesh.
|
||||
std::string materialRef;
|
||||
|
||||
/// Texture alias information.
|
||||
std::string textureAliasName;
|
||||
std::string textureAliasRef;
|
||||
|
||||
/// Assimp scene material index used by this submesh.
|
||||
/** -1 if no material or material could not be imported. */
|
||||
int materialIndex;
|
||||
|
||||
/// If submesh uses shared geometry from parent mesh.
|
||||
bool usesSharedVertexData;
|
||||
|
||||
/// Operation type.
|
||||
OperationType operationType;
|
||||
};
|
||||
|
||||
/// Ogre SubMesh
|
||||
class SubMesh : public ISubMesh
|
||||
{
|
||||
public:
|
||||
SubMesh();
|
||||
~SubMesh();
|
||||
|
||||
/// Releases all memory that this data structure owns.
|
||||
/** @note Vertex and index data contains shared ptrs
|
||||
that are freed automatically. In practice the ref count
|
||||
should be 0 after this reset. */
|
||||
void Reset();
|
||||
|
||||
/// Covert to Assimp mesh.
|
||||
aiMesh *ConvertToAssimpMesh(Mesh *parent);
|
||||
|
||||
/// Vertex data.
|
||||
VertexData *vertexData;
|
||||
|
||||
/// Index data.
|
||||
IndexData *indexData;
|
||||
};
|
||||
typedef std::vector<SubMesh*> SubMeshList;
|
||||
|
||||
/// Ogre Mesh
|
||||
class Mesh
|
||||
{
|
||||
public:
|
||||
Mesh();
|
||||
~Mesh();
|
||||
|
||||
/// Releases all memory that this data structure owns.
|
||||
void Reset();
|
||||
|
||||
/// Returns number of subMeshes.
|
||||
size_t NumSubMeshes() const;
|
||||
|
||||
/// Returns submesh for @c index.
|
||||
SubMesh *GetSubMesh(uint16_t index) const;
|
||||
|
||||
/// Convert mesh to Assimp scene.
|
||||
void ConvertToAssimpScene(aiScene* dest);
|
||||
|
||||
/// Mesh has skeletal animations.
|
||||
bool hasSkeletalAnimations;
|
||||
|
||||
/// Skeleton reference.
|
||||
std::string skeletonRef;
|
||||
|
||||
/// Skeleton.
|
||||
Skeleton *skeleton;
|
||||
|
||||
/// Vertex data
|
||||
VertexData *sharedVertexData;
|
||||
|
||||
/// Sub meshes.
|
||||
SubMeshList subMeshes;
|
||||
|
||||
/// Animations
|
||||
AnimationList animations;
|
||||
|
||||
/// Poses
|
||||
PoseList poses;
|
||||
};
|
||||
|
||||
/// Ogre XML Vertex Data
|
||||
class VertexDataXml : public IVertexData
|
||||
{
|
||||
public:
|
||||
VertexDataXml();
|
||||
|
||||
bool HasPositions() const;
|
||||
bool HasNormals() const;
|
||||
bool HasTangents() const;
|
||||
bool HasUvs() const;
|
||||
size_t NumUvs() const;
|
||||
|
||||
std::vector<aiVector3D> positions;
|
||||
std::vector<aiVector3D> normals;
|
||||
std::vector<aiVector3D> tangents;
|
||||
std::vector<std::vector<aiVector3D> > uvs;
|
||||
};
|
||||
|
||||
/// Ogre XML Index Data
|
||||
class IndexDataXml
|
||||
{
|
||||
public:
|
||||
IndexDataXml() : faceCount(0) {}
|
||||
|
||||
/// Face count.
|
||||
uint32_t faceCount;
|
||||
|
||||
std::vector<aiFace> faces;
|
||||
};
|
||||
|
||||
/// Ogre XML SubMesh
|
||||
class SubMeshXml : public ISubMesh
|
||||
{
|
||||
public:
|
||||
SubMeshXml();
|
||||
~SubMeshXml();
|
||||
|
||||
/// Releases all memory that this data structure owns.
|
||||
void Reset();
|
||||
|
||||
aiMesh *ConvertToAssimpMesh(MeshXml *parent);
|
||||
|
||||
IndexDataXml *indexData;
|
||||
VertexDataXml *vertexData;
|
||||
};
|
||||
typedef std::vector<SubMeshXml*> SubMeshXmlList;
|
||||
|
||||
/// Ogre XML Mesh
|
||||
class MeshXml
|
||||
{
|
||||
public:
|
||||
MeshXml();
|
||||
~MeshXml();
|
||||
|
||||
/// Releases all memory that this data structure owns.
|
||||
void Reset();
|
||||
|
||||
/// Returns number of subMeshes.
|
||||
size_t NumSubMeshes() const;
|
||||
|
||||
/// Returns submesh for @c index.
|
||||
SubMeshXml *GetSubMesh(uint16_t index) const;
|
||||
|
||||
/// Convert mesh to Assimp scene.
|
||||
void ConvertToAssimpScene(aiScene* dest);
|
||||
|
||||
/// Skeleton reference.
|
||||
std::string skeletonRef;
|
||||
|
||||
/// Skeleton.
|
||||
Skeleton *skeleton;
|
||||
|
||||
/// Vertex data
|
||||
VertexDataXml *sharedVertexData;
|
||||
|
||||
/// Sub meshes.
|
||||
SubMeshXmlList subMeshes;
|
||||
};
|
||||
|
||||
} // Ogre
|
||||
} // Assimp
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
#endif // AI_OGRESTRUCTS_H_INC
|
||||
1003
code/OgreXmlSerializer.cpp
Normal file
1003
code/OgreXmlSerializer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
116
code/OgreXmlSerializer.h
Normal file
116
code/OgreXmlSerializer.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2012, 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.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef AI_OGREXMLSERIALIZER_H_INC
|
||||
#define AI_OGREXMLSERIALIZER_H_INC
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
|
||||
#include "OgreStructs.h"
|
||||
#include "irrXMLWrapper.h"
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
namespace Ogre
|
||||
{
|
||||
|
||||
typedef irr::io::IrrXMLReader XmlReader;
|
||||
typedef boost::shared_ptr<XmlReader> XmlReaderPtr;
|
||||
|
||||
class OgreXmlSerializer
|
||||
{
|
||||
public:
|
||||
/// Imports mesh and returns the result.
|
||||
/** @note Fatal unrecoverable errors will throw a DeadlyImportError. */
|
||||
static MeshXml *ImportMesh(XmlReader *reader);
|
||||
|
||||
/// Imports skeleton to @c mesh.
|
||||
/** If mesh does not have a skeleton reference or the skeleton file
|
||||
cannot be found it is not a fatal DeadlyImportError.
|
||||
@return If skeleton import was successful. */
|
||||
static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh);
|
||||
static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh);
|
||||
|
||||
private:
|
||||
OgreXmlSerializer(XmlReader *reader) :
|
||||
m_reader(reader)
|
||||
{
|
||||
}
|
||||
|
||||
static XmlReaderPtr OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename);
|
||||
|
||||
// Mesh
|
||||
void ReadMesh(MeshXml *mesh);
|
||||
void ReadSubMesh(MeshXml *mesh);
|
||||
|
||||
void ReadGeometry(VertexDataXml *dest);
|
||||
void ReadGeometryVertexBuffer(VertexDataXml *dest);
|
||||
|
||||
void ReadBoneAssignments(VertexDataXml *dest);
|
||||
|
||||
// Skeleton
|
||||
void ReadSkeleton(Skeleton *skeleton);
|
||||
|
||||
void ReadBones(Skeleton *skeleton);
|
||||
void ReadBoneHierarchy(Skeleton *skeleton);
|
||||
|
||||
void ReadAnimations(Skeleton *skeleton);
|
||||
void ReadAnimationTracks(Animation *dest);
|
||||
void ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *dest);
|
||||
|
||||
template<typename T>
|
||||
T ReadAttribute(const std::string &name) const;
|
||||
bool HasAttribute(const std::string &name) const;
|
||||
|
||||
std::string &NextNode();
|
||||
std::string &SkipCurrentNode();
|
||||
|
||||
bool CurrentNodeNameEquals(const std::string &name) const;
|
||||
std::string CurrentNodeName(bool forceRead = false);
|
||||
|
||||
XmlReader *m_reader;
|
||||
std::string m_currentNodeName;
|
||||
};
|
||||
|
||||
} // Ogre
|
||||
} // Assimp
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
#endif // AI_OGREXMLSERIALIZER_H_INC
|
||||
@@ -47,22 +47,28 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
#include "OptimizeMeshes.h"
|
||||
#include "ProcessHelper.h"
|
||||
#include "SceneCombiner.h"
|
||||
|
||||
static const unsigned int NotSet = 0xffffffff;
|
||||
static const unsigned int DeadBeef = 0xdeadbeef;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
OptimizeMeshesProcess::OptimizeMeshesProcess()
|
||||
: pts (false)
|
||||
, max_verts (0xffffffff)
|
||||
, max_faces (0xffffffff)
|
||||
{}
|
||||
, max_verts( NotSet )
|
||||
, max_faces( NotSet ) {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
OptimizeMeshesProcess::~OptimizeMeshesProcess()
|
||||
{}
|
||||
OptimizeMeshesProcess::~OptimizeMeshesProcess() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
@@ -74,17 +80,17 @@ bool OptimizeMeshesProcess::IsActive( unsigned int pFlags) const
|
||||
// That's a serious design flaw, consider redesign.
|
||||
if( 0 != (pFlags & aiProcess_OptimizeMeshes) ) {
|
||||
pts = (0 != (pFlags & aiProcess_SortByPType));
|
||||
max_verts = (0 != (pFlags & aiProcess_SplitLargeMeshes)) ? 0xdeadbeef : max_verts;
|
||||
max_verts = ( 0 != ( pFlags & aiProcess_SplitLargeMeshes ) ) ? DeadBeef : max_verts;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Setup properties for the postprocessing step
|
||||
// Setup properties for the post-processing step
|
||||
void OptimizeMeshesProcess::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
if (max_verts == 0xdeadbeef /* magic hack */) {
|
||||
if( max_verts == DeadBeef /* magic hack */ ) {
|
||||
max_faces = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES);
|
||||
max_verts = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES);
|
||||
}
|
||||
@@ -104,35 +110,36 @@ void OptimizeMeshesProcess::Execute( aiScene* pScene)
|
||||
mScene = pScene;
|
||||
|
||||
// need to clear persistent members from previous runs
|
||||
merge_list.clear();
|
||||
output.clear();
|
||||
merge_list.resize( 0 );
|
||||
output.resize( 0 );
|
||||
|
||||
// ensure we have the right sizes
|
||||
merge_list.reserve(pScene->mNumMeshes);
|
||||
output.reserve(pScene->mNumMeshes);
|
||||
|
||||
// Prepare lookup tables
|
||||
meshes.resize(pScene->mNumMeshes);
|
||||
FindInstancedMeshes(pScene->mRootNode);
|
||||
if (max_verts == 0xdeadbeef) /* undo the magic hack */
|
||||
max_verts = 0xffffffff;
|
||||
if( max_verts == DeadBeef ) /* undo the magic hack */
|
||||
max_verts = NotSet;
|
||||
|
||||
// ... instanced meshes are immediately processed and added to the output list
|
||||
for (unsigned int i = 0, n = 0; i < pScene->mNumMeshes;++i) {
|
||||
meshes[i].vertex_format = GetMeshVFormatUnique(pScene->mMeshes[i]);
|
||||
|
||||
if (meshes[i].instance_cnt > 1 && meshes[i].output_id == 0xffffffff) {
|
||||
if (meshes[i].instance_cnt > 1 && meshes[i].output_id == NotSet ) {
|
||||
meshes[i].output_id = n++;
|
||||
output.push_back(mScene->mMeshes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// and process all nodes in the scenegraoh recursively
|
||||
// and process all nodes in the scenegraph recursively
|
||||
ProcessNode(pScene->mRootNode);
|
||||
if (!output.size()) {
|
||||
throw DeadlyImportError("OptimizeMeshes: No meshes remaining; there's definitely something wrong");
|
||||
}
|
||||
|
||||
meshes.clear();
|
||||
meshes.resize( 0 );
|
||||
ai_assert(output.size() <= num_old);
|
||||
|
||||
mScene->mNumMeshes = output.size();
|
||||
@@ -142,8 +149,9 @@ void OptimizeMeshesProcess::Execute( aiScene* pScene)
|
||||
char tmp[512];
|
||||
::sprintf(tmp,"OptimizeMeshesProcess finished. Input meshes: %i, Output meshes: %i",num_old,pScene->mNumMeshes);
|
||||
DefaultLogger::get()->info(tmp);
|
||||
}
|
||||
else DefaultLogger::get()->debug("OptimizeMeshesProcess finished");
|
||||
} else {
|
||||
DefaultLogger::get()->debug( "OptimizeMeshesProcess finished" );
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -157,7 +165,7 @@ void OptimizeMeshesProcess::ProcessNode( aiNode* pNode)
|
||||
im = meshes[im].output_id;
|
||||
}
|
||||
else {
|
||||
merge_list.clear();
|
||||
merge_list.resize( 0 );
|
||||
unsigned int verts = 0, faces = 0;
|
||||
|
||||
// Find meshes to merge with us
|
||||
@@ -170,8 +178,9 @@ void OptimizeMeshesProcess::ProcessNode( aiNode* pNode)
|
||||
faces += mScene->mMeshes[am]->mNumFaces;
|
||||
|
||||
--pNode->mNumMeshes;
|
||||
for (unsigned int n = a; n < pNode->mNumMeshes; ++n)
|
||||
pNode->mMeshes[n] = pNode->mMeshes[n+1];
|
||||
for( unsigned int n = a; n < pNode->mNumMeshes; ++n ) {
|
||||
pNode->mMeshes[ n ] = pNode->mMeshes[ n + 1 ];
|
||||
}
|
||||
|
||||
--a;
|
||||
}
|
||||
@@ -184,8 +193,7 @@ void OptimizeMeshesProcess::ProcessNode( aiNode* pNode)
|
||||
aiMesh* out;
|
||||
SceneCombiner::MergeMeshes(&out,0,merge_list.begin(),merge_list.end());
|
||||
output.push_back(out);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
output.push_back(mScene->mMeshes[im]);
|
||||
}
|
||||
im = output.size()-1;
|
||||
@@ -193,8 +201,9 @@ void OptimizeMeshesProcess::ProcessNode( aiNode* pNode)
|
||||
}
|
||||
|
||||
|
||||
for (unsigned int i = 0; i < pNode->mNumChildren; ++i)
|
||||
ProcessNode(pNode->mChildren[i]);
|
||||
for( unsigned int i = 0; i < pNode->mNumChildren; ++i ) {
|
||||
ProcessNode( pNode->mChildren[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -206,8 +215,8 @@ bool OptimizeMeshesProcess::CanJoin ( unsigned int a, unsigned int b, unsigned i
|
||||
|
||||
aiMesh* ma = mScene->mMeshes[a], *mb = mScene->mMeshes[b];
|
||||
|
||||
if ((0xffffffff != max_verts && verts+mb->mNumVertices > max_verts) ||
|
||||
(0xffffffff != max_faces && faces+mb->mNumFaces > max_faces)) {
|
||||
if ((NotSet != max_verts && verts+mb->mNumVertices > max_verts) ||
|
||||
(NotSet != max_faces && faces+mb->mNumFaces > max_faces)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -221,7 +230,7 @@ bool OptimizeMeshesProcess::CanJoin ( unsigned int a, unsigned int b, unsigned i
|
||||
return false;
|
||||
|
||||
// If both meshes are skinned, check whether we have many bones defined in both meshes.
|
||||
// If yes, we can savely join them.
|
||||
// If yes, we can join them.
|
||||
if (ma->HasBones()) {
|
||||
// TODO
|
||||
return false;
|
||||
@@ -230,14 +239,18 @@ bool OptimizeMeshesProcess::CanJoin ( unsigned int a, unsigned int b, unsigned i
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Buidl a LUT of all instanced meshes
|
||||
// Build a LUT of all instanced meshes
|
||||
void OptimizeMeshesProcess::FindInstancedMeshes (aiNode* pNode)
|
||||
{
|
||||
for (unsigned int i = 0; i < pNode->mNumMeshes;++i)
|
||||
++meshes[pNode->mMeshes[i]].instance_cnt;
|
||||
for( unsigned int i = 0; i < pNode->mNumMeshes; ++i ) {
|
||||
++meshes[ pNode->mMeshes[ i ] ].instance_cnt;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < pNode->mNumChildren; ++i)
|
||||
FindInstancedMeshes(pNode->mChildren[i]);
|
||||
for( unsigned int i = 0; i < pNode->mNumChildren; ++i ) {
|
||||
FindInstancedMeshes( pNode->mChildren[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
#endif // !! ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS
|
||||
|
||||
@@ -38,6 +38,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// TODO: refactor entire file to get rid of the "flat-copy" first approach
|
||||
// to copying structures. This easily breaks in the most unintuitive way
|
||||
// possible as new fields are added to assimp structures.
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** @file Implements Assimp::SceneCombiner. This is a smart utility
|
||||
@@ -1194,10 +1197,53 @@ void SceneCombiner::Copy (aiNode** _dest, const aiNode* src)
|
||||
// get a flat copy
|
||||
::memcpy(dest,src,sizeof(aiNode));
|
||||
|
||||
if (src->mMetaData) {
|
||||
Copy(&dest->mMetaData, src->mMetaData);
|
||||
}
|
||||
|
||||
// and reallocate all arrays
|
||||
GetArrayCopy( dest->mMeshes, dest->mNumMeshes );
|
||||
CopyPtrArray( dest->mChildren, src->mChildren,dest->mNumChildren);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SceneCombiner::Copy (aiMetadata** _dest, const aiMetadata* src)
|
||||
{
|
||||
ai_assert(NULL != _dest && NULL != src);
|
||||
|
||||
aiMetadata* dest = *_dest = new aiMetadata();
|
||||
dest->mNumProperties = src->mNumProperties;
|
||||
dest->mKeys = new aiString[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];
|
||||
out.mType = in.mType;
|
||||
switch (dest->mValues[i].mType) {
|
||||
case AI_BOOL:
|
||||
out.mData = new bool(*static_cast<bool*>(in.mData));
|
||||
break;
|
||||
case AI_INT:
|
||||
out.mData = new int(*static_cast<int*>(in.mData));
|
||||
break;
|
||||
case AI_UINT64:
|
||||
out.mData = new uint64_t(*static_cast<uint64_t*>(in.mData));
|
||||
break;
|
||||
case AI_FLOAT:
|
||||
out.mData = new float(*static_cast<float*>(in.mData));
|
||||
break;
|
||||
case AI_AISTRING:
|
||||
out.mData = new aiString(*static_cast<aiString*>(in.mData));
|
||||
break;
|
||||
case AI_AIVECTOR3D:
|
||||
out.mData = new aiVector3D(*static_cast<aiVector3D*>(in.mData));
|
||||
break;
|
||||
default:
|
||||
ai_assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -349,6 +349,7 @@ public:
|
||||
static void Copy (aiBone** dest, const aiBone* src);
|
||||
static void Copy (aiLight** dest, const aiLight* src);
|
||||
static void Copy (aiNodeAnim** dest, const aiNodeAnim* src);
|
||||
static void Copy (aiMetadata** dest, const aiMetadata* src);
|
||||
|
||||
// recursive, of course
|
||||
static void Copy (aiNode** dest, const aiNode* src);
|
||||
|
||||
517
code/XFileExporter.cpp
Normal file
517
code/XFileExporter.cpp
Normal file
@@ -0,0 +1,517 @@
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2012, 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.
|
||||
|
||||
@author: Richard Steffen, 2014
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "AssimpPCH.h"
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||
#ifndef ASSIMP_BUILD_NO_XFILE_EXPORTER
|
||||
#include "XFileExporter.h"
|
||||
#include "ConvertToLHProcess.h"
|
||||
#include "Bitmap.h"
|
||||
#include "fast_atof.h"
|
||||
#include "SceneCombiner.h"
|
||||
|
||||
#include <ctime>
|
||||
#include <set>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp
|
||||
void ExportSceneXFile(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene)
|
||||
{
|
||||
std::string path = "";
|
||||
std::string file = pFile;
|
||||
|
||||
// We need to test both types of folder separators because pIOSystem->getOsSeparator() is not reliable.
|
||||
// Moreover, the path given by some applications is not even consistent with the OS specific type of separator.
|
||||
const char* end_path = std::max(strrchr(pFile, '\\'), strrchr(pFile, '/'));
|
||||
|
||||
if(end_path != NULL) {
|
||||
path = std::string(pFile, end_path + 1 - pFile);
|
||||
file = file.substr(end_path + 1 - pFile, file.npos);
|
||||
|
||||
std::size_t pos = file.find_last_of('.');
|
||||
if(pos != file.npos) {
|
||||
file = file.substr(0, pos);
|
||||
}
|
||||
}
|
||||
|
||||
// invoke the exporter
|
||||
XFileExporter iDoTheExportThing( pScene, pIOSystem, path, file);
|
||||
|
||||
// we're still here - export successfully completed. Write result to the given IOSYstem
|
||||
boost::scoped_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
|
||||
if(outfile == NULL) {
|
||||
throw DeadlyExportError("could not open output .dae file: " + std::string(pFile));
|
||||
}
|
||||
|
||||
// XXX maybe use a small wrapper around IOStream that behaves like std::stringstream in order to avoid the extra copy.
|
||||
outfile->Write( iDoTheExportThing.mOutput.str().c_str(), static_cast<size_t>(iDoTheExportThing.mOutput.tellp()),1);
|
||||
}
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor for a specific scene to export
|
||||
XFileExporter::XFileExporter(const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file) : mIOSystem(pIOSystem), mPath(path), mFile(file)
|
||||
{
|
||||
// make sure that all formatting happens using the standard, C locale and not the user's current locale
|
||||
mOutput.imbue( std::locale("C") );
|
||||
|
||||
mScene = pScene;
|
||||
mSceneOwned = false;
|
||||
|
||||
// set up strings
|
||||
endstr = "\n";
|
||||
|
||||
// start writing
|
||||
WriteFile();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor
|
||||
XFileExporter::~XFileExporter()
|
||||
{
|
||||
if(mSceneOwned) {
|
||||
delete mScene;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Starts writing the contents
|
||||
void XFileExporter::WriteFile()
|
||||
{
|
||||
// note, that all realnumber values must be comma separated in x files
|
||||
mOutput.setf(std::ios::fixed);
|
||||
mOutput.precision(6); // precission for float
|
||||
|
||||
// entry of writing the file
|
||||
WriteHeader();
|
||||
|
||||
mOutput << startstr << "Frame DXCC_ROOT {" << endstr;
|
||||
PushTag();
|
||||
|
||||
aiMatrix4x4 I; // identity
|
||||
WriteFrameTransform(I);
|
||||
|
||||
WriteNode(mScene->mRootNode);
|
||||
PopTag();
|
||||
|
||||
mOutput << startstr << "}" << endstr;
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Writes the asset header
|
||||
void XFileExporter::WriteHeader()
|
||||
{
|
||||
mOutput << startstr << "xof 0303txt 0032" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template Frame {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<3d82ab46-62da-11cf-ab39-0020af71e433>" << endstr;
|
||||
mOutput << startstr << "[...]" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template Matrix4x4 {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<f6f23f45-7686-11cf-8f52-0040333594a3>" << endstr;
|
||||
mOutput << startstr << "array FLOAT matrix[16];" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template FrameTransformMatrix {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<f6f23f41-7686-11cf-8f52-0040333594a3>" << endstr;
|
||||
mOutput << startstr << "Matrix4x4 frameMatrix;" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template Vector {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<3d82ab5e-62da-11cf-ab39-0020af71e433>" << endstr;
|
||||
mOutput << startstr << "FLOAT x;" << endstr;
|
||||
mOutput << startstr << "FLOAT y;" << endstr;
|
||||
mOutput << startstr << "FLOAT z;" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template MeshFace {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<3d82ab5f-62da-11cf-ab39-0020af71e433>" << endstr;
|
||||
mOutput << startstr << "DWORD nFaceVertexIndices;" << endstr;
|
||||
mOutput << startstr << "array DWORD faceVertexIndices[nFaceVertexIndices];" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template Mesh {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<3d82ab44-62da-11cf-ab39-0020af71e433>" << endstr;
|
||||
mOutput << startstr << "DWORD nVertices;" << endstr;
|
||||
mOutput << startstr << "array Vector vertices[nVertices];" << endstr;
|
||||
mOutput << startstr << "DWORD nFaces;" << endstr;
|
||||
mOutput << startstr << "array MeshFace faces[nFaces];" << endstr;
|
||||
mOutput << startstr << "[...]" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template MeshNormals {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<f6f23f43-7686-11cf-8f52-0040333594a3>" << endstr;
|
||||
mOutput << startstr << "DWORD nNormals;" << endstr;
|
||||
mOutput << startstr << "array Vector normals[nNormals];" << endstr;
|
||||
mOutput << startstr << "DWORD nFaceNormals;" << endstr;
|
||||
mOutput << startstr << "array MeshFace faceNormals[nFaceNormals];" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template Coords2d {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<f6f23f44-7686-11cf-8f52-0040333594a3>" << endstr;
|
||||
mOutput << startstr << "FLOAT u;" << endstr;
|
||||
mOutput << startstr << "FLOAT v;" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template MeshTextureCoords {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<f6f23f40-7686-11cf-8f52-0040333594a3>" << endstr;
|
||||
mOutput << startstr << "DWORD nTextureCoords;" << endstr;
|
||||
mOutput << startstr << "array Coords2d textureCoords[nTextureCoords];" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template ColorRGBA {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<35ff44e0-6c7c-11cf-8f52-0040333594a3>" << endstr;
|
||||
mOutput << startstr << "FLOAT red;" << endstr;
|
||||
mOutput << startstr << "FLOAT green;" << endstr;
|
||||
mOutput << startstr << "FLOAT blue;" << endstr;
|
||||
mOutput << startstr << "FLOAT alpha;" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template IndexedColor {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<1630b820-7842-11cf-8f52-0040333594a3>" << endstr;
|
||||
mOutput << startstr << "DWORD index;" << endstr;
|
||||
mOutput << startstr << "ColorRGBA indexColor;" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template MeshVertexColors {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<1630b821-7842-11cf-8f52-0040333594a3>" << endstr;
|
||||
mOutput << startstr << "DWORD nVertexColors;" << endstr;
|
||||
mOutput << startstr << "array IndexedColor vertexColors[nVertexColors];" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template VertexElement {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<f752461c-1e23-48f6-b9f8-8350850f336f>" << endstr;
|
||||
mOutput << startstr << "DWORD Type;" << endstr;
|
||||
mOutput << startstr << "DWORD Method;" << endstr;
|
||||
mOutput << startstr << "DWORD Usage;" << endstr;
|
||||
mOutput << startstr << "DWORD UsageIndex;" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
mOutput << startstr << "template DeclData {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<bf22e553-292c-4781-9fea-62bd554bdd93>" << endstr;
|
||||
mOutput << startstr << "DWORD nElements;" << endstr;
|
||||
mOutput << startstr << "array VertexElement Elements[nElements];" << endstr;
|
||||
mOutput << startstr << "DWORD nDWords;" << endstr;
|
||||
mOutput << startstr << "array DWORD data[nDWords];" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
mOutput << endstr;
|
||||
}
|
||||
|
||||
|
||||
// Writes the material setup
|
||||
void XFileExporter::WriteFrameTransform(aiMatrix4x4& m)
|
||||
{
|
||||
mOutput << startstr << "FrameTransformMatrix {" << endstr << " ";
|
||||
PushTag();
|
||||
mOutput << startstr << m.a1 << ", " << m.b1 << ", " << m.c1 << ", " << m.d1 << "," << endstr;
|
||||
mOutput << startstr << m.a2 << ", " << m.b2 << ", " << m.c2 << ", " << m.d2 << "," << endstr;
|
||||
mOutput << startstr << m.a3 << ", " << m.b3 << ", " << m.c3 << ", " << m.d3 << "," << endstr;
|
||||
mOutput << startstr << m.a4 << ", " << m.b4 << ", " << m.c4 << ", " << m.d4 << ";;" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr << endstr;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Recursively writes the given node
|
||||
void XFileExporter::WriteNode( aiNode* pNode)
|
||||
{
|
||||
if (pNode->mName.length==0)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Node_" << pNode;
|
||||
pNode->mName.Set(ss.str());
|
||||
}
|
||||
mOutput << startstr << "Frame " << pNode->mName.C_Str() << " {" << endstr;
|
||||
|
||||
PushTag();
|
||||
|
||||
aiMatrix4x4 m = pNode->mTransformation;
|
||||
|
||||
WriteFrameTransform(m);
|
||||
|
||||
for (size_t i = 0; i < pNode->mNumMeshes; i++)
|
||||
WriteMesh(mScene->mMeshes[pNode->mMeshes[i]]);
|
||||
|
||||
// recursive call the Nodes
|
||||
for (size_t a = 0; a < pNode->mNumChildren; a++)
|
||||
WriteNode( mScene->mRootNode->mChildren[a]);
|
||||
|
||||
PopTag();
|
||||
|
||||
mOutput << startstr << "}" << endstr << endstr;
|
||||
}
|
||||
|
||||
void XFileExporter::WriteMesh(const aiMesh* mesh)
|
||||
{
|
||||
mOutput << startstr << "Mesh " << mesh->mName.C_Str() << "_mShape" << " {" << endstr;
|
||||
|
||||
PushTag();
|
||||
|
||||
// write all the vertices
|
||||
mOutput << startstr << mesh->mNumVertices << ";" << endstr;
|
||||
for (size_t a = 0; a < mesh->mNumVertices; a++)
|
||||
{
|
||||
aiVector3D &v = mesh->mVertices[a];
|
||||
mOutput << startstr << v[0] << ";"<< v[1] << ";" << v[2] << ";";
|
||||
if (a < mesh->mNumVertices - 1)
|
||||
mOutput << "," << endstr;
|
||||
else
|
||||
mOutput << ";" << endstr;
|
||||
}
|
||||
|
||||
// write all the faces
|
||||
mOutput << startstr << mesh->mNumFaces << ";" << endstr;
|
||||
for( size_t a = 0; a < mesh->mNumFaces; ++a )
|
||||
{
|
||||
const aiFace& face = mesh->mFaces[a];
|
||||
mOutput << startstr << face.mNumIndices << ";";
|
||||
// must be counter clockwise triangle
|
||||
//for(int b = face.mNumIndices - 1; b >= 0 ; --b)
|
||||
for(size_t b = 0; b < face.mNumIndices ; ++b)
|
||||
{
|
||||
mOutput << face.mIndices[b];
|
||||
//if (b > 0)
|
||||
if (b<face.mNumIndices-1)
|
||||
mOutput << ",";
|
||||
else
|
||||
mOutput << ";";
|
||||
}
|
||||
|
||||
if (a < mesh->mNumFaces - 1)
|
||||
mOutput << "," << endstr;
|
||||
else
|
||||
mOutput << ";" << endstr;
|
||||
}
|
||||
|
||||
mOutput << endstr;
|
||||
|
||||
if (mesh->HasTextureCoords(0))
|
||||
{
|
||||
const aiMaterial* mat = mScene->mMaterials[mesh->mMaterialIndex];
|
||||
aiString relpath;
|
||||
mat->Get(_AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE, 0, relpath);
|
||||
|
||||
mOutput << startstr << "MeshMaterialList {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "1;" << endstr; // number of materials
|
||||
mOutput << startstr << mesh->mNumFaces << ";" << endstr; // number of faces
|
||||
mOutput << startstr;
|
||||
for( size_t a = 0; a < mesh->mNumFaces; ++a )
|
||||
{
|
||||
mOutput << "0"; // the material index
|
||||
if (a < mesh->mNumFaces - 1)
|
||||
mOutput << ", ";
|
||||
else
|
||||
mOutput << ";" << endstr;
|
||||
}
|
||||
mOutput << startstr << "Material {" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "1.0; 1.0; 1.0; 1.000000;;" << endstr;
|
||||
mOutput << startstr << "1.000000;" << endstr; // power
|
||||
mOutput << startstr << "0.000000; 0.000000; 0.000000;;" << endstr; // specularity
|
||||
mOutput << startstr << "0.000000; 0.000000; 0.000000;;" << endstr; // emission
|
||||
mOutput << startstr << "TextureFilename { \"";
|
||||
|
||||
writePath(relpath);
|
||||
|
||||
mOutput << "\"; }" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr;
|
||||
}
|
||||
|
||||
// write normals (every vertex has one)
|
||||
if (mesh->HasNormals())
|
||||
{
|
||||
mOutput << endstr << startstr << "MeshNormals {" << endstr;
|
||||
mOutput << startstr << mesh->mNumVertices << ";" << endstr;
|
||||
for (size_t a = 0; a < mesh->mNumVertices; a++)
|
||||
{
|
||||
aiVector3D &v = mesh->mNormals[a];
|
||||
// because we have a LHS and also changed wth winding, we need to invert the normals again
|
||||
mOutput << startstr << -v[0] << ";"<< -v[1] << ";" << -v[2] << ";";
|
||||
if (a < mesh->mNumVertices - 1)
|
||||
mOutput << "," << endstr;
|
||||
else
|
||||
mOutput << ";" << endstr;
|
||||
}
|
||||
|
||||
mOutput << startstr << mesh->mNumFaces << ";" << endstr;
|
||||
for (size_t a = 0; a < mesh->mNumFaces; a++)
|
||||
{
|
||||
const aiFace& face = mesh->mFaces[a];
|
||||
mOutput << startstr << face.mNumIndices << ";";
|
||||
|
||||
//for(int b = face.mNumIndices-1; b >= 0 ; --b)
|
||||
for(size_t b = 0; b < face.mNumIndices ; ++b)
|
||||
{
|
||||
mOutput << face.mIndices[b];
|
||||
//if (b > 0)
|
||||
if (b<face.mNumIndices-1)
|
||||
mOutput << ",";
|
||||
else
|
||||
mOutput << ";";
|
||||
}
|
||||
|
||||
if (a < mesh->mNumFaces-1)
|
||||
mOutput << "," << endstr;
|
||||
else
|
||||
mOutput << ";" << endstr;
|
||||
}
|
||||
mOutput << startstr << "}" << endstr;
|
||||
}
|
||||
|
||||
// write texture UVs if available
|
||||
if (mesh->HasTextureCoords(0))
|
||||
{
|
||||
mOutput << endstr << startstr << "MeshTextureCoords {" << endstr;
|
||||
mOutput << startstr << mesh->mNumVertices << ";" << endstr;
|
||||
for (size_t a = 0; a < mesh->mNumVertices; a++)
|
||||
//for (int a = (int)mesh->mNumVertices-1; a >=0 ; a--)
|
||||
{
|
||||
aiVector3D& uv = mesh->mTextureCoords[0][a]; // uv of first uv layer for the vertex
|
||||
mOutput << startstr << uv.x << ";" << uv.y;
|
||||
if (a < mesh->mNumVertices-1)
|
||||
//if (a >0 )
|
||||
mOutput << ";," << endstr;
|
||||
else
|
||||
mOutput << ";;" << endstr;
|
||||
}
|
||||
mOutput << startstr << "}" << endstr;
|
||||
}
|
||||
|
||||
// write color channel if available
|
||||
if (mesh->HasVertexColors(0))
|
||||
{
|
||||
mOutput << endstr << startstr << "MeshVertexColors {" << endstr;
|
||||
mOutput << startstr << mesh->mNumVertices << ";" << endstr;
|
||||
for (size_t a = 0; a < mesh->mNumVertices; a++)
|
||||
{
|
||||
aiColor4D& mColors = mesh->mColors[0][a]; // color of first vertex color set for the vertex
|
||||
mOutput << startstr << a << ";" << mColors.r << ";" << mColors.g << ";" << mColors.b << ";" << mColors.a << ";;";
|
||||
if (a < mesh->mNumVertices-1)
|
||||
mOutput << "," << endstr;
|
||||
else
|
||||
mOutput << ";" << endstr;
|
||||
}
|
||||
mOutput << startstr << "}" << endstr;
|
||||
}
|
||||
/*
|
||||
else
|
||||
{
|
||||
mOutput << endstr << startstr << "MeshVertexColors {" << endstr;
|
||||
mOutput << startstr << mesh->mNumVertices << ";" << endstr;
|
||||
for (size_t a = 0; a < mesh->mNumVertices; a++)
|
||||
{
|
||||
aiColor4D* mColors = mesh->mColors[a];
|
||||
mOutput << startstr << a << ";0.500000;0.000000;0.000000;0.500000;;";
|
||||
if (a < mesh->mNumVertices-1)
|
||||
mOutput << "," << endstr;
|
||||
else
|
||||
mOutput << ";" << endstr;
|
||||
}
|
||||
mOutput << startstr << "}" << endstr;
|
||||
}
|
||||
*/
|
||||
PopTag();
|
||||
mOutput << startstr << "}" << endstr << endstr;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void XFileExporter::writePath(aiString path)
|
||||
{
|
||||
std::string str = std::string(path.C_Str());
|
||||
BaseImporter::ConvertUTF8toISO8859_1(str);
|
||||
|
||||
while( str.find( "\\\\") != std::string::npos)
|
||||
str.replace( str.find( "\\\\"), 2, "\\");
|
||||
|
||||
while( str.find( "\\") != std::string::npos)
|
||||
str.replace( str.find( "\\"), 1, "/");
|
||||
|
||||
mOutput << str;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
125
code/XFileExporter.h
Normal file
125
code/XFileExporter.h
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2012, 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.
|
||||
|
||||
@author: Richard Steffen, 2014
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file XFileExporter.h
|
||||
* Declares the exporter class to write a scene to a Collada file
|
||||
*/
|
||||
#ifndef AI_XFILEEXPORTER_H_INC
|
||||
#define AI_XFILEEXPORTER_H_INC
|
||||
|
||||
#include "../include/assimp/ai_assert.h"
|
||||
#include <sstream>
|
||||
|
||||
struct aiScene;
|
||||
struct aiNode;
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
|
||||
/// Helper class to export a given scene to a X-file.
|
||||
/// Note: an xFile uses a left hand system. Assimp used a right hand system (OpenGL), therefore we have to transform everything
|
||||
class XFileExporter
|
||||
{
|
||||
public:
|
||||
/// Constructor for a specific scene to export
|
||||
XFileExporter(const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file);
|
||||
|
||||
/// Destructor
|
||||
virtual ~XFileExporter();
|
||||
|
||||
protected:
|
||||
/// Starts writing the contents
|
||||
void WriteFile();
|
||||
|
||||
/// Writes the asset header
|
||||
void WriteHeader();
|
||||
|
||||
/// write a frame transform
|
||||
void WriteFrameTransform(aiMatrix4x4& m);
|
||||
|
||||
/// Recursively writes the given node
|
||||
void WriteNode( aiNode* pNode );
|
||||
|
||||
/// write a mesh entry of the scene
|
||||
void WriteMesh(const aiMesh* mesh);
|
||||
|
||||
/// Enters a new xml element, which increases the indentation
|
||||
void PushTag() { startstr.append( " "); }
|
||||
|
||||
/// Leaves an element, decreasing the indentation
|
||||
void PopTag() { ai_assert( startstr.length() > 1); startstr.erase( startstr.length() - 2); }
|
||||
|
||||
public:
|
||||
/// Stringstream to write all output into
|
||||
std::stringstream mOutput;
|
||||
|
||||
protected:
|
||||
|
||||
/// write a path
|
||||
void writePath(aiString path);
|
||||
|
||||
/// The IOSystem for output
|
||||
IOSystem* mIOSystem;
|
||||
|
||||
/// Path of the directory where the scene will be exported
|
||||
const std::string mPath;
|
||||
|
||||
/// Name of the file (without extension) where the scene will be exported
|
||||
const std::string mFile;
|
||||
|
||||
/// The scene to be written
|
||||
const aiScene* mScene;
|
||||
bool mSceneOwned;
|
||||
|
||||
/// current line start string, contains the current indentation for simple stream insertion
|
||||
std::string startstr;
|
||||
|
||||
/// current line end string for simple stream insertion
|
||||
std::string endstr;
|
||||
|
||||
protected:
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // !! AI_XFILEEXPORTER_H_INC
|
||||
729
code/pstdint.h
729
code/pstdint.h
@@ -1,729 +0,0 @@
|
||||
/* A portable stdint.h
|
||||
****************************************************************************
|
||||
* BSD License:
|
||||
****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2005-2007 Paul Hsieh
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||
*
|
||||
****************************************************************************
|
||||
*
|
||||
* Version 0.1.10
|
||||
*
|
||||
* The ANSI C standard committee, for the C99 standard, specified the
|
||||
* inclusion of a new standard include file called stdint.h. This is
|
||||
* a very useful and long desired include file which contains several
|
||||
* very precise definitions for integer scalar types that is
|
||||
* critically important for making portable several classes of
|
||||
* applications including cryptography, hashing, variable length
|
||||
* integer libraries and so on. But for most developers its likely
|
||||
* useful just for programming sanity.
|
||||
*
|
||||
* The problem is that most compiler vendors have decided not to
|
||||
* implement the C99 standard, and the next C++ language standard
|
||||
* (which has a lot more mindshare these days) will be a long time in
|
||||
* coming and its unknown whether or not it will include stdint.h or
|
||||
* how much adoption it will have. Either way, it will be a long time
|
||||
* before all compilers come with a stdint.h and it also does nothing
|
||||
* for the extremely large number of compilers available today which
|
||||
* do not include this file, or anything comparable to it.
|
||||
*
|
||||
* So that's what this file is all about. Its an attempt to build a
|
||||
* single universal include file that works on as many platforms as
|
||||
* possible to deliver what stdint.h is supposed to. A few things
|
||||
* that should be noted about this file:
|
||||
*
|
||||
* 1) It is not guaranteed to be portable and/or present an identical
|
||||
* interface on all platforms. The extreme variability of the
|
||||
* ANSI C standard makes this an impossibility right from the
|
||||
* very get go. Its really only meant to be useful for the vast
|
||||
* majority of platforms that possess the capability of
|
||||
* implementing usefully and precisely defined, standard sized
|
||||
* integer scalars. Systems which are not intrinsically 2s
|
||||
* complement may produce invalid constants.
|
||||
*
|
||||
* 2) There is an unavoidable use of non-reserved symbols.
|
||||
*
|
||||
* 3) Other standard include files are invoked.
|
||||
*
|
||||
* 4) This file may come in conflict with future platforms that do
|
||||
* include stdint.h. The hope is that one or the other can be
|
||||
* used with no real difference.
|
||||
*
|
||||
* 5) In the current verison, if your platform can't represent
|
||||
* int32_t, int16_t and int8_t, it just dumps out with a compiler
|
||||
* error.
|
||||
*
|
||||
* 6) 64 bit integers may or may not be defined. Test for their
|
||||
* presence with the test: #ifdef INT64_MAX or #ifdef UINT64_MAX.
|
||||
* Note that this is different from the C99 specification which
|
||||
* requires the existence of 64 bit support in the compiler. If
|
||||
* this is not defined for your platform, yet it is capable of
|
||||
* dealing with 64 bits then it is because this file has not yet
|
||||
* been extended to cover all of your system's capabilities.
|
||||
*
|
||||
* 7) (u)intptr_t may or may not be defined. Test for its presence
|
||||
* with the test: #ifdef PTRDIFF_MAX. If this is not defined
|
||||
* for your platform, then it is because this file has not yet
|
||||
* been extended to cover all of your system's capabilities, not
|
||||
* because its optional.
|
||||
*
|
||||
* 8) The following might not been defined even if your platform is
|
||||
* capable of defining it:
|
||||
*
|
||||
* WCHAR_MIN
|
||||
* WCHAR_MAX
|
||||
* (u)int64_t
|
||||
* PTRDIFF_MIN
|
||||
* PTRDIFF_MAX
|
||||
* (u)intptr_t
|
||||
*
|
||||
* 9) The following have not been defined:
|
||||
*
|
||||
* WINT_MIN
|
||||
* WINT_MAX
|
||||
*
|
||||
* 10) The criteria for defining (u)int_least(*)_t isn't clear,
|
||||
* except for systems which don't have a type that precisely
|
||||
* defined 8, 16, or 32 bit types (which this include file does
|
||||
* not support anyways). Default definitions have been given.
|
||||
*
|
||||
* 11) The criteria for defining (u)int_fast(*)_t isn't something I
|
||||
* would trust to any particular compiler vendor or the ANSI C
|
||||
* committee. It is well known that "compatible systems" are
|
||||
* commonly created that have very different performance
|
||||
* characteristics from the systems they are compatible with,
|
||||
* especially those whose vendors make both the compiler and the
|
||||
* system. Default definitions have been given, but its strongly
|
||||
* recommended that users never use these definitions for any
|
||||
* reason (they do *NOT* deliver any serious guarantee of
|
||||
* improved performance -- not in this file, nor any vendor's
|
||||
* stdint.h).
|
||||
*
|
||||
* 12) The following macros:
|
||||
*
|
||||
* PRINTF_INTMAX_MODIFIER
|
||||
* PRINTF_INT64_MODIFIER
|
||||
* PRINTF_INT32_MODIFIER
|
||||
* PRINTF_INT16_MODIFIER
|
||||
* PRINTF_LEAST64_MODIFIER
|
||||
* PRINTF_LEAST32_MODIFIER
|
||||
* PRINTF_LEAST16_MODIFIER
|
||||
* PRINTF_INTPTR_MODIFIER
|
||||
*
|
||||
* are strings which have been defined as the modifiers required
|
||||
* for the "d", "u" and "x" printf formats to correctly output
|
||||
* (u)intmax_t, (u)int64_t, (u)int32_t, (u)int16_t, (u)least64_t,
|
||||
* (u)least32_t, (u)least16_t and (u)intptr_t types respectively.
|
||||
* PRINTF_INTPTR_MODIFIER is not defined for some systems which
|
||||
* provide their own stdint.h. PRINTF_INT64_MODIFIER is not
|
||||
* defined if INT64_MAX is not defined. These are an extension
|
||||
* beyond what C99 specifies must be in stdint.h.
|
||||
*
|
||||
* In addition, the following macros are defined:
|
||||
*
|
||||
* PRINTF_INTMAX_HEX_WIDTH
|
||||
* PRINTF_INT64_HEX_WIDTH
|
||||
* PRINTF_INT32_HEX_WIDTH
|
||||
* PRINTF_INT16_HEX_WIDTH
|
||||
* PRINTF_INT8_HEX_WIDTH
|
||||
* PRINTF_INTMAX_DEC_WIDTH
|
||||
* PRINTF_INT64_DEC_WIDTH
|
||||
* PRINTF_INT32_DEC_WIDTH
|
||||
* PRINTF_INT16_DEC_WIDTH
|
||||
* PRINTF_INT8_DEC_WIDTH
|
||||
*
|
||||
* Which specifies the maximum number of characters required to
|
||||
* print the number of that type in either hexadecimal or decimal.
|
||||
* These are an extension beyond what C99 specifies must be in
|
||||
* stdint.h.
|
||||
*
|
||||
* Compilers tested (all with 0 warnings at their highest respective
|
||||
* settings): Borland Turbo C 2.0, WATCOM C/C++ 11.0 (16 bits and 32
|
||||
* bits), Microsoft Visual C++ 6.0 (32 bit), Microsoft Visual Studio
|
||||
* .net (VC7), Intel C++ 4.0, GNU gcc v3.3.3
|
||||
*
|
||||
* This file should be considered a work in progress. Suggestions for
|
||||
* improvements, especially those which increase coverage are strongly
|
||||
* encouraged.
|
||||
*
|
||||
* Acknowledgements
|
||||
*
|
||||
* The following people have made significant contributions to the
|
||||
* development and testing of this file:
|
||||
*
|
||||
* Chris Howie
|
||||
* John Steele Scott
|
||||
* Dave Thorup
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
|
||||
/*
|
||||
* For gcc with _STDINT_H, fill in the PRINTF_INT*_MODIFIER macros, and
|
||||
* do nothing else. On the Mac OS X version of gcc this is _STDINT_H_.
|
||||
*/
|
||||
|
||||
#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined (__WATCOMC__) && (defined (_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)))) && !defined (_PSTDINT_H_INCLUDED) && !defined(_STDINT)
|
||||
#include <stdint.h>
|
||||
#define _PSTDINT_H_INCLUDED
|
||||
# ifndef PRINTF_INT64_MODIFIER
|
||||
# define PRINTF_INT64_MODIFIER "ll"
|
||||
# endif
|
||||
# ifndef PRINTF_INT32_MODIFIER
|
||||
# define PRINTF_INT32_MODIFIER "l"
|
||||
# endif
|
||||
# ifndef PRINTF_INT16_MODIFIER
|
||||
# define PRINTF_INT16_MODIFIER "h"
|
||||
# endif
|
||||
# ifndef PRINTF_INTMAX_MODIFIER
|
||||
# define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER
|
||||
# endif
|
||||
# ifndef PRINTF_INT64_HEX_WIDTH
|
||||
# define PRINTF_INT64_HEX_WIDTH "16"
|
||||
# endif
|
||||
# ifndef PRINTF_INT32_HEX_WIDTH
|
||||
# define PRINTF_INT32_HEX_WIDTH "8"
|
||||
# endif
|
||||
# ifndef PRINTF_INT16_HEX_WIDTH
|
||||
# define PRINTF_INT16_HEX_WIDTH "4"
|
||||
# endif
|
||||
# ifndef PRINTF_INT8_HEX_WIDTH
|
||||
# define PRINTF_INT8_HEX_WIDTH "2"
|
||||
# endif
|
||||
# ifndef PRINTF_INT64_DEC_WIDTH
|
||||
# define PRINTF_INT64_DEC_WIDTH "20"
|
||||
# endif
|
||||
# ifndef PRINTF_INT32_DEC_WIDTH
|
||||
# define PRINTF_INT32_DEC_WIDTH "10"
|
||||
# endif
|
||||
# ifndef PRINTF_INT16_DEC_WIDTH
|
||||
# define PRINTF_INT16_DEC_WIDTH "5"
|
||||
# endif
|
||||
# ifndef PRINTF_INT8_DEC_WIDTH
|
||||
# define PRINTF_INT8_DEC_WIDTH "3"
|
||||
# endif
|
||||
# ifndef PRINTF_INTMAX_HEX_WIDTH
|
||||
# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH
|
||||
# endif
|
||||
# ifndef PRINTF_INTMAX_DEC_WIDTH
|
||||
# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH
|
||||
# endif
|
||||
|
||||
/*
|
||||
* Something really weird is going on with Open Watcom. Just pull some of
|
||||
* these duplicated definitions from Open Watcom's stdint.h file for now.
|
||||
*/
|
||||
|
||||
# if defined (__WATCOMC__) && __WATCOMC__ >= 1250
|
||||
# if !defined (INT64_C)
|
||||
# define INT64_C(x) (x + (INT64_MAX - INT64_MAX))
|
||||
# endif
|
||||
# if !defined (UINT64_C)
|
||||
# define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX))
|
||||
# endif
|
||||
# if !defined (INT32_C)
|
||||
# define INT32_C(x) (x + (INT32_MAX - INT32_MAX))
|
||||
# endif
|
||||
# if !defined (UINT32_C)
|
||||
# define UINT32_C(x) (x + (UINT32_MAX - UINT32_MAX))
|
||||
# endif
|
||||
# if !defined (INT16_C)
|
||||
# define INT16_C(x) (x)
|
||||
# endif
|
||||
# if !defined (UINT16_C)
|
||||
# define UINT16_C(x) (x)
|
||||
# endif
|
||||
# if !defined (INT8_C)
|
||||
# define INT8_C(x) (x)
|
||||
# endif
|
||||
# if !defined (UINT8_C)
|
||||
# define UINT8_C(x) (x)
|
||||
# endif
|
||||
# if !defined (UINT64_MAX)
|
||||
# define UINT64_MAX 18446744073709551615ULL
|
||||
# endif
|
||||
# if !defined (INT64_MAX)
|
||||
# define INT64_MAX 9223372036854775807LL
|
||||
# endif
|
||||
# if !defined (UINT32_MAX)
|
||||
# define UINT32_MAX 4294967295UL
|
||||
# endif
|
||||
# if !defined (INT32_MAX)
|
||||
# define INT32_MAX 2147483647L
|
||||
# endif
|
||||
# if !defined (INTMAX_MAX)
|
||||
# define INTMAX_MAX INT64_MAX
|
||||
# endif
|
||||
# if !defined (INTMAX_MIN)
|
||||
# define INTMAX_MIN INT64_MIN
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef _PSTDINT_H_INCLUDED
|
||||
#define _PSTDINT_H_INCLUDED
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
# define SIZE_MAX (~(size_t)0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Deduce the type assignments from limits.h under the assumption that
|
||||
* integer sizes in bits are powers of 2, and follow the ANSI
|
||||
* definitions.
|
||||
*/
|
||||
|
||||
#ifndef UINT8_MAX
|
||||
# define UINT8_MAX 0xff
|
||||
#endif
|
||||
#ifndef uint8_t
|
||||
# if (UCHAR_MAX == UINT8_MAX) || defined (S_SPLINT_S)
|
||||
typedef unsigned char uint8_t;
|
||||
# define UINT8_C(v) ((uint8_t) v)
|
||||
# else
|
||||
# error "Platform not supported"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef INT8_MAX
|
||||
# define INT8_MAX 0x7f
|
||||
#endif
|
||||
#ifndef INT8_MIN
|
||||
# define INT8_MIN INT8_C(0x80)
|
||||
#endif
|
||||
#ifndef int8_t
|
||||
# if (SCHAR_MAX == INT8_MAX) || defined (S_SPLINT_S)
|
||||
typedef signed char int8_t;
|
||||
# define INT8_C(v) ((int8_t) v)
|
||||
# else
|
||||
# error "Platform not supported"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef UINT16_MAX
|
||||
# define UINT16_MAX 0xffff
|
||||
#endif
|
||||
#ifndef uint16_t
|
||||
#if (UINT_MAX == UINT16_MAX) || defined (S_SPLINT_S)
|
||||
typedef unsigned int uint16_t;
|
||||
# ifndef PRINTF_INT16_MODIFIER
|
||||
# define PRINTF_INT16_MODIFIER ""
|
||||
# endif
|
||||
# define UINT16_C(v) ((uint16_t) (v))
|
||||
#elif (USHRT_MAX == UINT16_MAX)
|
||||
typedef unsigned short uint16_t;
|
||||
# define UINT16_C(v) ((uint16_t) (v))
|
||||
# ifndef PRINTF_INT16_MODIFIER
|
||||
# define PRINTF_INT16_MODIFIER "h"
|
||||
# endif
|
||||
#else
|
||||
#error "Platform not supported"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef INT16_MAX
|
||||
# define INT16_MAX 0x7fff
|
||||
#endif
|
||||
#ifndef INT16_MIN
|
||||
# define INT16_MIN INT16_C(0x8000)
|
||||
#endif
|
||||
#ifndef int16_t
|
||||
#if (INT_MAX == INT16_MAX) || defined (S_SPLINT_S)
|
||||
typedef signed int int16_t;
|
||||
# define INT16_C(v) ((int16_t) (v))
|
||||
# ifndef PRINTF_INT16_MODIFIER
|
||||
# define PRINTF_INT16_MODIFIER ""
|
||||
# endif
|
||||
#elif (SHRT_MAX == INT16_MAX)
|
||||
typedef signed short int16_t;
|
||||
# define INT16_C(v) ((int16_t) (v))
|
||||
# ifndef PRINTF_INT16_MODIFIER
|
||||
# define PRINTF_INT16_MODIFIER "h"
|
||||
# endif
|
||||
#else
|
||||
#error "Platform not supported"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef UINT32_MAX
|
||||
# define UINT32_MAX (0xffffffffUL)
|
||||
#endif
|
||||
#ifndef uint32_t
|
||||
#if (ULONG_MAX == UINT32_MAX) || defined (S_SPLINT_S)
|
||||
typedef unsigned long uint32_t;
|
||||
# define UINT32_C(v) v ## UL
|
||||
# ifndef PRINTF_INT32_MODIFIER
|
||||
# define PRINTF_INT32_MODIFIER "l"
|
||||
# endif
|
||||
#elif (UINT_MAX == UINT32_MAX)
|
||||
typedef unsigned int uint32_t;
|
||||
# ifndef PRINTF_INT32_MODIFIER
|
||||
# define PRINTF_INT32_MODIFIER ""
|
||||
# endif
|
||||
# define UINT32_C(v) v ## U
|
||||
#elif (USHRT_MAX == UINT32_MAX)
|
||||
typedef unsigned short uint32_t;
|
||||
# define UINT32_C(v) ((unsigned short) (v))
|
||||
# ifndef PRINTF_INT32_MODIFIER
|
||||
# define PRINTF_INT32_MODIFIER ""
|
||||
# endif
|
||||
#else
|
||||
#error "Platform not supported"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef INT32_MAX
|
||||
# define INT32_MAX (0x7fffffffL)
|
||||
#endif
|
||||
#ifndef INT32_MIN
|
||||
# define INT32_MIN INT32_C(0x80000000)
|
||||
#endif
|
||||
#ifndef int32_t
|
||||
#if (LONG_MAX == INT32_MAX) || defined (S_SPLINT_S)
|
||||
typedef signed long int32_t;
|
||||
# define INT32_C(v) v ## L
|
||||
# ifndef PRINTF_INT32_MODIFIER
|
||||
# define PRINTF_INT32_MODIFIER "l"
|
||||
# endif
|
||||
#elif (INT_MAX == INT32_MAX)
|
||||
typedef signed int int32_t;
|
||||
# define INT32_C(v) v
|
||||
# ifndef PRINTF_INT32_MODIFIER
|
||||
# define PRINTF_INT32_MODIFIER ""
|
||||
# endif
|
||||
#elif (SHRT_MAX == INT32_MAX)
|
||||
typedef signed short int32_t;
|
||||
# define INT32_C(v) ((short) (v))
|
||||
# ifndef PRINTF_INT32_MODIFIER
|
||||
# define PRINTF_INT32_MODIFIER ""
|
||||
# endif
|
||||
#else
|
||||
#error "Platform not supported"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The macro stdint_int64_defined is temporarily used to record
|
||||
* whether or not 64 integer support is available. It must be
|
||||
* defined for any 64 integer extensions for new platforms that are
|
||||
* added.
|
||||
*/
|
||||
|
||||
#undef stdint_int64_defined
|
||||
#if (defined(__STDC__) && defined(__STDC_VERSION__)) || defined (S_SPLINT_S)
|
||||
# if (__STDC__ && __STDC_VERSION >= 199901L) || defined (S_SPLINT_S)
|
||||
# define stdint_int64_defined
|
||||
typedef long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
# define UINT64_C(v) v ## ULL
|
||||
# define INT64_C(v) v ## LL
|
||||
# ifndef PRINTF_INT64_MODIFIER
|
||||
# define PRINTF_INT64_MODIFIER "ll"
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined (stdint_int64_defined)
|
||||
# if defined(__GNUC__)
|
||||
# define stdint_int64_defined
|
||||
__extension__ typedef long long int64_t;
|
||||
__extension__ typedef unsigned long long uint64_t;
|
||||
# define UINT64_C(v) v ## ULL
|
||||
# define INT64_C(v) v ## LL
|
||||
# ifndef PRINTF_INT64_MODIFIER
|
||||
# define PRINTF_INT64_MODIFIER "ll"
|
||||
# endif
|
||||
# elif defined(__MWERKS__) || defined (__SUNPRO_C) || defined (__SUNPRO_CC) || defined (__APPLE_CC__) || defined (_LONG_LONG) || defined (_CRAYC) || defined (S_SPLINT_S)
|
||||
# define stdint_int64_defined
|
||||
typedef long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
# define UINT64_C(v) v ## ULL
|
||||
# define INT64_C(v) v ## LL
|
||||
# ifndef PRINTF_INT64_MODIFIER
|
||||
# define PRINTF_INT64_MODIFIER "ll"
|
||||
# endif
|
||||
# elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined (__BORLANDC__) && __BORLANDC__ > 0x460) || defined (__alpha) || defined (__DECC)
|
||||
# define stdint_int64_defined
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
# define UINT64_C(v) v ## UI64
|
||||
# define INT64_C(v) v ## I64
|
||||
# ifndef PRINTF_INT64_MODIFIER
|
||||
# define PRINTF_INT64_MODIFIER "I64"
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined (LONG_LONG_MAX) && defined (INT64_C)
|
||||
# define LONG_LONG_MAX INT64_C (9223372036854775807)
|
||||
#endif
|
||||
#ifndef ULONG_LONG_MAX
|
||||
# define ULONG_LONG_MAX UINT64_C (18446744073709551615)
|
||||
#endif
|
||||
|
||||
#if !defined (INT64_MAX) && defined (INT64_C)
|
||||
# define INT64_MAX INT64_C (9223372036854775807)
|
||||
#endif
|
||||
#if !defined (INT64_MIN) && defined (INT64_C)
|
||||
# define INT64_MIN INT64_C (-9223372036854775808)
|
||||
#endif
|
||||
#if !defined (UINT64_MAX) && defined (INT64_C)
|
||||
# define UINT64_MAX UINT64_C (18446744073709551615)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Width of hexadecimal for number field.
|
||||
*/
|
||||
|
||||
#ifndef PRINTF_INT64_HEX_WIDTH
|
||||
# define PRINTF_INT64_HEX_WIDTH "16"
|
||||
#endif
|
||||
#ifndef PRINTF_INT32_HEX_WIDTH
|
||||
# define PRINTF_INT32_HEX_WIDTH "8"
|
||||
#endif
|
||||
#ifndef PRINTF_INT16_HEX_WIDTH
|
||||
# define PRINTF_INT16_HEX_WIDTH "4"
|
||||
#endif
|
||||
#ifndef PRINTF_INT8_HEX_WIDTH
|
||||
# define PRINTF_INT8_HEX_WIDTH "2"
|
||||
#endif
|
||||
|
||||
#ifndef PRINTF_INT64_DEC_WIDTH
|
||||
# define PRINTF_INT64_DEC_WIDTH "20"
|
||||
#endif
|
||||
#ifndef PRINTF_INT32_DEC_WIDTH
|
||||
# define PRINTF_INT32_DEC_WIDTH "10"
|
||||
#endif
|
||||
#ifndef PRINTF_INT16_DEC_WIDTH
|
||||
# define PRINTF_INT16_DEC_WIDTH "5"
|
||||
#endif
|
||||
#ifndef PRINTF_INT8_DEC_WIDTH
|
||||
# define PRINTF_INT8_DEC_WIDTH "3"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Ok, lets not worry about 128 bit integers for now. Moore's law says
|
||||
* we don't need to worry about that until about 2040 at which point
|
||||
* we'll have bigger things to worry about.
|
||||
*/
|
||||
|
||||
#ifdef stdint_int64_defined
|
||||
typedef int64_t intmax_t;
|
||||
typedef uint64_t uintmax_t;
|
||||
# define INTMAX_MAX INT64_MAX
|
||||
# define INTMAX_MIN INT64_MIN
|
||||
# define UINTMAX_MAX UINT64_MAX
|
||||
# define UINTMAX_C(v) UINT64_C(v)
|
||||
# define INTMAX_C(v) INT64_C(v)
|
||||
# ifndef PRINTF_INTMAX_MODIFIER
|
||||
# define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER
|
||||
# endif
|
||||
# ifndef PRINTF_INTMAX_HEX_WIDTH
|
||||
# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH
|
||||
# endif
|
||||
# ifndef PRINTF_INTMAX_DEC_WIDTH
|
||||
# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH
|
||||
# endif
|
||||
#else
|
||||
typedef int32_t intmax_t;
|
||||
typedef uint32_t uintmax_t;
|
||||
# define INTMAX_MAX INT32_MAX
|
||||
# define UINTMAX_MAX UINT32_MAX
|
||||
# define UINTMAX_C(v) UINT32_C(v)
|
||||
# define INTMAX_C(v) INT32_C(v)
|
||||
# ifndef PRINTF_INTMAX_MODIFIER
|
||||
# define PRINTF_INTMAX_MODIFIER PRINTF_INT32_MODIFIER
|
||||
# endif
|
||||
# ifndef PRINTF_INTMAX_HEX_WIDTH
|
||||
# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT32_HEX_WIDTH
|
||||
# endif
|
||||
# ifndef PRINTF_INTMAX_DEC_WIDTH
|
||||
# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT32_DEC_WIDTH
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Because this file currently only supports platforms which have
|
||||
* precise powers of 2 as bit sizes for the default integers, the
|
||||
* least definitions are all trivial. Its possible that a future
|
||||
* version of this file could have different definitions.
|
||||
*/
|
||||
|
||||
#ifndef stdint_least_defined
|
||||
typedef int8_t int_least8_t;
|
||||
typedef uint8_t uint_least8_t;
|
||||
typedef int16_t int_least16_t;
|
||||
typedef uint16_t uint_least16_t;
|
||||
typedef int32_t int_least32_t;
|
||||
typedef uint32_t uint_least32_t;
|
||||
# define PRINTF_LEAST32_MODIFIER PRINTF_INT32_MODIFIER
|
||||
# define PRINTF_LEAST16_MODIFIER PRINTF_INT16_MODIFIER
|
||||
# define UINT_LEAST8_MAX UINT8_MAX
|
||||
# define INT_LEAST8_MAX INT8_MAX
|
||||
# define UINT_LEAST16_MAX UINT16_MAX
|
||||
# define INT_LEAST16_MAX INT16_MAX
|
||||
# define UINT_LEAST32_MAX UINT32_MAX
|
||||
# define INT_LEAST32_MAX INT32_MAX
|
||||
# define INT_LEAST8_MIN INT8_MIN
|
||||
# define INT_LEAST16_MIN INT16_MIN
|
||||
# define INT_LEAST32_MIN INT32_MIN
|
||||
# ifdef stdint_int64_defined
|
||||
typedef int64_t int_least64_t;
|
||||
typedef uint64_t uint_least64_t;
|
||||
# define PRINTF_LEAST64_MODIFIER PRINTF_INT64_MODIFIER
|
||||
# define UINT_LEAST64_MAX UINT64_MAX
|
||||
# define INT_LEAST64_MAX INT64_MAX
|
||||
# define INT_LEAST64_MIN INT64_MIN
|
||||
# endif
|
||||
#endif
|
||||
#undef stdint_least_defined
|
||||
|
||||
/*
|
||||
* The ANSI C committee pretending to know or specify anything about
|
||||
* performance is the epitome of misguided arrogance. The mandate of
|
||||
* this file is to *ONLY* ever support that absolute minimum
|
||||
* definition of the fast integer types, for compatibility purposes.
|
||||
* No extensions, and no attempt to suggest what may or may not be a
|
||||
* faster integer type will ever be made in this file. Developers are
|
||||
* warned to stay away from these types when using this or any other
|
||||
* stdint.h.
|
||||
*/
|
||||
|
||||
typedef int_least8_t int_fast8_t;
|
||||
typedef uint_least8_t uint_fast8_t;
|
||||
typedef int_least16_t int_fast16_t;
|
||||
typedef uint_least16_t uint_fast16_t;
|
||||
typedef int_least32_t int_fast32_t;
|
||||
typedef uint_least32_t uint_fast32_t;
|
||||
#define UINT_FAST8_MAX UINT_LEAST8_MAX
|
||||
#define INT_FAST8_MAX INT_LEAST8_MAX
|
||||
#define UINT_FAST16_MAX UINT_LEAST16_MAX
|
||||
#define INT_FAST16_MAX INT_LEAST16_MAX
|
||||
#define UINT_FAST32_MAX UINT_LEAST32_MAX
|
||||
#define INT_FAST32_MAX INT_LEAST32_MAX
|
||||
#define INT_FAST8_MIN INT_LEAST8_MIN
|
||||
#define INT_FAST16_MIN INT_LEAST16_MIN
|
||||
#define INT_FAST32_MIN INT_LEAST32_MIN
|
||||
#ifdef stdint_int64_defined
|
||||
typedef int_least64_t int_fast64_t;
|
||||
typedef uint_least64_t uint_fast64_t;
|
||||
# define UINT_FAST64_MAX UINT_LEAST64_MAX
|
||||
# define INT_FAST64_MAX INT_LEAST64_MAX
|
||||
# define INT_FAST64_MIN INT_LEAST64_MIN
|
||||
#endif
|
||||
|
||||
#undef stdint_int64_defined
|
||||
|
||||
/*
|
||||
* Whatever piecemeal, per compiler thing we can do about the wchar_t
|
||||
* type limits.
|
||||
*/
|
||||
|
||||
#if defined(__WATCOMC__) || defined(_MSC_VER) || defined (__GNUC__)
|
||||
# include <wchar.h>
|
||||
# ifndef WCHAR_MIN
|
||||
# define WCHAR_MIN 0
|
||||
# endif
|
||||
# ifndef WCHAR_MAX
|
||||
# define WCHAR_MAX ((wchar_t)-1)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Whatever piecemeal, per compiler/platform thing we can do about the
|
||||
* (u)intptr_t types and limits.
|
||||
*/
|
||||
|
||||
#if defined (_MSC_VER) && defined (_UINTPTR_T_DEFINED)
|
||||
# define STDINT_H_UINTPTR_T_DEFINED
|
||||
#endif
|
||||
|
||||
#ifndef STDINT_H_UINTPTR_T_DEFINED
|
||||
# if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) || defined (_WIN64)
|
||||
# define stdint_intptr_bits 64
|
||||
# elif defined (__WATCOMC__) || defined (__TURBOC__)
|
||||
# if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__)
|
||||
# define stdint_intptr_bits 16
|
||||
# else
|
||||
# define stdint_intptr_bits 32
|
||||
# endif
|
||||
# elif defined (__i386__) || defined (_WIN32) || defined (WIN32)
|
||||
# define stdint_intptr_bits 32
|
||||
# elif defined (__INTEL_COMPILER)
|
||||
/* TODO -- what will Intel do about x86-64? */
|
||||
# endif
|
||||
|
||||
# ifdef stdint_intptr_bits
|
||||
# define stdint_intptr_glue3_i(a,b,c) a##b##c
|
||||
# define stdint_intptr_glue3(a,b,c) stdint_intptr_glue3_i(a,b,c)
|
||||
# ifndef PRINTF_INTPTR_MODIFIER
|
||||
# define PRINTF_INTPTR_MODIFIER stdint_intptr_glue3(PRINTF_INT,stdint_intptr_bits,_MODIFIER)
|
||||
# endif
|
||||
# ifndef PTRDIFF_MAX
|
||||
# define PTRDIFF_MAX stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX)
|
||||
# endif
|
||||
# ifndef PTRDIFF_MIN
|
||||
# define PTRDIFF_MIN stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN)
|
||||
# endif
|
||||
# ifndef UINTPTR_MAX
|
||||
# define UINTPTR_MAX stdint_intptr_glue3(UINT,stdint_intptr_bits,_MAX)
|
||||
# endif
|
||||
# ifndef INTPTR_MAX
|
||||
# define INTPTR_MAX stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX)
|
||||
# endif
|
||||
# ifndef INTPTR_MIN
|
||||
# define INTPTR_MIN stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN)
|
||||
# endif
|
||||
# ifndef INTPTR_C
|
||||
# define INTPTR_C(x) stdint_intptr_glue3(INT,stdint_intptr_bits,_C)(x)
|
||||
# endif
|
||||
# ifndef UINTPTR_C
|
||||
# define UINTPTR_C(x) stdint_intptr_glue3(UINT,stdint_intptr_bits,_C)(x)
|
||||
# endif
|
||||
typedef stdint_intptr_glue3(uint,stdint_intptr_bits,_t) uintptr_t;
|
||||
typedef stdint_intptr_glue3( int,stdint_intptr_bits,_t) intptr_t;
|
||||
# else
|
||||
/* TODO -- This following is likely wrong for some platforms, and does
|
||||
nothing for the definition of uintptr_t. */
|
||||
typedef ptrdiff_t intptr_t;
|
||||
# endif
|
||||
# define STDINT_H_UINTPTR_T_DEFINED
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Assumes sig_atomic_t is signed and we have a 2s complement machine.
|
||||
*/
|
||||
|
||||
#ifndef SIG_ATOMIC_MAX
|
||||
# define SIG_ATOMIC_MAX ((((sig_atomic_t) 1) << (sizeof (sig_atomic_t)*CHAR_BIT-1)) - 1)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user