mitsuba loader update
MODIFY
examples_tests/18.MitsubaLoader/main.cpp
examples_tests/18.MitsubaLoader/main.cpp
#include <irrlicht.h>
#include "../3rdparty/portable-file-dialogs/portable-file-dialogs.h"
+#include "..\..\ext\MitsubaLoader\CMitsubaLoader.h"
using namespace irr;
using namespace core;
+bool quit = false;
+class MyEventReceiver : public IEventReceiver
+{
+public:
+
+ MyEventReceiver()
+ {
+ }
+
+ bool OnEvent(const SEvent& event)
+ {
+ if (event.EventType == irr::EET_KEY_INPUT_EVENT && !event.KeyInput.PressedDown)
+ {
+ switch (event.KeyInput.Key)
+ {
+ case irr::KEY_ESCAPE:
+ case irr::KEY_KEY_Q:
+ quit = true;
+ return true;
+ default:
+ break;
+ }
+ }
+
+ return false;
+ }
+
+private:
+};
+
int main()
{
- //pfd::settings::verbose(true);
+ srand(time(0));
+ // create device with full flexibility over creation parameters
+ // you can add more parameters if desired, check irr::SIrrlichtCreationParameters
+ irr::SIrrlichtCreationParameters params;
+ params.Bits = 24; //may have to set to 32bit for some platforms
+ params.ZBufferBits = 24; //we'd like 32bit here
+ params.DriverType = video::EDT_OPENGL; //! Only Well functioning driver, software renderer left for sake of 2D image drawing
+ params.WindowSize = dimension2d<uint32_t>(800, 600);
+ params.Fullscreen = false;
+ params.Vsync = true; //! If supported by target platform
+ params.Doublebuffer = true;
+ params.Stencilbuffer = false; //! This will not even be a choice soon
+ IrrlichtDevice* device = createDeviceEx(params);
+
+ if (device == 0)
+ return 1; // could not create selected driver.
+
+ video::IVideoDriver* driver = device->getVideoDriver();
+ io::IFileSystem* fs = device->getFileSystem();
+ asset::IAssetManager& am = device->getAssetManager();
+ //temporary solution ofc
+ ext::MitsubaLoader::CMitsubaLoader* loader = new ext::MitsubaLoader::CMitsubaLoader(device);
+
+#define MITSUBA_LOADER_TESTS
+
+#ifdef MITSUBA_LOADER_TESTS
+ std::string filePath = "C:\\IrrlichtBAW\\IrrlichtBAW\\ext\\MitsubaLoader\\testScene.xml";
+#else
pfd::message("Choose file to load", "Choose mitsuba XML file to load. \nIf you cancel or choosen file fails to load bathroom will be loaded.", pfd::choice::ok);
pfd::open_file file("Choose XML file", "", { "XML files (.xml)", "*.xml" });
-
std::string filePath = file.result().empty() ? "C:\\IrrlichtBAW\\/IrrlichtBAW\\examples_tests\\media\\mitsuba\\bathroom\\scene.xml" : file.result()[0];
+#endif
+
+ io::IReadFile* xmlFile = fs->createAndOpenFile(filePath.c_str());
+ loader->loadAsset(xmlFile, {});
+
- std::cout << filePath;
+ loader->drop();
+ device->drop();
return 0;
}

ADD
ext/MitsubaLoader/CCubeElement.h
ext/MitsubaLoader/CCubeElement.h
ADD
ext/MitsubaLoader/CElementShapeCube.cpp
+#include "CElementShapeCube.h"
+
+namespace irr { namespace ext { namespace MitsubaLoader {
+
+CElementShapeCube::CElementShapeCube()
+{
+
+}
+
+bool CElementShapeCube::processAttributes(const char** _args)
+{
+ //TODO: only type is an acceptable argument
+ return true;
+}
+
+void CElementShapeCube::onEndTag(asset::IAssetManager& _assetManager, IElement* _parent)
+{
+ asset::ICPUMesh* cubeMesh = _assetManager.getGeometryCreator()->createCubeMesh(core::vector3df(2.0f, 2.0f, 2.0f));
+ //transform cubeMesh by this->transformMatrix
+ _parent->processChildData(this);
+}
+
+void CElementShapeCube::processChildData(IElement* child)
+{
+ switch (child->getType())
+ {
+ case IElement::Type::TO_WORLD_TRANSFORM:
+ break;
+
+ default:
+ std::cout << "Invalid .xml file structure: this is not a child of shape cube element. \n";
+ break;
+
+ }
+}
+
+}
+}
+}
\ No newline at end of file

ADD
ext/MitsubaLoader/CMakeLists.txt
+include(../../cmake/common.cmake)
+#update_git_submodule(./stb)
+
+
+set(IRR_EXT_MITSUBA_LOADER_H
+ test.h
+)
+
+set(IRR_EXT_MITSUBA_LOADER_SRC
+ test.cpp
+)
+
+set(IRR_EXT_CEGUI_EXTERNAL_INCLUDE
+ "${MITSUBA_LOADER_INCLUDE_PATH}"
+)
+
+irr_create_ext_library_project(
+ MITSUBA_LOADER
+ "${IRR_EXT_MITSUBA_LOADER_H}"
+ "${IRR_EXT_MITSUBA_LOADER_SRC}"
+ "${IRR_EXT_MITSUBA_LOADER_EXTERNAL_INCLUDE}"
+ ""
+)

ADD
ext/MitsubaLoader/CMitsubaLoader.cpp
+#include "CMitsubaLoader.h"
+#include "../3rdparty/libexpat/expat/lib/expat.h"
+#include "irr/asset/SCPUMesh.h"
+#include "irr/asset/IAssetManager.h"
+
+#include "IElement.h"
+#include "CMitsubaScene.h"
+
+#include "IrrlichtDevice.h"
+#include <stack>
+#include <chrono>
+
+namespace irr { namespace ext { namespace MitsubaLoader {
+
+//TODO:
+/*
+ - smart pointers
+ - proper handling of incorrect .xml file structure (in some situations parsing should be stoped and nullptr should be returned
+ from CMitsubaLoader::loadAsset, and in other situations only warning should be shown.)
+ - handle situations when elementFactory returns nullptr
+ - 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),
+ m_assetManager(device->getAssetManager())
+{
+#ifdef _IRR_DEBUG
+ setDebugName("CMitsubaLoader");
+#endif
+}
+
+bool CMitsubaLoader::isALoadableFileFormat(io::IReadFile* _file) const
+{
+ //not implemented
+ _IRR_DEBUG_BREAK_IF(true);
+ return true;
+}
+
+const char** CMitsubaLoader::getAssociatedFileExtensions() const
+{
+ static const char* ext[]{ "xml", nullptr };
+ return ext;
+}
+
+asset::IAsset* CMitsubaLoader::loadAsset(io::IReadFile* _file, const SAssetLoadParams& _params, IAssetLoaderOverride* _override, uint32_t _hierarchyLevel)
+{
+ //TODO: error handling
+ XML_Parser parser = XML_ParserCreate(nullptr);
+ XML_SetElementHandler(parser, elementHandlerStart, elementHandlerEnd);
+
+ ParserData data(m_assetManager, parser);
+
+ //from now data (instance of ParserData struct) will be visible to expat handlers
+ XML_SetUserData(parser, &data);
+
+ const char* buff = new char[_file->getSize()];
+
+ //will replace it with something like safeRead from CBAWMeshLoader
+ _file->read((void*)buff, _file->getSize());
+
+ XML_Status parseStatus = XML_Parse(parser, buff, _file->getSize(), 0);
+
+ switch (parseStatus)
+ {
+ case XML_STATUS_ERROR:
+ std::cout << "Parse status: XML_STATUS_ERROR\n";
+ break;
+
+ case XML_STATUS_OK:
+ std::cout << "Parse status: XML_STATUS_OK\n";
+ break;
+
+ case XML_STATUS_SUSPENDED:
+ std::cout << "Parse status: XML_STATUS_SUSPENDED\n";
+ break;
+
+ default:
+ std::cout << "Parse status: XML_STATUS_SUSPENDED\n";
+ break;
+
+ }
+
+ XML_ParserFree(parser);
+ return data.scene.releaseMesh();
+}
+
+}
+}
+}
\ No newline at end of file

ADD
ext/MitsubaLoader/CMitsubaLoader.h
+#ifndef __C_MITSUBA_LOADER_H_INCLUDED__
+#define __C_MITSUBA_LOADER_H_INCLUDED__
+
+#include "irr/asset/IAssetLoader.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>
+
+namespace irr { namespace ext { namespace MitsubaLoader {
+
+class CMitsubaLoader : public asset::IAssetLoader
+{
+public:
+ //! Constructor
+ CMitsubaLoader(IrrlichtDevice* device);
+
+protected:
+ //! Destructor
+ virtual ~CMitsubaLoader() = default;
+
+public:
+ //! Check if the file might be loaded by this class
+ /** Check might look into the file.
+ \param file File handle to check.
+ \return True if file seems to be loadable. */
+ virtual bool isALoadableFileFormat(io::IReadFile* _file) const override;
+
+ //! Returns an array of string literals terminated by nullptr
+ virtual const char** getAssociatedFileExtensions() const override;
+
+ //! Returns the assets loaded by the loader
+ /** Bits of the returned value correspond to each IAsset::E_TYPE
+ enumeration member, and the return value cannot be 0. */
+ //virtual uint64_t getSupportedAssetTypesBitfield() const { return 0; }
+
+ //! Loads an asset from an opened file, returns nullptr in case of failure.
+ virtual asset::IAsset* loadAsset(io::IReadFile* _file, const SAssetLoadParams& _params, IAssetLoaderOverride* _override = nullptr, uint32_t _hierarchyLevel = 0u) override;
+
+private:
+ IrrlichtDevice* m_device;
+ asset::IAssetManager& m_assetManager;
+};
+
+}
+}
+}
+#endif
\ No newline at end of file

ADD
ext/MitsubaLoader/CMitsubaScene.cpp
+#include "CMitsubaScene.h"
+#include <iostream>
+#include <string>
+
+namespace irr { namespace ext { namespace MitsubaLoader {
+
+
+bool CMitsubaScene::processAttributes(const char** _atts)
+{
+ if (std::strcmp(_atts[0], "version"))
+ {
+ std::cout << "Invalid .xml file structure: " << _atts[0] << "is not attribute of the scene element \n";
+ return false;
+ //return false and then stop parsing and return nullptr from CMitsubaLoader::loadAsset...
+ }
+ else
+ {
+ //temporary solution
+ std::cout << "version: " << _atts[1] << '\n';
+ return true;
+ }
+}
+
+void CMitsubaScene::onEndTag(asset::IAssetManager& assetManager, IElement* parent)
+{
+
+}
+
+void CMitsubaScene::processChildData(IElement* _child)
+{
+ //general idea is to retrive all asset data from child elements and put it in this->mesh
+ switch (_child->getType())
+ {
+ case IElement::Type::SHAPE_OBJ:
+ //add contents of the mesh held by child here
+ //for example:
+ /*
+ CElementShapeObj childObjElement = static_cast<CElementShapeObj*>(_child);
+ _child->getMesh()->getMeshBufferCount();
+ */
+ break;
+ case IElement::Type::SHAPE_CUBE:
+ std::cout << "Alright! Cube has been added to the scene! \n";
+
+ break;
+ default:
+ std::cout << "Invalid .xml file structure: this is not a child of the scene element \n";
+ break;
+ }
+}
+
+
+}
+}
+}
\ No newline at end of file

ADD
ext/MitsubaLoader/CMitsubaScene.h
+#ifndef __C_MITSUBA_SCENE_H_INCLUDED__
+#define __C_MITSUBA_SCENE_H_INCLUDED__
+
+#include "IElement.h"
+#include "irr/asset/SCPUMesh.h"
+
+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 IElement::Type getType() const override { return IElement::Type::SCENE; };
+ virtual void processChildData(IElement* child) override;
+
+ inline asset::SCPUMesh* releaseMesh() { return mesh; mesh = nullptr; }
+ //void appendMesh(asset::ICPUMesh* mesh);
+
+private:
+ asset::SCPUMesh* mesh;
+};
+
+}
+}
+}
+#endif
\ No newline at end of file

ADD
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

ADD
ext/MitsubaLoader/IElement.h
+#ifndef __I_ELEMENT_H_INCLUDED__
+#define __I_ELEMENT_H_INCLUDED__
+
+#include "irr/asset/IAssetManager.h"
+#include <iostream>
+
+namespace irr { namespace ext { namespace MitsubaLoader {
+
+//TODO: Provide elements with getName member function which will return std::string.
+
+struct ParserData;
+
+class IElement
+{
+public:
+ enum class Type
+ {
+ SCENE,
+
+ //shapes
+ SHAPE_OBJ,
+ SHAPE_PLY,
+ SHAPE_SERIALIZED,
+ SHAPE_CUBE,
+ SHAPE_SPHERE,
+ SHAPE_CYLINDER,
+ SHAPE_DISK,
+ SHAPE_RECTANGLE,
+
+ //vectors, points, scalars
+ FLOAT_RADIUS,
+ POINT_CENTER,
+
+ //other
+ TO_WORLD_TRANSFORM,
+ TEXTURE
+ };
+
+public:
+ //! default implementation for elements, which doesnt take 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";
+ return false;
+ }
+
+ return true;
+ };
+ virtual void onEndTag(asset::IAssetManager& _assetManager, IElement* _parent) = 0;
+ virtual IElement::Type getType() const = 0;
+ virtual void processChildData(IElement* child) = 0;
+
+};
+
+//constructs certain elements based on element's name and its arguments
+IElement* elementFactory(const char* _el, const char** attr);
+
+}
+}
+}
+
+#endif
\ No newline at end of file

DELETE
ext/MitsubaLoader/test.h
-#include <iostream>
-
-namespace irr {
-namespace ext {
-namespace MitsubaLoader{
-
-void test()
-{
- std::cout << "Hello!\n";
-}
-
-}
-}
-}
\ No newline at end of file

ADD
ext/MitsubaLoader/testScene.exr
ext/MitsubaLoader/testScene.exr
Binary files /dev/null and b/ext/MitsubaLoader/testScene.exr differ

ADD
ext/MitsubaLoader/testScene.xml
+<?xml version="1.0" encoding="utf-8"?>
+
+<scene version="0.5.0">
+
+ <shape type="cube">
+
+ </shape>
+
+</scene>
\ No newline at end of file

mitsuba loader update