From 959831f4ef5a3e797f576c3de08cd65032c997ad Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Sun, 13 Jan 2013 18:54:10 +1000 Subject: Remove damned ancient DOS line endings from Irrlicht. Hopefully I did not go overboard. --- .../source/Irrlicht/CColladaFileLoader.cpp | 5914 ++++++++++---------- 1 file changed, 2957 insertions(+), 2957 deletions(-) (limited to 'libraries/irrlicht-1.8/source/Irrlicht/CColladaFileLoader.cpp') diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CColladaFileLoader.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CColladaFileLoader.cpp index 6509812..210a59b 100644 --- a/libraries/irrlicht-1.8/source/Irrlicht/CColladaFileLoader.cpp +++ b/libraries/irrlicht-1.8/source/Irrlicht/CColladaFileLoader.cpp @@ -1,2957 +1,2957 @@ -// 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 - -#include "IrrCompileConfig.h" -#ifdef _IRR_COMPILE_WITH_COLLADA_LOADER_ - -#include "CColladaFileLoader.h" -#include "os.h" -#include "IXMLReader.h" -#include "IDummyTransformationSceneNode.h" -#include "SAnimatedMesh.h" -#include "fast_atof.h" -#include "quaternion.h" -#include "ILightSceneNode.h" -#include "ICameraSceneNode.h" -#include "IMeshManipulator.h" -#include "IReadFile.h" -#include "IAttributes.h" -#include "IMeshCache.h" -#include "IMeshSceneNode.h" -#include "SMeshBufferLightMap.h" -#include "irrMap.h" - -#ifdef _DEBUG -#define COLLADA_READER_DEBUG -#endif -namespace irr -{ -namespace scene -{ -namespace -{ - // currently supported COLLADA tag names - const core::stringc colladaSectionName = "COLLADA"; - const core::stringc librarySectionName = "library"; - const core::stringc libraryNodesSectionName = "library_nodes"; - const core::stringc libraryGeometriesSectionName = "library_geometries"; - const core::stringc libraryMaterialsSectionName = "library_materials"; - const core::stringc libraryImagesSectionName = "library_images"; - const core::stringc libraryVisualScenesSectionName = "library_visual_scenes"; - const core::stringc libraryCamerasSectionName = "library_cameras"; - const core::stringc libraryLightsSectionName = "library_lights"; - const core::stringc libraryEffectsSectionName = "library_effects"; - const core::stringc assetSectionName = "asset"; - const core::stringc sceneSectionName = "scene"; - const core::stringc visualSceneSectionName = "visual_scene"; - - const core::stringc lightPrefabName = "light"; - const core::stringc cameraPrefabName = "camera"; - const core::stringc materialSectionName = "material"; - const core::stringc geometrySectionName = "geometry"; - const core::stringc imageSectionName = "image"; - const core::stringc textureSectionName = "texture"; - const core::stringc effectSectionName = "effect"; - - const core::stringc pointSectionName = "point"; - const core::stringc directionalSectionName ="directional"; - const core::stringc spotSectionName = "spot"; - const core::stringc ambientSectionName = "ambient"; - const core::stringc meshSectionName = "mesh"; - const core::stringc sourceSectionName = "source"; - const core::stringc arraySectionName = "array"; - const core::stringc floatArraySectionName ="float_array"; - const core::stringc intArraySectionName = "int_array"; - const core::stringc techniqueCommonSectionName = "technique_common"; - const core::stringc accessorSectionName = "accessor"; - const core::stringc verticesSectionName = "vertices"; - const core::stringc inputTagName = "input"; - const core::stringc polylistSectionName = "polylist"; - const core::stringc trianglesSectionName = "triangles"; - const core::stringc polygonsSectionName = "polygons"; - const core::stringc primitivesName = "p"; - const core::stringc vcountName = "vcount"; - - const core::stringc upAxisNodeName = "up_axis"; - const core::stringc nodeSectionName = "node"; - const core::stringc lookatNodeName = "lookat"; - const core::stringc matrixNodeName = "matrix"; - const core::stringc perspectiveNodeName = "perspective"; - const core::stringc rotateNodeName = "rotate"; - const core::stringc scaleNodeName = "scale"; - const core::stringc translateNodeName = "translate"; - const core::stringc skewNodeName = "skew"; - const core::stringc bboxNodeName = "boundingbox"; - const core::stringc minNodeName = "min"; - const core::stringc maxNodeName = "max"; - const core::stringc instanceName = "instance"; - const core::stringc instanceGeometryName = "instance_geometry"; - const core::stringc instanceSceneName = "instance_visual_scene"; - const core::stringc instanceEffectName = "instance_effect"; - const core::stringc instanceMaterialName = "instance_material"; - const core::stringc instanceLightName = "instance_light"; - const core::stringc instanceNodeName = "instance_node"; - const core::stringc bindMaterialName = "bind_material"; - const core::stringc extraNodeName = "extra"; - const core::stringc techniqueNodeName = "technique"; - const core::stringc colorNodeName = "color"; - const core::stringc floatNodeName = "float"; - const core::stringc float2NodeName = "float2"; - const core::stringc float3NodeName = "float3"; - - const core::stringc newParamName = "newparam"; - const core::stringc paramTagName = "param"; - const core::stringc initFromName = "init_from"; - const core::stringc dataName = "data"; - const core::stringc wrapsName = "wrap_s"; - const core::stringc wraptName = "wrap_t"; - const core::stringc minfilterName = "minfilter"; - const core::stringc magfilterName = "magfilter"; - const core::stringc mipfilterName = "mipfilter"; - - const core::stringc textureNodeName = "texture"; - const core::stringc doubleSidedNodeName = "double_sided"; - const core::stringc constantAttenuationNodeName = "constant_attenuation"; - const core::stringc linearAttenuationNodeName = "linear_attenuation"; - const core::stringc quadraticAttenuationNodeName = "quadratic_attenuation"; - const core::stringc falloffAngleNodeName = "falloff_angle"; - const core::stringc falloffExponentNodeName = "falloff_exponent"; - - const core::stringc profileCOMMONSectionName = "profile_COMMON"; - const core::stringc profileCOMMONAttributeName = "COMMON"; - - const char* const inputSemanticNames[] = {"POSITION", "VERTEX", "NORMAL", "TEXCOORD", - "UV", "TANGENT", "IMAGE", "TEXTURE", 0}; - - // We have to read ambient lights like other light types here, so we need a type for it - const video::E_LIGHT_TYPE ELT_AMBIENT = video::E_LIGHT_TYPE(video::ELT_COUNT+1); -} - - //! following class is for holding and creating instances of library - //! objects, named prefabs in this loader. - class CPrefab : public IColladaPrefab - { - public: - - CPrefab(const core::stringc& id) : Id(id) - { - } - - //! creates an instance of this prefab - virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent, - scene::ISceneManager* mgr) - { - // empty implementation - return 0; - } - - //! returns id of this prefab - virtual const core::stringc& getId() - { - return Id; - } - - protected: - - core::stringc Id; - }; - - - //! prefab for a light scene node - class CLightPrefab : public CPrefab - { - public: - - CLightPrefab(const core::stringc& id) : CPrefab(id) - { - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA: loaded light prefab", Id.c_str(), ELL_DEBUG); - #endif - } - - video::SLight LightData; // publically accessible - - //! creates an instance of this prefab - virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent, - scene::ISceneManager* mgr) - { - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA: Constructing light instance", Id.c_str(), ELL_DEBUG); - #endif - - if ( LightData.Type == ELT_AMBIENT ) - { - mgr->setAmbientLight( LightData.DiffuseColor ); - return 0; - } - - scene::ILightSceneNode* l = mgr->addLightSceneNode(parent); - if (l) - { - l->setLightData ( LightData ); - l->setName(getId()); - } - return l; - } - }; - - - //! prefab for a mesh scene node - class CGeometryPrefab : public CPrefab - { - public: - - CGeometryPrefab(const core::stringc& id) : CPrefab(id) - { - } - - scene::IMesh* Mesh; - - //! creates an instance of this prefab - virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent, - scene::ISceneManager* mgr) - { - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA: Constructing mesh instance", Id.c_str(), ELL_DEBUG); - #endif - - scene::ISceneNode* m = mgr->addMeshSceneNode(Mesh, parent); - if (m) - { - m->setName(getId()); -// m->setMaterialFlag(video::EMF_BACK_FACE_CULLING, false); -// m->setDebugDataVisible(scene::EDS_FULL); - } - return m; - } - }; - - - //! prefab for a camera scene node - class CCameraPrefab : public CPrefab - { - public: - - CCameraPrefab(const core::stringc& id) - : CPrefab(id), YFov(core::PI / 2.5f), ZNear(1.0f), ZFar(3000.0f) - { - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA: loaded camera prefab", Id.c_str(), ELL_DEBUG); - #endif - } - - // publicly accessible data - f32 YFov; - f32 ZNear; - f32 ZFar; - - //! creates an instance of this prefab - virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent, - scene::ISceneManager* mgr) - { - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA: Constructing camera instance", Id.c_str(), ELL_DEBUG); - #endif - - scene::ICameraSceneNode* c = mgr->addCameraSceneNode(parent); - if (c) - { - c->setFOV(YFov); - c->setNearValue(ZNear); - c->setFarValue(ZFar); - c->setName(getId()); - } - return c; - } - }; - - - //! prefab for a container scene node - //! Collects other prefabs and instantiates them upon instantiation - //! Uses a dummy scene node to return the children as one scene node - class CScenePrefab : public CPrefab - { - public: - CScenePrefab(const core::stringc& id) : CPrefab(id) - { - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA: loaded scene prefab", Id.c_str(), ELL_DEBUG); - #endif - } - - //! creates an instance of this prefab - virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent, - scene::ISceneManager* mgr) - { - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA: Constructing scene instance", Id.c_str(), ELL_DEBUG); - #endif - - if (Children.size()==0) - return 0; - - scene::IDummyTransformationSceneNode* s = mgr->addDummyTransformationSceneNode(parent); - if (s) - { - s->setName(getId()); - s->getRelativeTransformationMatrix() = Transformation; - s->updateAbsolutePosition(); - core::stringc t; - for (u32 i=0; i<16; ++i) - { - t+=core::stringc((double)Transformation[i]); - t+=" "; - } - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA: Transformation", t.c_str(), ELL_DEBUG); - #endif - - for (u32 i=0; iaddInstance(s, mgr); - } - - return s; - } - - core::array Children; - core::matrix4 Transformation; - }; - - -//! Constructor -CColladaFileLoader::CColladaFileLoader(scene::ISceneManager* smgr, - io::IFileSystem* fs) -: SceneManager(smgr), FileSystem(fs), DummyMesh(0), - FirstLoadedMesh(0), LoadedMeshCount(0), CreateInstances(false) -{ - #ifdef _DEBUG - setDebugName("CColladaFileLoader"); - #endif -} - - -//! destructor -CColladaFileLoader::~CColladaFileLoader() -{ - if (DummyMesh) - DummyMesh->drop(); - - if (FirstLoadedMesh) - FirstLoadedMesh->drop(); -} - - -//! Returns true if the file maybe is able to be loaded by this class. -/** This decision should be based only on the file extension (e.g. ".cob") */ -bool CColladaFileLoader::isALoadableFileExtension(const io::path& filename) const -{ - return core::hasFileExtension ( filename, "xml", "dae" ); -} - - -//! creates/loads an animated mesh from the file. -//! \return Pointer to the created mesh. Returns 0 if loading failed. -//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). -//! See IReferenceCounted::drop() for more information. -IAnimatedMesh* CColladaFileLoader::createMesh(io::IReadFile* file) -{ - io::IXMLReaderUTF8* reader = FileSystem->createXMLReaderUTF8(file); - if (!reader) - return 0; - - CurrentlyLoadingMesh = file->getFileName(); - CreateInstances = SceneManager->getParameters()->getAttributeAsBool( - scene::COLLADA_CREATE_SCENE_INSTANCES); - Version = 0; - FlipAxis = false; - - // read until COLLADA section, skip other parts - - while(reader->read()) - { - if (reader->getNodeType() == io::EXN_ELEMENT) - { - if (colladaSectionName == reader->getNodeName()) - readColladaSection(reader); - else - skipSection(reader, true); // unknown section - } - } - - reader->drop(); - if (!Version) - return 0; - - // because this loader loads and creates a complete scene instead of - // a single mesh, return an empty dummy mesh to make the scene manager - // know that everything went well. - if (!DummyMesh) - DummyMesh = new SAnimatedMesh(); - scene::IAnimatedMesh* returnMesh = DummyMesh; - - if (Version < 10400) - instantiateNode(SceneManager->getRootSceneNode()); - - // add the first loaded mesh into the mesh cache too, if more than one - // meshes have been loaded from the file - if (LoadedMeshCount>1 && FirstLoadedMesh) - { - os::Printer::log("Added COLLADA mesh", FirstLoadedMeshName.c_str()); - SceneManager->getMeshCache()->addMesh(FirstLoadedMeshName.c_str(), FirstLoadedMesh); - } - - // clean up temporary loaded data - clearData(); - - returnMesh->grab(); // store until this loader is destroyed - - DummyMesh->drop(); - DummyMesh = 0; - - if (FirstLoadedMesh) - FirstLoadedMesh->drop(); - FirstLoadedMesh = 0; - LoadedMeshCount = 0; - - return returnMesh; -} - - -//! skips an (unknown) section in the collada document -void CColladaFileLoader::skipSection(io::IXMLReaderUTF8* reader, bool reportSkipping) -{ - #ifndef COLLADA_READER_DEBUG - if (reportSkipping) // always report in COLLADA_READER_DEBUG mode - #endif - os::Printer::log("COLLADA skipping section", core::stringc(reader->getNodeName()).c_str(), ELL_DEBUG); - - // skip if this element is empty anyway. - if (reader->isEmptyElement()) - return; - - // read until we've reached the last element in this section - u32 tagCounter = 1; - - while(tagCounter && reader->read()) - { - if (reader->getNodeType() == io::EXN_ELEMENT && - !reader->isEmptyElement()) - { - #ifdef COLLADA_READER_DEBUG - if (reportSkipping) - os::Printer::log("Skipping COLLADA unknown element", core::stringc(reader->getNodeName()).c_str(), ELL_DEBUG); - #endif - - ++tagCounter; - } - else - if (reader->getNodeType() == io::EXN_ELEMENT_END) - --tagCounter; - } -} - - -//! reads the section and its content -void CColladaFileLoader::readColladaSection(io::IXMLReaderUTF8* reader) -{ - if (reader->isEmptyElement()) - return; - - // todo: patch level needs to be handled - const f32 version = core::fast_atof(core::stringc(reader->getAttributeValue("version")).c_str()); - Version = core::floor32(version)*10000+core::round32(core::fract(version)*1000.0f); - // Version 1.4 can be checked for by if (Version >= 10400) - - while(reader->read()) - if (reader->getNodeType() == io::EXN_ELEMENT) - { - if (assetSectionName == reader->getNodeName()) - readAssetSection(reader); - else - if (librarySectionName == reader->getNodeName()) - readLibrarySection(reader); - else - if (libraryNodesSectionName == reader->getNodeName()) - readLibrarySection(reader); - else - if (libraryGeometriesSectionName == reader->getNodeName()) - readLibrarySection(reader); - else - if (libraryMaterialsSectionName == reader->getNodeName()) - readLibrarySection(reader); - else - if (libraryEffectsSectionName == reader->getNodeName()) - readLibrarySection(reader); - else - if (libraryImagesSectionName == reader->getNodeName()) - readLibrarySection(reader); - else - if (libraryCamerasSectionName == reader->getNodeName()) - readLibrarySection(reader); - else - if (libraryLightsSectionName == reader->getNodeName()) - readLibrarySection(reader); - else - if (libraryVisualScenesSectionName == reader->getNodeName()) - readVisualScene(reader); - else - if (assetSectionName == reader->getNodeName()) - readAssetSection(reader); - else - if (sceneSectionName == reader->getNodeName()) - readSceneSection(reader); - else - { - os::Printer::log("COLLADA loader warning: Wrong tag usage found", reader->getNodeName(), ELL_WARNING); - skipSection(reader, true); // unknown section - } - } -} - - -//! reads a section and its content -void CColladaFileLoader::readLibrarySection(io::IXMLReaderUTF8* reader) -{ - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading library", ELL_DEBUG); - #endif - - if (reader->isEmptyElement()) - return; - - while(reader->read()) - { - if (reader->getNodeType() == io::EXN_ELEMENT) - { - // animation section tbd - if (cameraPrefabName == reader->getNodeName()) - readCameraPrefab(reader); - else - // code section tbd - // controller section tbd - if (geometrySectionName == reader->getNodeName()) - readGeometry(reader); - else - if (imageSectionName == reader->getNodeName()) - readImage(reader); - else - if (lightPrefabName == reader->getNodeName()) - readLightPrefab(reader); - else - if (materialSectionName == reader->getNodeName()) - readMaterial(reader); - else - if (nodeSectionName == reader->getNodeName()) - { - CScenePrefab p(""); - - readNodeSection(reader, SceneManager->getRootSceneNode(), &p); - } - else - if (effectSectionName == reader->getNodeName()) - readEffect(reader); - else - // program section tbd - if (textureSectionName == reader->getNodeName()) - readTexture(reader); - else - skipSection(reader, true); // unknown section, not all allowed supported yet - } - else - if (reader->getNodeType() == io::EXN_ELEMENT_END) - { - if (librarySectionName == reader->getNodeName()) - break; // end reading. - if (libraryNodesSectionName == reader->getNodeName()) - break; // end reading. - if (libraryGeometriesSectionName == reader->getNodeName()) - break; // end reading. - if (libraryMaterialsSectionName == reader->getNodeName()) - break; // end reading. - if (libraryEffectsSectionName == reader->getNodeName()) - break; // end reading. - if (libraryImagesSectionName == reader->getNodeName()) - break; // end reading. - if (libraryLightsSectionName == reader->getNodeName()) - break; // end reading. - if (libraryCamerasSectionName == reader->getNodeName()) - break; // end reading. - } - } -} - - -//! reads a element and stores it as a prefab -void CColladaFileLoader::readVisualScene(io::IXMLReaderUTF8* reader) -{ - CScenePrefab* p = 0; - while(reader->read()) - { - if (reader->getNodeType() == io::EXN_ELEMENT) - { - if (visualSceneSectionName == reader->getNodeName()) - p = new CScenePrefab(readId(reader)); - else - if (p && nodeSectionName == reader->getNodeName()) // as a child of visual_scene - readNodeSection(reader, SceneManager->getRootSceneNode(), p); - else - if (assetSectionName == reader->getNodeName()) - readAssetSection(reader); - else - if (extraNodeName == reader->getNodeName()) - skipSection(reader, false); // ignore all other sections - else - { - os::Printer::log("COLLADA loader warning: Wrong tag usage found", reader->getNodeName(), ELL_WARNING); - skipSection(reader, true); // ignore all other sections - } - } - else - if (reader->getNodeType() == io::EXN_ELEMENT_END) - { - if (libraryVisualScenesSectionName == reader->getNodeName()) - return; - else - if ((visualSceneSectionName == reader->getNodeName()) && p) - { - Prefabs.push_back(p); - p = 0; - } - } - } -} - - -//! reads a section and its content -void CColladaFileLoader::readSceneSection(io::IXMLReaderUTF8* reader) -{ - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading scene", ELL_DEBUG); - #endif - - if (reader->isEmptyElement()) - return; - - // read the scene - - core::matrix4 transform; // transformation of this node - core::aabbox3df bbox; - scene::IDummyTransformationSceneNode* node = 0; - - while(reader->read()) - { - if (reader->getNodeType() == io::EXN_ELEMENT) - { - if (lookatNodeName == reader->getNodeName()) - transform *= readLookAtNode(reader); - else - if (matrixNodeName == reader->getNodeName()) - transform *= readMatrixNode(reader); - else - if (perspectiveNodeName == reader->getNodeName()) - transform *= readPerspectiveNode(reader); - else - if (rotateNodeName == reader->getNodeName()) - transform *= readRotateNode(reader); - else - if (scaleNodeName == reader->getNodeName()) - transform *= readScaleNode(reader); - else - if (skewNodeName == reader->getNodeName()) - transform *= readSkewNode(reader); - else - if (translateNodeName == reader->getNodeName()) - transform *= readTranslateNode(reader); - else - if (bboxNodeName == reader->getNodeName()) - readBboxNode(reader, bbox); - else - if (nodeSectionName == reader->getNodeName()) - { - // create dummy node if there is none yet. - if (!node) - node = SceneManager->addDummyTransformationSceneNode(SceneManager->getRootSceneNode()); - - readNodeSection(reader, node); - } - else - if ((instanceSceneName == reader->getNodeName())) - readInstanceNode(reader, SceneManager->getRootSceneNode(), 0, 0,instanceSceneName); - else - if (extraNodeName == reader->getNodeName()) - skipSection(reader, false); - else - { - os::Printer::log("COLLADA loader warning: Wrong tag usage found", reader->getNodeName(), ELL_WARNING); - skipSection(reader, true); // ignore all other sections - } - } - else - if ((reader->getNodeType() == io::EXN_ELEMENT_END) && - (sceneSectionName == reader->getNodeName())) - return; - } - if (node) - node->getRelativeTransformationMatrix() = transform; -} - - -//! reads a section and its content -void CColladaFileLoader::readAssetSection(io::IXMLReaderUTF8* reader) -{ - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading asset", ELL_DEBUG); - #endif - - if (reader->isEmptyElement()) - return; - - while(reader->read()) - { - if (reader->getNodeType() == io::EXN_ELEMENT) - { - if (upAxisNodeName == reader->getNodeName()) - { - reader->read(); - FlipAxis = (core::stringc("Z_UP") == reader->getNodeData()); - } - } - else - if ((reader->getNodeType() == io::EXN_ELEMENT_END) && - (assetSectionName == reader->getNodeName())) - return; - } -} - - -//! reads a section and its content -void CColladaFileLoader::readNodeSection(io::IXMLReaderUTF8* reader, scene::ISceneNode* parent, CScenePrefab* p) -{ - if (reader->isEmptyElement()) - { - return; - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading empty node", ELL_DEBUG); - #endif - } - - core::stringc name = readId(reader); - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading node", name, ELL_DEBUG); - #endif - - core::matrix4 transform; // transformation of this node - core::aabbox3df bbox; - scene::ISceneNode* node = 0; // instance - CScenePrefab* nodeprefab = 0; // prefab for library_nodes usage - - if (p) - { - nodeprefab = new CScenePrefab(readId(reader)); - p->Children.push_back(nodeprefab); - Prefabs.push_back(nodeprefab); // in order to delete them later on - } - - // read the node - - while(reader->read()) - { - if (reader->getNodeType() == io::EXN_ELEMENT) - { - if (assetSectionName == reader->getNodeName()) - readAssetSection(reader); - else - if (lookatNodeName == reader->getNodeName()) - transform *= readLookAtNode(reader); - else - if (matrixNodeName == reader->getNodeName()) - transform *= readMatrixNode(reader); - else - if (perspectiveNodeName == reader->getNodeName()) - transform *= readPerspectiveNode(reader); - else - if (rotateNodeName == reader->getNodeName()) - transform *= readRotateNode(reader); - else - if (scaleNodeName == reader->getNodeName()) - transform *= readScaleNode(reader); - else - if (skewNodeName == reader->getNodeName()) - transform *= readSkewNode(reader); - else - if (translateNodeName == reader->getNodeName()) - transform *= readTranslateNode(reader); - else - if (bboxNodeName == reader->getNodeName()) - readBboxNode(reader, bbox); - else - if ((instanceName == reader->getNodeName()) || - (instanceNodeName == reader->getNodeName()) || - (instanceGeometryName == reader->getNodeName()) || - (instanceLightName == reader->getNodeName())) - { - scene::ISceneNode* newnode = 0; - readInstanceNode(reader, parent, &newnode, nodeprefab, reader->getNodeName()); - - if (node && newnode) - { - // move children from dummy to new node - ISceneNodeList::ConstIterator it = node->getChildren().begin(); - for (; it != node->getChildren().end(); it = node->getChildren().begin()) - (*it)->setParent(newnode); - - // remove previous dummy node - node->remove(); - node = newnode; - } - } - else - if (nodeSectionName == reader->getNodeName()) - { - // create dummy node if there is none yet. - if (CreateInstances && !node) - { - scene::IDummyTransformationSceneNode* dummy = - SceneManager->addDummyTransformationSceneNode(parent); - dummy->getRelativeTransformationMatrix() = transform; - node = dummy; - } - else - node = parent; - - // read and add child - readNodeSection(reader, node, nodeprefab); - } - else - if (extraNodeName == reader->getNodeName()) - skipSection(reader, false); - else - skipSection(reader, true); // ignore all other sections - - } // end if node - else - if (reader->getNodeType() == io::EXN_ELEMENT_END) - { - if (nodeSectionName == reader->getNodeName()) - break; - } - } - - if (nodeprefab) - nodeprefab->Transformation = transform; - else - if (node) - { - // set transformation correctly into node. - node->setPosition(transform.getTranslation()); - node->setRotation(transform.getRotationDegrees()); - node->setScale(transform.getScale()); - node->updateAbsolutePosition(); - - node->setName(name); - } -} - - -//! reads a element and its content and creates a matrix from it -core::matrix4 CColladaFileLoader::readLookAtNode(io::IXMLReaderUTF8* reader) -{ - core::matrix4 mat; - if (reader->isEmptyElement()) - return mat; - - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading look at node", ELL_DEBUG); - #endif - - f32 floats[9]; - readFloatsInsideElement(reader, floats, 9); - - mat.buildCameraLookAtMatrixLH( - core::vector3df(floats[0], floats[1], floats[2]), - core::vector3df(floats[3], floats[4], floats[5]), - core::vector3df(floats[6], floats[7], floats[8])); - - return mat; -} - - -//! reads a element and its content and creates a matrix from it -core::matrix4 CColladaFileLoader::readSkewNode(io::IXMLReaderUTF8* reader) -{ - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading skew node", ELL_DEBUG); - #endif - - core::matrix4 mat; - if (reader->isEmptyElement()) - return mat; - - f32 floats[7]; // angle rotation-axis translation-axis - readFloatsInsideElement(reader, floats, 7); - - // build skew matrix from these 7 floats - core::quaternion q; - q.fromAngleAxis(floats[0]*core::DEGTORAD, core::vector3df(floats[1], floats[2], floats[3])); - mat = q.getMatrix(); - - if (floats[4]==1.f) // along x-axis - { - mat[4]=0.f; - mat[6]=0.f; - mat[8]=0.f; - mat[9]=0.f; - } - else - if (floats[5]==1.f) // along y-axis - { - mat[1]=0.f; - mat[2]=0.f; - mat[8]=0.f; - mat[9]=0.f; - } - else - if (floats[6]==1.f) // along z-axis - { - mat[1]=0.f; - mat[2]=0.f; - mat[4]=0.f; - mat[6]=0.f; - } - - return mat; -} - - -//! reads a element and its content and stores it in bbox -void CColladaFileLoader::readBboxNode(io::IXMLReaderUTF8* reader, - core::aabbox3df& bbox) -{ - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading boundingbox node", ELL_DEBUG); - #endif - - bbox.reset(core::aabbox3df()); - - if (reader->isEmptyElement()) - return; - - f32 floats[3]; - - while(reader->read()) - { - if (reader->getNodeType() == io::EXN_ELEMENT) - { - if (minNodeName == reader->getNodeName()) - { - readFloatsInsideElement(reader, floats, 3); - bbox.MinEdge.set(floats[0], floats[1], floats[2]); - } - else - if (maxNodeName == reader->getNodeName()) - { - readFloatsInsideElement(reader, floats, 3); - bbox.MaxEdge.set(floats[0], floats[1], floats[2]); - } - else - skipSection(reader, true); // ignore all other sections - } - else - if (reader->getNodeType() == io::EXN_ELEMENT_END) - { - if (bboxNodeName == reader->getNodeName()) - break; - } - } -} - - -//! reads a element and its content and creates a matrix from it -core::matrix4 CColladaFileLoader::readMatrixNode(io::IXMLReaderUTF8* reader) -{ - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading matrix node", ELL_DEBUG); - #endif - - core::matrix4 mat; - if (reader->isEmptyElement()) - return mat; - - readFloatsInsideElement(reader, mat.pointer(), 16); - // put translation into the correct place - if (FlipAxis) - { - core::matrix4 mat2(mat, core::matrix4::EM4CONST_TRANSPOSED); - mat2[1]=mat[8]; - mat2[2]=mat[4]; - mat2[4]=mat[2]; - mat2[5]=mat[10]; - mat2[6]=mat[6]; - mat2[8]=mat[1]; - mat2[9]=mat[9]; - mat2[10]=mat[5]; - mat2[12]=mat[3]; - mat2[13]=mat[11]; - mat2[14]=mat[7]; - return mat2; - } - else - return core::matrix4(mat, core::matrix4::EM4CONST_TRANSPOSED); -} - - -//! reads a element and its content and creates a matrix from it -core::matrix4 CColladaFileLoader::readPerspectiveNode(io::IXMLReaderUTF8* reader) -{ - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading perspective node", ELL_DEBUG); - #endif - - core::matrix4 mat; - if (reader->isEmptyElement()) - return mat; - - f32 floats[1]; - readFloatsInsideElement(reader, floats, 1); - - // TODO: build perspecitve matrix from this float - - os::Printer::log("COLLADA loader warning: not implemented yet.", ELL_WARNING); - - return mat; -} - - -//! reads a element and its content and creates a matrix from it -core::matrix4 CColladaFileLoader::readRotateNode(io::IXMLReaderUTF8* reader) -{ - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading rotate node", ELL_DEBUG); - #endif - - core::matrix4 mat; - if (reader->isEmptyElement()) - return mat; - - f32 floats[4]; - readFloatsInsideElement(reader, floats, 4); - - if (!core::iszero(floats[3])) - { - core::quaternion q; - if (FlipAxis) - q.fromAngleAxis(floats[3]*core::DEGTORAD, core::vector3df(floats[0], floats[2], floats[1])); - else - q.fromAngleAxis(floats[3]*core::DEGTORAD, core::vector3df(floats[0], floats[1], floats[2])); - return q.getMatrix(); - } - else - return core::IdentityMatrix; -} - - -//! reads a element and its content and creates a matrix from it -core::matrix4 CColladaFileLoader::readScaleNode(io::IXMLReaderUTF8* reader) -{ - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading scale node", ELL_DEBUG); - #endif - - core::matrix4 mat; - if (reader->isEmptyElement()) - return mat; - - f32 floats[3]; - readFloatsInsideElement(reader, floats, 3); - - if (FlipAxis) - mat.setScale(core::vector3df(floats[0], floats[2], floats[1])); - else - mat.setScale(core::vector3df(floats[0], floats[1], floats[2])); - - return mat; -} - - -//! reads a element and its content and creates a matrix from it -core::matrix4 CColladaFileLoader::readTranslateNode(io::IXMLReaderUTF8* reader) -{ - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading translate node", ELL_DEBUG); - #endif - - core::matrix4 mat; - if (reader->isEmptyElement()) - return mat; - - f32 floats[3]; - readFloatsInsideElement(reader, floats, 3); - - if (FlipAxis) - mat.setTranslation(core::vector3df(floats[0], floats[2], floats[1])); - else - mat.setTranslation(core::vector3df(floats[0], floats[1], floats[2])); - - return mat; -} - - -//! reads any kind of node -void CColladaFileLoader::readInstanceNode(io::IXMLReaderUTF8* reader, - scene::ISceneNode* parent, scene::ISceneNode** outNode, - CScenePrefab* p, const core::stringc& type) -{ - // find prefab of the specified id - core::stringc url = reader->getAttributeValue("url"); - uriToId(url); - - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading instance", url, ELL_DEBUG); - #endif - - if (!reader->isEmptyElement()) - { - while(reader->read()) - { - if (reader->getNodeType() == io::EXN_ELEMENT) - { - if (bindMaterialName == reader->getNodeName()) - readBindMaterialSection(reader,url); - else - if (extraNodeName == reader->getNodeName()) - skipSection(reader, false); - } - else - if (reader->getNodeType() == io::EXN_ELEMENT_END) - break; - } - } - instantiateNode(parent, outNode, p, url, type); -} - - -void CColladaFileLoader::instantiateNode(scene::ISceneNode* parent, - scene::ISceneNode** outNode, CScenePrefab* p, const core::stringc& url, - const core::stringc& type) -{ - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA instantiate node", ELL_DEBUG); - #endif - - for (u32 i=0; igetId()) - { - if (p) - p->Children.push_back(Prefabs[i]); - else - if (CreateInstances) - { - scene::ISceneNode * newNode - = Prefabs[i]->addInstance(parent, SceneManager); - if (outNode) - { - *outNode = newNode; - if (*outNode) - (*outNode)->setName(url); - } - } - return; - } - } - if (p) - { - if (instanceGeometryName==type) - { - Prefabs.push_back(new CGeometryPrefab(url)); - p->Children.push_back(Prefabs.getLast()); - } - } -} - - -//! reads a element and stores it as prefab -void CColladaFileLoader::readCameraPrefab(io::IXMLReaderUTF8* reader) -{ - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading camera prefab", ELL_DEBUG); - #endif - - CCameraPrefab* prefab = new CCameraPrefab(readId(reader)); - - if (!reader->isEmptyElement()) - { - // read techniques optics and imager (the latter is completely ignored, though) - readColladaParameters(reader, cameraPrefabName); - - SColladaParam* p; - - // XFOV not yet supported - p = getColladaParameter(ECPN_YFOV); - if (p && p->Type == ECPT_FLOAT) - prefab->YFov = p->Floats[0]; - - p = getColladaParameter(ECPN_ZNEAR); - if (p && p->Type == ECPT_FLOAT) - prefab->ZNear = p->Floats[0]; - - p = getColladaParameter(ECPN_ZFAR); - if (p && p->Type == ECPT_FLOAT) - prefab->ZFar = p->Floats[0]; - // orthographic camera uses LEFT, RIGHT, TOP, and BOTTOM - } - - Prefabs.push_back(prefab); -} - - -//! reads a element and stores it in the image section -void CColladaFileLoader::readImage(io::IXMLReaderUTF8* reader) -{ - // add image to list of loaded images. - Images.push_back(SColladaImage()); - SColladaImage& image=Images.getLast(); - - image.Id = readId(reader); - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading image", core::stringc(image.Id), ELL_DEBUG); - #endif - image.Dimension.Height = (u32)reader->getAttributeValueAsInt("height"); - image.Dimension.Width = (u32)reader->getAttributeValueAsInt("width"); - - if (Version >= 10400) // start with 1.4 - { - while(reader->read()) - { - if (reader->getNodeType() == io::EXN_ELEMENT) - { - if (assetSectionName == reader->getNodeName()) - skipSection(reader, false); - else - if (initFromName == reader->getNodeName()) - { - reader->read(); - image.Source = reader->getNodeData(); - image.Source.trim(); - image.SourceIsFilename=true; - } - else - if (dataName == reader->getNodeName()) - { - reader->read(); - image.Source = reader->getNodeData(); - image.Source.trim(); - image.SourceIsFilename=false; - } - else - if (extraNodeName == reader->getNodeName()) - skipSection(reader, false); - } - else - if (reader->getNodeType() == io::EXN_ELEMENT_END) - { - if (initFromName == reader->getNodeName()) - return; - } - } - } - else - { - image.Source = reader->getAttributeValue("source"); - image.Source.trim(); - image.SourceIsFilename=false; - } -} - - -//! reads a element and stores it in the texture section -void CColladaFileLoader::readTexture(io::IXMLReaderUTF8* reader) -{ - // add texture to list of loaded textures. - Textures.push_back(SColladaTexture()); - SColladaTexture& texture=Textures.getLast(); - - texture.Id = readId(reader); - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading texture", core::stringc(texture.Id), ELL_DEBUG); - #endif - - if (!reader->isEmptyElement()) - { - readColladaInputs(reader, textureSectionName); - SColladaInput* input = getColladaInput(ECIS_IMAGE); - if (input) - { - const core::stringc imageName = input->Source; - texture.Texture = getTextureFromImage(imageName, NULL); - } - } -} - - -//! reads a element and stores it in the material section -void CColladaFileLoader::readMaterial(io::IXMLReaderUTF8* reader) -{ - // add material to list of loaded materials. - Materials.push_back(SColladaMaterial()); - - SColladaMaterial& material = Materials.getLast(); - material.Id = readId(reader); - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading material", core::stringc(material.Id), ELL_DEBUG); - #endif - - if (Version >= 10400) - { - while(reader->read()) - { - if (reader->getNodeType() == io::EXN_ELEMENT && - instanceEffectName == reader->getNodeName()) - { - material.InstanceEffectId = reader->getAttributeValue("url"); - uriToId(material.InstanceEffectId); - } - else - if (reader->getNodeType() == io::EXN_ELEMENT_END && - materialSectionName == reader->getNodeName()) - { - break; - } - } // end while reader->read(); - } - else - { - if (!reader->isEmptyElement()) - { - readColladaInputs(reader, materialSectionName); - SColladaInput* input = getColladaInput(ECIS_TEXTURE); - if (input) - { - core::stringc textureName = input->Source; - uriToId(textureName); - for (u32 i=0; iType == ECPT_FLOAT3) - material.Mat.AmbientColor = video::SColorf(p->Floats[0],p->Floats[1],p->Floats[2]).toSColor(); - p = getColladaParameter(ECPN_DIFFUSE); - if (p && p->Type == ECPT_FLOAT3) - material.Mat.DiffuseColor = video::SColorf(p->Floats[0],p->Floats[1],p->Floats[2]).toSColor(); - p = getColladaParameter(ECPN_SPECULAR); - if (p && p->Type == ECPT_FLOAT3) - material.Mat.DiffuseColor = video::SColorf(p->Floats[0],p->Floats[1],p->Floats[2]).toSColor(); - p = getColladaParameter(ECPN_SHININESS); - if (p && p->Type == ECPT_FLOAT) - material.Mat.Shininess = p->Floats[0]; -#endif - } - } -} - -void CColladaFileLoader::readEffect(io::IXMLReaderUTF8* reader, SColladaEffect * effect) -{ - static const core::stringc constantNode("constant"); - static const core::stringc lambertNode("lambert"); - static const core::stringc phongNode("phong"); - static const core::stringc blinnNode("blinn"); - static const core::stringc emissionNode("emission"); - static const core::stringc ambientNode("ambient"); - static const core::stringc diffuseNode("diffuse"); - static const core::stringc specularNode("specular"); - static const core::stringc shininessNode("shininess"); - static const core::stringc reflectiveNode("reflective"); - static const core::stringc reflectivityNode("reflectivity"); - static const core::stringc transparentNode("transparent"); - static const core::stringc transparencyNode("transparency"); - static const core::stringc indexOfRefractionNode("index_of_refraction"); - - if (!effect) - { - Effects.push_back(SColladaEffect()); - effect = &Effects.getLast(); - effect->Parameters = new io::CAttributes(); - effect->Id = readId(reader); - effect->Transparency = 1.f; - effect->Mat.Lighting=true; - effect->Mat.NormalizeNormals=true; - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading effect", core::stringc(effect->Id), ELL_DEBUG); - #endif - } - while(reader->read()) - { - if (reader->getNodeType() == io::EXN_ELEMENT) - { - // first come the tags we descend, but ignore the top-levels - if (!reader->isEmptyElement() && ((profileCOMMONSectionName == reader->getNodeName()) || - (techniqueNodeName == reader->getNodeName()))) - readEffect(reader,effect); - else - if (newParamName == reader->getNodeName()) - readParameter(reader, effect->Parameters); - else - // these are the actual materials inside technique - if (constantNode == reader->getNodeName() || - lambertNode == reader->getNodeName() || - phongNode == reader->getNodeName() || - blinnNode == reader->getNodeName()) - { - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading effect part", reader->getNodeName(), ELL_DEBUG); - #endif - effect->Mat.setFlag(irr::video::EMF_GOURAUD_SHADING, - phongNode == reader->getNodeName() || - blinnNode == reader->getNodeName()); - while(reader->read()) - { - if (reader->getNodeType() == io::EXN_ELEMENT) - { - const core::stringc node = reader->getNodeName(); - if (emissionNode == node || ambientNode == node || - diffuseNode == node || specularNode == node || - reflectiveNode == node || transparentNode == node ) - { - // color or texture types - while(reader->read()) - { - if (reader->getNodeType() == io::EXN_ELEMENT && - colorNodeName == reader->getNodeName()) - { - const video::SColorf colorf = readColorNode(reader); - const video::SColor color = colorf.toSColor(); - if (emissionNode == node) - effect->Mat.EmissiveColor = color; - else - if (ambientNode == node) - effect->Mat.AmbientColor = color; - else - if (diffuseNode == node) - effect->Mat.DiffuseColor = color; - else - if (specularNode == node) - effect->Mat.SpecularColor = color; - else - if (transparentNode == node) - effect->Transparency = colorf.getAlpha(); - } - else - if (reader->getNodeType() == io::EXN_ELEMENT && - textureNodeName == reader->getNodeName()) - { - effect->Textures.push_back(reader->getAttributeValue("texture")); - break; - } - else - if (reader->getNodeType() == io::EXN_ELEMENT) - skipSection(reader, false); - else - if (reader->getNodeType() == io::EXN_ELEMENT_END && - node == reader->getNodeName()) - break; - } - } - else - if (shininessNode == node || reflectivityNode == node || - transparencyNode == node || indexOfRefractionNode == node ) - { - // float or param types - while(reader->read()) - { - if (reader->getNodeType() == io::EXN_ELEMENT && - floatNodeName == reader->getNodeName()) - { - f32 f = readFloatNode(reader); - if (shininessNode == node) - effect->Mat.Shininess = f; - else - if (transparencyNode == node) - effect->Transparency *= f; - } - else - if (reader->getNodeType() == io::EXN_ELEMENT) - skipSection(reader, false); - else - if (reader->getNodeType() == io::EXN_ELEMENT_END && - node == reader->getNodeName()) - break; - } - } - else - skipSection(reader, true); // ignore all other nodes - } - else - if (reader->getNodeType() == io::EXN_ELEMENT_END && ( - constantNode == reader->getNodeName() || - lambertNode == reader->getNodeName() || - phongNode == reader->getNodeName() || - blinnNode == reader->getNodeName() - )) - break; - } - } - else - if (!reader->isEmptyElement() && (extraNodeName == reader->getNodeName())) - readEffect(reader,effect); - else - if (doubleSidedNodeName == reader->getNodeName()) - { - // read the GoogleEarth extra flag for double sided polys - s32 doubleSided = 0; - readIntsInsideElement(reader,&doubleSided,1); - if (doubleSided) - { - #ifdef COLLADA_READER_DEBUG - os::Printer::log("Setting double sided flag for effect.", ELL_DEBUG); - #endif - - effect->Mat.setFlag(irr::video::EMF_BACK_FACE_CULLING,false); - } - } - else - skipSection(reader, true); // ignore all other sections - } - else - if (reader->getNodeType() == io::EXN_ELEMENT_END) - { - if (effectSectionName == reader->getNodeName()) - break; - else - if (profileCOMMONSectionName == reader->getNodeName()) - break; - else - if (techniqueNodeName == reader->getNodeName()) - break; - else - if (extraNodeName == reader->getNodeName()) - break; - } - } - - if (effect->Mat.AmbientColor == video::SColor(0) && - effect->Mat.DiffuseColor != video::SColor(0)) - effect->Mat.AmbientColor = effect->Mat.DiffuseColor; - if (effect->Mat.DiffuseColor == video::SColor(0) && - effect->Mat.AmbientColor != video::SColor(0)) - effect->Mat.DiffuseColor = effect->Mat.AmbientColor; - if ((effect->Transparency != 0.0f) && (effect->Transparency != 1.0f)) - { - effect->Mat.MaterialType = irr::video::EMT_TRANSPARENT_VERTEX_ALPHA; - effect->Mat.ZWriteEnable = false; - } - - video::E_TEXTURE_CLAMP twu = video::ETC_REPEAT; - s32 idx = effect->Parameters->findAttribute(wrapsName.c_str()); - if ( idx >= 0 ) - twu = (video::E_TEXTURE_CLAMP)(effect->Parameters->getAttributeAsInt(idx)); - video::E_TEXTURE_CLAMP twv = video::ETC_REPEAT; - idx = effect->Parameters->findAttribute(wraptName.c_str()); - if ( idx >= 0 ) - twv = (video::E_TEXTURE_CLAMP)(effect->Parameters->getAttributeAsInt(idx)); - - for (u32 i=0; iMat.TextureLayer[i].TextureWrapU = twu; - effect->Mat.TextureLayer[i].TextureWrapV = twv; - } - - effect->Mat.setFlag(video::EMF_BILINEAR_FILTER, effect->Parameters->getAttributeAsBool("bilinear")); - effect->Mat.setFlag(video::EMF_TRILINEAR_FILTER, effect->Parameters->getAttributeAsBool("trilinear")); - effect->Mat.setFlag(video::EMF_ANISOTROPIC_FILTER, effect->Parameters->getAttributeAsBool("anisotropic")); -} - - -const SColladaMaterial* CColladaFileLoader::findMaterial(const core::stringc& materialName) -{ - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA find material", materialName, ELL_DEBUG); - #endif - - // do a quick lookup in the materials - SColladaMaterial matToFind; - matToFind.Id = materialName; - s32 mat = Materials.binary_search(matToFind); - if (mat == -1) - return 0; - // instantiate the material effect if needed - if (Materials[mat].InstanceEffectId.size() != 0) - { - // do a quick lookup in the effects - SColladaEffect effectToFind; - effectToFind.Id = Materials[mat].InstanceEffectId; - s32 effect = Effects.binary_search(effectToFind); - if (effect != -1) - { - // found the effect, instantiate by copying into the material - Materials[mat].Mat = Effects[effect].Mat; - if (Effects[effect].Textures.size()) - Materials[mat].Mat.setTexture(0, getTextureFromImage(Effects[effect].Textures[0], &(Effects[effect]))); - Materials[mat].Transparency = Effects[effect].Transparency; - // and indicate the material is instantiated by removing the effect ref - Materials[mat].InstanceEffectId = ""; - } - else - return 0; - } - return &Materials[mat]; -} - - -void CColladaFileLoader::readBindMaterialSection(io::IXMLReaderUTF8* reader, const core::stringc & id) -{ - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading bind material", ELL_DEBUG); - #endif - - while(reader->read()) - { - if (reader->getNodeType() == io::EXN_ELEMENT) - { - if (instanceMaterialName == reader->getNodeName()) - { - // the symbol to retarget, and the target material - core::stringc meshbufferReference = reader->getAttributeValue("symbol"); - if (meshbufferReference.size()==0) - continue; - core::stringc target = reader->getAttributeValue("target"); - uriToId(target); - if (target.size()==0) - continue; - const SColladaMaterial * material = findMaterial(target); - if (!material) - continue; - // bind any pending materials for this node - meshbufferReference = id+"/"+meshbufferReference; -#ifdef COLLADA_READER_DEBUG - os::Printer::log((core::stringc("Material binding: ")+meshbufferReference+" "+target).c_str(), ELL_DEBUG); -#endif - if (MaterialsToBind.find(meshbufferReference)) - { - core::array & toBind - = MeshesToBind[MaterialsToBind[meshbufferReference]]; -#ifdef COLLADA_READER_DEBUG - os::Printer::log("Material binding now ",material->Id.c_str(), ELL_DEBUG); - os::Printer::log("#meshbuffers",core::stringc(toBind.size()).c_str(), ELL_DEBUG); -#endif - SMesh tmpmesh; - for (u32 i = 0; i < toBind.size(); ++i) - { - toBind[i]->getMaterial() = material->Mat; - tmpmesh.addMeshBuffer(toBind[i]); - - if ((material->Transparency!=0.0f) && (material->Transparency!=1.0f)) - { - toBind[i]->getMaterial().MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; - toBind[i]->getMaterial().ZWriteEnable = false; - } - } - SceneManager->getMeshManipulator()->setVertexColors(&tmpmesh,material->Mat.DiffuseColor); - if ((material->Transparency!=0.0f) && (material->Transparency!=1.0f)) - { - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA found transparency material", core::stringc(material->Transparency).c_str(), ELL_DEBUG); - #endif - SceneManager->getMeshManipulator()->setVertexColorAlpha(&tmpmesh, core::floor32(material->Transparency*255.0f)); - } - } - } - } - else - if (reader->getNodeType() == io::EXN_ELEMENT_END && - bindMaterialName == reader->getNodeName()) - break; - } -} - - -//! reads a element and stores it as mesh if possible -void CColladaFileLoader::readGeometry(io::IXMLReaderUTF8* reader) -{ - core::stringc id = readId(reader); - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading geometry", id, ELL_DEBUG); - #endif - - SAnimatedMesh* amesh = new SAnimatedMesh(); - scene::SMesh* mesh = new SMesh(); - amesh->addMesh(mesh); - core::array sources; - bool okToReadArray = false; - - // handles geometry node and the mesh children in this loop - // read sources with arrays and accessor for each mesh - if (!reader->isEmptyElement()) - while(reader->read()) - { - if (reader->getNodeType() == io::EXN_ELEMENT) - { - const char* nodeName = reader->getNodeName(); - if (meshSectionName == nodeName) - { - // inside a mesh section. Don't have to do anything here. - } - else - if (sourceSectionName == nodeName) - { - // create a new source - sources.push_back(SSource()); - sources.getLast().Id = readId(reader); - - #ifdef COLLADA_READER_DEBUG - os::Printer::log("Reading source", sources.getLast().Id.c_str(), ELL_DEBUG); - #endif - } - else - if (arraySectionName == nodeName || floatArraySectionName == nodeName || intArraySectionName == nodeName) - { - // create a new array and read it. - if (!sources.empty()) - { - sources.getLast().Array.Name = readId(reader); - - int count = reader->getAttributeValueAsInt("count"); - sources.getLast().Array.Data.set_used(count); // pre allocate - - // check if type of array is ok - const char* type = reader->getAttributeValue("type"); - okToReadArray = (type && (!strcmp("float", type) || !strcmp("int", type))) || floatArraySectionName == nodeName || intArraySectionName == nodeName; - - #ifdef COLLADA_READER_DEBUG - os::Printer::log("Read array", sources.getLast().Array.Name.c_str(), ELL_DEBUG); - #endif - } - #ifdef COLLADA_READER_DEBUG - else - os::Printer::log("Warning, array outside source found", - readId(reader).c_str(), ELL_DEBUG); - #endif - - } - else - if (accessorSectionName == nodeName) // child of source (below a technique tag) - { - #ifdef COLLADA_READER_DEBUG - os::Printer::log("Reading accessor", ELL_DEBUG); - #endif - SAccessor accessor; - accessor.Count = reader->getAttributeValueAsInt("count"); - accessor.Offset = reader->getAttributeValueAsInt("offset"); - accessor.Stride = reader->getAttributeValueAsInt("stride"); - if (accessor.Stride == 0) - accessor.Stride = 1; - - // the accessor contains some information on how to access (boi!) the array, - // the info is stored in collada style parameters, so just read them. - readColladaParameters(reader, accessorSectionName); - if (!sources.empty()) - { - sources.getLast().Accessors.push_back(accessor); - sources.getLast().Accessors.getLast().Parameters = ColladaParameters; - } - } - else - if (verticesSectionName == nodeName) - { - #ifdef COLLADA_READER_DEBUG - os::Printer::log("Reading vertices", ELL_DEBUG); - #endif - // read vertex input position source - readColladaInputs(reader, verticesSectionName); - } - else - // lines and linestrips missing - if (polygonsSectionName == nodeName || - polylistSectionName == nodeName || - trianglesSectionName == nodeName) - { - // read polygons section - readPolygonSection(reader, sources, mesh, id); - } - else - // trifans, and tristrips missing - if (doubleSidedNodeName == reader->getNodeName()) - { - // read the extra flag for double sided polys - s32 doubleSided = 0; - readIntsInsideElement(reader,&doubleSided,1); - if (doubleSided) - { - #ifdef COLLADA_READER_DEBUG - os::Printer::log("Setting double sided flag for mesh.", ELL_DEBUG); - #endif - amesh->setMaterialFlag(irr::video::EMF_BACK_FACE_CULLING,false); - } - } - else - // techniqueCommon or 'technique profile=common' must not be skipped - if ((techniqueCommonSectionName != nodeName) // Collada 1.2/1.3 - && (techniqueNodeName != nodeName) // Collada 1.4+ - && (extraNodeName != nodeName)) - { - os::Printer::log("COLLADA loader warning: Wrong tag usage found in geometry", reader->getNodeName(), ELL_WARNING); - skipSection(reader, true); // ignore all other sections - } - } // end if node type is element - else - if (reader->getNodeType() == io::EXN_TEXT) - { - // read array data - if (okToReadArray && !sources.empty()) - { - core::array& a = sources.getLast().Array.Data; - core::stringc data = reader->getNodeData(); - data.trim(); - const c8* p = &data[0]; - - for (u32 i=0; igetNodeType() == io::EXN_ELEMENT_END) - { - if (geometrySectionName == reader->getNodeName()) - { - // end of geometry section reached, cancel out - break; - } - } - } // end while reader->read(); - - // add mesh as geometry - - mesh->recalculateBoundingBox(); - amesh->recalculateBoundingBox(); - - // create virtual file name - io::path filename = CurrentlyLoadingMesh; - filename += '#'; - filename += id; - - // add to scene manager - if (LoadedMeshCount) - { - SceneManager->getMeshCache()->addMesh(filename.c_str(), amesh); - os::Printer::log("Added COLLADA mesh", filename.c_str(), ELL_DEBUG); - } - else - { - FirstLoadedMeshName = filename; - FirstLoadedMesh = amesh; - FirstLoadedMesh->grab(); - } - - ++LoadedMeshCount; - mesh->drop(); - amesh->drop(); - - // create geometry prefab - u32 i; - for (i=0; igetId()==id) - { - ((CGeometryPrefab*)Prefabs[i])->Mesh=mesh; - break; - } - } - if (i==Prefabs.size()) - { - CGeometryPrefab* prefab = new CGeometryPrefab(id); - prefab->Mesh = mesh; - Prefabs.push_back(prefab); - } - - // store as dummy mesh if no instances will be created - if (!CreateInstances && !DummyMesh) - { - DummyMesh = amesh; - DummyMesh->grab(); - } -} - - -struct SPolygon -{ - core::array Indices; -}; - -//! reads a polygons section and creates a mesh from it -void CColladaFileLoader::readPolygonSection(io::IXMLReaderUTF8* reader, - core::array& sources, scene::SMesh* mesh, - const core::stringc& geometryId) -{ - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading polygon section", ELL_DEBUG); - #endif - - core::stringc materialName = reader->getAttributeValue("material"); - - core::stringc polygonType = reader->getNodeName(); - const int polygonCount = reader->getAttributeValueAsInt("count"); // Not useful because it only determines the number of primitives, which have arbitrary vertices in case of polygon - core::array polygons; - if (polygonType == polygonsSectionName) - polygons.reallocate(polygonCount); - core::array vCounts; - bool parsePolygonOK = false; - bool parseVcountOK = false; - u32 inputSemanticCount = 0; - bool unresolvedInput=false; - u32 maxOffset = 0; - core::array localInputs; - - // read all and primitives - if (!reader->isEmptyElement()) - while(reader->read()) - { - const char* nodeName = reader->getNodeName(); - - if (reader->getNodeType() == io::EXN_ELEMENT) - { - // polygon node may contain params - if (inputTagName == nodeName) - { - // read input tag - readColladaInput(reader, localInputs); - - // resolve input source - SColladaInput& inp = localInputs.getLast(); - - // get input source array id, if it is a vertex input, take - // the -source attribute. - if (inp.Semantic == ECIS_VERTEX) - { - inp.Source = Inputs[0].Source; - for (u32 i=1; igetNodeType() == io::EXN_ELEMENT_END) - { - if (primitivesName == nodeName) - parsePolygonOK = false; // end parsing a polygon - else - if (vcountName == nodeName) - parseVcountOK = false; // end parsing vcounts - else - if (polygonType == nodeName) - break; // cancel out and create mesh - - } // end is element end - else - if (reader->getNodeType() == io::EXN_TEXT) - { - if (parseVcountOK) - { - core::stringc data = reader->getNodeData(); - data.trim(); - const c8* p = &data[0]; - while(*p) - { - findNextNoneWhiteSpace(&p); - if (*p) - vCounts.push_back(readInt(&p)); - } - parseVcountOK = false; - } - else - if (parsePolygonOK && polygons.size()) - { - core::stringc data = reader->getNodeData(); - data.trim(); - const c8* p = &data[0]; - SPolygon& poly = polygons.getLast(); - if (polygonType == polygonsSectionName) - poly.Indices.reallocate((maxOffset+1)*3); - else - poly.Indices.reallocate(polygonCount*(maxOffset+1)*3); - - if (vCounts.empty()) - { - while(*p) - { - findNextNoneWhiteSpace(&p); - poly.Indices.push_back(readInt(&p)); - } - } - else - { - for (u32 i = 0; i < vCounts.size(); i++) - { - const int polyVCount = vCounts[i]; - core::array polyCorners; - - for (u32 j = 0; j < polyVCount * inputSemanticCount; j++) - { - if (!*p) - break; - findNextNoneWhiteSpace(&p); - polyCorners.push_back(readInt(&p)); - } - - while (polyCorners.size() >= 3 * inputSemanticCount) - { - // add one triangle's worth of indices - for (u32 k = 0; k < inputSemanticCount * 3; ++k) - { - poly.Indices.push_back(polyCorners[k]); - } - - // remove one corner from our poly - polyCorners.erase(inputSemanticCount,inputSemanticCount); - } - polyCorners.clear(); - } - vCounts.clear(); - } - parsePolygonOK = false; - } - } - } // end while reader->read() - - // find source array (we'll ignore accessors for this implementation) - for (u32 i=0; i vertMap; - - for (u32 i=0; i indices; - const u32 vertexCount = polygons[i].Indices.size() / maxOffset; - mbuffer->Vertices.reallocate(mbuffer->Vertices.size()+vertexCount); - - // for all index/semantic groups - for (u32 v=0; v::Node* n = vertMap.find(vtx); - if (n) - { - indices.push_back(n->getValue()); - } - else - { - indices.push_back(mbuffer->getVertexCount()); - mbuffer->Vertices.push_back(vtx); - vertMap.insert(vtx, mbuffer->getVertexCount()-1); - } - } // end for all vertices - - if (polygonsSectionName == polygonType && - indices.size() > 3) - { - // need to tesselate for polygons of 4 or more vertices - // for now we naively turn interpret it as a triangle fan - // as full tesselation is problematic - if (FlipAxis) - { - for (u32 ind = indices.size()-3; ind>0 ; --ind) - { - mbuffer->Indices.push_back(indices[0]); - mbuffer->Indices.push_back(indices[ind+2]); - mbuffer->Indices.push_back(indices[ind+1]); - } - } - else - { - for (u32 ind = 0; ind+2 < indices.size(); ++ind) - { - mbuffer->Indices.push_back(indices[0]); - mbuffer->Indices.push_back(indices[ind+1]); - mbuffer->Indices.push_back(indices[ind+2]); - } - } - } - else - { - // it's just triangles - for (u32 ind = 0; ind < indices.size(); ind+=3) - { - if (FlipAxis) - { - mbuffer->Indices.push_back(indices[ind+2]); - mbuffer->Indices.push_back(indices[ind+1]); - mbuffer->Indices.push_back(indices[ind+0]); - } - else - { - mbuffer->Indices.push_back(indices[ind+0]); - mbuffer->Indices.push_back(indices[ind+1]); - mbuffer->Indices.push_back(indices[ind+2]); - } - } - } - - } // end for all polygons - } - else - { - // lightmap mesh buffer - - scene::SMeshBufferLightMap* mbuffer = new SMeshBufferLightMap(); - buffer = mbuffer; - - for (u32 i=0; iVertices.reallocate(mbuffer->Vertices.size()+vertexCount); - // for all vertices in array - for (u32 v=0; vVertices.push_back(vtx); - - } // end for all vertices - - // add vertex indices - const u32 oldVertexCount = mbuffer->Vertices.size() - vertexCount; - for (u32 face=0; faceIndices.push_back(oldVertexCount + 0); - mbuffer->Indices.push_back(oldVertexCount + 1 + face); - mbuffer->Indices.push_back(oldVertexCount + 2 + face); - } - - } // end for all polygons - } - - const SColladaMaterial* m = findMaterial(materialName); - if (m) - { - buffer->getMaterial() = m->Mat; - SMesh tmpmesh; - tmpmesh.addMeshBuffer(buffer); - SceneManager->getMeshManipulator()->setVertexColors(&tmpmesh,m->Mat.DiffuseColor); - if (m->Transparency != 1.0f) - SceneManager->getMeshManipulator()->setVertexColorAlpha(&tmpmesh,core::floor32(m->Transparency*255.0f)); - } - // add future bind reference for the material - core::stringc meshbufferReference = geometryId+"/"+materialName; - if (!MaterialsToBind.find(meshbufferReference)) - { - MaterialsToBind[meshbufferReference] = MeshesToBind.size(); - MeshesToBind.push_back(core::array()); - } - MeshesToBind[MaterialsToBind[meshbufferReference]].push_back(buffer); - - // calculate normals if there is no slot for it - - if (!normalSlotCount) - SceneManager->getMeshManipulator()->recalculateNormals(buffer, true); - - // recalculate bounding box - buffer->recalculateBoundingBox(); - - // add mesh buffer - mesh->addMeshBuffer(buffer); - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA added meshbuffer", core::stringc(buffer->getVertexCount())+" vertices, "+core::stringc(buffer->getIndexCount())+" indices.", ELL_DEBUG); - #endif - - buffer->drop(); -} - - -//! reads a element and stores it as prefab -void CColladaFileLoader::readLightPrefab(io::IXMLReaderUTF8* reader) -{ - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading light prefab", ELL_DEBUG); - #endif - - CLightPrefab* prefab = new CLightPrefab(readId(reader)); - - if (!reader->isEmptyElement()) - { - if (Version >= 10400) // start with 1.4 - { - while(reader->read()) - { - if (reader->getNodeType() == io::EXN_ELEMENT) - { - if (pointSectionName == reader->getNodeName()) - prefab->LightData.Type=video::ELT_POINT; - else - if (directionalSectionName == reader->getNodeName()) - prefab->LightData.Type=video::ELT_DIRECTIONAL; - else - if (spotSectionName == reader->getNodeName()) - prefab->LightData.Type=video::ELT_SPOT; - else - if (ambientSectionName == reader->getNodeName()) - prefab->LightData.Type=ELT_AMBIENT; - else - if (colorNodeName == reader->getNodeName()) - prefab->LightData.DiffuseColor=readColorNode(reader); - else - if (constantAttenuationNodeName == reader->getNodeName()) - readFloatsInsideElement(reader,&prefab->LightData.Attenuation.X,1); - else - if (linearAttenuationNodeName == reader->getNodeName()) - readFloatsInsideElement(reader,&prefab->LightData.Attenuation.Y,1); - else - if (quadraticAttenuationNodeName == reader->getNodeName()) - readFloatsInsideElement(reader,&prefab->LightData.Attenuation.Z,1); - else - if (falloffAngleNodeName == reader->getNodeName()) - { - readFloatsInsideElement(reader,&prefab->LightData.OuterCone,1); - prefab->LightData.OuterCone *= core::DEGTORAD; - } - else - if (falloffExponentNodeName == reader->getNodeName()) - readFloatsInsideElement(reader,&prefab->LightData.Falloff,1); - } - else - if (reader->getNodeType() == io::EXN_ELEMENT_END) - { - if ((pointSectionName == reader->getNodeName()) || - (directionalSectionName == reader->getNodeName()) || - (spotSectionName == reader->getNodeName()) || - (ambientSectionName == reader->getNodeName())) - break; - } - } - } - else - { - readColladaParameters(reader, lightPrefabName); - - SColladaParam* p = getColladaParameter(ECPN_COLOR); - if (p && p->Type == ECPT_FLOAT3) - prefab->LightData.DiffuseColor.set(p->Floats[0], p->Floats[1], p->Floats[2]); - } - } - - Prefabs.push_back(prefab); -} - - -//! returns a collada parameter or none if not found -SColladaParam* CColladaFileLoader::getColladaParameter(ECOLLADA_PARAM_NAME name) -{ - for (u32 i=0; i& inputs) -{ - // parse param - SColladaInput p; - - // get type - core::stringc semanticName = reader->getAttributeValue("semantic"); - for (u32 i=0; inputSemanticNames[i]; ++i) - { - if (semanticName == inputSemanticNames[i]) - { - p.Semantic = (ECOLLADA_INPUT_SEMANTIC)i; - break; - } - } - - // get source - p.Source = reader->getAttributeValue("source"); - if (reader->getAttributeValue("offset")) // Collada 1.4+ - p.Offset = (u32)reader->getAttributeValueAsInt("offset"); - else // Collada 1.2/1.3 - p.Offset = (u32)reader->getAttributeValueAsInt("idx"); - p.Set = (u32)reader->getAttributeValueAsInt("set"); - - // add input - inputs.push_back(p); -} - -//! parses all collada inputs inside an element and stores them in Inputs -void CColladaFileLoader::readColladaInputs(io::IXMLReaderUTF8* reader, const core::stringc& parentName) -{ - Inputs.clear(); - - while(reader->read()) - { - if (reader->getNodeType() == io::EXN_ELEMENT && - inputTagName == reader->getNodeName()) - { - readColladaInput(reader, Inputs); - } - else - if (reader->getNodeType() == io::EXN_ELEMENT_END) - { - if (parentName == reader->getNodeName()) - return; // end of parent reached - } - - } // end while reader->read(); -} - -//! parses all collada parameters inside an element and stores them in ColladaParameters -void CColladaFileLoader::readColladaParameters(io::IXMLReaderUTF8* reader, - const core::stringc& parentName) -{ - ColladaParameters.clear(); - - const char* const paramNames[] = {"COLOR", "AMBIENT", "DIFFUSE", - "SPECULAR", "SHININESS", "YFOV", "ZNEAR", "ZFAR", 0}; - - const char* const typeNames[] = {"float", "float2", "float3", 0}; - - while(reader->read()) - { - const char* nodeName = reader->getNodeName(); - if (reader->getNodeType() == io::EXN_ELEMENT && - paramTagName == nodeName) - { - // parse param - SColladaParam p; - - // get type - u32 i; - core::stringc typeName = reader->getAttributeValue("type"); - for (i=0; typeNames[i]; ++i) - if (typeName == typeNames[i]) - { - p.Type = (ECOLLADA_PARAM_TYPE)i; - break; - } - - // get name - core::stringc nameName = reader->getAttributeValue("name"); - for (i=0; typeNames[i]; ++i) - if (nameName == paramNames[i]) - { - p.Name = (ECOLLADA_PARAM_NAME)i; - break; - } - - // read parameter data inside parameter tags - switch(p.Type) - { - case ECPT_FLOAT: - case ECPT_FLOAT2: - case ECPT_FLOAT3: - case ECPT_FLOAT4: - readFloatsInsideElement(reader, p.Floats, p.Type - ECPT_FLOAT + 1); - break; - - // TODO: other types of data (ints, bools or whatever) - default: - break; - } - - // add param - ColladaParameters.push_back(p); - } - else - if (reader->getNodeType() == io::EXN_ELEMENT_END) - { - if (parentName == reader->getNodeName()) - return; // end of parent reached - } - - } // end while reader->read(); -} - - -//! parses a float from a char pointer and moves the pointer -//! to the end of the parsed float -inline f32 CColladaFileLoader::readFloat(const c8** p) -{ - f32 ftmp; - *p = core::fast_atof_move(*p, ftmp); - return ftmp; -} - - -//! parses an int from a char pointer and moves the pointer to -//! the end of the parsed float -inline s32 CColladaFileLoader::readInt(const c8** p) -{ - return (s32)readFloat(p); -} - - -//! places pointer to next begin of a token -void CColladaFileLoader::findNextNoneWhiteSpace(const c8** start) -{ - const c8* p = *start; - - while(*p && (*p==' ' || *p=='\n' || *p=='\r' || *p=='\t')) - ++p; - - // TODO: skip comments - - *start = p; -} - - -//! reads floats from inside of xml element until end of xml element -void CColladaFileLoader::readFloatsInsideElement(io::IXMLReaderUTF8* reader, f32* floats, u32 count) -{ - if (reader->isEmptyElement()) - return; - - while(reader->read()) - { - // TODO: check for comments inside the element - // and ignore them. - - if (reader->getNodeType() == io::EXN_TEXT) - { - // parse float data - core::stringc data = reader->getNodeData(); - data.trim(); - const c8* p = &data[0]; - - for (u32 i=0; igetNodeType() == io::EXN_ELEMENT_END) - break; // end parsing text - } -} - - -//! reads ints from inside of xml element until end of xml element -void CColladaFileLoader::readIntsInsideElement(io::IXMLReaderUTF8* reader, s32* ints, u32 count) -{ - if (reader->isEmptyElement()) - return; - - while(reader->read()) - { - // TODO: check for comments inside the element - // and ignore them. - - if (reader->getNodeType() == io::EXN_TEXT) - { - // parse float data - core::stringc data = reader->getNodeData(); - data.trim(); - const c8* p = &data[0]; - - for (u32 i=0; igetNodeType() == io::EXN_ELEMENT_END) - break; // end parsing text - } -} - - -video::SColorf CColladaFileLoader::readColorNode(io::IXMLReaderUTF8* reader) -{ - if (reader->getNodeType() == io::EXN_ELEMENT && - colorNodeName == reader->getNodeName()) - { - f32 color[4]; - readFloatsInsideElement(reader,color,4); - return video::SColorf(color[0], color[1], color[2], color[3]); - } - - return video::SColorf(); -} - - -f32 CColladaFileLoader::readFloatNode(io::IXMLReaderUTF8* reader) -{ - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading ", ELL_DEBUG); - #endif - - f32 result = 0.0f; - if (reader->getNodeType() == io::EXN_ELEMENT && - floatNodeName == reader->getNodeName()) - { - readFloatsInsideElement(reader,&result,1); - } - - return result; -} - - -//! clears all loaded data -void CColladaFileLoader::clearData() -{ - // delete all prefabs - - for (u32 i=0; idrop(); - - Prefabs.clear(); - - // clear all parameters - ColladaParameters.clear(); - - // clear all materials - Images.clear(); - - // clear all materials - Textures.clear(); - - // clear all materials - Materials.clear(); - - // clear all inputs - Inputs.clear(); - - // clear all effects - for ( u32 i=0; idrop(); - Effects.clear(); - - // clear all the materials to bind - MaterialsToBind.clear(); - MeshesToBind.clear(); -} - - -//! changes the XML URI into an internal id -void CColladaFileLoader::uriToId(core::stringc& str) -{ - // currently, we only remove the # from the begin if there - // because we simply don't support referencing other files. - if (!str.size()) - return; - - if (str[0] == '#') - str.erase(0); -} - - -//! read Collada Id, uses id or name if id is missing -core::stringc CColladaFileLoader::readId(io::IXMLReaderUTF8* reader) -{ - core::stringc id = reader->getAttributeValue("id"); - if (id.size()==0) - id = reader->getAttributeValue("name"); - return id; -} - - -//! create an Irrlicht texture from the reference -video::ITexture* CColladaFileLoader::getTextureFromImage(core::stringc uri, SColladaEffect * effect) -{ - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA searching texture", uri, ELL_DEBUG); - #endif - video::IVideoDriver* driver = SceneManager->getVideoDriver(); - for (;;) - { - uriToId(uri); - for (u32 i=0; iexistFile(Images[i].Source)) - return driver->getTexture(Images[i].Source); - return driver->getTexture((FileSystem->getFileDir(CurrentlyLoadingMesh)+"/"+Images[i].Source)); - } - else - if (Images[i].Source.size()) - { - //const u32 size = Images[i].Dimension.getArea(); - const u32 size = Images[i].Dimension.Width * Images[i].Dimension.Height;; - u32* data = new u32[size]; // we assume RGBA - u32* ptrdest = data; - const c8* ptrsrc = Images[i].Source.c_str(); - for (u32 j=0; jcreateImageFromData(video::ECF_A8R8G8B8, Images[i].Dimension, data, true, true); - video::ITexture* tex = driver->addTexture((CurrentlyLoadingMesh+"#"+Images[i].Id).c_str(), img); - img->drop(); - return tex; - } - break; - } - } - if (effect && effect->Parameters->getAttributeType(uri.c_str())==io::EAT_STRING) - { - uri = effect->Parameters->getAttributeAsString(uri.c_str()); -#ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA now searching texture", uri.c_str(), ELL_DEBUG); -#endif - } - else - break; - } - return 0; -} - - -//! read a parameter and value -void CColladaFileLoader::readParameter(io::IXMLReaderUTF8* reader, io::IAttributes* parameters) -{ - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading parameter", ELL_DEBUG); - #endif - - if ( !parameters ) - return; - - const core::stringc name = reader->getAttributeValue("sid"); - if (!reader->isEmptyElement()) - { - while(reader->read()) - { - if (reader->getNodeType() == io::EXN_ELEMENT) - { - if (floatNodeName == reader->getNodeName()) - { - const f32 f = readFloatNode(reader); - parameters->addFloat(name.c_str(), f); - } - else - if (float2NodeName == reader->getNodeName()) - { - f32 f[2]; - readFloatsInsideElement(reader, f, 2); -// Parameters.addVector2d(name.c_str(), core::vector2df(f[0],f[1])); - } - else - if (float3NodeName == reader->getNodeName()) - { - f32 f[3]; - readFloatsInsideElement(reader, f, 3); - parameters->addVector3d(name.c_str(), core::vector3df(f[0],f[1],f[2])); - } - else - if ((initFromName == reader->getNodeName()) || - (sourceSectionName == reader->getNodeName())) - { - reader->read(); - parameters->addString(name.c_str(), reader->getNodeData()); - } - else - if (wrapsName == reader->getNodeName()) - { - reader->read(); - const core::stringc val = reader->getNodeData(); - if (val == "WRAP") - parameters->addInt(wrapsName.c_str(), (int)video::ETC_REPEAT); - else if ( val== "MIRROR") - parameters->addInt(wrapsName.c_str(), (int)video::ETC_MIRROR); - else if ( val== "CLAMP") - parameters->addInt(wrapsName.c_str(), (int)video::ETC_CLAMP_TO_EDGE); - else if ( val== "BORDER") - parameters->addInt(wrapsName.c_str(), (int)video::ETC_CLAMP_TO_BORDER); - else if ( val== "NONE") - parameters->addInt(wrapsName.c_str(), (int)video::ETC_CLAMP_TO_BORDER); - } - else - if (wraptName == reader->getNodeName()) - { - reader->read(); - const core::stringc val = reader->getNodeData(); - if (val == "WRAP") - parameters->addInt(wraptName.c_str(), (int)video::ETC_REPEAT); - else if ( val== "MIRROR") - parameters->addInt(wraptName.c_str(), (int)video::ETC_MIRROR); - else if ( val== "CLAMP") - parameters->addInt(wraptName.c_str(), (int)video::ETC_CLAMP_TO_EDGE); - else if ( val== "BORDER") - parameters->addInt(wraptName.c_str(), (int)video::ETC_CLAMP_TO_BORDER); - else if ( val== "NONE") - parameters->addInt(wraptName.c_str(), (int)video::ETC_CLAMP_TO_BORDER); - } - else - if (minfilterName == reader->getNodeName()) - { - reader->read(); - const core::stringc val = reader->getNodeData(); - if (val == "LINEAR_MIPMAP_LINEAR") - parameters->addBool("trilinear", true); - else - if (val == "LINEAR_MIPMAP_NEAREST") - parameters->addBool("bilinear", true); - } - else - if (magfilterName == reader->getNodeName()) - { - reader->read(); - const core::stringc val = reader->getNodeData(); - if (val != "LINEAR") - { - parameters->addBool("bilinear", false); - parameters->addBool("trilinear", false); - } - } - else - if (mipfilterName == reader->getNodeName()) - { - parameters->addBool("anisotropic", true); - } - } - else - if(reader->getNodeType() == io::EXN_ELEMENT_END) - { - if (newParamName == reader->getNodeName()) - break; - } - } - } -} - - -} // end namespace scene -} // end namespace irr - -#endif // _IRR_COMPILE_WITH_COLLADA_LOADER_ - +// 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 + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_COLLADA_LOADER_ + +#include "CColladaFileLoader.h" +#include "os.h" +#include "IXMLReader.h" +#include "IDummyTransformationSceneNode.h" +#include "SAnimatedMesh.h" +#include "fast_atof.h" +#include "quaternion.h" +#include "ILightSceneNode.h" +#include "ICameraSceneNode.h" +#include "IMeshManipulator.h" +#include "IReadFile.h" +#include "IAttributes.h" +#include "IMeshCache.h" +#include "IMeshSceneNode.h" +#include "SMeshBufferLightMap.h" +#include "irrMap.h" + +#ifdef _DEBUG +#define COLLADA_READER_DEBUG +#endif +namespace irr +{ +namespace scene +{ +namespace +{ + // currently supported COLLADA tag names + const core::stringc colladaSectionName = "COLLADA"; + const core::stringc librarySectionName = "library"; + const core::stringc libraryNodesSectionName = "library_nodes"; + const core::stringc libraryGeometriesSectionName = "library_geometries"; + const core::stringc libraryMaterialsSectionName = "library_materials"; + const core::stringc libraryImagesSectionName = "library_images"; + const core::stringc libraryVisualScenesSectionName = "library_visual_scenes"; + const core::stringc libraryCamerasSectionName = "library_cameras"; + const core::stringc libraryLightsSectionName = "library_lights"; + const core::stringc libraryEffectsSectionName = "library_effects"; + const core::stringc assetSectionName = "asset"; + const core::stringc sceneSectionName = "scene"; + const core::stringc visualSceneSectionName = "visual_scene"; + + const core::stringc lightPrefabName = "light"; + const core::stringc cameraPrefabName = "camera"; + const core::stringc materialSectionName = "material"; + const core::stringc geometrySectionName = "geometry"; + const core::stringc imageSectionName = "image"; + const core::stringc textureSectionName = "texture"; + const core::stringc effectSectionName = "effect"; + + const core::stringc pointSectionName = "point"; + const core::stringc directionalSectionName ="directional"; + const core::stringc spotSectionName = "spot"; + const core::stringc ambientSectionName = "ambient"; + const core::stringc meshSectionName = "mesh"; + const core::stringc sourceSectionName = "source"; + const core::stringc arraySectionName = "array"; + const core::stringc floatArraySectionName ="float_array"; + const core::stringc intArraySectionName = "int_array"; + const core::stringc techniqueCommonSectionName = "technique_common"; + const core::stringc accessorSectionName = "accessor"; + const core::stringc verticesSectionName = "vertices"; + const core::stringc inputTagName = "input"; + const core::stringc polylistSectionName = "polylist"; + const core::stringc trianglesSectionName = "triangles"; + const core::stringc polygonsSectionName = "polygons"; + const core::stringc primitivesName = "p"; + const core::stringc vcountName = "vcount"; + + const core::stringc upAxisNodeName = "up_axis"; + const core::stringc nodeSectionName = "node"; + const core::stringc lookatNodeName = "lookat"; + const core::stringc matrixNodeName = "matrix"; + const core::stringc perspectiveNodeName = "perspective"; + const core::stringc rotateNodeName = "rotate"; + const core::stringc scaleNodeName = "scale"; + const core::stringc translateNodeName = "translate"; + const core::stringc skewNodeName = "skew"; + const core::stringc bboxNodeName = "boundingbox"; + const core::stringc minNodeName = "min"; + const core::stringc maxNodeName = "max"; + const core::stringc instanceName = "instance"; + const core::stringc instanceGeometryName = "instance_geometry"; + const core::stringc instanceSceneName = "instance_visual_scene"; + const core::stringc instanceEffectName = "instance_effect"; + const core::stringc instanceMaterialName = "instance_material"; + const core::stringc instanceLightName = "instance_light"; + const core::stringc instanceNodeName = "instance_node"; + const core::stringc bindMaterialName = "bind_material"; + const core::stringc extraNodeName = "extra"; + const core::stringc techniqueNodeName = "technique"; + const core::stringc colorNodeName = "color"; + const core::stringc floatNodeName = "float"; + const core::stringc float2NodeName = "float2"; + const core::stringc float3NodeName = "float3"; + + const core::stringc newParamName = "newparam"; + const core::stringc paramTagName = "param"; + const core::stringc initFromName = "init_from"; + const core::stringc dataName = "data"; + const core::stringc wrapsName = "wrap_s"; + const core::stringc wraptName = "wrap_t"; + const core::stringc minfilterName = "minfilter"; + const core::stringc magfilterName = "magfilter"; + const core::stringc mipfilterName = "mipfilter"; + + const core::stringc textureNodeName = "texture"; + const core::stringc doubleSidedNodeName = "double_sided"; + const core::stringc constantAttenuationNodeName = "constant_attenuation"; + const core::stringc linearAttenuationNodeName = "linear_attenuation"; + const core::stringc quadraticAttenuationNodeName = "quadratic_attenuation"; + const core::stringc falloffAngleNodeName = "falloff_angle"; + const core::stringc falloffExponentNodeName = "falloff_exponent"; + + const core::stringc profileCOMMONSectionName = "profile_COMMON"; + const core::stringc profileCOMMONAttributeName = "COMMON"; + + const char* const inputSemanticNames[] = {"POSITION", "VERTEX", "NORMAL", "TEXCOORD", + "UV", "TANGENT", "IMAGE", "TEXTURE", 0}; + + // We have to read ambient lights like other light types here, so we need a type for it + const video::E_LIGHT_TYPE ELT_AMBIENT = video::E_LIGHT_TYPE(video::ELT_COUNT+1); +} + + //! following class is for holding and creating instances of library + //! objects, named prefabs in this loader. + class CPrefab : public IColladaPrefab + { + public: + + CPrefab(const core::stringc& id) : Id(id) + { + } + + //! creates an instance of this prefab + virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent, + scene::ISceneManager* mgr) + { + // empty implementation + return 0; + } + + //! returns id of this prefab + virtual const core::stringc& getId() + { + return Id; + } + + protected: + + core::stringc Id; + }; + + + //! prefab for a light scene node + class CLightPrefab : public CPrefab + { + public: + + CLightPrefab(const core::stringc& id) : CPrefab(id) + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA: loaded light prefab", Id.c_str(), ELL_DEBUG); + #endif + } + + video::SLight LightData; // publically accessible + + //! creates an instance of this prefab + virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent, + scene::ISceneManager* mgr) + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA: Constructing light instance", Id.c_str(), ELL_DEBUG); + #endif + + if ( LightData.Type == ELT_AMBIENT ) + { + mgr->setAmbientLight( LightData.DiffuseColor ); + return 0; + } + + scene::ILightSceneNode* l = mgr->addLightSceneNode(parent); + if (l) + { + l->setLightData ( LightData ); + l->setName(getId()); + } + return l; + } + }; + + + //! prefab for a mesh scene node + class CGeometryPrefab : public CPrefab + { + public: + + CGeometryPrefab(const core::stringc& id) : CPrefab(id) + { + } + + scene::IMesh* Mesh; + + //! creates an instance of this prefab + virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent, + scene::ISceneManager* mgr) + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA: Constructing mesh instance", Id.c_str(), ELL_DEBUG); + #endif + + scene::ISceneNode* m = mgr->addMeshSceneNode(Mesh, parent); + if (m) + { + m->setName(getId()); +// m->setMaterialFlag(video::EMF_BACK_FACE_CULLING, false); +// m->setDebugDataVisible(scene::EDS_FULL); + } + return m; + } + }; + + + //! prefab for a camera scene node + class CCameraPrefab : public CPrefab + { + public: + + CCameraPrefab(const core::stringc& id) + : CPrefab(id), YFov(core::PI / 2.5f), ZNear(1.0f), ZFar(3000.0f) + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA: loaded camera prefab", Id.c_str(), ELL_DEBUG); + #endif + } + + // publicly accessible data + f32 YFov; + f32 ZNear; + f32 ZFar; + + //! creates an instance of this prefab + virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent, + scene::ISceneManager* mgr) + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA: Constructing camera instance", Id.c_str(), ELL_DEBUG); + #endif + + scene::ICameraSceneNode* c = mgr->addCameraSceneNode(parent); + if (c) + { + c->setFOV(YFov); + c->setNearValue(ZNear); + c->setFarValue(ZFar); + c->setName(getId()); + } + return c; + } + }; + + + //! prefab for a container scene node + //! Collects other prefabs and instantiates them upon instantiation + //! Uses a dummy scene node to return the children as one scene node + class CScenePrefab : public CPrefab + { + public: + CScenePrefab(const core::stringc& id) : CPrefab(id) + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA: loaded scene prefab", Id.c_str(), ELL_DEBUG); + #endif + } + + //! creates an instance of this prefab + virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent, + scene::ISceneManager* mgr) + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA: Constructing scene instance", Id.c_str(), ELL_DEBUG); + #endif + + if (Children.size()==0) + return 0; + + scene::IDummyTransformationSceneNode* s = mgr->addDummyTransformationSceneNode(parent); + if (s) + { + s->setName(getId()); + s->getRelativeTransformationMatrix() = Transformation; + s->updateAbsolutePosition(); + core::stringc t; + for (u32 i=0; i<16; ++i) + { + t+=core::stringc((double)Transformation[i]); + t+=" "; + } + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA: Transformation", t.c_str(), ELL_DEBUG); + #endif + + for (u32 i=0; iaddInstance(s, mgr); + } + + return s; + } + + core::array Children; + core::matrix4 Transformation; + }; + + +//! Constructor +CColladaFileLoader::CColladaFileLoader(scene::ISceneManager* smgr, + io::IFileSystem* fs) +: SceneManager(smgr), FileSystem(fs), DummyMesh(0), + FirstLoadedMesh(0), LoadedMeshCount(0), CreateInstances(false) +{ + #ifdef _DEBUG + setDebugName("CColladaFileLoader"); + #endif +} + + +//! destructor +CColladaFileLoader::~CColladaFileLoader() +{ + if (DummyMesh) + DummyMesh->drop(); + + if (FirstLoadedMesh) + FirstLoadedMesh->drop(); +} + + +//! Returns true if the file maybe is able to be loaded by this class. +/** This decision should be based only on the file extension (e.g. ".cob") */ +bool CColladaFileLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "xml", "dae" ); +} + + +//! creates/loads an animated mesh from the file. +//! \return Pointer to the created mesh. Returns 0 if loading failed. +//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). +//! See IReferenceCounted::drop() for more information. +IAnimatedMesh* CColladaFileLoader::createMesh(io::IReadFile* file) +{ + io::IXMLReaderUTF8* reader = FileSystem->createXMLReaderUTF8(file); + if (!reader) + return 0; + + CurrentlyLoadingMesh = file->getFileName(); + CreateInstances = SceneManager->getParameters()->getAttributeAsBool( + scene::COLLADA_CREATE_SCENE_INSTANCES); + Version = 0; + FlipAxis = false; + + // read until COLLADA section, skip other parts + + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (colladaSectionName == reader->getNodeName()) + readColladaSection(reader); + else + skipSection(reader, true); // unknown section + } + } + + reader->drop(); + if (!Version) + return 0; + + // because this loader loads and creates a complete scene instead of + // a single mesh, return an empty dummy mesh to make the scene manager + // know that everything went well. + if (!DummyMesh) + DummyMesh = new SAnimatedMesh(); + scene::IAnimatedMesh* returnMesh = DummyMesh; + + if (Version < 10400) + instantiateNode(SceneManager->getRootSceneNode()); + + // add the first loaded mesh into the mesh cache too, if more than one + // meshes have been loaded from the file + if (LoadedMeshCount>1 && FirstLoadedMesh) + { + os::Printer::log("Added COLLADA mesh", FirstLoadedMeshName.c_str()); + SceneManager->getMeshCache()->addMesh(FirstLoadedMeshName.c_str(), FirstLoadedMesh); + } + + // clean up temporary loaded data + clearData(); + + returnMesh->grab(); // store until this loader is destroyed + + DummyMesh->drop(); + DummyMesh = 0; + + if (FirstLoadedMesh) + FirstLoadedMesh->drop(); + FirstLoadedMesh = 0; + LoadedMeshCount = 0; + + return returnMesh; +} + + +//! skips an (unknown) section in the collada document +void CColladaFileLoader::skipSection(io::IXMLReaderUTF8* reader, bool reportSkipping) +{ + #ifndef COLLADA_READER_DEBUG + if (reportSkipping) // always report in COLLADA_READER_DEBUG mode + #endif + os::Printer::log("COLLADA skipping section", core::stringc(reader->getNodeName()).c_str(), ELL_DEBUG); + + // skip if this element is empty anyway. + if (reader->isEmptyElement()) + return; + + // read until we've reached the last element in this section + u32 tagCounter = 1; + + while(tagCounter && reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT && + !reader->isEmptyElement()) + { + #ifdef COLLADA_READER_DEBUG + if (reportSkipping) + os::Printer::log("Skipping COLLADA unknown element", core::stringc(reader->getNodeName()).c_str(), ELL_DEBUG); + #endif + + ++tagCounter; + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + --tagCounter; + } +} + + +//! reads the section and its content +void CColladaFileLoader::readColladaSection(io::IXMLReaderUTF8* reader) +{ + if (reader->isEmptyElement()) + return; + + // todo: patch level needs to be handled + const f32 version = core::fast_atof(core::stringc(reader->getAttributeValue("version")).c_str()); + Version = core::floor32(version)*10000+core::round32(core::fract(version)*1000.0f); + // Version 1.4 can be checked for by if (Version >= 10400) + + while(reader->read()) + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (assetSectionName == reader->getNodeName()) + readAssetSection(reader); + else + if (librarySectionName == reader->getNodeName()) + readLibrarySection(reader); + else + if (libraryNodesSectionName == reader->getNodeName()) + readLibrarySection(reader); + else + if (libraryGeometriesSectionName == reader->getNodeName()) + readLibrarySection(reader); + else + if (libraryMaterialsSectionName == reader->getNodeName()) + readLibrarySection(reader); + else + if (libraryEffectsSectionName == reader->getNodeName()) + readLibrarySection(reader); + else + if (libraryImagesSectionName == reader->getNodeName()) + readLibrarySection(reader); + else + if (libraryCamerasSectionName == reader->getNodeName()) + readLibrarySection(reader); + else + if (libraryLightsSectionName == reader->getNodeName()) + readLibrarySection(reader); + else + if (libraryVisualScenesSectionName == reader->getNodeName()) + readVisualScene(reader); + else + if (assetSectionName == reader->getNodeName()) + readAssetSection(reader); + else + if (sceneSectionName == reader->getNodeName()) + readSceneSection(reader); + else + { + os::Printer::log("COLLADA loader warning: Wrong tag usage found", reader->getNodeName(), ELL_WARNING); + skipSection(reader, true); // unknown section + } + } +} + + +//! reads a section and its content +void CColladaFileLoader::readLibrarySection(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading library", ELL_DEBUG); + #endif + + if (reader->isEmptyElement()) + return; + + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + // animation section tbd + if (cameraPrefabName == reader->getNodeName()) + readCameraPrefab(reader); + else + // code section tbd + // controller section tbd + if (geometrySectionName == reader->getNodeName()) + readGeometry(reader); + else + if (imageSectionName == reader->getNodeName()) + readImage(reader); + else + if (lightPrefabName == reader->getNodeName()) + readLightPrefab(reader); + else + if (materialSectionName == reader->getNodeName()) + readMaterial(reader); + else + if (nodeSectionName == reader->getNodeName()) + { + CScenePrefab p(""); + + readNodeSection(reader, SceneManager->getRootSceneNode(), &p); + } + else + if (effectSectionName == reader->getNodeName()) + readEffect(reader); + else + // program section tbd + if (textureSectionName == reader->getNodeName()) + readTexture(reader); + else + skipSection(reader, true); // unknown section, not all allowed supported yet + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + { + if (librarySectionName == reader->getNodeName()) + break; // end reading. + if (libraryNodesSectionName == reader->getNodeName()) + break; // end reading. + if (libraryGeometriesSectionName == reader->getNodeName()) + break; // end reading. + if (libraryMaterialsSectionName == reader->getNodeName()) + break; // end reading. + if (libraryEffectsSectionName == reader->getNodeName()) + break; // end reading. + if (libraryImagesSectionName == reader->getNodeName()) + break; // end reading. + if (libraryLightsSectionName == reader->getNodeName()) + break; // end reading. + if (libraryCamerasSectionName == reader->getNodeName()) + break; // end reading. + } + } +} + + +//! reads a element and stores it as a prefab +void CColladaFileLoader::readVisualScene(io::IXMLReaderUTF8* reader) +{ + CScenePrefab* p = 0; + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (visualSceneSectionName == reader->getNodeName()) + p = new CScenePrefab(readId(reader)); + else + if (p && nodeSectionName == reader->getNodeName()) // as a child of visual_scene + readNodeSection(reader, SceneManager->getRootSceneNode(), p); + else + if (assetSectionName == reader->getNodeName()) + readAssetSection(reader); + else + if (extraNodeName == reader->getNodeName()) + skipSection(reader, false); // ignore all other sections + else + { + os::Printer::log("COLLADA loader warning: Wrong tag usage found", reader->getNodeName(), ELL_WARNING); + skipSection(reader, true); // ignore all other sections + } + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + { + if (libraryVisualScenesSectionName == reader->getNodeName()) + return; + else + if ((visualSceneSectionName == reader->getNodeName()) && p) + { + Prefabs.push_back(p); + p = 0; + } + } + } +} + + +//! reads a section and its content +void CColladaFileLoader::readSceneSection(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading scene", ELL_DEBUG); + #endif + + if (reader->isEmptyElement()) + return; + + // read the scene + + core::matrix4 transform; // transformation of this node + core::aabbox3df bbox; + scene::IDummyTransformationSceneNode* node = 0; + + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (lookatNodeName == reader->getNodeName()) + transform *= readLookAtNode(reader); + else + if (matrixNodeName == reader->getNodeName()) + transform *= readMatrixNode(reader); + else + if (perspectiveNodeName == reader->getNodeName()) + transform *= readPerspectiveNode(reader); + else + if (rotateNodeName == reader->getNodeName()) + transform *= readRotateNode(reader); + else + if (scaleNodeName == reader->getNodeName()) + transform *= readScaleNode(reader); + else + if (skewNodeName == reader->getNodeName()) + transform *= readSkewNode(reader); + else + if (translateNodeName == reader->getNodeName()) + transform *= readTranslateNode(reader); + else + if (bboxNodeName == reader->getNodeName()) + readBboxNode(reader, bbox); + else + if (nodeSectionName == reader->getNodeName()) + { + // create dummy node if there is none yet. + if (!node) + node = SceneManager->addDummyTransformationSceneNode(SceneManager->getRootSceneNode()); + + readNodeSection(reader, node); + } + else + if ((instanceSceneName == reader->getNodeName())) + readInstanceNode(reader, SceneManager->getRootSceneNode(), 0, 0,instanceSceneName); + else + if (extraNodeName == reader->getNodeName()) + skipSection(reader, false); + else + { + os::Printer::log("COLLADA loader warning: Wrong tag usage found", reader->getNodeName(), ELL_WARNING); + skipSection(reader, true); // ignore all other sections + } + } + else + if ((reader->getNodeType() == io::EXN_ELEMENT_END) && + (sceneSectionName == reader->getNodeName())) + return; + } + if (node) + node->getRelativeTransformationMatrix() = transform; +} + + +//! reads a section and its content +void CColladaFileLoader::readAssetSection(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading asset", ELL_DEBUG); + #endif + + if (reader->isEmptyElement()) + return; + + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (upAxisNodeName == reader->getNodeName()) + { + reader->read(); + FlipAxis = (core::stringc("Z_UP") == reader->getNodeData()); + } + } + else + if ((reader->getNodeType() == io::EXN_ELEMENT_END) && + (assetSectionName == reader->getNodeName())) + return; + } +} + + +//! reads a section and its content +void CColladaFileLoader::readNodeSection(io::IXMLReaderUTF8* reader, scene::ISceneNode* parent, CScenePrefab* p) +{ + if (reader->isEmptyElement()) + { + return; + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading empty node", ELL_DEBUG); + #endif + } + + core::stringc name = readId(reader); + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading node", name, ELL_DEBUG); + #endif + + core::matrix4 transform; // transformation of this node + core::aabbox3df bbox; + scene::ISceneNode* node = 0; // instance + CScenePrefab* nodeprefab = 0; // prefab for library_nodes usage + + if (p) + { + nodeprefab = new CScenePrefab(readId(reader)); + p->Children.push_back(nodeprefab); + Prefabs.push_back(nodeprefab); // in order to delete them later on + } + + // read the node + + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (assetSectionName == reader->getNodeName()) + readAssetSection(reader); + else + if (lookatNodeName == reader->getNodeName()) + transform *= readLookAtNode(reader); + else + if (matrixNodeName == reader->getNodeName()) + transform *= readMatrixNode(reader); + else + if (perspectiveNodeName == reader->getNodeName()) + transform *= readPerspectiveNode(reader); + else + if (rotateNodeName == reader->getNodeName()) + transform *= readRotateNode(reader); + else + if (scaleNodeName == reader->getNodeName()) + transform *= readScaleNode(reader); + else + if (skewNodeName == reader->getNodeName()) + transform *= readSkewNode(reader); + else + if (translateNodeName == reader->getNodeName()) + transform *= readTranslateNode(reader); + else + if (bboxNodeName == reader->getNodeName()) + readBboxNode(reader, bbox); + else + if ((instanceName == reader->getNodeName()) || + (instanceNodeName == reader->getNodeName()) || + (instanceGeometryName == reader->getNodeName()) || + (instanceLightName == reader->getNodeName())) + { + scene::ISceneNode* newnode = 0; + readInstanceNode(reader, parent, &newnode, nodeprefab, reader->getNodeName()); + + if (node && newnode) + { + // move children from dummy to new node + ISceneNodeList::ConstIterator it = node->getChildren().begin(); + for (; it != node->getChildren().end(); it = node->getChildren().begin()) + (*it)->setParent(newnode); + + // remove previous dummy node + node->remove(); + node = newnode; + } + } + else + if (nodeSectionName == reader->getNodeName()) + { + // create dummy node if there is none yet. + if (CreateInstances && !node) + { + scene::IDummyTransformationSceneNode* dummy = + SceneManager->addDummyTransformationSceneNode(parent); + dummy->getRelativeTransformationMatrix() = transform; + node = dummy; + } + else + node = parent; + + // read and add child + readNodeSection(reader, node, nodeprefab); + } + else + if (extraNodeName == reader->getNodeName()) + skipSection(reader, false); + else + skipSection(reader, true); // ignore all other sections + + } // end if node + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + { + if (nodeSectionName == reader->getNodeName()) + break; + } + } + + if (nodeprefab) + nodeprefab->Transformation = transform; + else + if (node) + { + // set transformation correctly into node. + node->setPosition(transform.getTranslation()); + node->setRotation(transform.getRotationDegrees()); + node->setScale(transform.getScale()); + node->updateAbsolutePosition(); + + node->setName(name); + } +} + + +//! reads a element and its content and creates a matrix from it +core::matrix4 CColladaFileLoader::readLookAtNode(io::IXMLReaderUTF8* reader) +{ + core::matrix4 mat; + if (reader->isEmptyElement()) + return mat; + + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading look at node", ELL_DEBUG); + #endif + + f32 floats[9]; + readFloatsInsideElement(reader, floats, 9); + + mat.buildCameraLookAtMatrixLH( + core::vector3df(floats[0], floats[1], floats[2]), + core::vector3df(floats[3], floats[4], floats[5]), + core::vector3df(floats[6], floats[7], floats[8])); + + return mat; +} + + +//! reads a element and its content and creates a matrix from it +core::matrix4 CColladaFileLoader::readSkewNode(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading skew node", ELL_DEBUG); + #endif + + core::matrix4 mat; + if (reader->isEmptyElement()) + return mat; + + f32 floats[7]; // angle rotation-axis translation-axis + readFloatsInsideElement(reader, floats, 7); + + // build skew matrix from these 7 floats + core::quaternion q; + q.fromAngleAxis(floats[0]*core::DEGTORAD, core::vector3df(floats[1], floats[2], floats[3])); + mat = q.getMatrix(); + + if (floats[4]==1.f) // along x-axis + { + mat[4]=0.f; + mat[6]=0.f; + mat[8]=0.f; + mat[9]=0.f; + } + else + if (floats[5]==1.f) // along y-axis + { + mat[1]=0.f; + mat[2]=0.f; + mat[8]=0.f; + mat[9]=0.f; + } + else + if (floats[6]==1.f) // along z-axis + { + mat[1]=0.f; + mat[2]=0.f; + mat[4]=0.f; + mat[6]=0.f; + } + + return mat; +} + + +//! reads a element and its content and stores it in bbox +void CColladaFileLoader::readBboxNode(io::IXMLReaderUTF8* reader, + core::aabbox3df& bbox) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading boundingbox node", ELL_DEBUG); + #endif + + bbox.reset(core::aabbox3df()); + + if (reader->isEmptyElement()) + return; + + f32 floats[3]; + + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (minNodeName == reader->getNodeName()) + { + readFloatsInsideElement(reader, floats, 3); + bbox.MinEdge.set(floats[0], floats[1], floats[2]); + } + else + if (maxNodeName == reader->getNodeName()) + { + readFloatsInsideElement(reader, floats, 3); + bbox.MaxEdge.set(floats[0], floats[1], floats[2]); + } + else + skipSection(reader, true); // ignore all other sections + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + { + if (bboxNodeName == reader->getNodeName()) + break; + } + } +} + + +//! reads a element and its content and creates a matrix from it +core::matrix4 CColladaFileLoader::readMatrixNode(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading matrix node", ELL_DEBUG); + #endif + + core::matrix4 mat; + if (reader->isEmptyElement()) + return mat; + + readFloatsInsideElement(reader, mat.pointer(), 16); + // put translation into the correct place + if (FlipAxis) + { + core::matrix4 mat2(mat, core::matrix4::EM4CONST_TRANSPOSED); + mat2[1]=mat[8]; + mat2[2]=mat[4]; + mat2[4]=mat[2]; + mat2[5]=mat[10]; + mat2[6]=mat[6]; + mat2[8]=mat[1]; + mat2[9]=mat[9]; + mat2[10]=mat[5]; + mat2[12]=mat[3]; + mat2[13]=mat[11]; + mat2[14]=mat[7]; + return mat2; + } + else + return core::matrix4(mat, core::matrix4::EM4CONST_TRANSPOSED); +} + + +//! reads a element and its content and creates a matrix from it +core::matrix4 CColladaFileLoader::readPerspectiveNode(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading perspective node", ELL_DEBUG); + #endif + + core::matrix4 mat; + if (reader->isEmptyElement()) + return mat; + + f32 floats[1]; + readFloatsInsideElement(reader, floats, 1); + + // TODO: build perspecitve matrix from this float + + os::Printer::log("COLLADA loader warning: not implemented yet.", ELL_WARNING); + + return mat; +} + + +//! reads a element and its content and creates a matrix from it +core::matrix4 CColladaFileLoader::readRotateNode(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading rotate node", ELL_DEBUG); + #endif + + core::matrix4 mat; + if (reader->isEmptyElement()) + return mat; + + f32 floats[4]; + readFloatsInsideElement(reader, floats, 4); + + if (!core::iszero(floats[3])) + { + core::quaternion q; + if (FlipAxis) + q.fromAngleAxis(floats[3]*core::DEGTORAD, core::vector3df(floats[0], floats[2], floats[1])); + else + q.fromAngleAxis(floats[3]*core::DEGTORAD, core::vector3df(floats[0], floats[1], floats[2])); + return q.getMatrix(); + } + else + return core::IdentityMatrix; +} + + +//! reads a element and its content and creates a matrix from it +core::matrix4 CColladaFileLoader::readScaleNode(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading scale node", ELL_DEBUG); + #endif + + core::matrix4 mat; + if (reader->isEmptyElement()) + return mat; + + f32 floats[3]; + readFloatsInsideElement(reader, floats, 3); + + if (FlipAxis) + mat.setScale(core::vector3df(floats[0], floats[2], floats[1])); + else + mat.setScale(core::vector3df(floats[0], floats[1], floats[2])); + + return mat; +} + + +//! reads a element and its content and creates a matrix from it +core::matrix4 CColladaFileLoader::readTranslateNode(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading translate node", ELL_DEBUG); + #endif + + core::matrix4 mat; + if (reader->isEmptyElement()) + return mat; + + f32 floats[3]; + readFloatsInsideElement(reader, floats, 3); + + if (FlipAxis) + mat.setTranslation(core::vector3df(floats[0], floats[2], floats[1])); + else + mat.setTranslation(core::vector3df(floats[0], floats[1], floats[2])); + + return mat; +} + + +//! reads any kind of node +void CColladaFileLoader::readInstanceNode(io::IXMLReaderUTF8* reader, + scene::ISceneNode* parent, scene::ISceneNode** outNode, + CScenePrefab* p, const core::stringc& type) +{ + // find prefab of the specified id + core::stringc url = reader->getAttributeValue("url"); + uriToId(url); + + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading instance", url, ELL_DEBUG); + #endif + + if (!reader->isEmptyElement()) + { + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (bindMaterialName == reader->getNodeName()) + readBindMaterialSection(reader,url); + else + if (extraNodeName == reader->getNodeName()) + skipSection(reader, false); + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + break; + } + } + instantiateNode(parent, outNode, p, url, type); +} + + +void CColladaFileLoader::instantiateNode(scene::ISceneNode* parent, + scene::ISceneNode** outNode, CScenePrefab* p, const core::stringc& url, + const core::stringc& type) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA instantiate node", ELL_DEBUG); + #endif + + for (u32 i=0; igetId()) + { + if (p) + p->Children.push_back(Prefabs[i]); + else + if (CreateInstances) + { + scene::ISceneNode * newNode + = Prefabs[i]->addInstance(parent, SceneManager); + if (outNode) + { + *outNode = newNode; + if (*outNode) + (*outNode)->setName(url); + } + } + return; + } + } + if (p) + { + if (instanceGeometryName==type) + { + Prefabs.push_back(new CGeometryPrefab(url)); + p->Children.push_back(Prefabs.getLast()); + } + } +} + + +//! reads a element and stores it as prefab +void CColladaFileLoader::readCameraPrefab(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading camera prefab", ELL_DEBUG); + #endif + + CCameraPrefab* prefab = new CCameraPrefab(readId(reader)); + + if (!reader->isEmptyElement()) + { + // read techniques optics and imager (the latter is completely ignored, though) + readColladaParameters(reader, cameraPrefabName); + + SColladaParam* p; + + // XFOV not yet supported + p = getColladaParameter(ECPN_YFOV); + if (p && p->Type == ECPT_FLOAT) + prefab->YFov = p->Floats[0]; + + p = getColladaParameter(ECPN_ZNEAR); + if (p && p->Type == ECPT_FLOAT) + prefab->ZNear = p->Floats[0]; + + p = getColladaParameter(ECPN_ZFAR); + if (p && p->Type == ECPT_FLOAT) + prefab->ZFar = p->Floats[0]; + // orthographic camera uses LEFT, RIGHT, TOP, and BOTTOM + } + + Prefabs.push_back(prefab); +} + + +//! reads a element and stores it in the image section +void CColladaFileLoader::readImage(io::IXMLReaderUTF8* reader) +{ + // add image to list of loaded images. + Images.push_back(SColladaImage()); + SColladaImage& image=Images.getLast(); + + image.Id = readId(reader); + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading image", core::stringc(image.Id), ELL_DEBUG); + #endif + image.Dimension.Height = (u32)reader->getAttributeValueAsInt("height"); + image.Dimension.Width = (u32)reader->getAttributeValueAsInt("width"); + + if (Version >= 10400) // start with 1.4 + { + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (assetSectionName == reader->getNodeName()) + skipSection(reader, false); + else + if (initFromName == reader->getNodeName()) + { + reader->read(); + image.Source = reader->getNodeData(); + image.Source.trim(); + image.SourceIsFilename=true; + } + else + if (dataName == reader->getNodeName()) + { + reader->read(); + image.Source = reader->getNodeData(); + image.Source.trim(); + image.SourceIsFilename=false; + } + else + if (extraNodeName == reader->getNodeName()) + skipSection(reader, false); + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + { + if (initFromName == reader->getNodeName()) + return; + } + } + } + else + { + image.Source = reader->getAttributeValue("source"); + image.Source.trim(); + image.SourceIsFilename=false; + } +} + + +//! reads a element and stores it in the texture section +void CColladaFileLoader::readTexture(io::IXMLReaderUTF8* reader) +{ + // add texture to list of loaded textures. + Textures.push_back(SColladaTexture()); + SColladaTexture& texture=Textures.getLast(); + + texture.Id = readId(reader); + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading texture", core::stringc(texture.Id), ELL_DEBUG); + #endif + + if (!reader->isEmptyElement()) + { + readColladaInputs(reader, textureSectionName); + SColladaInput* input = getColladaInput(ECIS_IMAGE); + if (input) + { + const core::stringc imageName = input->Source; + texture.Texture = getTextureFromImage(imageName, NULL); + } + } +} + + +//! reads a element and stores it in the material section +void CColladaFileLoader::readMaterial(io::IXMLReaderUTF8* reader) +{ + // add material to list of loaded materials. + Materials.push_back(SColladaMaterial()); + + SColladaMaterial& material = Materials.getLast(); + material.Id = readId(reader); + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading material", core::stringc(material.Id), ELL_DEBUG); + #endif + + if (Version >= 10400) + { + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT && + instanceEffectName == reader->getNodeName()) + { + material.InstanceEffectId = reader->getAttributeValue("url"); + uriToId(material.InstanceEffectId); + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END && + materialSectionName == reader->getNodeName()) + { + break; + } + } // end while reader->read(); + } + else + { + if (!reader->isEmptyElement()) + { + readColladaInputs(reader, materialSectionName); + SColladaInput* input = getColladaInput(ECIS_TEXTURE); + if (input) + { + core::stringc textureName = input->Source; + uriToId(textureName); + for (u32 i=0; iType == ECPT_FLOAT3) + material.Mat.AmbientColor = video::SColorf(p->Floats[0],p->Floats[1],p->Floats[2]).toSColor(); + p = getColladaParameter(ECPN_DIFFUSE); + if (p && p->Type == ECPT_FLOAT3) + material.Mat.DiffuseColor = video::SColorf(p->Floats[0],p->Floats[1],p->Floats[2]).toSColor(); + p = getColladaParameter(ECPN_SPECULAR); + if (p && p->Type == ECPT_FLOAT3) + material.Mat.DiffuseColor = video::SColorf(p->Floats[0],p->Floats[1],p->Floats[2]).toSColor(); + p = getColladaParameter(ECPN_SHININESS); + if (p && p->Type == ECPT_FLOAT) + material.Mat.Shininess = p->Floats[0]; +#endif + } + } +} + +void CColladaFileLoader::readEffect(io::IXMLReaderUTF8* reader, SColladaEffect * effect) +{ + static const core::stringc constantNode("constant"); + static const core::stringc lambertNode("lambert"); + static const core::stringc phongNode("phong"); + static const core::stringc blinnNode("blinn"); + static const core::stringc emissionNode("emission"); + static const core::stringc ambientNode("ambient"); + static const core::stringc diffuseNode("diffuse"); + static const core::stringc specularNode("specular"); + static const core::stringc shininessNode("shininess"); + static const core::stringc reflectiveNode("reflective"); + static const core::stringc reflectivityNode("reflectivity"); + static const core::stringc transparentNode("transparent"); + static const core::stringc transparencyNode("transparency"); + static const core::stringc indexOfRefractionNode("index_of_refraction"); + + if (!effect) + { + Effects.push_back(SColladaEffect()); + effect = &Effects.getLast(); + effect->Parameters = new io::CAttributes(); + effect->Id = readId(reader); + effect->Transparency = 1.f; + effect->Mat.Lighting=true; + effect->Mat.NormalizeNormals=true; + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading effect", core::stringc(effect->Id), ELL_DEBUG); + #endif + } + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + // first come the tags we descend, but ignore the top-levels + if (!reader->isEmptyElement() && ((profileCOMMONSectionName == reader->getNodeName()) || + (techniqueNodeName == reader->getNodeName()))) + readEffect(reader,effect); + else + if (newParamName == reader->getNodeName()) + readParameter(reader, effect->Parameters); + else + // these are the actual materials inside technique + if (constantNode == reader->getNodeName() || + lambertNode == reader->getNodeName() || + phongNode == reader->getNodeName() || + blinnNode == reader->getNodeName()) + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading effect part", reader->getNodeName(), ELL_DEBUG); + #endif + effect->Mat.setFlag(irr::video::EMF_GOURAUD_SHADING, + phongNode == reader->getNodeName() || + blinnNode == reader->getNodeName()); + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + const core::stringc node = reader->getNodeName(); + if (emissionNode == node || ambientNode == node || + diffuseNode == node || specularNode == node || + reflectiveNode == node || transparentNode == node ) + { + // color or texture types + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT && + colorNodeName == reader->getNodeName()) + { + const video::SColorf colorf = readColorNode(reader); + const video::SColor color = colorf.toSColor(); + if (emissionNode == node) + effect->Mat.EmissiveColor = color; + else + if (ambientNode == node) + effect->Mat.AmbientColor = color; + else + if (diffuseNode == node) + effect->Mat.DiffuseColor = color; + else + if (specularNode == node) + effect->Mat.SpecularColor = color; + else + if (transparentNode == node) + effect->Transparency = colorf.getAlpha(); + } + else + if (reader->getNodeType() == io::EXN_ELEMENT && + textureNodeName == reader->getNodeName()) + { + effect->Textures.push_back(reader->getAttributeValue("texture")); + break; + } + else + if (reader->getNodeType() == io::EXN_ELEMENT) + skipSection(reader, false); + else + if (reader->getNodeType() == io::EXN_ELEMENT_END && + node == reader->getNodeName()) + break; + } + } + else + if (shininessNode == node || reflectivityNode == node || + transparencyNode == node || indexOfRefractionNode == node ) + { + // float or param types + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT && + floatNodeName == reader->getNodeName()) + { + f32 f = readFloatNode(reader); + if (shininessNode == node) + effect->Mat.Shininess = f; + else + if (transparencyNode == node) + effect->Transparency *= f; + } + else + if (reader->getNodeType() == io::EXN_ELEMENT) + skipSection(reader, false); + else + if (reader->getNodeType() == io::EXN_ELEMENT_END && + node == reader->getNodeName()) + break; + } + } + else + skipSection(reader, true); // ignore all other nodes + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END && ( + constantNode == reader->getNodeName() || + lambertNode == reader->getNodeName() || + phongNode == reader->getNodeName() || + blinnNode == reader->getNodeName() + )) + break; + } + } + else + if (!reader->isEmptyElement() && (extraNodeName == reader->getNodeName())) + readEffect(reader,effect); + else + if (doubleSidedNodeName == reader->getNodeName()) + { + // read the GoogleEarth extra flag for double sided polys + s32 doubleSided = 0; + readIntsInsideElement(reader,&doubleSided,1); + if (doubleSided) + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("Setting double sided flag for effect.", ELL_DEBUG); + #endif + + effect->Mat.setFlag(irr::video::EMF_BACK_FACE_CULLING,false); + } + } + else + skipSection(reader, true); // ignore all other sections + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + { + if (effectSectionName == reader->getNodeName()) + break; + else + if (profileCOMMONSectionName == reader->getNodeName()) + break; + else + if (techniqueNodeName == reader->getNodeName()) + break; + else + if (extraNodeName == reader->getNodeName()) + break; + } + } + + if (effect->Mat.AmbientColor == video::SColor(0) && + effect->Mat.DiffuseColor != video::SColor(0)) + effect->Mat.AmbientColor = effect->Mat.DiffuseColor; + if (effect->Mat.DiffuseColor == video::SColor(0) && + effect->Mat.AmbientColor != video::SColor(0)) + effect->Mat.DiffuseColor = effect->Mat.AmbientColor; + if ((effect->Transparency != 0.0f) && (effect->Transparency != 1.0f)) + { + effect->Mat.MaterialType = irr::video::EMT_TRANSPARENT_VERTEX_ALPHA; + effect->Mat.ZWriteEnable = false; + } + + video::E_TEXTURE_CLAMP twu = video::ETC_REPEAT; + s32 idx = effect->Parameters->findAttribute(wrapsName.c_str()); + if ( idx >= 0 ) + twu = (video::E_TEXTURE_CLAMP)(effect->Parameters->getAttributeAsInt(idx)); + video::E_TEXTURE_CLAMP twv = video::ETC_REPEAT; + idx = effect->Parameters->findAttribute(wraptName.c_str()); + if ( idx >= 0 ) + twv = (video::E_TEXTURE_CLAMP)(effect->Parameters->getAttributeAsInt(idx)); + + for (u32 i=0; iMat.TextureLayer[i].TextureWrapU = twu; + effect->Mat.TextureLayer[i].TextureWrapV = twv; + } + + effect->Mat.setFlag(video::EMF_BILINEAR_FILTER, effect->Parameters->getAttributeAsBool("bilinear")); + effect->Mat.setFlag(video::EMF_TRILINEAR_FILTER, effect->Parameters->getAttributeAsBool("trilinear")); + effect->Mat.setFlag(video::EMF_ANISOTROPIC_FILTER, effect->Parameters->getAttributeAsBool("anisotropic")); +} + + +const SColladaMaterial* CColladaFileLoader::findMaterial(const core::stringc& materialName) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA find material", materialName, ELL_DEBUG); + #endif + + // do a quick lookup in the materials + SColladaMaterial matToFind; + matToFind.Id = materialName; + s32 mat = Materials.binary_search(matToFind); + if (mat == -1) + return 0; + // instantiate the material effect if needed + if (Materials[mat].InstanceEffectId.size() != 0) + { + // do a quick lookup in the effects + SColladaEffect effectToFind; + effectToFind.Id = Materials[mat].InstanceEffectId; + s32 effect = Effects.binary_search(effectToFind); + if (effect != -1) + { + // found the effect, instantiate by copying into the material + Materials[mat].Mat = Effects[effect].Mat; + if (Effects[effect].Textures.size()) + Materials[mat].Mat.setTexture(0, getTextureFromImage(Effects[effect].Textures[0], &(Effects[effect]))); + Materials[mat].Transparency = Effects[effect].Transparency; + // and indicate the material is instantiated by removing the effect ref + Materials[mat].InstanceEffectId = ""; + } + else + return 0; + } + return &Materials[mat]; +} + + +void CColladaFileLoader::readBindMaterialSection(io::IXMLReaderUTF8* reader, const core::stringc & id) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading bind material", ELL_DEBUG); + #endif + + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (instanceMaterialName == reader->getNodeName()) + { + // the symbol to retarget, and the target material + core::stringc meshbufferReference = reader->getAttributeValue("symbol"); + if (meshbufferReference.size()==0) + continue; + core::stringc target = reader->getAttributeValue("target"); + uriToId(target); + if (target.size()==0) + continue; + const SColladaMaterial * material = findMaterial(target); + if (!material) + continue; + // bind any pending materials for this node + meshbufferReference = id+"/"+meshbufferReference; +#ifdef COLLADA_READER_DEBUG + os::Printer::log((core::stringc("Material binding: ")+meshbufferReference+" "+target).c_str(), ELL_DEBUG); +#endif + if (MaterialsToBind.find(meshbufferReference)) + { + core::array & toBind + = MeshesToBind[MaterialsToBind[meshbufferReference]]; +#ifdef COLLADA_READER_DEBUG + os::Printer::log("Material binding now ",material->Id.c_str(), ELL_DEBUG); + os::Printer::log("#meshbuffers",core::stringc(toBind.size()).c_str(), ELL_DEBUG); +#endif + SMesh tmpmesh; + for (u32 i = 0; i < toBind.size(); ++i) + { + toBind[i]->getMaterial() = material->Mat; + tmpmesh.addMeshBuffer(toBind[i]); + + if ((material->Transparency!=0.0f) && (material->Transparency!=1.0f)) + { + toBind[i]->getMaterial().MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; + toBind[i]->getMaterial().ZWriteEnable = false; + } + } + SceneManager->getMeshManipulator()->setVertexColors(&tmpmesh,material->Mat.DiffuseColor); + if ((material->Transparency!=0.0f) && (material->Transparency!=1.0f)) + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA found transparency material", core::stringc(material->Transparency).c_str(), ELL_DEBUG); + #endif + SceneManager->getMeshManipulator()->setVertexColorAlpha(&tmpmesh, core::floor32(material->Transparency*255.0f)); + } + } + } + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END && + bindMaterialName == reader->getNodeName()) + break; + } +} + + +//! reads a element and stores it as mesh if possible +void CColladaFileLoader::readGeometry(io::IXMLReaderUTF8* reader) +{ + core::stringc id = readId(reader); + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading geometry", id, ELL_DEBUG); + #endif + + SAnimatedMesh* amesh = new SAnimatedMesh(); + scene::SMesh* mesh = new SMesh(); + amesh->addMesh(mesh); + core::array sources; + bool okToReadArray = false; + + // handles geometry node and the mesh children in this loop + // read sources with arrays and accessor for each mesh + if (!reader->isEmptyElement()) + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + const char* nodeName = reader->getNodeName(); + if (meshSectionName == nodeName) + { + // inside a mesh section. Don't have to do anything here. + } + else + if (sourceSectionName == nodeName) + { + // create a new source + sources.push_back(SSource()); + sources.getLast().Id = readId(reader); + + #ifdef COLLADA_READER_DEBUG + os::Printer::log("Reading source", sources.getLast().Id.c_str(), ELL_DEBUG); + #endif + } + else + if (arraySectionName == nodeName || floatArraySectionName == nodeName || intArraySectionName == nodeName) + { + // create a new array and read it. + if (!sources.empty()) + { + sources.getLast().Array.Name = readId(reader); + + int count = reader->getAttributeValueAsInt("count"); + sources.getLast().Array.Data.set_used(count); // pre allocate + + // check if type of array is ok + const char* type = reader->getAttributeValue("type"); + okToReadArray = (type && (!strcmp("float", type) || !strcmp("int", type))) || floatArraySectionName == nodeName || intArraySectionName == nodeName; + + #ifdef COLLADA_READER_DEBUG + os::Printer::log("Read array", sources.getLast().Array.Name.c_str(), ELL_DEBUG); + #endif + } + #ifdef COLLADA_READER_DEBUG + else + os::Printer::log("Warning, array outside source found", + readId(reader).c_str(), ELL_DEBUG); + #endif + + } + else + if (accessorSectionName == nodeName) // child of source (below a technique tag) + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("Reading accessor", ELL_DEBUG); + #endif + SAccessor accessor; + accessor.Count = reader->getAttributeValueAsInt("count"); + accessor.Offset = reader->getAttributeValueAsInt("offset"); + accessor.Stride = reader->getAttributeValueAsInt("stride"); + if (accessor.Stride == 0) + accessor.Stride = 1; + + // the accessor contains some information on how to access (boi!) the array, + // the info is stored in collada style parameters, so just read them. + readColladaParameters(reader, accessorSectionName); + if (!sources.empty()) + { + sources.getLast().Accessors.push_back(accessor); + sources.getLast().Accessors.getLast().Parameters = ColladaParameters; + } + } + else + if (verticesSectionName == nodeName) + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("Reading vertices", ELL_DEBUG); + #endif + // read vertex input position source + readColladaInputs(reader, verticesSectionName); + } + else + // lines and linestrips missing + if (polygonsSectionName == nodeName || + polylistSectionName == nodeName || + trianglesSectionName == nodeName) + { + // read polygons section + readPolygonSection(reader, sources, mesh, id); + } + else + // trifans, and tristrips missing + if (doubleSidedNodeName == reader->getNodeName()) + { + // read the extra flag for double sided polys + s32 doubleSided = 0; + readIntsInsideElement(reader,&doubleSided,1); + if (doubleSided) + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("Setting double sided flag for mesh.", ELL_DEBUG); + #endif + amesh->setMaterialFlag(irr::video::EMF_BACK_FACE_CULLING,false); + } + } + else + // techniqueCommon or 'technique profile=common' must not be skipped + if ((techniqueCommonSectionName != nodeName) // Collada 1.2/1.3 + && (techniqueNodeName != nodeName) // Collada 1.4+ + && (extraNodeName != nodeName)) + { + os::Printer::log("COLLADA loader warning: Wrong tag usage found in geometry", reader->getNodeName(), ELL_WARNING); + skipSection(reader, true); // ignore all other sections + } + } // end if node type is element + else + if (reader->getNodeType() == io::EXN_TEXT) + { + // read array data + if (okToReadArray && !sources.empty()) + { + core::array& a = sources.getLast().Array.Data; + core::stringc data = reader->getNodeData(); + data.trim(); + const c8* p = &data[0]; + + for (u32 i=0; igetNodeType() == io::EXN_ELEMENT_END) + { + if (geometrySectionName == reader->getNodeName()) + { + // end of geometry section reached, cancel out + break; + } + } + } // end while reader->read(); + + // add mesh as geometry + + mesh->recalculateBoundingBox(); + amesh->recalculateBoundingBox(); + + // create virtual file name + io::path filename = CurrentlyLoadingMesh; + filename += '#'; + filename += id; + + // add to scene manager + if (LoadedMeshCount) + { + SceneManager->getMeshCache()->addMesh(filename.c_str(), amesh); + os::Printer::log("Added COLLADA mesh", filename.c_str(), ELL_DEBUG); + } + else + { + FirstLoadedMeshName = filename; + FirstLoadedMesh = amesh; + FirstLoadedMesh->grab(); + } + + ++LoadedMeshCount; + mesh->drop(); + amesh->drop(); + + // create geometry prefab + u32 i; + for (i=0; igetId()==id) + { + ((CGeometryPrefab*)Prefabs[i])->Mesh=mesh; + break; + } + } + if (i==Prefabs.size()) + { + CGeometryPrefab* prefab = new CGeometryPrefab(id); + prefab->Mesh = mesh; + Prefabs.push_back(prefab); + } + + // store as dummy mesh if no instances will be created + if (!CreateInstances && !DummyMesh) + { + DummyMesh = amesh; + DummyMesh->grab(); + } +} + + +struct SPolygon +{ + core::array Indices; +}; + +//! reads a polygons section and creates a mesh from it +void CColladaFileLoader::readPolygonSection(io::IXMLReaderUTF8* reader, + core::array& sources, scene::SMesh* mesh, + const core::stringc& geometryId) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading polygon section", ELL_DEBUG); + #endif + + core::stringc materialName = reader->getAttributeValue("material"); + + core::stringc polygonType = reader->getNodeName(); + const int polygonCount = reader->getAttributeValueAsInt("count"); // Not useful because it only determines the number of primitives, which have arbitrary vertices in case of polygon + core::array polygons; + if (polygonType == polygonsSectionName) + polygons.reallocate(polygonCount); + core::array vCounts; + bool parsePolygonOK = false; + bool parseVcountOK = false; + u32 inputSemanticCount = 0; + bool unresolvedInput=false; + u32 maxOffset = 0; + core::array localInputs; + + // read all and primitives + if (!reader->isEmptyElement()) + while(reader->read()) + { + const char* nodeName = reader->getNodeName(); + + if (reader->getNodeType() == io::EXN_ELEMENT) + { + // polygon node may contain params + if (inputTagName == nodeName) + { + // read input tag + readColladaInput(reader, localInputs); + + // resolve input source + SColladaInput& inp = localInputs.getLast(); + + // get input source array id, if it is a vertex input, take + // the -source attribute. + if (inp.Semantic == ECIS_VERTEX) + { + inp.Source = Inputs[0].Source; + for (u32 i=1; igetNodeType() == io::EXN_ELEMENT_END) + { + if (primitivesName == nodeName) + parsePolygonOK = false; // end parsing a polygon + else + if (vcountName == nodeName) + parseVcountOK = false; // end parsing vcounts + else + if (polygonType == nodeName) + break; // cancel out and create mesh + + } // end is element end + else + if (reader->getNodeType() == io::EXN_TEXT) + { + if (parseVcountOK) + { + core::stringc data = reader->getNodeData(); + data.trim(); + const c8* p = &data[0]; + while(*p) + { + findNextNoneWhiteSpace(&p); + if (*p) + vCounts.push_back(readInt(&p)); + } + parseVcountOK = false; + } + else + if (parsePolygonOK && polygons.size()) + { + core::stringc data = reader->getNodeData(); + data.trim(); + const c8* p = &data[0]; + SPolygon& poly = polygons.getLast(); + if (polygonType == polygonsSectionName) + poly.Indices.reallocate((maxOffset+1)*3); + else + poly.Indices.reallocate(polygonCount*(maxOffset+1)*3); + + if (vCounts.empty()) + { + while(*p) + { + findNextNoneWhiteSpace(&p); + poly.Indices.push_back(readInt(&p)); + } + } + else + { + for (u32 i = 0; i < vCounts.size(); i++) + { + const int polyVCount = vCounts[i]; + core::array polyCorners; + + for (u32 j = 0; j < polyVCount * inputSemanticCount; j++) + { + if (!*p) + break; + findNextNoneWhiteSpace(&p); + polyCorners.push_back(readInt(&p)); + } + + while (polyCorners.size() >= 3 * inputSemanticCount) + { + // add one triangle's worth of indices + for (u32 k = 0; k < inputSemanticCount * 3; ++k) + { + poly.Indices.push_back(polyCorners[k]); + } + + // remove one corner from our poly + polyCorners.erase(inputSemanticCount,inputSemanticCount); + } + polyCorners.clear(); + } + vCounts.clear(); + } + parsePolygonOK = false; + } + } + } // end while reader->read() + + // find source array (we'll ignore accessors for this implementation) + for (u32 i=0; i vertMap; + + for (u32 i=0; i indices; + const u32 vertexCount = polygons[i].Indices.size() / maxOffset; + mbuffer->Vertices.reallocate(mbuffer->Vertices.size()+vertexCount); + + // for all index/semantic groups + for (u32 v=0; v::Node* n = vertMap.find(vtx); + if (n) + { + indices.push_back(n->getValue()); + } + else + { + indices.push_back(mbuffer->getVertexCount()); + mbuffer->Vertices.push_back(vtx); + vertMap.insert(vtx, mbuffer->getVertexCount()-1); + } + } // end for all vertices + + if (polygonsSectionName == polygonType && + indices.size() > 3) + { + // need to tesselate for polygons of 4 or more vertices + // for now we naively turn interpret it as a triangle fan + // as full tesselation is problematic + if (FlipAxis) + { + for (u32 ind = indices.size()-3; ind>0 ; --ind) + { + mbuffer->Indices.push_back(indices[0]); + mbuffer->Indices.push_back(indices[ind+2]); + mbuffer->Indices.push_back(indices[ind+1]); + } + } + else + { + for (u32 ind = 0; ind+2 < indices.size(); ++ind) + { + mbuffer->Indices.push_back(indices[0]); + mbuffer->Indices.push_back(indices[ind+1]); + mbuffer->Indices.push_back(indices[ind+2]); + } + } + } + else + { + // it's just triangles + for (u32 ind = 0; ind < indices.size(); ind+=3) + { + if (FlipAxis) + { + mbuffer->Indices.push_back(indices[ind+2]); + mbuffer->Indices.push_back(indices[ind+1]); + mbuffer->Indices.push_back(indices[ind+0]); + } + else + { + mbuffer->Indices.push_back(indices[ind+0]); + mbuffer->Indices.push_back(indices[ind+1]); + mbuffer->Indices.push_back(indices[ind+2]); + } + } + } + + } // end for all polygons + } + else + { + // lightmap mesh buffer + + scene::SMeshBufferLightMap* mbuffer = new SMeshBufferLightMap(); + buffer = mbuffer; + + for (u32 i=0; iVertices.reallocate(mbuffer->Vertices.size()+vertexCount); + // for all vertices in array + for (u32 v=0; vVertices.push_back(vtx); + + } // end for all vertices + + // add vertex indices + const u32 oldVertexCount = mbuffer->Vertices.size() - vertexCount; + for (u32 face=0; faceIndices.push_back(oldVertexCount + 0); + mbuffer->Indices.push_back(oldVertexCount + 1 + face); + mbuffer->Indices.push_back(oldVertexCount + 2 + face); + } + + } // end for all polygons + } + + const SColladaMaterial* m = findMaterial(materialName); + if (m) + { + buffer->getMaterial() = m->Mat; + SMesh tmpmesh; + tmpmesh.addMeshBuffer(buffer); + SceneManager->getMeshManipulator()->setVertexColors(&tmpmesh,m->Mat.DiffuseColor); + if (m->Transparency != 1.0f) + SceneManager->getMeshManipulator()->setVertexColorAlpha(&tmpmesh,core::floor32(m->Transparency*255.0f)); + } + // add future bind reference for the material + core::stringc meshbufferReference = geometryId+"/"+materialName; + if (!MaterialsToBind.find(meshbufferReference)) + { + MaterialsToBind[meshbufferReference] = MeshesToBind.size(); + MeshesToBind.push_back(core::array()); + } + MeshesToBind[MaterialsToBind[meshbufferReference]].push_back(buffer); + + // calculate normals if there is no slot for it + + if (!normalSlotCount) + SceneManager->getMeshManipulator()->recalculateNormals(buffer, true); + + // recalculate bounding box + buffer->recalculateBoundingBox(); + + // add mesh buffer + mesh->addMeshBuffer(buffer); + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA added meshbuffer", core::stringc(buffer->getVertexCount())+" vertices, "+core::stringc(buffer->getIndexCount())+" indices.", ELL_DEBUG); + #endif + + buffer->drop(); +} + + +//! reads a element and stores it as prefab +void CColladaFileLoader::readLightPrefab(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading light prefab", ELL_DEBUG); + #endif + + CLightPrefab* prefab = new CLightPrefab(readId(reader)); + + if (!reader->isEmptyElement()) + { + if (Version >= 10400) // start with 1.4 + { + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (pointSectionName == reader->getNodeName()) + prefab->LightData.Type=video::ELT_POINT; + else + if (directionalSectionName == reader->getNodeName()) + prefab->LightData.Type=video::ELT_DIRECTIONAL; + else + if (spotSectionName == reader->getNodeName()) + prefab->LightData.Type=video::ELT_SPOT; + else + if (ambientSectionName == reader->getNodeName()) + prefab->LightData.Type=ELT_AMBIENT; + else + if (colorNodeName == reader->getNodeName()) + prefab->LightData.DiffuseColor=readColorNode(reader); + else + if (constantAttenuationNodeName == reader->getNodeName()) + readFloatsInsideElement(reader,&prefab->LightData.Attenuation.X,1); + else + if (linearAttenuationNodeName == reader->getNodeName()) + readFloatsInsideElement(reader,&prefab->LightData.Attenuation.Y,1); + else + if (quadraticAttenuationNodeName == reader->getNodeName()) + readFloatsInsideElement(reader,&prefab->LightData.Attenuation.Z,1); + else + if (falloffAngleNodeName == reader->getNodeName()) + { + readFloatsInsideElement(reader,&prefab->LightData.OuterCone,1); + prefab->LightData.OuterCone *= core::DEGTORAD; + } + else + if (falloffExponentNodeName == reader->getNodeName()) + readFloatsInsideElement(reader,&prefab->LightData.Falloff,1); + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + { + if ((pointSectionName == reader->getNodeName()) || + (directionalSectionName == reader->getNodeName()) || + (spotSectionName == reader->getNodeName()) || + (ambientSectionName == reader->getNodeName())) + break; + } + } + } + else + { + readColladaParameters(reader, lightPrefabName); + + SColladaParam* p = getColladaParameter(ECPN_COLOR); + if (p && p->Type == ECPT_FLOAT3) + prefab->LightData.DiffuseColor.set(p->Floats[0], p->Floats[1], p->Floats[2]); + } + } + + Prefabs.push_back(prefab); +} + + +//! returns a collada parameter or none if not found +SColladaParam* CColladaFileLoader::getColladaParameter(ECOLLADA_PARAM_NAME name) +{ + for (u32 i=0; i& inputs) +{ + // parse param + SColladaInput p; + + // get type + core::stringc semanticName = reader->getAttributeValue("semantic"); + for (u32 i=0; inputSemanticNames[i]; ++i) + { + if (semanticName == inputSemanticNames[i]) + { + p.Semantic = (ECOLLADA_INPUT_SEMANTIC)i; + break; + } + } + + // get source + p.Source = reader->getAttributeValue("source"); + if (reader->getAttributeValue("offset")) // Collada 1.4+ + p.Offset = (u32)reader->getAttributeValueAsInt("offset"); + else // Collada 1.2/1.3 + p.Offset = (u32)reader->getAttributeValueAsInt("idx"); + p.Set = (u32)reader->getAttributeValueAsInt("set"); + + // add input + inputs.push_back(p); +} + +//! parses all collada inputs inside an element and stores them in Inputs +void CColladaFileLoader::readColladaInputs(io::IXMLReaderUTF8* reader, const core::stringc& parentName) +{ + Inputs.clear(); + + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT && + inputTagName == reader->getNodeName()) + { + readColladaInput(reader, Inputs); + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + { + if (parentName == reader->getNodeName()) + return; // end of parent reached + } + + } // end while reader->read(); +} + +//! parses all collada parameters inside an element and stores them in ColladaParameters +void CColladaFileLoader::readColladaParameters(io::IXMLReaderUTF8* reader, + const core::stringc& parentName) +{ + ColladaParameters.clear(); + + const char* const paramNames[] = {"COLOR", "AMBIENT", "DIFFUSE", + "SPECULAR", "SHININESS", "YFOV", "ZNEAR", "ZFAR", 0}; + + const char* const typeNames[] = {"float", "float2", "float3", 0}; + + while(reader->read()) + { + const char* nodeName = reader->getNodeName(); + if (reader->getNodeType() == io::EXN_ELEMENT && + paramTagName == nodeName) + { + // parse param + SColladaParam p; + + // get type + u32 i; + core::stringc typeName = reader->getAttributeValue("type"); + for (i=0; typeNames[i]; ++i) + if (typeName == typeNames[i]) + { + p.Type = (ECOLLADA_PARAM_TYPE)i; + break; + } + + // get name + core::stringc nameName = reader->getAttributeValue("name"); + for (i=0; typeNames[i]; ++i) + if (nameName == paramNames[i]) + { + p.Name = (ECOLLADA_PARAM_NAME)i; + break; + } + + // read parameter data inside parameter tags + switch(p.Type) + { + case ECPT_FLOAT: + case ECPT_FLOAT2: + case ECPT_FLOAT3: + case ECPT_FLOAT4: + readFloatsInsideElement(reader, p.Floats, p.Type - ECPT_FLOAT + 1); + break; + + // TODO: other types of data (ints, bools or whatever) + default: + break; + } + + // add param + ColladaParameters.push_back(p); + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + { + if (parentName == reader->getNodeName()) + return; // end of parent reached + } + + } // end while reader->read(); +} + + +//! parses a float from a char pointer and moves the pointer +//! to the end of the parsed float +inline f32 CColladaFileLoader::readFloat(const c8** p) +{ + f32 ftmp; + *p = core::fast_atof_move(*p, ftmp); + return ftmp; +} + + +//! parses an int from a char pointer and moves the pointer to +//! the end of the parsed float +inline s32 CColladaFileLoader::readInt(const c8** p) +{ + return (s32)readFloat(p); +} + + +//! places pointer to next begin of a token +void CColladaFileLoader::findNextNoneWhiteSpace(const c8** start) +{ + const c8* p = *start; + + while(*p && (*p==' ' || *p=='\n' || *p=='\r' || *p=='\t')) + ++p; + + // TODO: skip comments + + *start = p; +} + + +//! reads floats from inside of xml element until end of xml element +void CColladaFileLoader::readFloatsInsideElement(io::IXMLReaderUTF8* reader, f32* floats, u32 count) +{ + if (reader->isEmptyElement()) + return; + + while(reader->read()) + { + // TODO: check for comments inside the element + // and ignore them. + + if (reader->getNodeType() == io::EXN_TEXT) + { + // parse float data + core::stringc data = reader->getNodeData(); + data.trim(); + const c8* p = &data[0]; + + for (u32 i=0; igetNodeType() == io::EXN_ELEMENT_END) + break; // end parsing text + } +} + + +//! reads ints from inside of xml element until end of xml element +void CColladaFileLoader::readIntsInsideElement(io::IXMLReaderUTF8* reader, s32* ints, u32 count) +{ + if (reader->isEmptyElement()) + return; + + while(reader->read()) + { + // TODO: check for comments inside the element + // and ignore them. + + if (reader->getNodeType() == io::EXN_TEXT) + { + // parse float data + core::stringc data = reader->getNodeData(); + data.trim(); + const c8* p = &data[0]; + + for (u32 i=0; igetNodeType() == io::EXN_ELEMENT_END) + break; // end parsing text + } +} + + +video::SColorf CColladaFileLoader::readColorNode(io::IXMLReaderUTF8* reader) +{ + if (reader->getNodeType() == io::EXN_ELEMENT && + colorNodeName == reader->getNodeName()) + { + f32 color[4]; + readFloatsInsideElement(reader,color,4); + return video::SColorf(color[0], color[1], color[2], color[3]); + } + + return video::SColorf(); +} + + +f32 CColladaFileLoader::readFloatNode(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading ", ELL_DEBUG); + #endif + + f32 result = 0.0f; + if (reader->getNodeType() == io::EXN_ELEMENT && + floatNodeName == reader->getNodeName()) + { + readFloatsInsideElement(reader,&result,1); + } + + return result; +} + + +//! clears all loaded data +void CColladaFileLoader::clearData() +{ + // delete all prefabs + + for (u32 i=0; idrop(); + + Prefabs.clear(); + + // clear all parameters + ColladaParameters.clear(); + + // clear all materials + Images.clear(); + + // clear all materials + Textures.clear(); + + // clear all materials + Materials.clear(); + + // clear all inputs + Inputs.clear(); + + // clear all effects + for ( u32 i=0; idrop(); + Effects.clear(); + + // clear all the materials to bind + MaterialsToBind.clear(); + MeshesToBind.clear(); +} + + +//! changes the XML URI into an internal id +void CColladaFileLoader::uriToId(core::stringc& str) +{ + // currently, we only remove the # from the begin if there + // because we simply don't support referencing other files. + if (!str.size()) + return; + + if (str[0] == '#') + str.erase(0); +} + + +//! read Collada Id, uses id or name if id is missing +core::stringc CColladaFileLoader::readId(io::IXMLReaderUTF8* reader) +{ + core::stringc id = reader->getAttributeValue("id"); + if (id.size()==0) + id = reader->getAttributeValue("name"); + return id; +} + + +//! create an Irrlicht texture from the reference +video::ITexture* CColladaFileLoader::getTextureFromImage(core::stringc uri, SColladaEffect * effect) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA searching texture", uri, ELL_DEBUG); + #endif + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + for (;;) + { + uriToId(uri); + for (u32 i=0; iexistFile(Images[i].Source)) + return driver->getTexture(Images[i].Source); + return driver->getTexture((FileSystem->getFileDir(CurrentlyLoadingMesh)+"/"+Images[i].Source)); + } + else + if (Images[i].Source.size()) + { + //const u32 size = Images[i].Dimension.getArea(); + const u32 size = Images[i].Dimension.Width * Images[i].Dimension.Height;; + u32* data = new u32[size]; // we assume RGBA + u32* ptrdest = data; + const c8* ptrsrc = Images[i].Source.c_str(); + for (u32 j=0; jcreateImageFromData(video::ECF_A8R8G8B8, Images[i].Dimension, data, true, true); + video::ITexture* tex = driver->addTexture((CurrentlyLoadingMesh+"#"+Images[i].Id).c_str(), img); + img->drop(); + return tex; + } + break; + } + } + if (effect && effect->Parameters->getAttributeType(uri.c_str())==io::EAT_STRING) + { + uri = effect->Parameters->getAttributeAsString(uri.c_str()); +#ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA now searching texture", uri.c_str(), ELL_DEBUG); +#endif + } + else + break; + } + return 0; +} + + +//! read a parameter and value +void CColladaFileLoader::readParameter(io::IXMLReaderUTF8* reader, io::IAttributes* parameters) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading parameter", ELL_DEBUG); + #endif + + if ( !parameters ) + return; + + const core::stringc name = reader->getAttributeValue("sid"); + if (!reader->isEmptyElement()) + { + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (floatNodeName == reader->getNodeName()) + { + const f32 f = readFloatNode(reader); + parameters->addFloat(name.c_str(), f); + } + else + if (float2NodeName == reader->getNodeName()) + { + f32 f[2]; + readFloatsInsideElement(reader, f, 2); +// Parameters.addVector2d(name.c_str(), core::vector2df(f[0],f[1])); + } + else + if (float3NodeName == reader->getNodeName()) + { + f32 f[3]; + readFloatsInsideElement(reader, f, 3); + parameters->addVector3d(name.c_str(), core::vector3df(f[0],f[1],f[2])); + } + else + if ((initFromName == reader->getNodeName()) || + (sourceSectionName == reader->getNodeName())) + { + reader->read(); + parameters->addString(name.c_str(), reader->getNodeData()); + } + else + if (wrapsName == reader->getNodeName()) + { + reader->read(); + const core::stringc val = reader->getNodeData(); + if (val == "WRAP") + parameters->addInt(wrapsName.c_str(), (int)video::ETC_REPEAT); + else if ( val== "MIRROR") + parameters->addInt(wrapsName.c_str(), (int)video::ETC_MIRROR); + else if ( val== "CLAMP") + parameters->addInt(wrapsName.c_str(), (int)video::ETC_CLAMP_TO_EDGE); + else if ( val== "BORDER") + parameters->addInt(wrapsName.c_str(), (int)video::ETC_CLAMP_TO_BORDER); + else if ( val== "NONE") + parameters->addInt(wrapsName.c_str(), (int)video::ETC_CLAMP_TO_BORDER); + } + else + if (wraptName == reader->getNodeName()) + { + reader->read(); + const core::stringc val = reader->getNodeData(); + if (val == "WRAP") + parameters->addInt(wraptName.c_str(), (int)video::ETC_REPEAT); + else if ( val== "MIRROR") + parameters->addInt(wraptName.c_str(), (int)video::ETC_MIRROR); + else if ( val== "CLAMP") + parameters->addInt(wraptName.c_str(), (int)video::ETC_CLAMP_TO_EDGE); + else if ( val== "BORDER") + parameters->addInt(wraptName.c_str(), (int)video::ETC_CLAMP_TO_BORDER); + else if ( val== "NONE") + parameters->addInt(wraptName.c_str(), (int)video::ETC_CLAMP_TO_BORDER); + } + else + if (minfilterName == reader->getNodeName()) + { + reader->read(); + const core::stringc val = reader->getNodeData(); + if (val == "LINEAR_MIPMAP_LINEAR") + parameters->addBool("trilinear", true); + else + if (val == "LINEAR_MIPMAP_NEAREST") + parameters->addBool("bilinear", true); + } + else + if (magfilterName == reader->getNodeName()) + { + reader->read(); + const core::stringc val = reader->getNodeData(); + if (val != "LINEAR") + { + parameters->addBool("bilinear", false); + parameters->addBool("trilinear", false); + } + } + else + if (mipfilterName == reader->getNodeName()) + { + parameters->addBool("anisotropic", true); + } + } + else + if(reader->getNodeType() == io::EXN_ELEMENT_END) + { + if (newParamName == reader->getNodeName()) + break; + } + } + } +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_COLLADA_LOADER_ + -- cgit v1.1