message: fixed smooth normal computation algorithm

diff:
-XD
\ No newline at end of file
+#include "CSmoothNormalGenerator.h"
+
+#include <iostream>
+#include <algorithm>
+#include <array>
+
+namespace irr
+{
+ namespace asset
+ {
+ static inline bool operator<(uint32_t lhs, const IMeshManipulator::SSNGVertexData& rhs)
+ {
+ return lhs < rhs.hash;
+ }
+
+ static inline bool operator<(const IMeshManipulator::SSNGVertexData& lhs, uint32_t rhs)
+ {
+ return lhs.hash < rhs;
+ }
+
+ static inline bool compareVertexPosition(const core::vectorSIMDf& a, const core::vectorSIMDf& b, float epsilon)
+ {
+ const core::vectorSIMDf difference = core::abs(b - a);
+ return (difference.x <= epsilon && difference.y <= epsilon && difference.z <= epsilon);
+ }
+
+ static inline core::vector3df_SIMD getAngleWeight(const core::vector3df_SIMD & v1,
+ const core::vector3df_SIMD & v2,
+ const core::vector3df_SIMD & v3)
+ {
+ // Calculate this triangle's weight for each of its three vertices
+ // start by calculating the lengths of its sides
+ const float a = v2.getDistanceFromSQAsFloat(v3);
+ const float asqrt = sqrtf(a);
+ const float b = v1.getDistanceFromSQAsFloat(v3);
+ const float bsqrt = sqrtf(b);
+ const float c = v1.getDistanceFromSQAsFloat(v2);
+ const float csqrt = sqrtf(c);
+
+ // use them to find the angle at each vertex
+ return core::vector3df_SIMD(
+ acosf((b + c - a) / (2.f * bsqrt * csqrt)),
+ acosf((-b + c + a) / (2.f * asqrt * csqrt)),
+ acosf((b - c + a) / (2.f * bsqrt * asqrt)));
+ }
+
+ asset::ICPUMeshBuffer * irr::asset::CSmoothNormalGenerator::calculateNormals(asset::ICPUMeshBuffer * buffer, float epsilon, asset::E_VERTEX_ATTRIBUTE_ID normalAttrID, IMeshManipulator::VxCmpFunction vxcmp)
+ {
+ VertexHashMap vertexArray = setupData(buffer, epsilon);
+ processConnectedVertices(buffer, vertexArray, epsilon, normalAttrID, vxcmp);
+
+ return buffer;
+ }
+
+ CSmoothNormalGenerator::VertexHashMap::VertexHashMap(size_t _vertexCount, uint32_t _hashTableMaxSize, float _cellSize)
+ :hashTableMaxSize(_hashTableMaxSize),
+ cellSize(_cellSize)
+ {
+ assert((core::isPoT(hashTableMaxSize)));
+
+ vertices.reserve(_vertexCount);
+ buckets.reserve(_hashTableMaxSize + 1);
+ }
+
+ uint32_t CSmoothNormalGenerator::VertexHashMap::hash(const IMeshManipulator::SSNGVertexData & vertex) const
+ {
+ static constexpr uint32_t primeNumber1 = 73856093;
+ static constexpr uint32_t primeNumber2 = 19349663;
+ static constexpr uint32_t primeNumber3 = 83492791;
+
+ const core::vector3df_SIMD position = vertex.position / cellSize;
+
+ return ((static_cast<uint32_t>(position.x) * primeNumber1) ^
+ (static_cast<uint32_t>(position.y) * primeNumber2) ^
+ (static_cast<uint32_t>(position.z) * primeNumber3))& (hashTableMaxSize - 1);
+ }
+
+ uint32_t CSmoothNormalGenerator::VertexHashMap::hash(const core::vector3du32_SIMD & position) const
+ {
+ static constexpr uint32_t primeNumber1 = 73856093;
+ static constexpr uint32_t primeNumber2 = 19349663;
+ static constexpr uint32_t primeNumber3 = 83492791;
+
+ return ((position.x * primeNumber1) ^
+ (position.y * primeNumber2) ^
+ (position.z * primeNumber3))& (hashTableMaxSize - 1);
+ }
+
+ void CSmoothNormalGenerator::VertexHashMap::add(IMeshManipulator::SSNGVertexData && vertex)
+ {
+ vertex.hash = hash(vertex);
+ vertices.push_back(vertex);
+ }
+
+ CSmoothNormalGenerator::VertexHashMap::BucketBounds CSmoothNormalGenerator::VertexHashMap::getBucketBoundsByHash(uint32_t hash)
+ {
+ if (hash == invalidHash)
+ return { vertices.end(), vertices.end() };
+
+ core::vector<IMeshManipulator::SSNGVertexData>::iterator begin = std::lower_bound(vertices.begin(), vertices.end(), hash);
+ core::vector<IMeshManipulator::SSNGVertexData>::iterator end = std::upper_bound(vertices.begin(), vertices.end(), hash);
+
+ //bucket missing
+ if (begin == vertices.end())
+ return { vertices.end(), vertices.end() };
+
+ //bucket missing
+ if (begin->hash != hash)
+ return { vertices.end(), vertices.end() };
+
+ return { begin, end };
+ }
+
+ void CSmoothNormalGenerator::VertexHashMap::validate()
+ {
+ std::sort(vertices.begin(), vertices.end(), [](IMeshManipulator::SSNGVertexData & a, IMeshManipulator::SSNGVertexData & b) { return a.hash < b.hash; });
+
+ uint16_t prevHash = vertices[0].hash;
+ core::vector<IMeshManipulator::SSNGVertexData>::iterator prevBegin = vertices.begin();
+ buckets.push_back(prevBegin);
+
+ while (true)
+ {
+ core::vector<IMeshManipulator::SSNGVertexData>::iterator next = std::upper_bound(prevBegin, vertices.end(), prevHash);
+ buckets.push_back(next);
+
+ if (next == vertices.end())
+ break;
+
+ prevBegin = next;
+ prevHash = next->hash;
+ }
+ }
+
+ CSmoothNormalGenerator::VertexHashMap CSmoothNormalGenerator::setupData(asset::ICPUMeshBuffer * buffer, float epsilon)
+ {
+ const size_t idxCount = buffer->getIndexCount();
+ _IRR_DEBUG_BREAK_IF((idxCount % 3));
+
+ VertexHashMap vertices(idxCount, std::min(16u * 1024u, core::roundUpToPoT<unsigned int>(idxCount * 1.0f / 32.0f)), epsilon == 0.0f ? 0.00001f : epsilon * 1.00001f);
+
+ core::vector3df_SIMD faceNormal;
+
+ for (uint32_t i = 0; i < idxCount; i += 3)
+ {
+ //calculate face normal of parent triangle
+ core::vectorSIMDf v1 = buffer->getPosition(i);
+ core::vectorSIMDf v2 = buffer->getPosition(i + 1);
+ core::vectorSIMDf v3 = buffer->getPosition(i + 2);
+
+ faceNormal = core::cross(v2 - v1, v3 - v1);
+ faceNormal = core::normalize(faceNormal);
+
+ //set data for vertices
+ core::vector3df_SIMD angleWages = getAngleWeight(v1, v2, v3);
+
+ vertices.add({ i, 0, angleWages.x, v1, faceNormal });
+ vertices.add({ i + 1, 0, angleWages.y, v2, faceNormal });
+ vertices.add({ i + 2, 0, angleWages.z, v3, faceNormal });
+ }
+
+ vertices.validate();
+
+ return vertices;
+ }
+
+ void CSmoothNormalGenerator::processConnectedVertices(asset::ICPUMeshBuffer * buffer, VertexHashMap & vertexHashMap, float epsilon, asset::E_VERTEX_ATTRIBUTE_ID normalAttrID, IMeshManipulator::VxCmpFunction vxcmp)
+ {
+ for (uint32_t cell = 0; cell < vertexHashMap.getBucketCount() - 1; cell++)
+ {
+ VertexHashMap::BucketBounds processedBucket = vertexHashMap.getBucketBoundsById(cell);
+
+ for (core::vector<IMeshManipulator::SSNGVertexData>::iterator processedVertex = processedBucket.begin; processedVertex != processedBucket.end; processedVertex++)
+ {
+ std::array<uint32_t, 8> neighboringCells = vertexHashMap.getNeighboringCellHashes(*processedVertex);
+ core::vector3df_SIMD normal = processedVertex->parentTriangleFaceNormal * processedVertex->wage;
+
+ //iterate among all neighboring cells
+ for (int i = 0; i < 8; i++)
+ {
+ VertexHashMap::BucketBounds bounds = vertexHashMap.getBucketBoundsByHash(neighboringCells[i]);
+ for (; bounds.begin != bounds.end; bounds.begin++)
+ {
+ if (processedVertex != bounds.begin)
+ if (compareVertexPosition(processedVertex->position, bounds.begin->position, epsilon) &&
+ vxcmp(*processedVertex, *bounds.begin, buffer))
+ {
+ //TODO: better mean calculation algorithm
+ normal += bounds.begin->parentTriangleFaceNormal * bounds.begin->wage;
+ }
+ }
+ }
+
+
+ normal = core::normalize(core::vectorSIMDf(normal));
+ buffer->setAttribute(normal, normalAttrID, processedVertex->indexOffset);
+ }
+ }
+
+
+ }
+
+ std::array<uint32_t, 8> CSmoothNormalGenerator::VertexHashMap::getNeighboringCellHashes(const IMeshManipulator::SSNGVertexData & vertex)
+ {
+ std::array<uint32_t, 8> neighbourhood;
+
+ core::vectorSIMDf cellFloatCoord = vertex.position / cellSize - core::vectorSIMDf(0.5f);
+ core::vector3du32_SIMD neighbor = core::vector3du32_SIMD(static_cast<uint32_t>(cellFloatCoord.x), static_cast<uint32_t>(cellFloatCoord.y), static_cast<uint32_t>(cellFloatCoord.z));
+
+ //left bottom near
+ neighbourhood[0] = hash(neighbor);
+
+ //right bottom near
+ neighbor = neighbor + core::vector3du32_SIMD(1, 0, 0);
+ neighbourhood[1] = hash(neighbor);
+
+ //right bottom far
+ neighbor = neighbor + core::vector3du32_SIMD(0, 0, 1);
+ neighbourhood[2] = hash(neighbor);
+
+ //left bottom far
+ neighbor = neighbor - core::vector3du32_SIMD(1, 0, 0);
+ neighbourhood[3] = hash(neighbor);
+
+ //left top far
+ neighbor = neighbor + core::vector3du32_SIMD(0, 1, 0);
+ neighbourhood[4] = hash(neighbor);
+
+ //right top far
+ neighbor = neighbor + core::vector3du32_SIMD(1, 0, 0);
+ neighbourhood[5] = hash(neighbor);
+
+ //righ top near
+ neighbor = neighbor - core::vector3du32_SIMD(0, 0, 1);
+ neighbourhood[6] = hash(neighbor);
+
+ //left top near
+ neighbor = neighbor - core::vector3du32_SIMD(1, 0, 0);
+ neighbourhood[7] = hash(neighbor);
+
+ //erase duplicated hashes
+ for (int i = 0; i < 8; i++)
+ {
+ uint32_t currHash = neighbourhood[i];
+ for (int j = i + 1; j < 8; j++)
+ {
+ if (neighbourhood[j] == currHash)
+ neighbourhood[j] = invalidHash;
+ }
+ }
+ return neighbourhood;
+ }
+
+ }
+}
\ No newline at end of file


message: few corrections

change_type: ADD

diff:
+// Copyright (C) 2002-2012 Nikolaus Gebhardt
+// This file is part of the "Irrlicht Engine".
+// For conditions of distribution and use, see copyright notice in irrlicht.h
+
+#ifndef __I_SCENE_NODE_ANIMATOR_CAMERA_MODIFIED_MAYA_H_INCLUDED__
+#define __I_SCENE_NODE_ANIMATOR_CAMERA_MODIFIED_MAYA_H_INCLUDED__
+
+#include "ISceneNodeAnimator.h"
+
+namespace irr
+{
+
+namespace scene
+{
+
+ //! Special scene node animator for Maya-style cameras
+ /** This scene node animator can be attached to a camera to make it act like a 3d
+ modelling tool.
+ The camera is moving relative to the target with the mouse, by pressing either
+ of the three buttons.
+ In order to move the camera, set a new target for the camera. The distance defines
+ the current orbit radius the camera moves on. Distance can be changed via the setter
+ or by mouse events.
+ */
+ class ISceneNodeAnimatorCameraModifiedMaya : public ISceneNodeAnimator
+ {
+ public:
+
+ //! Returns the speed of movement
+ virtual float getMoveSpeed() const = 0;
+
+ //! Sets the speed of movement
+ virtual void setMoveSpeed(float moveSpeed) = 0;
+
+ //! Returns the rotation speed
+ virtual float getRotateSpeed() const = 0;
+
+ //! Set the rotation speed
+ virtual void setRotateSpeed(float rotateSpeed) = 0;
+
+ //! Returns the zoom speed
+ virtual float getZoomSpeed() const = 0;
+
+ //! Returns the step zoom speed
+ virtual float getStepZoomSpeed() const = 0;
+
+ //! Set the zoom speed
+ virtual void setZoomSpeed(float zoomSpeed) = 0;
+
+ //! Set the zoom speed
+ virtual void setStepZoomSpeed(float stepZoomSpeed) = 0;
+
+ //! Returns the current distance, i.e. orbit radius
+ virtual float getDistance() const = 0;
+
+ // Enable/disable zooming when right button is pressed
+ virtual void toggleZoomWithRightButton() = 0;
+
+ //! Set the distance
+ virtual void setDistance(float distance) = 0;
+ };
+
+} // end namespace scene
+} // end namespace irr
+
+#endif
+

change_type: MODIFY

diff:
@@ -117,11 +117,6 @@ namespace irr
//! OnAnimate() is called just before rendering the whole scene.
void CSceneNodeAnimatorCameraModifiedMaya::animateNode(IDummyTransformationSceneNode* node, uint32_t timeMs)
{
-
- //Alt + LM = Rotate around camera pivot
- //Alt + LM + MM = Dolly forth/back in view direction (speed % distance camera pivot - max distance to pivot)
- //Alt + MM = Move on camera plane (Screen center is about the mouse pointer, depending on move speed)
-
if (!node || node->getType() != ESNT_CAMERA)
return;
@@ -141,7 +136,9 @@ namespace irr
float nRotY = RotY;
// Check for zooming with right-button
- if (ZoomWithRMB && isMouseKeyDown(2)) //if zoomWithRMB is enabled and RMB is pressed
+
+ if(!MouseShift)
+ if (ZoomWithRMB && isMouseKeyDown(2))
{
if (!Zooming)
{
@@ -156,24 +153,26 @@ namespace irr
ZoomStart = MousePos;
}
- else if (Zooming) //if zoomWithRMB is not enabled and RMB is not pressed and zooming has been performed in previous invocation
+ else if (Zooming)
{
Zooming = false;
-
}
// Zoom the cam
- core::vector3df zoomTarget(0, 0, 0); // move target to allow further zooming
+ core::vector3df zoomTarget(0.0f, 0.0f, 0.0f); // move target to allow further zooming
if (StepZooming || Zooming)
{
- CurrentZoom += (ZoomDelta * ZoomSpeed);
+ if (StepZooming)
+ CurrentZoom -= ZoomDelta * ScrllZoomSpeed;
+ else
+ CurrentZoom += ZoomDelta * ZoomSpeed;
- const float minDistance = 1.f;
+ const float minDistance = 1.0f;
if (CurrentZoom < minDistance)
{
zoomTarget = camera->getTarget() - camera->getPosition();
zoomTarget.setLength(-CurrentZoom + minDistance);
- CurrentZoom = 1.f;
+ CurrentZoom = 1.0f;
}
StepZooming = false;
}
@@ -290,9 +289,9 @@ namespace irr
// jox: fixed bug: jitter when rotating to the top and bottom of y
- core::vector3df UpVector(0, 1, 0);
- UpVector.rotateXYBy(-nRotY, core::vector3df(0, 0, 0));
- UpVector.rotateXZBy(-nRotX + 180.f, core::vector3df(0, 0, 0));
+ core::vector3df UpVector(0.0f, 1.0f, 0.0f);
+ UpVector.rotateXYBy(-nRotY, core::vector3df(0.0f, 0.0f, 0.0f));
+ UpVector.rotateXZBy(-nRotX + 180.0f, core::vector3df(0.0f, 0.0f, 0.0f));
camera->setUpVector(UpVector);
}
@@ -331,6 +330,11 @@ namespace irr
ZoomSpeed = speed;
}
+ //! Sets the zoom speed
+ void CSceneNodeAnimatorCameraModifiedMaya::setStepZoomSpeed(float speed)
+ {
+ ScrllZoomSpeed = speed;
+ }
//! Set the distance
void CSceneNodeAnimatorCameraModifiedMaya::setDistance(float distance)
@@ -359,6 +363,11 @@ namespace irr
return ZoomSpeed;
}
+ //! Gets the step zoom speed
+ float CSceneNodeAnimatorCameraModifiedMaya::getStepZoomSpeed() const
+ {
+ return ScrllZoomSpeed;
+ }
//! Returns the current distance, i.e. orbit radius
float CSceneNodeAnimatorCameraModifiedMaya::getDistance() const
@@ -366,6 +375,11 @@ namespace irr
return CurrentZoom;
}
+ void CSceneNodeAnimatorCameraModifiedMaya::toggleZoomWithRightButton()
+ {
+ ZoomWithRMB = !ZoomWithRMB;
+ }
+
ISceneNodeAnimator* CSceneNodeAnimatorCameraModifiedMaya::createClone(IDummyTransformationSceneNode * node, ISceneManager * newManager)
{

diff:
#ifndef __C_SCENE_NODE_ANIMATOR_CAMERA_MODIFIED_MAYA_H_INCLUDED__
#define __C_SCENE_NODE_ANIMATOR_CAMERA_MODIFIED_MAYA_H_INCLUDED__
-#include "ISceneNodeAnimatorCameraMaya.h"
+#include "ISceneNodeAnimatorCameraModifiedMaya.h"
#include "ICameraSceneNode.h"
#include "vector2d.h"
@@ -24,7 +24,7 @@ namespace irr
/** This scene node animator can be attached to a camera to make it act
like a 3d modelling tool camera
*/
- class CSceneNodeAnimatorCameraModifiedMaya : public ISceneNodeAnimatorCameraMaya
+ class CSceneNodeAnimatorCameraModifiedMaya : public ISceneNodeAnimatorCameraModifiedMaya
{
protected:
//! Destructor
@@ -37,43 +37,52 @@ namespace irr
float scrollZoomSpeed = 10.0f, bool zoomWithRBM = false);
//! Animates the scene node, currently only works on cameras
- virtual void animateNode(IDummyTransformationSceneNode* node, uint32_t timeMs);
+ virtual void animateNode(IDummyTransformationSceneNode* node, uint32_t timeMs) override;
//! Event receiver
- virtual bool OnEvent(const SEvent& event);
+ virtual bool OnEvent(const SEvent& event) override;
//! Returns the speed of movement in units per millisecond
- virtual float getMoveSpeed() const;
+ virtual float getMoveSpeed() const override;
//! Sets the speed of movement in units per millisecond
- virtual void setMoveSpeed(float moveSpeed);
+ virtual void setMoveSpeed(float moveSpeed) override;
//! Returns the rotation speed
- virtual float getRotateSpeed() const;
+ virtual float getRotateSpeed() const override;
//! Set the rotation speed
- virtual void setRotateSpeed(float rotateSpeed);
+ virtual void setRotateSpeed(float rotateSpeed) override;
//! Returns the zoom speed
- virtual float getZoomSpeed() const;
+ virtual float getZoomSpeed() const override;
+
+ //! Returns the step zoom speed
+ virtual float getStepZoomSpeed() const override;
//! Set the zoom speed
- virtual void setZoomSpeed(float zoomSpeed);
+ virtual void setZoomSpeed(float zoomSpeed) override;
+
+ //! Set the step zoom speed
+ virtual void setStepZoomSpeed(float zoomSpeed) override;
//! Returns the current distance, i.e. orbit radius
- virtual float getDistance() const;
+ virtual float getDistance() const override;
//! Set the distance
- virtual void setDistance(float distance);
+ virtual void setDistance(float distance) override;
//! This animator will receive events when attached to the active camera
- virtual bool isEventReceiverEnabled() const
+ virtual bool isEventReceiverEnabled() const override
{
return true;
}
+ //! Enable/disable zooming when right button is pressed
+ virtual void toggleZoomWithRightButton() override;
+
//! Returns type of the scene node
- virtual ESCENE_NODE_ANIMATOR_TYPE getType() const
+ virtual ESCENE_NODE_ANIMATOR_TYPE getType() const override
{
return ESNAT_CAMERA_MODIFIED_MAYA;
}
@@ -82,7 +91,7 @@ namespace irr
/** Please note that you will have to drop
(IReferenceCounted::drop()) the returned pointer after calling
this. */
- virtual ISceneNodeAnimator* createClone(IDummyTransformationSceneNode* node, ISceneManager* newManager = 0);
+ virtual ISceneNodeAnimator* createClone(IDummyTransformationSceneNode* node, ISceneManager* newManager = 0) override;
private:
void allKeysUp();

license: Apache License 2.0

repo: buildaworldnet/irrlichtbaw

original_message: few corrections


message: Deleted undesired line of code

diff:
@@ -136,8 +136,6 @@ namespace irr
float nRotY = RotY;
// Check for zooming with right-button
-
- if(!MouseShift)
if (ZoomWithRMB && isMouseKeyDown(2))
{
if (!Zooming)

original_message: Deleted undesired line of code


message: mitsuba loader update

diff:
#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;
}

diff:
+#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

diff:
+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}"
+ ""
+)

diff:
+#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

diff:
+#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

diff:
+#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

diff:
+#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

diff:
+#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

diff:
+#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

change_type: DELETE

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

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

diff:
+<?xml version="1.0" encoding="utf-8"?>
+
+<scene version="0.5.0">
+
+ <shape type="cube">
+
+ </shape>
+
+</scene>
\ No newline at end of file

original_message: mitsuba loader update


message: Mitsuba loader structure modification

diff:
+#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

diff:
+#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

diff:
#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;
}
}

diff:
@@ -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;

diff:
#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();
}
}

diff:
#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>

diff:
#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;
}
}

diff:
#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;
+
};
}

diff:
-#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

diff:
@@ -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);
-
}
}
}

diff:
+#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

diff:
+#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

original_message: Mitsuba loader structure modification


message: added CSimpleElement

diff:
#include <string>
#include "ParserUtil.h"
+#include "IElement.h"
#include "CElementShapeCube.h"
+#include "CSimpleElement.h"
namespace irr { namespace ext { namespace MitsubaLoader {
@@ -22,6 +24,22 @@ IElement* CElementFactory::createElement(const char* _el, const char** _atts)
{
return parseShape(_el, _atts);
}
+ if (!std::strcmp(_el, "float"))
+ {
+ return parseSimpleElement(_el, _atts, IElement::Type::FLOAT);
+ }
+ if (!std::strcmp(_el, "integer"))
+ {
+ return parseSimpleElement(_el, _atts, IElement::Type::INTEGER);
+ }
+ if (!std::strcmp(_el, "boolean"))
+ {
+ return parseSimpleElement(_el, _atts, IElement::Type::BOOLEAN);
+ }
+ if (!std::strcmp(_el, "point"))
+ {
+ return parseSimpleElement(_el, _atts, IElement::Type::POINT);
+ }
else
{
ParserLog::mitsubaLoaderError("invalid .xml file structure: element " + std::string(_el) + "is unknown. \n");
@@ -44,9 +62,7 @@ IElement* CElementFactory::parseShape(const char* _el, const char** _atts)
{
if (!std::strcmp(_atts[i + 1], "cube"))
{
- result = new CElementShapeCube();
- os::Printer::print("We have done it! we created a cube! \n");
- return result;
+ return new CElementShapeCube();
}
else
{
@@ -57,30 +73,32 @@ IElement* CElementFactory::parseShape(const char* _el, const char** _atts)
}
ParserLog::mitsubaLoaderError("There is no type attribute for shape element. \n");
+ return nullptr;
}
-//shape element processing loop
-/*std::string shapeType = "";
-for (int i = 0; _attr[i]; i += 2)
+IElement* CElementFactory::parseSimpleElement(const char* _el, const char** _atts, IElement::Type type)
{
- if (!std::strcmp(_attr[i], "type"))
+ switch (type)
{
- if (!std::strcmp(_attr[i + 1], "cube"))
+ case IElement::Type::FLOAT:
+ return new CElementFloat();
+ case IElement::Type::INTEGER:
{
+ //not implemented
+ _IRR_DEBUG_BREAK_IF(true);
return nullptr;
}
- else
- {
- std::cout << _attr[i + 1] << " is unknown shape type. \n";
- }
+ case IElement::Type::BOOLEAN:
+ return new CElementBoolean();
+ case IElement::Type::POINT:
+ return new CElementPoint();
+ default:
+ _IRR_DEBUG_BREAK_IF(true);
+ return nullptr;
}
- else
- {
- std::cout << _attr[i] << "is unknown paramater of element shape.\n";
+ return new CElementFloat();
}
-}*/
-
}
}
}
\ No newline at end of file

diff:
@@ -18,6 +18,7 @@ public:
private:
static IElement* parseScene(const char* _el, const char** _atts);
static IElement* parseShape(const char* _el, const char** _atts);
+ static IElement* parseSimpleElement(const char* _el, const char** _atts, IElement::Type type);
};
}

diff:
@@ -11,14 +11,13 @@ CElementShapeCube::CElementShapeCube()
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"))
{
- ParserLog::wrongAttribute(_atts[i], getName());
+ ParserLog::wrongAttribute(_atts[i], getLogName());
return false;
}
}
@@ -30,8 +29,6 @@ bool CElementShapeCube::onEndTag(asset::IAssetManager& _assetManager, IElement*
{
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;
@@ -44,11 +41,11 @@ bool CElementShapeCube::processChildData(IElement* _child)
{
switch (_child->getType())
{
- case IElement::Type::TO_WORLD_TRANSFORM:
+ case IElement::Type::TRANSFORM:
return true;
default:
- ParserLog::wrongChildElement(getName(), _child->getName());
+ ParserLog::wrongChildElement(getLogName(), _child->getLogName());
return false;
}
}

diff:
@@ -15,7 +15,7 @@ public:
virtual bool processAttributes(const char** _args) override;
virtual bool onEndTag(asset::IAssetManager& _assetManager, IElement* _parent) override;
virtual IElement::Type getType() const override { return IElement::Type::SHAPE_CUBE; };
- virtual std::string getName() const override { return "shape cube"; };
+ virtual std::string getLogName() const override { return "shape cube"; };
virtual bool processChildData(IElement* child) override;
private:

diff:
@@ -16,11 +16,17 @@ namespace irr { namespace ext { namespace MitsubaLoader {
//TODO:
/*
- - smart pointers
+ - !!!!!!!! REDUCE NUMBER OF ENUMS IN IElement::Type
+ - consider if getName function is really needed (getLogName maybe?)
+
- 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
+ - handle 'version' attribute
+
+ - make sure default values for <float .. /> <boolean .. /> etc. are correct
+ - test atof function (CSimpleElement.h)
+
+
*/

diff:
@@ -10,11 +10,10 @@ 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"))
{
- ParserLog::wrongAttribute(_atts[0], getName());
+ ParserLog::wrongAttribute(_atts[0], getLogName());
return false;
}
else
@@ -27,7 +26,6 @@ bool CMitsubaScene::processAttributes(const char** _atts)
bool CMitsubaScene::onEndTag(asset::IAssetManager& assetManager, IElement* parent)
{
- os::Printer::print("SCENE ON END TAG");
return true;
}
@@ -51,9 +49,9 @@ bool CMitsubaScene::processChildData(IElement* _child)
return true;
default:
- ParserLog::wrongChildElement(getName(), _child->getName());
+ ParserLog::wrongChildElement(getLogName(), _child->getLogName());
- return false;
+ return true;
}
}

diff:
@@ -19,7 +19,7 @@ public:
virtual bool processAttributes(const char** _arguments) override;
virtual bool onEndTag(asset::IAssetManager& assetManager, IElement* parent) override;
virtual IElement::Type getType() const override { return IElement::Type::SCENE; };
- virtual std::string getName() const override { return "scene"; };
+ virtual std::string getLogName() const override { return "scene"; };
virtual bool processChildData(IElement* child) override;
asset::SCPUMesh* releaseMesh() { return mesh; mesh = nullptr; }

diff:
+#ifndef __C_SIMPLE_ELEMENT_H_INCLUDED__
+#define __C_SIMPLE_ELEMENT_H_INCLUDED__
+
+#include "IElement.h"
+#include "../include/irr/static_if.h"
+#include "ParserUtil.h"
+
+#include "irrlicht.h"
+
+namespace irr { namespace ext { namespace MitsubaLoader {
+
+template<typename T>
+class CSimpleElement : public IElement
+{
+ static_assert(
+ std::is_same<T, float>::value ||
+ std::is_same<T, bool>::value ||
+ std::is_same<T, core::vector3df_SIMD>::value,
+ "assertion failed: cannot use this type");
+
+public:
+ CSimpleElement()
+ :type(IElement::Type::NONE),
+ value(0.0f)
+ {
+ IRR_PSEUDO_IF_CONSTEXPR_BEGIN(std::is_same<T, float>::value)
+ {
+ logName = "float";
+ return;
+ }
+ IRR_PSEUDO_IF_CONSTEXPR_END
+
+ IRR_PSEUDO_IF_CONSTEXPR_BEGIN(std::is_same<T, bool>::value)
+ {
+ logName = "boolean";
+ return;
+ }
+ IRR_PSEUDO_IF_CONSTEXPR_END
+
+ IRR_PSEUDO_IF_CONSTEXPR_BEGIN(std::is_same<T, core::vector3df_SIMD>::value)
+ {
+ logName = "point";
+ return;
+ }
+ IRR_PSEUDO_IF_CONSTEXPR_END
+ };
+
+ virtual bool processAttributes(const char** _atts) override;
+ virtual bool onEndTag(asset::IAssetManager& _assetManager, IElement* _parent) override
+ {
+ //so far it is only for testing purpose
+
+ os::Printer::print("\t" + getLogName() + " name: " + nameAttr + " value: ");
+ //os::Printer::print(value);
+
+ return true;
+ }
+ virtual IElement::Type getType() const override { return type; };
+ virtual std::string getLogName() const override { return logName; };
+
+ inline std::string getNameAttribute() const { return nameAttr; }
+ inline T getValueAttribute() const { return valueAttr; }
+
+private:
+ T value;
+ IElement::Type type;
+ std::string logName;
+
+ std::string nameAttr;
+ T valueAttr;
+};
+
+using CElementFloat = CSimpleElement<float>;
+using CElementBoolean = CSimpleElement<bool>;
+using CElementPoint = CSimpleElement<irr::core::vector3df_SIMD>;
+
+template<typename T>
+bool CSimpleElement<T>::processAttributes(const char** _atts)
+{
+ static_assert(false);
+}
+
+template<>
+bool CSimpleElement<float>::processAttributes(const char** _atts)
+{
+ bool isNameSet = false;
+
+ for (int i = 0; _atts[i]; i += 2)
+ {
+ if (!std::strcmp(_atts[i], "name"))
+ {
+ if (!std::strcmp(_atts[i + 1], "radius") ||
+ !std::strcmp(_atts[i + 1], "maxSmoothAngle"))
+ {
+ nameAttr = _atts[i + 1];
+ isNameSet = true;
+ }
+ else
+ {
+ //print warning
+ }
+ }
+ else if (!std::strcmp(_atts[i], "value"))
+ {
+ value = static_cast<float>(atof(_atts[i + 1]));
+ }
+ else
+ {
+ //print warning
+ }
+
+ }
+
+ if (!isNameSet)
+ ;//print error
+
+ return isNameSet;
+}
+
+template<>
+bool CSimpleElement<bool>::processAttributes(const char** _atts)
+{
+ bool isNameSet = false;
+
+ for (int i = 0; _atts[i]; i += 2)
+ {
+ if (!std::strcmp(_atts[i], "name"))
+ {
+ if (!std::strcmp(_atts[i + 1], "flipNormals") ||
+ !std::strcmp(_atts[i + 1], "flipTexCoords") ||
+ !std::strcmp(_atts[i + 1], "faceNormals") ||
+ !std::strcmp(_atts[i + 1], "srgb"))
+ {
+ nameAttr = _atts[i + 1];
+ isNameSet = true;
+ }
+ else
+ {
+ //print warning
+ }
+ }
+
+
+ if (!std::strcmp(_atts[i], "value"))
+ {
+ if (!std::strcmp(_atts[i + 1], "true"))
+ value = true;
+ else if (!std::strcmp(_atts[i + 1], "true"))
+ value = false;
+ else
+ {
+ //print warning
+ }
+ }
+ }
+
+ return isNameSet;
+}
+
+template<>
+bool CSimpleElement<core::vector3df_SIMD>::processAttributes(const char** _atts)
+{
+ bool isNameSet = false;
+
+ return isNameSet;
+}
+
+}
+}
+}
+
+#endif
\ No newline at end of file

diff:
@@ -15,6 +15,7 @@ class IElement
public:
enum class Type
{
+ NONE,
SCENE,
//shapes
@@ -28,11 +29,13 @@ public:
SHAPE_RECTANGLE,
//vectors, points, scalars
- FLOAT_RADIUS,
- POINT_CENTER,
+ FLOAT,
+ BOOLEAN,
+ INTEGER,
+ POINT,
//other
- TO_WORLD_TRANSFORM,
+ TRANSFORM,
TEXTURE
};
@@ -42,16 +45,26 @@ public:
{
if (_atts[0])
{
- std::cout << "Invalid .xml file structure: element " << getName().c_str() << " doesn't take any attributes \n";
+ std::cout << "Invalid .xml file structure: element " << getLogName().c_str() << " doesn't take any attributes \n";
return false;
}
return true;
- };
+ }
+ //! default implementation for elements that doesnt have any children
+ virtual bool processChildData(IElement* _child)
+ {
+ if (_child != nullptr)
+ {
+ //ParserLog::wrongChildElement(getName(), _child->getName());
+ return false;
+ }
+ return true;
+ }
virtual bool onEndTag(asset::IAssetManager& _assetManager, IElement* _parent) = 0;
virtual IElement::Type getType() const = 0;
- virtual std::string getName() const = 0;
- virtual bool processChildData(IElement* child) = 0;
+ virtual std::string getLogName() const = 0;
+
};

diff:
@@ -11,6 +11,8 @@ void ParserLog::wrongAttribute(const std::string& attribName, const std::string&
//or os::Printer::log ?
os::Printer::print(message);
+
+ _IRR_DEBUG_BREAK_IF(true);
}
void ParserLog::wrongChildElement(const std::string& parentName, const std::string& childName)
@@ -20,6 +22,8 @@ void ParserLog::wrongChildElement(const std::string& parentName, const std::stri
//or os::Printer::log ?
os::Printer::print(message);
+
+ _IRR_DEBUG_BREAK_IF(true);
}
void ParserLog::mitsubaLoaderError(const std::string& errorMessage)
@@ -29,6 +33,8 @@ void ParserLog::mitsubaLoaderError(const std::string& errorMessage)
//or os::Printer::log ?
os::Printer::print(message);
+
+ _IRR_DEBUG_BREAK_IF(true);
}
void elementHandlerStart(void* _data, const char* _el, const char** _atts)
@@ -37,15 +43,14 @@ void elementHandlerStart(void* _data, const char* _el, const char** _atts)
std::unique_ptr<IElement> element(CElementFactory::createElement(_el, _atts));
- //TODO: test ! operator of std::unique_ptr
-
if (!element)
{
XML_StopParser(data->parser, false);
+ _IRR_DEBUG_BREAK_IF(true);
return;
}
- if (element->getName() == "scene")
+ if (element->getType() == IElement::Type::SCENE)
{
if (!data->scene)
{
@@ -58,6 +63,7 @@ void elementHandlerStart(void* _data, const char* _el, const char** _atts)
{
ParserLog::wrongChildElement("scene", "scene");
XML_StopParser(data->parser, false);
+ _IRR_DEBUG_BREAK_IF(true);
return;
}
}
@@ -66,12 +72,14 @@ void elementHandlerStart(void* _data, const char* _el, const char** _atts)
{
ParserLog::mitsubaLoaderError("there is no scene element");
XML_StopParser(data->parser, false);
+ _IRR_DEBUG_BREAK_IF(true);
return;
}
if (!element->processAttributes(_atts))
{
XML_StopParser(data->parser, false);
+ _IRR_DEBUG_BREAK_IF(true);
return;
}
@@ -97,6 +105,7 @@ void elementHandlerEnd(void* _data, const char* _el)
if (!element->onEndTag(data->assetManager, parent))
{
XML_StopParser(data->parser, false);
+ _IRR_DEBUG_BREAK_IF(true);
return;
}
}

diff:
+#ifndef __I_PARSER_UTIL_H_INCLUDED__
+#define __I_PARSER_UTIL_H_INCLUDED__
+
#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"
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
{
@@ -64,3 +68,5 @@ void elementHandlerEnd(void* _data, const char* _el);
}
}
}
+
+#endif
\ No newline at end of file

diff:
<scene version="0.5.0">
+ <float name="radius" value="70" />
+ <boolean name="flipNormals" value = "true" />
+
+ <shape type="cube">
+
+ </shape>
+
<shape type="cube">
</shape>

original_message: added CSimpleElement


message: added CElementShapeOBJ

diff:
#include "ParserUtil.h"
#include "IElement.h"
#include "CElementShapeCube.h"
+#include "CElementShapeOBJ.h"
#include "CSimpleElement.h"
namespace irr { namespace ext { namespace MitsubaLoader {
@@ -40,6 +41,10 @@ IElement* CElementFactory::createElement(const char* _el, const char** _atts)
{
return parseSimpleElement(_el, _atts, IElement::Type::POINT);
}
+ if (!std::strcmp(_el, "string"))
+ {
+ return parseSimpleElement(_el, _atts, IElement::Type::STRING);
+ }
else
{
ParserLog::mitsubaLoaderError("invalid .xml file structure: element " + std::string(_el) + "is unknown. \n");
@@ -64,6 +69,10 @@ IElement* CElementFactory::parseShape(const char* _el, const char** _atts)
{
return new CElementShapeCube();
}
+ if (!std::strcmp(_atts[i + 1], "obj"))
+ {
+ return new CElementShapeOBJ();
+ }
else
{
ParserLog::mitsubaLoaderError(std::string(_atts[i + 1]) + "is not a type of shape element. \n");
@@ -82,6 +91,10 @@ IElement* CElementFactory::parseSimpleElement(const char* _el, const char** _att
{
case IElement::Type::FLOAT:
return new CElementFloat();
+
+ case IElement::Type::STRING:
+ return new CElementString();
+
case IElement::Type::INTEGER:
{
//not implemented
@@ -90,13 +103,15 @@ IElement* CElementFactory::parseSimpleElement(const char* _el, const char** _att
}
case IElement::Type::BOOLEAN:
return new CElementBoolean();
+
case IElement::Type::POINT:
return new CElementPoint();
+
default:
_IRR_DEBUG_BREAK_IF(true);
return nullptr;
+
}
- return new CElementFloat();
}
}

diff:
+#include "CElementShapeOBJ.h"
+
+#include "ParserUtil.h"
+#include "CSimpleElement.h"
+
+namespace irr { namespace ext { namespace MitsubaLoader {
+
+
+CElementShapeOBJ::~CElementShapeOBJ()
+{
+ if (mesh)
+ mesh->drop();
+}
+
+bool CElementShapeOBJ::processAttributes(const char** _atts)
+{
+ //only type is an acceptable argument
+ for (int i = 0; _atts[i]; i += 2)
+ {
+ if (std::strcmp(_atts[i], "type"))
+ {
+ ParserLog::wrongAttribute(_atts[i], getLogName());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool CElementShapeOBJ::onEndTag(asset::IAssetManager& _assetManager, IElement* _parent)
+{
+ if (!fileName.size())
+ {
+ _IRR_DEBUG_BREAK_IF(true);
+ //print error (name of the .obj file is not set)
+ return false;
+ }
+
+ //getAssetInHierarchy?
+ mesh = static_cast<asset::ICPUMesh*>(_assetManager.getAsset(fileName, asset::IAssetLoader::SAssetLoadParams()));
+
+ if (!mesh)
+ return false;
+
+ //transform mesh by this->transformMatrix
+
+ return _parent->processChildData(this);
+}
+
+bool CElementShapeOBJ::processChildData(IElement* _child)
+{
+ switch (_child->getType())
+ {
+ case IElement::Type::TRANSFORM:
+ return true;
+
+ case IElement::Type::STRING:
+ {
+ CElementString* stringElement = static_cast<CElementString*>(_child);
+
+ if (stringElement->getNameAttribute() == "filename")
+ {
+ fileName = stringElement->getValueAttribute();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ default:
+ ParserLog::wrongChildElement(getLogName(), _child->getLogName());
+ return false;
+ }
+}
+
+}
+}
+}
\ No newline at end of file

diff:
@@ -16,9 +16,6 @@ namespace irr { namespace ext { namespace MitsubaLoader {
//TODO:
/*
- - !!!!!!!! REDUCE NUMBER OF ENUMS IN IElement::Type
- - consider if getName function is really needed (getLogName maybe?)
-
- 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 'version' attribute
@@ -26,6 +23,9 @@ namespace irr { namespace ext { namespace MitsubaLoader {
- make sure default values for <float .. /> <boolean .. /> etc. are correct
- test atof function (CSimpleElement.h)
+ - how should loader treat upper/lower case letters in xml?
+
+ - clean up memory dynamically allocated by ParserData::scene
*/

diff:
#include "irrlicht.h"
#include "ParserUtil.h"
+#include "CElementSHapeOBJ.h"
+#include "CSimpleElement.h"
+
namespace irr { namespace ext { namespace MitsubaLoader {
@@ -35,19 +38,38 @@ bool CMitsubaScene::processChildData(IElement* _child)
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();
- */
+ {
+ CElementShapeOBJ* shape = static_cast<CElementShapeOBJ*>(_child);
+ const asset::ICPUMesh* shapeMesh = shape->getMesh();
+
+
+ if (!shapeMesh)
+ {
+ _IRR_DEBUG_BREAK_IF(true);
return false;
+ }
+
+
+ //is it possible that shapeMesh->getMeshBufferCount() > 1 ?
+ for (int i = 0; i < shapeMesh->getMeshBufferCount(); i++)
+ mesh->addMeshBuffer(shapeMesh->getMeshBuffer(i));
+
+
+ return true;
+ }
case IElement::Type::SHAPE_CUBE:
os::Printer::print("Alright! Cube has been added to the scene! \n");
return true;
+ case IElement::Type::FLOAT:
+
+ std::cout << static_cast<CElementFloat*>(_child)->getValueAttribute() << std::endl;
+
+ return true;
+
+
default:
ParserLog::wrongChildElement(getLogName(), _child->getLogName());

diff:
@@ -15,98 +15,76 @@ class CSimpleElement : public IElement
static_assert(
std::is_same<T, float>::value ||
std::is_same<T, bool>::value ||
- std::is_same<T, core::vector3df_SIMD>::value,
+ std::is_same<T, int>::value ||
+ std::is_same<T, core::vector3df_SIMD>::value ||
+ std::is_same<T, std::string>::value,
"assertion failed: cannot use this type");
public:
CSimpleElement()
- :type(IElement::Type::NONE),
- value(0.0f)
{
- IRR_PSEUDO_IF_CONSTEXPR_BEGIN(std::is_same<T, float>::value)
- {
- logName = "float";
- return;
- }
+ IRR_PSEUDO_IF_CONSTEXPR_BEGIN(std::is_same<T, float>::value) { logName = "float"; type = IElement::Type::FLOAT; }
IRR_PSEUDO_IF_CONSTEXPR_END
- IRR_PSEUDO_IF_CONSTEXPR_BEGIN(std::is_same<T, bool>::value)
- {
- logName = "boolean";
- return;
- }
+ IRR_PSEUDO_IF_CONSTEXPR_BEGIN(std::is_same<T, bool>::value) { logName = "boolean"; type = IElement::Type::BOOLEAN; }
IRR_PSEUDO_IF_CONSTEXPR_END
- IRR_PSEUDO_IF_CONSTEXPR_BEGIN(std::is_same<T, core::vector3df_SIMD>::value)
- {
- logName = "point";
- return;
- }
+ IRR_PSEUDO_IF_CONSTEXPR_BEGIN(std::is_same<T, core::vector3df_SIMD>::value) { logName = "point"; type = IElement::Type::POINT; }
IRR_PSEUDO_IF_CONSTEXPR_END
- };
- virtual bool processAttributes(const char** _atts) override;
- virtual bool onEndTag(asset::IAssetManager& _assetManager, IElement* _parent) override
- {
- //so far it is only for testing purpose
+ IRR_PSEUDO_IF_CONSTEXPR_BEGIN(std::is_same<T, int>::value) { logName = "integer"; type = IElement::Type::INTEGER; }
+ IRR_PSEUDO_IF_CONSTEXPR_END
- os::Printer::print("\t" + getLogName() + " name: " + nameAttr + " value: ");
- //os::Printer::print(value);
+ IRR_PSEUDO_IF_CONSTEXPR_BEGIN(std::is_same<T, std::string>::value) { logName = "string"; type = IElement::Type::STRING; }
+ IRR_PSEUDO_IF_CONSTEXPR_END
+ };
- return true;
- }
+ virtual bool processAttributes(const char** _atts) override;
+ virtual bool onEndTag(asset::IAssetManager& _assetManager, IElement* _parent) override;
virtual IElement::Type getType() const override { return type; };
virtual std::string getLogName() const override { return logName; };
inline std::string getNameAttribute() const { return nameAttr; }
- inline T getValueAttribute() const { return valueAttr; }
+ inline T getValueAttribute() const { return value; }
private:
- T value;
IElement::Type type;
std::string logName;
std::string nameAttr;
- T valueAttr;
+ T value;
};
using CElementFloat = CSimpleElement<float>;
using CElementBoolean = CSimpleElement<bool>;
using CElementPoint = CSimpleElement<irr::core::vector3df_SIMD>;
+using CElementString = CSimpleElement<std::string>;
template<typename T>
-bool CSimpleElement<T>::processAttributes(const char** _atts)
+inline bool CSimpleElement<T>::processAttributes(const char** _atts)
{
static_assert(false);
}
template<>
-bool CSimpleElement<float>::processAttributes(const char** _atts)
+inline bool CSimpleElement<float>::processAttributes(const char** _atts)
{
bool isNameSet = false;
for (int i = 0; _atts[i]; i += 2)
{
if (!std::strcmp(_atts[i], "name"))
- {
- if (!std::strcmp(_atts[i + 1], "radius") ||
- !std::strcmp(_atts[i + 1], "maxSmoothAngle"))
{
nameAttr = _atts[i + 1];
isNameSet = true;
}
- else
- {
- //print warning
- }
- }
else if (!std::strcmp(_atts[i], "value"))
{
value = static_cast<float>(atof(_atts[i + 1]));
}
else
{
- //print warning
+ //print warning (only attributes float has are name and value)
}
}
@@ -118,53 +96,89 @@ bool CSimpleElement<float>::processAttributes(const char** _atts)
}
template<>
-bool CSimpleElement<bool>::processAttributes(const char** _atts)
+inline bool CSimpleElement<bool>::processAttributes(const char** _atts)
{
bool isNameSet = false;
for (int i = 0; _atts[i]; i += 2)
{
if (!std::strcmp(_atts[i], "name"))
- {
- if (!std::strcmp(_atts[i + 1], "flipNormals") ||
- !std::strcmp(_atts[i + 1], "flipTexCoords") ||
- !std::strcmp(_atts[i + 1], "faceNormals") ||
- !std::strcmp(_atts[i + 1], "srgb"))
{
nameAttr = _atts[i + 1];
isNameSet = true;
}
- else
- {
- //print warning
- }
- }
if (!std::strcmp(_atts[i], "value"))
{
if (!std::strcmp(_atts[i + 1], "true"))
value = true;
- else if (!std::strcmp(_atts[i + 1], "true"))
+ else if (!std::strcmp(_atts[i + 1], "false"))
value = false;
else
{
- //print warning
+ //print warning (only true or false)
+ }
+ }
+ }
+
+ return isNameSet;
+}
+
+template<>
+inline bool CSimpleElement<std::string>::processAttributes(const char** _atts)
+{
+ bool isNameSet = false;
+
+ for (int i = 0; _atts[i]; i += 2)
+ {
+ if (!std::strcmp(_atts[i], "name"))
+ {
+ nameAttr = _atts[i + 1];
+ isNameSet = true;
+ }
+ else if (!std::strcmp(_atts[i], "value"))
+ {
+ value = _atts[i + 1];
+ }
+ else
+ {
+ //print warning (only attributes string has are name and value)
}
+
}
+
+ if (!isNameSet)
+ ;//print error
+
+ return isNameSet;
}
+template<>
+inline bool CSimpleElement<core::vector3df_SIMD>::processAttributes(const char** _atts)
+{
+ bool isNameSet = false;
+
return isNameSet;
}
template<>
-bool CSimpleElement<core::vector3df_SIMD>::processAttributes(const char** _atts)
+inline bool CSimpleElement<int>::processAttributes(const char** _atts)
{
bool isNameSet = false;
return isNameSet;
}
+template<typename T>
+bool CSimpleElement<T>::onEndTag(asset::IAssetManager& _assetManager, IElement* _parent)
+{
+ if (_parent)
+ return _parent->processChildData(this);
+
+ return true;
+}
+
}
}
}

diff:
@@ -36,7 +36,8 @@ public:
//other
TRANSFORM,
- TEXTURE
+ TEXTURE,
+ STRING
};
public:
@@ -61,6 +62,7 @@ public:
}
return true;
}
+ //
virtual bool onEndTag(asset::IAssetManager& _assetManager, IElement* _parent) = 0;
virtual IElement::Type getType() const = 0;
virtual std::string getLogName() const = 0;

diff:
@@ -109,38 +109,6 @@ void elementHandlerEnd(void* _data, const char* _el)
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;
- //}
}
}

original_message: added CElementShapeOBJ


message: Added CElementMatrix

diff:
#include "CElementShapeCube.h"
#include "CElementShapeOBJ.h"
#include "CSimpleElement.h"
+#include "CElementMatrix.h"
namespace irr { namespace ext { namespace MitsubaLoader {
@@ -21,31 +22,57 @@ IElement* CElementFactory::createElement(const char* _el, const char** _atts)
{
return parseScene(_el, _atts);
}
+ else
if (!std::strcmp(_el, "shape"))
{
return parseShape(_el, _atts);
}
+ else
if (!std::strcmp(_el, "float"))
{
return parseSimpleElement(_el, _atts, IElement::Type::FLOAT);
}
+ else
if (!std::strcmp(_el, "integer"))
{
return parseSimpleElement(_el, _atts, IElement::Type::INTEGER);
}
+ else
if (!std::strcmp(_el, "boolean"))
{
return parseSimpleElement(_el, _atts, IElement::Type::BOOLEAN);
}
+ else
if (!std::strcmp(_el, "point"))
{
return parseSimpleElement(_el, _atts, IElement::Type::POINT);
}
+ else
if (!std::strcmp(_el, "string"))
{
return parseSimpleElement(_el, _atts, IElement::Type::STRING);
}
else
+ if (!std::strcmp(_el, "matrix"))
+ {
+ return parseMatrix(_el, _atts, CElementMatrix::Type::ARBITRARY);
+ }
+ else
+ if (!std::strcmp(_el, "translate"))
+ {
+ return parseMatrix(_el, _atts, CElementMatrix::Type::TRANSLATION);
+ }
+ else
+ if (!std::strcmp(_el, "rotate"))
+ {
+ return parseMatrix(_el, _atts, CElementMatrix::Type::ROTATION);
+ }
+ else
+ if (!std::strcmp(_el, "scale"))
+ {
+ return parseMatrix(_el, _atts, CElementMatrix::Type::SCALE);
+ }
+ else
{
ParserLog::mitsubaLoaderError("invalid .xml file structure: element " + std::string(_el) + "is unknown. \n");
return nullptr;
@@ -114,6 +141,11 @@ IElement* CElementFactory::parseSimpleElement(const char* _el, const char** _att
}
}
+IElement* CElementFactory::parseMatrix(const char* _el, const char** _atts, CElementMatrix::Type type)
+{
+ return new CElementMatrix(type);
+}
+
}
}
}
\ No newline at end of file

diff:
#include "irr/asset/IAssetManager.h"
#include "IElement.h"
+#include "CElementMatrix.h"
#include <memory>
namespace irr { namespace ext { namespace MitsubaLoader {
-
+class CElementMatrix;
+enum class CElementMatrix::Type;
class CElementFactory
{
@@ -19,6 +21,7 @@ private:
static IElement* parseScene(const char* _el, const char** _atts);
static IElement* parseShape(const char* _el, const char** _atts);
static IElement* parseSimpleElement(const char* _el, const char** _atts, IElement::Type type);
+ static IElement* parseMatrix(const char* _el, const char** _atts, CElementMatrix::Type type);
};
}

diff:
+#include "CElementMatrix.h"
+
+#include "ParserUtil.h"
+#include "CSimpleElement.h"
+
+namespace irr { namespace ext { namespace MitsubaLoader {
+
+
+bool CElementMatrix::processAttributes(const char** _atts)
+{
+
+ switch (type)
+ {
+ case CElementMatrix::Type::ARBITRARY:
+ for (int i = 0; _atts[i]; i += 2)
+ {
+ if (!std::strcmp(_atts[i], "value"))
+ {
+ std::pair<bool, core::matrix4SIMD> result = getMatrixFromString(_atts[i + 1]);
+ matrix = result.second;
+ return result.first;
+ }
+ else
+ {
+ ParserLog::wrongAttribute(_atts[i], getLogName());
+ false;
+ }
+ }
+ case CElementMatrix::Type::TRANSLATION:
+ _IRR_DEBUG_BREAK_IF(true);
+ case CElementMatrix::Type::ROTATION:
+ _IRR_DEBUG_BREAK_IF(true);
+ case CElementMatrix::Type::SCALE:
+ _IRR_DEBUG_BREAK_IF(true);
+ }
+ //only type is an acceptable argument
+ for (int i = 0; _atts[i]; i += 2)
+ {
+ if (std::strcmp(_atts[i], "type"))
+ {
+ ParserLog::wrongAttribute(_atts[i], getLogName());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool CElementMatrix::onEndTag(asset::IAssetManager& _assetManager, IElement* _parent)
+{
+ return _parent->processChildData(this);
+}
+
+std::pair<bool, core::matrix4SIMD> CElementMatrix::getMatrixFromString(std::string _str) const
+{
+ std::replace(_str.begin(), _str.end(), ',', ' ');
+
+ float matrixData[16];
+ std::stringstream ss;
+ ss << _str;
+
+ for (int i = 0; i < 16; i++)
+ {
+ float f = std::numeric_limits<float>::quiet_NaN();
+ ss >> f;
+ std::cout << f << std::endl;
+
+ matrixData[i] = f;
+
+ if (isnan(f))
+ {
+ _IRR_DEBUG_BREAK_IF(true);
+ ParserLog::mitsubaLoaderError("Invalid matrix specified.");
+ return std::make_pair(false, core::matrix4SIMD());
+ }
+ }
+
+ return std::make_pair(true, core::matrix4SIMD(matrixData));
+}
+
+}
+}
+}
\ No newline at end of file

diff:
@@ -27,6 +27,8 @@ namespace irr { namespace ext { namespace MitsubaLoader {
- clean up memory dynamically allocated by ParserData::scene
+ - resolve header include conflict (IElement.h needs to include ParserUtil.h (only for ParserLog), and ParserUtil.h needs to include IElement.h)
+
*/

diff:
@@ -42,34 +42,20 @@ bool CMitsubaScene::processChildData(IElement* _child)
CElementShapeOBJ* shape = static_cast<CElementShapeOBJ*>(_child);
const asset::ICPUMesh* shapeMesh = shape->getMesh();
-
- if (!shapeMesh)
- {
- _IRR_DEBUG_BREAK_IF(true);
- return false;
- }
-
-
- //is it possible that shapeMesh->getMeshBufferCount() > 1 ?
- for (int i = 0; i < shapeMesh->getMeshBufferCount(); i++)
- mesh->addMeshBuffer(shapeMesh->getMeshBuffer(i));
-
-
-
- return true;
+ return appendMesh(shapeMesh);
}
case IElement::Type::SHAPE_CUBE:
+ {
os::Printer::print("Alright! Cube has been added to the scene! \n");
return true;
-
- case IElement::Type::FLOAT:
-
- std::cout << static_cast<CElementFloat*>(_child)->getValueAttribute() << std::endl;
-
+ }
+ case IElement::Type::MATRIX:
+ {
+ os::Printer::print("Alright! Cube has been added to the scene! \n");
+ _IRR_DEBUG_BREAK_IF(true);
return true;
-
-
+ }
default:
ParserLog::wrongChildElement(getLogName(), _child->getLogName());
@@ -77,6 +63,20 @@ bool CMitsubaScene::processChildData(IElement* _child)
}
}
+bool CMitsubaScene::appendMesh(const asset::ICPUMesh* _mesh)
+{
+ if (!_mesh)
+ {
+ _IRR_DEBUG_BREAK_IF(true);
+ return false;
+ }
+
+
+ //is it possible that shapeMesh->getMeshBufferCount() > 1 ?
+ for (int i = 0; i < _mesh->getMeshBufferCount(); i++)
+ mesh->addMeshBuffer(_mesh->getMeshBuffer(i));
+}
+
}
}

diff:
@@ -23,11 +23,12 @@ public:
virtual bool processChildData(IElement* child) override;
asset::SCPUMesh* releaseMesh() { return mesh; mesh = nullptr; }
- //void appendMesh(asset::ICPUMesh* mesh);
+
private:
asset::SCPUMesh* mesh;
+ bool appendMesh(const asset::ICPUMesh* _mesh);
};
}

diff:
#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.
@@ -37,7 +38,8 @@ public:
//other
TRANSFORM,
TEXTURE,
- STRING
+ STRING,
+ MATRIX
};
public:
@@ -57,7 +59,7 @@ public:
{
if (_child != nullptr)
{
- //ParserLog::wrongChildElement(getName(), _child->getName());
+ //ParserLog::wrongChildElement(getLogName(), _child->getName());
return false;
}
return true;

original_message: Added CElementMatrix


message: now unsupported elements will be omitted by parser

diff:
#include "../../ext/MitsubaLoader/ParserUtil.h"
#include "../../ext/MitsubaLoader/CElementFactory.h"
+
#include "irrlicht.h"
namespace irr { namespace ext { namespace MitsubaLoader {
@@ -34,14 +35,23 @@ void ParserLog::mitsubaLoaderError(const std::string& errorMessage)
//or os::Printer::log ?
os::Printer::print(message);
- _IRR_DEBUG_BREAK_IF(true);
+ //_IRR_DEBUG_BREAK_IF(true);
}
void elementHandlerStart(void* _data, const char* _el, const char** _atts)
{
-
ParserData* data = static_cast<ParserData*>(_data);
+ if (!data->pfc.suspendParsingIfElNotSupported(_el))
+ {
+ ParserLog::mitsubaLoaderError(std::string(_el) + " is not supported");
+ return;
+ }
+
+ if (data->pfc.isParsingSuspended())
+ return;
+
+
std::unique_ptr<IElement> element(CElementFactory::createElement(_el, _atts));
if (!element)
@@ -89,9 +99,14 @@ void elementHandlerStart(void* _data, const char* _el, const char** _atts)
void elementHandlerEnd(void* _data, const char* _el)
{
-
ParserData* data = static_cast<ParserData*>(_data);
+ if (data->pfc.isParsingSuspended())
+ {
+ data->pfc.checkForUnsuspend(_el);
+ return;
+ }
+
if (data->elements.empty())
{
data->scene->onEndTag(data->assetManager, nullptr);
@@ -113,6 +128,31 @@ void elementHandlerEnd(void* _data, const char* _el)
}
}
+void ParserFlowController::checkForUnsuspend(const char* _el)
+{
+ if (!std::strcmp(notSupportedElement.c_str(), _el))
+ {
+ isParsingSuspendedFlag = false;
+ notSupportedElement.clear();
+ }
+}
+
+bool ParserFlowController::suspendParsingIfElNotSupported(const char* _el)
+{
+ for (int i = 0; unsElements[i]; i++)
+ {
+ if (!std::strcmp(unsElements[i], _el))
+ {
+ isParsingSuspendedFlag = true;
+ notSupportedElement = _el;
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
}
}
}
\ No newline at end of file

diff:
namespace irr { namespace ext { namespace MitsubaLoader {
+//now unsupported elements (like <sensor> (for now), for example) and its children elements will be ignored
+class ParserFlowController
+{
+public:
+ ParserFlowController()
+ :isParsingSuspendedFlag(false) {};
+
+ bool suspendParsingIfElNotSupported(const char* _el);
+ void checkForUnsuspend(const char* _el);
+
+ inline bool isParsingSuspended() const { return isParsingSuspendedFlag; }
+
+private:
+ static constexpr const char* unsElements[] = { "integrator", "emitter", "ref", "bsdf", "sensor", nullptr };
+ bool isParsingSuspendedFlag;
+ std::string notSupportedElement;
+
+};
+
+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);
+
+};
+
//struct, which will be passed to expat handlers as user data (first argument) see: XML_StartElementHandler or XML_EndElementHandler in expat.h
struct ParserData
@@ -40,26 +79,8 @@ struct ParserData
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);
+ ParserFlowController pfc;
};
void elementHandlerStart(void* _data, const char* _el, const char** _atts);


message: Added createRectangleMesh and createDiskMesh to geometry creator

diff:
@@ -96,6 +96,10 @@ public:
const video::SColor& colorBottom=video::SColor(0xffffffff),
float oblique=0.f) const =0;
+ virtual asset::ICPUMesh* createRectangleMesh(const core::vector2df_SIMD& size = core::vector2df_SIMD(0.5f, 0.5f)) const = 0;
+
+ virtual asset::ICPUMesh* createDiskMesh(float radius, uint32_t tesselation) const = 0;
+
};
} // end namespace asset

diff:
@@ -141,7 +141,7 @@ asset::ICPUMesh* CGeometryCreator::createCubeMesh(const core::vector3df& size) c
//setVertexAttrBuffer(asset::ICPUBuffer* attrBuf, const E_VERTEX_ATTRIBUTE_ID& attrId, E_COMPONENTS_PER_ATTRIBUTE components, E_COMPONENT_TYPE type, const size_t &stride=0, size_t offset=0)
desc->setVertexAttrBuffer(vertices,asset::EVAI_ATTR0,asset::EF_R32G32B32_SFLOAT,vertexSize, offsetof(CubeVertex, pos));
desc->setVertexAttrBuffer(vertices,asset::EVAI_ATTR1,asset::EF_R8G8B8A8_UNORM,vertexSize,offsetof(CubeVertex, color));
- desc->setVertexAttrBuffer(vertices,asset::EVAI_ATTR2,asset::EF_R8G8_UNORM,vertexSize,offsetof(CubeVertex, uv));
+ desc->setVertexAttrBuffer(vertices, asset::EVAI_ATTR2, asset::EF_R8G8_USCALED, vertexSize, offsetof(CubeVertex, uv));
desc->setVertexAttrBuffer(vertices, asset::EVAI_ATTR3, asset::EF_R8G8B8_SNORM, vertexSize, offsetof(CubeVertex, normal));
vertices->drop();
@@ -568,6 +568,129 @@ asset::ICPUMesh* CGeometryCreator::createConeMesh(float radius, float length, ui
}
+asset::ICPUMesh* CGeometryCreator::createRectangleMesh(const core::vector2df_SIMD& _size) const
+{
+ asset::ICPUMeshDataFormatDesc* desc = new asset::ICPUMeshDataFormatDesc();
+ asset::ICPUMeshBuffer* buffer = new asset::ICPUMeshBuffer();
+ buffer->setMeshDataAndFormat(desc);
+ desc->drop();
+
+ // Create indices
+ uint16_t u[6];
+
+ /*
+ 0---1
+ | / |
+ 3---2
+ */
+ u[0] = 0;
+ u[1] = 3;
+ u[2] = 1;
+ u[3] = 1;
+ u[4] = 3;
+ u[5] = 2;
+
+ asset::ICPUBuffer* indices = new asset::ICPUBuffer(sizeof(u));
+ memcpy(indices->getPointer(), u, sizeof(u));
+ desc->setIndexBuffer(indices);
+ buffer->setIndexType(asset::EIT_16BIT);
+ buffer->setIndexCount(sizeof(u) / sizeof(*u));
+ indices->drop();
+
+ // Create vertices
+ const size_t vertexSize = sizeof(CGeometryCreator::RectangleVertex);
+ asset::ICPUBuffer* vertices = new asset::ICPUBuffer(4 * vertexSize);
+ RectangleVertex* ptr = (RectangleVertex*)vertices->getPointer();
+
+ ptr[0] = RectangleVertex(core::vector3df_SIMD(-1.0f, 1.0f, 0.0f) * _size, video::SColor(0xFFFFFFFFu),
+ core::vector2du32_SIMD(0u, 1u), core::vector3df_SIMD(0.0f, 0.0f, 1.0f));
+ ptr[1] = RectangleVertex(core::vector3df_SIMD( 1.0f, 1.0f, 0.0f) * _size, video::SColor(0xFFFFFFFFu),
+ core::vector2du32_SIMD(1u, 1u), core::vector3df_SIMD(0.0f, 0.0f, 1.0f));
+ ptr[2] = RectangleVertex(core::vector3df_SIMD( 1.0f, -1.0f, 0.0f) * _size, video::SColor(0xFFFFFFFFu),
+ core::vector2du32_SIMD(1u, 0u), core::vector3df_SIMD(0.0f, 0.0f, 1.0f));
+ ptr[3] = RectangleVertex(core::vector3df_SIMD(-1.0f, -1.0f, 0.0f) * _size, video::SColor(0xFFFFFFFFu),
+ core::vector2du32_SIMD(0u, 0u), core::vector3df_SIMD(0.0f, 0.0f, 1.0f));
+
+ desc->setVertexAttrBuffer(vertices, asset::EVAI_ATTR0, asset::EF_R32G32B32_SFLOAT, vertexSize, offsetof(RectangleVertex, pos));
+ desc->setVertexAttrBuffer(vertices, asset::EVAI_ATTR1, asset::EF_R8G8B8A8_UNORM, vertexSize, offsetof(RectangleVertex, color));
+ desc->setVertexAttrBuffer(vertices, asset::EVAI_ATTR2, asset::EF_R8G8_USCALED, vertexSize, offsetof(RectangleVertex, uv));
+ desc->setVertexAttrBuffer(vertices, asset::EVAI_ATTR3, asset::EF_R32G32B32_SFLOAT, vertexSize, offsetof(RectangleVertex, normal));
+ vertices->drop();
+
+ asset::SCPUMesh* mesh = new asset::SCPUMesh;
+ mesh->addMeshBuffer(buffer);
+ buffer->drop();
+
+ mesh->recalculateBoundingBox();
+ return mesh;
+}
+
+asset::ICPUMesh* CGeometryCreator::createDiskMesh(float radius, uint32_t tesselation) const
+{
+ asset::ICPUMeshDataFormatDesc* desc = new asset::ICPUMeshDataFormatDesc();
+ asset::ICPUMeshBuffer* buffer = new asset::ICPUMeshBuffer();
+ buffer->setPrimitiveType(asset::E_PRIMITIVE_TYPE::EPT_TRIANGLE_FAN);
+ buffer->setMeshDataAndFormat(desc);
+ desc->drop();
+
+ const size_t vertexCount = 1u + tesselation;
+
+ const size_t vertexSize = sizeof(CGeometryCreator::DiskVertex);
+ const float angle = 360.0f / static_cast<float>(tesselation);
+
+ asset::ICPUBuffer* vertices = new asset::ICPUBuffer(vertexCount * vertexSize);
+ DiskVertex* ptr = (DiskVertex*)vertices->getPointer();
+
+
+ /*
+ example:
+
+ v1 v0 v7
+ \ | /
+ v2 -- s -- v6
+ / | \
+ v3 v4 v5
+ */
+
+
+ const core::vectorSIMDf v0(0.0f, radius, 0.0f, 0.0f);
+ core::matrix3x4SIMD rotation;
+
+ //center
+ ptr[0] = DiskVertex(core::vector3df_SIMD(0.0f), video::SColor(0xFFFFFFFFu),
+ core::vector2du32_SIMD(0u, 1u), core::vector3df_SIMD(0.0f, 0.0f, 1.0f));
+
+ //v0
+ ptr[1] = DiskVertex(v0, video::SColor(0xFFFFFFFFu),
+ core::vector2du32_SIMD(0u, 1u), core::vector3df_SIMD(0.0f, 0.0f, 1.0f));
+
+ //v1, v2, ..., vn
+ for (int i = 2; i < vertexCount; i++)
+ {
+ core::vectorSIMDf vn;
+ core::matrix3x4SIMD rotMatrix;
+ rotMatrix.setRotation(core::quaternion(0.0f, 0.0f, core::degToRad(angle * (i - 1))));
+
+ rotMatrix.transformVect(vn, v0);
+ ptr[i] = DiskVertex(vn, video::SColor(0xFFFFFFFFu),
+ core::vector2du32_SIMD(0u, 1u), core::vector3df_SIMD(0.0f, 0.0f, 1.0f));
+ }
+
+ desc->setVertexAttrBuffer(vertices, asset::EVAI_ATTR0, asset::EF_R32G32B32_SFLOAT, vertexSize, offsetof(DiskVertex, pos));
+ desc->setVertexAttrBuffer(vertices, asset::EVAI_ATTR1, asset::EF_R8G8B8A8_UNORM, vertexSize, offsetof(DiskVertex, color));
+ desc->setVertexAttrBuffer(vertices, asset::EVAI_ATTR2, asset::EF_R8G8_USCALED, vertexSize, offsetof(DiskVertex, uv));
+ desc->setVertexAttrBuffer(vertices, asset::EVAI_ATTR3, asset::EF_R32G32B32_SFLOAT, vertexSize, offsetof(DiskVertex, normal));
+ vertices->drop();
+
+ asset::SCPUMesh* mesh = new asset::SCPUMesh;
+ mesh->addMeshBuffer(buffer);
+ buffer->drop();
+
+ mesh->recalculateBoundingBox();
+ return mesh;
+}
+
+
} // end namespace asset
} // end namespace irr

diff:
@@ -33,6 +33,26 @@ private:
void setUv(uint8_t u, uint8_t v) { uv[0] = u; uv[1] = v; }
} PACK_STRUCT;
+ struct RectangleVertex
+ {
+ RectangleVertex(const core::vector3df_SIMD& _pos, const video::SColor& _color, const core::vector2du32_SIMD _uv, const core::vector3df_SIMD _normal)
+ {
+ memcpy(pos, _pos.pointer, sizeof(float) * 3);
+ _color.toOpenGLColor(color);
+ uv[0] = _uv.x;
+ uv[1] = _uv.y;
+ normal[0] = _normal.x;
+ normal[1] = _normal.y;
+ normal[2] = _normal.z;
+ }
+ float pos[3];
+ uint8_t color[4];
+ uint8_t uv[2];
+ float normal[3];
+ } PACK_STRUCT;
+
+ typedef RectangleVertex DiskVertex;
+
struct ConeVertex
{
inline ConeVertex(const core::vectorSIMDf& _pos, uint32_t _nml, const video::SColor& _color) : normal{_nml}
@@ -77,6 +97,10 @@ public:
const video::SColor& colorBottom=0xffffffff,
float oblique=0.f) const override;
+ virtual asset::ICPUMesh* createRectangleMesh(const core::vector2df_SIMD& _size = core::vector2df_SIMD(0.5f, 0.5f)) const override;
+
+ virtual asset::ICPUMesh* createDiskMesh(float radius, uint32_t tesselation) const override;
+
};
} // end namespace asset


message: Fixed createDiskMesh function

diff:
@@ -633,7 +633,10 @@ asset::ICPUMesh* CGeometryCreator::createDiskMesh(float radius, uint32_t tessela
buffer->setMeshDataAndFormat(desc);
desc->drop();
- const size_t vertexCount = 1u + tesselation;
+ const size_t vertexCount = 2u + tesselation;
+
+ buffer->setIndexType(asset::EIT_16BIT);
+ buffer->setIndexCount(vertexCount);
const size_t vertexSize = sizeof(CGeometryCreator::DiskVertex);
const float angle = 360.0f / static_cast<float>(tesselation);
@@ -644,12 +647,12 @@ asset::ICPUMesh* CGeometryCreator::createDiskMesh(float radius, uint32_t tessela
/*
example:
-
v1 v0 v7
\ | /
v2 -- s -- v6
/ | \
v3 v4 v5
+
*/
@@ -664,14 +667,17 @@ asset::ICPUMesh* CGeometryCreator::createDiskMesh(float radius, uint32_t tessela
ptr[1] = DiskVertex(v0, video::SColor(0xFFFFFFFFu),
core::vector2du32_SIMD(0u, 1u), core::vector3df_SIMD(0.0f, 0.0f, 1.0f));
- //v1, v2, ..., vn
- for (int i = 2; i < vertexCount; i++)
+ //vn
+ ptr[vertexCount - 1] = ptr[1];
+
+ //v1, v2, ..., vn-1
+ for (int i = 2; i < vertexCount-1; i++)
{
core::vectorSIMDf vn;
core::matrix3x4SIMD rotMatrix;
rotMatrix.setRotation(core::quaternion(0.0f, 0.0f, core::degToRad(angle * (i - 1))));
-
rotMatrix.transformVect(vn, v0);
+
ptr[i] = DiskVertex(vn, video::SColor(0xFFFFFFFFu),
core::vector2du32_SIMD(0u, 1u), core::vector3df_SIMD(0.0f, 0.0f, 1.0f));
}

original_message: Fixed createDiskMesh function