Fix up scene loading. pugixml is a breadth-first parser while irrxml is
a depth first. This only parses scene structure, no mesh loading yet.pull/5166/head
parent
537b445a59
commit
3e1fd74940
|
@ -43,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* @brief Implementation of the Irr importer class
|
||||
*/
|
||||
|
||||
#include "assimp/StringComparison.h"
|
||||
#ifndef ASSIMP_BUILD_NO_IRR_IMPORTER
|
||||
|
||||
#include "AssetLib/Irr/IRRLoader.h"
|
||||
|
@ -62,7 +63,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
|
||||
#include <csignal>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <stack>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
|
@ -835,175 +840,164 @@ 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) {
|
||||
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
|
||||
void IRRImporter::ParseNodeAttributes(pugi::xml_node &attributesNode, IRRImporter::Node *nd, BatchLoader &batch) {
|
||||
ai_assert(!ASSIMP_stricmp(attributesNode.name(), "attributes")); // Node must be <attributes>
|
||||
ai_assert(nd != nullptr); // dude
|
||||
|
||||
// Check whether we can read from the file
|
||||
if (file == nullptr) {
|
||||
throw DeadlyImportError("Failed to open IRR file ", pFile);
|
||||
// Big switch statement that tests for various tags inside <attributes>
|
||||
// and applies them to nd
|
||||
// I don't believe nodes have boolean attributes
|
||||
for (pugi::xml_node &attribute : attributesNode.children()) {
|
||||
if (attribute.type() != pugi::node_element) continue;
|
||||
if (!ASSIMP_stricmp(attribute.name(), "vector3d")) { // <vector3d />
|
||||
VectorProperty prop;
|
||||
ReadVectorProperty(prop, attribute);
|
||||
if (prop.name == "Position") {
|
||||
nd->position = prop.value;
|
||||
} else if (prop.name == "Rotation") {
|
||||
nd->rotation = prop.value;
|
||||
} else if (prop.name == "Scale") {
|
||||
nd->scaling = prop.value;
|
||||
} else if (Node::CAMERA == nd->type) {
|
||||
aiCamera *cam = cameras.back();
|
||||
if (prop.name == "Target") {
|
||||
cam->mLookAt = prop.value;
|
||||
} else if (prop.name == "UpVector") {
|
||||
cam->mUp = prop.value;
|
||||
}
|
||||
|
||||
// Construct the irrXML parser
|
||||
XmlParser st;
|
||||
if (!st.parse(file.get())) {
|
||||
throw DeadlyImportError("XML parse error while loading IRR file ", pFile);
|
||||
}
|
||||
pugi::xml_node rootElement = st.getRootNode();
|
||||
|
||||
// The root node of the scene
|
||||
Node *root = new Node(Node::DUMMY);
|
||||
root->parent = nullptr;
|
||||
root->name = "<IRRSceneRoot>";
|
||||
|
||||
// Current node parent
|
||||
Node *curParent = root;
|
||||
|
||||
// Scene-graph node we're currently working on
|
||||
Node *curNode = nullptr;
|
||||
|
||||
// List of output cameras
|
||||
std::vector<aiCamera *> cameras;
|
||||
|
||||
// List of output lights
|
||||
std::vector<aiLight *> lights;
|
||||
|
||||
// Batch loader used to load external models
|
||||
BatchLoader batch(pIOHandler);
|
||||
// batch.SetBasePath(pFile);
|
||||
|
||||
cameras.reserve(5);
|
||||
lights.reserve(5);
|
||||
|
||||
bool inMaterials = false, inAnimator = false;
|
||||
unsigned int guessedAnimCnt = 0, guessedMeshCnt = 0, guessedMatCnt = 0;
|
||||
|
||||
// Parse the XML file
|
||||
|
||||
// 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:
|
||||
*
|
||||
* "mesh" - Load a mesh from an external file
|
||||
* "cube" - Generate a cube
|
||||
* "skybox" - Generate a skybox
|
||||
* "light" - A light source
|
||||
* "sphere" - Generate a sphere mesh
|
||||
* "animatedMesh" - Load an animated mesh from an external file
|
||||
* and join its animation channels with ours.
|
||||
* "empty" - A dummy node
|
||||
* "camera" - A camera
|
||||
* "terrain" - a terrain node (data comes from a heightmap)
|
||||
* "billboard", ""
|
||||
*
|
||||
* Each of these nodes can be animated and all can have multiple
|
||||
* materials assigned (except lights, cameras and dummies, of course).
|
||||
} else if (!ASSIMP_stricmp(attribute.name(), "float")) { // <float />
|
||||
FloatProperty prop;
|
||||
ReadFloatProperty(prop, attribute);
|
||||
if (prop.name == "FramesPerSecond" && Node::ANIMMESH == nd->type) {
|
||||
nd->framesPerSecond = prop.value;
|
||||
} else if (Node::CAMERA == nd->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.
|
||||
*/
|
||||
// ***********************************************************************
|
||||
// const char *sz = reader->getAttributeValueSafe("type");
|
||||
pugi::xml_attribute attrib = child.attribute("type");
|
||||
Node *nd;
|
||||
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(attrib.name(), "cube")) {
|
||||
nd = new Node(Node::CUBE);
|
||||
++guessedMeshCnt;
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "skybox")) {
|
||||
nd = new Node(Node::SKYBOX);
|
||||
guessedMeshCnt += 6;
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "camera")) {
|
||||
nd = new Node(Node::CAMERA);
|
||||
if (prop.name == "Fovy") {
|
||||
cameras.back()->mHorizontalFOV = prop.value;
|
||||
} else if (prop.name == "Aspect") {
|
||||
cameras.back()->mAspect = prop.value;
|
||||
} else if (prop.name == "ZNear") {
|
||||
cameras.back()->mClipPlaneNear = prop.value;
|
||||
} else if (prop.name == "ZFar") {
|
||||
cameras.back()->mClipPlaneFar = prop.value;
|
||||
}
|
||||
} else if (Node::LIGHT == nd->type) {
|
||||
/* Additional light information
|
||||
*/
|
||||
if (prop.name == "Attenuation") {
|
||||
lights.back()->mAttenuationLinear = prop.value;
|
||||
} else if (prop.name == "OuterCone") {
|
||||
lights.back()->mAngleOuterCone = AI_DEG_TO_RAD(prop.value);
|
||||
} 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 == nd->type && prop.name == "Radius") ||
|
||||
(Node::CUBE == nd->type && prop.name == "Size")) {
|
||||
nd->sphereRadius = prop.value;
|
||||
}
|
||||
} else if (!ASSIMP_stricmp(attribute.name(), "int")) { // <int />
|
||||
// Only sphere nodes make use of integer attributes
|
||||
if (Node::SPHERE == nd->type) {
|
||||
IntProperty prop;
|
||||
ReadIntProperty(prop, attribute);
|
||||
if (prop.name == "PolyCountX") {
|
||||
nd->spherePolyCountX = prop.value;
|
||||
} else if (prop.name == "PolyCountY") {
|
||||
nd->spherePolyCountY = prop.value;
|
||||
}
|
||||
}
|
||||
} else if (!ASSIMP_stricmp(attribute.name(), "string") || !ASSIMP_stricmp(attribute.name(), "enum")) { // <string /> or < enum />
|
||||
StringProperty prop;
|
||||
ReadStringProperty(prop, attribute);
|
||||
if (prop.value.length() == 0) continue; // skip empty strings
|
||||
if (prop.name == "Name") {
|
||||
nd->name = prop.value;
|
||||
|
||||
// Setup a temporary name for the camera
|
||||
aiCamera *cam = new aiCamera();
|
||||
cam->mName.Set(nd->name);
|
||||
cameras.push_back(cam);
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "light")) {
|
||||
nd = new Node(Node::LIGHT);
|
||||
/* If we're either a camera or a light source
|
||||
* we need to update the name in the aiLight/
|
||||
* aiCamera structure, too.
|
||||
*/
|
||||
if (Node::CAMERA == nd->type) {
|
||||
cameras.back()->mName.Set(prop.value);
|
||||
} else if (Node::LIGHT == nd->type) {
|
||||
lights.back()->mName.Set(prop.value);
|
||||
}
|
||||
} else if (Node::LIGHT == nd->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 {
|
||||
// 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();
|
||||
lights.pop_back();
|
||||
nd->type = Node::DUMMY;
|
||||
|
||||
// Setup a temporary name for the light
|
||||
aiLight *cam = new aiLight();
|
||||
cam->mName.Set(nd->name);
|
||||
lights.push_back(cam);
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "sphere")) {
|
||||
nd = new Node(Node::SPHERE);
|
||||
++guessedMeshCnt;
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "animatedMesh")) {
|
||||
nd = new Node(Node::ANIMMESH);
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "empty")) {
|
||||
nd = new Node(Node::DUMMY);
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "terrain")) {
|
||||
nd = new Node(Node::TERRAIN);
|
||||
} 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);
|
||||
ASSIMP_LOG_ERROR("Ignoring light of unknown type: ", prop.value);
|
||||
}
|
||||
} else if ((prop.name == "Mesh" && Node::MESH == nd->type) ||
|
||||
Node::ANIMMESH == nd->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.
|
||||
*/
|
||||
unsigned int pp = 0;
|
||||
BatchLoader::PropertyMap map;
|
||||
|
||||
/* If the mesh is a static one remove all animations from the impor data
|
||||
*/
|
||||
if (Node::ANIMMESH != nd->type) {
|
||||
pp |= aiProcess_RemoveComponent;
|
||||
SetGenericProperty<int>(map.ints, AI_CONFIG_PP_RVC_FLAGS,
|
||||
aiComponent_ANIMATIONS | aiComponent_BONEWEIGHTS);
|
||||
}
|
||||
|
||||
/* TODO: maybe implement the protection against recursive
|
||||
* loading calls directly in BatchLoader? The current
|
||||
* implementation is not absolutely safe. A LWS and an IRR
|
||||
* file referencing each other *could* cause the system to
|
||||
* recurse forever.
|
||||
*/
|
||||
|
||||
const std::string extension = GetExtension(prop.value);
|
||||
if ("irr" == extension) {
|
||||
ASSIMP_LOG_ERROR("IRR: Can't load another IRR file recursively");
|
||||
} else {
|
||||
ASSIMP_LOG_WARN("IRR: Found unknown node: ", attrib.name());
|
||||
|
||||
/* We skip the contents of nodes we don't know.
|
||||
* We parse the transformation and all animators
|
||||
* and skip the rest.
|
||||
*/
|
||||
nd = new Node(Node::DUMMY);
|
||||
}
|
||||
|
||||
/* Attach the newly created node to the scene-graph
|
||||
*/
|
||||
curNode = nd;
|
||||
nd->parent = curParent;
|
||||
curParent->children.push_back(nd);
|
||||
} else if (!ASSIMP_stricmp(child.name(), "materials")) {
|
||||
inMaterials = true;
|
||||
} else if (!ASSIMP_stricmp(child.name(), "animators")) {
|
||||
inAnimator = true;
|
||||
} 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) {
|
||||
continue;
|
||||
nd->id = batch.AddLoadRequest(prop.value, pp, &map);
|
||||
nd->meshPath = prop.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IRRImporter::ParseAnimators(pugi::xml_node &animatorNode, IRRImporter::Node *nd) {
|
||||
Animator *curAnim = nullptr;
|
||||
|
||||
// Materials can occur for nearly any type of node
|
||||
if (inMaterials && curNode->type != Node::DUMMY) {
|
||||
// This is a material description - parse it!
|
||||
curNode->materials.emplace_back();
|
||||
std::pair<aiMaterial *, unsigned int> &p = curNode->materials.back();
|
||||
|
||||
p.first = ParseMaterial(p.second);
|
||||
++guessedMatCnt;
|
||||
continue;
|
||||
} else if (inAnimator) {
|
||||
// This is an animation path - add a new animator
|
||||
// to the list.
|
||||
curNode->animators.emplace_back();
|
||||
curAnim = &curNode->animators.back();
|
||||
|
||||
++guessedAnimCnt;
|
||||
// Make empty animator
|
||||
nd->animators.emplace_back();
|
||||
curAnim = &nd->animators.back(); // Push it back
|
||||
pugi::xml_node attributes = animatorNode.child("attributes");
|
||||
if (!attributes) {
|
||||
ASSIMP_LOG_WARN("Animator node does not contain attributes. ");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Parse all elements in the attributes block
|
||||
* and process them.
|
||||
*/
|
||||
// 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")) {
|
||||
for (pugi::xml_node attrib : attributes.children()) {
|
||||
// XML may contain useless noes like CDATA
|
||||
if (!ASSIMP_stricmp(attrib.name(), "vector3d")) {
|
||||
VectorProperty prop;
|
||||
ReadVectorProperty(prop);
|
||||
ReadVectorProperty(prop, attrib);
|
||||
|
||||
if (inAnimator) {
|
||||
if (curAnim->type == Animator::ROTATION && prop.name == "Rotation") {
|
||||
// We store the rotation euler angles in 'direction'
|
||||
curAnim->direction = prop.value;
|
||||
|
@ -1040,36 +1034,20 @@ void IRRImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
|||
curAnim->direction = prop.value;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (prop.name == "Position") {
|
||||
curNode->position = prop.value;
|
||||
} else if (prop.name == "Rotation") {
|
||||
curNode->rotation = prop.value;
|
||||
} else if (prop.name == "Scale") {
|
||||
curNode->scaling = prop.value;
|
||||
} else if (Node::CAMERA == curNode->type) {
|
||||
aiCamera *cam = cameras.back();
|
||||
if (prop.name == "Target") {
|
||||
cam->mLookAt = prop.value;
|
||||
} else if (prop.name == "UpVector") {
|
||||
cam->mUp = prop.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//} else if (!ASSIMP_stricmp(reader->getNodeName(), "bool")) {
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "bool")) {
|
||||
BoolProperty prop;
|
||||
ReadBoolProperty(prop);
|
||||
ReadBoolProperty(prop, attrib);
|
||||
|
||||
if (inAnimator && curAnim->type == Animator::FLY_CIRCLE && prop.name == "Loop") {
|
||||
if (curAnim->type == Animator::FLY_CIRCLE && prop.name == "Loop") {
|
||||
curAnim->loop = prop.value;
|
||||
}
|
||||
//} else if (!ASSIMP_stricmp(reader->getNodeName(), "float")) {
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "float")) {
|
||||
FloatProperty prop;
|
||||
ReadFloatProperty(prop);
|
||||
ReadFloatProperty(prop, attrib);
|
||||
|
||||
if (inAnimator) {
|
||||
// The speed property exists for several animators
|
||||
if (prop.name == "Speed") {
|
||||
curAnim->speed = prop.value;
|
||||
|
@ -1078,126 +1056,20 @@ void IRRImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
|||
} else if (curAnim->type == Animator::FOLLOW_SPLINE && prop.name == "Tightness") {
|
||||
curAnim->tightness = prop.value;
|
||||
}
|
||||
} else {
|
||||
if (prop.name == "FramesPerSecond" && Node::ANIMMESH == curNode->type) {
|
||||
curNode->framesPerSecond = prop.value;
|
||||
} 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") {
|
||||
cameras.back()->mAspect = prop.value;
|
||||
} else if (prop.name == "ZNear") {
|
||||
cameras.back()->mClipPlaneNear = prop.value;
|
||||
} else if (prop.name == "ZFar") {
|
||||
cameras.back()->mClipPlaneFar = prop.value;
|
||||
}
|
||||
} else if (Node::LIGHT == curNode->type) {
|
||||
/* Additional light information
|
||||
*/
|
||||
if (prop.name == "Attenuation") {
|
||||
lights.back()->mAttenuationLinear = prop.value;
|
||||
} else if (prop.name == "OuterCone") {
|
||||
lights.back()->mAngleOuterCone = AI_DEG_TO_RAD(prop.value);
|
||||
} 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")) {
|
||||
|
||||
curNode->sphereRadius = prop.value;
|
||||
}
|
||||
}
|
||||
//} else if (!ASSIMP_stricmp(reader->getNodeName(), "int")) {
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "int")) {
|
||||
IntProperty prop;
|
||||
ReadIntProperty(prop);
|
||||
ReadIntProperty(prop, attrib);
|
||||
|
||||
if (inAnimator) {
|
||||
if (curAnim->type == Animator::FLY_STRAIGHT && prop.name == "TimeForWay") {
|
||||
curAnim->timeForWay = prop.value;
|
||||
}
|
||||
} 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") {
|
||||
curNode->spherePolyCountY = prop.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
//} 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()) {
|
||||
if (prop.name == "Name") {
|
||||
curNode->name = prop.value;
|
||||
ReadStringProperty(prop, attrib);
|
||||
|
||||
/* If we're either a camera or a light source
|
||||
* we need to update the name in the aiLight/
|
||||
* aiCamera structure, too.
|
||||
*/
|
||||
if (Node::CAMERA == curNode->type) {
|
||||
cameras.back()->mName.Set(prop.value);
|
||||
} else if (Node::LIGHT == curNode->type) {
|
||||
lights.back()->mName.Set(prop.value);
|
||||
}
|
||||
} 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 {
|
||||
// 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();
|
||||
lights.pop_back();
|
||||
curNode->type = Node::DUMMY;
|
||||
|
||||
ASSIMP_LOG_ERROR("Ignoring light of unknown type: ", prop.value);
|
||||
}
|
||||
} 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.
|
||||
*/
|
||||
unsigned int pp = 0;
|
||||
BatchLoader::PropertyMap map;
|
||||
|
||||
/* If the mesh is a static one remove all animations from the impor data
|
||||
*/
|
||||
if (Node::ANIMMESH != curNode->type) {
|
||||
pp |= aiProcess_RemoveComponent;
|
||||
SetGenericProperty<int>(map.ints, AI_CONFIG_PP_RVC_FLAGS,
|
||||
aiComponent_ANIMATIONS | aiComponent_BONEWEIGHTS);
|
||||
}
|
||||
|
||||
/* TODO: maybe implement the protection against recursive
|
||||
* loading calls directly in BatchLoader? The current
|
||||
* implementation is not absolutely safe. A LWS and an IRR
|
||||
* file referencing each other *could* cause the system to
|
||||
* recurse forever.
|
||||
*/
|
||||
|
||||
const std::string extension = GetExtension(prop.value);
|
||||
if ("irr" == extension) {
|
||||
ASSIMP_LOG_ERROR("IRR: Can't load another IRR file recursively");
|
||||
} else {
|
||||
curNode->id = batch.AddLoadRequest(prop.value, pp, &map);
|
||||
curNode->meshPath = prop.value;
|
||||
}
|
||||
} else if (inAnimator && prop.name == "Type") {
|
||||
if (prop.name == "Type") {
|
||||
// type of the animator
|
||||
if (prop.value == "rotation") {
|
||||
curAnim->type = Animator::ROTATION;
|
||||
|
@ -1215,42 +1087,187 @@ void IRRImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
|||
}
|
||||
}
|
||||
}
|
||||
//} 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:
|
||||
IRRImporter::Node *IRRImporter::ParseNode(pugi::xml_node &node, BatchLoader &batch) {
|
||||
// Parse <node> tags.
|
||||
// <node> tags have various types
|
||||
// <node> tags can contain <attribute>, <material>
|
||||
// they can also contain other <node> tags, (and can reference other files as well?)
|
||||
// ***********************************************************************
|
||||
/* What we're going to do with the node depends
|
||||
* on its type:
|
||||
*
|
||||
* "mesh" - Load a mesh from an external file
|
||||
* "cube" - Generate a cube
|
||||
* "skybox" - Generate a skybox
|
||||
* "light" - A light source
|
||||
* "sphere" - Generate a sphere mesh
|
||||
* "animatedMesh" - Load an animated mesh from an external file
|
||||
* and join its animation channels with ours.
|
||||
* "empty" - A dummy node
|
||||
* "camera" - A camera
|
||||
* "terrain" - a terrain node (data comes from a heightmap)
|
||||
* "billboard", ""
|
||||
*
|
||||
* Each of these nodes can be animated and all can have multiple
|
||||
* materials assigned (except lights, cameras and dummies, of course).
|
||||
* Said materials and animators are all collected at the bottom
|
||||
*/
|
||||
// ***********************************************************************
|
||||
Node *nd;
|
||||
pugi::xml_attribute nodeTypeAttrib = node.attribute("type");
|
||||
if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "mesh") || !ASSIMP_stricmp(nodeTypeAttrib.value(), "octTree")) {
|
||||
// OctTree's and meshes are treated equally
|
||||
nd = new Node(Node::MESH);
|
||||
} else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "cube")) {
|
||||
nd = new Node(Node::CUBE);
|
||||
guessedMeshCnt += 1; // Cube is only one mesh
|
||||
} else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "skybox")) {
|
||||
nd = new Node(Node::SKYBOX);
|
||||
guessedMeshCnt += 6; // Skybox is a box, with 6 meshes?
|
||||
} else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "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(nodeTypeAttrib.value(), "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(nodeTypeAttrib.value(), "sphere")) {
|
||||
nd = new Node(Node::SPHERE);
|
||||
guessedMeshCnt += 1;
|
||||
} else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "animatedMesh")) {
|
||||
nd = new Node(Node::ANIMMESH);
|
||||
} else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "empty")) {
|
||||
nd = new Node(Node::DUMMY);
|
||||
} else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "terrain")) {
|
||||
nd = new Node(Node::TERRAIN);
|
||||
} else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "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: ", nodeTypeAttrib.value());
|
||||
|
||||
// If we reached the end of a node, we need to continue processing its parent
|
||||
if (!ASSIMP_stricmp(reader->getNodeName(), "node")) {
|
||||
if (!curNode) {
|
||||
// currently is no node set. We need to go
|
||||
// back in the node hierarchy
|
||||
if (!curParent) {
|
||||
curParent = root;
|
||||
ASSIMP_LOG_ERROR("IRR: Too many closing <node> elements");
|
||||
} else
|
||||
curParent = curParent->parent;
|
||||
} else
|
||||
curNode = nullptr;
|
||||
/* We skip the contents of nodes we don't know.
|
||||
* We parse the transformation and all animators
|
||||
* and skip the rest.
|
||||
*/
|
||||
nd = new Node(Node::DUMMY);
|
||||
}
|
||||
// clear all flags
|
||||
else if (!ASSIMP_stricmp(reader->getNodeName(), "materials")) {
|
||||
inMaterials = false;
|
||||
} else if (!ASSIMP_stricmp(reader->getNodeName(), "animators")) {
|
||||
inAnimator = false;
|
||||
}
|
||||
break;*/
|
||||
|
||||
default:
|
||||
// GCC complains that not all enumeration values are handled
|
||||
break;
|
||||
// TODO: consolidate all into one loop
|
||||
// Collect node attributes first
|
||||
for (pugi::xml_node attr_node : node.children()) {
|
||||
if (!ASSIMP_stricmp(attr_node.name(), "attributes")) {
|
||||
ParseNodeAttributes(attr_node, nd, batch); // Parse attributes into this node
|
||||
}
|
||||
}
|
||||
|
||||
// Then parse any materials
|
||||
// Materials are available to almost all node types
|
||||
if (nd->type != Node::DUMMY) {
|
||||
for (pugi::xml_node materialNode : node.children()) {
|
||||
if (!ASSIMP_stricmp(materialNode.name(), "materials")) {
|
||||
// Parse material description directly
|
||||
// Each material should contain an <attributes> node
|
||||
// with everything specified
|
||||
nd->materials.emplace_back();
|
||||
std::pair<aiMaterial *, unsigned int> &p = nd->materials.back();
|
||||
p.first = ParseMaterial(materialNode, p.second);
|
||||
guessedMatCnt += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then parse any animators
|
||||
for (pugi::xml_node animatorNode : node.children()) {
|
||||
if (!ASSIMP_stricmp(animatorNode.name(), "animators")) {
|
||||
// All animators should contain an <attributes> tag
|
||||
// This is an animation path - add a new animator
|
||||
// to the list.
|
||||
ParseAnimators(animatorNode, nd); // Function modifies nd's animator vector
|
||||
guessedAnimCnt += 1;
|
||||
}
|
||||
}
|
||||
// Then parse any child nodes
|
||||
/* Attach the newly created node to the scene-graph
|
||||
*/
|
||||
// curNode = nd;
|
||||
// nd->parent = curParent;
|
||||
// curParent->children.push_back(nd);
|
||||
for (pugi::xml_node child : node.children()) {
|
||||
if (!ASSIMP_stricmp(child.name(), "node")) { // Is a child node
|
||||
Node *childNd = ParseNode(child, batch); // Repeat this function for all children
|
||||
nd->children.push_back(childNd);
|
||||
};
|
||||
}
|
||||
|
||||
return nd;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file into the given scene structure.
|
||||
void IRRImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
|
||||
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
|
||||
// Check whether we can read from the file
|
||||
if (file == nullptr) {
|
||||
throw DeadlyImportError("Failed to open IRR file ", pFile);
|
||||
}
|
||||
|
||||
// Construct the irrXML parser
|
||||
XmlParser st;
|
||||
if (!st.parse(file.get())) {
|
||||
throw DeadlyImportError("XML parse error while loading IRR file ", pFile);
|
||||
}
|
||||
pugi::xml_node rootElement = st.getRootNode();
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "Document name: " << rootElement.name() << std::endl;
|
||||
ss << "Document content: " << std::endl;
|
||||
rootElement.print(ss);
|
||||
ss << std::endl;
|
||||
std::cout << "IrrImporter with";
|
||||
std::cout << ss.str() << std::endl;
|
||||
// The root node of the scene
|
||||
// TODO: Appearantly root node is specified somewhere?
|
||||
Node *root = new Node(Node::DUMMY);
|
||||
root->parent = nullptr;
|
||||
root->name = "<IRRSceneRoot>";
|
||||
|
||||
// Batch loader used to load external models
|
||||
BatchLoader batch(pIOHandler);
|
||||
// batch.SetBasePath(pFile);
|
||||
|
||||
cameras.reserve(1); // Probably only one camera in entire scene
|
||||
lights.reserve(5);
|
||||
|
||||
this->guessedAnimCnt = 0;
|
||||
this->guessedMeshCnt = 0;
|
||||
this->guessedMatCnt = 0;
|
||||
|
||||
// Parse the XML
|
||||
// First node is the xml header. Awkwardly skip to sibling's children
|
||||
// I don't like recursion
|
||||
std::vector<pugi::xml_node> nextNodes;
|
||||
for (auto &node : rootElement.children().begin()->next_sibling().children()) {
|
||||
nextNodes.push_back(node); // Find second node, <irr_scene>, and push it's children to queue
|
||||
}
|
||||
for (pugi::xml_node &child : nextNodes) {
|
||||
if (child.type() != pugi::node_element) continue; // Only semantically valuable nodes
|
||||
// XML elements are either nodes, animators, attributes, or materials
|
||||
if (!ASSIMP_stricmp(child.name(), "node")) {
|
||||
// Recursive ollect subtree children
|
||||
Node *nd = ParseNode(child, batch);
|
||||
// Attach to root
|
||||
root->children.push_back(nd);
|
||||
}
|
||||
}
|
||||
//}
|
||||
|
||||
// Now iterate through all cameras and compute their final (horizontal) FOV
|
||||
for (aiCamera *cam : cameras) {
|
||||
|
@ -1336,8 +1353,7 @@ void IRRImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
|||
// 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) :
|
||||
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));
|
||||
|
||||
// If we have no meshes | no materials now set the INCOMPLETE
|
||||
|
|
|
@ -207,6 +207,24 @@ private:
|
|||
aiVector3D position, normal, uv;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Parse <node> tag from XML file and extract child node
|
||||
// @param node XML node
|
||||
// @param guessedMeshesContained number of extra guessed meshes
|
||||
IRRImporter::Node *ParseNode(pugi::xml_node &node, BatchLoader& batch);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Parse <attributes> tags within <node> tags and apply to scene node
|
||||
// @param attributeNode XML child node
|
||||
// @param nd Attributed scene node
|
||||
void ParseNodeAttributes(pugi::xml_node &attributeNode, IRRImporter::Node *nd, BatchLoader& batch);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Parse an <animator> node and attach an animator to a node
|
||||
// @param animatorNode XML animator node
|
||||
// @param nd Animated scene node
|
||||
void ParseAnimators(pugi::xml_node &animatorNode, IRRImporter::Node *nd);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/// Fill the scene-graph recursively
|
||||
void GenerateGraph(Node *root, aiNode *rootOut, aiScene *scene,
|
||||
|
@ -261,6 +279,12 @@ private:
|
|||
|
||||
/// Configuration option: speed flag was set?
|
||||
bool configSpeedFlag;
|
||||
|
||||
std::vector<aiCamera*> cameras;
|
||||
std::vector<aiLight*> lights;
|
||||
unsigned int guessedMeshCnt;
|
||||
unsigned int guessedMatCnt;
|
||||
unsigned int guessedAnimCnt;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
|
|
@ -176,7 +176,7 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
|
|||
ASSIMP_LOG_WARN("IRRMESH: Only one material description per buffer, please");
|
||||
releaseMaterial(&curMat);
|
||||
}
|
||||
curMat = ParseMaterial(curMatFlags);
|
||||
// curMat = ParseMaterial(curMatFlags);
|
||||
}
|
||||
/* no else here! */ if (!ASSIMP_stricmp(child.name(), "vertices")) {
|
||||
pugi::xml_attribute attr = child.attribute("vertexCount");
|
||||
|
@ -495,4 +495,8 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
|
|||
}
|
||||
}
|
||||
|
||||
void IRRMeshImporter::ParseMaterialBuffer(pugi::xml_node& bufferNode) {
|
||||
|
||||
}
|
||||
|
||||
#endif // !! ASSIMP_BUILD_NO_IRRMESH_IMPORTER
|
||||
|
|
|
@ -85,6 +85,8 @@ protected:
|
|||
*/
|
||||
void InternReadFile(const std::string &pFile, aiScene *pScene,
|
||||
IOSystem *pIOHandler) override;
|
||||
private:
|
||||
void ParseMaterialBuffer(pugi::xml_node& bufferNode);
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
|
|
@ -63,34 +63,34 @@ const aiMatrix4x4 Assimp::AI_TO_IRR_MATRIX = aiMatrix4x4(
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read a property in hexadecimal format (i.e. ffffffff)
|
||||
void IrrlichtBase::ReadHexProperty(HexProperty &out) {
|
||||
for (pugi::xml_attribute attrib : mNode->attributes()) {
|
||||
void IrrlichtBase::ReadHexProperty(HexProperty &out, pugi::xml_node& hexnode) {
|
||||
for (pugi::xml_attribute attrib : hexnode.attributes()) {
|
||||
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
||||
out.name = std::string(attrib.value());
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||
// parse the hexadecimal value
|
||||
out.value = strtoul16(attrib.name());
|
||||
out.value = strtoul16(attrib.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read a decimal property
|
||||
void IrrlichtBase::ReadIntProperty(IntProperty &out) {
|
||||
for (pugi::xml_attribute attrib : mNode->attributes()) {
|
||||
void IrrlichtBase::ReadIntProperty(IntProperty &out, pugi::xml_node& intnode) {
|
||||
for (pugi::xml_attribute attrib : intnode.attributes()) {
|
||||
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
||||
out.name = std::string(attrib.value());
|
||||
} else if (!ASSIMP_stricmp(attrib.value(), "value")) {
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||
// parse the int value
|
||||
out.value = strtol10(attrib.name());
|
||||
out.value = strtol10(attrib.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read a string property
|
||||
void IrrlichtBase::ReadStringProperty(StringProperty &out) {
|
||||
for (pugi::xml_attribute attrib : mNode->attributes()) {
|
||||
void IrrlichtBase::ReadStringProperty(StringProperty &out, pugi::xml_node& stringnode) {
|
||||
for (pugi::xml_attribute attrib : stringnode.attributes()) {
|
||||
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
||||
out.name = std::string(attrib.value());
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||
|
@ -102,8 +102,8 @@ void IrrlichtBase::ReadStringProperty(StringProperty &out) {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read a boolean property
|
||||
void IrrlichtBase::ReadBoolProperty(BoolProperty &out) {
|
||||
for (pugi::xml_attribute attrib : mNode->attributes()) {
|
||||
void IrrlichtBase::ReadBoolProperty(BoolProperty &out, pugi::xml_node& boolnode) {
|
||||
for (pugi::xml_attribute attrib : boolnode.attributes()) {
|
||||
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
||||
out.name = std::string(attrib.value());
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||
|
@ -115,8 +115,8 @@ void IrrlichtBase::ReadBoolProperty(BoolProperty &out) {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read a float property
|
||||
void IrrlichtBase::ReadFloatProperty(FloatProperty &out) {
|
||||
for (pugi::xml_attribute attrib : mNode->attributes()) {
|
||||
void IrrlichtBase::ReadFloatProperty(FloatProperty &out, pugi::xml_node &floatnode) {
|
||||
for (pugi::xml_attribute attrib : floatnode.attributes()) {
|
||||
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
||||
out.name = std::string(attrib.value());
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||
|
@ -128,8 +128,8 @@ void IrrlichtBase::ReadFloatProperty(FloatProperty &out) {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read a vector property
|
||||
void IrrlichtBase::ReadVectorProperty(VectorProperty &out) {
|
||||
for (pugi::xml_attribute attrib : mNode->attributes()) {
|
||||
void IrrlichtBase::ReadVectorProperty(VectorProperty &out, pugi::xml_node& vectornode) {
|
||||
for (pugi::xml_attribute attrib : vectornode.attributes()) {
|
||||
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
||||
out.name = std::string(attrib.value());
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||
|
@ -170,7 +170,7 @@ int ConvertMappingMode(const std::string &mode) {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Parse a material from the XML file
|
||||
aiMaterial *IrrlichtBase::ParseMaterial(unsigned int &matFlags) {
|
||||
aiMaterial *IrrlichtBase::ParseMaterial(pugi::xml_node& materialNode, unsigned int &matFlags) {
|
||||
aiMaterial *mat = new aiMaterial();
|
||||
aiColor4D clr;
|
||||
aiString s;
|
||||
|
@ -179,10 +179,10 @@ aiMaterial *IrrlichtBase::ParseMaterial(unsigned int &matFlags) {
|
|||
int cnt = 0; // number of used texture channels
|
||||
unsigned int nd = 0;
|
||||
|
||||
for (pugi::xml_node child : mNode->children()) {
|
||||
for (pugi::xml_node child : materialNode.children()) {
|
||||
if (!ASSIMP_stricmp(child.name(), "color")) { // Hex properties
|
||||
HexProperty prop;
|
||||
ReadHexProperty(prop);
|
||||
ReadHexProperty(prop, child);
|
||||
if (prop.name == "Diffuse") {
|
||||
ColorFromARGBPacked(prop.value, clr);
|
||||
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
|
||||
|
@ -206,13 +206,13 @@ aiMaterial *IrrlichtBase::ParseMaterial(unsigned int &matFlags) {
|
|||
#endif
|
||||
} else if (!ASSIMP_stricmp(child.name(), "float")) { // Float properties
|
||||
FloatProperty prop;
|
||||
ReadFloatProperty(prop);
|
||||
ReadFloatProperty(prop, child);
|
||||
if (prop.name == "Shininess") {
|
||||
mat->AddProperty(&prop.value, 1, AI_MATKEY_SHININESS);
|
||||
}
|
||||
} else if (!ASSIMP_stricmp(child.name(), "bool")) { // Bool properties
|
||||
BoolProperty prop;
|
||||
ReadBoolProperty(prop);
|
||||
ReadBoolProperty(prop, child);
|
||||
if (prop.name == "Wireframe") {
|
||||
int val = (prop.value ? true : false);
|
||||
mat->AddProperty(&val, 1, AI_MATKEY_ENABLE_WIREFRAME);
|
||||
|
@ -226,7 +226,7 @@ aiMaterial *IrrlichtBase::ParseMaterial(unsigned int &matFlags) {
|
|||
} else if (!ASSIMP_stricmp(child.name(), "texture") ||
|
||||
!ASSIMP_stricmp(child.name(), "enum")) { // String properties - textures and texture related properties
|
||||
StringProperty prop;
|
||||
ReadStringProperty(prop);
|
||||
ReadStringProperty(prop, child);
|
||||
if (prop.value.length()) {
|
||||
// material type (shader)
|
||||
if (prop.name == "Type") {
|
||||
|
@ -379,7 +379,7 @@ aiMaterial *IrrlichtBase::ParseMaterial(unsigned int &matFlags) {
|
|||
}
|
||||
}*/
|
||||
}
|
||||
ASSIMP_LOG_ERROR("IRRMESH: Unexpected end of file. Material is not complete");
|
||||
//ASSIMP_LOG_ERROR("IRRMESH: Unexpected end of file. Material is not complete");
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
|
|
@ -58,8 +58,7 @@ extern const aiMatrix4x4 AI_TO_IRR_MATRIX;
|
|||
*/
|
||||
class IrrlichtBase {
|
||||
protected:
|
||||
IrrlichtBase() :
|
||||
mNode(nullptr) {
|
||||
IrrlichtBase() {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -82,25 +81,25 @@ protected:
|
|||
|
||||
/// XML reader instance
|
||||
XmlParser mParser;
|
||||
pugi::xml_node *mNode;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a material description from the XML
|
||||
* @return The created material
|
||||
* @param matFlags Receives AI_IRRMESH_MAT_XX flags
|
||||
*/
|
||||
aiMaterial *ParseMaterial(unsigned int &matFlags);
|
||||
aiMaterial *ParseMaterial(pugi::xml_node &materialNode, unsigned int &matFlags);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Read a property of the specified type from the current XML element.
|
||||
* @param out Receives output data
|
||||
* @param node XML attribute element data
|
||||
*/
|
||||
void ReadHexProperty(HexProperty &out);
|
||||
void ReadStringProperty(StringProperty &out);
|
||||
void ReadBoolProperty(BoolProperty &out);
|
||||
void ReadFloatProperty(FloatProperty &out);
|
||||
void ReadVectorProperty(VectorProperty &out);
|
||||
void ReadIntProperty(IntProperty &out);
|
||||
void ReadHexProperty(HexProperty &out, pugi::xml_node& hexnode);
|
||||
void ReadStringProperty(StringProperty &out, pugi::xml_node& stringnode);
|
||||
void ReadBoolProperty(BoolProperty &out, pugi::xml_node& boolnode);
|
||||
void ReadFloatProperty(FloatProperty &out, pugi::xml_node& floatnode);
|
||||
void ReadVectorProperty(VectorProperty &out, pugi::xml_node& vectornode);
|
||||
void ReadIntProperty(IntProperty &out, pugi::xml_node& intnode);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue