Mitsuba loader structure modification
ADD
ext/MitsubaLoader/CElementFactory.cpp
+#include "CElementFactory.h"
+#include "irrlicht.h"
+
+#include <string>
+
+#include "ParserUtil.h"
+#include "CElementShapeCube.h"
+
+namespace irr { namespace ext { namespace MitsubaLoader {
+
+//TODO: elementFactory should be an actuall class with distinct private member functions..
+
+IElement* CElementFactory::createElement(const char* _el, const char** _atts)
+{
+ //should be removing white spaces performed before string comparison?
+ IElement* result = nullptr;
+ if (!std::strcmp(_el, "scene"))
+ {
+ return parseScene(_el, _atts);
+ }
+ if (!std::strcmp(_el, "shape"))
+ {
+ return parseShape(_el, _atts);
+ }
+ else
+ {
+ ParserLog::mitsubaLoaderError("invalid .xml file structure: element " + std::string(_el) + "is unknown. \n");
+ return nullptr;
+ }
+}
+
+IElement* CElementFactory::parseScene(const char* _el, const char** _atts)
+{
+ return new CMitsubaScene();
+}
+
+IElement* CElementFactory::parseShape(const char* _el, const char** _atts)
+{
+ IElement* result = nullptr;
+
+ for (int i = 0; _atts[i]; i += 2)
+ {
+ if (!std::strcmp(_atts[i], "type"))
+ {
+ if (!std::strcmp(_atts[i + 1], "cube"))
+ {
+ result = new CElementShapeCube();
+ os::Printer::print("We have done it! we created a cube! \n");
+ return result;
+ }
+ else
+ {
+ ParserLog::mitsubaLoaderError(std::string(_atts[i + 1]) + "is not a type of shape element. \n");
+ return nullptr;
+ }
+ }
+ }
+
+ ParserLog::mitsubaLoaderError("There is no type attribute for shape element. \n");
+}
+
+//shape element processing loop
+/*std::string shapeType = "";
+for (int i = 0; _attr[i]; i += 2)
+{
+ if (!std::strcmp(_attr[i], "type"))
+ {
+ if (!std::strcmp(_attr[i + 1], "cube"))
+ {
+ return nullptr;
+ }
+ else
+ {
+ std::cout << _attr[i + 1] << " is unknown shape type. \n";
+ }
+ }
+ else
+ {
+ std::cout << _attr[i] << "is unknown paramater of element shape.\n";
+ }
+
+}*/
+
+}
+}
+}
\ No newline at end of file

ADD
ext/MitsubaLoader/CElementFactory.h
+#ifndef __I_ELEMENT_FACTORY_H_INCLUDED__
+#define __I_ELEMENT_FACTORY_H_INCLUDED__
+
+#include "irr/asset/IAssetManager.h"
+#include "IElement.h"
+#include <memory>
+
+namespace irr { namespace ext { namespace MitsubaLoader {
+
+
+
+class CElementFactory
+{
+public:
+ //constructs certain elements based on element's name and its attributes
+ static IElement* createElement(const char* _el, const char** _atts);
+
+private:
+ static IElement* parseScene(const char* _el, const char** _atts);
+ static IElement* parseShape(const char* _el, const char** _atts);
+};
+
+}
+}
+}
+
+#endif
\ No newline at end of file

MODIFY
ext/MitsubaLoader/CElementShapeCube.cpp
ext/MitsubaLoader/CElementShapeCube.cpp
#include "CElementShapeCube.h"
+#include "ParserUtil.h"
+
namespace irr { namespace ext { namespace MitsubaLoader {
CElementShapeCube::CElementShapeCube()
@@ -7,30 +9,47 @@ CElementShapeCube::CElementShapeCube()
}
-bool CElementShapeCube::processAttributes(const char** _args)
+bool CElementShapeCube::processAttributes(const char** _atts)
+{
+ os::Printer::print("SHAPE CUBE ON BEGIN TAG");
+
+ //only type is an acceptable argument
+ for (int i = 0; _atts[i]; i += 2)
+ {
+ if (std::strcmp(_atts[i], "type"))
{
- //TODO: only type is an acceptable argument
+ ParserLog::wrongAttribute(_atts[i], getName());
+ return false;
+ }
+ }
+
return true;
}
-void CElementShapeCube::onEndTag(asset::IAssetManager& _assetManager, IElement* _parent)
+bool CElementShapeCube::onEndTag(asset::IAssetManager& _assetManager, IElement* _parent)
{
asset::ICPUMesh* cubeMesh = _assetManager.getGeometryCreator()->createCubeMesh(core::vector3df(2.0f, 2.0f, 2.0f));
+
+ os::Printer::print("SHAPE CUBE ON END TAG");
+
+ if (!cubeMesh)
+ return false;
+
//transform cubeMesh by this->transformMatrix
- _parent->processChildData(this);
+
+ return _parent->processChildData(this);
}
-void CElementShapeCube::processChildData(IElement* child)
+bool CElementShapeCube::processChildData(IElement* _child)
{
- switch (child->getType())
+ switch (_child->getType())
{
case IElement::Type::TO_WORLD_TRANSFORM:
- break;
+ return true;
default:
- std::cout << "Invalid .xml file structure: this is not a child of shape cube element. \n";
- break;
-
+ ParserLog::wrongChildElement(getName(), _child->getName());
+ return false;
}
}

MODIFY
ext/MitsubaLoader/CElementShapeCube.h
ext/MitsubaLoader/CElementShapeCube.h
@@ -13,9 +13,10 @@ public:
CElementShapeCube();
virtual bool processAttributes(const char** _args) override;
- virtual void onEndTag(asset::IAssetManager& _assetManager, IElement* _parent) override;
+ virtual bool onEndTag(asset::IAssetManager& _assetManager, IElement* _parent) override;
virtual IElement::Type getType() const override { return IElement::Type::SHAPE_CUBE; };
- virtual void processChildData(IElement* child) override;
+ virtual std::string getName() const override { return "shape cube"; };
+ virtual bool processChildData(IElement* child) override;
private:
core::matrix4SIMD transform;

MODIFY
ext/MitsubaLoader/CMitsubaLoader.cpp
ext/MitsubaLoader/CMitsubaLoader.cpp
#include <stack>
#include <chrono>
+#include "ParserUtil.h"
+
namespace irr { namespace ext { namespace MitsubaLoader {
//TODO:
@@ -21,116 +23,6 @@ namespace irr { namespace ext { namespace MitsubaLoader {
- use log functions instead of std::cout
*/
-//struct, which will be passed to expat handlers as user data (first argument) see: XML_StartElementHandler or XML_EndElementHandler in expat.h
-struct ParserData
-{
- //!Constructor
- ParserData(irr::asset::IAssetManager& _assetManager, XML_Parser _parser)
- : assetManager(_assetManager),
- isSceneActive(false),
- parser(_parser)
- {
-
- }
-
- irr::asset::IAssetManager& assetManager;
-
- /*root element, which will hold all loaded assets and material data
- in irr::asset::SCPUMesh (for now) instance*/
- CMitsubaScene scene;
-
- /*array of currently processed elements
- each element of index N is parent of the element of index N+1
- the scene element is a parent of all elements of index 0 */
- core::vector<IElement*> elements;
-
- /*used to control if first element in xml file is a scene,
- if not then .xml file is considered invalid and error is generated*/
- bool isSceneActive;
-
-
- XML_Parser parser;
-};
-
-static void elementHandlerStart(void* _data, const char* _el, const char** _atts)
-{
- ParserData* data = static_cast<ParserData*>(_data);
-
- if(!std::strcmp(_el, "scene"))
- {
- //if element being parsed is a scene and there was scene element parsed before (which is incorrect)
- if (data->isSceneActive)
- {
- std::cout << "invalid .xml file structure: \"scene\" cannot be child element of \"scene\" \n";
- //stop parsing and return nullptr from CMitsubaLoader::loadAsset
- }
- else
- {
- data->isSceneActive = true;
- data->scene.processAttributes(_atts);
- }
- }
- else
- {
- //if element being parsed is NOT a scene and there was scene element parsed before
- if (data->isSceneActive)
- {
- IElement* newElement = elementFactory(_el, _atts);
-
- if (newElement)
- {
- data->elements.push_back(newElement);
- }
- else
- {
- std::cout << "invalid .xml file structure: " << _el << " \n";
- //stop parsing and return nullptr from CMitsubaLoader::loadAsset
- }
-
- }
- else
- {
- std::cout << "invalid .xml file structure: there is no scene as a root element \n";
- //stop parsing and return nullptr from CMitsubaLoader::loadAsset
- }
- }
-
- //XML_StopParser(data->parser, false);
-}
-
-static void elementHandlerEnd(void* _data, const char* _el)
-{
- ParserData* data = static_cast<ParserData*>(_data);
-
- if (!std::strcmp(_el, "scene"))
- {
- if (!data->isSceneActive) //this scenario is not possible to happen i think (parser would return with XML_STATUS_ERROR anyway)
- {
- assert(false);
- std::cout << "invalid .xml file structure: wat? \n";
- //stop parsing and return nullptr from CMitsubaLoader::loadAsset
- }
- else
- {
- data->scene.onEndTag(data->assetManager, nullptr);
- data->isSceneActive = false;
- }
- }
- else
- {
- //here, array of elements should have at least one element
- assert(!data->elements.empty());
-
- IElement* element = *(data->elements.end() - 1);
- data->elements.pop_back();
-
- //
- IElement* parent = (data->elements.empty()) ? &(data->scene) : *(data->elements.end() - 1);
-
- element->onEndTag(data->assetManager, parent);
- delete element;
- }
-}
CMitsubaLoader::CMitsubaLoader(IrrlichtDevice* device)
:m_device(device),
@@ -148,6 +40,8 @@ bool CMitsubaLoader::isALoadableFileFormat(io::IReadFile* _file) const
return true;
}
+ //SHAPE CUBE ON BEGIN TAG printed twice
+
const char** CMitsubaLoader::getAssociatedFileExtensions() const
{
static const char* ext[]{ "xml", nullptr };
@@ -193,7 +87,11 @@ asset::IAsset* CMitsubaLoader::loadAsset(io::IReadFile* _file, const SAssetLoadP
}
XML_ParserFree(parser);
- return data.scene.releaseMesh();
+
+ if (!data.scene)
+ return nullptr;
+
+ return data.scene->releaseMesh();
}
}

MODIFY
ext/MitsubaLoader/CMitsubaLoader.h
ext/MitsubaLoader/CMitsubaLoader.h
#include "ISceneManager.h"
#include "IFileSystem.h"
#include "irr/asset/ICPUMesh.h"
-#include "irr/asset/bawformat/legacy/CBAWLegacy.h"
-#include "irr/asset/bawformat/CBlobsLoadingManager.h"
-#include "irr/asset/ICPUSkinnedMeshBuffer.h"
#include <iostream>

MODIFY
ext/MitsubaLoader/CMitsubaScene.cpp
ext/MitsubaLoader/CMitsubaScene.cpp
#include <iostream>
#include <string>
+#include "irrlicht.h"
+#include "ParserUtil.h"
+
namespace irr { namespace ext { namespace MitsubaLoader {
bool CMitsubaScene::processAttributes(const char** _atts)
{
+ os::Printer::print("SCENE ON BEGIN TAG");
+
if (std::strcmp(_atts[0], "version"))
{
- std::cout << "Invalid .xml file structure: " << _atts[0] << "is not attribute of the scene element \n";
+ ParserLog::wrongAttribute(_atts[0], getName());
return false;
- //return false and then stop parsing and return nullptr from CMitsubaLoader::loadAsset...
}
else
{
@@ -21,12 +25,13 @@ bool CMitsubaScene::processAttributes(const char** _atts)
}
}
-void CMitsubaScene::onEndTag(asset::IAssetManager& assetManager, IElement* parent)
+bool CMitsubaScene::onEndTag(asset::IAssetManager& assetManager, IElement* parent)
{
-
+ os::Printer::print("SCENE ON END TAG");
+ return true;
}
-void CMitsubaScene::processChildData(IElement* _child)
+bool CMitsubaScene::processChildData(IElement* _child)
{
//general idea is to retrive all asset data from child elements and put it in this->mesh
switch (_child->getType())
@@ -38,14 +43,17 @@ void CMitsubaScene::processChildData(IElement* _child)
CElementShapeObj childObjElement = static_cast<CElementShapeObj*>(_child);
_child->getMesh()->getMeshBufferCount();
*/
- break;
+ return false;
+
case IElement::Type::SHAPE_CUBE:
- std::cout << "Alright! Cube has been added to the scene! \n";
+ os::Printer::print("Alright! Cube has been added to the scene! \n");
+
+ return true;
- break;
default:
- std::cout << "Invalid .xml file structure: this is not a child of the scene element \n";
- break;
+ ParserLog::wrongChildElement(getName(), _child->getName());
+
+ return false;
}
}

MODIFY
ext/MitsubaLoader/CMitsubaScene.h
ext/MitsubaLoader/CMitsubaScene.h
#include "IElement.h"
#include "irr/asset/SCPUMesh.h"
+#include <memory>
+
namespace irr { namespace ext { namespace MitsubaLoader {
-//TODO: functions like processAttributes should have bool as return type (true if all arguemnts are valid)
-//TODO: change every std::cout << .. to log
-//root element
class CMitsubaScene : public IElement
{
public:
//! Constructor
CMitsubaScene()
- //acceptable?
:mesh(new asset::SCPUMesh) {}
virtual bool processAttributes(const char** _arguments) override;
- virtual void onEndTag(asset::IAssetManager& assetManager, IElement* parent) override;
+ virtual bool onEndTag(asset::IAssetManager& assetManager, IElement* parent) override;
virtual IElement::Type getType() const override { return IElement::Type::SCENE; };
- virtual void processChildData(IElement* child) override;
+ virtual std::string getName() const override { return "scene"; };
+ virtual bool processChildData(IElement* child) override;
- inline asset::SCPUMesh* releaseMesh() { return mesh; mesh = nullptr; }
+ asset::SCPUMesh* releaseMesh() { return mesh; mesh = nullptr; }
//void appendMesh(asset::ICPUMesh* mesh);
private:
asset::SCPUMesh* mesh;
+
};
}

DELETE
ext/MitsubaLoader/ElementFactory.cpp
-#include "IElement.h"
-
-#include <string>
-#include <iostream>
-
-#include "CElementShapeCube.h"
-
-namespace irr { namespace ext { namespace MitsubaLoader {
-
-//TODO: elementFactory should be an actuall class with distinct private member functions..
-
-IElement* elementFactory(const char* _el, const char** _atts)
-{
- //should be removing white spaces performed before string comparison?
- IElement* result = nullptr;
-
- if (!std::strcmp(_el, "shape"))
- {
- for (int i = 0; _atts[i]; i += 2)
- {
- if (!std::strcmp(_atts[i], "type"))
- {
- if (!std::strcmp(_atts[i + 1], "cube"))
- {
- result = new CElementShapeCube();
- result->processAttributes(_atts);
- std::cout << "We have done it! we created a cube! \n";
- return result;
- }
- else
- {
- std::cout << "invalid .xml file structure: " << _atts[i + 1] << "is not a type of shape element. \n";
- result = nullptr;
- }
- }
- }
-
- std::cout << "There is no type attribute for shape element. \n";
-
- }
- else
- {
- std::cout << "invalid .xml file structure: element " << _el << "is unknown. \n";
- return nullptr;
- }
-
- return nullptr;
-}
-
-//shape element processing loop
-/*std::string shapeType = "";
-for (int i = 0; _attr[i]; i += 2)
-{
- if (!std::strcmp(_attr[i], "type"))
- {
- if (!std::strcmp(_attr[i + 1], "cube"))
- {
- return nullptr;
- }
- else
- {
- std::cout << _attr[i + 1] << " is unknown shape type. \n";
- }
- }
- else
- {
- std::cout << _attr[i] << "is unknown paramater of element shape.\n";
- }
-
-}*/
-
-}
-}
-}
\ No newline at end of file

MODIFY
ext/MitsubaLoader/IElement.h
ext/MitsubaLoader/IElement.h
@@ -37,26 +37,24 @@ public:
};
public:
- //! default implementation for elements, which doesnt take any attributes
+ //! default implementation for elements that doesnt have any attributes
virtual bool processAttributes(const char** _atts)
{
if (_atts[0])
{
- std::cout << "Invalid .xml file structure: this element doesn't take any attributes \n";
+ std::cout << "Invalid .xml file structure: element " << getName().c_str() << " doesn't take any attributes \n";
return false;
}
return true;
};
- virtual void onEndTag(asset::IAssetManager& _assetManager, IElement* _parent) = 0;
+ virtual bool onEndTag(asset::IAssetManager& _assetManager, IElement* _parent) = 0;
virtual IElement::Type getType() const = 0;
- virtual void processChildData(IElement* child) = 0;
+ virtual std::string getName() const = 0;
+ virtual bool processChildData(IElement* child) = 0;
};
-//constructs certain elements based on element's name and its arguments
-IElement* elementFactory(const char* _el, const char** attr);
-
}
}
}

ADD
ext/MitsubaLoader/ParserUtil.cpp
+#include "ParserUtil.h"
+#include "irrlicht.h"
+#include "CElementFactory.h"
+
+namespace irr { namespace ext { namespace MitsubaLoader {
+
+void ParserLog::wrongAttribute(const std::string& attribName, const std::string& elementName)
+{
+ std::string message = "Mitsuba loader error:\nInvalid .xml file structure: attribute '"
+ + attribName + "' is not declared for element '" + elementName + "'\n";
+
+ //or os::Printer::log ?
+ os::Printer::print(message);
+}
+
+void ParserLog::wrongChildElement(const std::string& parentName, const std::string& childName)
+{
+ std::string message = "Mitsuba loader error:\nInvalid .xml file structure: '"
+ + parentName + "' is not a parent of '" + childName + "'\n";
+
+ //or os::Printer::log ?
+ os::Printer::print(message);
+}
+
+void ParserLog::mitsubaLoaderError(const std::string& errorMessage)
+{
+ std::string message = "Mitsuba loader error:\nInvalid .xml file structure: '"
+ + errorMessage + '\n';
+
+ //or os::Printer::log ?
+ os::Printer::print(message);
+}
+
+void elementHandlerStart(void* _data, const char* _el, const char** _atts)
+{
+ ParserData* data = static_cast<ParserData*>(_data);
+
+ std::unique_ptr<IElement> element(CElementFactory::createElement(_el, _atts));
+
+ //TODO: test ! operator of std::unique_ptr
+
+ if (!element)
+ {
+ XML_StopParser(data->parser, false);
+ return;
+ }
+
+ if (element->getName() == "scene")
+ {
+ if (!data->scene)
+ {
+
+ data->scene.reset(static_cast<CMitsubaScene*>(element.release()));
+ data->scene->processAttributes(_atts);
+ return;
+ }
+ else
+ {
+ ParserLog::wrongChildElement("scene", "scene");
+ XML_StopParser(data->parser, false);
+ return;
+ }
+ }
+
+ if (!data->scene)
+ {
+ ParserLog::mitsubaLoaderError("there is no scene element");
+ XML_StopParser(data->parser, false);
+ return;
+ }
+
+ if (!element->processAttributes(_atts))
+ {
+ XML_StopParser(data->parser, false);
+ return;
+ }
+
+ data->elements.push_back(std::move(element));
+}
+
+void elementHandlerEnd(void* _data, const char* _el)
+{
+ ParserData* data = static_cast<ParserData*>(_data);
+
+ if (data->elements.empty())
+ {
+ data->scene->onEndTag(data->assetManager, nullptr);
+ return;
+ }
+ else
+ {
+ std::unique_ptr<IElement> element = std::move(data->elements.back());
+ data->elements.pop_back();
+
+ IElement* parent = (data->elements.empty()) ? data->scene.get() : data->elements.back().get();
+
+ if (!element->onEndTag(data->assetManager, parent))
+ {
+ XML_StopParser(data->parser, false);
+ return;
+ }
+ }
+
+
+
+
+ //if (!std::strcmp(_el, "scene"))
+ //{
+ // if (!data->isSceneActive) //this scenario is not possible to happen i think (parser would return with XML_STATUS_ERROR anyway)
+ // {
+ // assert(false);
+ // std::cout << "invalid .xml file structure: wat? \n";
+ // //stop parsing and return nullptr from CMitsubaLoader::loadAsset
+ // }
+ // else
+ // {
+ // data->scene.onEndTag(data->assetManager, nullptr);
+ // data->isSceneActive = false;
+ // }
+ //}
+ //else
+ //{
+ // //here, array of elements should have at least one element
+ // assert(!data->elements.empty());
+
+ // IElement* element = *(data->elements.end() - 1);
+ // data->elements.pop_back();
+
+ // //
+ // IElement* parent = (data->elements.empty()) ? &(data->scene) : *(data->elements.end() - 1);
+
+ // element->onEndTag(data->assetManager, parent);
+ // delete element;
+ //}
+}
+
+}
+}
+}
\ No newline at end of file

ADD
ext/MitsubaLoader/ParserUtil.h
+#include "../3rdparty/libexpat/expat/lib/expat.h"
+#include "irr/asset/IAssetManager.h"
+
+#include "CMitsubaScene.h"
+#include "IElement.h"
+#include "CMitsubaScene.h"
+
+#include "irr/asset/IAssetLoader.h"
+#include "ISceneManager.h"
+#include "IFileSystem.h"
+#include "irr/asset/ICPUMesh.h"
+
+namespace irr { namespace ext { namespace MitsubaLoader {
+
+//struct, which will be passed to expat handlers as user data (first argument) see: XML_StartElementHandler or XML_EndElementHandler in expat.h
+struct ParserData
+{
+ //! Constructor
+ ParserData(irr::asset::IAssetManager& _assetManager, XML_Parser _parser)
+ : assetManager(_assetManager),
+ scene(nullptr),
+ parser(_parser)
+ {
+
+ }
+
+ irr::asset::IAssetManager& assetManager;
+
+ /*root element, which will hold all loaded assets and material data
+ in irr::asset::SCPUMesh (for now) instance*/
+ std::unique_ptr<CMitsubaScene> scene;
+
+ /*array of currently processed elements
+ each element of index N is parent of the element of index N+1
+ the scene element is a parent of all elements of index 0 */
+ core::vector<std::unique_ptr<IElement>> elements;
+
+ XML_Parser parser;
+};
+
+class ParserLog
+{
+public:
+ /*prints this message:
+ Mitsuba loader error:
+ Invalid .xml file structure: attribute 'attribName' is not declared for element 'elementName' */
+ static void wrongAttribute(const std::string& attribName, const std::string& elementName);
+
+ /*prints this message:
+ Mitsuba loader error:
+ Invalid .xml file structure: 'parentName' is not a parent of 'wrongChildName' */
+ static void wrongChildElement(const std::string& parentName, const std::string& childName);
+
+ /*prints this message:
+ Mitsuba loader error:
+ Invalid .xml file structure: message */
+ static void mitsubaLoaderError(const std::string& errorMessage);
+
+};
+
+void elementHandlerStart(void* _data, const char* _el, const char** _atts);
+void elementHandlerEnd(void* _data, const char* _el);
+
+}
+}
+}
\ No newline at end of file

Mitsuba loader structure modification