IrrXml: replaced irrXml by pugixml.
parent
d48b93cf34
commit
a905303764
|
@ -58,8 +58,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
// Header files, stdlib.
|
||||
#include <memory>
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
namespace Assimp {
|
||||
|
||||
/// \var aiImporterDesc AMFImporter::Description
|
||||
/// Conastant which hold importer description
|
||||
|
@ -76,24 +75,26 @@ const aiImporterDesc AMFImporter::Description = {
|
|||
"amf"
|
||||
};
|
||||
|
||||
void AMFImporter::Clear()
|
||||
{
|
||||
void AMFImporter::Clear() {
|
||||
mNodeElement_Cur = nullptr;
|
||||
mUnit.clear();
|
||||
mMaterial_Converted.clear();
|
||||
mTexture_Converted.clear();
|
||||
// Delete all elements
|
||||
if(!mNodeElement_List.empty())
|
||||
{
|
||||
for(CAMFImporter_NodeElement* ne: mNodeElement_List) { delete ne; }
|
||||
if(!mNodeElement_List.empty()) {
|
||||
for(CAMFImporter_NodeElement* ne: mNodeElement_List) {
|
||||
delete ne;
|
||||
}
|
||||
|
||||
mNodeElement_List.clear();
|
||||
}
|
||||
}
|
||||
|
||||
AMFImporter::~AMFImporter()
|
||||
{
|
||||
if(mReader != nullptr) delete mReader;
|
||||
AMFImporter::~AMFImporter() {
|
||||
if (mReader != nullptr) {
|
||||
delete mReader;
|
||||
}
|
||||
|
||||
// Clear() is accounting if data already is deleted. So, just check again if all data is deleted.
|
||||
Clear();
|
||||
}
|
||||
|
@ -117,15 +118,14 @@ bool AMFImporter::Find_NodeElement(const std::string& pID, const CAMFImporter_No
|
|||
return false;
|
||||
}
|
||||
|
||||
bool AMFImporter::Find_ConvertedNode(const std::string& pID, std::list<aiNode*>& pNodeList, aiNode** pNode) const
|
||||
{
|
||||
aiString node_name(pID.c_str());
|
||||
bool AMFImporter::Find_ConvertedNode(const std::string& id, std::list<aiNode*>& nodeList, aiNode** pNode) const {
|
||||
aiString node_name(id.c_str());
|
||||
|
||||
for(aiNode* node: pNodeList)
|
||||
{
|
||||
if(node->mName == node_name)
|
||||
{
|
||||
if(pNode != nullptr) *pNode = node;
|
||||
for(aiNode* node: nodeList) {
|
||||
if(node->mName == node_name) {
|
||||
if (pNode != nullptr) {
|
||||
*pNode = node;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -134,13 +134,12 @@ aiString node_name(pID.c_str());
|
|||
return false;
|
||||
}
|
||||
|
||||
bool AMFImporter::Find_ConvertedMaterial(const std::string& pID, const SPP_Material** pConvertedMaterial) const
|
||||
{
|
||||
for(const SPP_Material& mat: mMaterial_Converted)
|
||||
{
|
||||
if(mat.ID == pID)
|
||||
{
|
||||
if(pConvertedMaterial != nullptr) *pConvertedMaterial = &mat;
|
||||
bool AMFImporter::Find_ConvertedMaterial(const std::string& id, const SPP_Material** pConvertedMaterial) const {
|
||||
for(const SPP_Material& mat: mMaterial_Converted) {
|
||||
if(mat.ID == id) {
|
||||
if (pConvertedMaterial != nullptr) {
|
||||
*pConvertedMaterial = &mat;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -153,13 +152,11 @@ bool AMFImporter::Find_ConvertedMaterial(const std::string& pID, const SPP_Mater
|
|||
/************************************************************ Functions: throw set ***********************************************************/
|
||||
/*********************************************************************************************************************************************/
|
||||
|
||||
void AMFImporter::Throw_CloseNotFound(const std::string& pNode)
|
||||
{
|
||||
void AMFImporter::Throw_CloseNotFound(const std::string& pNode) {
|
||||
throw DeadlyImportError("Close tag for node <" + pNode + "> not found. Seems file is corrupt.");
|
||||
}
|
||||
|
||||
void AMFImporter::Throw_IncorrectAttr(const std::string& pAttrName)
|
||||
{
|
||||
void AMFImporter::Throw_IncorrectAttr(const std::string& pAttrName) {
|
||||
throw DeadlyImportError("Node <" + std::string(mReader->getNodeName()) + "> has incorrect attribute \"" + pAttrName + "\".");
|
||||
}
|
||||
|
||||
|
@ -234,11 +231,13 @@ casu_cres:
|
|||
}
|
||||
}
|
||||
|
||||
bool AMFImporter::XML_SearchNode(const std::string& pNodeName)
|
||||
{
|
||||
while(mReader->read())
|
||||
{
|
||||
if((mReader->getNodeType() == irr::io::EXN_ELEMENT) && XML_CheckNode_NameEqual(pNodeName)) return true;
|
||||
bool AMFImporter::XML_SearchNode(const std::string& pNodeName) {
|
||||
mReader->
|
||||
while(mReader->read()) {
|
||||
//if((mReader->getNodeType() == irr::io::EXN_ELEMENT) && XML_CheckNode_NameEqual(pNodeName)) return true;
|
||||
if ((mReader->getNodeType() == pugi::node_element) && XML_CheckNode_NameEqual(pNodeName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -403,16 +402,22 @@ void AMFImporter::ParseHelper_Decode_Base64(const std::string& pInputBase64, std
|
|||
|
||||
void AMFImporter::ParseFile(const std::string& pFile, IOSystem* pIOHandler)
|
||||
{
|
||||
irr::io::IrrXMLReader* OldReader = mReader;// store current XMLreader.
|
||||
// irr::io::IrrXMLReader* OldReader = mReader;// store current XMLreader.
|
||||
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
|
||||
|
||||
// Check whether we can read from the file
|
||||
if(file.get() == NULL) throw DeadlyImportError("Failed to open AMF file " + pFile + ".");
|
||||
|
||||
mReader = new XmlParser;
|
||||
if (!mReader->parse(file.get())) {
|
||||
throw DeadlyImportError("Failed to create XML reader for file" + pFile + ".");
|
||||
}
|
||||
|
||||
// generate a XML reader for it
|
||||
std::unique_ptr<CIrrXML_IOStreamReader> mIOWrapper(new CIrrXML_IOStreamReader(file.get()));
|
||||
mReader = irr::io::createIrrXMLReader(mIOWrapper.get());
|
||||
if(!mReader) throw DeadlyImportError("Failed to create XML reader for file" + pFile + ".");
|
||||
//std::unique_ptr<CIrrXML_IOStreamReader> mIOWrapper(new CIrrXML_IOStreamReader(file.get()));
|
||||
//mReader = irr::io::createIrrXMLReader(mIOWrapper.get());
|
||||
//if(!mReader) throw DeadlyImportError("Failed to create XML reader for file" + pFile + ".");
|
||||
|
||||
//
|
||||
// start reading
|
||||
// search for root tag <amf>
|
||||
|
|
|
@ -58,7 +58,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <assimp/importerdesc.h>
|
||||
#include "assimp/types.h"
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <assimp/irrXMLWrapper.h>
|
||||
#include <assimp/XmlParser.h>
|
||||
|
||||
// Header files, stdlib.
|
||||
#include <set>
|
||||
|
@ -285,7 +285,10 @@ private:
|
|||
/// Check if current node name is equal to pNodeName.
|
||||
/// \param [in] pNodeName - name for checking.
|
||||
/// return true if current node name is equal to pNodeName, else - false.
|
||||
bool XML_CheckNode_NameEqual(const std::string& pNodeName) { return mReader->getNodeName() == pNodeName; }
|
||||
bool XML_CheckNode_NameEqual(const std::string& pNodeName){
|
||||
// return mReader->getNodeName() == pNodeName;
|
||||
mReader->mDoc.
|
||||
}
|
||||
|
||||
/// Skip unsupported node and report about that. Depend on node name can be skipped begin tag of node all whole node.
|
||||
/// \param [in] pParentNodeName - parent node name. Used for reporting.
|
||||
|
@ -420,7 +423,8 @@ private:
|
|||
|
||||
CAMFImporter_NodeElement* mNodeElement_Cur;///< Current element.
|
||||
std::list<CAMFImporter_NodeElement*> mNodeElement_List;///< All elements of scene graph.
|
||||
irr::io::IrrXMLReader* mReader;///< Pointer to XML-reader object
|
||||
XmlParser *mReader;
|
||||
//irr::io::IrrXMLReader* mReader;///< Pointer to XML-reader object
|
||||
std::string mUnit;
|
||||
std::list<SPP_Material> mMaterial_Converted;///< List of converted materials for postprocessing step.
|
||||
std::list<SPP_Texture> mTexture_Converted;///< List of converted textures for postprocessing step.
|
||||
|
|
|
@ -135,7 +135,7 @@ SET( PUBLIC_HEADERS
|
|||
${HEADER_PATH}/XMLTools.h
|
||||
${HEADER_PATH}/IOStreamBuffer.h
|
||||
${HEADER_PATH}/CreateAnimMesh.h
|
||||
${HEADER_PATH}/irrXMLWrapper.h
|
||||
${HEADER_PATH}/XmlParser.h
|
||||
${HEADER_PATH}/BlobIOSystem.h
|
||||
${HEADER_PATH}/MathFunctions.h
|
||||
${HEADER_PATH}/Exceptional.h
|
||||
|
@ -703,8 +703,8 @@ SET( PostProcessing_SRCS
|
|||
)
|
||||
SOURCE_GROUP( PostProcessing FILES ${PostProcessing_SRCS})
|
||||
|
||||
SET( IrrXML_SRCS ${HEADER_PATH}/irrXMLWrapper.h )
|
||||
SOURCE_GROUP( IrrXML FILES ${IrrXML_SRCS})
|
||||
#SET( IrrXML_SRCS ${HEADER_PATH}/irrXMLWrapper.h )
|
||||
#SOURCE_GROUP( IrrXML FILES ${IrrXML_SRCS})
|
||||
|
||||
ADD_ASSIMP_IMPORTER( Q3D
|
||||
Q3D/Q3DLoader.cpp
|
||||
|
@ -1105,7 +1105,7 @@ SET( assimp_src
|
|||
${ASSIMP_EXPORTER_SRCS}
|
||||
|
||||
# Third-party libraries
|
||||
${IrrXML_SRCS}
|
||||
#${IrrXML_SRCS}
|
||||
${unzip_compile_SRCS}
|
||||
${Poly2Tri_SRCS}
|
||||
${Clipper_SRCS}
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
#ifndef AI_COLLADAPARSER_H_INC
|
||||
#define AI_COLLADAPARSER_H_INC
|
||||
|
||||
#include <assimp/irrXMLWrapper.h>
|
||||
#include <assimp/XmlParser.h>
|
||||
#include "ColladaHelper.h"
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <assimp/TinyFormatter.h>
|
||||
|
|
|
@ -45,32 +45,28 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* @brief Implementation of the Irr importer class
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_IRR_IMPORTER
|
||||
|
||||
#include "Irr/IRRLoader.h"
|
||||
#include "Common/Importer.h"
|
||||
|
||||
#include <assimp/ParsingUtils.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/GenericProperty.h>
|
||||
#include <assimp/MathFunctions.h>
|
||||
#include <assimp/ParsingUtils.h>
|
||||
#include <assimp/SceneCombiner.h>
|
||||
#include <assimp/StandardShapes.h>
|
||||
#include <assimp/MathFunctions.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/mesh.h>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/mesh.h>
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
using namespace Assimp;
|
||||
using namespace irr;
|
||||
using namespace irr::io;
|
||||
|
||||
static const aiImporterDesc desc = {
|
||||
"Irrlicht Scene Reader",
|
||||
|
@ -87,9 +83,8 @@ static const aiImporterDesc desc = {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
IRRImporter::IRRImporter()
|
||||
: fps()
|
||||
, configSpeedFlag(){
|
||||
IRRImporter::IRRImporter() :
|
||||
fps(), configSpeedFlag() {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -121,14 +116,12 @@ bool IRRImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiImporterDesc* IRRImporter::GetInfo () const
|
||||
{
|
||||
const aiImporterDesc *IRRImporter::GetInfo() const {
|
||||
return &desc;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void IRRImporter::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
void IRRImporter::SetupProperties(const Importer *pImp) {
|
||||
// read the output frame rate of all node animation channels
|
||||
fps = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_IRR_ANIM_FPS, 100);
|
||||
if (fps < 10.) {
|
||||
|
@ -145,8 +138,7 @@ void IRRImporter::SetupProperties(const Importer* pImp)
|
|||
aiMesh *IRRImporter::BuildSingleQuadMesh(const SkyboxVertex &v1,
|
||||
const SkyboxVertex &v2,
|
||||
const SkyboxVertex &v3,
|
||||
const SkyboxVertex& v4)
|
||||
{
|
||||
const SkyboxVertex &v4) {
|
||||
// allocate and prepare the mesh
|
||||
aiMesh *out = new aiMesh();
|
||||
|
||||
|
@ -188,8 +180,7 @@ aiMesh* IRRImporter::BuildSingleQuadMesh(const SkyboxVertex& v1,
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void IRRImporter::BuildSkybox(std::vector<aiMesh*>& meshes, std::vector<aiMaterial*> materials)
|
||||
{
|
||||
void IRRImporter::BuildSkybox(std::vector<aiMesh *> &meshes, std::vector<aiMaterial *> materials) {
|
||||
// Update the material of the skybox - replace the name and disable shading for skyboxes.
|
||||
for (unsigned int i = 0; i < 6; ++i) {
|
||||
aiMaterial *out = (aiMaterial *)(*(materials.end() - (6 - i)));
|
||||
|
@ -261,12 +252,10 @@ void IRRImporter::BuildSkybox(std::vector<aiMesh*>& meshes, std::vector<aiMateri
|
|||
void IRRImporter::CopyMaterial(std::vector<aiMaterial *> &materials,
|
||||
std::vector<std::pair<aiMaterial *, unsigned int>> &inmaterials,
|
||||
unsigned int &defMatIdx,
|
||||
aiMesh* mesh)
|
||||
{
|
||||
aiMesh *mesh) {
|
||||
if (inmaterials.empty()) {
|
||||
// Do we have a default material? If not we need to create one
|
||||
if (UINT_MAX == defMatIdx)
|
||||
{
|
||||
if (UINT_MAX == defMatIdx) {
|
||||
defMatIdx = (unsigned int)materials.size();
|
||||
//TODO: add this materials to someone?
|
||||
/*aiMaterial* mat = new aiMaterial();
|
||||
|
@ -280,8 +269,7 @@ void IRRImporter::CopyMaterial(std::vector<aiMaterial*>& materials,
|
|||
}
|
||||
mesh->mMaterialIndex = defMatIdx;
|
||||
return;
|
||||
}
|
||||
else if (inmaterials.size() > 1) {
|
||||
} else if (inmaterials.size() > 1) {
|
||||
ASSIMP_LOG_INFO("IRR: Skipping additional materials");
|
||||
}
|
||||
|
||||
|
@ -289,25 +277,25 @@ void IRRImporter::CopyMaterial(std::vector<aiMaterial*>& materials,
|
|||
materials.push_back(inmaterials[0].first);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
inline
|
||||
int ClampSpline(int idx, int size) {
|
||||
inline int ClampSpline(int idx, int size) {
|
||||
return (idx < 0 ? size + idx : (idx >= size ? idx - size : idx));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
inline void FindSuitableMultiple(int& angle)
|
||||
{
|
||||
if (angle < 3) angle = 3;
|
||||
else if (angle < 10) angle = 10;
|
||||
else if (angle < 20) angle = 20;
|
||||
else if (angle < 30) angle = 30;
|
||||
inline void FindSuitableMultiple(int &angle) {
|
||||
if (angle < 3)
|
||||
angle = 3;
|
||||
else if (angle < 10)
|
||||
angle = 10;
|
||||
else if (angle < 20)
|
||||
angle = 20;
|
||||
else if (angle < 30)
|
||||
angle = 30;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNodeAnim*>& anims)
|
||||
{
|
||||
void IRRImporter::ComputeAnimations(Node *root, aiNode *real, std::vector<aiNodeAnim *> &anims) {
|
||||
ai_assert(nullptr != root && nullptr != real);
|
||||
|
||||
// XXX totally WIP - doesn't produce proper results, need to evaluate
|
||||
|
@ -337,8 +325,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
|
|||
|
||||
unsigned int cur = 0;
|
||||
for (std::list<Animator>::iterator it = root->animators.begin();
|
||||
it != root->animators.end(); ++it)
|
||||
{
|
||||
it != root->animators.end(); ++it) {
|
||||
if ((*it).type == Animator::UNKNOWN || (*it).type == Animator::OTHER) continue;
|
||||
|
||||
Animator &in = *it;
|
||||
|
@ -368,13 +355,12 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
|
|||
// the transformation matrix of the dummy node is the identity
|
||||
|
||||
real->mParent = dummy;
|
||||
}
|
||||
else anim->mNodeName.Set(root->name);
|
||||
} else
|
||||
anim->mNodeName.Set(root->name);
|
||||
++cur;
|
||||
|
||||
switch (in.type) {
|
||||
case Animator::ROTATION:
|
||||
{
|
||||
case Animator::ROTATION: {
|
||||
// -----------------------------------------------------
|
||||
// find out how long a full rotation will take
|
||||
// This is the least common multiple of 360.f and all
|
||||
|
@ -392,8 +378,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
|
|||
angles[1] %= 360;
|
||||
angles[2] %= 360;
|
||||
|
||||
if ( (angles[0]*angles[1]) != 0 && (angles[1]*angles[2]) != 0 )
|
||||
{
|
||||
if ((angles[0] * angles[1]) != 0 && (angles[1] * angles[2]) != 0) {
|
||||
FindSuitableMultiple(angles[0]);
|
||||
FindSuitableMultiple(angles[1]);
|
||||
FindSuitableMultiple(angles[2]);
|
||||
|
@ -436,8 +421,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
|
|||
|
||||
// begin with a zero angle
|
||||
aiVector3D angle;
|
||||
for (unsigned int i = 0; i < anim->mNumRotationKeys;++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) {
|
||||
// build the quaternion for the given euler angles
|
||||
aiQuatKey &q = anim->mRotationKeys[i];
|
||||
|
||||
|
@ -450,11 +434,9 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
|
|||
|
||||
// This animation is repeated and repeated ...
|
||||
anim->mPostState = anim->mPreState = aiAnimBehaviour_REPEAT;
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
case Animator::FLY_CIRCLE:
|
||||
{
|
||||
case Animator::FLY_CIRCLE: {
|
||||
// -----------------------------------------------------
|
||||
// Find out how much time we'll need to perform a
|
||||
// full circle.
|
||||
|
@ -469,8 +451,8 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
|
|||
aiVector3D vecU, vecV;
|
||||
if (in.direction.y) {
|
||||
vecV = aiVector3D(50, 0, 0) ^ in.direction;
|
||||
}
|
||||
else vecV = aiVector3D(0,50,00) ^ in.direction;
|
||||
} else
|
||||
vecV = aiVector3D(0, 50, 00) ^ in.direction;
|
||||
vecV.Normalize();
|
||||
vecU = (vecV ^ in.direction).Normalize();
|
||||
|
||||
|
@ -485,11 +467,9 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
|
|||
|
||||
// This animation is repeated and repeated ...
|
||||
anim->mPostState = anim->mPreState = aiAnimBehaviour_REPEAT;
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
case Animator::FLY_STRAIGHT:
|
||||
{
|
||||
case Animator::FLY_STRAIGHT: {
|
||||
anim->mPostState = anim->mPreState = (in.loop ? aiAnimBehaviour_REPEAT : aiAnimBehaviour_CONSTANT);
|
||||
const double seconds = in.timeForWay / 1000.;
|
||||
const double tdelta = 1000. / fps;
|
||||
|
@ -509,11 +489,9 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
|
|||
key.mTime = i * tdelta;
|
||||
key.mValue = in.circleCenter + diff * ai_real(timeFactor * key.mTime);
|
||||
}
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
case Animator::FOLLOW_SPLINE:
|
||||
{
|
||||
case Animator::FOLLOW_SPLINE: {
|
||||
// repeat outside the defined time range
|
||||
anim->mPostState = anim->mPreState = aiAnimBehaviour_REPEAT;
|
||||
const int size = (int)in.splineKeys.size();
|
||||
|
@ -524,8 +502,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
|
|||
delete anim;
|
||||
anim = nullptr;
|
||||
break;
|
||||
}
|
||||
else if (size == 1) {
|
||||
} else if (size == 1) {
|
||||
// We have just one point in the spline so we don't need the full calculation
|
||||
anim->mNumPositionKeys = 1;
|
||||
anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
|
||||
|
@ -539,8 +516,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
|
|||
anim->mNumPositionKeys = (unsigned int)(ticksPerFull * fps);
|
||||
anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
|
||||
|
||||
for (unsigned int i = 0; i < anim->mNumPositionKeys;++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) {
|
||||
aiVectorKey &key = anim->mPositionKeys[i];
|
||||
|
||||
const ai_real dt = (i * in.speed * ai_real(0.001));
|
||||
|
@ -573,8 +549,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
|
|||
key.mValue = t2;
|
||||
key.mTime = (double)i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
default:
|
||||
// UNKNOWN , OTHER
|
||||
break;
|
||||
|
@ -588,8 +563,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// This function is maybe more generic than we'd need it here
|
||||
void SetupMapping (aiMaterial* mat, aiTextureMapping mode, const aiVector3D& axis = aiVector3D(0.f,0.f,-1.f))
|
||||
{
|
||||
void SetupMapping(aiMaterial *mat, aiTextureMapping mode, const aiVector3D &axis = aiVector3D(0.f, 0.f, -1.f)) {
|
||||
// Check whether there are texture properties defined - setup
|
||||
// the desired texture mapping mode for all of them and ignore
|
||||
// all UV settings we might encounter. WE HAVE NO UVS!
|
||||
|
@ -597,8 +571,7 @@ void SetupMapping (aiMaterial* mat, aiTextureMapping mode, const aiVector3D& axi
|
|||
std::vector<aiMaterialProperty *> p;
|
||||
p.reserve(mat->mNumProperties + 1);
|
||||
|
||||
for (unsigned int i = 0; i < mat->mNumProperties;++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < mat->mNumProperties; ++i) {
|
||||
aiMaterialProperty *prop = mat->mProperties[i];
|
||||
if (!::strcmp(prop->mKey.data, "$tex.file")) {
|
||||
// Setup the mapping key
|
||||
|
@ -628,11 +601,10 @@ void SetupMapping (aiMaterial* mat, aiTextureMapping mode, const aiVector3D& axi
|
|||
*((aiVector3D *)m->mData) = axis;
|
||||
p.push_back(m);
|
||||
}
|
||||
}
|
||||
else if (! ::strcmp( prop->mKey.data, "$tex.uvwsrc")) {
|
||||
} else if (!::strcmp(prop->mKey.data, "$tex.uvwsrc")) {
|
||||
delete mat->mProperties[i];
|
||||
}
|
||||
else p.push_back(prop);
|
||||
} else
|
||||
p.push_back(prop);
|
||||
}
|
||||
|
||||
if (p.empty()) return;
|
||||
|
@ -655,17 +627,14 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
|
|||
std::vector<aiNodeAnim *> &anims,
|
||||
std::vector<AttachmentInfo> &attach,
|
||||
std::vector<aiMaterial *> &materials,
|
||||
unsigned int& defMatIdx)
|
||||
{
|
||||
unsigned int &defMatIdx) {
|
||||
unsigned int oldMeshSize = (unsigned int)meshes.size();
|
||||
//unsigned int meshTrafoAssign = 0;
|
||||
|
||||
// Now determine the type of the node
|
||||
switch (root->type)
|
||||
{
|
||||
switch (root->type) {
|
||||
case Node::ANIMMESH:
|
||||
case Node::MESH:
|
||||
{
|
||||
case Node::MESH: {
|
||||
if (!root->meshPath.length())
|
||||
break;
|
||||
|
||||
|
@ -705,7 +674,6 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
|
|||
// Process material flags
|
||||
aiMesh *mesh = localScene->mMeshes[i];
|
||||
|
||||
|
||||
// If "trans_vertex_alpha" mode is enabled, search all vertex colors
|
||||
// and check whether they have a common alpha value. This is quite
|
||||
// often the case so we can simply extract it to a shared oacity
|
||||
|
@ -713,8 +681,7 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
|
|||
std::pair<aiMaterial *, unsigned int> &src = root->materials[mesh->mMaterialIndex];
|
||||
aiMaterial *mat = (aiMaterial *)src.first;
|
||||
|
||||
if (mesh->HasVertexColors(0) && src.second & AI_IRRMESH_MAT_trans_vertex_alpha)
|
||||
{
|
||||
if (mesh->HasVertexColors(0) && src.second & AI_IRRMESH_MAT_trans_vertex_alpha) {
|
||||
bool bdo = true;
|
||||
for (unsigned int a = 1; a < mesh->mNumVertices; ++a) {
|
||||
|
||||
|
@ -742,14 +709,12 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
|
|||
int idx = 1;
|
||||
if (src.second & (AI_IRRMESH_MAT_solid_2layer | AI_IRRMESH_MAT_lightmap)) {
|
||||
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_DIFFUSE(0));
|
||||
}
|
||||
else if (src.second & AI_IRRMESH_MAT_normalmap_solid) {
|
||||
} else if (src.second & AI_IRRMESH_MAT_normalmap_solid) {
|
||||
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_NORMALS(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
case Node::LIGHT:
|
||||
case Node::CAMERA:
|
||||
|
@ -757,18 +722,19 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
|
|||
// We're already finished with lights and cameras
|
||||
break;
|
||||
|
||||
|
||||
case Node::SPHERE:
|
||||
{
|
||||
case Node::SPHERE: {
|
||||
// Generate the sphere model. Our input parameter to
|
||||
// the sphere generation algorithm is the number of
|
||||
// subdivisions of each triangle - but here we have
|
||||
// the number of poylgons on a specific axis. Just
|
||||
// use some hardcoded limits to approximate this ...
|
||||
unsigned int mul = root->spherePolyCountX * root->spherePolyCountY;
|
||||
if (mul < 100)mul = 2;
|
||||
else if (mul < 300)mul = 3;
|
||||
else mul = 4;
|
||||
if (mul < 100)
|
||||
mul = 2;
|
||||
else if (mul < 300)
|
||||
mul = 3;
|
||||
else
|
||||
mul = 4;
|
||||
|
||||
meshes.push_back(StandardShapes::MakeMesh(mul,
|
||||
&StandardShapes::MakeSphere));
|
||||
|
@ -782,11 +748,9 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
|
|||
// Now adjust this output material - if there is a first texture
|
||||
// set, setup spherical UV mapping around the Y axis.
|
||||
SetupMapping((aiMaterial *)materials.back(), aiTextureMapping_SPHERE);
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
case Node::CUBE:
|
||||
{
|
||||
case Node::CUBE: {
|
||||
// Generate an unit cube first
|
||||
meshes.push_back(StandardShapes::MakeMesh(
|
||||
&StandardShapes::MakeHexahedron));
|
||||
|
@ -800,12 +764,9 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
|
|||
// Now adjust this output material - if there is a first texture
|
||||
// set, setup cubic UV mapping
|
||||
SetupMapping((aiMaterial *)materials.back(), aiTextureMapping_BOX);
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
|
||||
case Node::SKYBOX:
|
||||
{
|
||||
case Node::SKYBOX: {
|
||||
// A skybox is defined by six materials
|
||||
if (root->materials.size() < 6) {
|
||||
ASSIMP_LOG_ERROR("IRR: There should be six materials for a skybox");
|
||||
|
@ -827,15 +788,12 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
|
|||
root->name = "IRR.SkyBox_" + root->name;
|
||||
ASSIMP_LOG_INFO("IRR: Loading skybox, this will "
|
||||
"require special handling to be displayed correctly");
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
case Node::TERRAIN:
|
||||
{
|
||||
case Node::TERRAIN: {
|
||||
// to support terrains, we'd need to have a texture decoder
|
||||
ASSIMP_LOG_ERROR("IRR: Unsupported node - TERRAIN");
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
default:
|
||||
// DUMMY
|
||||
break;
|
||||
|
@ -901,8 +859,7 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file into the given scene structure.
|
||||
void IRRImporter::InternReadFile(const std::string &pFile,
|
||||
aiScene* pScene, IOSystem* pIOHandler)
|
||||
{
|
||||
aiScene *pScene, IOSystem *pIOHandler) {
|
||||
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
|
||||
|
||||
// Check whether we can read from the file
|
||||
|
@ -911,8 +868,9 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
}
|
||||
|
||||
// Construct the irrXML parser
|
||||
CIrrXML_IOStreamReader st(file.get());
|
||||
reader = createIrrXMLReader((IFileReadCallBack*) &st);
|
||||
XmlParser st;
|
||||
pugi::xml_node *rootElement = st.parse(file.get());
|
||||
// reader = createIrrXMLReader((IFileReadCallBack*) &st);
|
||||
|
||||
// The root node of the scene
|
||||
Node *root = new Node(Node::DUMMY);
|
||||
|
@ -942,11 +900,12 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
unsigned int guessedAnimCnt = 0, guessedMeshCnt = 0, guessedMatCnt = 0;
|
||||
|
||||
// Parse the XML file
|
||||
while (reader->read()) {
|
||||
switch (reader->getNodeType()) {
|
||||
case EXN_ELEMENT:
|
||||
|
||||
if (!ASSIMP_stricmp(reader->getNodeName(),"node")) {
|
||||
//while (reader->read()) {
|
||||
for (pugi::xml_node child : rootElement->children())
|
||||
switch (child.type()) {
|
||||
case pugi::node_element:
|
||||
if (!ASSIMP_stricmp(child.name(), "node")) {
|
||||
// ***********************************************************************
|
||||
/* What we're going to do with the node depends
|
||||
* on its type:
|
||||
|
@ -967,57 +926,47 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
* materials assigned (except lights, cameras and dummies, of course).
|
||||
*/
|
||||
// ***********************************************************************
|
||||
const char* sz = reader->getAttributeValueSafe("type");
|
||||
//const char *sz = reader->getAttributeValueSafe("type");
|
||||
pugi::xml_attribute attrib = child.attribute("type");
|
||||
Node *nd;
|
||||
if (!ASSIMP_stricmp(sz,"mesh") || !ASSIMP_stricmp(sz,"octTree")) {
|
||||
if (!ASSIMP_stricmp(attrib.name(), "mesh") || !ASSIMP_stricmp(attrib.name(), "octTree")) {
|
||||
// OctTree's and meshes are treated equally
|
||||
nd = new Node(Node::MESH);
|
||||
}
|
||||
else if (!ASSIMP_stricmp(sz,"cube")) {
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "cube")) {
|
||||
nd = new Node(Node::CUBE);
|
||||
++guessedMeshCnt;
|
||||
// meshes.push_back(StandardShapes::MakeMesh(&StandardShapes::MakeHexahedron));
|
||||
}
|
||||
else if (!ASSIMP_stricmp(sz,"skybox")) {
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "skybox")) {
|
||||
nd = new Node(Node::SKYBOX);
|
||||
guessedMeshCnt += 6;
|
||||
}
|
||||
else if (!ASSIMP_stricmp(sz,"camera")) {
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "camera")) {
|
||||
nd = new Node(Node::CAMERA);
|
||||
|
||||
// Setup a temporary name for the camera
|
||||
aiCamera *cam = new aiCamera();
|
||||
cam->mName.Set(nd->name);
|
||||
cameras.push_back(cam);
|
||||
}
|
||||
else if (!ASSIMP_stricmp(sz,"light")) {
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "light")) {
|
||||
nd = new Node(Node::LIGHT);
|
||||
|
||||
// Setup a temporary name for the light
|
||||
aiLight *cam = new aiLight();
|
||||
cam->mName.Set(nd->name);
|
||||
lights.push_back(cam);
|
||||
}
|
||||
else if (!ASSIMP_stricmp(sz,"sphere")) {
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "sphere")) {
|
||||
nd = new Node(Node::SPHERE);
|
||||
++guessedMeshCnt;
|
||||
}
|
||||
else if (!ASSIMP_stricmp(sz,"animatedMesh")) {
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "animatedMesh")) {
|
||||
nd = new Node(Node::ANIMMESH);
|
||||
}
|
||||
else if (!ASSIMP_stricmp(sz,"empty")) {
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "empty")) {
|
||||
nd = new Node(Node::DUMMY);
|
||||
}
|
||||
else if (!ASSIMP_stricmp(sz,"terrain")) {
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "terrain")) {
|
||||
nd = new Node(Node::TERRAIN);
|
||||
}
|
||||
else if (!ASSIMP_stricmp(sz,"billBoard")) {
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "billBoard")) {
|
||||
// We don't support billboards, so ignore them
|
||||
ASSIMP_LOG_ERROR("IRR: Billboards are not supported by Assimp");
|
||||
nd = new Node(Node::DUMMY);
|
||||
}
|
||||
else {
|
||||
ASSIMP_LOG_WARN("IRR: Found unknown node: " + std::string(sz));
|
||||
} else {
|
||||
ASSIMP_LOG_WARN("IRR: Found unknown node: " + std::string(attrib.name()));
|
||||
|
||||
/* We skip the contents of nodes we don't know.
|
||||
* We parse the transformation and all animators
|
||||
|
@ -1026,22 +975,18 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
nd = new Node(Node::DUMMY);
|
||||
}
|
||||
|
||||
/* Attach the newly created node to the scenegraph
|
||||
/* Attach the newly created node to the scene-graph
|
||||
*/
|
||||
curNode = nd;
|
||||
nd->parent = curParent;
|
||||
curParent->children.push_back(nd);
|
||||
}
|
||||
else if (!ASSIMP_stricmp(reader->getNodeName(),"materials")) {
|
||||
} else if (!ASSIMP_stricmp(child.name(), "materials")) {
|
||||
inMaterials = true;
|
||||
}
|
||||
else if (!ASSIMP_stricmp(reader->getNodeName(),"animators")) {
|
||||
} else if (!ASSIMP_stricmp(child.name(), "animators")) {
|
||||
inAnimator = true;
|
||||
}
|
||||
else if (!ASSIMP_stricmp(reader->getNodeName(),"attributes")) {
|
||||
/* We should have a valid node here
|
||||
* FIX: no ... the scene root node is also contained in an attributes block
|
||||
*/
|
||||
} else if (!ASSIMP_stricmp(child.name(), "attributes")) {
|
||||
// We should have a valid node here
|
||||
// FIX: no ... the scene root node is also contained in an attributes block
|
||||
if (!curNode) {
|
||||
#if 0
|
||||
ASSIMP_LOG_ERROR("IRR: Encountered <attributes> element, but "
|
||||
|
@ -1054,8 +999,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
|
||||
// Materials can occur for nearly any type of node
|
||||
if (inMaterials && curNode->type != Node::DUMMY) {
|
||||
/* This is a material description - parse it!
|
||||
*/
|
||||
// This is a material description - parse it!
|
||||
curNode->materials.push_back(std::pair<aiMaterial *, unsigned int>());
|
||||
std::pair<aiMaterial *, unsigned int> &p = curNode->materials.back();
|
||||
|
||||
|
@ -1063,11 +1007,9 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
|
||||
++guessedMatCnt;
|
||||
continue;
|
||||
}
|
||||
else if (inAnimator) {
|
||||
/* This is an animation path - add a new animator
|
||||
* to the list.
|
||||
*/
|
||||
} else if (inAnimator) {
|
||||
// This is an animation path - add a new animator
|
||||
// to the list.
|
||||
curNode->animators.push_back(Animator());
|
||||
curAnim = &curNode->animators.back();
|
||||
|
||||
|
@ -1077,9 +1019,12 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
/* Parse all elements in the attributes block
|
||||
* and process them.
|
||||
*/
|
||||
while (reader->read()) {
|
||||
if (reader->getNodeType() == EXN_ELEMENT) {
|
||||
if (!ASSIMP_stricmp(reader->getNodeName(),"vector3d")) {
|
||||
// while (reader->read()) {
|
||||
for (pugi::xml_node attrib : child.children()) {
|
||||
if (attrib.type() == pugi::node_element) {
|
||||
//if (reader->getNodeType() == EXN_ELEMENT) {
|
||||
//if (!ASSIMP_stricmp(reader->getNodeName(), "vector3d")) {
|
||||
if (!ASSIMP_stricmp(attrib.name(), "vector3d")) {
|
||||
VectorProperty prop;
|
||||
ReadVectorProperty(prop);
|
||||
|
||||
|
@ -1087,8 +1032,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
if (curAnim->type == Animator::ROTATION && prop.name == "Rotation") {
|
||||
// We store the rotation euler angles in 'direction'
|
||||
curAnim->direction = prop.value;
|
||||
}
|
||||
else if (curAnim->type == Animator::FOLLOW_SPLINE) {
|
||||
} else if (curAnim->type == Animator::FOLLOW_SPLINE) {
|
||||
// Check whether the vector follows the PointN naming scheme,
|
||||
// here N is the ONE-based index of the point
|
||||
if (prop.name.length() >= 6 && prop.name.substr(0, 5) == "Point") {
|
||||
|
@ -1100,63 +1044,53 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
key.mValue = prop.value;
|
||||
key.mTime = strtoul10(&prop.name[5]);
|
||||
}
|
||||
}
|
||||
else if (curAnim->type == Animator::FLY_CIRCLE) {
|
||||
} else if (curAnim->type == Animator::FLY_CIRCLE) {
|
||||
if (prop.name == "Center") {
|
||||
curAnim->circleCenter = prop.value;
|
||||
}
|
||||
else if (prop.name == "Direction") {
|
||||
} else if (prop.name == "Direction") {
|
||||
curAnim->direction = prop.value;
|
||||
|
||||
// From Irrlicht's source - a workaround for backward compatibility with Irrlicht 1.1
|
||||
if (curAnim->direction == aiVector3D()) {
|
||||
curAnim->direction = aiVector3D(0.f, 1.f, 0.f);
|
||||
} else
|
||||
curAnim->direction.Normalize();
|
||||
}
|
||||
else curAnim->direction.Normalize();
|
||||
}
|
||||
}
|
||||
else if (curAnim->type == Animator::FLY_STRAIGHT) {
|
||||
} else if (curAnim->type == Animator::FLY_STRAIGHT) {
|
||||
if (prop.name == "Start") {
|
||||
// We reuse the field here
|
||||
curAnim->circleCenter = prop.value;
|
||||
}
|
||||
else if (prop.name == "End") {
|
||||
} else if (prop.name == "End") {
|
||||
// We reuse the field here
|
||||
curAnim->direction = prop.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (prop.name == "Position") {
|
||||
curNode->position = prop.value;
|
||||
}
|
||||
else if (prop.name == "Rotation") {
|
||||
} else if (prop.name == "Rotation") {
|
||||
curNode->rotation = prop.value;
|
||||
}
|
||||
else if (prop.name == "Scale") {
|
||||
} else if (prop.name == "Scale") {
|
||||
curNode->scaling = prop.value;
|
||||
}
|
||||
else if (Node::CAMERA == curNode->type)
|
||||
{
|
||||
} else if (Node::CAMERA == curNode->type) {
|
||||
aiCamera *cam = cameras.back();
|
||||
if (prop.name == "Target") {
|
||||
cam->mLookAt = prop.value;
|
||||
}
|
||||
else if (prop.name == "UpVector") {
|
||||
} else if (prop.name == "UpVector") {
|
||||
cam->mUp = prop.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!ASSIMP_stricmp(reader->getNodeName(),"bool")) {
|
||||
//} else if (!ASSIMP_stricmp(reader->getNodeName(), "bool")) {
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "bool")) {
|
||||
BoolProperty prop;
|
||||
ReadBoolProperty(prop);
|
||||
|
||||
if (inAnimator && curAnim->type == Animator::FLY_CIRCLE && prop.name == "Loop") {
|
||||
curAnim->loop = prop.value;
|
||||
}
|
||||
}
|
||||
else if (!ASSIMP_stricmp(reader->getNodeName(),"float")) {
|
||||
//} else if (!ASSIMP_stricmp(reader->getNodeName(), "float")) {
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "float")) {
|
||||
FloatProperty prop;
|
||||
ReadFloatProperty(prop);
|
||||
|
||||
|
@ -1164,59 +1098,48 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
// The speed property exists for several animators
|
||||
if (prop.name == "Speed") {
|
||||
curAnim->speed = prop.value;
|
||||
}
|
||||
else if (curAnim->type == Animator::FLY_CIRCLE && prop.name == "Radius") {
|
||||
} else if (curAnim->type == Animator::FLY_CIRCLE && prop.name == "Radius") {
|
||||
curAnim->circleRadius = prop.value;
|
||||
}
|
||||
else if (curAnim->type == Animator::FOLLOW_SPLINE && prop.name == "Tightness") {
|
||||
} else if (curAnim->type == Animator::FOLLOW_SPLINE && prop.name == "Tightness") {
|
||||
curAnim->tightness = prop.value;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (prop.name == "FramesPerSecond" && Node::ANIMMESH == curNode->type) {
|
||||
curNode->framesPerSecond = prop.value;
|
||||
}
|
||||
else if (Node::CAMERA == curNode->type) {
|
||||
} else if (Node::CAMERA == curNode->type) {
|
||||
/* This is the vertical, not the horizontal FOV.
|
||||
* We need to compute the right FOV from the
|
||||
* screen aspect which we don't know yet.
|
||||
*/
|
||||
if (prop.name == "Fovy") {
|
||||
cameras.back()->mHorizontalFOV = prop.value;
|
||||
}
|
||||
else if (prop.name == "Aspect") {
|
||||
} else if (prop.name == "Aspect") {
|
||||
cameras.back()->mAspect = prop.value;
|
||||
}
|
||||
else if (prop.name == "ZNear") {
|
||||
} else if (prop.name == "ZNear") {
|
||||
cameras.back()->mClipPlaneNear = prop.value;
|
||||
}
|
||||
else if (prop.name == "ZFar") {
|
||||
} else if (prop.name == "ZFar") {
|
||||
cameras.back()->mClipPlaneFar = prop.value;
|
||||
}
|
||||
}
|
||||
else if (Node::LIGHT == curNode->type) {
|
||||
} else if (Node::LIGHT == curNode->type) {
|
||||
/* Additional light information
|
||||
*/
|
||||
if (prop.name == "Attenuation") {
|
||||
lights.back()->mAttenuationLinear = prop.value;
|
||||
}
|
||||
else if (prop.name == "OuterCone") {
|
||||
} else if (prop.name == "OuterCone") {
|
||||
lights.back()->mAngleOuterCone = AI_DEG_TO_RAD(prop.value);
|
||||
}
|
||||
else if (prop.name == "InnerCone") {
|
||||
} else if (prop.name == "InnerCone") {
|
||||
lights.back()->mAngleInnerCone = AI_DEG_TO_RAD(prop.value);
|
||||
}
|
||||
}
|
||||
// radius of the sphere to be generated -
|
||||
// or alternatively, size of the cube
|
||||
else if ((Node::SPHERE == curNode->type && prop.name == "Radius")
|
||||
|| (Node::CUBE == curNode->type && prop.name == "Size" )) {
|
||||
else if ((Node::SPHERE == curNode->type && prop.name == "Radius") || (Node::CUBE == curNode->type && prop.name == "Size")) {
|
||||
|
||||
curNode->sphereRadius = prop.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!ASSIMP_stricmp(reader->getNodeName(),"int")) {
|
||||
//} else if (!ASSIMP_stricmp(reader->getNodeName(), "int")) {
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "int")) {
|
||||
IntProperty prop;
|
||||
ReadIntProperty(prop);
|
||||
|
||||
|
@ -1224,21 +1147,19 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
if (curAnim->type == Animator::FLY_STRAIGHT && prop.name == "TimeForWay") {
|
||||
curAnim->timeForWay = prop.value;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// sphere polgon numbers in each direction
|
||||
} else {
|
||||
// sphere polygon numbers in each direction
|
||||
if (Node::SPHERE == curNode->type) {
|
||||
|
||||
if (prop.name == "PolyCountX") {
|
||||
curNode->spherePolyCountX = prop.value;
|
||||
}
|
||||
else if (prop.name == "PolyCountY") {
|
||||
} else if (prop.name == "PolyCountY") {
|
||||
curNode->spherePolyCountY = prop.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!ASSIMP_stricmp(reader->getNodeName(),"string") ||!ASSIMP_stricmp(reader->getNodeName(),"enum")) {
|
||||
//} else if (!ASSIMP_stricmp(reader->getNodeName(), "string") || !ASSIMP_stricmp(reader->getNodeName(), "enum")) {
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "string") || !ASSIMP_stricmp(attrib.name(), "enum")) {
|
||||
StringProperty prop;
|
||||
ReadStringProperty(prop);
|
||||
if (prop.value.length()) {
|
||||
|
@ -1251,21 +1172,17 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
*/
|
||||
if (Node::CAMERA == curNode->type) {
|
||||
cameras.back()->mName.Set(prop.value);
|
||||
}
|
||||
else if (Node::LIGHT == curNode->type) {
|
||||
} else if (Node::LIGHT == curNode->type) {
|
||||
lights.back()->mName.Set(prop.value);
|
||||
}
|
||||
}
|
||||
else if (Node::LIGHT == curNode->type && "LightType" == prop.name)
|
||||
{
|
||||
} else if (Node::LIGHT == curNode->type && "LightType" == prop.name) {
|
||||
if (prop.value == "Spot")
|
||||
lights.back()->mType = aiLightSource_SPOT;
|
||||
else if (prop.value == "Point")
|
||||
lights.back()->mType = aiLightSource_POINT;
|
||||
else if (prop.value == "Directional")
|
||||
lights.back()->mType = aiLightSource_DIRECTIONAL;
|
||||
else
|
||||
{
|
||||
else {
|
||||
// We won't pass the validation with aiLightSourceType_UNDEFINED,
|
||||
// so we remove the light and replace it with a silly dummy node
|
||||
delete lights.back();
|
||||
|
@ -1274,10 +1191,8 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
|
||||
ASSIMP_LOG_ERROR("Ignoring light of unknown type: " + prop.value);
|
||||
}
|
||||
}
|
||||
else if ((prop.name == "Mesh" && Node::MESH == curNode->type) ||
|
||||
Node::ANIMMESH == curNode->type)
|
||||
{
|
||||
} else if ((prop.name == "Mesh" && Node::MESH == curNode->type) ||
|
||||
Node::ANIMMESH == curNode->type) {
|
||||
/* This is the file name of the mesh - either
|
||||
* animated or not. We need to make sure we setup
|
||||
* the correct post-processing settings here.
|
||||
|
@ -1303,46 +1218,37 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
const std::string extension = GetExtension(prop.value);
|
||||
if ("irr" == extension) {
|
||||
ASSIMP_LOG_ERROR("IRR: Can't load another IRR file recursively");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
curNode->id = batch.AddLoadRequest(prop.value, pp, &map);
|
||||
curNode->meshPath = prop.value;
|
||||
}
|
||||
}
|
||||
else if (inAnimator && prop.name == "Type")
|
||||
{
|
||||
} else if (inAnimator && prop.name == "Type") {
|
||||
// type of the animator
|
||||
if (prop.value == "rotation") {
|
||||
curAnim->type = Animator::ROTATION;
|
||||
}
|
||||
else if (prop.value == "flyCircle") {
|
||||
} else if (prop.value == "flyCircle") {
|
||||
curAnim->type = Animator::FLY_CIRCLE;
|
||||
}
|
||||
else if (prop.value == "flyStraight") {
|
||||
} else if (prop.value == "flyStraight") {
|
||||
curAnim->type = Animator::FLY_CIRCLE;
|
||||
}
|
||||
else if (prop.value == "followSpline") {
|
||||
} else if (prop.value == "followSpline") {
|
||||
curAnim->type = Animator::FOLLOW_SPLINE;
|
||||
}
|
||||
else {
|
||||
ASSIMP_LOG_WARN("IRR: Ignoring unknown animator: "
|
||||
+ prop.value);
|
||||
} else {
|
||||
ASSIMP_LOG_WARN("IRR: Ignoring unknown animator: " + prop.value);
|
||||
|
||||
curAnim->type = Animator::UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (reader->getNodeType() == EXN_ELEMENT_END && !ASSIMP_stricmp(reader->getNodeName(),"attributes")) {
|
||||
//} else if (reader->getNodeType() == EXN_ELEMENT_END && !ASSIMP_stricmp(reader->getNodeName(), "attributes")) {
|
||||
} else if (attrib.type() == pugi::node_null && !ASSIMP_stricmp(attrib.name(), "attributes")) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EXN_ELEMENT_END:
|
||||
/*case EXN_ELEMENT_END:
|
||||
|
||||
// If we reached the end of a node, we need to continue processing its parent
|
||||
if (!ASSIMP_stricmp(reader->getNodeName(), "node")) {
|
||||
|
@ -1352,25 +1258,24 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
if (!curParent) {
|
||||
curParent = root;
|
||||
ASSIMP_LOG_ERROR("IRR: Too many closing <node> elements");
|
||||
}
|
||||
else curParent = curParent->parent;
|
||||
}
|
||||
else curNode = nullptr;
|
||||
} else
|
||||
curParent = curParent->parent;
|
||||
} else
|
||||
curNode = nullptr;
|
||||
}
|
||||
// clear all flags
|
||||
else if (!ASSIMP_stricmp(reader->getNodeName(), "materials")) {
|
||||
inMaterials = false;
|
||||
}
|
||||
else if (!ASSIMP_stricmp(reader->getNodeName(),"animators")) {
|
||||
} else if (!ASSIMP_stricmp(reader->getNodeName(), "animators")) {
|
||||
inAnimator = false;
|
||||
}
|
||||
break;
|
||||
break;*/
|
||||
|
||||
default:
|
||||
// GCC complains that not all enumeration values are handled
|
||||
break;
|
||||
}
|
||||
}
|
||||
//}
|
||||
|
||||
// Now iterate through all cameras and compute their final (horizontal) FOV
|
||||
for (aiCamera *cam : cameras) {
|
||||
|
@ -1384,22 +1289,19 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
|
||||
batch.LoadAll();
|
||||
|
||||
/* Allocate a tempoary scene data structure
|
||||
*/
|
||||
// Allocate a temporary scene data structure
|
||||
aiScene *tempScene = new aiScene();
|
||||
tempScene->mRootNode = new aiNode();
|
||||
tempScene->mRootNode->mName.Set("<IRRRoot>");
|
||||
|
||||
/* Copy the cameras to the output array
|
||||
*/
|
||||
// Copy the cameras to the output array
|
||||
if (!cameras.empty()) {
|
||||
tempScene->mNumCameras = (unsigned int)cameras.size();
|
||||
tempScene->mCameras = new aiCamera *[tempScene->mNumCameras];
|
||||
::memcpy(tempScene->mCameras, &cameras[0], sizeof(void *) * tempScene->mNumCameras);
|
||||
}
|
||||
|
||||
/* Copy the light sources to the output array
|
||||
*/
|
||||
// Copy the light sources to the output array
|
||||
if (!lights.empty()) {
|
||||
tempScene->mNumLights = (unsigned int)lights.size();
|
||||
tempScene->mLights = new aiLight *[tempScene->mNumLights];
|
||||
|
@ -1417,15 +1319,13 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
meshes.reserve(guessedMeshCnt + (guessedMeshCnt >> 2));
|
||||
materials.reserve(guessedMatCnt + (guessedMatCnt >> 2));
|
||||
|
||||
/* Now process our scenegraph recursively: generate final
|
||||
* meshes and generate animation channels for all nodes.
|
||||
*/
|
||||
// Now process our scene-graph recursively: generate final
|
||||
// meshes and generate animation channels for all nodes.
|
||||
unsigned int defMatIdx = UINT_MAX;
|
||||
GenerateGraph(root, tempScene->mRootNode, tempScene,
|
||||
batch, meshes, anims, attach, materials, defMatIdx);
|
||||
|
||||
if (!anims.empty())
|
||||
{
|
||||
if (!anims.empty()) {
|
||||
tempScene->mNumAnimations = 1;
|
||||
tempScene->mAnimations = new aiAnimation *[tempScene->mNumAnimations];
|
||||
aiAnimation *an = tempScene->mAnimations[0] = new aiAnimation();
|
||||
|
@ -1448,40 +1348,33 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
// copy all meshes to the temporary scene
|
||||
tempScene->mNumMeshes = (unsigned int)meshes.size();
|
||||
tempScene->mMeshes = new aiMesh *[tempScene->mNumMeshes];
|
||||
::memcpy(tempScene->mMeshes,&meshes[0],tempScene->mNumMeshes*
|
||||
sizeof(void*));
|
||||
::memcpy(tempScene->mMeshes, &meshes[0], tempScene->mNumMeshes * sizeof(void *));
|
||||
}
|
||||
|
||||
/* Copy all materials to the output array
|
||||
*/
|
||||
// Copy all materials to the output array
|
||||
if (!materials.empty()) {
|
||||
tempScene->mNumMaterials = (unsigned int)materials.size();
|
||||
tempScene->mMaterials = new aiMaterial *[tempScene->mNumMaterials];
|
||||
::memcpy(tempScene->mMaterials,&materials[0],sizeof(void*)*
|
||||
tempScene->mNumMaterials);
|
||||
::memcpy(tempScene->mMaterials, &materials[0], sizeof(void *) * tempScene->mNumMaterials);
|
||||
}
|
||||
|
||||
/* Now merge all sub scenes and attach them to the correct
|
||||
* attachment points in the scenegraph.
|
||||
*/
|
||||
// Now merge all sub scenes and attach them to the correct
|
||||
// attachment points in the scenegraph.
|
||||
SceneCombiner::MergeScenes(&pScene, tempScene, attach,
|
||||
AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | (!configSpeedFlag ? (
|
||||
AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY | AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) : 0));
|
||||
AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY | AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) :
|
||||
0));
|
||||
|
||||
|
||||
/* If we have no meshes | no materials now set the INCOMPLETE
|
||||
* scene flag. This is necessary if we failed to load all
|
||||
* models from external files
|
||||
*/
|
||||
// If we have no meshes | no materials now set the INCOMPLETE
|
||||
// scene flag. This is necessary if we failed to load all
|
||||
// models from external files
|
||||
if (!pScene->mNumMeshes || !pScene->mNumMaterials) {
|
||||
ASSIMP_LOG_WARN("IRR: No meshes loaded, setting AI_SCENE_FLAGS_INCOMPLETE");
|
||||
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
|
||||
}
|
||||
|
||||
/* Finished ... everything destructs automatically and all
|
||||
* temporary scenes have already been deleted by MergeScenes()
|
||||
*/
|
||||
|
||||
// Finished ... everything destructs automatically and all
|
||||
// temporary scenes have already been deleted by MergeScenes()
|
||||
delete root;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#ifndef INCLUDED_AI_IRRSHARED_H
|
||||
#define INCLUDED_AI_IRRSHARED_H
|
||||
|
||||
#include <assimp/irrXMLWrapper.h>
|
||||
#include <assimp/XmlParser.h>
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -78,9 +78,8 @@ protected:
|
|||
typedef Property<aiVector3D> VectorProperty;
|
||||
typedef Property<int> IntProperty;
|
||||
|
||||
/** XML reader instance
|
||||
*/
|
||||
irr::io::IrrXMLReader* reader;
|
||||
/// XML reader instance
|
||||
XmlParser mParser;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a material description from the XML
|
||||
|
|
|
@ -46,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
|
||||
#include "OgreStructs.h"
|
||||
#include <assimp/irrXMLWrapper.h>
|
||||
#include <assimp/XmlParser.h>
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
|
|
|
@ -60,7 +60,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#ifdef ASSIMP_USE_HUNTER
|
||||
# include <irrXML/irrXML.h>
|
||||
#else
|
||||
# include <irrXML.h>
|
||||
# include <assimp/XmlParser.h>
|
||||
#endif
|
||||
|
||||
namespace Assimp {
|
||||
|
|
|
@ -56,7 +56,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <assimp/ProgressHandler.hpp>
|
||||
#include <assimp/types.h>
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <assimp/irrXMLWrapper.h>
|
||||
#include <assimp/XmlParser.h>
|
||||
#include "FIReader.hpp"
|
||||
//#include <regex>
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#define AI_XGLLOADER_H_INCLUDED
|
||||
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <assimp/irrXMLWrapper.h>
|
||||
#include <assimp/XmlParser.h>
|
||||
#include <assimp/LogAux.h>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/Importer.hpp>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Compile internal irrXML only if system is not requested
|
||||
if( NOT SYSTEM_IRRXML )
|
||||
add_subdirectory(irrXML)
|
||||
endif( NOT SYSTEM_IRRXML )
|
||||
#if( NOT SYSTEM_IRRXML )
|
||||
# add_subdirectory(irrXML)
|
||||
#endif( NOT SYSTEM_IRRXML )
|
||||
|
||||
add_subdirectory( pugixml-1.9 )
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
set( IrrXML_SRCS
|
||||
CXMLReaderImpl.h
|
||||
heapsort.h
|
||||
irrArray.h
|
||||
irrString.h
|
||||
irrTypes.h
|
||||
irrXML.cpp
|
||||
irrXML.h
|
||||
)
|
||||
|
||||
if ( MSVC )
|
||||
ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS )
|
||||
ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS )
|
||||
endif ( MSVC )
|
||||
|
||||
IF(CMAKE_SYSTEM_NAME MATCHES "(Darwin|FreeBSD)")
|
||||
add_library(IrrXML ${IrrXML_SRCS})
|
||||
ELSE()
|
||||
add_library(IrrXML STATIC ${IrrXML_SRCS})
|
||||
ENDIF()
|
||||
set(IRRXML_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "IrrXML_Include" )
|
||||
set(IRRXML_LIBRARY "IrrXML" CACHE INTERNAL "IrrXML" )
|
||||
|
||||
install(TARGETS IrrXML
|
||||
LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
|
||||
ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
|
||||
RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR}
|
||||
FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
|
||||
COMPONENT ${LIBASSIMP_COMPONENT})
|
|
@ -1,819 +0,0 @@
|
|||
// Copyright (C) 2002-2005 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine" and the "irrXML" project.
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h and/or irrXML.h
|
||||
|
||||
#ifndef __ICXML_READER_IMPL_H_INCLUDED__
|
||||
#define __ICXML_READER_IMPL_H_INCLUDED__
|
||||
|
||||
#include "irrXML.h"
|
||||
#include "irrString.h"
|
||||
#include "irrArray.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <stdlib.h>
|
||||
#include <cctype>
|
||||
#include <cstdint>
|
||||
//using namespace Assimp;
|
||||
|
||||
// For locale independent number conversion
|
||||
#include <sstream>
|
||||
#include <locale>
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define IRR_DEBUGPRINT(x) printf((x));
|
||||
#else // _DEBUG
|
||||
#define IRR_DEBUGPRINT(x)
|
||||
#endif // _DEBUG
|
||||
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
|
||||
//! implementation of the IrrXMLReader
|
||||
template<class char_type, class superclass>
|
||||
class CXMLReaderImpl : public IIrrXMLReader<char_type, superclass>
|
||||
{
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
CXMLReaderImpl(IFileReadCallBack* callback, bool deleteCallBack = true)
|
||||
: TextData(0), P(0), TextBegin(0), TextSize(0), CurrentNodeType(EXN_NONE),
|
||||
SourceFormat(ETF_ASCII), TargetFormat(ETF_ASCII)
|
||||
{
|
||||
if (!callback)
|
||||
return;
|
||||
|
||||
storeTargetFormat();
|
||||
|
||||
// read whole xml file
|
||||
|
||||
readFile(callback);
|
||||
|
||||
// clean up
|
||||
|
||||
if (deleteCallBack)
|
||||
delete callback;
|
||||
|
||||
// create list with special characters
|
||||
|
||||
createSpecialCharacterList();
|
||||
|
||||
// set pointer to text begin
|
||||
P = TextBegin;
|
||||
}
|
||||
|
||||
|
||||
//! Destructor
|
||||
virtual ~CXMLReaderImpl()
|
||||
{
|
||||
delete [] TextData;
|
||||
}
|
||||
|
||||
|
||||
//! Reads forward to the next xml node.
|
||||
//! \return Returns false, if there was no further node.
|
||||
virtual bool read()
|
||||
{
|
||||
// if not end reached, parse the node
|
||||
if (P && (unsigned int)(P - TextBegin) < TextSize - 1 && *P != 0)
|
||||
{
|
||||
parseCurrentNode();
|
||||
return true;
|
||||
}
|
||||
|
||||
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//! Returns the type of the current XML node.
|
||||
virtual EXML_NODE getNodeType() const
|
||||
{
|
||||
return CurrentNodeType;
|
||||
}
|
||||
|
||||
|
||||
//! Returns attribute count of the current XML node.
|
||||
virtual int getAttributeCount() const
|
||||
{
|
||||
return Attributes.size();
|
||||
}
|
||||
|
||||
|
||||
//! Returns name of an attribute.
|
||||
virtual const char_type* getAttributeName(int idx) const
|
||||
{
|
||||
if (idx < 0 || idx >= (int)Attributes.size())
|
||||
return 0;
|
||||
|
||||
return Attributes[idx].Name.c_str();
|
||||
}
|
||||
|
||||
|
||||
//! Returns the value of an attribute.
|
||||
virtual const char_type* getAttributeValue(int idx) const
|
||||
{
|
||||
if (idx < 0 || idx >= (int)Attributes.size())
|
||||
return 0;
|
||||
|
||||
return Attributes[idx].Value.c_str();
|
||||
}
|
||||
|
||||
|
||||
//! Returns the value of an attribute.
|
||||
virtual const char_type* getAttributeValue(const char_type* name) const
|
||||
{
|
||||
const SAttribute* attr = getAttributeByName(name);
|
||||
if (!attr)
|
||||
return 0;
|
||||
|
||||
return attr->Value.c_str();
|
||||
}
|
||||
|
||||
|
||||
//! Returns the value of an attribute
|
||||
virtual const char_type* getAttributeValueSafe(const char_type* name) const
|
||||
{
|
||||
const SAttribute* attr = getAttributeByName(name);
|
||||
if (!attr)
|
||||
return EmptyString.c_str();
|
||||
|
||||
return attr->Value.c_str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Returns the value of an attribute as integer.
|
||||
int getAttributeValueAsInt(const char_type* name) const
|
||||
{
|
||||
return (int)getAttributeValueAsFloat(name);
|
||||
}
|
||||
|
||||
|
||||
//! Returns the value of an attribute as integer.
|
||||
int getAttributeValueAsInt(int idx) const
|
||||
{
|
||||
return (int)getAttributeValueAsFloat(idx);
|
||||
}
|
||||
|
||||
|
||||
//! Returns the value of an attribute as float.
|
||||
float getAttributeValueAsFloat(const char_type* name) const
|
||||
{
|
||||
const SAttribute* attr = getAttributeByName(name);
|
||||
if (!attr)
|
||||
return 0;
|
||||
|
||||
core::stringc c = attr->Value.c_str();
|
||||
return static_cast<float>(atof(c.c_str()));
|
||||
//return fast_atof(c.c_str());
|
||||
}
|
||||
|
||||
|
||||
//! Returns the value of an attribute as float.
|
||||
float getAttributeValueAsFloat(int idx) const
|
||||
{
|
||||
const char_type* attrvalue = getAttributeValue(idx);
|
||||
if (!attrvalue)
|
||||
return 0;
|
||||
|
||||
core::stringc c = attrvalue;
|
||||
std::istringstream sstr(c.c_str());
|
||||
sstr.imbue(std::locale("C")); // Locale free number convert
|
||||
float fNum;
|
||||
sstr >> fNum;
|
||||
return fNum;
|
||||
}
|
||||
|
||||
|
||||
//! Returns the name of the current node.
|
||||
virtual const char_type* getNodeName() const
|
||||
{
|
||||
return NodeName.c_str();
|
||||
}
|
||||
|
||||
|
||||
//! Returns data of the current node.
|
||||
virtual const char_type* getNodeData() const
|
||||
{
|
||||
return NodeName.c_str();
|
||||
}
|
||||
|
||||
|
||||
//! Returns if an element is an empty element, like <foo />
|
||||
virtual bool isEmptyElement() const
|
||||
{
|
||||
return IsEmptyElement;
|
||||
}
|
||||
|
||||
//! Returns format of the source xml file.
|
||||
virtual ETEXT_FORMAT getSourceFormat() const
|
||||
{
|
||||
return SourceFormat;
|
||||
}
|
||||
|
||||
//! Returns format of the strings returned by the parser.
|
||||
virtual ETEXT_FORMAT getParserFormat() const
|
||||
{
|
||||
return TargetFormat;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// Reads the current xml node
|
||||
void parseCurrentNode()
|
||||
{
|
||||
char_type* start = P;
|
||||
|
||||
// move forward until '<' found
|
||||
while(*P != L'<' && *P)
|
||||
++P;
|
||||
|
||||
if (!*P)
|
||||
return;
|
||||
|
||||
if (P - start > 0)
|
||||
{
|
||||
// we found some text, store it
|
||||
if (setText(start, P))
|
||||
return;
|
||||
}
|
||||
|
||||
++P;
|
||||
|
||||
// based on current token, parse and report next element
|
||||
switch(*P)
|
||||
{
|
||||
case L'/':
|
||||
parseClosingXMLElement();
|
||||
break;
|
||||
case L'?':
|
||||
ignoreDefinition();
|
||||
break;
|
||||
case L'!':
|
||||
if (!parseCDATA())
|
||||
parseComment();
|
||||
break;
|
||||
default:
|
||||
parseOpeningXMLElement();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! sets the state that text was found. Returns true if set should be set
|
||||
bool setText(char_type* start, char_type* end)
|
||||
{
|
||||
// check if text is more than 2 characters, and if not, check if there is
|
||||
// only white space, so that this text won't be reported
|
||||
if (end - start < 3)
|
||||
{
|
||||
char_type* p = start;
|
||||
for(; p != end; ++p)
|
||||
if (!isWhiteSpace(*p))
|
||||
break;
|
||||
|
||||
if (p == end)
|
||||
return false;
|
||||
}
|
||||
|
||||
// set current text to the parsed text, and replace xml special characters
|
||||
core::string<char_type> s(start, (int)(end - start));
|
||||
NodeName = replaceSpecialCharacters(s);
|
||||
|
||||
// current XML node type is text
|
||||
CurrentNodeType = EXN_TEXT;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! ignores an xml definition like <?xml something />
|
||||
void ignoreDefinition()
|
||||
{
|
||||
CurrentNodeType = EXN_UNKNOWN;
|
||||
|
||||
// move until end marked with '>' reached
|
||||
while(*P != L'>')
|
||||
++P;
|
||||
|
||||
++P;
|
||||
}
|
||||
|
||||
|
||||
//! parses a comment
|
||||
void parseComment()
|
||||
{
|
||||
CurrentNodeType = EXN_COMMENT;
|
||||
P += 1;
|
||||
|
||||
char_type *pCommentBegin = P;
|
||||
|
||||
int count = 1;
|
||||
|
||||
// move until end of comment reached
|
||||
while(count)
|
||||
{
|
||||
if (*P == L'>')
|
||||
--count;
|
||||
else
|
||||
if (*P == L'<')
|
||||
++count;
|
||||
|
||||
++P;
|
||||
}
|
||||
|
||||
P -= 3;
|
||||
NodeName = core::string<char_type>(pCommentBegin+2, (int)(P - pCommentBegin-2));
|
||||
P += 3;
|
||||
}
|
||||
|
||||
|
||||
//! parses an opening xml element and reads attributes
|
||||
void parseOpeningXMLElement()
|
||||
{
|
||||
CurrentNodeType = EXN_ELEMENT;
|
||||
IsEmptyElement = false;
|
||||
Attributes.clear();
|
||||
|
||||
// find name
|
||||
const char_type* startName = P;
|
||||
|
||||
// find end of element
|
||||
while(*P != L'>' && !isWhiteSpace(*P))
|
||||
++P;
|
||||
|
||||
const char_type* endName = P;
|
||||
|
||||
// find Attributes
|
||||
while(*P != L'>')
|
||||
{
|
||||
if (isWhiteSpace(*P))
|
||||
++P;
|
||||
else
|
||||
{
|
||||
if (*P != L'/')
|
||||
{
|
||||
// we've got an attribute
|
||||
|
||||
// read the attribute names
|
||||
const char_type* attributeNameBegin = P;
|
||||
|
||||
while(!isWhiteSpace(*P) && *P != L'=')
|
||||
++P;
|
||||
|
||||
const char_type* attributeNameEnd = P;
|
||||
++P;
|
||||
|
||||
// read the attribute value
|
||||
// check for quotes and single quotes, thx to murphy
|
||||
while( (*P != L'\"') && (*P != L'\'') && *P)
|
||||
++P;
|
||||
|
||||
if (!*P) // malformatted xml file
|
||||
return;
|
||||
|
||||
const char_type attributeQuoteChar = *P;
|
||||
|
||||
++P;
|
||||
const char_type* attributeValueBegin = P;
|
||||
|
||||
while(*P != attributeQuoteChar && *P)
|
||||
++P;
|
||||
|
||||
if (!*P) // malformatted xml file
|
||||
return;
|
||||
|
||||
const char_type* attributeValueEnd = P;
|
||||
++P;
|
||||
|
||||
SAttribute attr;
|
||||
attr.Name = core::string<char_type>(attributeNameBegin,
|
||||
(int)(attributeNameEnd - attributeNameBegin));
|
||||
|
||||
core::string<char_type> s(attributeValueBegin,
|
||||
(int)(attributeValueEnd - attributeValueBegin));
|
||||
|
||||
attr.Value = replaceSpecialCharacters(s);
|
||||
Attributes.push_back(attr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// tag is closed directly
|
||||
++P;
|
||||
IsEmptyElement = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if this tag is closing directly
|
||||
if (endName > startName && *(endName-1) == L'/')
|
||||
{
|
||||
// directly closing tag
|
||||
IsEmptyElement = true;
|
||||
endName--;
|
||||
}
|
||||
|
||||
NodeName = core::string<char_type>(startName, (int)(endName - startName));
|
||||
|
||||
++P;
|
||||
}
|
||||
|
||||
|
||||
//! parses an closing xml tag
|
||||
void parseClosingXMLElement()
|
||||
{
|
||||
CurrentNodeType = EXN_ELEMENT_END;
|
||||
IsEmptyElement = false;
|
||||
Attributes.clear();
|
||||
|
||||
++P;
|
||||
const char_type* pBeginClose = P;
|
||||
|
||||
while(*P != L'>')
|
||||
++P;
|
||||
|
||||
// remove trailing whitespace, if any
|
||||
while( std::isspace( P[-1]))
|
||||
--P;
|
||||
|
||||
NodeName = core::string<char_type>(pBeginClose, (int)(P - pBeginClose));
|
||||
++P;
|
||||
}
|
||||
|
||||
//! parses a possible CDATA section, returns false if begin was not a CDATA section
|
||||
bool parseCDATA()
|
||||
{
|
||||
if (*(P+1) != L'[')
|
||||
return false;
|
||||
|
||||
CurrentNodeType = EXN_CDATA;
|
||||
|
||||
// skip '<![CDATA['
|
||||
int count=0;
|
||||
while( *P && count<8 )
|
||||
{
|
||||
++P;
|
||||
++count;
|
||||
}
|
||||
|
||||
if (!*P)
|
||||
return true;
|
||||
|
||||
char_type *cDataBegin = P;
|
||||
char_type *cDataEnd = 0;
|
||||
|
||||
// find end of CDATA
|
||||
while(*P && !cDataEnd)
|
||||
{
|
||||
if (*P == L'>' &&
|
||||
(*(P-1) == L']') &&
|
||||
(*(P-2) == L']'))
|
||||
{
|
||||
cDataEnd = P - 2;
|
||||
}
|
||||
|
||||
++P;
|
||||
}
|
||||
|
||||
if ( cDataEnd )
|
||||
NodeName = core::string<char_type>(cDataBegin, (int)(cDataEnd - cDataBegin));
|
||||
else
|
||||
NodeName = "";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// structure for storing attribute-name pairs
|
||||
struct SAttribute
|
||||
{
|
||||
core::string<char_type> Name;
|
||||
core::string<char_type> Value;
|
||||
};
|
||||
|
||||
// finds a current attribute by name, returns 0 if not found
|
||||
const SAttribute* getAttributeByName(const char_type* name) const
|
||||
{
|
||||
if (!name)
|
||||
return 0;
|
||||
|
||||
core::string<char_type> n = name;
|
||||
|
||||
for (int i=0; i<(int)Attributes.size(); ++i)
|
||||
if (Attributes[i].Name == n)
|
||||
return &Attributes[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// replaces xml special characters in a string and creates a new one
|
||||
core::string<char_type> replaceSpecialCharacters(
|
||||
core::string<char_type>& origstr)
|
||||
{
|
||||
int pos = origstr.findFirst(L'&');
|
||||
int oldPos = 0;
|
||||
|
||||
if (pos == -1)
|
||||
return origstr;
|
||||
|
||||
core::string<char_type> newstr;
|
||||
|
||||
while(pos != -1 && pos < origstr.size()-2)
|
||||
{
|
||||
// check if it is one of the special characters
|
||||
|
||||
int specialChar = -1;
|
||||
for (int i=0; i<(int)SpecialCharacters.size(); ++i)
|
||||
{
|
||||
const char_type* p = &origstr.c_str()[pos]+1;
|
||||
|
||||
if (equalsn(&SpecialCharacters[i][1], p, SpecialCharacters[i].size()-1))
|
||||
{
|
||||
specialChar = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (specialChar != -1)
|
||||
{
|
||||
newstr.append(origstr.subString(oldPos, pos - oldPos));
|
||||
newstr.append(SpecialCharacters[specialChar][0]);
|
||||
pos += SpecialCharacters[specialChar].size();
|
||||
}
|
||||
else
|
||||
{
|
||||
newstr.append(origstr.subString(oldPos, pos - oldPos + 1));
|
||||
pos += 1;
|
||||
}
|
||||
|
||||
// find next &
|
||||
oldPos = pos;
|
||||
pos = origstr.findNext(L'&', pos);
|
||||
}
|
||||
|
||||
if (oldPos < origstr.size()-1)
|
||||
newstr.append(origstr.subString(oldPos, origstr.size()-oldPos));
|
||||
|
||||
return newstr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! reads the xml file and converts it into the wanted character format.
|
||||
bool readFile(IFileReadCallBack* callback)
|
||||
{
|
||||
int size = callback->getSize();
|
||||
size += 4; // We need two terminating 0's at the end.
|
||||
// For ASCII we need 1 0's, for UTF-16 2, for UTF-32 4.
|
||||
|
||||
char* data8 = new char[size];
|
||||
|
||||
if (!callback->read(data8, size-4))
|
||||
{
|
||||
delete [] data8;
|
||||
return false;
|
||||
}
|
||||
|
||||
// add zeros at end
|
||||
|
||||
data8[size-1] = 0;
|
||||
data8[size-2] = 0;
|
||||
data8[size-3] = 0;
|
||||
data8[size-4] = 0;
|
||||
|
||||
char16* data16 = reinterpret_cast<char16*>(data8);
|
||||
char32* data32 = reinterpret_cast<char32*>(data8);
|
||||
|
||||
// now we need to convert the data to the desired target format
|
||||
// based on the byte order mark.
|
||||
|
||||
const unsigned char UTF8[] = {0xEF, 0xBB, 0xBF}; // 0xEFBBBF;
|
||||
const int UTF16_BE = 0xFFFE;
|
||||
const int UTF16_LE = 0xFEFF;
|
||||
const int UTF32_BE = 0xFFFE0000;
|
||||
const int UTF32_LE = 0x0000FEFF;
|
||||
|
||||
// check source for all utf versions and convert to target data format
|
||||
|
||||
if (size >= 4 && data32[0] == (char32)UTF32_BE)
|
||||
{
|
||||
// UTF-32, big endian
|
||||
SourceFormat = ETF_UTF32_BE;
|
||||
convertTextData(data32+1, data8, (size/4)); // data32+1 because we need to skip the header
|
||||
}
|
||||
else
|
||||
if (size >= 4 && data32[0] == (char32)UTF32_LE)
|
||||
{
|
||||
// UTF-32, little endian
|
||||
SourceFormat = ETF_UTF32_LE;
|
||||
convertTextData(data32+1, data8, (size/4)); // data32+1 because we need to skip the header
|
||||
}
|
||||
else
|
||||
if (size >= 2 && data16[0] == UTF16_BE)
|
||||
{
|
||||
// UTF-16, big endian
|
||||
SourceFormat = ETF_UTF16_BE;
|
||||
convertTextData(data16+1, data8, (size/2)); // data16+1 because we need to skip the header
|
||||
}
|
||||
else
|
||||
if (size >= 2 && data16[0] == UTF16_LE)
|
||||
{
|
||||
// UTF-16, little endian
|
||||
SourceFormat = ETF_UTF16_LE;
|
||||
convertTextData(data16+1, data8, (size/2)); // data16+1 because we need to skip the header
|
||||
}
|
||||
else
|
||||
if (size >= 3 && data8[0] == UTF8[0] && data8[1] == UTF8[1] && data8[2] == UTF8[2])
|
||||
{
|
||||
// UTF-8
|
||||
SourceFormat = ETF_UTF8;
|
||||
convertTextData(data8+3, data8, size); // data8+3 because we need to skip the header
|
||||
}
|
||||
else
|
||||
{
|
||||
// ASCII
|
||||
SourceFormat = ETF_ASCII;
|
||||
convertTextData(data8, data8, size);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//! converts the text file into the desired format.
|
||||
//! \param source: begin of the text (without byte order mark)
|
||||
//! \param pointerToStore: pointer to text data block which can be
|
||||
//! stored or deleted based on the nesessary conversion.
|
||||
//! \param sizeWithoutHeader: Text size in characters without header
|
||||
template<class src_char_type>
|
||||
void convertTextData(src_char_type* source, char* pointerToStore, int sizeWithoutHeader)
|
||||
{
|
||||
// convert little to big endian if necessary
|
||||
if (sizeof(src_char_type) > 1 &&
|
||||
isLittleEndian(TargetFormat) != isLittleEndian(SourceFormat))
|
||||
convertToLittleEndian(source);
|
||||
|
||||
// check if conversion is necessary:
|
||||
if (sizeof(src_char_type) == sizeof(char_type))
|
||||
{
|
||||
// no need to convert
|
||||
TextBegin = (char_type*)source;
|
||||
TextData = (char_type*)pointerToStore;
|
||||
TextSize = sizeWithoutHeader;
|
||||
}
|
||||
else
|
||||
{
|
||||
// convert source into target data format.
|
||||
// TODO: implement a real conversion. This one just
|
||||
// copies bytes. This is a problem when there are
|
||||
// unicode symbols using more than one character.
|
||||
|
||||
TextData = new char_type[sizeWithoutHeader];
|
||||
|
||||
// MSVC debugger complains here about loss of data ...
|
||||
size_t numShift = sizeof( char_type) * 8;
|
||||
assert(numShift < 64);
|
||||
const src_char_type cc = (src_char_type)(((uint64_t(1u) << numShift) - 1));
|
||||
for (int i=0; i<sizeWithoutHeader; ++i)
|
||||
TextData[i] = char_type( source[i] & cc);
|
||||
|
||||
TextBegin = TextData;
|
||||
TextSize = sizeWithoutHeader;
|
||||
|
||||
// delete original data because no longer needed
|
||||
delete [] pointerToStore;
|
||||
}
|
||||
}
|
||||
|
||||
//! converts whole text buffer to little endian
|
||||
template<class src_char_type>
|
||||
void convertToLittleEndian(src_char_type* t)
|
||||
{
|
||||
if (sizeof(src_char_type) == 4)
|
||||
{
|
||||
// 32 bit
|
||||
|
||||
while(*t)
|
||||
{
|
||||
*t = ((*t & 0xff000000) >> 24) |
|
||||
((*t & 0x00ff0000) >> 8) |
|
||||
((*t & 0x0000ff00) << 8) |
|
||||
((*t & 0x000000ff) << 24);
|
||||
++t;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 16 bit
|
||||
|
||||
while(*t)
|
||||
{
|
||||
*t = (*t >> 8) | (*t << 8);
|
||||
++t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! returns if a format is little endian
|
||||
inline bool isLittleEndian(ETEXT_FORMAT f)
|
||||
{
|
||||
return f == ETF_ASCII ||
|
||||
f == ETF_UTF8 ||
|
||||
f == ETF_UTF16_LE ||
|
||||
f == ETF_UTF32_LE;
|
||||
}
|
||||
|
||||
|
||||
//! returns true if a character is whitespace
|
||||
inline bool isWhiteSpace(char_type c)
|
||||
{
|
||||
return (c==' ' || c=='\t' || c=='\n' || c=='\r');
|
||||
}
|
||||
|
||||
|
||||
//! generates a list with xml special characters
|
||||
void createSpecialCharacterList()
|
||||
{
|
||||
// list of strings containing special symbols,
|
||||
// the first character is the special character,
|
||||
// the following is the symbol string without trailing &.
|
||||
|
||||
SpecialCharacters.push_back("&");
|
||||
SpecialCharacters.push_back("<lt;");
|
||||
SpecialCharacters.push_back(">gt;");
|
||||
SpecialCharacters.push_back("\"quot;");
|
||||
SpecialCharacters.push_back("'apos;");
|
||||
|
||||
}
|
||||
|
||||
|
||||
//! compares the first n characters of the strings
|
||||
bool equalsn(const char_type* str1, const char_type* str2, int len)
|
||||
{
|
||||
int i;
|
||||
for(i=0; str1[i] && str2[i] && i < len; ++i)
|
||||
if (str1[i] != str2[i])
|
||||
return false;
|
||||
|
||||
// if one (or both) of the strings was smaller then they
|
||||
// are only equal if they have the same lenght
|
||||
return (i == len) || (str1[i] == 0 && str2[i] == 0);
|
||||
}
|
||||
|
||||
|
||||
//! stores the target text format
|
||||
void storeTargetFormat()
|
||||
{
|
||||
// get target format. We could have done this using template specialization,
|
||||
// but VisualStudio 6 don't like it and we want to support it.
|
||||
|
||||
switch(sizeof(char_type))
|
||||
{
|
||||
case 1:
|
||||
TargetFormat = ETF_UTF8;
|
||||
break;
|
||||
case 2:
|
||||
TargetFormat = ETF_UTF16_LE;
|
||||
break;
|
||||
case 4:
|
||||
TargetFormat = ETF_UTF32_LE;
|
||||
break;
|
||||
default:
|
||||
TargetFormat = ETF_ASCII; // should never happen.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// instance variables:
|
||||
|
||||
char_type* TextData; // data block of the text file
|
||||
char_type* P; // current point in text to parse
|
||||
char_type* TextBegin; // start of text to parse
|
||||
unsigned int TextSize; // size of text to parse in characters, not bytes
|
||||
|
||||
EXML_NODE CurrentNodeType; // type of the currently parsed node
|
||||
ETEXT_FORMAT SourceFormat; // source format of the xml file
|
||||
ETEXT_FORMAT TargetFormat; // output format of this parser
|
||||
|
||||
core::string<char_type> NodeName; // name of the node currently in
|
||||
core::string<char_type> EmptyString; // empty string to be returned by getSafe() methods
|
||||
|
||||
bool IsEmptyElement; // is the currently parsed node empty?
|
||||
|
||||
core::array< core::string<char_type> > SpecialCharacters; // see createSpecialCharacterList()
|
||||
|
||||
core::array<SAttribute> Attributes; // attributes of current element
|
||||
|
||||
}; // end CXMLReaderImpl
|
||||
|
||||
|
||||
} // end namespace
|
||||
} // end namespace
|
||||
|
||||
#endif
|
|
@ -1,73 +0,0 @@
|
|||
// Copyright (C) 2002-2005 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#ifndef __IRR_HEAPSORT_H_INCLUDED__
|
||||
#define __IRR_HEAPSORT_H_INCLUDED__
|
||||
|
||||
#include "irrTypes.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace core
|
||||
{
|
||||
|
||||
//! Sinks an element into the heap.
|
||||
template<class T>
|
||||
inline void heapsink(T*array, s32 element, s32 max)
|
||||
{
|
||||
while ((element<<1) < max) // there is a left child
|
||||
{
|
||||
s32 j = (element<<1);
|
||||
|
||||
if (j+1 < max && array[j] < array[j+1])
|
||||
j = j+1; // take right child
|
||||
|
||||
if (array[element] < array[j])
|
||||
{
|
||||
T t = array[j]; // swap elements
|
||||
array[j] = array[element];
|
||||
array[element] = t;
|
||||
element = j;
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! Sorts an array with size 'size' using heapsort.
|
||||
template<class T>
|
||||
inline void heapsort(T* array_, s32 size)
|
||||
{
|
||||
// for heapsink we pretent this is not c++, where
|
||||
// arrays start with index 0. So we decrease the array pointer,
|
||||
// the maximum always +2 and the element always +1
|
||||
|
||||
T* virtualArray = array_ - 1;
|
||||
s32 virtualSize = size + 2;
|
||||
s32 i;
|
||||
|
||||
// build heap
|
||||
|
||||
for (i=((size-1)/2); i>=0; --i)
|
||||
heapsink(virtualArray, i+1, virtualSize-1);
|
||||
|
||||
// sort array
|
||||
|
||||
for (i=size-1; i>=0; --i)
|
||||
{
|
||||
T t = array_[0];
|
||||
array_[0] = array_[i];
|
||||
array_[i] = t;
|
||||
heapsink(virtualArray, 1, i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace core
|
||||
} // end namespace irr
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,443 +0,0 @@
|
|||
// Copyright (C) 2002-2005 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine" and the "irrXML" project.
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h
|
||||
|
||||
#ifndef __IRR_ARRAY_H_INCLUDED__
|
||||
#define __IRR_ARRAY_H_INCLUDED__
|
||||
|
||||
#include "irrTypes.h"
|
||||
#include "heapsort.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace core
|
||||
{
|
||||
|
||||
//! Self reallocating template array (like stl vector) with additional features.
|
||||
/** Some features are: Heap sorting, binary search methods, easier debugging.
|
||||
*/
|
||||
template <class T>
|
||||
class array
|
||||
{
|
||||
|
||||
public:
|
||||
array()
|
||||
: data(0), allocated(0), used(0),
|
||||
free_when_destroyed(true), is_sorted(true)
|
||||
{
|
||||
}
|
||||
|
||||
//! Constructs a array and allocates an initial chunk of memory.
|
||||
//! \param start_count: Amount of elements to allocate.
|
||||
array(u32 start_count)
|
||||
: data(0), allocated(0), used(0),
|
||||
free_when_destroyed(true), is_sorted(true)
|
||||
{
|
||||
reallocate(start_count);
|
||||
}
|
||||
|
||||
|
||||
//! Copy constructor
|
||||
array(const array<T>& other)
|
||||
: data(0)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Destructor. Frees allocated memory, if set_free_when_destroyed
|
||||
//! was not set to false by the user before.
|
||||
~array()
|
||||
{
|
||||
if (free_when_destroyed)
|
||||
delete [] data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Reallocates the array, make it bigger or smaller.
|
||||
//! \param new_size: New size of array.
|
||||
void reallocate(u32 new_size)
|
||||
{
|
||||
T* old_data = data;
|
||||
|
||||
data = new T[new_size];
|
||||
allocated = new_size;
|
||||
|
||||
s32 end = used < new_size ? used : new_size;
|
||||
for (s32 i=0; i<end; ++i)
|
||||
data[i] = old_data[i];
|
||||
|
||||
if (allocated < used)
|
||||
used = allocated;
|
||||
|
||||
delete [] old_data;
|
||||
}
|
||||
|
||||
//! Adds an element at back of array. If the array is to small to
|
||||
//! add this new element, the array is made bigger.
|
||||
//! \param element: Element to add at the back of the array.
|
||||
void push_back(const T& element)
|
||||
{
|
||||
if (used + 1 > allocated)
|
||||
{
|
||||
// reallocate(used * 2 +1);
|
||||
// this doesn't work if the element is in the same array. So
|
||||
// we'll copy the element first to be sure we'll get no data
|
||||
// corruption
|
||||
|
||||
T e;
|
||||
e = element; // copy element
|
||||
reallocate(used * 2 +1); // increase data block
|
||||
data[used++] = e; // push_back
|
||||
is_sorted = false;
|
||||
return;
|
||||
}
|
||||
|
||||
data[used++] = element;
|
||||
is_sorted = false;
|
||||
}
|
||||
|
||||
|
||||
//! Adds an element at the front of the array. If the array is to small to
|
||||
//! add this new element, the array is made bigger. Please note that this
|
||||
//! is slow, because the whole array needs to be copied for this.
|
||||
//! \param element: Element to add at the back of the array.
|
||||
void push_front(const T& element)
|
||||
{
|
||||
if (used + 1 > allocated)
|
||||
reallocate(used * 2 +1);
|
||||
|
||||
for (int i=(int)used; i>0; --i)
|
||||
data[i] = data[i-1];
|
||||
|
||||
data[0] = element;
|
||||
is_sorted = false;
|
||||
++used;
|
||||
}
|
||||
|
||||
|
||||
//! Insert item into array at specified position. Please use this
|
||||
//! only if you know what you are doing (possible performance loss).
|
||||
//! The preferred method of adding elements should be push_back().
|
||||
//! \param element: Element to be inserted
|
||||
//! \param index: Where position to insert the new element.
|
||||
void insert(const T& element, u32 index=0)
|
||||
{
|
||||
_IRR_DEBUG_BREAK_IF(index>used) // access violation
|
||||
|
||||
if (used + 1 > allocated)
|
||||
reallocate(used * 2 +1);
|
||||
|
||||
for (u32 i=used++; i>index; i--)
|
||||
data[i] = data[i-1];
|
||||
|
||||
data[index] = element;
|
||||
is_sorted = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//! Clears the array and deletes all allocated memory.
|
||||
void clear()
|
||||
{
|
||||
delete [] data;
|
||||
data = 0;
|
||||
used = 0;
|
||||
allocated = 0;
|
||||
is_sorted = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Sets pointer to new array, using this as new workspace.
|
||||
//! \param newPointer: Pointer to new array of elements.
|
||||
//! \param size: Size of the new array.
|
||||
void set_pointer(T* newPointer, u32 size)
|
||||
{
|
||||
delete [] data;
|
||||
data = newPointer;
|
||||
allocated = size;
|
||||
used = size;
|
||||
is_sorted = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Sets if the array should delete the memory it used.
|
||||
//! \param f: If true, the array frees the allocated memory in its
|
||||
//! destructor, otherwise not. The default is true.
|
||||
void set_free_when_destroyed(bool f)
|
||||
{
|
||||
free_when_destroyed = f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Sets the size of the array.
|
||||
//! \param usedNow: Amount of elements now used.
|
||||
void set_used(u32 usedNow)
|
||||
{
|
||||
if (allocated < usedNow)
|
||||
reallocate(usedNow);
|
||||
|
||||
used = usedNow;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Assignement operator
|
||||
void operator=(const array<T>& other)
|
||||
{
|
||||
if (data)
|
||||
delete [] data;
|
||||
|
||||
//if (allocated < other.allocated)
|
||||
if (other.allocated == 0)
|
||||
data = 0;
|
||||
else
|
||||
data = new T[other.allocated];
|
||||
|
||||
used = other.used;
|
||||
free_when_destroyed = other.free_when_destroyed;
|
||||
is_sorted = other.is_sorted;
|
||||
allocated = other.allocated;
|
||||
|
||||
for (u32 i=0; i<other.used; ++i)
|
||||
data[i] = other.data[i];
|
||||
}
|
||||
|
||||
|
||||
//! Direct access operator
|
||||
T& operator [](u32 index)
|
||||
{
|
||||
_IRR_DEBUG_BREAK_IF(index>=used) // access violation
|
||||
|
||||
return data[index];
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Direct access operator
|
||||
const T& operator [](u32 index) const
|
||||
{
|
||||
_IRR_DEBUG_BREAK_IF(index>=used) // access violation
|
||||
|
||||
return data[index];
|
||||
}
|
||||
|
||||
//! Gets last frame
|
||||
const T& getLast() const
|
||||
{
|
||||
_IRR_DEBUG_BREAK_IF(!used) // access violation
|
||||
|
||||
return data[used-1];
|
||||
}
|
||||
|
||||
//! Gets last frame
|
||||
T& getLast()
|
||||
{
|
||||
_IRR_DEBUG_BREAK_IF(!used) // access violation
|
||||
|
||||
return data[used-1];
|
||||
}
|
||||
|
||||
|
||||
//! Returns a pointer to the array.
|
||||
//! \return Pointer to the array.
|
||||
T* pointer()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Returns a const pointer to the array.
|
||||
//! \return Pointer to the array.
|
||||
const T* const_pointer() const
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Returns size of used array.
|
||||
//! \return Size of elements in the array.
|
||||
u32 size() const
|
||||
{
|
||||
return used;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Returns amount memory allocated.
|
||||
//! \return Returns amount of memory allocated. The amount of bytes
|
||||
//! allocated would be allocated_size() * sizeof(ElementsUsed);
|
||||
u32 allocated_size() const
|
||||
{
|
||||
return allocated;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Returns true if array is empty
|
||||
//! \return True if the array is empty, false if not.
|
||||
bool empty() const
|
||||
{
|
||||
return used == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Sorts the array using heapsort. There is no additional memory waste and
|
||||
//! the algorithm performs (O) n log n in worst case.
|
||||
void sort()
|
||||
{
|
||||
if (is_sorted || used<2)
|
||||
return;
|
||||
|
||||
heapsort(data, used);
|
||||
is_sorted = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Performs a binary search for an element, returns -1 if not found.
|
||||
//! The array will be sorted before the binary search if it is not
|
||||
//! already sorted.
|
||||
//! \param element: Element to search for.
|
||||
//! \return Returns position of the searched element if it was found,
|
||||
//! otherwise -1 is returned.
|
||||
s32 binary_search(const T& element)
|
||||
{
|
||||
return binary_search(element, 0, used-1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Performs a binary search for an element, returns -1 if not found.
|
||||
//! The array will be sorted before the binary search if it is not
|
||||
//! already sorted.
|
||||
//! \param element: Element to search for.
|
||||
//! \param left: First left index
|
||||
//! \param right: Last right index.
|
||||
//! \return Returns position of the searched element if it was found,
|
||||
//! otherwise -1 is returned.
|
||||
s32 binary_search(const T& element, s32 left, s32 right)
|
||||
{
|
||||
if (!used)
|
||||
return -1;
|
||||
|
||||
sort();
|
||||
|
||||
s32 m;
|
||||
|
||||
do
|
||||
{
|
||||
m = (left+right)>>1;
|
||||
|
||||
if (element < data[m])
|
||||
right = m - 1;
|
||||
else
|
||||
left = m + 1;
|
||||
|
||||
} while((element < data[m] || data[m] < element) && left<=right);
|
||||
|
||||
// this last line equals to:
|
||||
// " while((element != array[m]) && left<=right);"
|
||||
// but we only want to use the '<' operator.
|
||||
// the same in next line, it is "(element == array[m])"
|
||||
|
||||
if (!(element < data[m]) && !(data[m] < element))
|
||||
return m;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//! Finds an element in linear time, which is very slow. Use
|
||||
//! binary_search for faster finding. Only works if =operator is implemented.
|
||||
//! \param element: Element to search for.
|
||||
//! \return Returns position of the searched element if it was found,
|
||||
//! otherwise -1 is returned.
|
||||
s32 linear_search(T& element)
|
||||
{
|
||||
for (u32 i=0; i<used; ++i)
|
||||
if (!(element < data[i]) && !(data[i] < element))
|
||||
return (s32)i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//! Finds an element in linear time, which is very slow. Use
|
||||
//! binary_search for faster finding. Only works if =operator is implemented.
|
||||
//! \param element: Element to search for.
|
||||
//! \return Returns position of the searched element if it was found,
|
||||
//! otherwise -1 is returned.
|
||||
s32 linear_reverse_search(T& element)
|
||||
{
|
||||
for (s32 i=used-1; i>=0; --i)
|
||||
if (data[i] == element)
|
||||
return (s32)i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Erases an element from the array. May be slow, because all elements
|
||||
//! following after the erased element have to be copied.
|
||||
//! \param index: Index of element to be erased.
|
||||
void erase(u32 index)
|
||||
{
|
||||
_IRR_DEBUG_BREAK_IF(index>=used || index<0) // access violation
|
||||
|
||||
for (u32 i=index+1; i<used; ++i)
|
||||
data[i-1] = data[i];
|
||||
|
||||
--used;
|
||||
}
|
||||
|
||||
|
||||
//! Erases some elements from the array. may be slow, because all elements
|
||||
//! following after the erased element have to be copied.
|
||||
//! \param index: Index of the first element to be erased.
|
||||
//! \param count: Amount of elements to be erased.
|
||||
void erase(u32 index, s32 count)
|
||||
{
|
||||
_IRR_DEBUG_BREAK_IF(index>=used || index<0 || count<1 || index+count>used) // access violation
|
||||
|
||||
for (u32 i=index+count; i<used; ++i)
|
||||
data[i-count] = data[i];
|
||||
|
||||
used-= count;
|
||||
}
|
||||
|
||||
|
||||
//! Sets if the array is sorted
|
||||
void set_sorted(bool _is_sorted)
|
||||
{
|
||||
is_sorted = _is_sorted;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
T* data;
|
||||
u32 allocated;
|
||||
u32 used;
|
||||
bool free_when_destroyed;
|
||||
bool is_sorted;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace core
|
||||
} // end namespace irr
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,664 +0,0 @@
|
|||
// Copyright (C) 2002-2005 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine" and the "irrXML" project.
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h
|
||||
|
||||
#ifndef __IRR_STRING_H_INCLUDED__
|
||||
#define __IRR_STRING_H_INCLUDED__
|
||||
|
||||
#include "irrTypes.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace core
|
||||
{
|
||||
|
||||
//! Very simple string class with some useful features.
|
||||
/** string<c8> and string<wchar_t> work both with unicode AND ascii,
|
||||
so you can assign unicode to string<c8> and ascii to string<wchar_t>
|
||||
(and the other way round) if your ever would want to.
|
||||
Note that the conversation between both is not done using an encoding.
|
||||
|
||||
Known bugs:
|
||||
Special characters like 'Ă„', 'Ăś' and 'Ă–' are ignored in the
|
||||
methods make_upper, make_lower and equals_ignore_case.
|
||||
*/
|
||||
template <class T>
|
||||
class string
|
||||
{
|
||||
public:
|
||||
|
||||
//! Default constructor
|
||||
string()
|
||||
: array(0), allocated(1), used(1)
|
||||
{
|
||||
array = new T[1];
|
||||
array[0] = 0x0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Constructor
|
||||
string(const string<T>& other)
|
||||
: array(0), allocated(0), used(0)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
|
||||
//! Constructs a string from an int
|
||||
string(int number)
|
||||
: array(0), allocated(0), used(0)
|
||||
{
|
||||
// store if negative and make positive
|
||||
|
||||
bool negative = false;
|
||||
if (number < 0)
|
||||
{
|
||||
number *= -1;
|
||||
negative = true;
|
||||
}
|
||||
|
||||
// temporary buffer for 16 numbers
|
||||
|
||||
c8 tmpbuf[16];
|
||||
tmpbuf[15] = 0;
|
||||
s32 idx = 15;
|
||||
|
||||
// special case '0'
|
||||
|
||||
if (!number)
|
||||
{
|
||||
tmpbuf[14] = '0';
|
||||
*this = &tmpbuf[14];
|
||||
return;
|
||||
}
|
||||
|
||||
// add numbers
|
||||
|
||||
while(number && idx)
|
||||
{
|
||||
idx--;
|
||||
tmpbuf[idx] = (c8)('0' + (number % 10));
|
||||
number = number / 10;
|
||||
}
|
||||
|
||||
// add sign
|
||||
|
||||
if (negative)
|
||||
{
|
||||
idx--;
|
||||
tmpbuf[idx] = '-';
|
||||
}
|
||||
|
||||
*this = &tmpbuf[idx];
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Constructor for copying a string from a pointer with a given lenght
|
||||
template <class B>
|
||||
string(const B* c, s32 lenght)
|
||||
: array(0), allocated(0), used(0)
|
||||
{
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
allocated = used = lenght+1;
|
||||
array = new T[used];
|
||||
|
||||
for (s32 l = 0; l<lenght; ++l)
|
||||
array[l] = (T)c[l];
|
||||
|
||||
array[lenght] = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Constructor for unicode and ascii strings
|
||||
template <class B>
|
||||
string(const B* c)
|
||||
: array(0),allocated(0), used(0)
|
||||
{
|
||||
*this = c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! destructor
|
||||
~string()
|
||||
{
|
||||
delete [] array;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Assignment operator
|
||||
string<T>& operator=(const string<T>& other)
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
|
||||
delete [] array;
|
||||
allocated = used = other.size()+1;
|
||||
array = new T[used];
|
||||
|
||||
const T* p = other.c_str();
|
||||
for (s32 i=0; i<used; ++i, ++p)
|
||||
array[i] = *p;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Assignment operator for strings, ascii and unicode
|
||||
template <class B>
|
||||
string<T>& operator=(const B* c)
|
||||
{
|
||||
if (!c)
|
||||
{
|
||||
if (!array)
|
||||
{
|
||||
array = new T[1];
|
||||
allocated = 1;
|
||||
used = 1;
|
||||
}
|
||||
array[0] = 0x0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
if ((void*)c == (void*)array)
|
||||
return *this;
|
||||
|
||||
s32 len = 0;
|
||||
const B* p = c;
|
||||
while(*p)
|
||||
{
|
||||
++len;
|
||||
++p;
|
||||
}
|
||||
|
||||
// we'll take the old string for a while, because the new string could be
|
||||
// a part of the current string.
|
||||
T* oldArray = array;
|
||||
|
||||
allocated = used = len+1;
|
||||
array = new T[used];
|
||||
|
||||
for (s32 l = 0; l<len+1; ++l)
|
||||
array[l] = (T)c[l];
|
||||
|
||||
delete [] oldArray;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Add operator for other strings
|
||||
string<T> operator+(const string<T>& other)
|
||||
{
|
||||
string<T> str(*this);
|
||||
str.append(other);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
//! Add operator for strings, ascii and unicode
|
||||
template <class B>
|
||||
string<T> operator+(const B* c)
|
||||
{
|
||||
string<T> str(*this);
|
||||
str.append(c);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Direct access operator
|
||||
T& operator [](const s32 index) const
|
||||
{
|
||||
_IRR_DEBUG_BREAK_IF(index>=used) // bad index
|
||||
|
||||
return array[index];
|
||||
}
|
||||
|
||||
|
||||
//! Comparison operator
|
||||
bool operator ==(const T* str) const
|
||||
{
|
||||
int i;
|
||||
for(i=0; array[i] && str[i]; ++i)
|
||||
if (array[i] != str[i])
|
||||
return false;
|
||||
|
||||
return !array[i] && !str[i];
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Comparison operator
|
||||
bool operator ==(const string<T>& other) const
|
||||
{
|
||||
for(s32 i=0; array[i] && other.array[i]; ++i)
|
||||
if (array[i] != other.array[i])
|
||||
return false;
|
||||
|
||||
return used == other.used;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Is smaller operator
|
||||
bool operator <(const string<T>& other) const
|
||||
{
|
||||
for(s32 i=0; array[i] && other.array[i]; ++i)
|
||||
if (array[i] != other.array[i])
|
||||
return (array[i] < other.array[i]);
|
||||
|
||||
return used < other.used;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Equals not operator
|
||||
bool operator !=(const string<T>& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Returns length of string
|
||||
/** \return Returns length of the string in characters. */
|
||||
s32 size() const
|
||||
{
|
||||
return used-1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Returns character string
|
||||
/** \return Returns pointer to C-style zero terminated string. */
|
||||
const T* c_str() const
|
||||
{
|
||||
return array;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Makes the string lower case.
|
||||
void make_lower()
|
||||
{
|
||||
const T A = (T)'A';
|
||||
const T Z = (T)'Z';
|
||||
const T diff = (T)'a' - A;
|
||||
|
||||
for (s32 i=0; i<used; ++i)
|
||||
{
|
||||
if (array[i]>=A && array[i]<=Z)
|
||||
array[i] += diff;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Makes the string upper case.
|
||||
void make_upper()
|
||||
{
|
||||
const T a = (T)'a';
|
||||
const T z = (T)'z';
|
||||
const T diff = (T)'A' - a;
|
||||
|
||||
for (s32 i=0; i<used; ++i)
|
||||
{
|
||||
if (array[i]>=a && array[i]<=z)
|
||||
array[i] += diff;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Compares the string ignoring case.
|
||||
/** \param other: Other string to compare.
|
||||
\return Returns true if the string are equal ignoring case. */
|
||||
bool equals_ignore_case(const string<T>& other) const
|
||||
{
|
||||
for(s32 i=0; array[i] && other[i]; ++i)
|
||||
if (toLower(array[i]) != toLower(other[i]))
|
||||
return false;
|
||||
|
||||
return used == other.used;
|
||||
}
|
||||
|
||||
|
||||
//! compares the first n characters of the strings
|
||||
bool equalsn(const string<T>& other, int len)
|
||||
{
|
||||
int i;
|
||||
for(i=0; array[i] && other[i] && i < len; ++i)
|
||||
if (array[i] != other[i])
|
||||
return false;
|
||||
|
||||
// if one (or both) of the strings was smaller then they
|
||||
// are only equal if they have the same lenght
|
||||
return (i == len) || (used == other.used);
|
||||
}
|
||||
|
||||
|
||||
//! compares the first n characters of the strings
|
||||
bool equalsn(const T* str, int len)
|
||||
{
|
||||
int i;
|
||||
for(i=0; array[i] && str[i] && i < len; ++i)
|
||||
if (array[i] != str[i])
|
||||
return false;
|
||||
|
||||
// if one (or both) of the strings was smaller then they
|
||||
// are only equal if they have the same lenght
|
||||
return (i == len) || (array[i] == 0 && str[i] == 0);
|
||||
}
|
||||
|
||||
|
||||
//! Appends a character to this string
|
||||
/** \param character: Character to append. */
|
||||
void append(T character)
|
||||
{
|
||||
if (used + 1 > allocated)
|
||||
reallocate((s32)used + 1);
|
||||
|
||||
used += 1;
|
||||
|
||||
array[used-2] = character;
|
||||
array[used-1] = 0;
|
||||
}
|
||||
|
||||
//! Appends a string to this string
|
||||
/** \param other: String to append. */
|
||||
void append(const string<T>& other)
|
||||
{
|
||||
--used;
|
||||
|
||||
s32 len = other.size();
|
||||
|
||||
if (used + len + 1 > allocated)
|
||||
reallocate((s32)used + (s32)len + 1);
|
||||
|
||||
for (s32 l=0; l<len+1; ++l)
|
||||
array[l+used] = other[l];
|
||||
|
||||
used = used + len + 1;
|
||||
}
|
||||
|
||||
|
||||
//! Appends a string of the length l to this string.
|
||||
/** \param other: other String to append to this string.
|
||||
\param length: How much characters of the other string to add to this one. */
|
||||
void append(const string<T>& other, s32 length)
|
||||
{
|
||||
s32 len = other.size();
|
||||
|
||||
if (len < length)
|
||||
{
|
||||
append(other);
|
||||
return;
|
||||
}
|
||||
|
||||
len = length;
|
||||
--used;
|
||||
|
||||
if (used + len > allocated)
|
||||
reallocate((s32)used + (s32)len);
|
||||
|
||||
for (s32 l=0; l<len; ++l)
|
||||
array[l+used] = other[l];
|
||||
|
||||
used = used + len;
|
||||
}
|
||||
|
||||
|
||||
//! Reserves some memory.
|
||||
/** \param count: Amount of characters to reserve. */
|
||||
void reserve(s32 count)
|
||||
{
|
||||
if (count < allocated)
|
||||
return;
|
||||
|
||||
reallocate(count);
|
||||
}
|
||||
|
||||
|
||||
//! finds first occurrence of character in string
|
||||
/** \param c: Character to search for.
|
||||
\return Returns position where the character has been found,
|
||||
or -1 if not found. */
|
||||
s32 findFirst(T c) const
|
||||
{
|
||||
for (s32 i=0; i<used; ++i)
|
||||
if (array[i] == c)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//! finds first occurrence of a character of a list in string
|
||||
/** \param c: List of strings to find. For example if the method
|
||||
should find the first occurance of 'a' or 'b', this parameter should be "ab".
|
||||
\param count: Amount of characters in the list. Ususally,
|
||||
this should be strlen(ofParameter1)
|
||||
\return Returns position where one of the character has been found,
|
||||
or -1 if not found. */
|
||||
s32 findFirstChar(T* c, int count) const
|
||||
{
|
||||
for (s32 i=0; i<used; ++i)
|
||||
for (int j=0; j<count; ++j)
|
||||
if (array[i] == c[j])
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//! Finds first position of a character not in a given list.
|
||||
/** \param c: List of characters not to find. For example if the method
|
||||
should find the first occurance of a character not 'a' or 'b', this parameter should be "ab".
|
||||
\param count: Amount of characters in the list. Ususally,
|
||||
this should be strlen(ofParameter1)
|
||||
\return Returns position where the character has been found,
|
||||
or -1 if not found. */
|
||||
template <class B>
|
||||
s32 findFirstCharNotInList(B* c, int count) const
|
||||
{
|
||||
for (int i=0; i<used; ++i)
|
||||
{
|
||||
int j;
|
||||
for (j=0; j<count; ++j)
|
||||
if (array[i] == c[j])
|
||||
break;
|
||||
|
||||
if (j==count)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//! Finds last position of a character not in a given list.
|
||||
/** \param c: List of characters not to find. For example if the method
|
||||
should find the first occurance of a character not 'a' or 'b', this parameter should be "ab".
|
||||
\param count: Amount of characters in the list. Ususally,
|
||||
this should be strlen(ofParameter1)
|
||||
\return Returns position where the character has been found,
|
||||
or -1 if not found. */
|
||||
template <class B>
|
||||
s32 findLastCharNotInList(B* c, int count) const
|
||||
{
|
||||
for (int i=used-2; i>=0; --i)
|
||||
{
|
||||
int j;
|
||||
for (j=0; j<count; ++j)
|
||||
if (array[i] == c[j])
|
||||
break;
|
||||
|
||||
if (j==count)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//! finds next occurrence of character in string
|
||||
/** \param c: Character to search for.
|
||||
\param startPos: Position in string to start searching.
|
||||
\return Returns position where the character has been found,
|
||||
or -1 if not found. */
|
||||
s32 findNext(T c, s32 startPos) const
|
||||
{
|
||||
for (s32 i=startPos; i<used; ++i)
|
||||
if (array[i] == c)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//! finds last occurrence of character in string
|
||||
//! \param c: Character to search for.
|
||||
//! \return Returns position where the character has been found,
|
||||
//! or -1 if not found.
|
||||
s32 findLast(T c) const
|
||||
{
|
||||
for (s32 i=used-1; i>=0; --i)
|
||||
if (array[i] == c)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//! Returns a substring
|
||||
//! \param begin: Start of substring.
|
||||
//! \param length: Length of substring.
|
||||
string<T> subString(s32 begin, s32 length)
|
||||
{
|
||||
if (length <= 0)
|
||||
return string<T>("");
|
||||
|
||||
string<T> o;
|
||||
o.reserve(length+1);
|
||||
|
||||
for (s32 i=0; i<length; ++i)
|
||||
o.array[i] = array[i+begin];
|
||||
|
||||
o.array[length] = 0;
|
||||
o.used = o.allocated;
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
void operator += (T c)
|
||||
{
|
||||
append(c);
|
||||
}
|
||||
|
||||
void operator += (const string<T>& other)
|
||||
{
|
||||
append(other);
|
||||
}
|
||||
|
||||
void operator += (int i)
|
||||
{
|
||||
append(string<T>(i));
|
||||
}
|
||||
|
||||
//! replaces all characters of a special type with another one
|
||||
void replace(T toReplace, T replaceWith)
|
||||
{
|
||||
for (s32 i=0; i<used; ++i)
|
||||
if (array[i] == toReplace)
|
||||
array[i] = replaceWith;
|
||||
}
|
||||
|
||||
//! trims the string.
|
||||
/** Removes whitespace from begin and end of the string. */
|
||||
void trim()
|
||||
{
|
||||
const char whitespace[] = " \t\n";
|
||||
const int whitespacecount = 3;
|
||||
|
||||
// find start and end of real string without whitespace
|
||||
int begin = findFirstCharNotInList(whitespace, whitespacecount);
|
||||
if (begin == -1)
|
||||
return;
|
||||
|
||||
int end = findLastCharNotInList(whitespace, whitespacecount);
|
||||
if (end == -1)
|
||||
return;
|
||||
|
||||
*this = subString(begin, (end +1) - begin);
|
||||
}
|
||||
|
||||
|
||||
//! Erases a character from the string. May be slow, because all elements
|
||||
//! following after the erased element have to be copied.
|
||||
//! \param index: Index of element to be erased.
|
||||
void erase(int index)
|
||||
{
|
||||
_IRR_DEBUG_BREAK_IF(index>=used || index<0) // access violation
|
||||
|
||||
for (int i=index+1; i<used; ++i)
|
||||
array[i-1] = array[i];
|
||||
|
||||
--used;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
//! Returns a character converted to lower case
|
||||
T toLower(const T& t) const
|
||||
{
|
||||
if (t>=(T)'A' && t<=(T)'Z')
|
||||
return t + ((T)'a' - (T)'A');
|
||||
else
|
||||
return t;
|
||||
}
|
||||
|
||||
//! Reallocate the array, make it bigger or smaler
|
||||
void reallocate(s32 new_size)
|
||||
{
|
||||
T* old_array = array;
|
||||
|
||||
array = new T[new_size];
|
||||
allocated = new_size;
|
||||
|
||||
s32 amount = used < new_size ? used : new_size;
|
||||
for (s32 i=0; i<amount; ++i)
|
||||
array[i] = old_array[i];
|
||||
|
||||
if (allocated < used)
|
||||
used = allocated;
|
||||
|
||||
delete [] old_array;
|
||||
}
|
||||
|
||||
|
||||
//--- member variables
|
||||
|
||||
T* array;
|
||||
s32 allocated;
|
||||
s32 used;
|
||||
};
|
||||
|
||||
|
||||
//! Typedef for character strings
|
||||
typedef string<irr::c8> stringc;
|
||||
|
||||
//! Typedef for wide character strings
|
||||
typedef string<wchar_t> stringw;
|
||||
|
||||
} // end namespace core
|
||||
} // end namespace irr
|
||||
|
||||
#endif
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
// Copyright (C) 2002-2005 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#ifndef __IRR_TYPES_H_INCLUDED__
|
||||
#define __IRR_TYPES_H_INCLUDED__
|
||||
|
||||
namespace irr
|
||||
{
|
||||
|
||||
//! 8 bit unsigned variable.
|
||||
/** This is a typedef for unsigned char, it ensures portability of the engine. */
|
||||
typedef unsigned char u8;
|
||||
|
||||
//! 8 bit signed variable.
|
||||
/** This is a typedef for signed char, it ensures portability of the engine. */
|
||||
typedef signed char s8;
|
||||
|
||||
//! 8 bit character variable.
|
||||
/** This is a typedef for char, it ensures portability of the engine. */
|
||||
typedef char c8;
|
||||
|
||||
|
||||
|
||||
//! 16 bit unsigned variable.
|
||||
/** This is a typedef for unsigned short, it ensures portability of the engine. */
|
||||
typedef unsigned short u16;
|
||||
|
||||
//! 16 bit signed variable.
|
||||
/** This is a typedef for signed short, it ensures portability of the engine. */
|
||||
typedef signed short s16;
|
||||
|
||||
|
||||
|
||||
//! 32 bit unsigned variable.
|
||||
/** This is a typedef for unsigned int, it ensures portability of the engine. */
|
||||
typedef unsigned int u32;
|
||||
|
||||
//! 32 bit signed variable.
|
||||
/** This is a typedef for signed int, it ensures portability of the engine. */
|
||||
typedef signed int s32;
|
||||
|
||||
|
||||
|
||||
// 64 bit signed variable.
|
||||
// This is a typedef for __int64, it ensures portability of the engine.
|
||||
// This type is currently not used by the engine and not supported by compilers
|
||||
// other than Microsoft Compilers, so it is outcommented.
|
||||
//typedef __int64 s64;
|
||||
|
||||
|
||||
|
||||
//! 32 bit floating point variable.
|
||||
/** This is a typedef for float, it ensures portability of the engine. */
|
||||
typedef float f32;
|
||||
|
||||
//! 64 bit floating point variable.
|
||||
/** This is a typedef for double, it ensures portability of the engine. */
|
||||
typedef double f64;
|
||||
|
||||
|
||||
} // end namespace
|
||||
|
||||
|
||||
// define the wchar_t type if not already built in.
|
||||
#ifdef _MSC_VER
|
||||
#ifndef _WCHAR_T_DEFINED
|
||||
//! A 16 bit wide character type.
|
||||
/**
|
||||
Defines the wchar_t-type.
|
||||
In VS6, its not possible to tell
|
||||
the standard compiler to treat wchar_t as a built-in type, and
|
||||
sometimes we just don't want to include the huge stdlib.h or wchar.h,
|
||||
so we'll use this.
|
||||
*/
|
||||
typedef unsigned short wchar_t;
|
||||
#define _WCHAR_T_DEFINED
|
||||
#endif // wchar is not defined
|
||||
#endif // microsoft compiler
|
||||
|
||||
//! define a break macro for debugging only in Win32 mode.
|
||||
// WORKAROUND (assimp): remove __asm
|
||||
#if defined(WIN32) && defined(_MSC_VER) && defined(_DEBUG)
|
||||
#if defined(_M_IX86)
|
||||
#define _IRR_DEBUG_BREAK_IF( _CONDITION_ ) /*if (_CONDITION_) {_asm int 3}*/
|
||||
#else
|
||||
#define _IRR_DEBUG_BREAK_IF( _CONDITION_ )
|
||||
#endif
|
||||
#else
|
||||
#define _IRR_DEBUG_BREAK_IF( _CONDITION_ )
|
||||
#endif
|
||||
|
||||
//! Defines a small statement to work around a microsoft compiler bug.
|
||||
/** The microsft compiler 7.0 - 7.1 has a bug:
|
||||
When you call unmanaged code that returns a bool type value of false from managed code,
|
||||
the return value may appear as true. See
|
||||
http://support.microsoft.com/default.aspx?kbid=823071 for details.
|
||||
Compiler version defines: VC6.0 : 1200, VC7.0 : 1300, VC7.1 : 1310, VC8.0 : 1400*/
|
||||
|
||||
// WORKAROUND (assimp): remove __asm
|
||||
#if defined(WIN32) && defined(_MSC_VER) && (_MSC_VER > 1299) && (_MSC_VER < 1400)
|
||||
#define _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX /*__asm mov eax,100*/
|
||||
#else
|
||||
#define _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX
|
||||
#endif // _IRR_MANAGED_MARSHALLING_BUGFIX
|
||||
|
||||
#endif // __IRR_TYPES_H_INCLUDED__
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
// Copyright (C) 2002-2005 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine" and the "irrXML" project.
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h and/or irrXML.h
|
||||
|
||||
// Need to include Assimp, too. We're using Assimp's version of fast_atof
|
||||
// so we need stdint.h. But no PCH.
|
||||
|
||||
|
||||
#include "irrXML.h"
|
||||
#include "irrString.h"
|
||||
#include "irrArray.h"
|
||||
//#include <assimp/fast_atof.h>
|
||||
#include "CXMLReaderImpl.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
//! Implementation of the file read callback for ordinary files
|
||||
class IRRXML_API CFileReadCallBack : public IFileReadCallBack
|
||||
{
|
||||
public:
|
||||
|
||||
//! construct from filename
|
||||
CFileReadCallBack(const char* filename)
|
||||
: File(0), Size(0), Close(true)
|
||||
{
|
||||
// open file
|
||||
File = fopen(filename, "rb");
|
||||
|
||||
if (File)
|
||||
getFileSize();
|
||||
}
|
||||
|
||||
//! construct from FILE pointer
|
||||
CFileReadCallBack(FILE* file)
|
||||
: File(file), Size(0), Close(false)
|
||||
{
|
||||
if (File)
|
||||
getFileSize();
|
||||
}
|
||||
|
||||
//! destructor
|
||||
virtual ~CFileReadCallBack()
|
||||
{
|
||||
if (Close && File)
|
||||
fclose(File);
|
||||
}
|
||||
|
||||
//! Reads an amount of bytes from the file.
|
||||
virtual int read(void* buffer, int sizeToRead)
|
||||
{
|
||||
if (!File)
|
||||
return 0;
|
||||
|
||||
return (int)fread(buffer, 1, sizeToRead, File);
|
||||
}
|
||||
|
||||
//! Returns size of file in bytes
|
||||
virtual int getSize()
|
||||
{
|
||||
return Size;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//! retrieves the file size of the open file
|
||||
void getFileSize()
|
||||
{
|
||||
fseek(File, 0, SEEK_END);
|
||||
Size = ftell(File);
|
||||
fseek(File, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
FILE* File;
|
||||
int Size;
|
||||
bool Close;
|
||||
|
||||
}; // end class CFileReadCallBack
|
||||
|
||||
|
||||
|
||||
// FACTORY FUNCTIONS:
|
||||
|
||||
|
||||
//! Creates an instance of an UFT-8 or ASCII character xml parser.
|
||||
IrrXMLReader* createIrrXMLReader(const char* filename)
|
||||
{
|
||||
return new CXMLReaderImpl<char, IXMLBase>(new CFileReadCallBack(filename));
|
||||
}
|
||||
|
||||
|
||||
//! Creates an instance of an UFT-8 or ASCII character xml parser.
|
||||
IrrXMLReader* createIrrXMLReader(FILE* file)
|
||||
{
|
||||
return new CXMLReaderImpl<char, IXMLBase>(new CFileReadCallBack(file));
|
||||
}
|
||||
|
||||
|
||||
//! Creates an instance of an UFT-8 or ASCII character xml parser.
|
||||
IrrXMLReader* createIrrXMLReader(IFileReadCallBack* callback)
|
||||
{
|
||||
return new CXMLReaderImpl<char, IXMLBase>(callback, false);
|
||||
}
|
||||
|
||||
|
||||
//! Creates an instance of an UTF-16 xml parser.
|
||||
IrrXMLReaderUTF16* createIrrXMLReaderUTF16(const char* filename)
|
||||
{
|
||||
return new CXMLReaderImpl<char16, IXMLBase>(new CFileReadCallBack(filename));
|
||||
}
|
||||
|
||||
|
||||
//! Creates an instance of an UTF-16 xml parser.
|
||||
IrrXMLReaderUTF16* createIrrXMLReaderUTF16(FILE* file)
|
||||
{
|
||||
return new CXMLReaderImpl<char16, IXMLBase>(new CFileReadCallBack(file));
|
||||
}
|
||||
|
||||
|
||||
//! Creates an instance of an UTF-16 xml parser.
|
||||
IrrXMLReaderUTF16* createIrrXMLReaderUTF16(IFileReadCallBack* callback)
|
||||
{
|
||||
return new CXMLReaderImpl<char16, IXMLBase>(callback, false);
|
||||
}
|
||||
|
||||
|
||||
//! Creates an instance of an UTF-32 xml parser.
|
||||
IrrXMLReaderUTF32* createIrrXMLReaderUTF32(const char* filename)
|
||||
{
|
||||
return new CXMLReaderImpl<char32, IXMLBase>(new CFileReadCallBack(filename));
|
||||
}
|
||||
|
||||
|
||||
//! Creates an instance of an UTF-32 xml parser.
|
||||
IrrXMLReaderUTF32* createIrrXMLReaderUTF32(FILE* file)
|
||||
{
|
||||
return new CXMLReaderImpl<char32, IXMLBase>(new CFileReadCallBack(file));
|
||||
}
|
||||
|
||||
|
||||
//! Creates an instance of an UTF-32 xml parser.
|
||||
IrrXMLReaderUTF32* createIrrXMLReaderUTF32(IFileReadCallBack* callback)
|
||||
{
|
||||
return new CXMLReaderImpl<char32, IXMLBase>(callback, false);
|
||||
}
|
||||
|
||||
|
||||
} // end namespace io
|
||||
} // end namespace irr
|
|
@ -1,546 +0,0 @@
|
|||
// Copyright (C) 2002-2005 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine" and the "irrXML" project.
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h and/or irrXML.h
|
||||
|
||||
#ifndef __IRR_XML_H_INCLUDED__
|
||||
#define __IRR_XML_H_INCLUDED__
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# define IRRXML_API __declspec(dllexport)
|
||||
#else
|
||||
# define IRRXML_API __attribute__ ((visibility("default")))
|
||||
#endif // _WIN32
|
||||
|
||||
/** \mainpage irrXML 1.2 API documentation
|
||||
<div align="center"><img src="logobig.png" ></div>
|
||||
|
||||
\section intro Introduction
|
||||
|
||||
Welcome to the irrXML API documentation.
|
||||
Here you'll find any information you'll need to develop applications with
|
||||
irrXML. If you look for a tutorial on how to start, take a look at the \ref irrxmlexample,
|
||||
at the homepage of irrXML at <A HREF="http://xml.irrlicht3d.org" >xml.irrlicht3d.org</A>
|
||||
or into the SDK in the directory \example.
|
||||
|
||||
irrXML is intended to be a high speed and easy-to-use XML Parser for C++, and
|
||||
this documentation is an important part of it. If you have any questions or
|
||||
suggestions, just send a email to the author of the engine, Nikolaus Gebhardt
|
||||
(niko (at) irrlicht3d.org). For more informations about this parser, see \ref history.
|
||||
|
||||
\section features Features
|
||||
|
||||
irrXML provides forward-only, read-only
|
||||
access to a stream of non validated XML data. It was fully implemented by
|
||||
Nikolaus Gebhardt. Its current features are:
|
||||
|
||||
- It it fast as lighting and has very low memory usage. It was
|
||||
developed with the intention of being used in 3D games, as it already has been.
|
||||
- irrXML is very small: It only consists of 60 KB of code and can be added easily
|
||||
to your existing project.
|
||||
- Of course, it is platform independent and works with lots of compilers.
|
||||
- It is able to parse ASCII, UTF-8, UTF-16 and UTF-32 text files, both in
|
||||
little and big endian format.
|
||||
- Independent of the input file format, the parser can return all strings in ASCII, UTF-8,
|
||||
UTF-16 and UTF-32 format.
|
||||
- With its optional file access abstraction it has the advantage that it can read not
|
||||
only from files but from any type of data (memory, network, ...). For example when
|
||||
used with the Irrlicht Engine, it directly reads from compressed .zip files.
|
||||
- Just like the Irrlicht Engine for which it was originally created, it is extremely easy
|
||||
to use.
|
||||
- It has no external dependencies, it does not even need the STL.
|
||||
|
||||
Although irrXML has some strenghts, it currently also has the following limitations:
|
||||
|
||||
- The input xml file is not validated and assumed to be correct.
|
||||
|
||||
\section irrxmlexample Example
|
||||
|
||||
The following code demonstrates the basic usage of irrXML. A simple xml
|
||||
file like this is parsed:
|
||||
\code
|
||||
<?xml version="1.0"?>
|
||||
<config>
|
||||
<!-- This is a config file for the mesh viewer -->
|
||||
<model file="dwarf.dea" />
|
||||
<messageText caption="Irrlicht Engine Mesh Viewer">
|
||||
Welcome to the Mesh Viewer of the "Irrlicht Engine".
|
||||
</messageText>
|
||||
</config>
|
||||
\endcode
|
||||
|
||||
The code for parsing this file would look like this:
|
||||
\code
|
||||
#include <irrXML.h>
|
||||
using namespace irr; // irrXML is located in the namespace irr::io
|
||||
using namespace io;
|
||||
|
||||
#include <string> // we use STL strings to store data in this example
|
||||
|
||||
void main()
|
||||
{
|
||||
// create the reader using one of the factory functions
|
||||
|
||||
IrrXMLReader* xml = createIrrXMLReader("config.xml");
|
||||
|
||||
// strings for storing the data we want to get out of the file
|
||||
std::string modelFile;
|
||||
std::string messageText;
|
||||
std::string caption;
|
||||
|
||||
// parse the file until end reached
|
||||
|
||||
while(xml && xml->read())
|
||||
{
|
||||
switch(xml->getNodeType())
|
||||
{
|
||||
case EXN_TEXT:
|
||||
// in this xml file, the only text which occurs is the messageText
|
||||
messageText = xml->getNodeData();
|
||||
break;
|
||||
case EXN_ELEMENT:
|
||||
{
|
||||
if (!strcmp("model", xml->getNodeName()))
|
||||
modelFile = xml->getAttributeValue("file");
|
||||
else
|
||||
if (!strcmp("messageText", xml->getNodeName()))
|
||||
caption = xml->getAttributeValue("caption");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// delete the xml parser after usage
|
||||
delete xml;
|
||||
}
|
||||
\endcode
|
||||
|
||||
\section howto How to use
|
||||
|
||||
Simply add the source files in the /src directory of irrXML to your project. Done.
|
||||
|
||||
\section license License
|
||||
|
||||
The irrXML license is based on the zlib license. Basicly, this means you can do with
|
||||
irrXML whatever you want:
|
||||
|
||||
Copyright (C) 2002-2005 Nikolaus Gebhardt
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
\section history History
|
||||
|
||||
As lots of references in this documentation and the source show, this xml
|
||||
parser has originally been a part of the
|
||||
<A HREF="http://irrlicht.sourceforge.net" >Irrlicht Engine</A>. But because
|
||||
the parser has become very useful with the latest release, people asked for a
|
||||
separate version of it, to be able to use it in non Irrlicht projects. With
|
||||
irrXML 1.0, this has now been done.
|
||||
*/
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
//! Enumeration of all supported source text file formats
|
||||
enum ETEXT_FORMAT
|
||||
{
|
||||
//! ASCII, file without byte order mark, or not a text file
|
||||
ETF_ASCII,
|
||||
|
||||
//! UTF-8 format
|
||||
ETF_UTF8,
|
||||
|
||||
//! UTF-16 format, big endian
|
||||
ETF_UTF16_BE,
|
||||
|
||||
//! UTF-16 format, little endian
|
||||
ETF_UTF16_LE,
|
||||
|
||||
//! UTF-32 format, big endian
|
||||
ETF_UTF32_BE,
|
||||
|
||||
//! UTF-32 format, little endian
|
||||
ETF_UTF32_LE
|
||||
};
|
||||
|
||||
|
||||
//! Enumeration for all xml nodes which are parsed by IrrXMLReader
|
||||
enum EXML_NODE
|
||||
{
|
||||
//! No xml node. This is usually the node if you did not read anything yet.
|
||||
EXN_NONE,
|
||||
|
||||
//! A xml element, like <foo>
|
||||
EXN_ELEMENT,
|
||||
|
||||
//! End of an xml element, like </foo>
|
||||
EXN_ELEMENT_END,
|
||||
|
||||
//! Text within a xml element: <foo> this is the text. </foo>
|
||||
EXN_TEXT,
|
||||
|
||||
//! An xml comment like <!-- I am a comment --> or a DTD definition.
|
||||
EXN_COMMENT,
|
||||
|
||||
//! An xml cdata section like <![CDATA[ this is some CDATA ]]>
|
||||
EXN_CDATA,
|
||||
|
||||
//! Unknown element.
|
||||
EXN_UNKNOWN
|
||||
};
|
||||
|
||||
//! Callback class for file read abstraction.
|
||||
/** With this, it is possible to make the xml parser read in other things
|
||||
than just files. The Irrlicht engine is using this for example to
|
||||
read xml from compressed .zip files. To make the parser read in
|
||||
any other data, derive a class from this interface, implement the
|
||||
two methods to read your data and give a pointer to an instance of
|
||||
your implementation when calling createIrrXMLReader(),
|
||||
createIrrXMLReaderUTF16() or createIrrXMLReaderUTF32() */
|
||||
class IRRXML_API IFileReadCallBack
|
||||
{
|
||||
public:
|
||||
|
||||
//! virtual destructor
|
||||
virtual ~IFileReadCallBack() {};
|
||||
|
||||
//! Reads an amount of bytes from the file.
|
||||
/** \param buffer: Pointer to buffer where to read bytes will be written to.
|
||||
\param sizeToRead: Amount of bytes to read from the file.
|
||||
\return Returns how much bytes were read. */
|
||||
virtual int read(void* buffer, int sizeToRead) = 0;
|
||||
|
||||
//! Returns size of file in bytes
|
||||
virtual int getSize() = 0;
|
||||
};
|
||||
|
||||
//! Empty class to be used as parent class for IrrXMLReader.
|
||||
/** If you need another class as base class for the xml reader, you can do this by creating
|
||||
the reader using for example new CXMLReaderImpl<char, YourBaseClass>(yourcallback);
|
||||
The Irrlicht Engine for example needs IUnknown as base class for every object to
|
||||
let it automaticly reference countend, hence it replaces IXMLBase with IUnknown.
|
||||
See irrXML.cpp on how this can be done in detail. */
|
||||
class IXMLBase
|
||||
{
|
||||
};
|
||||
|
||||
//! Interface providing easy read access to a XML file.
|
||||
/** You can create an instance of this reader using one of the factory functions
|
||||
createIrrXMLReader(), createIrrXMLReaderUTF16() and createIrrXMLReaderUTF32().
|
||||
If using the parser from the Irrlicht Engine, please use IFileSystem::createXMLReader()
|
||||
instead.
|
||||
For a detailed intro how to use the parser, see \ref irrxmlexample and \ref features.
|
||||
|
||||
The typical usage of this parser looks like this:
|
||||
\code
|
||||
#include <irrXML.h>
|
||||
using namespace irr; // irrXML is located in the namespace irr::io
|
||||
using namespace io;
|
||||
|
||||
void main()
|
||||
{
|
||||
// create the reader using one of the factory functions
|
||||
IrrXMLReader* xml = createIrrXMLReader("config.xml");
|
||||
|
||||
if (xml == 0)
|
||||
return; // file could not be opened
|
||||
|
||||
// parse the file until end reached
|
||||
while(xml->read())
|
||||
{
|
||||
// based on xml->getNodeType(), do something.
|
||||
}
|
||||
|
||||
// delete the xml parser after usage
|
||||
delete xml;
|
||||
}
|
||||
\endcode
|
||||
See \ref irrxmlexample for a more detailed example.
|
||||
*/
|
||||
template<class char_type, class super_class>
|
||||
class IIrrXMLReader : public super_class
|
||||
{
|
||||
public:
|
||||
|
||||
//! Destructor
|
||||
virtual ~IIrrXMLReader() {};
|
||||
|
||||
//! Reads forward to the next xml node.
|
||||
/** \return Returns false, if there was no further node. */
|
||||
virtual bool read() = 0;
|
||||
|
||||
//! Returns the type of the current XML node.
|
||||
virtual EXML_NODE getNodeType() const = 0;
|
||||
|
||||
//! Returns attribute count of the current XML node.
|
||||
/** This is usually
|
||||
non null if the current node is EXN_ELEMENT, and the element has attributes.
|
||||
\return Returns amount of attributes of this xml node. */
|
||||
virtual int getAttributeCount() const = 0;
|
||||
|
||||
//! Returns name of an attribute.
|
||||
/** \param idx: Zero based index, should be something between 0 and getAttributeCount()-1.
|
||||
\return Name of the attribute, 0 if an attribute with this index does not exist. */
|
||||
virtual const char_type* getAttributeName(int idx) const = 0;
|
||||
|
||||
//! Returns the value of an attribute.
|
||||
/** \param idx: Zero based index, should be something between 0 and getAttributeCount()-1.
|
||||
\return Value of the attribute, 0 if an attribute with this index does not exist. */
|
||||
virtual const char_type* getAttributeValue(int idx) const = 0;
|
||||
|
||||
//! Returns the value of an attribute.
|
||||
/** \param name: Name of the attribute.
|
||||
\return Value of the attribute, 0 if an attribute with this name does not exist. */
|
||||
virtual const char_type* getAttributeValue(const char_type* name) const = 0;
|
||||
|
||||
//! Returns the value of an attribute in a safe way.
|
||||
/** Like getAttributeValue(), but does not
|
||||
return 0 if the attribute does not exist. An empty string ("") is returned then.
|
||||
\param name: Name of the attribute.
|
||||
\return Value of the attribute, and "" if an attribute with this name does not exist */
|
||||
virtual const char_type* getAttributeValueSafe(const char_type* name) const = 0;
|
||||
|
||||
//! Returns the value of an attribute as integer.
|
||||
/** \param name Name of the attribute.
|
||||
\return Value of the attribute as integer, and 0 if an attribute with this name does not exist or
|
||||
the value could not be interpreted as integer. */
|
||||
virtual int getAttributeValueAsInt(const char_type* name) const = 0;
|
||||
|
||||
//! Returns the value of an attribute as integer.
|
||||
/** \param idx: Zero based index, should be something between 0 and getAttributeCount()-1.
|
||||
\return Value of the attribute as integer, and 0 if an attribute with this index does not exist or
|
||||
the value could not be interpreted as integer. */
|
||||
virtual int getAttributeValueAsInt(int idx) const = 0;
|
||||
|
||||
//! Returns the value of an attribute as float.
|
||||
/** \param name: Name of the attribute.
|
||||
\return Value of the attribute as float, and 0 if an attribute with this name does not exist or
|
||||
the value could not be interpreted as float. */
|
||||
virtual float getAttributeValueAsFloat(const char_type* name) const = 0;
|
||||
|
||||
//! Returns the value of an attribute as float.
|
||||
/** \param idx: Zero based index, should be something between 0 and getAttributeCount()-1.
|
||||
\return Value of the attribute as float, and 0 if an attribute with this index does not exist or
|
||||
the value could not be interpreted as float. */
|
||||
virtual float getAttributeValueAsFloat(int idx) const = 0;
|
||||
|
||||
//! Returns the name of the current node.
|
||||
/** Only non null, if the node type is EXN_ELEMENT.
|
||||
\return Name of the current node or 0 if the node has no name. */
|
||||
virtual const char_type* getNodeName() const = 0;
|
||||
|
||||
//! Returns data of the current node.
|
||||
/** Only non null if the node has some
|
||||
data and it is of type EXN_TEXT or EXN_UNKNOWN. */
|
||||
virtual const char_type* getNodeData() const = 0;
|
||||
|
||||
//! Returns if an element is an empty element, like <foo />
|
||||
virtual bool isEmptyElement() const = 0;
|
||||
|
||||
//! Returns format of the source xml file.
|
||||
/** It is not necessary to use
|
||||
this method because the parser will convert the input file format
|
||||
to the format wanted by the user when creating the parser. This
|
||||
method is useful to get/display additional informations. */
|
||||
virtual ETEXT_FORMAT getSourceFormat() const = 0;
|
||||
|
||||
//! Returns format of the strings returned by the parser.
|
||||
/** This will be UTF8 for example when you created a parser with
|
||||
IrrXMLReaderUTF8() and UTF32 when it has been created using
|
||||
IrrXMLReaderUTF32. It should not be necessary to call this
|
||||
method and only exists for informational purposes. */
|
||||
virtual ETEXT_FORMAT getParserFormat() const = 0;
|
||||
};
|
||||
|
||||
|
||||
//! defines the utf-16 type.
|
||||
/** Not using wchar_t for this because
|
||||
wchar_t has 16 bit on windows and 32 bit on other operating systems. */
|
||||
typedef unsigned short char16;
|
||||
|
||||
//! defines the utf-32 type.
|
||||
/** Not using wchar_t for this because
|
||||
wchar_t has 16 bit on windows and 32 bit on other operating systems. */
|
||||
typedef unsigned long char32;
|
||||
|
||||
//! A UTF-8 or ASCII character xml parser.
|
||||
/** This means that all character data will be returned in 8 bit ASCII or UTF-8 by this parser.
|
||||
The file to read can be in any format, it will be converted to UTF-8 if it is not
|
||||
in this format.
|
||||
Create an instance of this with createIrrXMLReader();
|
||||
See IIrrXMLReader for description on how to use it. */
|
||||
typedef IIrrXMLReader<char, IXMLBase> IrrXMLReader;
|
||||
|
||||
//! A UTF-16 xml parser.
|
||||
/** This means that all character data will be returned in UTF-16 by this parser.
|
||||
The file to read can be in any format, it will be converted to UTF-16 if it is not
|
||||
in this format.
|
||||
Create an instance of this with createIrrXMLReaderUTF16();
|
||||
See IIrrXMLReader for description on how to use it. */
|
||||
typedef IIrrXMLReader<char16, IXMLBase> IrrXMLReaderUTF16;
|
||||
|
||||
//! A UTF-32 xml parser.
|
||||
/** This means that all character data will be returned in UTF-32 by this parser.
|
||||
The file to read can be in any format, it will be converted to UTF-32 if it is not
|
||||
in this format.
|
||||
Create an instance of this with createIrrXMLReaderUTF32();
|
||||
See IIrrXMLReader for description on how to use it. */
|
||||
typedef IIrrXMLReader<char32, IXMLBase> IrrXMLReaderUTF32;
|
||||
|
||||
|
||||
//! Creates an instance of an UFT-8 or ASCII character xml parser.
|
||||
/** This means that all character data will be returned in 8 bit ASCII or UTF-8.
|
||||
The file to read can be in any format, it will be converted to UTF-8 if it is not in this format.
|
||||
If you are using the Irrlicht Engine, it is better not to use this function but
|
||||
IFileSystem::createXMLReaderUTF8() instead.
|
||||
\param filename: Name of file to be opened.
|
||||
\return Returns a pointer to the created xml parser. This pointer should be
|
||||
deleted using 'delete' after no longer needed. Returns 0 if an error occured
|
||||
and the file could not be opened. */
|
||||
IRRXML_API IrrXMLReader* createIrrXMLReader(const char* filename);
|
||||
|
||||
//! Creates an instance of an UFT-8 or ASCII character xml parser.
|
||||
/** This means that all character data will be returned in 8 bit ASCII or UTF-8. The file to read can
|
||||
be in any format, it will be converted to UTF-8 if it is not in this format.
|
||||
If you are using the Irrlicht Engine, it is better not to use this function but
|
||||
IFileSystem::createXMLReaderUTF8() instead.
|
||||
\param file: Pointer to opened file, must have been opened in binary mode, e.g.
|
||||
using fopen("foo.bar", "wb"); The file will not be closed after it has been read.
|
||||
\return Returns a pointer to the created xml parser. This pointer should be
|
||||
deleted using 'delete' after no longer needed. Returns 0 if an error occured
|
||||
and the file could not be opened. */
|
||||
IRRXML_API IrrXMLReader* createIrrXMLReader(FILE* file);
|
||||
|
||||
//! Creates an instance of an UFT-8 or ASCII character xml parser.
|
||||
/** This means that all character data will be returned in 8 bit ASCII or UTF-8. The file to read can
|
||||
be in any format, it will be converted to UTF-8 if it is not in this format.
|
||||
If you are using the Irrlicht Engine, it is better not to use this function but
|
||||
IFileSystem::createXMLReaderUTF8() instead.
|
||||
\param callback: Callback for file read abstraction. Implement your own
|
||||
callback to make the xml parser read in other things than just files. See
|
||||
IFileReadCallBack for more information about this.
|
||||
\return Returns a pointer to the created xml parser. This pointer should be
|
||||
deleted using 'delete' after no longer needed. Returns 0 if an error occured
|
||||
and the file could not be opened. */
|
||||
IRRXML_API IrrXMLReader* createIrrXMLReader(IFileReadCallBack* callback);
|
||||
|
||||
//! Creates an instance of an UFT-16 xml parser.
|
||||
/** This means that
|
||||
all character data will be returned in UTF-16. The file to read can
|
||||
be in any format, it will be converted to UTF-16 if it is not in this format.
|
||||
If you are using the Irrlicht Engine, it is better not to use this function but
|
||||
IFileSystem::createXMLReader() instead.
|
||||
\param filename: Name of file to be opened.
|
||||
\return Returns a pointer to the created xml parser. This pointer should be
|
||||
deleted using 'delete' after no longer needed. Returns 0 if an error occured
|
||||
and the file could not be opened. */
|
||||
IRRXML_API IrrXMLReaderUTF16* createIrrXMLReaderUTF16(const char* filename);
|
||||
|
||||
//! Creates an instance of an UFT-16 xml parser.
|
||||
/** This means that all character data will be returned in UTF-16. The file to read can
|
||||
be in any format, it will be converted to UTF-16 if it is not in this format.
|
||||
If you are using the Irrlicht Engine, it is better not to use this function but
|
||||
IFileSystem::createXMLReader() instead.
|
||||
\param file: Pointer to opened file, must have been opened in binary mode, e.g.
|
||||
using fopen("foo.bar", "wb"); The file will not be closed after it has been read.
|
||||
\return Returns a pointer to the created xml parser. This pointer should be
|
||||
deleted using 'delete' after no longer needed. Returns 0 if an error occured
|
||||
and the file could not be opened. */
|
||||
IRRXML_API IrrXMLReaderUTF16* createIrrXMLReaderUTF16(FILE* file);
|
||||
|
||||
//! Creates an instance of an UFT-16 xml parser.
|
||||
/** This means that all character data will be returned in UTF-16. The file to read can
|
||||
be in any format, it will be converted to UTF-16 if it is not in this format.
|
||||
If you are using the Irrlicht Engine, it is better not to use this function but
|
||||
IFileSystem::createXMLReader() instead.
|
||||
\param callback: Callback for file read abstraction. Implement your own
|
||||
callback to make the xml parser read in other things than just files. See
|
||||
IFileReadCallBack for more information about this.
|
||||
\return Returns a pointer to the created xml parser. This pointer should be
|
||||
deleted using 'delete' after no longer needed. Returns 0 if an error occured
|
||||
and the file could not be opened. */
|
||||
IRRXML_API IrrXMLReaderUTF16* createIrrXMLReaderUTF16(IFileReadCallBack* callback);
|
||||
|
||||
|
||||
//! Creates an instance of an UFT-32 xml parser.
|
||||
/** This means that all character data will be returned in UTF-32. The file to read can
|
||||
be in any format, it will be converted to UTF-32 if it is not in this format.
|
||||
If you are using the Irrlicht Engine, it is better not to use this function but
|
||||
IFileSystem::createXMLReader() instead.
|
||||
\param filename: Name of file to be opened.
|
||||
\return Returns a pointer to the created xml parser. This pointer should be
|
||||
deleted using 'delete' after no longer needed. Returns 0 if an error occured
|
||||
and the file could not be opened. */
|
||||
IRRXML_API IrrXMLReaderUTF32* createIrrXMLReaderUTF32(const char* filename);
|
||||
|
||||
//! Creates an instance of an UFT-32 xml parser.
|
||||
/** This means that all character data will be returned in UTF-32. The file to read can
|
||||
be in any format, it will be converted to UTF-32 if it is not in this format.
|
||||
if you are using the Irrlicht Engine, it is better not to use this function but
|
||||
IFileSystem::createXMLReader() instead.
|
||||
\param file: Pointer to opened file, must have been opened in binary mode, e.g.
|
||||
using fopen("foo.bar", "wb"); The file will not be closed after it has been read.
|
||||
\return Returns a pointer to the created xml parser. This pointer should be
|
||||
deleted using 'delete' after no longer needed. Returns 0 if an error occured
|
||||
and the file could not be opened. */
|
||||
IRRXML_API IrrXMLReaderUTF32* createIrrXMLReaderUTF32(FILE* file);
|
||||
|
||||
//! Creates an instance of an UFT-32 xml parser.
|
||||
/** This means that
|
||||
all character data will be returned in UTF-32. The file to read can
|
||||
be in any format, it will be converted to UTF-32 if it is not in this format.
|
||||
If you are using the Irrlicht Engine, it is better not to use this function but
|
||||
IFileSystem::createXMLReader() instead.
|
||||
\param callback: Callback for file read abstraction. Implement your own
|
||||
callback to make the xml parser read in other things than just files. See
|
||||
IFileReadCallBack for more information about this.
|
||||
\return Returns a pointer to the created xml parser. This pointer should be
|
||||
deleted using 'delete' after no longer needed. Returns 0 if an error occured
|
||||
and the file could not be opened. */
|
||||
IRRXML_API IrrXMLReaderUTF32* createIrrXMLReaderUTF32(IFileReadCallBack* callback);
|
||||
|
||||
|
||||
/*! \file irrxml.h
|
||||
\brief Header file of the irrXML, the Irrlicht XML parser.
|
||||
|
||||
This file includes everything needed for using irrXML,
|
||||
the XML parser of the Irrlicht Engine. To use irrXML,
|
||||
you only need to include this file in your project:
|
||||
|
||||
\code
|
||||
#include <irrXML.h>
|
||||
\endcode
|
||||
|
||||
It is also common to use the two namespaces in which irrXML is included,
|
||||
directly after #including irrXML.h:
|
||||
|
||||
\code
|
||||
#include <irrXML.h>
|
||||
using namespace irr;
|
||||
using namespace io;
|
||||
\endcode
|
||||
*/
|
||||
|
||||
} // end namespace io
|
||||
} // end namespace irr
|
||||
|
||||
#endif // __IRR_XML_H_INCLUDED__
|
||||
|
|
@ -44,13 +44,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#define INCLUDED_AI_IRRXML_WRAPPER
|
||||
|
||||
// some long includes ....
|
||||
#ifdef ASSIMP_USE_HUNTER
|
||||
# include <irrXML/irrXML.h>
|
||||
#else
|
||||
# include <irrXML.h>
|
||||
#endif
|
||||
#include "IOStream.hpp"
|
||||
#include "BaseImporter.h"
|
||||
#include "IOStream.hpp"
|
||||
#include <pugixml.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace Assimp {
|
||||
|
@ -75,7 +71,7 @@ namespace Assimp {
|
|||
* }
|
||||
* @endcode
|
||||
**/
|
||||
class CIrrXML_IOStreamReader : public irr::io::IFileReadCallBack {
|
||||
/*class CIrrXML_IOStreamReader : public irr::io::IFileReadCallBack {
|
||||
public:
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
@ -110,14 +106,14 @@ public:
|
|||
|
||||
// ----------------------------------------------------------------------------------
|
||||
//! Virtual destructor
|
||||
virtual ~CIrrXML_IOStreamReader() {}
|
||||
virtual ~CIrrXML_IOStreamReader() {}*/
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
//! Reads an amount of bytes from the file.
|
||||
/** @param buffer: Pointer to output buffer.
|
||||
* @param sizeToRead: Amount of bytes to read
|
||||
* @return Returns how much bytes were read. */
|
||||
virtual int read(void* buffer, int sizeToRead) {
|
||||
/*virtual int read(void* buffer, int sizeToRead) {
|
||||
if(sizeToRead<0) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -143,7 +139,51 @@ private:
|
|||
size_t t;
|
||||
|
||||
}; // ! class CIrrXML_IOStreamReader
|
||||
*/
|
||||
|
||||
} // ! Assimp
|
||||
class XmlParser {
|
||||
public:
|
||||
XmlParser() :
|
||||
mDoc(nullptr), mRoot(nullptr), mData() {
|
||||
// empty
|
||||
}
|
||||
|
||||
~XmlParser() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
mData.resize(0);
|
||||
delete mDoc;
|
||||
mDoc = nullptr;
|
||||
}
|
||||
|
||||
pugi::xml_node *parse(IOStream *stream) {
|
||||
if (nullptr == stream) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mData.resize(stream->FileSize());
|
||||
stream->Read(&mData[0], mData.size(), 1);
|
||||
mDoc = new pugi::xml_document();
|
||||
pugi::xml_parse_result result = mDoc->load_string(&mData[0]);
|
||||
if (result.status == pugi::status_ok) {
|
||||
mRoot = &mDoc->root();
|
||||
}
|
||||
|
||||
return mRoot;
|
||||
}
|
||||
|
||||
pugi::xml_document *getDocument() const {
|
||||
return mDoc;
|
||||
}
|
||||
|
||||
private:
|
||||
pugi::xml_document *mDoc;
|
||||
pugi::xml_node *mRoot;
|
||||
std::vector<char> mData;
|
||||
};
|
||||
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // !! INCLUDED_AI_IRRXML_WRAPPER
|
Loading…
Reference in New Issue