assimp/code/OgreImporter.cpp

255 lines
8.5 KiB
C++

/*
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.
----------------------------------------------------------------------
*/
/** @file OgreImporter.cpp
* @brief Implementation of the Ogre XML (.mesh.xml) loader.
*/
#include "AssimpPCH.h"
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
#include <vector>
#include <sstream>
#include "OgreImporter.hpp"
#include "TinyFormatter.h"
#include "irrXMLWrapper.h"
static const aiImporterDesc desc = {
"Ogre XML Mesh Importer",
"",
"",
"",
aiImporterFlags_SupportTextFlavour,
0,
0,
0,
0,
"mesh.xml"
};
using namespace std;
namespace Assimp
{
namespace Ogre
{
bool OgreImporter::CanRead(const std::string &pFile, Assimp::IOSystem *pIOHandler, bool checkSig) const
{
if (!checkSig)
{
string ext = "mesh.xml";
int len = ext.length();
return (ASSIMP_stricmp(pFile.substr(pFile.length()-len, len), ext) == 0);
}
const char* tokens[] = {"<mesh>"};
return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
}
void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Assimp::IOSystem *pIOHandler)
{
m_CurrentFilename = pFile;
m_CurrentIOHandler = pIOHandler;
m_CurrentScene = pScene;
// -------------------- Initial file and XML operations --------------------
// Open
boost::scoped_ptr<IOStream> file(pIOHandler->Open(pFile));
if (file.get() == NULL)
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, "mesh"))
throw DeadlyImportError("Root node is not <mesh> but <" + string(reader->getNodeName()) + ">");
// 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, nnSharedGeometry))
{
DefaultLogger::get()->debug("Reading shared geometry");
unsigned int NumVertices = GetAttribute<unsigned int>(reader.get(), "vertexcount");
NextNode(reader.get());
while(CurrentNodeNameEquals(reader, nnVertexBuffer))
ReadVertexBuffer(m_SharedGeometry, reader.get(), NumVertices);
}
// -------------------- Sub Meshes --------------------
if (!CurrentNodeNameEquals(reader, nnSubMeshes))
throw DeadlyImportError("Could not find <submeshes> node inside root <mesh> node");
list<boost::shared_ptr<SubMesh> > subMeshes;
vector<aiMaterial*> materials;
NextNode(reader.get());
while(CurrentNodeNameEquals(reader, 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 = LoadMaterial(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, nnSubMeshNames))
{
NextNode(reader.get());
while(CurrentNodeNameEquals(reader, nnSubMesh))
NextNode(reader.get());
}
// -------------------- Skeleton --------------------
vector<Bone> Bones;
vector<Animation> Animations;
if (CurrentNodeNameEquals(reader, nnSkeletonLink))
{
string SkeletonFile = GetAttribute<string>(reader.get(), "name");
if (!SkeletonFile.empty())
LoadSkeleton(SkeletonFile, Bones, Animations);
else
DefaultLogger::get()->debug("Found a unusual <" + nnSkeletonLink + "> with a empty reference");
NextNode(reader.get());
}
else
DefaultLogger::get()->debug("Mesh has no assigned skeleton with <" + nnSkeletonLink + ">");
// Now there might be <boneassignments> for the shared geometry
if (CurrentNodeNameEquals(reader, "boneassignments"))
ReadBoneWeights(m_SharedGeometry, reader.get());
// -------------------- Process Results --------------------
BOOST_FOREACH(boost::shared_ptr<SubMesh> theSubMesh, subMeshes)
{
ProcessSubMesh(*theSubMesh, m_SharedGeometry);
}
// -------------------- Apply to aiScene --------------------
//put the aiMaterials in the scene:
m_CurrentScene->mMaterials=new aiMaterial*[materials.size()];
m_CurrentScene->mNumMaterials=materials.size();
for(unsigned int i=0; i<materials.size(); ++i)
m_CurrentScene->mMaterials[i]=materials[i];
//create the aiMehs...
vector<aiMesh*> aiMeshes;
BOOST_FOREACH(boost::shared_ptr<SubMesh> theSubMesh, subMeshes)
{
aiMeshes.push_back(CreateAssimpSubMesh(*theSubMesh, Bones));
}
//... and put them in the scene:
m_CurrentScene->mNumMeshes=aiMeshes.size();
m_CurrentScene->mMeshes=new aiMesh*[aiMeshes.size()];
memcpy(m_CurrentScene->mMeshes, &(aiMeshes[0]), sizeof(aiMeshes[0])*aiMeshes.size());
//Create the root node
m_CurrentScene->mRootNode=new aiNode("root");
//link the meshs with the root node:
m_CurrentScene->mRootNode->mMeshes=new unsigned int[subMeshes.size()];
m_CurrentScene->mRootNode->mNumMeshes=subMeshes.size();
for(unsigned int i=0; i<subMeshes.size(); ++i)
m_CurrentScene->mRootNode->mMeshes[i]=i;
CreateAssimpSkeleton(Bones, Animations);
PutAnimationsInScene(Bones, Animations);
}
const aiImporterDesc* OgreImporter::GetInfo () const
{
return &desc;
}
void OgreImporter::SetupProperties(const Importer* pImp)
{
m_MaterialLibFilename=pImp->GetPropertyString(AI_CONFIG_IMPORT_OGRE_MATERIAL_FILE, "Scene.material");
m_TextureTypeFromFilename=pImp->GetPropertyBool(AI_CONFIG_IMPORT_OGRE_TEXTURETYPE_FROM_FILENAME, false);
}
}//namespace Ogre
}//namespace Assimp
#endif // !! ASSIMP_BUILD_NO_OGRE_IMPORTER