From 3274951f2a43e8670cf47a25e16bd9770c9ebda8 Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Thu, 29 Sep 2016 18:50:24 +0300 Subject: [PATCH 1/6] [+] X3D importer. --- code/CMakeLists.txt | 16 + code/ImporterRegistry.cpp | 6 + code/X3DImporter.cpp | 1560 ++++++++++++++++++++++++++++++ code/X3DImporter.hpp | 954 ++++++++++++++++++ code/X3DImporter_Geometry2D.cpp | 481 +++++++++ code/X3DImporter_Geometry3D.cpp | 947 ++++++++++++++++++ code/X3DImporter_Group.cpp | 269 ++++++ code/X3DImporter_Light.cpp | 251 +++++ code/X3DImporter_Macro.hpp | 154 +++ code/X3DImporter_Metadata.cpp | 236 +++++ code/X3DImporter_Networking.cpp | 69 ++ code/X3DImporter_Node.hpp | 761 +++++++++++++++ code/X3DImporter_Postprocess.cpp | 772 +++++++++++++++ code/X3DImporter_Rendering.cpp | 937 ++++++++++++++++++ code/X3DImporter_Shape.cpp | 209 ++++ code/X3DImporter_Texturing.cpp | 156 +++ 16 files changed, 7778 insertions(+) create mode 100644 code/X3DImporter.cpp create mode 100644 code/X3DImporter.hpp create mode 100644 code/X3DImporter_Geometry2D.cpp create mode 100644 code/X3DImporter_Geometry3D.cpp create mode 100644 code/X3DImporter_Group.cpp create mode 100644 code/X3DImporter_Light.cpp create mode 100644 code/X3DImporter_Macro.hpp create mode 100644 code/X3DImporter_Metadata.cpp create mode 100644 code/X3DImporter_Networking.cpp create mode 100644 code/X3DImporter_Node.hpp create mode 100644 code/X3DImporter_Postprocess.cpp create mode 100644 code/X3DImporter_Rendering.cpp create mode 100644 code/X3DImporter_Shape.cpp create mode 100644 code/X3DImporter_Texturing.cpp diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 32d4914a1..545cf7ed4 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -610,6 +610,22 @@ ADD_ASSIMP_IMPORTER( X XFileExporter.cpp ) +ADD_ASSIMP_IMPORTER(X3D + X3DImporter.cpp + X3DImporter.hpp + X3DImporter_Geometry2D.cpp + X3DImporter_Geometry3D.cpp + X3DImporter_Group.cpp + X3DImporter_Light.cpp + X3DImporter_Metadata.cpp + X3DImporter_Networking.cpp + X3DImporter_Node.hpp + X3DImporter_Postprocess.cpp + X3DImporter_Rendering.cpp + X3DImporter_Shape.cpp + X3DImporter_Texturing.cpp +) + ADD_ASSIMP_IMPORTER( GLTF glTFAsset.h glTFAsset.inl diff --git a/code/ImporterRegistry.cpp b/code/ImporterRegistry.cpp index af56f0674..95a1867e0 100644 --- a/code/ImporterRegistry.cpp +++ b/code/ImporterRegistry.cpp @@ -185,6 +185,9 @@ corresponding preprocessor flag to selectively disable formats. #ifndef ASSIMP_BUILD_NO_3MF_IMPORTER # include "D3MFImporter.h" #endif +#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER +# include "X3DImporter.hpp" +#endif namespace Assimp { @@ -331,6 +334,9 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out) #if ( !defined ASSIMP_BUILD_NO_3MF_IMPORTER ) out.push_back(new D3MFImporter() ); #endif +#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER + out.push_back( new X3DImporter() ); +#endif } /** will delete all registered importers. */ diff --git a/code/X3DImporter.cpp b/code/X3DImporter.cpp new file mode 100644 index 000000000..ab0b23dec --- /dev/null +++ b/code/X3DImporter.cpp @@ -0,0 +1,1560 @@ +/// \file X3DImporter.hpp +/// \brief X3D-format files importer for Assimp: main algorithm implementation. +/// \date 2015-2016 +/// \author nevorek@gmail.com + +#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER + +#include "X3DImporter.hpp" +#include "X3DImporter_Macro.hpp" + +#include "fast_atof.h" +#include "DefaultIOSystem.h" + +#include +#include +#include + +namespace Assimp +{ + +/// \var aiImporterDesc X3DImporter::Description +/// Conastant which hold importer description +const aiImporterDesc X3DImporter::Description = { + "Extensible 3D(X3D) Importer", + "nevorek", + "", + "See documentation in source code. Chapter: Limitations.", + aiImporterFlags_SupportTextFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental, + 0, + 0, + 0, + 0, + "x3d" +}; + +void X3DImporter::Clear() +{ + // Delete all elements + if(NodeElement_List.size()) + { + for(std::list::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); it++) delete *it; + + NodeElement_List.clear(); + } +} + +X3DImporter::~X3DImporter() +{ + if(mReader != NULL) delete mReader; + // Clear() is accounting if data already is deleted. So, just check again if all data is deleted. + Clear(); +} + +/*********************************************************************************************************************************************/ +/************************************************************ Functions: find set ************************************************************/ +/*********************************************************************************************************************************************/ + +bool X3DImporter::FindNodeElement_FromRoot(const std::string& pID, const CX3DImporter_NodeElement::EType pType, CX3DImporter_NodeElement** pElement) +{ + for(std::list::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); it++) + { + if(((*it)->Type == pType) && ((*it)->ID == pID)) + { + if(pElement != NULL) *pElement = *it; + + return true; + } + }// for(std::list::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); it++) + + return false; +} + +bool X3DImporter::FindNodeElement_FromNode(CX3DImporter_NodeElement* pStartNode, const std::string& pID, + const CX3DImporter_NodeElement::EType pType, CX3DImporter_NodeElement** pElement) +{ +bool found = false;// flag: true - if requested element is found. + + // Check if pStartNode - this is the element, we are looking for. + if((pStartNode->Type == pType) && (pStartNode->ID == pID)) + { + found = true; + if(pElement != NULL) *pElement = pStartNode; + + goto fne_fn_end; + }// if((pStartNode->Type() == pType) && (pStartNode->ID() == pID)) + + // Check childs of pStartNode. + for(std::list::iterator ch_it = pStartNode->Child.begin(); ch_it != pStartNode->Child.end(); ch_it++) + { + found = FindNodeElement_FromNode(*ch_it, pID, pType, pElement); + if(found) break; + }// for(std::list::iterator ch_it = it->Child.begin(); ch_it != it->Child.end(); ch_it++) + +fne_fn_end: + + return found; +} + +bool X3DImporter::FindNodeElement(const std::string& pID, const CX3DImporter_NodeElement::EType pType, CX3DImporter_NodeElement** pElement) +{ +CX3DImporter_NodeElement* tnd = NodeElement_Cur;// temporary pointer to node. +bool static_search = false;// flag: true if searching in static node. + + // At first check if we have deal with static node. Go up thru parent nodes and check flag. + while(tnd != NULL) + { + if(tnd->Type == CX3DImporter_NodeElement::ENET_Group) + { + if(((CX3DImporter_NodeElement_Group*)tnd)->Static) + { + static_search = true;// Flag found, stop walking up. Node with static flag will holded in tnd variable. + + break; + } + } + + tnd = tnd->Parent;// go up in graph. + }// while(tnd != NULL) + + // at now call appropriate search function. + if(static_search) + return FindNodeElement_FromNode(tnd, pID, pType, pElement); + else + return FindNodeElement_FromRoot(pID, pType, pElement); +} + +/*********************************************************************************************************************************************/ +/************************************************************ Functions: throw set ***********************************************************/ +/*********************************************************************************************************************************************/ + +void X3DImporter::Throw_ArgOutOfRange(const std::string& pArgument) +{ + throw DeadlyImportError("Argument value is out of range for: \"" + pArgument + "\"."); +} + +void X3DImporter::Throw_CloseNotFound(const std::string& pNode) +{ + throw DeadlyImportError("Close tag for node <" + pNode + "> not found. Seems file is corrupt."); +} + +void X3DImporter::Throw_ConvertFail_Str2ArrF(const std::string& pAttrValue) +{ + throw DeadlyImportError(boost::str(boost::format("In <%s> failed to convert attribute value \"%s\" from string to array of floats.") % + mReader->getNodeName() % pAttrValue)); +} + +void X3DImporter::Throw_DEF_And_USE() +{ + throw DeadlyImportError(boost::str(boost::format("\"DEF\" and \"USE\" can not be defined both in <%s>.") % mReader->getNodeName())); +} + +void X3DImporter::Throw_IncorrectAttr(const std::string& pAttrName) +{ + throw DeadlyImportError(boost::str(boost::format("Node <%s> has incorrect attribute \"%s\".") % mReader->getNodeName() % pAttrName)); +} + +void X3DImporter::Throw_IncorrectAttrValue(const std::string& pAttrName) +{ + throw DeadlyImportError(boost::str(boost::format("Attribute \"%s\" in node <%s> has incorrect value.") % pAttrName % mReader->getNodeName())); +} + +void X3DImporter::Throw_MoreThanOnceDefined(const std::string& pNodeType, const std::string& pDescription) +{ + throw DeadlyImportError("\"" + pNodeType + "\" node can be used only once in " + mReader->getNodeName() + ". Description: " + pDescription); +} + +void X3DImporter::Throw_TagCountIncorrect(const std::string& pNode) +{ + throw DeadlyImportError("Count of open and close tags for node <" + pNode + "> are not equivalent. Seems file is corrupt."); +} + +void X3DImporter::Throw_USE_NotFound(const std::string& pAttrValue) +{ + throw DeadlyImportError(boost::str(boost::format("Not found node with name \"%s\" in <%s>.") % pAttrValue % mReader->getNodeName())); +} + +/*********************************************************************************************************************************************/ +/************************************************************* Functions: XML set ************************************************************/ +/*********************************************************************************************************************************************/ + +void X3DImporter::XML_CheckNode_MustBeEmpty() +{ + if(!mReader->isEmptyElement()) throw DeadlyImportError(std::string("Node <") + mReader->getNodeName() + "> must be empty."); +} + +void X3DImporter::XML_CheckNode_SkipUnsupported(const std::string& pParentNodeName) +{ +const size_t Uns_Skip_Len = 189; +const char* Uns_Skip[Uns_Skip_Len] = { + // CAD geometry component + "CADAssembly", "CADFace", "CADLayer", "CADPart", "IndexedQuadSet", "QuadSet", + // Core + "ROUTE", "ExternProtoDeclare", "ProtoDeclare", "ProtoInstance", "ProtoInterface", "WorldInfo", + // Distributed interactive simulation (DIS) component + "DISEntityManager", "DISEntityTypeMapping", "EspduTransform", "ReceiverPdu", "SignalPdu", "TransmitterPdu", + // Cube map environmental texturing component + "ComposedCubeMapTexture", "GeneratedCubeMapTexture", "ImageCubeMapTexture", + // Environmental effects component + "Background", "Fog", "FogCoordinate", "LocalFog", "TextureBackground", + // Environmental sensor component + "ProximitySensor", "TransformSensor", "VisibilitySensor", + // Followers component + "ColorChaser", "ColorDamper", "CoordinateChaser", "CoordinateDamper", "OrientationChaser", "OrientationDamper", "PositionChaser", "PositionChaser2D", + "PositionDamper", "PositionDamper2D", "ScalarChaser", "ScalarDamper", "TexCoordChaser2D", "TexCoordDamper2D", + // Geospatial component + "GeoCoordinate", "GeoElevationGrid", "GeoLocation", "GeoLOD", "GeoMetadata", "GeoOrigin", "GeoPositionInterpolator", "GeoProximitySensor", + "GeoTouchSensor", "GeoTransform", "GeoViewpoint", + // Humanoid Animation (H-Anim) component + "HAnimDisplacer", "HAnimHumanoid", "HAnimJoint", "HAnimSegment", "HAnimSite", + // Interpolation component + "ColorInterpolator", "CoordinateInterpolator", "CoordinateInterpolator2D", "EaseInEaseOut", "NormalInterpolator", "OrientationInterpolator", + "PositionInterpolator", "PositionInterpolator2D", "ScalarInterpolator", "SplinePositionInterpolator", "SplinePositionInterpolator2D", + "SplineScalarInterpolator", "SquadOrientationInterpolator", + // Key device sensor component + "KeySensor", "StringSensor" + // Layering component + "Layer", "LayerSet", "Viewport", + // Layout component + "Layout", "LayoutGroup", "LayoutLayer", "ScreenFontStyle", "ScreenGroup", + // Navigation component + "Billboard", "Collision", "LOD", "NavigationInfo", "OrthoViewpoint", "Viewpoint", "ViewpointGroup", + // Networking component + "Anchor", "LoadSensor", + // NURBS component + "Contour2D", "ContourPolyline2D", "CoordinateDouble", "NurbsCurve", "NurbsCurve2D", "NurbsOrientationInterpolator", "NurbsPatchSurface", + "NurbsPositionInterpolator", "NurbsSet", "NurbsSurfaceInterpolator", "NurbsSweptSurface", "NurbsSwungSurface", "NurbsTextureCoordinate", + "NurbsTrimmedSurface", + // Particle systems component + "BoundedPhysicsModel", "ConeEmitter", "ExplosionEmitter", "ForcePhysicsModel", "ParticleSystem", "PointEmitter", "PolylineEmitter", "SurfaceEmitter", + "VolumeEmitter", "WindPhysicsModel", + // Picking component + "LinePickSensor", "PickableGroup", "PointPickSensor", "PrimitivePickSensor", "VolumePickSensor", + // Pointing device sensor component + "CylinderSensor", "PlaneSensor", "SphereSensor", "TouchSensor", + // Rendering component + "ClipPlane", + // Rigid body physics + "BallJoint", "CollidableOffset", "CollidableShape", "CollisionCollection", "CollisionSensor", "CollisionSpace", "Contact", "DoubleAxisHingeJoint", + "MotorJoint", "RigidBody", "RigidBodyCollection", "SingleAxisHingeJoint", "SliderJoint", "UniversalJoint", + // Scripting component + "Script", + // Programmable shaders component + "ComposedShader", "FloatVertexAttribute", "Matrix3VertexAttribute", "Matrix4VertexAttribute", "PackagedShader", "ProgramShader", "ShaderPart", + "ShaderProgram", + // Shape component + "FillProperties", "LineProperties", "TwoSidedMaterial", + // Sound component + "AudioClip", "Sound", + // Text component + "FontStyle", "Text", + // Texturing3D Component + "ComposedTexture3D", "ImageTexture3D", "PixelTexture3D", "TextureCoordinate3D", "TextureCoordinate4D", "TextureTransformMatrix3D", "TextureTransform3D", + // Texturing component + "MovieTexture", "MultiTexture", "MultiTextureCoordinate", "MultiTextureTransform", "PixelTexture", "TextureCoordinateGenerator", "TextureProperties", + // Time component + "TimeSensor", + // Event Utilities component + "BooleanFilter", "BooleanSequencer", "BooleanToggle", "BooleanTrigger", "IntegerSequencer", "IntegerTrigger", "TimeTrigger", + // Volume rendering component + "BlendedVolumeStyle", "BoundaryEnhancementVolumeStyle", "CartoonVolumeStyle", "ComposedVolumeStyle", "EdgeEnhancementVolumeStyle", "IsoSurfaceVolumeData", + "OpacityMapVolumeStyle", "ProjectionVolumeStyle", "SegmentedVolumeData", "ShadedVolumeStyle", "SilhouetteEnhancementVolumeStyle", "ToneMappedVolumeStyle", + "VolumeData" +}; + +std::string nn(mReader->getNodeName()); +bool found = false; +bool close_found = false; + + for(size_t i = 0; i < Uns_Skip_Len; i++) + { + if(nn == Uns_Skip[i]) + { + found = true; + if(mReader->isEmptyElement()) + { + close_found = true; + + goto casu_cres; + } + + while(mReader->read()) + { + if((mReader->getNodeType() == irr::io::EXN_ELEMENT_END) && (nn == mReader->getNodeName())) + { + close_found = true; + + goto casu_cres; + } + } + } + } + +casu_cres: + + if(!found) throw DeadlyImportError(boost::str(boost::format("Unknown node \"%s\" in %s.") % nn % pParentNodeName)); + + if(close_found) + LogInfo(boost::str(boost::format("Skipping node \"%s\" in %s.") % nn % pParentNodeName)); + else + Throw_CloseNotFound(nn); +} + +bool X3DImporter::XML_SearchNode(const std::string& pNodeName) +{ + while(mReader->read()) + { + if((mReader->getNodeType() == irr::io::EXN_ELEMENT) && XML_CheckNode_NameEqual(pNodeName)) return true; + } + + return false; +} + +bool X3DImporter::XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx) +{ +std::string val(mReader->getAttributeValue(pAttrIdx)); + + if(val == "false") + return false; + else if(val == "true") + return true; + else + throw DeadlyImportError("Bool attribute value can contain \"false\" or \"true\" not the \"" + val + "\""); +} + +float X3DImporter::XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx) +{ +std::string val; +float tvalf; + + ParseHelper_FixTruncatedFloatString(mReader->getAttributeValue(pAttrIdx), val); + fast_atoreal_move(val.c_str(), tvalf, false); + + return tvalf; +} + +int32_t X3DImporter::XML_ReadNode_GetAttrVal_AsI32(const int pAttrIdx) +{ + return strtol10(mReader->getAttributeValue(pAttrIdx)); +} + +void X3DImporter::XML_ReadNode_GetAttrVal_AsCol3f(const int pAttrIdx, aiColor3D& pValue) +{ +std::list tlist; +std::list::iterator it; + + XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist); + if(tlist.size() != 3) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx)); + + it = tlist.begin(); + pValue.r = *it++; + pValue.g = *it++; + pValue.b = *it; +} + +void X3DImporter::XML_ReadNode_GetAttrVal_AsVec2f(const int pAttrIdx, aiVector2D& pValue) +{ +std::list tlist; +std::list::iterator it; + + XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist); + if(tlist.size() != 2) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx)); + + it = tlist.begin(); + pValue.x = *it++; + pValue.y = *it; +} + +void X3DImporter::XML_ReadNode_GetAttrVal_AsVec3f(const int pAttrIdx, aiVector3D& pValue) +{ +std::list tlist; +std::list::iterator it; + + XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist); + if(tlist.size() != 3) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx)); + + it = tlist.begin(); + pValue.x = *it++; + pValue.y = *it++; + pValue.z = *it; +} + +void X3DImporter::XML_ReadNode_GetAttrVal_AsListB(const int pAttrIdx, std::list& pValue) +{ +char* tok_str; +size_t tok_str_len; + + // make copy of attribute value - string with list of bool values. Also all bool values is strings. + tok_str_len = strlen(mReader->getAttributeValue(pAttrIdx)); + if(!tok_str_len) Throw_IncorrectAttrValue(mReader->getAttributeName(pAttrIdx)); + + tok_str_len++;// take in account terminating '\0'. + tok_str = new char[tok_str_len]; + + strcpy(tok_str, mReader->getAttributeValue(pAttrIdx)); + // change all spacebars to symbol '\0'. That is needed for parsing. + for(size_t i = 0; i < tok_str_len; i++) + { + if(tok_str[i] == ' ') tok_str[i] = 0; + } + + // at now check what current token is + for(char *tok_cur = tok_str, *tok_end = (tok_str + tok_str_len); tok_cur < tok_end;) + { + if(strncmp(tok_cur, "true", 4) == 0) + { + pValue.push_back(true); + tok_cur += 5;// five, not four. Because '\0' must be skipped too. + } + else if(strncmp(tok_cur, "false", 5) == 0) + { + pValue.push_back(true); + tok_cur += 6;// six, not five. Because '\0' must be skipped too. + } + else + { + Throw_IncorrectAttrValue(mReader->getAttributeName(pAttrIdx)); + } + }// for(char* tok_cur = tok_str, tok_end = (tok_str + tok_str_len); tok_cur < tok_end;) + + // delete temporary string + delete [] tok_str; +} + +void X3DImporter::XML_ReadNode_GetAttrVal_AsArrB(const int pAttrIdx, std::vector& pValue) +{ +std::list tlist; + + XML_ReadNode_GetAttrVal_AsListB(pAttrIdx, tlist);// read as list + // and copy to array + if(tlist.size() > 0) + { + pValue.reserve(tlist.size()); + for(std::list::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it); + } +} + +void X3DImporter::XML_ReadNode_GetAttrVal_AsListI32(const int pAttrIdx, std::list& pValue) +{ +const char* tstr = mReader->getAttributeValue(pAttrIdx); +const char* tstr_end = tstr + strlen(tstr); + + do + { + int32_t tval32; + const char* ostr; + + tval32 = strtol10(tstr, &ostr); + if(ostr == tstr) break; + + while((ostr < tstr_end) && (*ostr == ' ')) ostr++;// skip spaces between values. + + tstr = ostr; + pValue.push_back(tval32); + } while(tstr < tstr_end); +} + +void X3DImporter::XML_ReadNode_GetAttrVal_AsArrI32(const int pAttrIdx, std::vector& pValue) +{ +std::list tlist; + + XML_ReadNode_GetAttrVal_AsListI32(pAttrIdx, tlist);// read as list + // and copy to array + if(tlist.size() > 0) + { + pValue.reserve(tlist.size()); + for(std::list::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it); + } +} + +void X3DImporter::XML_ReadNode_GetAttrVal_AsListF(const int pAttrIdx, std::list& pValue) +{ +std::string str_fixed; + + // at first check string values like '.xxx'. + ParseHelper_FixTruncatedFloatString(mReader->getAttributeValue(pAttrIdx), str_fixed); + if(!str_fixed.size()) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx)); + + // and convert all values and place it in list. + const char* pstr = str_fixed.c_str(); + const char* pstr_end = pstr + str_fixed.size(); + + do + { + float tvalf; + + while((*pstr == ' ') && (pstr < pstr_end)) pstr++;// skip spaces between values. + + if(pstr < pstr_end)// additional check, because attribute value can be ended with spaces. + { + pstr = fast_atoreal_move(pstr, tvalf, false); + pValue.push_back(tvalf); + } + } while(pstr < pstr_end); +} + +void X3DImporter::XML_ReadNode_GetAttrVal_AsArrF(const int pAttrIdx, std::vector& pValue) +{ +std::list tlist; + + XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);// read as list + // and copy to array + if(tlist.size() > 0) + { + pValue.reserve(tlist.size()); + for(std::list::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it); + } +} + +void X3DImporter::XML_ReadNode_GetAttrVal_AsListD(const int pAttrIdx, std::list& pValue) +{ +std::string str_fixed; + + // at first check string values like '.xxx'. + ParseHelper_FixTruncatedFloatString(mReader->getAttributeValue(pAttrIdx), str_fixed); + if(!str_fixed.size()) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx)); + + // and convert all values and place it in list. + const char* pstr = str_fixed.c_str(); + const char* pstr_end = pstr + str_fixed.size(); + + do + { + double tvald; + + while((*pstr == ' ') && (pstr < pstr_end)) pstr++;// skip spaces between values. + + if(pstr < pstr_end)// additional check, because attribute value can be ended with spaces. + { + pstr = fast_atoreal_move(pstr, tvald, false); + pValue.push_back(tvald); + } + } while(pstr < pstr_end); +} + +void X3DImporter::XML_ReadNode_GetAttrVal_AsArrD(const int pAttrIdx, std::vector& pValue) +{ +std::list tlist; + + XML_ReadNode_GetAttrVal_AsListD(pAttrIdx, tlist);// read as list + // and copy to array + if(tlist.size() > 0) + { + pValue.reserve(tlist.size()); + for(std::list::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it); + } +} + +void X3DImporter::XML_ReadNode_GetAttrVal_AsListCol3f(const int pAttrIdx, std::list& pValue) +{ +std::list tlist; + + XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);// read as list + if(tlist.size() % 3) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx)); + + // copy data to array + for(std::list::iterator it = tlist.begin(); it != tlist.end();) + { + aiColor3D tcol; + + tcol.r = *it++; + tcol.g = *it++; + tcol.b = *it++; + pValue.push_back(tcol); + } +} + +void X3DImporter::XML_ReadNode_GetAttrVal_AsArrCol3f(const int pAttrIdx, std::vector& pValue) +{ +std::list tlist; + + XML_ReadNode_GetAttrVal_AsListCol3f(pAttrIdx, tlist);// read as list + // and copy to array + if(tlist.size() > 0) + { + pValue.reserve(tlist.size()); + for(std::list::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it); + } +} + +void X3DImporter::XML_ReadNode_GetAttrVal_AsListCol4f(const int pAttrIdx, std::list& pValue) +{ +std::list tlist; + + XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);// read as list + if(tlist.size() % 4) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx)); + + // copy data to array + for(std::list::iterator it = tlist.begin(); it != tlist.end();) + { + aiColor4D tcol; + + tcol.r = *it++; + tcol.g = *it++; + tcol.b = *it++; + tcol.a = *it++; + pValue.push_back(tcol); + } +} + +void X3DImporter::XML_ReadNode_GetAttrVal_AsArrCol4f(const int pAttrIdx, std::vector& pValue) +{ +std::list tlist; + + XML_ReadNode_GetAttrVal_AsListCol4f(pAttrIdx, tlist);// read as list + // and copy to array + if(tlist.size() > 0) + { + pValue.reserve(tlist.size()); + for(std::list::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it); + } +} + +void X3DImporter::XML_ReadNode_GetAttrVal_AsListVec2f(const int pAttrIdx, std::list& pValue) +{ +std::list tlist; + + XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);// read as list + if(tlist.size() % 2) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx)); + + // copy data to array + for(std::list::iterator it = tlist.begin(); it != tlist.end();) + { + aiVector2D tvec; + + tvec.x = *it++; + tvec.y = *it++; + pValue.push_back(tvec); + } +} + +void X3DImporter::XML_ReadNode_GetAttrVal_AsArrVec2f(const int pAttrIdx, std::vector& pValue) +{ +std::list tlist; + + XML_ReadNode_GetAttrVal_AsListVec2f(pAttrIdx, tlist);// read as list + // and copy to array + if(tlist.size() > 0) + { + pValue.reserve(tlist.size()); + for(std::list::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it); + } +} + +void X3DImporter::XML_ReadNode_GetAttrVal_AsListVec3f(const int pAttrIdx, std::list& pValue) +{ +std::list tlist; + + XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);// read as list + if(tlist.size() % 3) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx)); + + // copy data to array + for(std::list::iterator it = tlist.begin(); it != tlist.end();) + { + aiVector3D tvec; + + tvec.x = *it++; + tvec.y = *it++; + tvec.z = *it++; + pValue.push_back(tvec); + } +} + +void X3DImporter::XML_ReadNode_GetAttrVal_AsArrVec3f(const int pAttrIdx, std::vector& pValue) +{ +std::list tlist; + + XML_ReadNode_GetAttrVal_AsListVec3f(pAttrIdx, tlist);// read as list + // and copy to array + if(tlist.size() > 0) + { + pValue.reserve(tlist.size()); + for(std::list::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it); + } +} + +void X3DImporter::XML_ReadNode_GetAttrVal_AsListS(const int pAttrIdx, std::list& pValue) +{ +char* tok_str; +char* tok_str_end; +size_t tok_str_len; + + // make copy of attribute value - strings list. + tok_str_len = strlen(mReader->getAttributeValue(pAttrIdx)); + if(!tok_str_len) Throw_IncorrectAttrValue(mReader->getAttributeName(pAttrIdx)); + + // get pointer to begin of value. + tok_str = const_cast(mReader->getAttributeValue(pAttrIdx)); + tok_str_end = tok_str + tok_str_len; + // string list has following format: attr_name='"s1" "s2" "sn"'. + do + { + char* tbeg; + char* tend; + size_t tlen; + std::string tstr; + + // find begin of string(element of string list): "sn". + tbeg = strstr(tok_str, "\""); + if(tbeg == NULL) Throw_IncorrectAttrValue(mReader->getAttributeName(pAttrIdx)); + + tbeg++;// forward pointer from '\"' symbol to next after it. + tok_str = tbeg; + // find end of string(element of string list): "sn". + tend = strstr(tok_str, "\""); + if(tend == NULL) Throw_IncorrectAttrValue(mReader->getAttributeName(pAttrIdx)); + + tok_str = tend + 1; + // create storage for new string + tlen = tend - tbeg; + tstr.resize(tlen);// reserve enough space and copy data + memcpy((void*)tstr.data(), tbeg, tlen);// not strcpy because end of copied string from tok_str has no terminator. + // and store string in output list. + pValue.push_back(tstr); + } while(tok_str < tok_str_end); +} + +/*********************************************************************************************************************************************/ +/****************************************************** Functions: geometry helper set ******************************************************/ +/*********************************************************************************************************************************************/ + +aiVector3D X3DImporter::GeometryHelper_Make_Point2D(const float pAngle, const float pRadius) +{ + return aiVector3D(pRadius * cosf(pAngle), pRadius * sinf(pAngle), 0); +} + +void X3DImporter::GeometryHelper_Make_Arc2D(const float pStartAngle, const float pEndAngle, const float pRadius, size_t pNumSegments, + std::list& pVertices) +{ +float angle_full, angle_step; + + // check argument values ranges. + if((pStartAngle < -AI_MATH_TWO_PI_F) || (pStartAngle > AI_MATH_TWO_PI_F)) Throw_ArgOutOfRange("GeometryHelper_Make_Arc2D.pStartAngle"); + if((pEndAngle < -AI_MATH_TWO_PI_F) || (pEndAngle > AI_MATH_TWO_PI_F)) Throw_ArgOutOfRange("GeometryHelper_Make_Arc2D.pEndAngle"); + if(pRadius <= 0) Throw_ArgOutOfRange("GeometryHelper_Make_Arc2D.pRadius"); + + // calculate arc angle and check type of arc + angle_full = fabs(pEndAngle - pStartAngle); + if((angle_full > AI_MATH_TWO_PI_F) || (angle_full == 0.0f)) angle_full = AI_MATH_TWO_PI_F; + + // calculate angle for one step - angle to next point of line. + angle_step = angle_full / (float)pNumSegments; + // make points + for(size_t pi = 0; pi <= pNumSegments; pi++) + { + float tangle; + + tangle = pStartAngle + pi * angle_step; + pVertices.push_back(GeometryHelper_Make_Point2D(tangle, pRadius)); + }// for(size_t pi = 0; pi <= pNumSegments; pi++) + + // if we making full circle then add last vertex equal to first vertex + if(angle_full == AI_MATH_TWO_PI_F) pVertices.push_back(*pVertices.begin()); +} + +void X3DImporter::GeometryHelper_Extend_PointToLine(const std::list& pPoint, std::list& pLine) +{ +std::list::const_iterator pit = pPoint.begin(); +std::list::const_iterator pit_last = pPoint.end(); + + pit_last--; + + if(pPoint.size() < 2) Throw_ArgOutOfRange("GeometryHelper_Extend_PointToLine.pPoint.size() can not be less than 2."); + + // add first point of first line. + pLine.push_back(*pit++); + // add internal points + while(pit != pit_last) + { + pLine.push_back(*pit);// second point of previous line + pLine.push_back(*pit);// first point of next line + pit++; + } + // add last point of last line + pLine.push_back(*pit); +} + +void X3DImporter::GeometryHelper_Extend_PolylineIdxToLineIdx(const std::list& pPolylineCoordIdx, std::list& pLineCoordIdx) +{ +std::list::const_iterator plit = pPolylineCoordIdx.begin(); + + while(plit != pPolylineCoordIdx.end()) + { + // add first point of polyline + pLineCoordIdx.push_back(*plit++); + while((*plit != (-1)) && (plit != pPolylineCoordIdx.end())) + { + std::list::const_iterator plit_next; + + plit_next = plit, plit_next++; + pLineCoordIdx.push_back(*plit);// second point of previous line. + pLineCoordIdx.push_back(-1);// delimiter + if((*plit_next == (-1)) || (plit_next == pPolylineCoordIdx.end())) break;// current polyline is finished + + pLineCoordIdx.push_back(*plit);// first point of next line. + plit = plit_next; + }// while((*plit != (-1)) && (plit != pPolylineCoordIdx.end())) + }// while(plit != pPolylineCoordIdx.end()) +} + +#define MESH_RectParallelepiped_CREATE_VERT \ +aiVector3D vert_set[8]; \ +float x1, x2, y1, y2, z1, z2, hs; \ + \ + hs = pSize.x / 2, x1 = -hs, x2 = hs; \ + hs = pSize.y / 2, y1 = -hs, y2 = hs; \ + hs = pSize.z / 2, z1 = -hs, z2 = hs; \ + vert_set[0].Set(x2, y1, z2); \ + vert_set[1].Set(x2, y2, z2); \ + vert_set[2].Set(x2, y2, z1); \ + vert_set[3].Set(x2, y1, z1); \ + vert_set[4].Set(x1, y1, z2); \ + vert_set[5].Set(x1, y2, z2); \ + vert_set[6].Set(x1, y2, z1); \ + vert_set[7].Set(x1, y1, z1) + +void X3DImporter::GeometryHelper_MakeQL_RectParallelepiped(const aiVector3D& pSize, std::list& pVertices) +{ + MESH_RectParallelepiped_CREATE_VERT; + MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 3, 2, 1, 0);// front + MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 6, 7, 4, 5);// back + MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 7, 3, 0, 4);// left + MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 2, 6, 5, 1);// right + MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 0, 1, 5, 4);// top + MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 7, 6, 2, 3);// bottom +} + +#undef MESH_RectParallelepiped_CREATE_VERT + +void X3DImporter::GeometryHelper_CoordIdxStr2FacesArr(const std::list& pCoordIdx, std::vector& pFaces, unsigned int& pPrimitiveTypes) const +{ +std::list f_data(pCoordIdx); +std::vector inds; +unsigned int prim_type = 0; + + if(f_data.back() != (-1)) f_data.push_back(-1); + + // reserve average size. + pFaces.reserve(f_data.size() / 3); + inds.reserve(4); +//PrintVectorSet("build. ci", pCoordIdx); + for(std::list::iterator it = f_data.begin(); it != f_data.end(); it++) + { + // when face is got count how many indices in it. + if(*it == (-1)) + { + aiFace tface; + size_t ts; + + ts = inds.size(); + switch(ts) + { + case 0: goto mg_m_err; + case 1: prim_type |= aiPrimitiveType_POINT; + case 2: prim_type |= aiPrimitiveType_LINE; + case 3: prim_type |= aiPrimitiveType_TRIANGLE; + default: prim_type |= aiPrimitiveType_POLYGON; + } + + tface.mNumIndices = ts; + tface.mIndices = new unsigned int[ts]; + memcpy(tface.mIndices, inds.data(), ts * sizeof(unsigned int)); + pFaces.push_back(tface); + inds.clear(); + }// if(*it == (-1)) + else + { + inds.push_back(*it); + }// if(*it == (-1)) else + }// for(std::list::iterator it = f_data.begin(); it != f_data.end(); it++) +//PrintVectorSet("build. faces", pCoordIdx); + + pPrimitiveTypes = prim_type; + + return; + +mg_m_err: + + for(size_t i = 0, i_e = pFaces.size(); i < i_e; i++) delete [] pFaces.at(i).mIndices; + + pFaces.clear(); +} + +void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list& pColors, const bool pColorPerVertex) const +{ +std::list tcol; + + // create RGBA array from RGB. + for(std::list::const_iterator it = pColors.begin(); it != pColors.end(); it++) tcol.push_back(aiColor4D((*it).r, (*it).g, (*it).b, 1)); + + // call existing function for adding RGBA colors + MeshGeometry_AddColor(pMesh, tcol, pColorPerVertex); +} + +void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list& pColors, const bool pColorPerVertex) const +{ +std::list::const_iterator col_it = pColors.begin(); + + if(pColorPerVertex) + { + if(pColors.size() < pMesh.mNumVertices) + { + throw DeadlyImportError(boost::str(boost::format("MeshGeometry_AddColor1. Colors count(%s) can not be less than Vertices count(%s).") % + pColors.size() % pMesh.mNumVertices)); + } + + // copy colors to mesh + pMesh.mColors[0] = new aiColor4D[pMesh.mNumVertices]; + for(size_t i = 0; i < pMesh.mNumVertices; i++) pMesh.mColors[0][i] = *col_it++; + }// if(pColorPerVertex) + else + { + if(pColors.size() < pMesh.mNumFaces) + { + throw DeadlyImportError(boost::str(boost::format("MeshGeometry_AddColor1. Colors count(%s) can not be less than Faces count(%s).") % + pColors.size() % pMesh.mNumFaces)); + } + + // copy colors to mesh + pMesh.mColors[0] = new aiColor4D[pMesh.mNumVertices]; + for(size_t fi = 0; fi < pMesh.mNumFaces; fi++) + { + // apply color to all vertices of face + for(size_t vi = 0, vi_e = pMesh.mFaces[fi].mNumIndices; vi < vi_e; vi++) pMesh.mColors[0][pMesh.mFaces[fi].mIndices[vi]] = *col_it; + + col_it++; + } + }// if(pColorPerVertex) else +} + +void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pColorIdx, + const std::list& pColors, const bool pColorPerVertex) const +{ +std::list tcol; + + // create RGBA array from RGB. + for(std::list::const_iterator it = pColors.begin(); it != pColors.end(); it++) tcol.push_back(aiColor4D((*it).r, (*it).g, (*it).b, 1)); + + // call existing function for adding RGBA colors + MeshGeometry_AddColor(pMesh, pCoordIdx, pColorIdx, tcol, pColorPerVertex); +} + +void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pColorIdx, + const std::list& pColors, const bool pColorPerVertex) const +{ +std::vector col_tgt_arr; +std::list col_tgt_list; +std::vector col_arr_copy; + + if(pCoordIdx.size() == 0) throw DeadlyImportError("MeshGeometry_AddColor2. pCoordIdx can not be empty."); + + // copy list to array because we are need indexed access to colors. + col_arr_copy.reserve(pColors.size()); + for(std::list::const_iterator it = pColors.begin(); it != pColors.end(); it++) col_arr_copy.push_back(*it); + + if(pColorPerVertex) + { + if(pColorIdx.size() > 0) + { + // check indices array count. + if(pColorIdx.size() < pCoordIdx.size()) + { + throw DeadlyImportError(boost::str(boost::format("MeshGeometry_AddColor2. Colors indices count(%s) can not be less than Coords inidces count(%s).") % + pColorIdx.size() % pCoordIdx.size())); + } + // create list with colors for every vertex. + col_tgt_arr.resize(pMesh.mNumVertices); + for(std::list::const_iterator colidx_it = pColorIdx.begin(), coordidx_it = pCoordIdx.begin(); colidx_it != pColorIdx.end(); colidx_it++, coordidx_it++) + { + if(*colidx_it == (-1)) continue;// skip faces delimiter + if((unsigned int)(*coordidx_it) > pMesh.mNumVertices) throw DeadlyImportError("MeshGeometry_AddColor2. Coordinate idx is out of range."); + if((unsigned int)*colidx_it > pMesh.mNumVertices) throw DeadlyImportError("MeshGeometry_AddColor2. Color idx is out of range."); + + col_tgt_arr[*coordidx_it] = col_arr_copy[*colidx_it]; + } + }// if(pColorIdx.size() > 0) + else + { + // when color indices list is absent use CoordIdx. + // check indices array count. + if(pColors.size() < pMesh.mNumVertices) + { + throw DeadlyImportError(boost::str(boost::format("MeshGeometry_AddColor2. Colors count(%s) can not be less than Vertices count(%s).") % + pColors.size() % pMesh.mNumVertices)); + } + // create list with colors for every vertex. + col_tgt_arr.resize(pMesh.mNumVertices); + for(size_t i = 0; i < pMesh.mNumVertices; i++) col_tgt_arr[i] = col_arr_copy[i]; + }// if(pColorIdx.size() > 0) else + }// if(pColorPerVertex) + else + { + if(pColorIdx.size() > 0) + { + // check indices array count. + if(pColorIdx.size() < pMesh.mNumFaces) + { + throw DeadlyImportError(boost::str(boost::format("MeshGeometry_AddColor2. Colors indices count(%s) can not be less than Faces count(%s).") % + pColorIdx.size() % pMesh.mNumFaces)); + } + // create list with colors for every vertex using faces indices. + col_tgt_arr.resize(pMesh.mNumFaces); + + std::list::const_iterator colidx_it = pColorIdx.begin(); + for(size_t fi = 0; fi < pMesh.mNumFaces; fi++) + { + if((unsigned int)*colidx_it > pMesh.mNumFaces) throw DeadlyImportError("MeshGeometry_AddColor2. Face idx is out of range."); + + col_tgt_arr[fi] = col_arr_copy[*colidx_it++]; + } + }// if(pColorIdx.size() > 0) + else + { + // when color indices list is absent use CoordIdx. + // check indices array count. + if(pColors.size() < pMesh.mNumFaces) + { + throw DeadlyImportError(boost::str(boost::format("MeshGeometry_AddColor2. Colors count(%s) can not be less than Faces count(%s).") % + pColors.size() % pMesh.mNumFaces)); + } + // create list with colors for every vertex using faces indices. + col_tgt_arr.resize(pMesh.mNumFaces); + for(size_t fi = 0; fi < pMesh.mNumFaces; fi++) col_tgt_arr[fi] = col_arr_copy[fi]; + + }// if(pColorIdx.size() > 0) else + }// if(pColorPerVertex) else + + // copy array to list for calling function that add colors. + for(std::vector::const_iterator it = col_tgt_arr.begin(); it != col_tgt_arr.end(); it++) col_tgt_list.push_back(*it); + // add prepared colors list to mesh. + MeshGeometry_AddColor(pMesh, col_tgt_list, pColorPerVertex); +} + +void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pNormalIdx, + const std::list& pNormals, const bool pNormalPerVertex) const +{ +std::vector tind; +std::vector norm_arr_copy; + + // copy list to array because we are need indexed access to normals. + norm_arr_copy.reserve(pNormals.size()); + for(std::list::const_iterator it = pNormals.begin(); it != pNormals.end(); it++) norm_arr_copy.push_back(*it); + + if(pNormalPerVertex) + { + const std::list* srcidx; + + if(pNormalIdx.size() > 0) + { + // check indices array count. + if(pNormalIdx.size() != pCoordIdx.size()) throw DeadlyImportError("Normals and Coords inidces count must be equal."); + + srcidx = &pNormalIdx; + } + else + { + srcidx = &pCoordIdx; + } + + tind.reserve(srcidx->size()); + for(std::list::const_iterator it = srcidx->begin(); it != srcidx->end(); it++) + { + if(*it != (-1)) tind.push_back(*it); + } + + // copy normals to mesh + pMesh.mNormals = new aiVector3D[pMesh.mNumVertices]; + for(size_t i = 0; (i < pMesh.mNumVertices) && (i < tind.size()); i++) + { + if(tind[i] >= norm_arr_copy.size()) + throw DeadlyImportError(boost::str(boost::format("MeshGeometry_AddNormal. Normal index(%s) is out of range. Normals count: %s.") % + tind[i] % norm_arr_copy.size())); + + pMesh.mNormals[i] = norm_arr_copy[tind[i]]; + } + }// if(pNormalPerVertex) + else + { + if(pNormalIdx.size() > 0) + { + if(pMesh.mNumFaces != pNormalIdx.size()) throw DeadlyImportError("Normals faces count must be equal to mesh faces count."); + + std::list::const_iterator normidx_it = pNormalIdx.begin(); + + tind.reserve(pNormalIdx.size()); + for(size_t i = 0, i_e = pNormalIdx.size(); i < i_e; i++) tind.push_back(*normidx_it++); + + } + else + { + tind.reserve(pMesh.mNumFaces); + for(size_t i = 0; i < pMesh.mNumFaces; i++) tind.push_back(i); + + } + + // copy normals to mesh + pMesh.mNormals = new aiVector3D[pMesh.mNumVertices]; + for(size_t fi = 0; fi < pMesh.mNumFaces; fi++) + { + aiVector3D tnorm; + + tnorm = norm_arr_copy[tind[fi]]; + for(size_t vi = 0, vi_e = pMesh.mFaces[fi].mNumIndices; vi < vi_e; vi++) pMesh.mNormals[pMesh.mFaces[fi].mIndices[vi]] = tnorm; + } + }// if(pNormalPerVertex) else +} + +void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::list& pNormals, const bool pNormalPerVertex) const +{ +std::list::const_iterator norm_it = pNormals.begin(); + + if(pNormalPerVertex) + { + if(pNormals.size() != pMesh.mNumVertices) throw DeadlyImportError("MeshGeometry_AddNormal. Normals and vertices count must be equal."); + + // copy normals to mesh + pMesh.mNormals = new aiVector3D[pMesh.mNumVertices]; + for(size_t i = 0; i < pMesh.mNumVertices; i++) pMesh.mNormals[i] = *norm_it++; + }// if(pNormalPerVertex) + else + { + if(pNormals.size() != pMesh.mNumFaces) throw DeadlyImportError("MeshGeometry_AddNormal. Normals and faces count must be equal."); + + // copy normals to mesh + pMesh.mNormals = new aiVector3D[pMesh.mNumVertices]; + for(size_t fi = 0; fi < pMesh.mNumFaces; fi++) + { + // apply color to all vertices of face + for(size_t vi = 0, vi_e = pMesh.mFaces[fi].mNumIndices; vi < vi_e; vi++) pMesh.mNormals[pMesh.mFaces[fi].mIndices[vi]] = *norm_it; + + norm_it++; + } + }// if(pNormalPerVertex) else +} + +void X3DImporter::MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pTexCoordIdx, + const std::list& pTexCoords) const +{ +std::vector texcoord_arr_copy; +std::vector faces; +unsigned int prim_type; + + // copy list to array because we are need indexed access to normals. + texcoord_arr_copy.reserve(pTexCoords.size()); + for(std::list::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); it++) + { + texcoord_arr_copy.push_back(aiVector3D((*it).x, (*it).y, 0)); + } + + if(pTexCoordIdx.size() > 0) + { + GeometryHelper_CoordIdxStr2FacesArr(pTexCoordIdx, faces, prim_type); + if(!faces.size()) throw DeadlyImportError("Failed to add texture coordinates to mesh, faces list is empty."); + if(faces.size() != pMesh.mNumFaces) throw DeadlyImportError("Texture coordinates faces count must be equal to mesh faces count."); + } + else + { + GeometryHelper_CoordIdxStr2FacesArr(pCoordIdx, faces, prim_type); + } + + pMesh.mTextureCoords[0] = new aiVector3D[pMesh.mNumVertices]; + pMesh.mNumUVComponents[0] = 2; + for(size_t fi = 0, fi_e = faces.size(); fi < fi_e; fi++) + { + if(pMesh.mFaces[fi].mNumIndices != faces.at(fi).mNumIndices) + throw DeadlyImportError(boost::str(boost::format("Number of indices in texture face and mesh face must be equal. Invalid face index: %s") % fi)); + + for(size_t ii = 0; ii < pMesh.mFaces[fi].mNumIndices; ii++) + { + size_t vert_idx = pMesh.mFaces[fi].mIndices[ii]; + size_t tc_idx = faces.at(fi).mIndices[ii]; + + pMesh.mTextureCoords[0][vert_idx] = texcoord_arr_copy.at(tc_idx); + } + }// for(size_t fi = 0, fi_e = faces.size(); fi < fi_e; fi++) +} + +void X3DImporter::MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::list& pTexCoords) const +{ +std::vector tc_arr_copy; + + if(pTexCoords.size() != pMesh.mNumVertices) throw DeadlyImportError("MeshGeometry_AddTexCoord. Texture coordinates and vertices count must be equal."); + + // copy list to array because we are need convert aiVector2D to aiVector3D and also get indexed access as a bonus. + tc_arr_copy.reserve(pTexCoords.size()); + for(std::list::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); it++) tc_arr_copy.push_back(aiVector3D((*it).x, (*it).y, 0)); + + // copy texture coordinates to mesh + pMesh.mTextureCoords[0] = new aiVector3D[pMesh.mNumVertices]; + pMesh.mNumUVComponents[0] = 2; + for(size_t i = 0; i < pMesh.mNumVertices; i++) pMesh.mTextureCoords[0][i] = tc_arr_copy[i]; +} + +aiMesh* X3DImporter::GeometryHelper_MakeMesh(const std::list& pCoordIdx, const std::list& pVertices) const +{ +aiMesh* tmesh; +std::vector faces; +unsigned int prim_type = 0; +size_t ts; + + // create faces array from input string with vertices indices. + GeometryHelper_CoordIdxStr2FacesArr(pCoordIdx, faces, prim_type); + if(!faces.size()) throw DeadlyImportError("Failed to create mesh, faces list is empty."); + + // + // Create new mesh and copy geometry data. + // + tmesh = new aiMesh; + ts = faces.size(); + // faces + tmesh->mFaces = new aiFace[ts]; + tmesh->mNumFaces = ts; + for(size_t i = 0; i < ts; i++) tmesh->mFaces[i] = faces.at(i); + + // vertices + std::list::const_iterator vit = pVertices.begin(); + + ts = pVertices.size(); + tmesh->mVertices = new aiVector3D[ts]; + tmesh->mNumVertices = ts; + for(size_t i = 0; i < ts; i++) tmesh->mVertices[i] = *vit++; + + // set primitives type and return result. + tmesh->mPrimitiveTypes = prim_type; + + return tmesh; +} + +/*********************************************************************************************************************************************/ +/************************************************************ Functions: parse set ***********************************************************/ +/*********************************************************************************************************************************************/ + +void X3DImporter::ParseHelper_Group_Begin(const bool pStatic) +{ +CX3DImporter_NodeElement_Group* new_group = new CX3DImporter_NodeElement_Group(NodeElement_Cur, pStatic);// create new node with current node as parent. + + // if we are adding not the root element then add new element to current element child list. + if(NodeElement_Cur != NULL) NodeElement_Cur->Child.push_back(new_group); + + NodeElement_List.push_back(new_group);// it's a new element - add it to list. + NodeElement_Cur = new_group;// switch current element to new one. +} + +void X3DImporter::ParseHelper_Node_Enter(CX3DImporter_NodeElement* pNode) +{ + NodeElement_Cur->Child.push_back(pNode);// add new element to current element child list. + NodeElement_Cur = pNode;// switch current element to new one. +} + +void X3DImporter::ParseHelper_Node_Exit() +{ + // check if we can walk up. + if(NodeElement_Cur != NULL) NodeElement_Cur = NodeElement_Cur->Parent; +} + +void X3DImporter::ParseHelper_FixTruncatedFloatString(const char* pInStr, std::string& pOutString) +{ +size_t instr_len; + + pOutString.clear(); + instr_len = strlen(pInStr); + if(!instr_len) return; + + pOutString.reserve(instr_len * 3 / 2); + // check and correct floats in format ".x". Must be "x.y". + if(pInStr[0] == '.') pOutString.push_back('0'); + + pOutString.push_back(pInStr[0]); + for(size_t ci = 1; ci < instr_len; ci++) + { + if((pInStr[ci] == '.') && ((pInStr[ci - 1] == ' ') || (pInStr[ci - 1] == '-') || (pInStr[ci - 1] == '+') || (pInStr[ci - 1] == '\t'))) + { + pOutString.push_back('0'); + pOutString.push_back('.'); + } + else + { + pOutString.push_back(pInStr[ci]); + } + } +} + +void X3DImporter::ParseFile(const std::string& pFile, IOSystem* pIOHandler) +{ +irr::io::IrrXMLReader* OldReader = mReader;// store current XMLreader. +boost::scoped_ptr file(pIOHandler->Open(pFile, "rb")); + + // Check whether we can read from the file + if(file.get() == NULL) throw DeadlyImportError("Failed to open X3D file " + pFile + "."); + // generate a XML reader for it + boost::scoped_ptr mIOWrapper(new CIrrXML_IOStreamReader(file.get())); + mReader = irr::io::createIrrXMLReader(mIOWrapper.get()); + if(!mReader) throw DeadlyImportError("Failed to create XML reader for file" + pFile + "."); + // start reading + ParseNode_Root(); + + delete mReader; + // restore old XMLreader + mReader = OldReader; +} + +void X3DImporter::ParseNode_Root() +{ +LogInfo("ParseNode_Root b"); + // search for root tag + if(!XML_SearchNode("X3D")) throw DeadlyImportError("Root node \"X3D\" not found."); + + ParseHelper_Group_Begin();// create root node element. + // parse other contents +LogInfo("ParseNode_Root. read loop"); + while(mReader->read()) + { + if(mReader->getNodeType() != irr::io::EXN_ELEMENT) continue; + + if(XML_CheckNode_NameEqual("head")) + ParseNode_Head(); + else if(XML_CheckNode_NameEqual("Scene")) + ParseNode_Scene(); + else + XML_CheckNode_SkipUnsupported("Root"); + } +LogInfo("ParseNode_Root. end loop"); + + // exit from root node element. + ParseHelper_Node_Exit(); +LogInfo("ParseNode_Root e"); +} + +void X3DImporter::ParseNode_Head() +{ +bool close_found = false;// flag: true if close tag of node are found. + + while(mReader->read()) + { + if(mReader->getNodeType() == irr::io::EXN_ELEMENT) + { + if(XML_CheckNode_NameEqual("meta")) + { + XML_CheckNode_MustBeEmpty(); + + // adding metada from as MetaString from + CX3DImporter_NodeElement_MetaString* ms = new CX3DImporter_NodeElement_MetaString(NodeElement_Cur); + + ms->Name = mReader->getAttributeValueSafe("name"); + // name can not be empty + if(!ms->Name.empty()) + { + ms->Value.push_back(mReader->getAttributeValueSafe("content")); + NodeElement_List.push_back(ms); + if(NodeElement_Cur != NULL) NodeElement_Cur->Child.push_back(ms); + } + }// if(XML_CheckNode_NameEqual("meta")) + }// if(mReader->getNodeType() == irr::io::EXN_ELEMENT) + else if(mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + { + if(XML_CheckNode_NameEqual("head")) + { + close_found = true; + + break; + } + }// if(mReader->getNodeType() == irr::io::EXN_ELEMENT) else + }// while(mReader->read()) + + if(!close_found) Throw_CloseNotFound("head"); + +} + +void X3DImporter::ParseNode_Scene() +{ +bool close_found = false; +ssize_t group_cnt = 0; +ssize_t transform_cnt = 0; +ssize_t sw_cnt = 0; + + // while create static node? Because objects name used deeper in "USE" attribute can be equal to some meta in node. + ParseHelper_Group_Begin(true); + while(mReader->read()) + { + if(mReader->getNodeType() == irr::io::EXN_ELEMENT) + { + if(XML_CheckNode_NameEqual("Shape")) + { + ParseNode_Shape_Shape(); + } + else if(XML_CheckNode_NameEqual("Group")) + { + group_cnt++; + ParseNode_Grouping_Group(); + if(mReader->isEmptyElement()) group_cnt--;// if node is empty then decrease group counter at this place. + } + else if(XML_CheckNode_NameEqual("StaticGroup")) + { + group_cnt++; + ParseNode_Grouping_StaticGroup(); + if(mReader->isEmptyElement()) group_cnt--;// if node is empty then decrease group counter at this place. + + } + else if(XML_CheckNode_NameEqual("Transform")) + { + transform_cnt++; + ParseNode_Grouping_Transform(); + if(mReader->isEmptyElement()) transform_cnt--;// if node is empty then decrease group counter at this place. + } + else if(XML_CheckNode_NameEqual("Switch")) + { + sw_cnt++; + ParseNode_Grouping_Switch(); + if(mReader->isEmptyElement()) sw_cnt--;// if node is empty then decrease group counter at this place. + } + else if(XML_CheckNode_NameEqual("DirectionalLight")) + { + ParseNode_Lighting_DirectionalLight(); + } + else if(XML_CheckNode_NameEqual("PointLight")) + { + ParseNode_Lighting_PointLight(); + } + else if(XML_CheckNode_NameEqual("SpotLight")) + { + ParseNode_Lighting_SpotLight(); + } + else if(XML_CheckNode_NameEqual("Inline")) + { + ParseNode_Networking_Inline(); + } + else if(!ParseHelper_CheckRead_X3DMetadataObject()) + { + XML_CheckNode_SkipUnsupported("Scene"); + } + }// if(mReader->getNodeType() == irr::io::EXN_ELEMENT) + else if(mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + { + if(XML_CheckNode_NameEqual("Scene")) + { + close_found = true; + + break; + } + else if(XML_CheckNode_NameEqual("Group")) + { + group_cnt--; + ParseNode_Grouping_GroupEnd(); + } + else if(XML_CheckNode_NameEqual("StaticGroup")) + { + group_cnt--; + ParseNode_Grouping_StaticGroupEnd(); + } + else if(XML_CheckNode_NameEqual("Transform")) + { + transform_cnt--; + ParseNode_Grouping_TransformEnd(); + } + else if(XML_CheckNode_NameEqual("Switch")) + { + sw_cnt--; + ParseNode_Grouping_SwitchEnd(); + } + }// if(mReader->getNodeType() == irr::io::EXN_ELEMENT) else + }// while(mReader->read()) + + ParseHelper_Node_Exit(); + + if(group_cnt) Throw_TagCountIncorrect("Group"); + if(transform_cnt) Throw_TagCountIncorrect("Transform"); + if(sw_cnt) Throw_TagCountIncorrect("Switch"); + if(!close_found) Throw_CloseNotFound("Scene"); + +} + +/*********************************************************************************************************************************************/ +/******************************************************** Functions: BaseImporter set ********************************************************/ +/*********************************************************************************************************************************************/ + +bool X3DImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool pCheckSig) const +{ +const std::string extension = GetExtension(pFile); + + if(extension == "x3d") return true; + + if(!extension.length() || pCheckSig) + { + const char* tokens[] = { "DOCTYPE X3D PUBLIC", "http://www.web3d.org/specifications/x3d" }; + + return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 2); + } + + return false; +} + +void X3DImporter::GetExtensionList(std::set& pExtensionList) +{ + pExtensionList.insert("x3d"); +} + +const aiImporterDesc* X3DImporter::GetInfo () const +{ + return &Description; +} + +void X3DImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) +{ + Clear();// delete old graph. + mFileDir = DefaultIOSystem::absolutePath(pFile); + ParseFile(pFile, pIOHandler); + // + // Assimp use static arrays of objects for fast speed of rendering. That's good, but need some additional operations/ + // We know that geometry objects(meshes) are stored in , also in -> materials(in Assimp logical view) + // are stored. So at first we need to count how meshes and materials are stored in scene graph. + // + // at first creating root node for aiScene. + pScene->mRootNode = new aiNode; + pScene->mRootNode->mParent = NULL; + + //search for root node element + NodeElement_Cur = NodeElement_List.front(); + while(NodeElement_Cur->Parent != NULL) NodeElement_Cur = NodeElement_Cur->Parent; + + {// fill aiScene with objects. + std::list mesh_list; + std::list mat_list; + std::list light_list; + + // create nodes tree + Postprocess_BuildNode(*NodeElement_Cur, *pScene->mRootNode, mesh_list, mat_list, light_list); + // copy needed data to scene + if(mesh_list.size() > 0) + { + std::list::const_iterator it = mesh_list.begin(); + + pScene->mNumMeshes = mesh_list.size(); + pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; + for(size_t i = 0; i < pScene->mNumMeshes; i++) pScene->mMeshes[i] = *it++; + } + + if(mat_list.size() > 0) + { + std::list::const_iterator it = mat_list.begin(); + + pScene->mNumMaterials = mat_list.size(); + pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; + for(size_t i = 0; i < pScene->mNumMaterials; i++) pScene->mMaterials[i] = *it++; + } + + if(light_list.size() > 0) + { + std::list::const_iterator it = light_list.begin(); + + pScene->mNumLights = light_list.size(); + pScene->mLights = new aiLight*[pScene->mNumLights]; + for(size_t i = 0; i < pScene->mNumLights; i++) pScene->mLights[i] = *it++; + } + }// END: fill aiScene with objects. + + ///TODO: IME optimize tree +} + +}// namespace Assimp + +#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER diff --git a/code/X3DImporter.hpp b/code/X3DImporter.hpp new file mode 100644 index 000000000..5d8b9bd1b --- /dev/null +++ b/code/X3DImporter.hpp @@ -0,0 +1,954 @@ +/// \file X3DImporter.hpp +/// \brief X3D-format files importer for Assimp. +/// \date 2015-2016 +/// \author nevorek@gmail.com + +#ifndef INCLUDED_AI_X3D_IMPORTER_H +#define INCLUDED_AI_X3D_IMPORTER_H + +// Pay attention - you must include some files from Assimp before including BaseImporter.h. +// magic region begin +#include + +#include "../include/assimp/DefaultLogger.hpp" +#include "../include/assimp/importerdesc.h" +#include "../include/assimp/ProgressHandler.hpp" +#include "../include/assimp/types.h" +// magic region end +#include "BaseImporter.h" +#include "irrXMLWrapper.h" + +#include "X3DImporter_Node.hpp" + +namespace Assimp +{ + +/// \class X3DImporter +/// Class that holding scene graph which include: groups, geometry, metadata etc. +/// +/// Limitations. +/// +/// Pay attention that X3D is format for interactive graphic and simulations for web browsers. +/// So not all features can be imported using Assimp. +/// +/// Unsupported nodes: +/// CAD geometry component: +/// "CADAssembly", "CADFace", "CADLayer", "CADPart", "IndexedQuadSet", "QuadSet" +/// Core component: +/// "ROUTE", "ExternProtoDeclare", "ProtoDeclare", "ProtoInstance", "ProtoInterface", "WorldInfo" +/// Distributed interactive simulation (DIS) component: +/// "DISEntityManager", "DISEntityTypeMapping", "EspduTransform", "ReceiverPdu", "SignalPdu", "TransmitterPdu" +/// Cube map environmental texturing component: +/// "ComposedCubeMapTexture", "GeneratedCubeMapTexture", "ImageCubeMapTexture" +/// Environmental effects component: +/// "Background", "Fog", "FogCoordinate", "LocalFog", "TextureBackground" +/// Environmental sensor component: +/// "ProximitySensor", "TransformSensor", "VisibilitySensor" +/// Followers component: +/// "ColorChaser", "ColorDamper", "CoordinateChaser", "CoordinateDamper", "OrientationChaser", "OrientationDamper", "PositionChaser", +/// "PositionChaser2D", "PositionDamper", "PositionDamper2D", "ScalarChaser", "ScalarDamper", "TexCoordChaser2D", "TexCoordDamper2D" +/// Geospatial component: +/// "GeoCoordinate", "GeoElevationGrid", "GeoLocation", "GeoLOD", "GeoMetadata", "GeoOrigin", "GeoPositionInterpolator", "GeoProximitySensor", +/// "GeoTouchSensor", "GeoTransform", "GeoViewpoint" +/// Humanoid Animation (H-Anim) component: +/// "HAnimDisplacer", "HAnimHumanoid", "HAnimJoint", "HAnimSegment", "HAnimSite" +/// Interpolation component: +/// "ColorInterpolator", "CoordinateInterpolator", "CoordinateInterpolator2D", "EaseInEaseOut", "NormalInterpolator", "OrientationInterpolator", +/// "PositionInterpolator", "PositionInterpolator2D", "ScalarInterpolator", "SplinePositionInterpolator", "SplinePositionInterpolator2D", +/// "SplineScalarInterpolator", "SquadOrientationInterpolator", +/// Key device sensor component: +/// "KeySensor", "StringSensor" +/// Layering component: +/// "Layer", "LayerSet", "Viewport" +/// Layout component: +/// "Layout", "LayoutGroup", "LayoutLayer", "ScreenFontStyle", "ScreenGroup" +/// Navigation component: +/// "Billboard", "Collision", "LOD", "NavigationInfo", "OrthoViewpoint", "Viewpoint", "ViewpointGroup" +/// Networking component: +/// "Anchor", "LoadSensor" +/// NURBS component: +/// "Contour2D", "ContourPolyline2D", "CoordinateDouble", "NurbsCurve", "NurbsCurve2D", "NurbsOrientationInterpolator", "NurbsPatchSurface", +/// "NurbsPositionInterpolator", "NurbsSet", "NurbsSurfaceInterpolator", "NurbsSweptSurface", "NurbsSwungSurface", "NurbsTextureCoordinate", +/// "NurbsTrimmedSurface" +/// Particle systems component: +/// "BoundedPhysicsModel", "ConeEmitter", "ExplosionEmitter", "ForcePhysicsModel", "ParticleSystem", "PointEmitter", "PolylineEmitter", +/// "SurfaceEmitter", "VolumeEmitter", "WindPhysicsModel" +/// Picking component: +/// "LinePickSensor", "PickableGroup", "PointPickSensor", "PrimitivePickSensor", "VolumePickSensor" +/// Pointing device sensor component: +/// "CylinderSensor", "PlaneSensor", "SphereSensor", "TouchSensor" +/// Rendering component: +/// "ClipPlane" +/// Rigid body physics: +/// "BallJoint", "CollidableOffset", "CollidableShape", "CollisionCollection", "CollisionSensor", "CollisionSpace", "Contact", "DoubleAxisHingeJoint", +/// "MotorJoint", "RigidBody", "RigidBodyCollection", "SingleAxisHingeJoint", "SliderJoint", "UniversalJoint" +/// Scripting component: +/// "Script" +/// Programmable shaders component: +/// "ComposedShader", "FloatVertexAttribute", "Matrix3VertexAttribute", "Matrix4VertexAttribute", "PackagedShader", "ProgramShader", "ShaderPart", +/// "ShaderProgram", +/// Shape component: +/// "FillProperties", "LineProperties", "TwoSidedMaterial" +/// Sound component: +/// "AudioClip", "Sound" +/// Text component: +/// "FontStyle", "Text" +/// Texturing3D Component: +/// "ComposedTexture3D", "ImageTexture3D", "PixelTexture3D", "TextureCoordinate3D", "TextureCoordinate4D", "TextureTransformMatrix3D", +/// "TextureTransform3D" +/// Texturing component: +/// "MovieTexture", "MultiTexture", "MultiTextureCoordinate", "MultiTextureTransform", "PixelTexture", "TextureCoordinateGenerator", +/// "TextureProperties", +/// Time component: +/// "TimeSensor" +/// Event Utilities component: +/// "BooleanFilter", "BooleanSequencer", "BooleanToggle", "BooleanTrigger", "IntegerSequencer", "IntegerTrigger", "TimeTrigger", +/// Volume rendering component: +/// "BlendedVolumeStyle", "BoundaryEnhancementVolumeStyle", "CartoonVolumeStyle", "ComposedVolumeStyle", "EdgeEnhancementVolumeStyle", +/// "IsoSurfaceVolumeData", "OpacityMapVolumeStyle", "ProjectionVolumeStyle", "SegmentedVolumeData", "ShadedVolumeStyle", +/// "SilhouetteEnhancementVolumeStyle", "ToneMappedVolumeStyle", "VolumeData" +/// +/// Supported nodes: +/// Core component: +/// "MetadataBoolean", "MetadataDouble", "MetadataFloat", "MetadataInteger", "MetadataSet", "MetadataString" +/// Geometry2D component: +/// "Arc2D", "ArcClose2D", "Circle2D", "Disk2D", "Polyline2D", "Polypoint2D", "Rectangle2D", "TriangleSet2D" +/// Geometry3D component: +/// "Box", "Cone", "Cylinder", "ElevationGrid", "Extrusion", "IndexedFaceSet", "Sphere" +/// Grouping component: +/// "Group", "StaticGroup", "Switch", "Transform" +/// Lighting component: +/// "DirectionalLight", "PointLight", "SpotLight" +/// Networking component: +/// "Inline" +/// Rendering component: +/// "Color", "ColorRGBA", "Coordinate", "IndexedLineSet", "IndexedTriangleFanSet", "IndexedTriangleSet", "IndexedTriangleStripSet", "LineSet", +/// "PointSet", "TriangleFanSet", "TriangleSet", "TriangleStripSet", "Normal" +/// Shape component: +/// "Shape", "Appearance", "Material" +/// Texturing component: +/// "ImageTexture", "TextureCoordinate", "TextureTransform" +/// +/// Limitations of attribute "USE". +/// If "USE" is set then node must be empty, like that: +/// +/// not the +/// +/// +/// Ignored attributes: "creaseAngle", "convex", "solid". +/// +/// Texture coordinates generating: only for Sphere, Cone, Cylinder. In all other case used PLANE mapping. +/// It's better that Assimp main code has powerfull texture coordinates generator. Then is not needed to +/// duplicate this code in every importer. +/// +/// Lighting limitations. +/// If light source placed in some group with "DEF" set. And after that some node is use it group with "USE" attribute then +/// you will get error about duplicate light sources. That's happening because Assimp require names for lights but do not like +/// duplicates of it )). +/// +/// Color for faces. +/// That's happening when attribute "colorPerVertex" is set to "false". But Assimp do not hold how many colors has mesh and reuire +/// equal length for mVertices and mColors. You will see the colors but vertices will use call which last used in "colorIdx". +/// +/// That's all for now. Enjoy +/// +class X3DImporter : public BaseImporter +{ + /***********************************************/ + /******************** Types ********************/ + /***********************************************/ + + /***********************************************/ + /****************** Constants ******************/ + /***********************************************/ + +private: + + static const aiImporterDesc Description; + + /***********************************************/ + /****************** Variables ******************/ + /***********************************************/ + +private: + + CX3DImporter_NodeElement* NodeElement_Cur;///< Current element. + irr::io::IrrXMLReader* mReader;///< Pointer to XML-reader object + std::string mFileDir; + +public: + + std::list NodeElement_List;///< All elements of scene graph. + + /***********************************************/ + /****************** Functions ******************/ + /***********************************************/ + +private: + + /// \fn X3DImporter(const X3DImporter& pScene) + /// Disabled copy constructor. + X3DImporter(const X3DImporter& pScene); + + /// \fn X3DImporter& operator=(const X3DImporter& pScene) + /// Disabled assign operator. + X3DImporter& operator=(const X3DImporter& pScene); + + /// \fn void Clear() + /// Clear all temporary data. + void Clear(); + + /***********************************************/ + /************* Functions: find set *************/ + /***********************************************/ + + /// \fn bool FindNodeElement_FromRoot(const std::string& pID, const CX3DImporter_NodeElement::EType pType, CX3DImporter_NodeElement** pElement) + /// Find requested node element. Search will be made in all existing nodes. + /// \param [in] pID - ID of requested element. + /// \param [in] pType - type of requested element. + /// \param [out] pElement - pointer to pointer to item found. + /// \return true - if the element is found, else - false. + bool FindNodeElement_FromRoot(const std::string& pID, const CX3DImporter_NodeElement::EType pType, CX3DImporter_NodeElement** pElement); + + /// \fn bool FindNodeElement_FromNode(CX3DImporter_NodeElement* pStartNode, const std::string& pID, const CX3DImporter_NodeElement::EType pType, CX3DImporter_NodeElement** pElement) + /// Find requested node element. Search will be made from pointed node down to childs. + /// \param [in] pStartNode - pointer to start node. + /// \param [in] pID - ID of requested element. + /// \param [in] pType - type of requested element. + /// \param [out] pElement - pointer to pointer to item found. + /// \return true - if the element is found, else - false. + bool FindNodeElement_FromNode(CX3DImporter_NodeElement* pStartNode, const std::string& pID, const CX3DImporter_NodeElement::EType pType, + CX3DImporter_NodeElement** pElement); + + /// \fn bool FindNodeElement(const std::string& pName, const CX3DImporter_NodeElement::EType pType, CX3DImporter_NodeElement** pElement) + /// Find requested node element. For "Node"'s accounting flag "Static". + /// \param [in] pName - name of requested element. + /// \param [in] pType - type of requested element. + /// \param [out] pElement - pointer to pointer to item found. + /// \return true - if the element is found, else - false. + bool FindNodeElement(const std::string& pName, const CX3DImporter_NodeElement::EType pType, CX3DImporter_NodeElement** pElement); + + /***********************************************/ + /********* Functions: postprocess set **********/ + /***********************************************/ + + /// \fn aiMatrix4x4 PostprocessHelper_Matrix_GlobalToCurrent() const + /// \return transformation matrix from global coordinate system to local. + aiMatrix4x4 PostprocessHelper_Matrix_GlobalToCurrent() const; + + /// \fn void PostprocessHelper_CollectMetadata(const CX3DImporter_NodeElement& pNodeElement, std::list& pList) const + /// Check if child elements of node element is metadata and add it to temporary list. + /// \param [in] pNodeElement - node element where metadata is searching. + /// \param [out] pList - temporary list for collected metadata. + void PostprocessHelper_CollectMetadata(const CX3DImporter_NodeElement& pNodeElement, std::list& pList) const; + + /// \fn bool bool PostprocessHelper_ElementIsMetadata(const CX3DImporter_NodeElement::EType pType) const + /// Check if type of node element is metadata. E.g. , . + /// \param [in] pType - checked type. + /// \return true - if the type corresponds to the metadata. + bool PostprocessHelper_ElementIsMetadata(const CX3DImporter_NodeElement::EType pType) const; + + /// \fn bool PostprocessHelper_ElementIsMesh(const CX3DImporter_NodeElement::EType pType) const + /// Check if type of node element is geometry object and can be used to build mesh. E.g. , . + /// \param [in] pType - checked type. + /// \return true - if the type corresponds to the mesh. + bool PostprocessHelper_ElementIsMesh(const CX3DImporter_NodeElement::EType pType) const; + + /// \fn void Postprocess_BuildLight(const CX3DImporter_NodeElement& pNodeElement, std::list& pSceneLightList) const + /// Read CX3DImporter_NodeElement_Light, create aiLight and add it to list of the lights. + /// \param [in] pNodeElement - reference to lisght element(, , ). + /// \param [out] pSceneLightList - reference to list of the lights. + void Postprocess_BuildLight(const CX3DImporter_NodeElement& pNodeElement, std::list& pSceneLightList) const; + + /// \fn void Postprocess_BuildMaterial(const CX3DImporter_NodeElement& pNodeElement, aiMaterial** pMaterial) const + /// Create filled structure with type \ref aiMaterial from \ref CX3DImporter_NodeElement. This function itseld extract + /// all needed data from scene graph. + /// \param [in] pNodeElement - reference to material element(). + /// \param [out] pMaterial - pointer to pointer to created material. *pMaterial must be NULL. + void Postprocess_BuildMaterial(const CX3DImporter_NodeElement& pNodeElement, aiMaterial** pMaterial) const; + + /// \fn void Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeElement, aiMesh** pMesh) const + /// Create filled structure with type \ref aiMaterial from \ref CX3DImporter_NodeElement. This function itseld extract + /// all needed data from scene graph. + /// \param [in] pNodeElement - reference to geometry object. + /// \param [out] pMesh - pointer to pointer to created mesh. *pMesh must be NULL. + void Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeElement, aiMesh** pMesh) const; + + /// \fn void Postprocess_BuildNode(const CX3DImporter_NodeElement& pNodeElement, aiNode& pSceneNode, std::list& pSceneMeshList, std::list& pSceneMaterialList, std::list& pSceneLightList) const + /// Create aiNode from CX3DImporter_NodeElement. Also function check children and make recursive call. + /// \param [out] pNode - pointer to pointer to created node. *pNode must be NULL. + /// \param [in] pNodeElement - CX3DImporter_NodeElement which read. + /// \param [out] pSceneNode - aiNode for filling. + /// \param [out] pSceneMeshList - list with aiMesh which belong to scene. + /// \param [out] pSceneMaterialList - list with aiMaterial which belong to scene. + /// \param [out] pSceneLightList - list with aiLight which belong to scene. + void Postprocess_BuildNode(const CX3DImporter_NodeElement& pNodeElement, aiNode& pSceneNode, std::list& pSceneMeshList, + std::list& pSceneMaterialList, std::list& pSceneLightList) const; + + /// \fn void Postprocess_BuildShape(const CX3DImporter_NodeElement_Shape& pShapeNodeElement, std::list& pNodeMeshInd, std::list& pSceneMeshList, std::list& pSceneMaterialList) const + /// To create mesh and material kept in . + /// \param pShapeNodeElement - reference to node element which kept data. + /// \param pNodeMeshInd - reference to list with mesh indices. When pShapeNodeElement will read new mesh index will be added to this list. + /// \param pSceneMeshList - reference to list with meshes. When pShapeNodeElement will read new mesh will be added to this list. + /// \param pSceneMaterialList - reference to list with materials. When pShapeNodeElement will read new material will be added to this list. + void Postprocess_BuildShape(const CX3DImporter_NodeElement_Shape& pShapeNodeElement, std::list& pNodeMeshInd, + std::list& pSceneMeshList, std::list& pSceneMaterialList) const; + + /// \fn void Postprocess_CollectMetadata(aiNode& pSceneNode, const CX3DImporter_NodeElement& pNodeElement) const + /// Check if child elements of node element is metadata and add it to scene node. + /// \param [in] pNodeElement - node element where metadata is searching. + /// \param [out] pSceneNode - scene node in which metadata will be added. + void Postprocess_CollectMetadata(const CX3DImporter_NodeElement& pNodeElement, aiNode& pSceneNode) const; + + /***********************************************/ + /************* Functions: throw set ************/ + /***********************************************/ + + /// \fn void Throw_ArgOutOfRange(const std::string& pArgument) + /// Call that function when argument is out of range and exception must be raised. + /// \throw DeadlyImportError. + /// \param [in] pArgument - argument name. + void Throw_ArgOutOfRange(const std::string& pArgument); + + /// \fn void Throw_CloseNotFound(const std::string& pNode) + /// Call that function when close tag of node not found and exception must be raised. + /// E.g.: + /// + /// + /// + /// \throw DeadlyImportError. + /// \param [in] pNode - node name in which exception happened. + void Throw_CloseNotFound(const std::string& pNode); + + /// \fn void Throw_ConvertFail_Str2ArrF(const std::string& pAttrValue) + /// Call that function when string value can not be converted to floating point value and exception must be raised. + /// \param [in] pAttrValue - attribute value. + /// \throw DeadlyImportError. + void Throw_ConvertFail_Str2ArrF(const std::string& pAttrValue); + + /// \fn void Throw_DEF_And_USE() + /// Call that function when in node defined attributes "DEF" and "USE" and exception must be raised. + /// E.g.: + /// \throw DeadlyImportError. + void Throw_DEF_And_USE(); + + /// \fn void Throw_IncorrectAttr(const std::string& pAttrName) + /// Call that function when attribute name is incorrect and exception must be raised. + /// \param [in] pAttrName - attribute name. + /// \throw DeadlyImportError. + void Throw_IncorrectAttr(const std::string& pAttrName); + + /// \fn void Throw_IncorrectAttrValue(const std::string& pAttrName) + /// Call that function when attribute value is incorrect and exception must be raised. + /// \param [in] pAttrName - attribute name. + /// \throw DeadlyImportError. + void Throw_IncorrectAttrValue(const std::string& pAttrName); + + /// \fn void Throw_MoreThanOnceDefined(const std::string& pNode, const std::string& pDescription) + /// Call that function when some type of nodes are defined twice or more when must be used only once and exception must be raised. + /// E.g.: + /// + /// + /// + /// + /// \throw DeadlyImportError. + /// \param [in] pNodeType - type of node which defined one more time. + /// \param [in] pDescription - message about error. E.g. what the node defined while exception raised. + void Throw_MoreThanOnceDefined(const std::string& pNodeType, const std::string& pDescription); + + /// \fn void Throw_TagCountIncorrect(const std::string& pNode) + /// Call that function when count of opening and closing tags which create group(e.g. ) are not equal and exception must be raised. + /// E.g.: + /// + /// + /// + /// + /// + /// \throw DeadlyImportError. + /// \param [in] pNode - node name in which exception happened. + void Throw_TagCountIncorrect(const std::string& pNode); + + /// \fn void Throw_USE_NotFound(const std::string& pAttrValue) + /// Call that function when defined in "USE" element are not found in graph and exception must be raised. + /// \param [in] pAttrValue - "USE" attribute value. + /// \throw DeadlyImportError. + void Throw_USE_NotFound(const std::string& pAttrValue); + + /***********************************************/ + /************** Functions: LOG set *************/ + /***********************************************/ + + /// \fn void LogInfo(const std::string& pMessage) + /// Short variant for calling \ref DefaultLogger::get()->info() + void LogInfo(const std::string& pMessage) { DefaultLogger::get()->info(pMessage); } + + /// \fn void LogWarning(const std::string& pMessage) + /// Short variant for calling \ref DefaultLogger::get()->warn() + void LogWarning(const std::string& pMessage) { DefaultLogger::get()->warn(pMessage); } + + /// \fn void LogError(const std::string& pMessage) + /// Short variant for calling \ref DefaultLogger::get()->error() + void LogError(const std::string& pMessage) { DefaultLogger::get()->error(pMessage); } + + /***********************************************/ + /************** Functions: XML set *************/ + /***********************************************/ + + /// \fn void XML_CheckNode_MustBeEmpty() + /// Chek if current node is empty: . If not then exception will throwed. + void XML_CheckNode_MustBeEmpty(); + + /// \fn bool XML_CheckNode_NameEqual(const std::string& pNodeName) + /// Chek if current node name is equal to pNodeName. + /// \param [in] pNodeName - name for checking. + /// return true if current node name is equal to pNodeName, else - false. + bool XML_CheckNode_NameEqual(const std::string& pNodeName) { return mReader->getNodeName() == pNodeName; } + + /// \fn void XML_CheckNode_SkipUnsupported(const std::string& pParentNodeName) + /// Skip unsupported node and report about that. Depend on node name can be skipped begin tag of node all whole node. + /// \param [in] pParentNodeName - parent node name. Used for reporting. + void XML_CheckNode_SkipUnsupported(const std::string& pParentNodeName); + + /// \fn bool XML_SearchNode(const std::string& pNodeName) + /// Search for specified node in file. XML file read pointer(mReader) will point to found node or file end after search is end. + /// \param [in] pNodeName - requested node name. + /// return true - if node is found, else - false. + bool XML_SearchNode(const std::string& pNodeName); + + /// \fn bool XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx) + /// Read attribute value. + /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). + /// \return read data. + bool XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx); + + /// \fn float XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx) + /// Read attribute value. + /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). + /// \return read data. + float XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx); + + /// \fn int32_t XML_ReadNode_GetAttrVal_AsI32(const int pAttrIdx) + /// Read attribute value. + /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). + /// \return read data. + int32_t XML_ReadNode_GetAttrVal_AsI32(const int pAttrIdx); + + /// \fn void XML_ReadNode_GetAttrVal_AsCol3f(const int pAttrIdx, aiColor3D& pValue) + /// Read attribute value. + /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). + /// \param [out] pValue - read data. + void XML_ReadNode_GetAttrVal_AsCol3f(const int pAttrIdx, aiColor3D& pValue); + + /// \fn void XML_ReadNode_GetAttrVal_AsVec2f(const int pAttrIdx, aiVector2D& pValue) + /// Read attribute value. + /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). + /// \param [out] pValue - read data. + void XML_ReadNode_GetAttrVal_AsVec2f(const int pAttrIdx, aiVector2D& pValue); + + /// \fn void XML_ReadNode_GetAttrVal_AsVec3f(const int pAttrIdx, aiVector3D& pValue) + /// Read attribute value. + /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). + /// \param [out] pValue - read data. + void XML_ReadNode_GetAttrVal_AsVec3f(const int pAttrIdx, aiVector3D& pValue); + + /// \fn void XML_ReadNode_GetAttrVal_AsListB(const int pAttrIdx, std::list& pValue) + /// Read attribute value. + /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). + /// \param [out] pValue - read data. + void XML_ReadNode_GetAttrVal_AsListB(const int pAttrIdx, std::list& pValue); + + /// \fn void XML_ReadNode_GetAttrVal_AsArrB(const int pAttrIdx, std::vector& pValue) + /// \overload void XML_ReadNode_GetAttrVal_AsListBool(const int pAttrIdx, std::list& pValue) + void XML_ReadNode_GetAttrVal_AsArrB(const int pAttrIdx, std::vector& pValue); + + /// \fn void XML_ReadNode_GetAttrVal_AsListI32(const int pAttrIdx, std::list& pValue) + /// Read attribute value. + /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). + /// \param [out] pValue - read data. + void XML_ReadNode_GetAttrVal_AsListI32(const int pAttrIdx, std::list& pValue); + + /// \fn void XML_ReadNode_GetAttrVal_AsArrI32(const int pAttrIdx, std::vector& pValue) + /// \overload void XML_ReadNode_GetAttrVal_AsListI32(const int pAttrIdx, std::list& pValue) + void XML_ReadNode_GetAttrVal_AsArrI32(const int pAttrIdx, std::vector& pValue); + + /// \fn void XML_ReadNode_GetAttrVal_AsListF(const int pAttrIdx, std::list& pValue) + /// Read attribute value. + /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). + /// \param [out] pValue - read data. + void XML_ReadNode_GetAttrVal_AsListF(const int pAttrIdx, std::list& pValue); + + /// \fn void XML_ReadNode_GetAttrVal_AsArrF(const int pAttrIdx, std::vector& pValue) + /// \overload void XML_ReadNode_GetAttrVal_AsListF(const int pAttrIdx, std::list& pValue) + void XML_ReadNode_GetAttrVal_AsArrF(const int pAttrIdx, std::vector& pValue); + + /// \fn void XML_ReadNode_GetAttrVal_AsListD(const int pAttrIdx, std::list& pValue) + /// Read attribute value. + /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). + /// \param [out] pValue - read data. + void XML_ReadNode_GetAttrVal_AsListD(const int pAttrIdx, std::list& pValue); + + /// \fn void XML_ReadNode_GetAttrVal_AsArrD(const int pAttrIdx, std::vector& pValue) + /// \overload void XML_ReadNode_GetAttrVal_AsListD(const int pAttrIdx, std::list& pValue) + void XML_ReadNode_GetAttrVal_AsArrD(const int pAttrIdx, std::vector& pValue); + + /// \fn void XML_ReadNode_GetAttrVal_AsListCol3f(const int pAttrIdx, std::list& pValue) + /// Read attribute value. + /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). + /// \param [out] pValue - read data. + void XML_ReadNode_GetAttrVal_AsListCol3f(const int pAttrIdx, std::list& pValue); + + /// \fn void XML_ReadNode_GetAttrVal_AsArrCol3f(const int pAttrIdx, std::vector& pValue) + /// \overload void XML_ReadNode_GetAttrVal_AsListCol3f(const int pAttrIdx, std::vector& pValue) + void XML_ReadNode_GetAttrVal_AsArrCol3f(const int pAttrIdx, std::vector& pValue); + + /// \fn void XML_ReadNode_GetAttrVal_AsListCol4f(const int pAttrIdx, std::list& pValue) + /// Read attribute value. + /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). + /// \param [out] pValue - read data. + void XML_ReadNode_GetAttrVal_AsListCol4f(const int pAttrIdx, std::list& pValue); + + /// \fn void XML_ReadNode_GetAttrVal_AsArrCol4f(const int pAttrIdx, std::vector& pValue) + /// \overload void XML_ReadNode_GetAttrVal_AsListCol4f(const int pAttrIdx, std::list& pValue) + void XML_ReadNode_GetAttrVal_AsArrCol4f(const int pAttrIdx, std::vector& pValue); + + /// \fn void XML_ReadNode_GetAttrVal_AsListVec2f(const int pAttrIdx, std::list& pValue) + /// Read attribute value. + /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). + /// \param [out] pValue - read data. + void XML_ReadNode_GetAttrVal_AsListVec2f(const int pAttrIdx, std::list& pValue); + + /// \fn void XML_ReadNode_GetAttrVal_AsArrVec2f(const int pAttrIdx, std::vector& pValue) + /// \overload void XML_ReadNode_GetAttrVal_AsListVec2f(const int pAttrIdx, std::list& pValue) + void XML_ReadNode_GetAttrVal_AsArrVec2f(const int pAttrIdx, std::vector& pValue); + + /// \fn void XML_ReadNode_GetAttrVal_AsListVec3f(const int pAttrIdx, std::list& pValue) + /// Read attribute value. + /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). + /// \param [out] pValue - read data. + void XML_ReadNode_GetAttrVal_AsListVec3f(const int pAttrIdx, std::list& pValue); + + /// \fn void XML_ReadNode_GetAttrVal_AsArrVec3f(const int pAttrIdx, std::vector& pValue) + /// \overload void XML_ReadNode_GetAttrVal_AsListVec3f(const int pAttrIdx, std::list& pValue) + void XML_ReadNode_GetAttrVal_AsArrVec3f(const int pAttrIdx, std::vector& pValue); + + /// \fn void XML_ReadNode_GetAttrVal_AsListS(const int pAttrIdx, std::list& pValue) + /// Read attribute value. + /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). + /// \param [out] pValue - read data. + void XML_ReadNode_GetAttrVal_AsListS(const int pAttrIdx, std::list& pValue); + + /***********************************************/ + /******* Functions: geometry helper set *******/ + /***********************************************/ + + /// \fn aiVector3D GeometryHelper_Make_Point2D(const float pAngle, const float pRadius) + /// Make point on surface oXY. + /// \param [in] pAngle - angle in radians between radius-vector of point and oX axis. Angle extends from the oX axis counterclockwise to the radius-vector. + /// \param [in] pRadius - length of radius-vector. + /// \return made point coordinates. + aiVector3D GeometryHelper_Make_Point2D(const float pAngle, const float pRadius); + + /// \fn void GeometryHelper_Make_Arc2D(const float pStartAngle, const float pEndAngle, const float pRadius, size_t pNumSegments, std::list& pVertices) + /// Make 2D figure - linear circular arc with center in (0, 0). The z-coordinate is 0. The arc extends from the pStartAngle counterclockwise + /// to the pEndAngle. If pStartAngle and pEndAngle have the same value, a circle is specified. If the absolute difference between pStartAngle + /// and pEndAngle is greater than or equal to 2pi, a circle is specified. + /// \param [in] pStartAngle - angle in radians of start of the arc. + /// \param [in] pEndAngle - angle in radians of end of the arc. + /// \param [in] pRadius - radius of the arc. + /// \param [out] pNumSegments - number of segments in arc. In other words - tesselation factor. + /// \param [out] pVertices - generated vertices. + void GeometryHelper_Make_Arc2D(const float pStartAngle, const float pEndAngle, const float pRadius, size_t pNumSegments, std::list& pVertices); + + /// \fn void GeometryHelper_Extend_PointToLine(const std::list& pPoint, std::list& pLine) + /// Create line set from point set. + /// \param [in] pPoint - input points list. + /// \param [out] pLine - made lines list. + void GeometryHelper_Extend_PointToLine(const std::list& pPoint, std::list& pLine); + + /// \fn GeometryHelper_Extend_PolylineIdxToLineIdx(const std::list& pPolylineCoordIdx, std::list& pLineCoordIdx) + /// Create CoordIdx of line set from CoordIdx of polyline set. + /// \param [in] pPolylineCoordIdx - vertices indices divided by delimiter "-1". Must contain faces with two or more indices. + /// \param [out] pLineCoordIdx - made CoordIdx of line set. + void GeometryHelper_Extend_PolylineIdxToLineIdx(const std::list& pPolylineCoordIdx, std::list& pLineCoordIdx); + + /// \fn void GeometryHelper_MakeQL_RectParallelepiped(const aiVector3D& pSize, std::list& pVertices) + /// Make 3D body - rectangular parallelepiped with center in (0, 0). QL mean quadlist (\sa pVertices). + /// \param [in] pSize - scale factor for body for every axis. E.g. (1, 2, 1) mean: X-size and Z-size - 1, Y-size - 2. + /// \param [out] pVertices - generated vertices. The list of vertices is grouped in quads. + void GeometryHelper_MakeQL_RectParallelepiped(const aiVector3D& pSize, std::list& pVertices); + + /// \fn void GeometryHelper_CoordIdxStr2FacesArr(const std::list& pCoordIdx, std::vector& pFaces, unsigned int& pPrimitiveTypes) const + /// Create faces array from vertices indices array. + /// \param [in] pCoordIdx - vertices indices divided by delimiter "-1". + /// \param [in] pFaces - created faces array. + /// \param [in] pPrimitiveTypes - type of primitives in faces. + void GeometryHelper_CoordIdxStr2FacesArr(const std::list& pCoordIdx, std::vector& pFaces, unsigned int& pPrimitiveTypes) const; + + /// \fn void MeshGeometry_AddColor(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pColors, const bool pColorPerVertex) const + /// Add colors to mesh. + /// a. If colorPerVertex is FALSE, colours are applied to each face, as follows: + /// If the colorIndex field is not empty, one colour is used for each face of the mesh. There shall be at least as many indices in the + /// colorIndex field as there are faces in the mesh. The colorIndex field shall not contain any negative entries. + /// If the colorIndex field is empty, the colours in the X3DColorNode node are applied to each face of the mesh in order. + /// There shall be at least as many colours in the X3DColorNode node as there are faces. + /// b. If colorPerVertex is TRUE, colours are applied to each vertex, as follows: + /// If the colorIndex field is not empty, colours are applied to each vertex of the mesh in exactly the same manner that the coordIndex + /// field is used to choose coordinates for each vertex from the node. The colorIndex field shall contain end-of-face markers (−1) + /// in exactly the same places as the coordIndex field. + /// If the colorIndex field is empty, the coordIndex field is used to choose colours from the X3DColorNode node. + /// \param [in] pMesh - mesh for adding data. + /// \param [in] pCoordIdx - vertices indices divided by delimiter "-1". + /// \param [in] pColorIdx - color indices for every vertex divided by delimiter "-1" if \ref pColorPerVertex is true. if \ref pColorPerVertex is false + /// then pColorIdx contain color indices for every faces and must not contain delimiter "-1". + /// \param [in] pColors - defined colors. + /// \param [in] pColorPerVertex - if \ref pColorPerVertex is true then color in \ref pColors defined for every vertex, if false - for every face. + void MeshGeometry_AddColor(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pColorIdx, + const std::list& pColors, const bool pColorPerVertex) const; + + /// \fn void MeshGeometry_AddColor(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pColorIdx, const std::list& pColors, const bool pColorPerVertex) const; + /// \overload void MeshGeometry_AddColor(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pColorIdx, const std::list& pColors, const bool pColorPerVertex) const; + void MeshGeometry_AddColor(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pColorIdx, + const std::list& pColors, const bool pColorPerVertex) const; + + /// \fn void MeshGeometry_AddColor(aiMesh& pMesh, const std::list& pColors, const bool pColorPerVertex) const + /// Add colors to mesh. + /// \param [in] pMesh - mesh for adding data. + /// \param [in] pColors - defined colors. + /// \param [in] pColorPerVertex - if \ref pColorPerVertex is true then color in \ref pColors defined for every vertex, if false - for every face. + void MeshGeometry_AddColor(aiMesh& pMesh, const std::list& pColors, const bool pColorPerVertex) const; + + /// \fn void MeshGeometry_AddColor(aiMesh& pMesh, const std::list& pColors, const bool pColorPerVertex) const + /// \overload void MeshGeometry_AddColor(aiMesh& pMesh, const std::list& pColors, const bool pColorPerVertex) const + void MeshGeometry_AddColor(aiMesh& pMesh, const std::list& pColors, const bool pColorPerVertex) const; + + /// \fn void MeshGeometry_AddNormal(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pNormalIdx, const std::list& pNormals, const bool pNormalPerVertex) const + /// Add normals to mesh. Function work similar to \ref MeshGeometry_AddColor; + void MeshGeometry_AddNormal(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pNormalIdx, + const std::list& pNormals, const bool pNormalPerVertex) const; + + /// \fn void MeshGeometry_AddNormal(aiMesh& pMesh, const std::list& pNormals, const bool pNormalPerVertex) const + /// Add normals to mesh. Function work similar to \ref MeshGeometry_AddColor; + void MeshGeometry_AddNormal(aiMesh& pMesh, const std::list& pNormals, const bool pNormalPerVertex) const; + + /// \fn void MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pTexCoordIdx, const std::list& pTexCoords) const + /// Add texture coordinates to mesh. Function work similar to \ref MeshGeometry_AddColor; + void MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pTexCoordIdx, + const std::list& pTexCoords) const; + + /// \fn void MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::list& pTexCoords) const + /// Add texture coordinates to mesh. Function work similar to \ref MeshGeometry_AddColor; + void MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::list& pTexCoords) const; + + /// \fn aiMesh* GeometryHelper_MakeMesh(const std::list& pCoordIdx, const std::list& pVertices) const + /// Create mesh. + /// \param [in] pCoordIdx - vertices indices divided by delimiter "-1". + /// \param [in] pVertices - vertices of mesh. + /// \return created mesh. + aiMesh* GeometryHelper_MakeMesh(const std::list& pCoordIdx, const std::list& pVertices) const; + + /***********************************************/ + /******** Functions: parse set private *********/ + /***********************************************/ + + /// \fn void ParseHelper_Group_Begin() + /// Create node element with type "Node" in scene graph. That operation is needed when you enter to X3D group node + /// like , etc. When exiting from X3D group node(e.g. ) \ref ParseHelper_Node_Exit must + /// be called. + /// \param [in] pStatic - flag: if true then static node is created(e.g. ). + void ParseHelper_Group_Begin(const bool pStatic = false); + + /// \fn void ParseHelper_Node_Enter(CX3DImporter_NodeElement* pNode) + /// Make pNode as current and enter deeper for parsing child nodes. At end \ref ParseHelper_Node_Exit must be called. + /// \param [in] pNode - new current node. + void ParseHelper_Node_Enter(CX3DImporter_NodeElement* pNode); + + /// \fn void ParseHelper_Group_End() + /// This function must be called when exiting from X3D group node(e.g. ). \ref ParseHelper_Group_Begin. + void ParseHelper_Node_Exit(); + + /// \fn void ParseHelper_FixTruncatedFloatString(const char* pInStr, std::string& pOutString) + /// Attribute values of floating point types can take form ".x"(without leading zero). irrXMLReader can not read this form of values and it + /// must be converted to right form - "0.xxx". + /// \param [in] pInStr - pointer to input string which can contain incorrect form of values. + /// \param [out[ pOutString - output string with right form of values. + void ParseHelper_FixTruncatedFloatString(const char* pInStr, std::string& pOutString); + + /// \fn bool ParseHelper_CheckRead_X3DMetadataObject() + /// Check if current node has nodes of type X3DMetadataObject. Why we must do it? Because X3DMetadataObject can be in any non-empty X3DNode. + /// Meaning that X3DMetadataObject can be in any non-empty node in . + /// \return true - if metadata node are found and parsed, false - metadata not found. + bool ParseHelper_CheckRead_X3DMetadataObject(); + + /// \fn bool ParseHelper_CheckRead_X3DMetadataObject() + /// Check if current node has nodes of type X3DGeometricPropertyNode. X3DGeometricPropertyNode + /// X3DGeometricPropertyNode inheritors: + /// , , , , , , , , + /// , , , , , + /// , , . + /// \return true - if nodes are found and parsed, false - nodes not found. + bool ParseHelper_CheckRead_X3DGeometricPropertyNode(); + + /// \fn void ParseNode_Root() + /// Parse node of the file. + void ParseNode_Root(); + + /// \fn void ParseNode_Head() + /// Parse node of the file. + void ParseNode_Head(); + + /// \fn void ParseNode_Root() + /// Parse node of the file. + void ParseNode_Scene(); + + /// \fn void ParseNode_Metadata(CX3DImporter_NodeElement* pParent, const std::string& pNodeName) + /// Parse child nodes of node. + /// \param [in] pNodeName - parsed node name. Must be set because that function is general and name needed for checking the end + /// and error reporing. + /// \param [in] pParentElement - parent metadata element. + void ParseNode_Metadata(CX3DImporter_NodeElement* pParentElement, const std::string& pNodeName); + + /// \fn void ParseNode_MetadataBoolean() + /// Parse node of the file. + void ParseNode_MetadataBoolean(); + + /// \fn void ParseNode_MetadataDouble() + /// Parse node of the file. + void ParseNode_MetadataDouble(); + + /// \fn void ParseNode_MetadataFloat() + /// Parse node of the file. + void ParseNode_MetadataFloat(); + + /// \fn void ParseNode_MetadataInteger() + /// Parse node of the file. + void ParseNode_MetadataInteger(); + + /// \fn void ParseNode_MetadataSet() + /// Parse node of the file. + void ParseNode_MetadataSet(); + + /// \fn void ParseNode_MetadataString() + /// Parse node of the file. + void ParseNode_MetadataString(); + + /// \fn void ParseNode_Geometry2D_Arc2D() + /// Parse node of the file. + void ParseNode_Geometry2D_Arc2D(); + + /// \fn void ParseNode_Geometry2D_ArcClose2D() + /// Parse node of the file. + void ParseNode_Geometry2D_ArcClose2D(); + + /// \fn void ParseNode_Geometry2D_Circle2D() + /// Parse node of the file. + void ParseNode_Geometry2D_Circle2D(); + + /// \fn void ParseNode_Geometry2D_Disk2D() + /// Parse node of the file. + void ParseNode_Geometry2D_Disk2D(); + + /// \fn void ParseNode_Geometry2D_Polyline2D() + /// Parse node of the file. + void ParseNode_Geometry2D_Polyline2D(); + + /// \fn void ParseNode_Geometry2D_Polypoint2D() + /// Parse node of the file. + void ParseNode_Geometry2D_Polypoint2D(); + + /// \fn void ParseNode_Geometry2D_Rectangle2D() + /// Parse node of the file. + void ParseNode_Geometry2D_Rectangle2D(); + + /// \fn void ParseNode_Geometry2D_TriangleSet2D() + /// Parse node of the file. + void ParseNode_Geometry2D_TriangleSet2D(); + + /// \fn void ParseNode_Geometry3D_Box() + /// Parse node of the file. + void ParseNode_Geometry3D_Box(); + + /// \fn void ParseNode_Geometry3D_Cone() + /// Parse node of the file. + void ParseNode_Geometry3D_Cone(); + + /// \fn void ParseNode_Geometry3D_Cylinder() + /// Parse node of the file. + void ParseNode_Geometry3D_Cylinder(); + + /// \fn void ParseNode_Geometry3D_ElevationGrid() + /// Parse node of the file. + void ParseNode_Geometry3D_ElevationGrid(); + + /// \fn void ParseNode_Geometry3D_Extrusion() + /// Parse node of the file. + void ParseNode_Geometry3D_Extrusion(); + + /// \fn void ParseNode_Geometry3D_IndexedFaceSet() + /// Parse node of the file. + void ParseNode_Geometry3D_IndexedFaceSet(); + + /// \fn void ParseNode_Geometry3D_Sphere() + /// Parse node of the file. + void ParseNode_Geometry3D_Sphere(); + + /// \fn void ParseNode_Grouping_Group() + /// Parse node of the file. And create new node in scene graph. + void ParseNode_Grouping_Group(); + + /// \fn void ParseNode_Grouping_GroupEnd() + /// Doing actions at an exit from . Walk up in scene graph. + void ParseNode_Grouping_GroupEnd(); + + /// \fn void ParseNode_Grouping_StaticGroup() + /// Parse node of the file. And create new node in scene graph. + void ParseNode_Grouping_StaticGroup(); + + /// \fn void ParseNode_Grouping_StaticGroupEnd() + /// Doing actions at an exit from . Walk up in scene graph. + void ParseNode_Grouping_StaticGroupEnd(); + + /// \fn void ParseNode_Grouping_Switch() + /// Parse node of the file. And create new node in scene graph. + void ParseNode_Grouping_Switch(); + + /// \fn void ParseNode_Grouping_SwitchEnd() + /// Doing actions at an exit from . Walk up in scene graph. + void ParseNode_Grouping_SwitchEnd(); + + /// \fn void ParseNode_Grouping_Transform() + /// Parse node of the file. And create new node in scene graph. + void ParseNode_Grouping_Transform(); + + /// \fn void ParseNode_Grouping_TransformEnd() + /// Doing actions at an exit from . Walk up in scene graph. + void ParseNode_Grouping_TransformEnd(); + + /// \fn void ParseNode_Rendering_Color() + /// Parse node of the file. + void ParseNode_Rendering_Color(); + + /// \fn void ParseNode_Rendering_ColorRGBA() + /// Parse node of the file. + void ParseNode_Rendering_ColorRGBA(); + + /// \fn void ParseNode_Rendering_Coordinate() + /// Parse node of the file. + void ParseNode_Rendering_Coordinate(); + + /// \fn void ParseNode_Rendering_Normal() + /// Parse node of the file. + void ParseNode_Rendering_Normal(); + + /// \fn void ParseNode_Rendering_IndexedLineSet() + /// Parse node of the file. + void ParseNode_Rendering_IndexedLineSet(); + + /// \fn void ParseNode_Rendering_IndexedTriangleFanSet() + /// Parse node of the file. + void ParseNode_Rendering_IndexedTriangleFanSet(); + + /// \fn void ParseNode_Rendering_IndexedTriangleSet() + /// Parse node of the file. + void ParseNode_Rendering_IndexedTriangleSet(); + + /// \fn void ParseNode_Rendering_IndexedTriangleStripSet() + /// Parse node of the file. + void ParseNode_Rendering_IndexedTriangleStripSet(); + + /// \fn void ParseNode_Rendering_LineSet() + /// Parse node of the file. + void ParseNode_Rendering_LineSet(); + + /// \fn void ParseNode_Rendering_PointSet() + /// Parse node of the file. + void ParseNode_Rendering_PointSet(); + + /// \fn void ParseNode_Rendering_TriangleFanSet() + /// Parse node of the file. + void ParseNode_Rendering_TriangleFanSet(); + + /// \fn void ParseNode_Rendering_TriangleSet() + /// Parse node of the file. + void ParseNode_Rendering_TriangleSet(); + + /// \fn void ParseNode_Rendering_TriangleStripSet() + /// Parse node of the file. + void ParseNode_Rendering_TriangleStripSet(); + + /// \fn void ParseNode_Texturing_ImageTexture() + /// Parse node of the file. + void ParseNode_Texturing_ImageTexture(); + + /// \fn void ParseNode_Texturing_TextureCoordinate() + /// Parse node of the file. + void ParseNode_Texturing_TextureCoordinate(); + + /// \fn void ParseNode_Texturing_TextureTransform() + /// Parse node of the file. + void ParseNode_Texturing_TextureTransform(); + + /// \fn void ParseNode_Shape_Shape() + /// Parse node of the file. + void ParseNode_Shape_Shape(); + + /// \fn void ParseNode_Shape_Appearance() + /// Parse node of the file. + void ParseNode_Shape_Appearance(); + + /// \fn void ParseNode_Shape_Material() + /// Parse node of the file. + void ParseNode_Shape_Material(); + + /// \fn void ParseNode_Networking_Inline() + /// Parse node of the file. + void ParseNode_Networking_Inline(); + + /// \fn void ParseNode_Lighting_DirectionalLight() + /// Parse node of the file. + void ParseNode_Lighting_DirectionalLight(); + + /// \fn void ParseNode_Lighting_PointLight() + /// Parse node of the file. + void ParseNode_Lighting_PointLight(); + + /// \fn void ParseNode_Lighting_SpotLight() + /// Parse node of the file. + void ParseNode_Lighting_SpotLight(); + +public: + + /// \fn X3DImporter() + /// Default constructor. + X3DImporter() + : NodeElement_Cur(NULL), mReader(NULL) + {} + + /// \fn ~X3DImporter() + /// Default destructor. + ~X3DImporter(); + + /***********************************************/ + /******** Functions: parse set, public *********/ + /***********************************************/ + + /// \fn void ParseFile(const std::string& pFile, IOSystem* pIOHandler) + /// Parse X3D file and fill scene graph. The function has no return value. Result can be found by analyzing the generated graph. + /// Also exception can be throwed if trouble will found. + /// \param [in] pFile - name of file to be parsed. + /// \param [in] pIOHandler - pointer to IO helper object. + void ParseFile(const std::string& pFile, IOSystem* pIOHandler); + + /***********************************************/ + /********* Functions: BaseImporter set *********/ + /***********************************************/ + + bool CanRead(const std::string& pFile, IOSystem* pIOHandler, bool pCheckSig) const; + void GetExtensionList(std::set& pExtensionList); + void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); + const aiImporterDesc* GetInfo ()const; + +};// class X3DImporter + +}// namespace Assimp + +#endif // INCLUDED_AI_X3D_IMPORTER_H diff --git a/code/X3DImporter_Geometry2D.cpp b/code/X3DImporter_Geometry2D.cpp new file mode 100644 index 000000000..d4a62f58c --- /dev/null +++ b/code/X3DImporter_Geometry2D.cpp @@ -0,0 +1,481 @@ +/// \file X3DImporter_Geometry2D.cpp +/// \brief Parsing data from nodes of "Geometry2D" set of X3D. +/// \date 2015-2016 +/// \author nevorek@gmail.com + +#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER + +#include "X3DImporter.hpp" +#include "X3DImporter_Node.hpp" +#include "X3DImporter_Macro.hpp" + +namespace Assimp +{ + +// +// The Arc2D node specifies a linear circular arc whose center is at (0,0) and whose angles are measured starting at the positive x-axis and sweeping +// towards the positive y-axis. The radius field specifies the radius of the circle of which the arc is a portion. The arc extends from the startAngle +// counterclockwise to the endAngle. The values of startAngle and endAngle shall be in the range [-2pi, 2pi] radians (or the equivalent if a different +// angle base unit has been specified). If startAngle and endAngle have the same value, a circle is specified. +void X3DImporter::ParseNode_Geometry2D_Arc2D() +{ +std::string def, use; +float endAngle = AI_MATH_HALF_PI_F; +float radius = 1; +float startAngle = 0; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("endAngle", endAngle, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_RET("radius", radius, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_RET("startAngle", startAngle, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_Arc2D, ne); + } + else + { + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_Arc2D, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + // create point list of geometry object and convert it to line set. + std::list tlist; + + GeometryHelper_Make_Arc2D(startAngle, endAngle, radius, 10, tlist);///TODO: IME - AI_CONFIG for NumSeg + GeometryHelper_Extend_PointToLine(tlist, ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices); + ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 2; + // check for X3DMetadataObject childs. + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "Arc2D"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +// The ArcClose node specifies a portion of a circle whose center is at (0,0) and whose angles are measured starting at the positive x-axis and sweeping +// towards the positive y-axis. The end points of the arc specified are connected as defined by the closureType field. The radius field specifies the radius +// of the circle of which the arc is a portion. The arc extends from the startAngle counterclockwise to the endAngle. The value of radius shall be greater +// than zero. The values of startAngle and endAngle shall be in the range [-2pi, 2pi] radians (or the equivalent if a different default angle base unit has +// been specified). If startAngle and endAngle have the same value, a circle is specified and closureType is ignored. If the absolute difference between +// startAngle and endAngle is greater than or equal to 2pi, a complete circle is produced with no chord or radial line(s) drawn from the center. +// A closureType of "PIE" connects the end point to the start point by defining two straight line segments first from the end point to the center and then +// the center to the start point. A closureType of "CHORD" connects the end point to the start point by defining a straight line segment from the end point +// to the start point. Textures are applied individually to each face of the ArcClose2D. On the front (+Z) and back (-Z) faces of the ArcClose2D, when +// viewed from the +Z-axis, the texture is mapped onto each face with the same orientation as if the image were displayed normally in 2D. +void X3DImporter::ParseNode_Geometry2D_ArcClose2D() +{ +std::string def, use; +std::string closureType("PIE"); +float endAngle = AI_MATH_HALF_PI_F; +float radius = 1; +bool solid = false; +float startAngle = 0; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("closureType", closureType, mReader->getAttributeValue); + MACRO_ATTRREAD_CHECK_RET("endAngle", endAngle, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_RET("radius", radius, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("startAngle", startAngle, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_ArcClose2D, ne); + } + else + { + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_ArcClose2D, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + ((CX3DImporter_NodeElement_Geometry2D*)ne)->Solid = solid; + // create point list of geometry object. + GeometryHelper_Make_Arc2D(startAngle, endAngle, radius, 10, ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices);///TODO: IME - AI_CONFIG for NumSeg + // add chord or two radiuses only if not a circle was defined + if(!((fabs(endAngle - startAngle) >= AI_MATH_TWO_PI_F) || (endAngle == startAngle))) + { + std::list& vlist = ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices;// just short alias. + + if((closureType == "PIE") || (closureType == "\"PIE\"")) + vlist.push_back(aiVector3D(0, 0, 0));// center point - first radial line + else if((closureType != "CHORD") && (closureType != "\"CHORD\"")) + Throw_IncorrectAttrValue("closureType"); + + vlist.push_back(*vlist.begin());// arc first point - chord from first to last point of arc(if CHORD) or second radial line(if PIE). + } + + ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices.size(); + // check for X3DMetadataObject childs. + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "ArcClose2D"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +void X3DImporter::ParseNode_Geometry2D_Circle2D() +{ +std::string def, use; +float radius = 1; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("radius", radius, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_Circle2D, ne); + } + else + { + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_Circle2D, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + // create point list of geometry object and convert it to line set. + std::list tlist; + + GeometryHelper_Make_Arc2D(0, 0, radius, 10, tlist);///TODO: IME - AI_CONFIG for NumSeg + GeometryHelper_Extend_PointToLine(tlist, ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices); + ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 2; + // check for X3DMetadataObject childs. + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "Circle2D"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +// The Disk2D node specifies a circular disk which is centred at (0, 0) in the local coordinate system. The outerRadius field specifies the radius of the +// outer dimension of the Disk2D. The innerRadius field specifies the inner dimension of the Disk2D. The value of outerRadius shall be greater than zero. +// The value of innerRadius shall be greater than or equal to zero and less than or equal to outerRadius. If innerRadius is zero, the Disk2D is completely +// filled. Otherwise, the area within the innerRadius forms a hole in the Disk2D. If innerRadius is equal to outerRadius, a solid circular line shall +// be drawn using the current line properties. Textures are applied individually to each face of the Disk2D. On the front (+Z) and back (-Z) faces of +// the Disk2D, when viewed from the +Z-axis, the texture is mapped onto each face with the same orientation as if the image were displayed normally in 2D. +void X3DImporter::ParseNode_Geometry2D_Disk2D() +{ +std::string def, use; +float innerRadius = 0; +float outerRadius = 1; +bool solid = false; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("innerRadius", innerRadius, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_RET("outerRadius", outerRadius, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_Disk2D, ne); + } + else + { + std::list tlist_o, tlist_i; + + if(innerRadius > outerRadius) Throw_IncorrectAttrValue("innerRadius"); + + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_Disk2D, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + // create point list of geometry object. + ///TODO: IME - AI_CONFIG for NumSeg + GeometryHelper_Make_Arc2D(0, 0, outerRadius, 10, tlist_o);// outer circle + if(innerRadius == 0.0f) + {// make filled disk + // in tlist_o we already have points of circle. just copy it and sign as polygon. + ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices = tlist_o; + ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = tlist_o.size(); + } + else if(innerRadius == outerRadius) + {// make circle + // in tlist_o we already have points of circle. convert it to line set. + GeometryHelper_Extend_PointToLine(tlist_o, ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices); + ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 2; + } + else + {// make disk + std::list& vlist = ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices;// just short alias. + + GeometryHelper_Make_Arc2D(0, 0, innerRadius, 10, tlist_i);// inner circle + // + // create quad list from two point lists + // + if(tlist_i.size() < 2) throw DeadlyImportError("Disk2D. Not enough points for creating quad list.");// tlist_i and tlist_o has equal size. + + // add all quads except last + for(std::list::iterator it_i = tlist_i.begin(), it_o = tlist_o.begin(); it_i != tlist_i.end();) + { + // do not forget - CCW direction + vlist.push_back(*it_i++);// 1st point + vlist.push_back(*it_o++);// 2nd point + vlist.push_back(*it_o);// 3rd point + vlist.push_back(*it_i);// 4th point + } + + // add last quad + vlist.push_back(*tlist_i.end());// 1st point + vlist.push_back(*tlist_o.end());// 2nd point + vlist.push_back(*tlist_o.begin());// 3rd point + vlist.push_back(*tlist_o.begin());// 4th point + + ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 4; + } + + ((CX3DImporter_NodeElement_Geometry2D*)ne)->Solid = solid; + // check for X3DMetadataObject childs. + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "Disk2D"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +void X3DImporter::ParseNode_Geometry2D_Polyline2D() +{ +std::string def, use; +std::list lineSegments; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_REF("lineSegments", lineSegments, XML_ReadNode_GetAttrVal_AsListVec2f); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_Polyline2D, ne); + } + else + { + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_Polyline2D, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + // + // convert read point list of geometry object to line set. + // + std::list tlist; + + // convert vec2 to vec3 + for(std::list::iterator it2 = lineSegments.begin(); it2 != lineSegments.end(); it2++) tlist.push_back(aiVector3D(it2->x, it2->y, 0)); + + // convert point set to line set + GeometryHelper_Extend_PointToLine(tlist, ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices); + ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 2; + // check for X3DMetadataObject childs. + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "Polyline2D"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +void X3DImporter::ParseNode_Geometry2D_Polypoint2D() +{ +std::string def, use; +std::list point; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_REF("point", point, XML_ReadNode_GetAttrVal_AsListVec2f); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_Polypoint2D, ne); + } + else + { + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_Polypoint2D, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + // convert vec2 to vec3 + for(std::list::iterator it2 = point.begin(); it2 != point.end(); it2++) + { + ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices.push_back(aiVector3D(it2->x, it2->y, 0)); + } + + ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 1; + // check for X3DMetadataObject childs. + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "Polypoint2D"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +void X3DImporter::ParseNode_Geometry2D_Rectangle2D() +{ +std::string def, use; +aiVector2D size(2, 2); +bool solid = false; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_REF("size", size, XML_ReadNode_GetAttrVal_AsVec2f); + MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_Rectangle2D, ne); + } + else + { + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_Rectangle2D, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + float x1 = -size.x / 2.0f; + float x2 = size.x / 2.0f; + float y1 = -size.y / 2.0f; + float y2 = size.y / 2.0f; + std::list& vlist = ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices;// just short alias. + + vlist.push_back(aiVector3D(x2, y1, 0));// 1st point + vlist.push_back(aiVector3D(x2, y2, 0));// 2nd point + vlist.push_back(aiVector3D(x1, y2, 0));// 3rd point + vlist.push_back(aiVector3D(x1, y1, 0));// 4th point + ((CX3DImporter_NodeElement_Geometry2D*)ne)->Solid = solid; + ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 4; + // check for X3DMetadataObject childs. + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "Rectangle2D"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +void X3DImporter::ParseNode_Geometry2D_TriangleSet2D() +{ +std::string def, use; +bool solid = false; +std::list vertices; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_REF("vertices", vertices, XML_ReadNode_GetAttrVal_AsListVec2f); + MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_TriangleSet2D, ne); + } + else + { + if(vertices.size() % 3) throw DeadlyImportError("TriangleSet2D. Not enough points for defining triangle."); + + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_TriangleSet2D, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + // convert vec2 to vec3 + for(std::list::iterator it2 = vertices.begin(); it2 != vertices.end(); it2++) + { + ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices.push_back(aiVector3D(it2->x, it2->y, 0)); + } + + ((CX3DImporter_NodeElement_Geometry2D*)ne)->Solid = solid; + ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 3; + // check for X3DMetadataObject childs. + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "TriangleSet2D"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +}// namespace Assimp + +#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER diff --git a/code/X3DImporter_Geometry3D.cpp b/code/X3DImporter_Geometry3D.cpp new file mode 100644 index 000000000..63a02b6b8 --- /dev/null +++ b/code/X3DImporter_Geometry3D.cpp @@ -0,0 +1,947 @@ +/// \file X3DImporter_Geometry3D.cpp +/// \brief Parsing data from nodes of "Geometry3D" set of X3D. +/// \date 2015-2016 +/// \author nevorek@gmail.com + +#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER + +#include "X3DImporter.hpp" +#include "X3DImporter_Macro.hpp" +#include "StandardShapes.h" + +namespace Assimp +{ + +// +// The Box node specifies a rectangular parallelepiped box centred at (0, 0, 0) in the local coordinate system and aligned with the local coordinate axes. +// By default, the box measures 2 units in each dimension, from -1 to +1. The size field specifies the extents of the box along the X-, Y-, and Z-axes +// respectively and each component value shall be greater than zero. +void X3DImporter::ParseNode_Geometry3D_Box() +{ +std::string def, use; +bool solid = true; +aiVector3D size(2, 2, 2); +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_REF("size", size, XML_ReadNode_GetAttrVal_AsVec3f); + MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_Box, ne); + } + else + { + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Geometry3D(CX3DImporter_NodeElement::ENET_Box, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + GeometryHelper_MakeQL_RectParallelepiped(size, ((CX3DImporter_NodeElement_Geometry3D*)ne)->Vertices);// get quad list + ((CX3DImporter_NodeElement_Geometry3D*)ne)->Solid = solid; + ((CX3DImporter_NodeElement_Geometry3D*)ne)->NumIndices = 4; + // check for X3DMetadataObject childs. + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "Box"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +void X3DImporter::ParseNode_Geometry3D_Cone() +{ +std::string use, def; +bool bottom = true; +float bottomRadius = 1; +float height = 2; +bool side = true; +bool solid = true; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("side", side, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("bottom", bottom, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("height", height, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_RET("bottomRadius", bottomRadius, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_Cone, ne); + } + else + { + const unsigned int tess = 30;///TODO: IME tesselation factor thru ai_property + std::vector tvec;// temp array for vertices. + + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Geometry3D(CX3DImporter_NodeElement::ENET_Cone, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + // make cone or parts according to flags. + if(side) + { + StandardShapes::MakeCone(height, 0, bottomRadius, tess, tvec, !bottom); + } + else if(bottom) + { + StandardShapes::MakeCircle(bottomRadius, tess, tvec); + height = -(height / 2); + for(std::vector::iterator it = tvec.begin(); it != tvec.end(); it++) it->y = height;// y - because circle made in oXZ. + } + + // copy data from temp array + for(std::vector::iterator it = tvec.begin(); it != tvec.end(); it++) ((CX3DImporter_NodeElement_Geometry3D*)ne)->Vertices.push_back(*it); + + ((CX3DImporter_NodeElement_Geometry3D*)ne)->Solid = solid; + ((CX3DImporter_NodeElement_Geometry3D*)ne)->NumIndices = 3; + // check for X3DMetadataObject childs. + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "Cone"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +void X3DImporter::ParseNode_Geometry3D_Cylinder() +{ +std::string use, def; +bool bottom = true; +float height = 2; +float radius = 1; +bool side = true; +bool solid = true; +bool top = true; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("radius", radius, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("bottom", bottom, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("top", top, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("side", side, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("height", height, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_Cylinder, ne); + } + else + { + const unsigned int tess = 30;///TODO: IME tesselation factor thru ai_property + std::vector tside;// temp array for vertices of side. + std::vector tcir;// temp array for vertices of circle. + + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Geometry3D(CX3DImporter_NodeElement::ENET_Cylinder, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + // make cilynder or parts according to flags. + if(side) StandardShapes::MakeCone(height, radius, radius, tess, tside, true); + + height /= 2;// height defined for whole cylinder, when creating top and bottom circle we are using just half of height. + if(top || bottom) StandardShapes::MakeCircle(radius, tess, tcir); + // copy data from temp arrays + std::list& vlist = ((CX3DImporter_NodeElement_Geometry3D*)ne)->Vertices;// just short alias. + + for(std::vector::iterator it = tside.begin(); it != tside.end(); it++) vlist.push_back(*it); + + if(top) + { + for(std::vector::iterator it = tcir.begin(); it != tcir.end(); it++) + { + (*it).y = height;// y - because circle made in oXZ. + vlist.push_back(*it); + } + }// if(top) + + if(bottom) + { + for(std::vector::iterator it = tcir.begin(); it != tcir.end(); it++) + { + (*it).y = -height;// y - because circle made in oXZ. + vlist.push_back(*it); + } + }// if(top) + + ((CX3DImporter_NodeElement_Geometry3D*)ne)->Solid = solid; + ((CX3DImporter_NodeElement_Geometry3D*)ne)->NumIndices = 3; + // check for X3DMetadataObject childs. + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "Cylinder"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +// +// ColorNormalTexCoordContentModel can contain Color (or ColorRGBA), Normal and TextureCoordinate, in any order. No more than one instance of any single +// node type is allowed. A ProtoInstance node (with the proper node type) can be substituted for any node in this content model. +// +// The ElevationGrid node specifies a uniform rectangular grid of varying height in the Y=0 plane of the local coordinate system. The geometry is described +// by a scalar array of height values that specify the height of a surface above each point of the grid. The xDimension and zDimension fields indicate +// the number of elements of the grid height array in the X and Z directions. Both xDimension and zDimension shall be greater than or equal to zero. +// If either the xDimension or the zDimension is less than two, the ElevationGrid contains no quadrilaterals. +void X3DImporter::ParseNode_Geometry3D_ElevationGrid() +{ +std::string use, def; +bool ccw = true; +bool colorPerVertex = true; +float creaseAngle = 0; +std::list height; +bool normalPerVertex = true; +bool solid = true; +int32_t xDimension = 0; +float xSpacing = 1; +int32_t zDimension = 0; +float zSpacing = 1; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("creaseAngle", creaseAngle, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_REF("height", height, XML_ReadNode_GetAttrVal_AsListF); + MACRO_ATTRREAD_CHECK_RET("xDimension", xDimension, XML_ReadNode_GetAttrVal_AsI32); + MACRO_ATTRREAD_CHECK_RET("xSpacing", xSpacing, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_RET("zDimension", zDimension, XML_ReadNode_GetAttrVal_AsI32); + MACRO_ATTRREAD_CHECK_RET("zSpacing", zSpacing, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_ElevationGrid, ne); + } + else + { + if((xSpacing == 0.0f) || (zSpacing == 0.0f)) throw DeadlyImportError("Spacing in must be grater than zero."); + if((xDimension <= 0) || (zDimension <= 0)) throw DeadlyImportError("Dimension in must be grater than zero."); + if((size_t)(xDimension * zDimension) != height.size()) Throw_IncorrectAttrValue("Heights count must be equal to \"xDimension * zDimension\""); + + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_ElevationGrid(CX3DImporter_NodeElement::ENET_ElevationGrid, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + CX3DImporter_NodeElement_ElevationGrid& grid_alias = *((CX3DImporter_NodeElement_ElevationGrid*)ne);// create alias for conveience + + {// create grid vertices list + std::list::const_iterator he_it = height.begin(); + + for(int32_t zi = 0; zi < zDimension; zi++)// rows + { + for(int32_t xi = 0; xi < xDimension; xi++)// columns + { + aiVector3D tvec(xSpacing * xi, *he_it, zSpacing * zi); + + grid_alias.Vertices.push_back(tvec); + he_it++; + } + } + }// END: create grid vertices list + // + // create faces list. In "coordIdx" format + // + // check if we have quads + if((xDimension < 2) || (zDimension < 2))// only one element in dimension is set, create line set. + { + ((CX3DImporter_NodeElement_ElevationGrid*)ne)->NumIndices = 2;// will be holded as line set. + for(size_t i = 0, i_e = (grid_alias.Vertices.size() - 1); i < i_e; i++) + { + grid_alias.CoordIdx.push_back(i); + grid_alias.CoordIdx.push_back(i + 1); + grid_alias.CoordIdx.push_back(-1); + } + } + else// two or more elements in every dimension is set. create quad set. + { + ((CX3DImporter_NodeElement_ElevationGrid*)ne)->NumIndices = 4; + for(int32_t fzi = 0, fzi_e = (zDimension - 1); fzi < fzi_e; fzi++)// rows + { + for(int32_t fxi = 0, fxi_e = (xDimension - 1); fxi < fxi_e; fxi++)// columns + { + // points direction in face. + if(ccw) + { + // CCW: + // 3 2 + // 0 1 + grid_alias.CoordIdx.push_back((fzi + 1) * xDimension + fxi); + grid_alias.CoordIdx.push_back((fzi + 1) * xDimension + (fxi + 1)); + grid_alias.CoordIdx.push_back(fzi * xDimension + (fxi + 1)); + grid_alias.CoordIdx.push_back(fzi * xDimension + fxi); + } + else + { + // CW: + // 0 1 + // 3 2 + grid_alias.CoordIdx.push_back(fzi * xDimension + fxi); + grid_alias.CoordIdx.push_back(fzi * xDimension + (fxi + 1)); + grid_alias.CoordIdx.push_back((fzi + 1) * xDimension + (fxi + 1)); + grid_alias.CoordIdx.push_back((fzi + 1) * xDimension + fxi); + }// if(ccw) else + + grid_alias.CoordIdx.push_back(-1); + }// for(int32_t fxi = 0, fxi_e = (xDimension - 1); fxi < fxi_e; fxi++) + }// for(int32_t fzi = 0, fzi_e = (zDimension - 1); fzi < fzi_e; fzi++) + }// if((xDimension < 2) || (zDimension < 2)) else + + grid_alias.ColorPerVertex = colorPerVertex; + grid_alias.NormalPerVertex = normalPerVertex; + grid_alias.CreaseAngle = creaseAngle; + grid_alias.Solid = solid; + // check for child nodes + if(!mReader->isEmptyElement()) + { + ParseHelper_Node_Enter(ne); + MACRO_NODECHECK_LOOPBEGIN("ElevationGrid"); + // check for X3DComposedGeometryNodes + if(XML_CheckNode_NameEqual("Color")) { ParseNode_Rendering_Color(); continue; } + if(XML_CheckNode_NameEqual("ColorRGBA")) { ParseNode_Rendering_ColorRGBA(); continue; } + if(XML_CheckNode_NameEqual("Normal")) { ParseNode_Rendering_Normal(); continue; } + if(XML_CheckNode_NameEqual("TextureCoordinate")) { ParseNode_Texturing_TextureCoordinate(); continue; } + // check for X3DMetadataObject + if(!ParseHelper_CheckRead_X3DMetadataObject()) XML_CheckNode_SkipUnsupported("ElevationGrid"); + + MACRO_NODECHECK_LOOPEND("ElevationGrid"); + ParseHelper_Node_Exit(); + }// if(!mReader->isEmptyElement()) + else + { + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + }// if(!mReader->isEmptyElement()) else + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +template +static void GeometryHelper_Extrusion_CurveIsClosed(std::vector& pCurve, const bool pDropTail, const bool pRemoveLastPoint, bool& pCurveIsClosed) +{ +size_t cur_sz = pCurve.size(); + + pCurveIsClosed = false; + // for curve with less than four points checking is have no sense, + if(cur_sz < 4) return; + + for(size_t s = 3, s_e = cur_sz; s < s_e; s++) + { + // search for first point of duplicated part. + if(pCurve[0] == pCurve[s]) + { + bool found = true; + + // check if tail(indexed by b2) is duplicate of head(indexed by b1). + for(size_t b1 = 1, b2 = (s + 1); b2 < cur_sz; b1++, b2++) + { + if(pCurve[b1] != pCurve[b2]) + {// points not match: clear flag and break loop. + found = false; + + break; + } + }// for(size_t b1 = 1, b2 = (s + 1); b2 < cur_sz; b1++, b2++) + + // if duplicate tail is found then drop or not it depending on flags. + if(found) + { + pCurveIsClosed = true; + if(pDropTail) + { + if(!pRemoveLastPoint) s++;// prepare value for iterator's arithmetics. + + pCurve.erase(pCurve.begin() + s, pCurve.end());// remove tail + } + + break; + }// if(found) + }// if(pCurve[0] == pCurve[s]) + }// for(size_t s = 3, s_e = (cur_sz - 1); s < s_e; s++) +} + +static aiVector3D GeometryHelper_Extrusion_GetNextY(const size_t pSpine_PointIdx, const std::vector& pSpine, const bool pSpine_Closed) +{ +const size_t spine_idx_last = pSpine.size() - 1; +aiVector3D tvec; + + if((pSpine_PointIdx == 0) || (pSpine_PointIdx == spine_idx_last))// at first special cases + { + if(pSpine_Closed) + {// If the spine curve is closed: The SCP for the first and last points is the same and is found using (spine[1] − spine[n − 2]) to compute the Y-axis. + // As we even for closed spine curve last and first point in pSpine are not the same: duplicates(spine[n - 1] which are equivalent to spine[0]) + // in tail are removed. + // So, last point in pSpine is a spine[n - 2] + tvec = pSpine[1] - pSpine[spine_idx_last]; + } + else if(pSpine_PointIdx == 0) + {// The Y-axis used for the first point is the vector from spine[0] to spine[1] + tvec = pSpine[1] - pSpine[0]; + } + else + {// The Y-axis used for the last point it is the vector from spine[n−2] to spine[n−1]. In our case(see above about droping tail) spine[n - 1] is + // the spine[0]. + tvec = pSpine[spine_idx_last] - pSpine[spine_idx_last - 1]; + } + }// if((pSpine_PointIdx == 0) || (pSpine_PointIdx == spine_idx_last)) + else + {// For all points other than the first or last: The Y-axis for spine[i] is found by normalizing the vector defined by (spine[i+1] − spine[i−1]). + tvec = pSpine[pSpine_PointIdx + 1] - pSpine[pSpine_PointIdx - 1]; + }// if((pSpine_PointIdx == 0) || (pSpine_PointIdx == spine_idx_last)) else + + return tvec.Normalize(); +} + +static aiVector3D GeometryHelper_Extrusion_GetNextZ(const size_t pSpine_PointIdx, const std::vector& pSpine, const bool pSpine_Closed, + const aiVector3D pVecZ_Prev) +{ +const aiVector3D zero_vec(0); +const size_t spine_idx_last = pSpine.size() - 1; +aiVector3D tvec; + + // at first special cases + if(pSpine.size() < 3)// spine have not enough points for vector calculations. + { + tvec.Set(0, 0, 1); + } + else if(pSpine_PointIdx == 0)// special case: first point + { + if(pSpine_Closed)// for calculating use previous point in curve s[n - 2]. In list it's a last point, because point s[n - 1] was removed as duplicate. + { + tvec = (pSpine[1] - pSpine[0]) ^ (pSpine[spine_idx_last] - pSpine[0]); + } + else // for not closed curve first and next point(s[0] and s[1]) has the same vector Z. + { + bool found = false; + + // As said: "If the Z-axis of the first point is undefined (because the spine is not closed and the first two spine segments are collinear) + // then the Z-axis for the first spine point with a defined Z-axis is used." + // Walk thru spine and find Z. + for(size_t next_point = 2; (next_point <= spine_idx_last) && !found; next_point++) + { + // (pSpine[2] - pSpine[1]) ^ (pSpine[0] - pSpine[1]) + tvec = (pSpine[next_point] - pSpine[next_point - 1]) ^ (pSpine[next_point - 2] - pSpine[next_point - 1]); + found = !tvec.Equal(zero_vec); + } + + // if entire spine are collinear then use OZ axis. + if(!found) tvec.Set(0, 0, 1); + }// if(pSpine_Closed) else + }// else if(pSpine_PointIdx == 0) + else if(pSpine_PointIdx == spine_idx_last)// special case: last point + { + if(pSpine_Closed) + {// do not forget that real last point s[n - 1] is removed as duplicated. And in this case we are calculating vector Z for point s[n - 2]. + tvec = (pSpine[0] - pSpine[pSpine_PointIdx]) ^ (pSpine[pSpine_PointIdx - 1] - pSpine[pSpine_PointIdx]); + // if taken spine vectors are collinear then use previous vector Z. + if(tvec.Equal(zero_vec)) tvec = pVecZ_Prev; + } + else + {// vector Z for last point of not closed curve is previous vector Z. + tvec = pVecZ_Prev; + } + } + else// regular point + { + tvec = (pSpine[pSpine_PointIdx + 1] - pSpine[pSpine_PointIdx]) ^ (pSpine[pSpine_PointIdx - 1] - pSpine[pSpine_PointIdx]); + // if taken spine vectors are collinear then use previous vector Z. + if(tvec.Equal(zero_vec)) tvec = pVecZ_Prev; + } + + // After determining the Z-axis, its dot product with the Z-axis of the previous spine point is computed. If this value is negative, the Z-axis + // is flipped (multiplied by −1). + if((tvec * pVecZ_Prev) < 0) tvec = -tvec; + + return tvec.Normalize(); +} + +// +void X3DImporter::ParseNode_Geometry3D_Extrusion() +{ +std::string use, def; +bool beginCap = true; +bool ccw = true; +bool convex = true; +float creaseAngle = 0; +std::vector crossSection; +bool endCap = true; +std::vector orientation; +std::vector scale; +bool solid = true; +std::vector spine; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("beginCap", beginCap, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("convex", convex, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("creaseAngle", creaseAngle, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_REF("crossSection", crossSection, XML_ReadNode_GetAttrVal_AsArrVec2f); + MACRO_ATTRREAD_CHECK_RET("endCap", endCap, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_REF("orientation", orientation, XML_ReadNode_GetAttrVal_AsArrF); + MACRO_ATTRREAD_CHECK_REF("scale", scale, XML_ReadNode_GetAttrVal_AsArrVec2f); + MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_REF("spine", spine, XML_ReadNode_GetAttrVal_AsArrVec3f); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_Extrusion, ne); + } + else + { + // + // check if default values must be assigned + // + if(spine.size() == 0) + { + spine.resize(2); + spine[0].Set(0, 0, 0), spine[1].Set(0, 1, 0); + } + else if(spine.size() == 1) + { + throw DeadlyImportError("ParseNode_Geometry3D_Extrusion. Spine must have at least two points."); + } + + if(crossSection.size() == 0) + { + crossSection.resize(5); + crossSection[0].Set(1, 1), crossSection[1].Set(1, -1), crossSection[2].Set(-1, -1), crossSection[3].Set(-1, 1), crossSection[4].Set(1, 1); + } + + {// orientation + size_t ori_size = orientation.size() / 4; + + if(ori_size < spine.size()) + { + float add_ori[4];// values that will be added + + if(ori_size == 1)// if "orientation" has one element(means one MFRotation with four components) then use it value for all spine points. + { + add_ori[0] = orientation[0], add_ori[1] = orientation[1], add_ori[2] = orientation[2], add_ori[3] = orientation[3]; + } + else// else - use default values + { + add_ori[0] = 0, add_ori[1] = 0, add_ori[2] = 1, add_ori[3] = 0; + } + + orientation.reserve(spine.size() * 4); + for(size_t i = 0, i_e = (spine.size() - ori_size); i < i_e; i++) + orientation.push_back(add_ori[0]), orientation.push_back(add_ori[1]), orientation.push_back(add_ori[2]), orientation.push_back(add_ori[3]); + } + + if(orientation.size() % 4) throw DeadlyImportError("Attribute \"orientation\" in must has multiple four quantity of numbers."); + }// END: orientation + + {// scale + if(scale.size() < spine.size()) + { + aiVector2D add_sc; + + if(scale.size() == 1)// if "scale" has one element then use it value for all spine points. + add_sc = scale[0]; + else// else - use default values + add_sc.Set(1, 1); + + scale.reserve(spine.size()); + for(size_t i = 0, i_e = (spine.size() - scale.size()); i < i_e; i++) scale.push_back(add_sc); + } + }// END: scale + // + // create and if needed - define new geometry object. + // + ne = new CX3DImporter_NodeElement_IndexedSet(CX3DImporter_NodeElement::ENET_Extrusion, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + CX3DImporter_NodeElement_IndexedSet& ext_alias = *((CX3DImporter_NodeElement_IndexedSet*)ne);// create alias for conveience + // assign part of input data + ext_alias.CCW = ccw; + ext_alias.Convex = convex; + ext_alias.CreaseAngle = creaseAngle; + ext_alias.Solid = solid; + + // + // How we done it at all? + // 1. At first we will calculate array of basises for every point in spine(look SCP in ISO-dic). Also "orientation" vector + // are applied vor every basis. + // 2. After that we can create array of point sets: which are scaled, transfered to basis of relative basis and at final translated to real position + // using relative spine point. + // 3. Next step is creating CoordIdx array(do not forget "-1" delimiter). While creating CoordIdx also created faces for begin and end caps, if + // needed. While createing CootdIdx is taking in account CCW flag. + // 4. The last step: create Vertices list. + // + bool spine_closed;// flag: true if spine curve is closed. + bool cross_closed;// flag: true if cross curve is closed. + std::vector basis_arr;// array of basises. ROW_a - X, ROW_b - Y, ROW_c - Z. + std::vector > pointset_arr;// array of point sets: cross curves. + + // detect closed curves + GeometryHelper_Extrusion_CurveIsClosed(crossSection, true, true, cross_closed);// true - drop tail, true - remove duplicate end. + GeometryHelper_Extrusion_CurveIsClosed(spine, true, true, spine_closed);// true - drop tail, true - remove duplicate end. + // If both cap are requested and spine curve is closed then we can make only one cap. Because second cap will be the same surface. + if(spine_closed) + { + beginCap |= endCap; + endCap = false; + } + + {// 1. Calculate array of basises. + aiMatrix4x4 rotmat; + aiVector3D vecX(0), vecY(0), vecZ(0); + + basis_arr.resize(spine.size()); + for(size_t i = 0, i_e = spine.size(); i < i_e; i++) + { + aiVector3D tvec; + + // get axises of basis. + vecY = GeometryHelper_Extrusion_GetNextY(i, spine, spine_closed); + vecZ = GeometryHelper_Extrusion_GetNextZ(i, spine, spine_closed, vecZ); + vecX = (vecY ^ vecZ).Normalize(); + // get rotation matrix and apply "orientation" to basis + aiMatrix4x4::Rotation(orientation[i * 4 + 3], aiVector3D(orientation[i * 4], orientation[i * 4 + 1], orientation[i * 4 + 2]), rotmat); + tvec = vecX, tvec *= rotmat, basis_arr[i].a1 = tvec.x, basis_arr[i].a2 = tvec.y, basis_arr[i].a3 = tvec.z; + tvec = vecY, tvec *= rotmat, basis_arr[i].b1 = tvec.x, basis_arr[i].b2 = tvec.y, basis_arr[i].b3 = tvec.z; + tvec = vecZ, tvec *= rotmat, basis_arr[i].c1 = tvec.x, basis_arr[i].c2 = tvec.y, basis_arr[i].c3 = tvec.z; + }// for(size_t i = 0, i_e = spine.size(); i < i_e; i++) + }// END: 1. Calculate array of basises + + {// 2. Create array of point sets. + aiMatrix4x4 scmat; + std::vector tcross(crossSection.size()); + + pointset_arr.resize(spine.size()); + for(size_t spi = 0, spi_e = spine.size(); spi < spi_e; spi++) + { + aiVector3D tc23vec; + + tc23vec.Set(scale[spi].x, 0, scale[spi].y); + aiMatrix4x4::Scaling(tc23vec, scmat); + for(size_t cri = 0, cri_e = crossSection.size(); cri < cri_e; cri++) + { + aiVector3D tvecX, tvecY, tvecZ; + + tc23vec.Set(crossSection[cri].x, 0, crossSection[cri].y); + // apply scaling to point + tcross[cri] = scmat * tc23vec; + // + // transfer point to new basis + // calculate coordinate in new basis + tvecX.Set(basis_arr[spi].a1, basis_arr[spi].a2, basis_arr[spi].a3), tvecX *= tcross[cri].x; + tvecY.Set(basis_arr[spi].b1, basis_arr[spi].b2, basis_arr[spi].b3), tvecY *= tcross[cri].y; + tvecZ.Set(basis_arr[spi].c1, basis_arr[spi].c2, basis_arr[spi].c3), tvecZ *= tcross[cri].z; + // apply new coordinates and translate it to spine point. + tcross[cri] = tvecX + tvecY + tvecZ + spine[spi]; + }// for(size_t cri = 0, cri_e = crossSection.size(); cri < cri_e; i++) + + pointset_arr[spi] = tcross;// store transfered point set + }// for(size_t spi = 0, spi_e = spine.size(); spi < spi_e; i++) + }// END: 2. Create array of point sets. + + {// 3. Create CoordIdx. + // add caps if needed + if(beginCap) + { + // add cap as polygon. vertices of cap are places at begin, so just add numbers from zero. + for(size_t i = 0, i_e = crossSection.size(); i < i_e; i++) ext_alias.CoordIndex.push_back(i); + + // add delimiter + ext_alias.CoordIndex.push_back(-1); + }// if(beginCap) + + if(endCap) + { + // add cap as polygon. vertices of cap are places at end, as for beginCap use just sequence of numbers but with offset. + size_t beg = (pointset_arr.size() - 1) * crossSection.size(); + + for(size_t i = beg, i_e = (beg + crossSection.size()); i < i_e; i++) ext_alias.CoordIndex.push_back(i); + + // add delimiter + ext_alias.CoordIndex.push_back(-1); + }// if(beginCap) + + // add quads + for(size_t spi = 0, spi_e = (spine.size() - 1); spi <= spi_e; spi++) + { + const size_t cr_sz = crossSection.size(); + const size_t cr_last = crossSection.size() - 1; + + size_t right_col;// hold index basis for points of quad placed in right column; + + if(spi != spi_e) + right_col = spi + 1; + else if(spine_closed)// if spine curve is closed then one more quad is needed: between first and last points of curve. + right_col = 0; + else + break;// if spine curve is not closed then break the loop, because spi is out of range for that type of spine. + + for(size_t cri = 0; cri < cr_sz; cri++) + { + if(cri != cr_last) + { + MACRO_FACE_ADD_QUAD(ccw, ext_alias.CoordIndex, + spi * cr_sz + cri, right_col * cr_sz + cri, right_col * cr_sz + cri + 1, spi * cr_sz + cri + 1); + // add delimiter + ext_alias.CoordIndex.push_back(-1); + } + else if(cross_closed)// if cross curve is closed then one more quad is needed: between first and last points of curve. + { + MACRO_FACE_ADD_QUAD(ccw, ext_alias.CoordIndex, + spi * cr_sz + cri, right_col * cr_sz + cri, right_col * cr_sz + 0, spi * cr_sz + 0); + // add delimiter + ext_alias.CoordIndex.push_back(-1); + } + }// for(size_t cri = 0; cri < cr_sz; cri++) + }// for(size_t spi = 0, spi_e = (spine.size() - 2); spi < spi_e; spi++) + }// END: 3. Create CoordIdx. + + {// 4. Create vertices list. + // just copy all vertices + for(size_t spi = 0, spi_e = spine.size(); spi < spi_e; spi++) + { + for(size_t cri = 0, cri_e = crossSection.size(); cri < cri_e; cri++) + { + ext_alias.Vertices.push_back(pointset_arr[spi][cri]); + } + } + }// END: 4. Create vertices list. +//PrintVectorSet("Ext. CoordIdx", ext_alias.CoordIndex); +//PrintVectorSet("Ext. Vertices", ext_alias.Vertices); + // check for child nodes + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "Extrusion"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +// +// ComposedGeometryContentModel is the child-node content model corresponding to X3DComposedGeometryNodes. It can contain Color (or ColorRGBA), Coordinate, +// Normal and TextureCoordinate, in any order. No more than one instance of these nodes is allowed. Multiple VertexAttribute (FloatVertexAttribute, +// Matrix3VertexAttribute, Matrix4VertexAttribute) nodes can also be contained. +// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model. +// +void X3DImporter::ParseNode_Geometry3D_IndexedFaceSet() +{ +std::string use, def; +bool ccw = true; +std::list colorIndex; +bool colorPerVertex = true; +bool convex = true; +std::list coordIndex; +float creaseAngle = 0; +std::list normalIndex; +bool normalPerVertex = true; +bool solid = true; +std::list texCoordIndex; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_REF("colorIndex", colorIndex, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("convex", convex, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_REF("coordIndex", coordIndex, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_CHECK_RET("creaseAngle", creaseAngle, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_REF("normalIndex", normalIndex, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_REF("texCoordIndex", texCoordIndex, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_IndexedFaceSet, ne); + } + else + { + // check data + if(coordIndex.size() == 0) throw DeadlyImportError("IndexedFaceSet must contain not empty \"coordIndex\" attribute."); + + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_IndexedSet(CX3DImporter_NodeElement::ENET_IndexedFaceSet, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + CX3DImporter_NodeElement_IndexedSet& ne_alias = *((CX3DImporter_NodeElement_IndexedSet*)ne); + + ne_alias.CCW = ccw; + ne_alias.ColorIndex = colorIndex; + ne_alias.ColorPerVertex = colorPerVertex; + ne_alias.Convex = convex; + ne_alias.CoordIndex = coordIndex; + ne_alias.CreaseAngle = creaseAngle; + ne_alias.NormalIndex = normalIndex; + ne_alias.NormalPerVertex = normalPerVertex; + ne_alias.Solid = solid; + ne_alias.TexCoordIndex = texCoordIndex; + // check for child nodes + if(!mReader->isEmptyElement()) + { + ParseHelper_Node_Enter(ne); + MACRO_NODECHECK_LOOPBEGIN("IndexedFaceSet"); + // check for X3DComposedGeometryNodes + if(XML_CheckNode_NameEqual("Color")) { ParseNode_Rendering_Color(); continue; } + if(XML_CheckNode_NameEqual("ColorRGBA")) { ParseNode_Rendering_ColorRGBA(); continue; } + if(XML_CheckNode_NameEqual("Coordinate")) { ParseNode_Rendering_Coordinate(); continue; } + if(XML_CheckNode_NameEqual("Normal")) { ParseNode_Rendering_Normal(); continue; } + if(XML_CheckNode_NameEqual("TextureCoordinate")) { ParseNode_Texturing_TextureCoordinate(); continue; } + // check for X3DMetadataObject + if(!ParseHelper_CheckRead_X3DMetadataObject()) XML_CheckNode_SkipUnsupported("IndexedFaceSet"); + + MACRO_NODECHECK_LOOPEND("IndexedFaceSet"); + ParseHelper_Node_Exit(); + }// if(!mReader->isEmptyElement()) + else + { + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + } + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +void X3DImporter::ParseNode_Geometry3D_Sphere() +{ +std::string use, def; +float radius = 1; +bool solid = true; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("radius", radius, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_Sphere, ne); + } + else + { + const unsigned int tess = 3;///TODO: IME tesselation factor thru ai_property + std::vector tlist; + + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Geometry3D(CX3DImporter_NodeElement::ENET_Sphere, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + StandardShapes::MakeSphere(tess, tlist); + // copy data from temp array and apply scale + for(std::vector::iterator it = tlist.begin(); it != tlist.end(); it++) + { + ((CX3DImporter_NodeElement_Geometry3D*)ne)->Vertices.push_back(*it * radius); + } + + ((CX3DImporter_NodeElement_Geometry3D*)ne)->Solid = solid; + ((CX3DImporter_NodeElement_Geometry3D*)ne)->NumIndices = 3; + // check for X3DMetadataObject childs. + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "Sphere"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + + +}// namespace Assimp + +#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER diff --git a/code/X3DImporter_Group.cpp b/code/X3DImporter_Group.cpp new file mode 100644 index 000000000..c1e7bf6d2 --- /dev/null +++ b/code/X3DImporter_Group.cpp @@ -0,0 +1,269 @@ +/// \file X3DImporter_Group.cpp +/// \brief Parsing data from nodes of "Grouping" set of X3D. +/// \date 2015-2016 +/// \author nevorek@gmail.com + +#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER + +#include "X3DImporter.hpp" +#include "X3DImporter_Macro.hpp" + +namespace Assimp +{ + +// +// +// ChildContentModel is the child-node content model corresponding to X3DChildNode, combining all profiles. ChildContentModel can contain most nodes, +// other Grouping nodes, Prototype declarations and ProtoInstances in any order and any combination. When the assigned profile is less than Full, the +// precise palette of legal nodes that are available depends on assigned profile and components. +// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model. +// +// A Group node contains children nodes without introducing a new transformation. It is equivalent to a Transform node containing an identity transform. +void X3DImporter::ParseNode_Grouping_Group() +{ +std::string def, use; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + CX3DImporter_NodeElement* ne; + + MACRO_USE_CHECKANDAPPLY(def, use, ENET_Group, ne); + } + else + { + ParseHelper_Group_Begin();// create new grouping element and go deeper if node has children. + // at this place new group mode created and made current, so we can name it. + if(!def.empty()) NodeElement_Cur->ID = def; + // in grouping set of nodes check X3DMetadataObject is not needed, because it is done in parser function. + + // for empty element exit from node in that place + if(mReader->isEmptyElement()) ParseHelper_Node_Exit(); + }// if(!use.empty()) else +} + +void X3DImporter::ParseNode_Grouping_GroupEnd() +{ + ParseHelper_Node_Exit();// go up in scene graph +} + +// +// +// ChildContentModel is the child-node content model corresponding to X3DChildNode, combining all profiles. ChildContentModel can contain most nodes, +// other Grouping nodes, Prototype declarations and ProtoInstances in any order and any combination. When the assigned profile is less than Full, the +// precise palette of legal nodes that are available depends on assigned profile and components. +// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model. +// +// The StaticGroup node contains children nodes which cannot be modified. StaticGroup children are guaranteed to not change, send events, receive events or +// contain any USE references outside the StaticGroup. +void X3DImporter::ParseNode_Grouping_StaticGroup() +{ +std::string def, use; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + CX3DImporter_NodeElement* ne; + + MACRO_USE_CHECKANDAPPLY(def, use, ENET_Group, ne); + } + else + { + ParseHelper_Group_Begin(true);// create new grouping element and go deeper if node has children. + // at this place new group mode created and made current, so we can name it. + if(!def.empty()) NodeElement_Cur->ID = def; + // in grouping set of nodes check X3DMetadataObject is not needed, because it is done in parser function. + + // for empty element exit from node in that place + if(mReader->isEmptyElement()) ParseHelper_Node_Exit(); + }// if(!use.empty()) else +} + +void X3DImporter::ParseNode_Grouping_StaticGroupEnd() +{ + ParseHelper_Node_Exit();// go up in scene graph +} + +// +// +// ChildContentModel is the child-node content model corresponding to X3DChildNode, combining all profiles. ChildContentModel can contain most nodes, +// other Grouping nodes, Prototype declarations and ProtoInstances in any order and any combination. When the assigned profile is less than Full, the +// precise palette of legal nodes that are available depends on assigned profile and components. +// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model. +// +// The Switch grouping node traverses zero or one of the nodes specified in the children field. The whichChoice field specifies the index of the child +// to traverse, with the first child having index 0. If whichChoice is less than zero or greater than the number of nodes in the children field, nothing +// is chosen. +void X3DImporter::ParseNode_Grouping_Switch() +{ +std::string def, use; +int32_t whichChoice = -1; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("whichChoice", whichChoice, XML_ReadNode_GetAttrVal_AsI32); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + CX3DImporter_NodeElement* ne; + + MACRO_USE_CHECKANDAPPLY(def, use, ENET_Group, ne); + } + else + { + ParseHelper_Group_Begin();// create new grouping element and go deeper if node has children. + // at this place new group mode created and made current, so we can name it. + if(!def.empty()) NodeElement_Cur->ID = def; + + // also set values specific to this type of group + ((CX3DImporter_NodeElement_Group*)NodeElement_Cur)->UseChoice = true; + ((CX3DImporter_NodeElement_Group*)NodeElement_Cur)->Choice = whichChoice; + // in grouping set of nodes check X3DMetadataObject is not needed, because it is done in parser function. + + // for empty element exit from node in that place + if(mReader->isEmptyElement()) ParseHelper_Node_Exit(); + }// if(!use.empty()) else +} + +void X3DImporter::ParseNode_Grouping_SwitchEnd() +{ + // just exit from node. Defined choice will be accepted at postprocessing stage. + ParseHelper_Node_Exit();// go up in scene graph +} + +// +// +// ChildContentModel is the child-node content model corresponding to X3DChildNode, combining all profiles. ChildContentModel can contain most nodes, +// other Grouping nodes, Prototype declarations and ProtoInstances in any order and any combination. When the assigned profile is less than Full, the +// precise palette of legal nodes that are available depends on assigned profile and components. +// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model. +// +// The Transform node is a grouping node that defines a coordinate system for its children that is relative to the coordinate systems of its ancestors. +// Given a 3-dimensional point P and Transform node, P is transformed into point P' in its parent's coordinate system by a series of intermediate +// transformations. In matrix transformation notation, where C (center), SR (scaleOrientation), T (translation), R (rotation), and S (scale) are the +// equivalent transformation matrices, +// P' = T * C * R * SR * S * -SR * -C * P +void X3DImporter::ParseNode_Grouping_Transform() +{ +aiVector3D center(0, 0, 0); +float rotation[4] = {0, 0, 1, 0}; +aiVector3D scale(1, 1, 1);// A value of zero indicates that any child geometry shall not be displayed +float scale_orientation[4] = {0, 0, 1, 0}; +aiVector3D translation(0, 0, 0); +aiMatrix4x4 matr, tmatr; +std::string use, def; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_REF("center", center, XML_ReadNode_GetAttrVal_AsVec3f); + MACRO_ATTRREAD_CHECK_REF("scale", scale, XML_ReadNode_GetAttrVal_AsVec3f); + MACRO_ATTRREAD_CHECK_REF("translation", translation, XML_ReadNode_GetAttrVal_AsVec3f); + if(an == "rotation") + { + std::vector tvec; + + XML_ReadNode_GetAttrVal_AsArrF(idx, tvec); + if(tvec.size() != 4) throw DeadlyImportError(": rotation vector must have 4 elements."); + + memcpy(rotation, tvec.data(), sizeof(rotation)); + + continue; + } + + if(an == "scaleOrientation") + { + std::vector tvec; + + XML_ReadNode_GetAttrVal_AsArrF(idx, tvec); + if(tvec.size() != 4) throw DeadlyImportError(": scaleOrientation vector must have 4 elements."); + + memcpy(scale_orientation, tvec.data(), sizeof(scale_orientation)); + + continue; + } + + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + CX3DImporter_NodeElement* ne; + + MACRO_USE_CHECKANDAPPLY(def, use, ENET_Group, ne); + } + else + { + ParseHelper_Group_Begin();// create new grouping element and go deeper if node has children. + // at this place new group mode created and made current, so we can name it. + if(!def.empty()) NodeElement_Cur->ID = def; + + // + // also set values specific to this type of group + // + // calculate tranformation matrix + aiMatrix4x4::Translation(translation, matr);// T + aiMatrix4x4::Translation(center, tmatr);// C + matr *= tmatr; + aiMatrix4x4::Rotation(rotation[3], aiVector3D(rotation[0], rotation[1], rotation[2]), tmatr);// R + matr *= tmatr; + aiMatrix4x4::Rotation(scale_orientation[3], aiVector3D(scale_orientation[0], scale_orientation[1], scale_orientation[2]), tmatr);// SR + matr *= tmatr; + aiMatrix4x4::Scaling(scale, tmatr);// S + matr *= tmatr; + aiMatrix4x4::Rotation(-scale_orientation[3], aiVector3D(scale_orientation[0], scale_orientation[1], scale_orientation[2]), tmatr);// -SR + matr *= tmatr; + aiMatrix4x4::Translation(-center, tmatr);// -C + matr *= tmatr; + // and assign it + ((CX3DImporter_NodeElement_Group*)NodeElement_Cur)->Transformation = matr; + // in grouping set of nodes check X3DMetadataObject is not needed, because it is done in parser function. + + // for empty element exit from node in that place + if(mReader->isEmptyElement()) ParseHelper_Node_Exit(); + }// if(!use.empty()) else +} + +void X3DImporter::ParseNode_Grouping_TransformEnd() +{ + ParseHelper_Node_Exit();// go up in scene graph +} + +}// namespace Assimp + +#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER diff --git a/code/X3DImporter_Light.cpp b/code/X3DImporter_Light.cpp new file mode 100644 index 000000000..0e2b1d7f6 --- /dev/null +++ b/code/X3DImporter_Light.cpp @@ -0,0 +1,251 @@ +/// \file X3DImporter_Light.cpp +/// \brief Parsing data from nodes of "Lighting" set of X3D. +/// \date 2015-2016 +/// \author nevorek@gmail.com + +#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER + +#include "X3DImporter.hpp" +#include "X3DImporter_Macro.hpp" + +#include + +namespace Assimp +{ + +// +void X3DImporter::ParseNode_Lighting_DirectionalLight() +{ +std::string def, use; +float ambientIntensity = 0; +aiColor3D color(1, 1, 1); +aiVector3D direction(0, 0, -1); +bool global = false; +float intensity = 1; +bool on = true; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("ambientIntensity", ambientIntensity, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_REF("color", color, XML_ReadNode_GetAttrVal_AsCol3f); + MACRO_ATTRREAD_CHECK_REF("direction", direction, XML_ReadNode_GetAttrVal_AsVec3f); + MACRO_ATTRREAD_CHECK_RET("global", global, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("intensity", intensity, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_RET("on", on, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_DirectionalLight, ne); + } + else + { + if(on) + { + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Light(CX3DImporter_NodeElement::ENET_DirectionalLight, NodeElement_Cur); + if(!def.empty()) + ne->ID = def; + else + ne->ID = boost::str(boost::format("DirectionalLight_%s") % (size_t)ne);// make random name + + ((CX3DImporter_NodeElement_Light*)ne)->AmbientIntensity = ambientIntensity; + ((CX3DImporter_NodeElement_Light*)ne)->Color = color; + ((CX3DImporter_NodeElement_Light*)ne)->Direction = direction; + ((CX3DImporter_NodeElement_Light*)ne)->Global = global; + ((CX3DImporter_NodeElement_Light*)ne)->Intensity = intensity; + // Assimp want a node with name similar to a light. "Why? I don't no." ) + ParseHelper_Group_Begin(false); + + NodeElement_Cur->ID = ne->ID;// assign name to node and return to light element. + ParseHelper_Node_Exit(); + // check for child nodes + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "DirectionalLight"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(on) + }// if(!use.empty()) else +} + +// +void X3DImporter::ParseNode_Lighting_PointLight() +{ +std::string def, use; +float ambientIntensity = 0; +aiVector3D attenuation(1, 0, 0); +aiColor3D color(1, 1, 1); +bool global = true; +float intensity = 1; +aiVector3D location(0, 0, 0); +bool on = true; +float radius = 100; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("ambientIntensity", ambientIntensity, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_REF("attenuation", attenuation, XML_ReadNode_GetAttrVal_AsVec3f); + MACRO_ATTRREAD_CHECK_REF("color", color, XML_ReadNode_GetAttrVal_AsCol3f); + MACRO_ATTRREAD_CHECK_RET("global", global, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("intensity", intensity, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_REF("location", location, XML_ReadNode_GetAttrVal_AsVec3f); + MACRO_ATTRREAD_CHECK_RET("on", on, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("radius", radius, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_PointLight, ne); + } + else + { + if(on) + { + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Light(CX3DImporter_NodeElement::ENET_PointLight, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + ((CX3DImporter_NodeElement_Light*)ne)->AmbientIntensity = ambientIntensity; + ((CX3DImporter_NodeElement_Light*)ne)->Attenuation = attenuation; + ((CX3DImporter_NodeElement_Light*)ne)->Color = color; + ((CX3DImporter_NodeElement_Light*)ne)->Global = global; + ((CX3DImporter_NodeElement_Light*)ne)->Intensity = intensity; + ((CX3DImporter_NodeElement_Light*)ne)->Location = location; + ((CX3DImporter_NodeElement_Light*)ne)->Radius = radius; + // Assimp want a node with name similar to a light. "Why? I don't no." ) + ParseHelper_Group_Begin(false); + // make random name + if(ne->ID.empty()) ne->ID = boost::str(boost::format("PointLight_%s") % (size_t)ne); + + NodeElement_Cur->ID = ne->ID;// assign name to node and return to light element. + ParseHelper_Node_Exit(); + // check for child nodes + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "PointLight"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(on) + }// if(!use.empty()) else +} + +// +void X3DImporter::ParseNode_Lighting_SpotLight() +{ +std::string def, use; +float ambientIntensity = 0; +aiVector3D attenuation(1, 0, 0); +float beamWidth = 0.7854; +aiColor3D color(1, 1, 1); +float cutOffAngle = 1.570796; +aiVector3D direction(0, 0, -1); +bool global = true; +float intensity = 1; +aiVector3D location(0, 0, 0); +bool on = true; +float radius = 100; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("ambientIntensity", ambientIntensity, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_REF("attenuation", attenuation, XML_ReadNode_GetAttrVal_AsVec3f); + MACRO_ATTRREAD_CHECK_RET("beamWidth", beamWidth, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_REF("color", color, XML_ReadNode_GetAttrVal_AsCol3f); + MACRO_ATTRREAD_CHECK_RET("cutOffAngle", cutOffAngle, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_REF("direction", direction, XML_ReadNode_GetAttrVal_AsVec3f); + MACRO_ATTRREAD_CHECK_RET("global", global, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("intensity", intensity, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_REF("location", location, XML_ReadNode_GetAttrVal_AsVec3f); + MACRO_ATTRREAD_CHECK_RET("on", on, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("radius", radius, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_SpotLight, ne); + } + else + { + if(on) + { + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Light(CX3DImporter_NodeElement::ENET_SpotLight, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + if(beamWidth > cutOffAngle) beamWidth = cutOffAngle; + + ((CX3DImporter_NodeElement_Light*)ne)->AmbientIntensity = ambientIntensity; + ((CX3DImporter_NodeElement_Light*)ne)->Attenuation = attenuation; + ((CX3DImporter_NodeElement_Light*)ne)->BeamWidth = beamWidth; + ((CX3DImporter_NodeElement_Light*)ne)->Color = color; + ((CX3DImporter_NodeElement_Light*)ne)->CutOffAngle = cutOffAngle; + ((CX3DImporter_NodeElement_Light*)ne)->Direction = direction; + ((CX3DImporter_NodeElement_Light*)ne)->Global = global; + ((CX3DImporter_NodeElement_Light*)ne)->Intensity = intensity; + ((CX3DImporter_NodeElement_Light*)ne)->Location = location; + ((CX3DImporter_NodeElement_Light*)ne)->Radius = radius; + + // Assimp want a node with name similar to a light. "Why? I don't no." ) + ParseHelper_Group_Begin(false); + // make random name + if(ne->ID.empty()) ne->ID = boost::str(boost::format("SpotLight_%s") % (size_t)ne); + + NodeElement_Cur->ID = ne->ID;// assign name to node and return to light element. + ParseHelper_Node_Exit(); + // check for child nodes + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "SpotLight"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(on) + }// if(!use.empty()) else +} + +}// namespace Assimp + +#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER diff --git a/code/X3DImporter_Macro.hpp b/code/X3DImporter_Macro.hpp new file mode 100644 index 000000000..9a1e302fb --- /dev/null +++ b/code/X3DImporter_Macro.hpp @@ -0,0 +1,154 @@ +/// \file X3DImporter_Macro.hpp +/// \brief Useful macrodefines. +/// \date 2015-2016 +/// \author nevorek@gmail.com + +#ifndef X3DIMPORTER_MACRO_HPP_INCLUDED +#define X3DIMPORTER_MACRO_HPP_INCLUDED + +/// \def MACRO_USE_CHECKANDAPPLY(pDEF, pUSE, pNE) +/// Used for regular checking while attribute "USE" is defined. +/// \param [in] pDEF - string holding "DEF" value. +/// \param [in] pUSE - string holding "USE" value. +/// \param [in] pType - type of element to find. +/// \param [out] pNE - pointer to found node element. +#define MACRO_USE_CHECKANDAPPLY(pDEF, pUSE, pType, pNE) \ + do { \ + XML_CheckNode_MustBeEmpty(); \ + if(!pDEF.empty()) Throw_DEF_And_USE(); \ + if(!FindNodeElement(pUSE, CX3DImporter_NodeElement::pType, &pNE)) Throw_USE_NotFound(pUSE); \ + \ + NodeElement_Cur->Child.push_back(pNE);/* add found object as child to current element */ \ + } while(false) + +/// \def MACRO_ATTRREAD_LOOPBEG +/// Begin of loop that read attributes values. +#define MACRO_ATTRREAD_LOOPBEG \ + for(int idx = 0, idx_end = mReader->getAttributeCount(); idx < idx_end; idx++) \ + { \ + std::string an(mReader->getAttributeName(idx)); + +/// \def MACRO_ATTRREAD_LOOPEND +/// End of loop that read attributes values. +#define MACRO_ATTRREAD_LOOPEND \ + Throw_IncorrectAttr(an); \ + } + +/// \def MACRO_ATTRREAD_CHECK_REF +/// Check curent attribute name and if it equal to requested then read value. Result write to output variable by reference. If result was read then +/// "continue" will called. +/// \param [in] pAttrName - attribute name. +/// \param [out] pVarName - output variable name. +/// \param [in] pFunction - function which read attribute value and write it to pVarName. +#define MACRO_ATTRREAD_CHECK_REF(pAttrName, pVarName, pFunction) \ + if(an == pAttrName) \ + { \ + pFunction(idx, pVarName); \ + continue; \ + } + +/// \def MACRO_ATTRREAD_CHECK_RET +/// Check curent attribute name and if it equal to requested then read value. Result write to output variable using return value of \ref pFunction. +/// If result was read then "continue" will called. +/// \param [in] pAttrName - attribute name. +/// \param [out] pVarName - output variable name. +/// \param [in] pFunction - function which read attribute value and write it to pVarName. +#define MACRO_ATTRREAD_CHECK_RET(pAttrName, pVarName, pFunction) \ + if(an == pAttrName) \ + { \ + pVarName = pFunction(idx); \ + continue; \ + } + +/// \def MACRO_ATTRREAD_CHECKUSEDEF_RET +/// Compact variant for checking "USE" and "DEF". Also skip bbox attributes: "bboxCenter", "bboxSize". +/// If result was read then "continue" will called. +/// \param [out] pDEF_Var - output variable name for "DEF" value. +/// \param [out] pUSE_Var - output variable name for "USE" value. +#define MACRO_ATTRREAD_CHECKUSEDEF_RET(pDEF_Var, pUSE_Var) \ + MACRO_ATTRREAD_CHECK_RET("DEF", pDEF_Var, mReader->getAttributeValue); \ + MACRO_ATTRREAD_CHECK_RET("USE", pUSE_Var, mReader->getAttributeValue); \ + if(an == "bboxCenter") continue; \ + if(an == "bboxSize") continue; \ + if(an == "containerField") continue; \ + do {} while(false) + +/// \def MACRO_NODECHECK_LOOPBEGIN(pNodeName) +/// Begin of loop of parsing child nodes. Do not add ';' at end. +/// \param [in] pNodeName - current node name. +#define MACRO_NODECHECK_LOOPBEGIN(pNodeName) \ + do { \ + bool close_found = false; \ + \ + while(mReader->read()) \ + { \ + if(mReader->getNodeType() == irr::io::EXN_ELEMENT) \ + { + +/// \def MACRO_NODECHECK_LOOPEND(pNodeName) +/// End of loop of parsing child nodes. +/// \param [in] pNodeName - current node name. +#define MACRO_NODECHECK_LOOPEND(pNodeName) \ + }/* if(mReader->getNodeType() == irr::io::EXN_ELEMENT) */ \ + else if(mReader->getNodeType() == irr::io::EXN_ELEMENT_END) \ + { \ + if(XML_CheckNode_NameEqual(pNodeName)) \ + { \ + close_found = true; \ + \ + break; \ + } \ + }/* else if(mReader->getNodeType() == irr::io::EXN_ELEMENT_END) */ \ + }/* while(mReader->read()) */ \ + \ + if(!close_found) Throw_CloseNotFound(pNodeName); \ + \ + } while(false) + +#define MACRO_NODECHECK_METADATA(pNodeName) \ + MACRO_NODECHECK_LOOPBEGIN(pNodeName) \ + /* and childs must be metadata nodes */ \ + if(!ParseHelper_CheckRead_X3DMetadataObject()) XML_CheckNode_SkipUnsupported(pNodeName); \ + MACRO_NODECHECK_LOOPEND(pNodeName) + +/// \def MACRO_FACE_ADD_QUAD_FA(pCCW, pOut, pIn, pP1, pP2, pP3, pP4) +/// Add points as quad. Means that pP1..pP4 set in CCW order. +#define MACRO_FACE_ADD_QUAD_FA(pCCW, pOut, pIn, pP1, pP2, pP3, pP4) \ + do { \ + if(pCCW) \ + { \ + pOut.push_back(pIn[pP1]); \ + pOut.push_back(pIn[pP2]); \ + pOut.push_back(pIn[pP3]); \ + pOut.push_back(pIn[pP4]); \ + } \ + else \ + { \ + pOut.push_back(pIn[pP4]); \ + pOut.push_back(pIn[pP3]); \ + pOut.push_back(pIn[pP2]); \ + pOut.push_back(pIn[pP1]); \ + } \ + } while(false) + +/// \def MACRO_FACE_ADD_QUAD(pCCW, pOut, pP1, pP2, pP3, pP4) +/// Add points as quad. Means that pP1..pP4 set in CCW order. +#define MACRO_FACE_ADD_QUAD(pCCW, pOut, pP1, pP2, pP3, pP4) \ + do { \ + if(pCCW) \ + { \ + pOut.push_back(pP1); \ + pOut.push_back(pP2); \ + pOut.push_back(pP3); \ + pOut.push_back(pP4); \ + } \ + else \ + { \ + pOut.push_back(pP4); \ + pOut.push_back(pP3); \ + pOut.push_back(pP2); \ + pOut.push_back(pP1); \ + } \ + } while(false) + +#endif // X3DIMPORTER_MACRO_HPP_INCLUDED diff --git a/code/X3DImporter_Metadata.cpp b/code/X3DImporter_Metadata.cpp new file mode 100644 index 000000000..ab5ab40d2 --- /dev/null +++ b/code/X3DImporter_Metadata.cpp @@ -0,0 +1,236 @@ +/// \file X3DImporter_Metadata.cpp +/// \brief Parsing data from nodes of "Metadata" set of X3D. +/// \date 2015-2016 +/// \author nevorek@gmail.com + +#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER + +#include "X3DImporter.hpp" +#include "X3DImporter_Macro.hpp" + +namespace Assimp +{ + +/// \def MACRO_METADATA_FINDCREATE(pDEF_Var, pUSE_Var, pReference, pValue, pNE, pMetaName) +/// Find element by "USE" or create new one. +/// \param [in] pDEF_Var - variable name with "DEF" value. +/// \param [in] pUSE_Var - variable name with "USE" value. +/// \param [in] pReference - variable name with "reference" value. +/// \param [in] pValue - variable name with "value" value. +/// \param [in, out] pNE - pointer to node element. +/// \param [in] pMetaClass - Class of node. +/// \param [in] pMetaName - Name of node. +/// \param [in] pType - type of element to find. +#define MACRO_METADATA_FINDCREATE(pDEF_Var, pUSE_Var, pReference, pValue, pNE, pMetaClass, pMetaName, pType) \ + /* if "USE" defined then find already defined element. */ \ + if(!pUSE_Var.empty()) \ + { \ + MACRO_USE_CHECKANDAPPLY(pDEF_Var, pUSE_Var, pType, pNE); \ + } \ + else \ + { \ + pNE = new pMetaClass(NodeElement_Cur); \ + if(!pDEF_Var.empty()) pNE->ID = pDEF_Var; \ + \ + ((pMetaClass*)pNE)->Reference = pReference; \ + ((pMetaClass*)pNE)->Value = pValue; \ + /* also metadata node can contain childs */ \ + if(!mReader->isEmptyElement()) \ + ParseNode_Metadata(pNE, pMetaName);/* in that case node element will be added to child elements list of current node. */ \ + else \ + NodeElement_Cur->Child.push_back(pNE);/* else - add element to child list manualy */ \ + \ + NodeElement_List.push_back(pNE);/* add new element to elements list. */ \ + }/* if(!pUSE_Var.empty()) else */ \ + \ + do {} while(false) + +bool X3DImporter::ParseHelper_CheckRead_X3DMetadataObject() +{ + if(XML_CheckNode_NameEqual("MetadataBoolean")) + ParseNode_MetadataBoolean(); + else if(XML_CheckNode_NameEqual("MetadataDouble")) + ParseNode_MetadataDouble(); + else if(XML_CheckNode_NameEqual("MetadataFloat")) + ParseNode_MetadataFloat(); + else if(XML_CheckNode_NameEqual("MetadataInteger")) + ParseNode_MetadataInteger(); + else if(XML_CheckNode_NameEqual("MetadataSet")) + ParseNode_MetadataSet(); + else if(XML_CheckNode_NameEqual("MetadataString")) + ParseNode_MetadataString(); + else + return false; + + return true; +} + +void X3DImporter::ParseNode_Metadata(CX3DImporter_NodeElement* pParentElement, const std::string& pNodeName) +{ + ParseHelper_Node_Enter(pParentElement); + MACRO_NODECHECK_METADATA(mReader->getNodeName()); + ParseHelper_Node_Exit(); +} + +// +void X3DImporter::ParseNode_MetadataBoolean() +{ +std::string def, use; +std::string name, reference; +std::list value; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("name", name, mReader->getAttributeValue); + MACRO_ATTRREAD_CHECK_RET("reference", reference, mReader->getAttributeValue); + MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsListB); + MACRO_ATTRREAD_LOOPEND; + + MACRO_METADATA_FINDCREATE(def, use, reference, value, ne, CX3DImporter_NodeElement_MetaBoolean, "MetadataBoolean", ENET_MetaBoolean); +} + +// +void X3DImporter::ParseNode_MetadataDouble() +{ +std::string def, use; +std::string name, reference; +std::list value; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("name", name, mReader->getAttributeValue); + MACRO_ATTRREAD_CHECK_RET("reference", reference, mReader->getAttributeValue); + MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsListD); + MACRO_ATTRREAD_LOOPEND; + + MACRO_METADATA_FINDCREATE(def, use, reference, value, ne, CX3DImporter_NodeElement_MetaDouble, "MetadataDouble", ENET_MetaDouble); +} + +// +void X3DImporter::ParseNode_MetadataFloat() +{ +std::string def, use; +std::string name, reference; +std::list value; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("name", name, mReader->getAttributeValue); + MACRO_ATTRREAD_CHECK_RET("reference", reference, mReader->getAttributeValue); + MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsListF); + MACRO_ATTRREAD_LOOPEND; + + MACRO_METADATA_FINDCREATE(def, use, reference, value, ne, CX3DImporter_NodeElement_MetaFloat, "MetadataFloat", ENET_MetaFloat); +} + +// +void X3DImporter::ParseNode_MetadataInteger() +{ +std::string def, use; +std::string name, reference; +std::list value; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("name", name, mReader->getAttributeValue); + MACRO_ATTRREAD_CHECK_RET("reference", reference, mReader->getAttributeValue); + MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_LOOPEND; + + MACRO_METADATA_FINDCREATE(def, use, reference, value, ne, CX3DImporter_NodeElement_MetaInteger, "MetadataInteger", ENET_MetaInteger); +} + +// +void X3DImporter::ParseNode_MetadataSet() +{ +std::string def, use; +std::string name, reference; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("name", name, mReader->getAttributeValue); + MACRO_ATTRREAD_CHECK_RET("reference", reference, mReader->getAttributeValue); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_MetaSet, ne); + } + else + { + ne = new CX3DImporter_NodeElement_MetaSet(NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + ((CX3DImporter_NodeElement_MetaSet*)ne)->Reference = reference; + // also metadata node can contain childs + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "MetadataSet"); + else + NodeElement_Cur->Child.push_back(ne);// made object as child to current element + + NodeElement_List.push_back(ne);// add new element to elements list. + }// if(!use.empty()) else +} + +// +void X3DImporter::ParseNode_MetadataString() +{ +std::string def, use; +std::string name, reference; +std::list value; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("name", name, mReader->getAttributeValue); + MACRO_ATTRREAD_CHECK_RET("reference", reference, mReader->getAttributeValue); + MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsListS); + MACRO_ATTRREAD_LOOPEND; + + MACRO_METADATA_FINDCREATE(def, use, reference, value, ne, CX3DImporter_NodeElement_MetaString, "MetadataString", ENET_MetaString); +} + +}// namespace Assimp + +#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER diff --git a/code/X3DImporter_Networking.cpp b/code/X3DImporter_Networking.cpp new file mode 100644 index 000000000..5d257f5f8 --- /dev/null +++ b/code/X3DImporter_Networking.cpp @@ -0,0 +1,69 @@ +/// \file X3DImporter_Rendering.cpp +/// \brief Parsing data from nodes of "Networking" set of X3D. +/// \date 2015-2016 +/// \author nevorek@gmail.com + +#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER + +#include "X3DImporter.hpp" +#include "X3DImporter_Macro.hpp" + +#include "DefaultIOSystem.h" + +namespace Assimp +{ + +// +void X3DImporter::ParseNode_Networking_Inline() +{ +std::string def, use; +bool load = true; +std::list url; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("load", load, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_REF("url", url, XML_ReadNode_GetAttrVal_AsListS); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + CX3DImporter_NodeElement* ne; + + MACRO_USE_CHECKANDAPPLY(def, use, ENET_Group, ne); + } + else + { + ParseHelper_Group_Begin(true);// create new grouping element and go deeper if node has children. + // at this place new group mode created and made current, so we can name it. + if(!def.empty()) NodeElement_Cur->ID = def; + + if(load && (url.size() > 0)) + { + DefaultIOSystem io_handler; + std::string full_path; + + full_path = mFileDir + "/" + url.front(); + // Attribute "url" can contain list of strings. But we need only one - first. + ParseFile(full_path, &io_handler); + } + + // check for X3DMetadataObject childs. + if(!mReader->isEmptyElement()) ParseNode_Metadata(NodeElement_Cur, "Inline"); + + // exit from node in that place + ParseHelper_Node_Exit(); + }// if(!use.empty()) else +} + +}// namespace Assimp + +#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER diff --git a/code/X3DImporter_Node.hpp b/code/X3DImporter_Node.hpp new file mode 100644 index 000000000..ba52e4e52 --- /dev/null +++ b/code/X3DImporter_Node.hpp @@ -0,0 +1,761 @@ +/// \file X3DImporter_Node.hpp +/// \brief Elements of scene graph. +/// \date 2015-2016 +/// \author nevorek@gmail.com + +#ifndef INCLUDED_AI_X3D_IMPORTER_NODE_H +#define INCLUDED_AI_X3D_IMPORTER_NODE_H + +#include +#include + +#include "../include/assimp/types.h" +#include "../include/assimp/scene.h" + +/// \class CX3DImporter_NodeElement +/// Base class for elements of nodes. +class CX3DImporter_NodeElement +{ + /***********************************************/ + /******************** Types ********************/ + /***********************************************/ + +public: + + /// \enum EType + /// Define what data type contain node element. + enum EType + { + ENET_Group, ///< Element has type "Group". + ENET_MetaBoolean, ///< Element has type "Metadata boolean". + ENET_MetaDouble, ///< Element has type "Metadata double". + ENET_MetaFloat, ///< Element has type "Metadata float". + ENET_MetaInteger, ///< Element has type "Metadata integer". + ENET_MetaSet, ///< Element has type "Metadata set". + ENET_MetaString, ///< Element has type "Metadata string". + ENET_Arc2D, ///< Element has type "Arc2D". + ENET_ArcClose2D, ///< Element has type "ArcClose2D". + ENET_Circle2D, ///< Element has type "Circle2D". + ENET_Disk2D, ///< Element has type "Disk2D". + ENET_Polyline2D, ///< Element has type "Polyline2D". + ENET_Polypoint2D, ///< Element has type "Polypoint2D". + ENET_Rectangle2D, ///< Element has type "Rectangle2D". + ENET_TriangleSet2D, ///< Element has type "TriangleSet2D". + ENET_Box, ///< Element has type "Box". + ENET_Cone, ///< Element has type "Cone". + ENET_Cylinder, ///< Element has type "Cylinder". + ENET_Sphere, ///< Element has type "Sphere". + ENET_ElevationGrid, ///< Element has type "ElevationGrid". + ENET_Extrusion, ///< Element has type "Extrusion". + ENET_Coordinate, ///< Element has type "Coordinate". + ENET_Normal, ///< Element has type "Normal". + ENET_TextureCoordinate, ///< Element has type "TextureCoordinate". + ENET_IndexedFaceSet, ///< Element has type "IndexedFaceSet". + ENET_IndexedLineSet, ///< Element has type "IndexedLineSet". + ENET_IndexedTriangleSet, ///< Element has type "IndexedTriangleSet". + ENET_IndexedTriangleFanSet, ///< Element has type "IndexedTriangleFanSet". + ENET_IndexedTriangleStripSet,///< Element has type "IndexedTriangleStripSet". + ENET_LineSet, ///< Element has type "LineSet". + ENET_PointSet, ///< Element has type "PointSet". + ENET_TriangleSet, ///< Element has type "TriangleSet". + ENET_TriangleFanSet, ///< Element has type "TriangleFanSet". + ENET_TriangleStripSet, ///< Element has type "TriangleStripSet". + ENET_Color, ///< Element has type "Color". + ENET_ColorRGBA, ///< Element has type "ColorRGBA". + ENET_Shape, ///< Element has type "Shape". + ENET_Appearance, ///< Element has type "Appearance". + ENET_Material, ///< Element has type "Material". + ENET_ImageTexture, ///< Element has type "ImageTexture". + ENET_TextureTransform, ///< Element has type "TextureTransform". + ENET_DirectionalLight, ///< Element has type "DirectionalLight". + ENET_PointLight, ///< Element has type "PointLight". + ENET_SpotLight, ///< Element has type "SpotLight". + + ENET_Invalid ///< Element has invalid type and possible contain invalid data. + }; + + /***********************************************/ + /****************** Constants ******************/ + /***********************************************/ + +public: + + const EType Type; + + /***********************************************/ + /****************** Variables ******************/ + /***********************************************/ + +public: + + std::string ID;///< ID of the element. Can be empty. In X3D synonym for "ID" attribute. + CX3DImporter_NodeElement* Parent;///< Parrent element. If NULL then this node is root. + std::list Child;///< Child elements. + + /***********************************************/ + /****************** Functions ******************/ + /***********************************************/ + +private: + + /// \fn CX3DImporter_NodeElement(const CX3DImporter_NodeElement& pNodeElement) + /// Disabled copy constructor. + CX3DImporter_NodeElement(const CX3DImporter_NodeElement& pNodeElement); + + /// \fn CX3DImporter_NodeElement& operator=(const CX3DImporter_NodeElement& pNodeElement) + /// Disabled assign operator. + CX3DImporter_NodeElement& operator=(const CX3DImporter_NodeElement& pNodeElement); + + /// \fn CX3DImporter_NodeElement() + /// Disabled default constructor. + CX3DImporter_NodeElement(); + +protected: + + /// \fn CX3DImporter_NodeElement(const EType pType, CX3DImporter_NodeElement* pParent) + /// In constructor inheritor must set element type. + /// \param [in] pType - element type. + /// \param [in] pParent - parent element. + CX3DImporter_NodeElement(const EType pType, CX3DImporter_NodeElement* pParent) + : Type(pType), Parent(pParent) + {} + +};// class IX3DImporter_NodeElement + +/// \class CX3DImporter_NodeElement_Group +/// Class that define grouping node. Define transformation matrix for children. +/// Also can select which child will be kept and others are removed. +class CX3DImporter_NodeElement_Group : public CX3DImporter_NodeElement +{ + /***********************************************/ + /****************** Variables ******************/ + /***********************************************/ + +public: + + aiMatrix4x4 Transformation;///< Transformation matrix. + + /// \var bool Static + /// As you know node elements can use already defined node elements when attribute "USE" is defined. + /// Standard search when looking for an element in the whole scene graph, existing at this moment. + /// If a node is marked as static, the children(or lower) can not search for elements in the nodes upper then static. + bool Static; + + bool UseChoice;///< Flag: if true then use number from \ref Choice to choose what the child will be kept. + int32_t Choice;///< Number of the child which will be kept. + + /***********************************************/ + /****************** Functions ******************/ + /***********************************************/ + +private: + + /// \fn CX3DImporter_NodeElement_Group(const CX3DImporter_NodeElement_Group& pNode) + /// Disabled copy constructor. + CX3DImporter_NodeElement_Group(const CX3DImporter_NodeElement_Group& pNode); + + /// \fn CX3DImporter_NodeElement_Group& operator=(const CX3DImporter_NodeElement_Group& pNode) + /// Disabled assign operator. + CX3DImporter_NodeElement_Group& operator=(const CX3DImporter_NodeElement_Group& pNode); + + /// \fn CX3DImporter_NodeElement_Group() + /// Disabled default constructor. + CX3DImporter_NodeElement_Group(); + +public: + + /// \fn CX3DImporter_NodeElement_Group(CX3DImporter_NodeElement_Group* pParent, const bool pStatic = false) + /// Constructor. + /// \param [in] pParent - pointer to parent node. + /// \param [in] pStatic - static node flag. + CX3DImporter_NodeElement_Group(CX3DImporter_NodeElement* pParent, const bool pStatic = false) + : CX3DImporter_NodeElement(ENET_Group, pParent), Static(pStatic), UseChoice(false) + {} + +};// class CX3DImporter_NodeElement_Group + +/// \class CX3DImporter_NodeElement_Meta +/// This struct describe metavalue. +class CX3DImporter_NodeElement_Meta : public CX3DImporter_NodeElement +{ + /***********************************************/ + /****************** Variables ******************/ + /***********************************************/ + +public: + + std::string Name;///< Name of metadata object. + /// \var std::string Reference + /// If provided, it identifies the metadata standard or other specification that defines the name field. If the reference field is not provided or is + /// empty, the meaning of the name field is considered implicit to the characters in the string. + std::string Reference; + + /***********************************************/ + /****************** Functions ******************/ + /***********************************************/ + +private: + + /// \fn CX3DImporter_NodeElement_Meta(const CX3DImporter_NodeElement_Meta& pNode) + /// Disabled copy constructor. + CX3DImporter_NodeElement_Meta(const CX3DImporter_NodeElement_Meta& pNode); + + /// \fn CX3DImporter_NodeElement_Meta& operator=(const CX3DImporter_NodeElement_Meta& pNode) + /// Disabled assign operator. + CX3DImporter_NodeElement_Meta& operator=(const CX3DImporter_NodeElement_Meta& pNode); + + /// \fn CX3DImporter_NodeElement_Meta() + /// Disabled default constructor. + CX3DImporter_NodeElement_Meta(); + +public: + + /// \fn CX3DImporter_NodeElement_Meta(const EType pType, CX3DImporter_NodeElement* pParent) + /// In constructor inheritor must set element type. + /// \param [in] pType - element type. + /// \param [in] pParent - pointer to parent node. + CX3DImporter_NodeElement_Meta(const EType pType, CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement(pType, pParent) + {} + +};// class CX3DImporter_NodeElement_Meta + +/// \struct CX3DImporter_NodeElement_MetaBoolean +/// This struct describe metavalue of type boolean. +struct CX3DImporter_NodeElement_MetaBoolean : public CX3DImporter_NodeElement_Meta +{ + std::list Value;///< Stored value. + + /// \fn CX3DImporter_NodeElement_MetaBoolean(CX3DImporter_NodeElement* pParent) + /// Constructor + /// \param [in] pParent - pointer to parent node. + CX3DImporter_NodeElement_MetaBoolean(CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement_Meta(ENET_MetaBoolean, pParent) + {} + +};// struct CX3DImporter_NodeElement_MetaBoolean + +/// \struct CX3DImporter_NodeElement_MetaDouble +/// This struct describe metavalue of type double. +struct CX3DImporter_NodeElement_MetaDouble : public CX3DImporter_NodeElement_Meta +{ + std::list Value;///< Stored value. + + /// \fn CX3DImporter_NodeElement_MetaDouble(CX3DImporter_NodeElement* pParent) + /// Constructor + /// \param [in] pParent - pointer to parent node. + CX3DImporter_NodeElement_MetaDouble(CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement_Meta(ENET_MetaDouble, pParent) + {} + +};// struct CX3DImporter_NodeElement_MetaDouble + +/// \struct CX3DImporter_NodeElement_MetaFloat +/// This struct describe metavalue of type float. +struct CX3DImporter_NodeElement_MetaFloat : public CX3DImporter_NodeElement_Meta +{ + std::list Value;///< Stored value. + + /// \fn CX3DImporter_NodeElement_MetaFloat(CX3DImporter_NodeElement* pParent) + /// Constructor + /// \param [in] pParent - pointer to parent node. + CX3DImporter_NodeElement_MetaFloat(CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement_Meta(ENET_MetaFloat, pParent) + {} + +};// struct CX3DImporter_NodeElement_MetaFloat + +/// \struct CX3DImporter_NodeElement_MetaInteger +/// This struct describe metavalue of type integer. +struct CX3DImporter_NodeElement_MetaInteger : public CX3DImporter_NodeElement_Meta +{ + std::list Value;///< Stored value. + + /// \fn CX3DImporter_NodeElement_MetaInteger(CX3DImporter_NodeElement* pParent) + /// Constructor + /// \param [in] pParent - pointer to parent node. + CX3DImporter_NodeElement_MetaInteger(CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement_Meta(ENET_MetaInteger, pParent) + {} + +};// struct CX3DImporter_NodeElement_MetaInteger + +/// \struct CX3DImporter_NodeElement_MetaSet +/// This struct describe container for metaobjects. +struct CX3DImporter_NodeElement_MetaSet : public CX3DImporter_NodeElement_Meta +{ + std::list Value;///< Stored value. + + /// \fn CX3DImporter_NodeElement_MetaSet(CX3DImporter_NodeElement* pParent) + /// Constructor + /// \param [in] pParent - pointer to parent node. + CX3DImporter_NodeElement_MetaSet(CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement_Meta(ENET_MetaSet, pParent) + {} + +};// struct CX3DImporter_NodeElement_MetaSet + +/// \struct CX3DImporter_NodeElement_MetaString +/// This struct describe metavalue of type string. +struct CX3DImporter_NodeElement_MetaString : public CX3DImporter_NodeElement_Meta +{ + std::list Value;///< Stored value. + + /// \fn CX3DImporter_NodeElement_MetaString(CX3DImporter_NodeElement* pParent) + /// Constructor + /// \param [in] pParent - pointer to parent node. + CX3DImporter_NodeElement_MetaString(CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement_Meta(ENET_MetaString, pParent) + {} + +};// struct CX3DImporter_NodeElement_MetaString + +/// \struct CX3DImporter_NodeElement_Color +/// This struct hold value. +struct CX3DImporter_NodeElement_Color : public CX3DImporter_NodeElement +{ + std::list Value;///< Stored value. + + /// \fn CX3DImporter_NodeElement_Color(CX3DImporter_NodeElement* pParent) + /// Constructor + /// \param [in] pParent - pointer to parent node. + CX3DImporter_NodeElement_Color(CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement(ENET_Color, pParent) + {} + +};// struct CX3DImporter_NodeElement_Color + +/// \struct CX3DImporter_NodeElement_ColorRGBA +/// This struct hold value. +struct CX3DImporter_NodeElement_ColorRGBA : public CX3DImporter_NodeElement +{ + std::list Value;///< Stored value. + + /// \fn CX3DImporter_NodeElement_ColorRGBA(CX3DImporter_NodeElement* pParent) + /// Constructor + /// \param [in] pParent - pointer to parent node. + CX3DImporter_NodeElement_ColorRGBA(CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement(ENET_ColorRGBA, pParent) + {} + +};// struct CX3DImporter_NodeElement_ColorRGBA + +/// \struct CX3DImporter_NodeElement_Coordinate +/// This struct hold value. +struct CX3DImporter_NodeElement_Coordinate : public CX3DImporter_NodeElement +{ + std::list Value;///< Stored value. + + /// \fn CX3DImporter_NodeElement_Coordinate(CX3DImporter_NodeElement* pParent) + /// Constructor + /// \param [in] pParent - pointer to parent node. + CX3DImporter_NodeElement_Coordinate(CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement(ENET_Coordinate, pParent) + {} + +};// struct CX3DImporter_NodeElement_Coordinate + +/// \struct CX3DImporter_NodeElement_Normal +/// This struct hold value. +struct CX3DImporter_NodeElement_Normal : public CX3DImporter_NodeElement +{ + std::list Value;///< Stored value. + + /// \fn CX3DImporter_NodeElement_Normal(CX3DImporter_NodeElement* pParent) + /// Constructor + /// \param [in] pParent - pointer to parent node. + CX3DImporter_NodeElement_Normal(CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement(ENET_Normal, pParent) + {} + +};// struct CX3DImporter_NodeElement_Normal + +/// \struct CX3DImporter_NodeElement_TextureCoordinate +/// This struct hold value. +struct CX3DImporter_NodeElement_TextureCoordinate : public CX3DImporter_NodeElement +{ + std::list Value;///< Stored value. + + /// \fn CX3DImporter_NodeElement_TextureCoordinate(CX3DImporter_NodeElement* pParent) + /// Constructor + /// \param [in] pParent - pointer to parent node. + CX3DImporter_NodeElement_TextureCoordinate(CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement(ENET_TextureCoordinate, pParent) + {} + +};// struct CX3DImporter_NodeElement_TextureCoordinate + +/// \class CX3DImporter_NodeElement_Geometry2D +/// Two-dimensional figure. +class CX3DImporter_NodeElement_Geometry2D : public CX3DImporter_NodeElement +{ + /***********************************************/ + /****************** Variables ******************/ + /***********************************************/ + +public: + + std::list Vertices;///< Vertices list. + size_t NumIndices;///< Number of indices in one face. + bool Solid;///< Flag: if true then render must use back-face culling, else render must draw both sides of object. + + /***********************************************/ + /****************** Functions ******************/ + /***********************************************/ + +private: + + /// \fn CX3DImporter_NodeElement_Geometry2D(const CX3DImporter_NodeElement_Geometry2D& pNode) + /// Disabled copy constructor. + CX3DImporter_NodeElement_Geometry2D(const CX3DImporter_NodeElement_Geometry2D& pNode); + + /// \fn CX3DImporter_NodeElement_Geometry2D& operator=(const CX3DImporter_NodeElement_Geometry2D& pNode) + /// Disabled assign operator. + CX3DImporter_NodeElement_Geometry2D& operator=(const CX3DImporter_NodeElement_Geometry2D& pNode); + +public: + + /// \fn CX3DImporter_NodeElement_Geometry2D(const EType pType, CX3DImporter_NodeElement* pParent) + /// Constructor. + /// \param [in] pParent - pointer to parent node. + /// \param [in] pType - type of geometry object. + CX3DImporter_NodeElement_Geometry2D(const EType pType, CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement(pType, pParent), Solid(true) + {} + +};// class CX3DImporter_NodeElement_Geometry2D + +/// \class CX3DImporter_NodeElement_Geometry3D +/// Three-dimensional body. +class CX3DImporter_NodeElement_Geometry3D : public CX3DImporter_NodeElement +{ + /***********************************************/ + /****************** Variables ******************/ + /***********************************************/ + +public: + + std::list Vertices;///< Vertices list. + size_t NumIndices;///< Number of indices in one face. + bool Solid;///< Flag: if true then render must use back-face culling, else render must draw both sides of object. + + /***********************************************/ + /****************** Functions ******************/ + /***********************************************/ + +private: + + /// \fn CX3DImporter_NodeElement_Geometry3D(const CX3DImporter_NodeElement_Geometry3D& pNode) + /// Disabled copy constructor. + CX3DImporter_NodeElement_Geometry3D(const CX3DImporter_NodeElement_Geometry3D& pNode); + + /// \fn CX3DImporter_NodeElement_Geometry3D& operator=(const CX3DImporter_NodeElement_Geometry3D& pNode) + /// Disabled assign operator. + CX3DImporter_NodeElement_Geometry3D& operator=(const CX3DImporter_NodeElement_Geometry3D& pNode); + +public: + + /// \fn CX3DImporter_NodeElement_Geometry3D(const EType pType, CX3DImporter_NodeElement* pParent) + /// Constructor. + /// \param [in] pParent - pointer to parent node. + /// \param [in] pType - type of geometry object. + CX3DImporter_NodeElement_Geometry3D(const EType pType, CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement(pType, pParent), Solid(true) + {} + +};// class CX3DImporter_NodeElement_Geometry3D + +/// \class CX3DImporter_NodeElement_ElevationGrid +/// Uniform rectangular grid of varying height. +class CX3DImporter_NodeElement_ElevationGrid : public CX3DImporter_NodeElement_Geometry3D +{ + /***********************************************/ + /****************** Variables ******************/ + /***********************************************/ + +public: + + bool NormalPerVertex;///< If true then normals are defined for every vertex, else for every face(line). + bool ColorPerVertex;///< If true then colors are defined for every vertex, else for every face(line). + /// \var CreaseAngle + /// If the angle between the geometric normals of two adjacent faces is less than the crease angle, normals shall be calculated so that the faces are + /// shaded smoothly across the edge; otherwise, normals shall be calculated so that a lighting discontinuity across the edge is produced. + float CreaseAngle; + std::list CoordIdx;///< Coordinates list by faces. In X3D format: "-1" - delimiter for faces. + + /***********************************************/ + /****************** Functions ******************/ + /***********************************************/ + +private: + + /// \fn CX3DImporter_NodeElement_ElevationGrid(const CX3DImporter_NodeElement_ElevationGrid& pNode) + /// Disabled copy constructor. + CX3DImporter_NodeElement_ElevationGrid(const CX3DImporter_NodeElement_ElevationGrid& pNode); + + /// \fn CX3DImporter_NodeElement_ElevationGrid& operator=(const CX3DImporter_NodeElement_ElevationGrid& pNode) + /// Disabled assign operator. + CX3DImporter_NodeElement_ElevationGrid& operator=(const CX3DImporter_NodeElement_ElevationGrid& pNode); + +public: + + /// \fn CX3DImporter_NodeElement_ElevationGrid(const EType pType, CX3DImporter_NodeElement* pParent) + /// Constructor. + /// \param [in] pParent - pointer to parent node. + /// \param [in] pType - type of geometry object. + CX3DImporter_NodeElement_ElevationGrid(const EType pType, CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement_Geometry3D(pType, pParent) + {} + +};// class CX3DImporter_NodeElement_IndexedSet + +/// \class CX3DImporter_NodeElement_IndexedSet +/// Shape with indexed vertices. +class CX3DImporter_NodeElement_IndexedSet : public CX3DImporter_NodeElement_Geometry3D +{ + /***********************************************/ + /****************** Variables ******************/ + /***********************************************/ + +public: + + /// \var CCW + /// The ccw field defines the ordering of the vertex coordinates of the geometry with respect to user-given or automatically generated normal vectors + /// used in the lighting model equations. If ccw is TRUE, the normals shall follow the right hand rule; the orientation of each normal with respect to + /// the vertices (taken in order) shall be such that the vertices appear to be oriented in a counterclockwise order when the vertices are viewed (in the + /// local coordinate system of the Shape) from the opposite direction as the normal. If ccw is FALSE, the normals shall be oriented in the opposite + /// direction. If normals are not generated but are supplied using a Normal node, and the orientation of the normals does not match the setting of the + /// ccw field, results are undefined. + bool CCW; + std::list ColorIndex;///< Field to specify the polygonal faces by indexing into the or . + bool ColorPerVertex;///< If true then colors are defined for every vertex, else for every face(line). + /// \var Convex + /// The convex field indicates whether all polygons in the shape are convex (TRUE). A polygon is convex if it is planar, does not intersect itself, + /// and all of the interior angles at its vertices are less than 180 degrees. Non planar and self intersecting polygons may produce undefined results + /// even if the convex field is FALSE. + bool Convex; + std::list CoordIndex;///< Field to specify the polygonal faces by indexing into the . + /// \var CreaseAngle + /// If the angle between the geometric normals of two adjacent faces is less than the crease angle, normals shall be calculated so that the faces are + /// shaded smoothly across the edge; otherwise, normals shall be calculated so that a lighting discontinuity across the edge is produced. + float CreaseAngle; + std::list NormalIndex;///< Field to specify the polygonal faces by indexing into the . + bool NormalPerVertex;///< If true then normals are defined for every vertex, else for every face(line). + std::list TexCoordIndex;///< Field to specify the polygonal faces by indexing into the . + + /***********************************************/ + /****************** Functions ******************/ + /***********************************************/ + +private: + + /// \fn CX3DImporter_NodeElement_IndexedSet(const CX3DImporter_NodeElement_IndexedSet& pNode) + /// Disabled copy constructor. + CX3DImporter_NodeElement_IndexedSet(const CX3DImporter_NodeElement_IndexedSet& pNode); + + /// \fn CX3DImporter_NodeElement_IndexedSet& operator=(const CX3DImporter_NodeElement_IndexedSet& pNode) + /// Disabled assign operator. + CX3DImporter_NodeElement_IndexedSet& operator=(const CX3DImporter_NodeElement_IndexedSet& pNode); + +public: + + /// \fn CX3DImporter_NodeElement_IndexedSet(const EType pType, CX3DImporter_NodeElement* pParent) + /// Constructor. + /// \param [in] pParent - pointer to parent node. + /// \param [in] pType - type of geometry object. + CX3DImporter_NodeElement_IndexedSet(const EType pType, CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement_Geometry3D(pType, pParent) + {} + +};// class CX3DImporter_NodeElement_IndexedSet + +/// \class CX3DImporter_NodeElement_Set +/// Shape with set of vertices. +class CX3DImporter_NodeElement_Set : public CX3DImporter_NodeElement_Geometry3D +{ + /***********************************************/ + /****************** Variables ******************/ + /***********************************************/ + +public: + + /// \var CCW + /// The ccw field defines the ordering of the vertex coordinates of the geometry with respect to user-given or automatically generated normal vectors + /// used in the lighting model equations. If ccw is TRUE, the normals shall follow the right hand rule; the orientation of each normal with respect to + /// the vertices (taken in order) shall be such that the vertices appear to be oriented in a counterclockwise order when the vertices are viewed (in the + /// local coordinate system of the Shape) from the opposite direction as the normal. If ccw is FALSE, the normals shall be oriented in the opposite + /// direction. If normals are not generated but are supplied using a Normal node, and the orientation of the normals does not match the setting of the + /// ccw field, results are undefined. + bool CCW; + bool ColorPerVertex;///< If true then colors are defined for every vertex, else for every face(line). + bool NormalPerVertex;///< If true then normals are defined for every vertex, else for every face(line). + std::list CoordIndex;///< Field to specify the polygonal faces by indexing into the . + std::list NormalIndex;///< Field to specify the polygonal faces by indexing into the . + std::list TexCoordIndex;///< Field to specify the polygonal faces by indexing into the . + std::list VertexCount;///< Field describes how many vertices are to be used in each polyline(polygon) from the field. + + /***********************************************/ + /****************** Functions ******************/ + /***********************************************/ + +private: + + /// \fn CX3DImporter_NodeElement_Set(const CX3DImporter_NodeElement_Set& pNode) + /// Disabled copy constructor. + CX3DImporter_NodeElement_Set(const CX3DImporter_NodeElement_Set& pNode); + + /// \fn CX3DImporter_NodeElement_Set& operator=(const CX3DImporter_NodeElement_Set& pNode) + /// Disabled assign operator. + CX3DImporter_NodeElement_Set& operator=(const CX3DImporter_NodeElement_Set& pNode); + +public: + + /// \fn CX3DImporter_NodeElement_Set(const EType pType, CX3DImporter_NodeElement* pParent) + /// Constructor. + /// \param [in] pParent - pointer to parent node. + /// \param [in] pType - type of geometry object. + CX3DImporter_NodeElement_Set(const EType pType, CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement_Geometry3D(pType, pParent) + {} + +};// class CX3DImporter_NodeElement_Set + +/// \struct CX3DImporter_NodeElement_Shape +/// This struct hold value. +struct CX3DImporter_NodeElement_Shape : public CX3DImporter_NodeElement +{ + /// \fn CX3DImporter_NodeElement_Shape(CX3DImporter_NodeElement_Shape* pParent) + /// Constructor + /// \param [in] pParent - pointer to parent node. + CX3DImporter_NodeElement_Shape(CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement(ENET_Shape, pParent) + {} + +};// struct CX3DImporter_NodeElement_Shape + +/// \struct CX3DImporter_NodeElement_Appearance +/// This struct hold value. +struct CX3DImporter_NodeElement_Appearance : public CX3DImporter_NodeElement +{ + /// \fn CX3DImporter_NodeElement_Appearance(CX3DImporter_NodeElement_Appearance* pParent) + /// Constructor + /// \param [in] pParent - pointer to parent node. + CX3DImporter_NodeElement_Appearance(CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement(ENET_Appearance, pParent) + {} + +};// struct CX3DImporter_NodeElement_Appearance + +/// \class CX3DImporter_NodeElement_Material +/// Material. +class CX3DImporter_NodeElement_Material : public CX3DImporter_NodeElement +{ + /***********************************************/ + /****************** Variables ******************/ + /***********************************************/ + +public: + + float AmbientIntensity;///< Specifies how much ambient light from light sources this surface shall reflect. + aiColor3D DiffuseColor;///< Reflects all X3D light sources depending on the angle of the surface with respect to the light source. + aiColor3D EmissiveColor;///< Models "glowing" objects. This can be useful for displaying pre-lit models. + float Shininess;///< Lower shininess values produce soft glows, while higher values result in sharper, smaller highlights. + aiColor3D SpecularColor;///< The specularColor and shininess fields determine the specular highlights. + float Transparency;///< Specifies how "clear" an object is, with 1.0 being completely transparent, and 0.0 completely opaque. + + /***********************************************/ + /****************** Functions ******************/ + /***********************************************/ + +private: + + /// \fn CX3DImporter_NodeElement_Material(const CX3DImporter_NodeElement_Material& pNode) + /// Disabled copy constructor. + CX3DImporter_NodeElement_Material(const CX3DImporter_NodeElement_Material& pNode); + + /// \fn CX3DImporter_NodeElement_Material& operator=(const CX3DImporter_NodeElement_Material& pNode) + /// Disabled assign operator. + CX3DImporter_NodeElement_Material& operator=(const CX3DImporter_NodeElement_Material& pNode); + +public: + + /// \fn CX3DImporter_NodeElement_Material(const EType pType, CX3DImporter_NodeElement* pParent) + /// Constructor. + /// \param [in] pParent - pointer to parent node. + /// \param [in] pType - type of geometry object. + CX3DImporter_NodeElement_Material(CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement(ENET_Material, pParent) + {} + +};// class CX3DImporter_NodeElement_Material + +/// \struct CX3DImporter_NodeElement_ImageTexture +/// This struct hold value. +struct CX3DImporter_NodeElement_ImageTexture : public CX3DImporter_NodeElement +{ + /// \var RepeatS + /// RepeatS and RepeatT, that specify how the texture wraps in the S and T directions. If repeatS is TRUE (the default), the texture map is repeated + /// outside the [0.0, 1.0] texture coordinate range in the S direction so that it fills the shape. If repeatS is FALSE, the texture coordinates are + /// clamped in the S direction to lie within the [0.0, 1.0] range. The repeatT field is analogous to the repeatS field. + bool RepeatS; + bool RepeatT;///< See \ref RepeatS. + std::string URL;///< URL of the texture. + /// \fn CX3DImporter_NodeElement_ImageTexture(CX3DImporter_NodeElement_ImageTexture* pParent) + /// Constructor + /// \param [in] pParent - pointer to parent node. + CX3DImporter_NodeElement_ImageTexture(CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement(ENET_ImageTexture, pParent) + {} + +};// struct CX3DImporter_NodeElement_ImageTexture + +/// \struct CX3DImporter_NodeElement_TextureTransform +/// This struct hold value. +struct CX3DImporter_NodeElement_TextureTransform : public CX3DImporter_NodeElement +{ + aiVector2D Center;///< Specifies a translation offset in texture coordinate space about which the rotation and scale fields are applied. + float Rotation;///< Specifies a rotation in angle base units of the texture coordinates about the center point after the scale has been applied. + aiVector2D Scale;///< Specifies a scaling factor in S and T of the texture coordinates about the center point. + aiVector2D Translation;///< Specifies a translation of the texture coordinates. + + /// \fn CX3DImporter_NodeElement_TextureTransform(CX3DImporter_NodeElement_TextureTransform* pParent) + /// Constructor + /// \param [in] pParent - pointer to parent node. + CX3DImporter_NodeElement_TextureTransform(CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement(ENET_TextureTransform, pParent) + {} + +};// struct CX3DImporter_NodeElement_TextureTransform + +/// \struct CX3DImporter_NodeElement_Light +/// This struct hold value. +struct CX3DImporter_NodeElement_Light : public CX3DImporter_NodeElement +{ + float AmbientIntensity;///< Specifies the intensity of the ambient emission from the light. + aiColor3D Color;///< specifies the spectral colour properties of both the direct and ambient light emission as an RGB value. + aiVector3D Direction;///< Specifies the direction vector of the illumination emanating from the light source in the local coordinate system. + /// \var Global + /// Field that determines whether the light is global or scoped. Global lights illuminate all objects that fall within their volume of lighting influence. + /// Scoped lights only illuminate objects that are in the same transformation hierarchy as the light. + bool Global; + float Intensity;///< Specifies the brightness of the direct emission from the light. + /// \var Attenuation + /// PointLight node's illumination falls off with distance as specified by three attenuation coefficients. The attenuation factor + /// is: "1 / max(attenuation[0] + attenuation[1] × r + attenuation[2] × r2, 1)", where r is the distance from the light to the surface being illuminated. + aiVector3D Attenuation; + aiVector3D Location;///< Specifies a translation offset of the centre point of the light source from the light's local coordinate system origin. + float Radius;///< Specifies the radial extent of the solid angle and the maximum distance from location that may be illuminated by the light source. + float BeamWidth;///< Specifies an inner solid angle in which the light source emits light at uniform full intensity. + float CutOffAngle;///< The light source's emission intensity drops off from the inner solid angle (beamWidth) to the outer solid angle (cutOffAngle). + + /// \fn CX3DImporter_NodeElement_Light(EType pLightType, CX3DImporter_NodeElement* pParent) + /// Constructor + /// \param [in] pParent - pointer to parent node. + /// \param [in] pLightType - type of the light source. + CX3DImporter_NodeElement_Light(EType pLightType, CX3DImporter_NodeElement* pParent) + : CX3DImporter_NodeElement(pLightType, pParent) + {} + +};// struct CX3DImporter_NodeElement_Light + +#endif // INCLUDED_AI_X3D_IMPORTER_NODE_H diff --git a/code/X3DImporter_Postprocess.cpp b/code/X3DImporter_Postprocess.cpp new file mode 100644 index 000000000..ffb4c8e23 --- /dev/null +++ b/code/X3DImporter_Postprocess.cpp @@ -0,0 +1,772 @@ +/// \file X3DImporter_Postprocess.cpp +/// \brief Convert built scenegraph and objects to Assimp scenegraph. +/// \date 2015-2016 +/// \author nevorek@gmail.com + +#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER + +#include "X3DImporter.hpp" +#include "StandardShapes.h" + +#include +#include + +#include +#include + +namespace Assimp +{ + +aiMatrix4x4 X3DImporter::PostprocessHelper_Matrix_GlobalToCurrent() const +{ +CX3DImporter_NodeElement* cur_node; +std::list matr; +aiMatrix4x4 out_matr; + + // starting walk from current element to root + cur_node = NodeElement_Cur; + if(cur_node != NULL) + { + do + { + // if cur_node is group then store group transformation matrix in list. + if(cur_node->Type == CX3DImporter_NodeElement::ENET_Group) matr.push_back(((CX3DImporter_NodeElement_Group*)cur_node)->Transformation); + + cur_node = cur_node->Parent; + } while(cur_node != NULL); + } + + // multiplicate all matrices in reverse order + for(std::list::reverse_iterator rit = matr.rbegin(); rit != matr.rend(); rit++) out_matr = out_matr * (*rit); + + return out_matr; +} + +void X3DImporter::PostprocessHelper_CollectMetadata(const CX3DImporter_NodeElement& pNodeElement, std::list& pList) const +{ + // walk thru childs and find for metadata. + for(std::list::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); el_it++) + { + if(((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaBoolean) || ((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaDouble) || + ((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaFloat) || ((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaInteger) || + ((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaString)) + { + pList.push_back(*el_it); + } + else if((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaSet) + { + PostprocessHelper_CollectMetadata(**el_it, pList); + } + }// for(std::list::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); el_it++) +} + +bool X3DImporter::PostprocessHelper_ElementIsMetadata(const CX3DImporter_NodeElement::EType pType) const +{ + if((pType == CX3DImporter_NodeElement::ENET_MetaBoolean) || (pType == CX3DImporter_NodeElement::ENET_MetaDouble) || + (pType == CX3DImporter_NodeElement::ENET_MetaFloat) || (pType == CX3DImporter_NodeElement::ENET_MetaInteger) || + (pType == CX3DImporter_NodeElement::ENET_MetaString) || (pType == CX3DImporter_NodeElement::ENET_MetaSet)) + { + return true; + } + else + { + return false; + } +} + +bool X3DImporter::PostprocessHelper_ElementIsMesh(const CX3DImporter_NodeElement::EType pType) const +{ + if((pType == CX3DImporter_NodeElement::ENET_Arc2D) || (pType == CX3DImporter_NodeElement::ENET_ArcClose2D) || + (pType == CX3DImporter_NodeElement::ENET_Box) || (pType == CX3DImporter_NodeElement::ENET_Circle2D) || + (pType == CX3DImporter_NodeElement::ENET_Cone) || (pType == CX3DImporter_NodeElement::ENET_Cylinder) || + (pType == CX3DImporter_NodeElement::ENET_Disk2D) || (pType == CX3DImporter_NodeElement::ENET_ElevationGrid) || + (pType == CX3DImporter_NodeElement::ENET_Extrusion) || (pType == CX3DImporter_NodeElement::ENET_IndexedFaceSet) || + (pType == CX3DImporter_NodeElement::ENET_IndexedLineSet) || (pType == CX3DImporter_NodeElement::ENET_IndexedTriangleFanSet) || + (pType == CX3DImporter_NodeElement::ENET_IndexedTriangleSet) || (pType == CX3DImporter_NodeElement::ENET_IndexedTriangleStripSet) || + (pType == CX3DImporter_NodeElement::ENET_PointSet) || (pType == CX3DImporter_NodeElement::ENET_LineSet) || + (pType == CX3DImporter_NodeElement::ENET_Polyline2D) || (pType == CX3DImporter_NodeElement::ENET_Polypoint2D) || + (pType == CX3DImporter_NodeElement::ENET_Rectangle2D) || (pType == CX3DImporter_NodeElement::ENET_Sphere) || + (pType == CX3DImporter_NodeElement::ENET_TriangleFanSet) || (pType == CX3DImporter_NodeElement::ENET_TriangleSet) || + (pType == CX3DImporter_NodeElement::ENET_TriangleSet2D) || (pType == CX3DImporter_NodeElement::ENET_TriangleStripSet)) + { + return true; + } + else + { + return false; + } +} + +void X3DImporter::Postprocess_BuildLight(const CX3DImporter_NodeElement& pNodeElement, std::list& pSceneLightList) const +{ +aiLight* new_light = new aiLight; +const CX3DImporter_NodeElement_Light& ne = *((CX3DImporter_NodeElement_Light*)&pNodeElement); +aiMatrix4x4 transform_matr = PostprocessHelper_Matrix_GlobalToCurrent(); + + new_light->mName = ne.ID; + new_light->mColorAmbient = ne.Color * ne.AmbientIntensity; + new_light->mColorDiffuse = ne.Color * ne.Intensity; + new_light->mColorSpecular = ne.Color * ne.Intensity; + switch(pNodeElement.Type) + { + case CX3DImporter_NodeElement::ENET_DirectionalLight: + new_light->mType = aiLightSource_DIRECTIONAL; + new_light->mDirection = ne.Direction, new_light->mDirection *= transform_matr; + + break; + case CX3DImporter_NodeElement::ENET_PointLight: + new_light->mType = aiLightSource_POINT; + new_light->mPosition = ne.Location, new_light->mPosition *= transform_matr; + new_light->mAttenuationConstant = ne.Attenuation.x; + new_light->mAttenuationLinear = ne.Attenuation.y; + new_light->mAttenuationQuadratic = ne.Attenuation.z; + + break; + case CX3DImporter_NodeElement::ENET_SpotLight: + new_light->mType = aiLightSource_SPOT; + new_light->mPosition = ne.Location, new_light->mPosition *= transform_matr; + new_light->mDirection = ne.Direction, new_light->mDirection *= transform_matr; + new_light->mAttenuationConstant = ne.Attenuation.x; + new_light->mAttenuationLinear = ne.Attenuation.y; + new_light->mAttenuationQuadratic = ne.Attenuation.z; + new_light->mAngleInnerCone = ne.BeamWidth; + new_light->mAngleOuterCone = ne.CutOffAngle; + + break; + default: + throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildLight. Unknown type of light: %s") % pNodeElement.Type)); + } + + pSceneLightList.push_back(new_light); +} + +void X3DImporter::Postprocess_BuildMaterial(const CX3DImporter_NodeElement& pNodeElement, aiMaterial** pMaterial) const +{ + // check argument + if(pMaterial == NULL) throw DeadlyImportError("Postprocess_BuildMaterial. pMaterial is NULL."); + if(*pMaterial != NULL) throw DeadlyImportError("Postprocess_BuildMaterial. *pMaterial must be NULL."); + + *pMaterial = new aiMaterial; + aiMaterial& taimat = **pMaterial;// creating alias for convenience. + + // at this point pNodeElement point to node. Walk thru childs and add all stored data. + for(std::list::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); el_it++) + { + if((*el_it)->Type == CX3DImporter_NodeElement::ENET_Material) + { + aiColor3D tcol3; + float tvalf; + CX3DImporter_NodeElement_Material& tnemat = *((CX3DImporter_NodeElement_Material*)*el_it); + + tcol3.r = tnemat.AmbientIntensity, tcol3.g = tnemat.AmbientIntensity, tcol3.b = tnemat.AmbientIntensity; + taimat.AddProperty(&tcol3, 1, AI_MATKEY_COLOR_AMBIENT); + taimat.AddProperty(&tnemat.DiffuseColor, 1, AI_MATKEY_COLOR_DIFFUSE); + taimat.AddProperty(&tnemat.EmissiveColor, 1, AI_MATKEY_COLOR_EMISSIVE); + taimat.AddProperty(&tnemat.SpecularColor, 1, AI_MATKEY_COLOR_SPECULAR); + tvalf = 1; + taimat.AddProperty(&tvalf, 1, AI_MATKEY_SHININESS_STRENGTH); + taimat.AddProperty(&tnemat.Shininess, 1, AI_MATKEY_SHININESS); + tvalf = 1.0 - tnemat.Transparency; + taimat.AddProperty(&tvalf, 1, AI_MATKEY_OPACITY); + }// if((*el_it)->Type == CX3DImporter_NodeElement::ENET_Material) + else if((*el_it)->Type == CX3DImporter_NodeElement::ENET_ImageTexture) + { + CX3DImporter_NodeElement_ImageTexture& tnetex = *((CX3DImporter_NodeElement_ImageTexture*)*el_it); + aiString url_str(tnetex.URL.c_str()); + int mode = aiTextureOp_Multiply; + + taimat.AddProperty(&url_str, AI_MATKEY_TEXTURE_DIFFUSE(0)); + taimat.AddProperty(&tnetex.RepeatS, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0)); + taimat.AddProperty(&tnetex.RepeatT, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0)); + taimat.AddProperty(&mode, 1, AI_MATKEY_TEXOP_DIFFUSE(0)); + }// else if((*el_it)->Type == CX3DImporter_NodeElement::ENET_ImageTexture) + else if((*el_it)->Type == CX3DImporter_NodeElement::ENET_TextureTransform) + { + aiUVTransform trans; + CX3DImporter_NodeElement_TextureTransform& tnetextr = *((CX3DImporter_NodeElement_TextureTransform*)*el_it); + + trans.mTranslation = tnetextr.Translation - tnetextr.Center; + trans.mScaling = tnetextr.Scale; + trans.mRotation = tnetextr.Rotation; + taimat.AddProperty(&trans, 1, AI_MATKEY_UVTRANSFORM_DIFFUSE(0)); + }// else if((*el_it)->Type == CX3DImporter_NodeElement::ENET_TextureTransform) + }// for(std::list::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); el_it++) +} + +void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeElement, aiMesh** pMesh) const +{ + // check argument + if(pMesh == NULL) throw DeadlyImportError("Postprocess_BuildMesh. pMesh is NULL."); + if(*pMesh != NULL) throw DeadlyImportError("Postprocess_BuildMesh. *pMesh must be NULL."); + + /************************************************************************************************************************************/ + /************************************************************ Geometry2D ************************************************************/ + /************************************************************************************************************************************/ + if((pNodeElement.Type == CX3DImporter_NodeElement::ENET_Arc2D) || (pNodeElement.Type == CX3DImporter_NodeElement::ENET_ArcClose2D) || + (pNodeElement.Type == CX3DImporter_NodeElement::ENET_Circle2D) || (pNodeElement.Type == CX3DImporter_NodeElement::ENET_Disk2D) || + (pNodeElement.Type == CX3DImporter_NodeElement::ENET_Polyline2D) || (pNodeElement.Type == CX3DImporter_NodeElement::ENET_Polypoint2D) || + (pNodeElement.Type == CX3DImporter_NodeElement::ENET_Rectangle2D) || (pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleSet2D)) + { + CX3DImporter_NodeElement_Geometry2D& tnemesh = *((CX3DImporter_NodeElement_Geometry2D*)&pNodeElement);// create alias for convenience + std::vector tarr; + + tarr.reserve(tnemesh.Vertices.size()); + for(std::list::iterator it = tnemesh.Vertices.begin(); it != tnemesh.Vertices.end(); it++) tarr.push_back(*it); + *pMesh = StandardShapes::MakeMesh(tarr, tnemesh.NumIndices);// create mesh from vertices using Assimp help. + + return;// mesh is build, nothing to do anymore. + } + /************************************************************************************************************************************/ + /************************************************************ Geometry3D ************************************************************/ + /************************************************************************************************************************************/ + // + // Predefined figures + // + if((pNodeElement.Type == CX3DImporter_NodeElement::ENET_Box) || (pNodeElement.Type == CX3DImporter_NodeElement::ENET_Cone) || + (pNodeElement.Type == CX3DImporter_NodeElement::ENET_Cylinder) || (pNodeElement.Type == CX3DImporter_NodeElement::ENET_Sphere)) + { + CX3DImporter_NodeElement_Geometry3D& tnemesh = *((CX3DImporter_NodeElement_Geometry3D*)&pNodeElement);// create alias for convenience + std::vector tarr; + + tarr.reserve(tnemesh.Vertices.size()); + for(std::list::iterator it = tnemesh.Vertices.begin(); it != tnemesh.Vertices.end(); it++) tarr.push_back(*it); + + *pMesh = StandardShapes::MakeMesh(tarr, tnemesh.NumIndices);// create mesh from vertices using Assimp help. + + return;// mesh is build, nothing to do anymore. + } + // + // Parametric figures + // + if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_ElevationGrid) + { + CX3DImporter_NodeElement_ElevationGrid& tnemesh = *((CX3DImporter_NodeElement_ElevationGrid*)&pNodeElement);// create alias for convenience + + // at first create mesh from existing vertices. + *pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIdx, tnemesh.Vertices); + // copy additional information from children + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + { + if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) + MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA) + MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_ColorRGBA*)*ch_it)->Value, tnemesh.ColorPerVertex); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Normal) + MeshGeometry_AddNormal(**pMesh, ((CX3DImporter_NodeElement_Normal*)*ch_it)->Value, tnemesh.NormalPerVertex); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate) + MeshGeometry_AddTexCoord(**pMesh, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); + else + throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildMesh. Unknown child of ElevationGrid: %s.") % (*ch_it)->Type)); + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + + return;// mesh is build, nothing to do anymore. + }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_ElevationGrid) + // + // Indexed primitives sets + // + if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedFaceSet) + { + CX3DImporter_NodeElement_IndexedSet& tnemesh = *((CX3DImporter_NodeElement_IndexedSet*)&pNodeElement);// create alias for convenience + + // at first search for node and create mesh. + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + { + if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) + { + *pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIndex, ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value); + } + } + + // copy additional information from children + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + { + if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) + MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA) + MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((CX3DImporter_NodeElement_ColorRGBA*)*ch_it)->Value, + tnemesh.ColorPerVertex); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) + {} // skip because already read when mesh created. + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Normal) + MeshGeometry_AddNormal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((CX3DImporter_NodeElement_Normal*)*ch_it)->Value, + tnemesh.NormalPerVertex); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate) + MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); + else + throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildMesh. Unknown child of IndexedFaceSet: %s.") % (*ch_it)->Type)); + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + + return;// mesh is build, nothing to do anymore. + }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedFaceSet) + + if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedLineSet) + { + CX3DImporter_NodeElement_IndexedSet& tnemesh = *((CX3DImporter_NodeElement_IndexedSet*)&pNodeElement);// create alias for convenience + + // at first search for node and create mesh. + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + { + if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) + { + *pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIndex, ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value); + } + } + + // copy additional information from children + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + { + if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) + MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA) + MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((CX3DImporter_NodeElement_ColorRGBA*)*ch_it)->Value, + tnemesh.ColorPerVertex); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) + {} // skip because already read when mesh created. + else + throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildMesh. Unknown child of IndexedLineSet: %s.") % (*ch_it)->Type)); + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + + return;// mesh is build, nothing to do anymore. + }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedLineSet) + + if((pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedTriangleSet) || + (pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedTriangleFanSet) || + (pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedTriangleStripSet)) + { + CX3DImporter_NodeElement_IndexedSet& tnemesh = *((CX3DImporter_NodeElement_IndexedSet*)&pNodeElement);// create alias for convenience + + // at first search for node and create mesh. + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + { + if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) + { + *pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIndex, ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value); + } + } + + // copy additional information from children + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + { + if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) + MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA) + MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((CX3DImporter_NodeElement_ColorRGBA*)*ch_it)->Value, + tnemesh.ColorPerVertex); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) + {} // skip because already read when mesh created. + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Normal) + MeshGeometry_AddNormal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((CX3DImporter_NodeElement_Normal*)*ch_it)->Value, + tnemesh.NormalPerVertex); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate) + MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); + else + throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildMesh. Unknown child of IndexedTriangleSet or IndexedTriangleFanSet, or \ + IndexedTriangleStripSet: %s.") % (*ch_it)->Type)); + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + + return;// mesh is build, nothing to do anymore. + }// if((pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedTriangleFanSet) || (pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedTriangleStripSet)) + + if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_Extrusion) + { + CX3DImporter_NodeElement_IndexedSet& tnemesh = *((CX3DImporter_NodeElement_IndexedSet*)&pNodeElement);// create alias for convenience + + *pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIndex, tnemesh.Vertices); + + return;// mesh is build, nothing to do anymore. + }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_Extrusion) + + // + // Primitives sets + // + if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_PointSet) + { + CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience + + // at first search for node and create mesh. + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + { + if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) + { + std::vector vec_copy; + + vec_copy.reserve(((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.size()); + for(std::list::const_iterator it = ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.begin(); + it != ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.end(); it++) + { + vec_copy.push_back(*it); + } + + *pMesh = StandardShapes::MakeMesh(vec_copy, 1); + } + } + + // copy additional information from children + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + { + if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) + MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, true); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA) + MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_ColorRGBA*)*ch_it)->Value, true); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) + {} // skip because already read when mesh created. + else + throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildMesh. Unknown child of PointSet: %s.") % (*ch_it)->Type)); + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + + return;// mesh is build, nothing to do anymore. + }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_PointSet) + + if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_LineSet) + { + CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience + + // at first search for node and create mesh. + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + { + if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) + { + *pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIndex, ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value); + } + } + + // copy additional information from children + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + { + if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) + MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, true); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA) + MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_ColorRGBA*)*ch_it)->Value, true); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) + {} // skip because already read when mesh created. + else + throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildMesh. Unknown child of LineSet: %s.") % (*ch_it)->Type)); + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + + return;// mesh is build, nothing to do anymore. + }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_LineSet) + + if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleFanSet) + { + CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience + + // at first search for node and create mesh. + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + { + if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) + { + *pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIndex, ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value); + } + } + + // copy additional information from children + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + { + if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) + MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value,tnemesh.ColorPerVertex); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA) + MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_ColorRGBA*)*ch_it)->Value, tnemesh.ColorPerVertex); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) + {} // skip because already read when mesh created. + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Normal) + MeshGeometry_AddNormal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((CX3DImporter_NodeElement_Normal*)*ch_it)->Value, + tnemesh.NormalPerVertex); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate) + MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); + else + throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildMesh. Unknown child of TrianlgeFanSet: %s.") % (*ch_it)->Type)); + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + + return;// mesh is build, nothing to do anymore. + }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleFanSet) + + if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleSet) + { + CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience + + // at first search for node and create mesh. + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + { + if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) + { + std::vector vec_copy; + + vec_copy.reserve(((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.size()); + for(std::list::const_iterator it = ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.begin(); + it != ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.end(); it++) + { + vec_copy.push_back(*it); + } + + *pMesh = StandardShapes::MakeMesh(vec_copy, 3); + } + } + + // copy additional information from children + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + { + if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) + MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA) + MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_ColorRGBA*)*ch_it)->Value, tnemesh.ColorPerVertex); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) + {} // skip because already read when mesh created. + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Normal) + MeshGeometry_AddNormal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((CX3DImporter_NodeElement_Normal*)*ch_it)->Value, + tnemesh.NormalPerVertex); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate) + MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); + else + throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildMesh. Unknown child of TrianlgeSet: %s.") % (*ch_it)->Type)); + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + + return;// mesh is build, nothing to do anymore. + }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleSet) + + if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleStripSet) + { + CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience + + // at first search for node and create mesh. + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + { + if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) + { + *pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIndex, ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value); + } + } + + // copy additional information from children + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + { + if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) + MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA) + MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_ColorRGBA*)*ch_it)->Value, tnemesh.ColorPerVertex); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) + {} // skip because already read when mesh created. + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Normal) + MeshGeometry_AddNormal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((CX3DImporter_NodeElement_Normal*)*ch_it)->Value, + tnemesh.NormalPerVertex); + else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate) + MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); + else + throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildMesh. Unknown child of TriangleStripSet: %s.") % (*ch_it)->Type)); + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + + return;// mesh is build, nothing to do anymore. + }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleStripSet) + + throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildMesh. Unknown mesh type: %s.") % pNodeElement.Type)); +} + +void X3DImporter::Postprocess_BuildNode(const CX3DImporter_NodeElement& pNodeElement, aiNode& pSceneNode, std::list& pSceneMeshList, + std::list& pSceneMaterialList, std::list& pSceneLightList) const +{ +std::list::const_iterator chit_begin = pNodeElement.Child.begin(); +std::list::const_iterator chit_end = pNodeElement.Child.end(); +std::list SceneNode_Child; +std::list SceneNode_Light; +std::list SceneNode_Mesh; + + // At first read all metadata + Postprocess_CollectMetadata(pNodeElement, pSceneNode); + // check if we have deal with grouping node. Which can contain transformation or switch + if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_Group) + { + const CX3DImporter_NodeElement_Group& tne_group = *((CX3DImporter_NodeElement_Group*)&pNodeElement);// create alias for convenience + + pSceneNode.mTransformation = tne_group.Transformation; + if(tne_group.UseChoice) + { + // If Choice is less than zero or greater than the number of nodes in the children field, nothing is chosen. + if((tne_group.Choice < 0) || ((size_t)tne_group.Choice >= pNodeElement.Child.size())) + { + chit_begin = pNodeElement.Child.end(); + chit_end = pNodeElement.Child.end(); + } + else + { + for(size_t i = 0; i < (size_t)tne_group.Choice; i++) chit_begin++;// forward iterator to choosed node. + + chit_end = chit_begin; + chit_end++;// point end iterator to next element after choosed. + } + }// if(tne_group.UseChoice) + }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_Group) + + // Reserve memory for fast access and check children. + for(std::list::const_iterator it = chit_begin; it != chit_end; it++) + {// in this loop we do not read metadata because it's already read at begin. + if((*it)->Type == CX3DImporter_NodeElement::ENET_Group) + { + // if child is group then create new node and do recursive call. + aiNode* new_node = new aiNode; + + new_node->mName = (*it)->ID; + new_node->mParent = &pSceneNode; + SceneNode_Child.push_back(new_node); + Postprocess_BuildNode(**it, *new_node, pSceneMeshList, pSceneMaterialList, pSceneLightList); + } + else if((*it)->Type == CX3DImporter_NodeElement::ENET_Shape) + { + // shape can contain only one geometry and one appearance nodes. + Postprocess_BuildShape(*((CX3DImporter_NodeElement_Shape*)*it), SceneNode_Mesh, pSceneMeshList, pSceneMaterialList); + } + else if(((*it)->Type == CX3DImporter_NodeElement::ENET_DirectionalLight) || ((*it)->Type == CX3DImporter_NodeElement::ENET_PointLight) || + ((*it)->Type == CX3DImporter_NodeElement::ENET_SpotLight)) + { + Postprocess_BuildLight(*((CX3DImporter_NodeElement_Light*)*it), pSceneLightList); + } + else if(!PostprocessHelper_ElementIsMetadata((*it)->Type))// skip metadata + { + throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildNode. Unknown type: %s.") % (*it)->Type)); + } + }// for(std::list::const_iterator it = chit_begin; it != chit_end; it++) + + // copy data about children and meshes to aiNode. + if(SceneNode_Child.size() > 0) + { + std::list::const_iterator it = SceneNode_Child.begin(); + + pSceneNode.mNumChildren = SceneNode_Child.size(); + pSceneNode.mChildren = new aiNode*[pSceneNode.mNumChildren]; + for(size_t i = 0; i < pSceneNode.mNumChildren; i++) pSceneNode.mChildren[i] = *it++; + } + + if(SceneNode_Mesh.size() > 0) + { + std::list::const_iterator it = SceneNode_Mesh.begin(); + + pSceneNode.mNumMeshes = SceneNode_Mesh.size(); + pSceneNode.mMeshes = new unsigned int[pSceneNode.mNumMeshes]; + for(size_t i = 0; i < pSceneNode.mNumMeshes; i++) pSceneNode.mMeshes[i] = *it++; + } + + // that's all. return to previous deals +} + +void X3DImporter::Postprocess_BuildShape(const CX3DImporter_NodeElement_Shape& pShapeNodeElement, std::list& pNodeMeshInd, + std::list& pSceneMeshList, std::list& pSceneMaterialList) const +{ +aiMaterial* tmat = NULL; +aiMesh* tmesh = NULL; +CX3DImporter_NodeElement::EType mesh_type = CX3DImporter_NodeElement::ENET_Invalid; +unsigned int mat_ind = 0; + + for(std::list::const_iterator it = pShapeNodeElement.Child.begin(); it != pShapeNodeElement.Child.end(); it++) + { + if(PostprocessHelper_ElementIsMesh((*it)->Type)) + { + Postprocess_BuildMesh(**it, &tmesh); + if(tmesh != NULL) + { + // if mesh successfully built then add data about it to arrays + pNodeMeshInd.push_back(pSceneMeshList.size()); + pSceneMeshList.push_back(tmesh); + // keep mesh type. Need above for texture coordinate generation. + mesh_type = (*it)->Type; + } + } + else if((*it)->Type == CX3DImporter_NodeElement::ENET_Appearance) + { + Postprocess_BuildMaterial(**it, &tmat); + if(tmat != NULL) + { + // if material successfully built then add data about it to array + mat_ind = pSceneMaterialList.size(); + pSceneMaterialList.push_back(tmat); + } + } + }// for(std::list::const_iterator it = pShapeNodeElement.Child.begin(); it != pShapeNodeElement.Child.end(); it++) + + // associate read material with read mesh. + if((tmesh != NULL) && (tmat != NULL)) + { + tmesh->mMaterialIndex = mat_ind; + // Check texture mapping. If material has texture but mesh has no texture coordinate then try to ask Assimp to generate texture coordinates. + if((tmat->GetTextureCount(aiTextureType_DIFFUSE) != 0) && !tmesh->HasTextureCoords(0)) + { + int32_t tm; + aiVector3D tvec3; + + switch(mesh_type) + { + case CX3DImporter_NodeElement::ENET_Box: + tm = aiTextureMapping_BOX; + break; + case CX3DImporter_NodeElement::ENET_Cone: + case CX3DImporter_NodeElement::ENET_Cylinder: + tm = aiTextureMapping_CYLINDER; + break; + case CX3DImporter_NodeElement::ENET_Sphere: + tm = aiTextureMapping_SPHERE; + break; + default: + tm = aiTextureMapping_PLANE; + break; + }// switch(mesh_type) + + tmat->AddProperty(&tm, 1, AI_MATKEY_MAPPING_DIFFUSE(0)); + }// if((tmat->GetTextureCount(aiTextureType_DIFFUSE) != 0) && !tmesh->HasTextureCoords(0)) + }// if((tmesh != NULL) && (tmat != NULL)) +} + +void X3DImporter::Postprocess_CollectMetadata(const CX3DImporter_NodeElement& pNodeElement, aiNode& pSceneNode) const +{ +std::list meta_list; +size_t meta_idx = 0; + + PostprocessHelper_CollectMetadata(pNodeElement, meta_list);// find metadata in current node element. + if(meta_list.size() > 0) + { + if(pSceneNode.mMetaData != NULL) throw DeadlyImportError("Postprocess. MetaData member in node are not NULL. Something went wrong."); + + // copy collected metadata to output node. + pSceneNode.mMetaData = new aiMetadata(); + pSceneNode.mMetaData->mNumProperties = meta_list.size(); + pSceneNode.mMetaData->mKeys = new aiString[pSceneNode.mMetaData->mNumProperties]; + pSceneNode.mMetaData->mValues = new aiMetadataEntry[pSceneNode.mMetaData->mNumProperties]; + for(std::list::const_iterator it = meta_list.begin(); it != meta_list.end(); it++) + { + CX3DImporter_NodeElement_Meta* cur_meta = (CX3DImporter_NodeElement_Meta*)*it; + + // due to limitations we can add only first element of value list. + // Add an element according to its type. + if((*it)->Type == CX3DImporter_NodeElement::ENET_MetaBoolean) + { + if(((CX3DImporter_NodeElement_MetaBoolean*)cur_meta)->Value.size() > 0) + pSceneNode.mMetaData->Set(meta_idx, cur_meta->Name, *(((CX3DImporter_NodeElement_MetaBoolean*)cur_meta)->Value.begin())); + } + else if((*it)->Type == CX3DImporter_NodeElement::ENET_MetaDouble) + { + // at this case also converting double to float. + if(((CX3DImporter_NodeElement_MetaBoolean*)cur_meta)->Value.size() > 0) + pSceneNode.mMetaData->Set(meta_idx, cur_meta->Name, (float)*(((CX3DImporter_NodeElement_MetaDouble*)cur_meta)->Value.begin())); + } + else if((*it)->Type == CX3DImporter_NodeElement::ENET_MetaFloat) + { + if(((CX3DImporter_NodeElement_MetaBoolean*)cur_meta)->Value.size() > 0) + pSceneNode.mMetaData->Set(meta_idx, cur_meta->Name, *(((CX3DImporter_NodeElement_MetaFloat*)cur_meta)->Value.begin())); + } + else if((*it)->Type == CX3DImporter_NodeElement::ENET_MetaInteger) + { + if(((CX3DImporter_NodeElement_MetaBoolean*)cur_meta)->Value.size() > 0) + pSceneNode.mMetaData->Set(meta_idx, cur_meta->Name, *(((CX3DImporter_NodeElement_MetaInteger*)cur_meta)->Value.begin())); + } + else if((*it)->Type == CX3DImporter_NodeElement::ENET_MetaString) + { + if(((CX3DImporter_NodeElement_MetaBoolean*)cur_meta)->Value.size() > 0) + pSceneNode.mMetaData->Set(meta_idx, cur_meta->Name, ((CX3DImporter_NodeElement_MetaString*)cur_meta)->Value.begin()->data()); + } + else + { + throw DeadlyImportError("Postprocess. Unknown metadata type."); + }// if((*it)->Type == CX3DImporter_NodeElement::ENET_Meta*) else + }// for(std::list::const_iterator it = meta_list.begin(); it != meta_list.end(); it++) + }// if(meta_list.size() > 0) +} + +}// namespace Assimp + +#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER diff --git a/code/X3DImporter_Rendering.cpp b/code/X3DImporter_Rendering.cpp new file mode 100644 index 000000000..4dba0f8c8 --- /dev/null +++ b/code/X3DImporter_Rendering.cpp @@ -0,0 +1,937 @@ +/// \file X3DImporter_Rendering.cpp +/// \brief Parsing data from nodes of "Rendering" set of X3D. +/// \date 2015-2016 +/// \author nevorek@gmail.com + +#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER + +#include "X3DImporter.hpp" +#include "X3DImporter_Macro.hpp" + +namespace Assimp +{ + +// +void X3DImporter::ParseNode_Rendering_Color() +{ +std::string use, def; +std::list color; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_REF("color", color, XML_ReadNode_GetAttrVal_AsListCol3f); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_Color, ne); + } + else + { + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Color(NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + ((CX3DImporter_NodeElement_Color*)ne)->Value = color; + // check for X3DMetadataObject childs. + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "Color"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +void X3DImporter::ParseNode_Rendering_ColorRGBA() +{ +std::string use, def; +std::list color; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_REF("color", color, XML_ReadNode_GetAttrVal_AsListCol4f); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_ColorRGBA, ne); + } + else + { + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_ColorRGBA(NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + ((CX3DImporter_NodeElement_ColorRGBA*)ne)->Value = color; + // check for X3DMetadataObject childs. + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "ColorRGBA"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +void X3DImporter::ParseNode_Rendering_Coordinate() +{ +std::string use, def; +std::list point; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_REF("point", point, XML_ReadNode_GetAttrVal_AsListVec3f); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_Coordinate, ne); + } + else + { + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Coordinate(NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + ((CX3DImporter_NodeElement_Coordinate*)ne)->Value = point; + // check for X3DMetadataObject childs. + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "Coordinate"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +// +// ColorCoordinateContentModel is the child-node content model corresponding to IndexedLineSet, LineSet and PointSet. ColorCoordinateContentModel can +// contain any-order Coordinate node with Color (or ColorRGBA) node. No more than one instance of any single node type is allowed. +// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model. +// +void X3DImporter::ParseNode_Rendering_IndexedLineSet() +{ +std::string use, def; +std::list colorIndex; +bool colorPerVertex = true; +std::list coordIndex; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_REF("colorIndex", colorIndex, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_REF("coordIndex", coordIndex, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_IndexedLineSet, ne); + } + else + { + // check data + if((coordIndex.size() < 2) || ((coordIndex.back() == (-1)) && (coordIndex.size() < 3))) + throw DeadlyImportError("IndexedLineSet must contain not empty \"coordIndex\" attribute."); + + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_IndexedSet(CX3DImporter_NodeElement::ENET_IndexedLineSet, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + CX3DImporter_NodeElement_IndexedSet& ne_alias = *((CX3DImporter_NodeElement_IndexedSet*)ne); + + ne_alias.ColorIndex = colorIndex; + ne_alias.ColorPerVertex = colorPerVertex; + ne_alias.CoordIndex = coordIndex; + // check for child nodes + if(!mReader->isEmptyElement()) + { + ParseHelper_Node_Enter(ne); + MACRO_NODECHECK_LOOPBEGIN("IndexedLineSet"); + // check for Color and Coordinate nodes + if(XML_CheckNode_NameEqual("Color")) { ParseNode_Rendering_Color(); continue; } + if(XML_CheckNode_NameEqual("ColorRGBA")) { ParseNode_Rendering_ColorRGBA(); continue; } + if(XML_CheckNode_NameEqual("Coordinate")) { ParseNode_Rendering_Coordinate(); continue; } + // check for X3DMetadataObject + if(!ParseHelper_CheckRead_X3DMetadataObject()) XML_CheckNode_SkipUnsupported("IndexedLineSet"); + + MACRO_NODECHECK_LOOPEND("IndexedLineSet"); + ParseHelper_Node_Exit(); + }// if(!mReader->isEmptyElement()) + else + { + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + } + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +// +// ComposedGeometryContentModel is the child-node content model corresponding to X3DComposedGeometryNodes. It can contain Color (or ColorRGBA), Coordinate, +// Normal and TextureCoordinate, in any order. No more than one instance of these nodes is allowed. Multiple VertexAttribute (FloatVertexAttribute, +// Matrix3VertexAttribute, Matrix4VertexAttribute) nodes can also be contained. +// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model. +// +void X3DImporter::ParseNode_Rendering_IndexedTriangleFanSet() +{ +std::string use, def; +bool ccw = true; +bool colorPerVertex = true; +std::list index; +bool normalPerVertex = true; +bool solid = true; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_REF("index", index, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_IndexedTriangleFanSet, ne); + } + else + { + // check data + if(index.size() == 0) throw DeadlyImportError("IndexedTriangleFanSet must contain not empty \"index\" attribute."); + + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_IndexedSet(CX3DImporter_NodeElement::ENET_IndexedTriangleFanSet, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + CX3DImporter_NodeElement_IndexedSet& ne_alias = *((CX3DImporter_NodeElement_IndexedSet*)ne); + + ne_alias.CCW = ccw; + ne_alias.ColorPerVertex = colorPerVertex; + ne_alias.CoordIndex = index; + ne_alias.NormalPerVertex = normalPerVertex; + ne_alias.Solid = solid; + // check for child nodes + if(!mReader->isEmptyElement()) + { + ParseHelper_Node_Enter(ne); + MACRO_NODECHECK_LOOPBEGIN("IndexedTriangleFanSet"); + // check for X3DComposedGeometryNodes + if(XML_CheckNode_NameEqual("Color")) { ParseNode_Rendering_Color(); continue; } + if(XML_CheckNode_NameEqual("ColorRGBA")) { ParseNode_Rendering_ColorRGBA(); continue; } + if(XML_CheckNode_NameEqual("Coordinate")) { ParseNode_Rendering_Coordinate(); continue; } + if(XML_CheckNode_NameEqual("Normal")) { ParseNode_Rendering_Normal(); continue; } + if(XML_CheckNode_NameEqual("TextureCoordinate")) { ParseNode_Texturing_TextureCoordinate(); continue; } + // check for X3DMetadataObject + if(!ParseHelper_CheckRead_X3DMetadataObject()) XML_CheckNode_SkipUnsupported("IndexedTriangleFanSet"); + + MACRO_NODECHECK_LOOPEND("IndexedTriangleFanSet"); + ParseHelper_Node_Exit(); + }// if(!mReader->isEmptyElement()) + else + { + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + } + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +// +// ComposedGeometryContentModel is the child-node content model corresponding to X3DComposedGeometryNodes. It can contain Color (or ColorRGBA), Coordinate, +// Normal and TextureCoordinate, in any order. No more than one instance of these nodes is allowed. Multiple VertexAttribute (FloatVertexAttribute, +// Matrix3VertexAttribute, Matrix4VertexAttribute) nodes can also be contained. +// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model. +// +void X3DImporter::ParseNode_Rendering_IndexedTriangleSet() +{ +std::string use, def; +bool ccw = true; +bool colorPerVertex = true; +std::list index; +bool normalPerVertex = true; +bool solid = true; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_REF("index", index, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_IndexedTriangleSet, ne); + } + else + { + // check data + if(index.size() == 0) throw DeadlyImportError("IndexedTriangleSet must contain not empty \"index\" attribute."); + + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_IndexedSet(CX3DImporter_NodeElement::ENET_IndexedTriangleSet, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + CX3DImporter_NodeElement_IndexedSet& ne_alias = *((CX3DImporter_NodeElement_IndexedSet*)ne); + + ne_alias.CCW = ccw; + ne_alias.ColorPerVertex = colorPerVertex; + ne_alias.CoordIndex = index; + ne_alias.NormalPerVertex = normalPerVertex; + ne_alias.Solid = solid; + // check for child nodes + if(!mReader->isEmptyElement()) + { + ParseHelper_Node_Enter(ne); + MACRO_NODECHECK_LOOPBEGIN("IndexedTriangleSet"); + // check for X3DComposedGeometryNodes + if(XML_CheckNode_NameEqual("Color")) { ParseNode_Rendering_Color(); continue; } + if(XML_CheckNode_NameEqual("ColorRGBA")) { ParseNode_Rendering_ColorRGBA(); continue; } + if(XML_CheckNode_NameEqual("Coordinate")) { ParseNode_Rendering_Coordinate(); continue; } + if(XML_CheckNode_NameEqual("Normal")) { ParseNode_Rendering_Normal(); continue; } + if(XML_CheckNode_NameEqual("TextureCoordinate")) { ParseNode_Texturing_TextureCoordinate(); continue; } + // check for X3DMetadataObject + if(!ParseHelper_CheckRead_X3DMetadataObject()) XML_CheckNode_SkipUnsupported("IndexedTriangleSet"); + + MACRO_NODECHECK_LOOPEND("IndexedTriangleSet"); + ParseHelper_Node_Exit(); + }// if(!mReader->isEmptyElement()) + else + { + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + } + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +// +// ComposedGeometryContentModel is the child-node content model corresponding to X3DComposedGeometryNodes. It can contain Color (or ColorRGBA), Coordinate, +// Normal and TextureCoordinate, in any order. No more than one instance of these nodes is allowed. Multiple VertexAttribute (FloatVertexAttribute, +// Matrix3VertexAttribute, Matrix4VertexAttribute) nodes can also be contained. +// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model. +// +void X3DImporter::ParseNode_Rendering_IndexedTriangleStripSet() +{ +std::string use, def; +bool ccw = true; +bool colorPerVertex = true; +std::list index; +bool normalPerVertex = true; +bool solid = true; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_REF("index", index, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_IndexedTriangleStripSet, ne); + } + else + { + // check data + if(index.size() == 0) throw DeadlyImportError("IndexedTriangleStripSet must contain not empty \"index\" attribute."); + + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_IndexedSet(CX3DImporter_NodeElement::ENET_IndexedTriangleStripSet, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + CX3DImporter_NodeElement_IndexedSet& ne_alias = *((CX3DImporter_NodeElement_IndexedSet*)ne); + + ne_alias.CCW = ccw; + ne_alias.ColorPerVertex = colorPerVertex; + ne_alias.CoordIndex = index; + ne_alias.NormalPerVertex = normalPerVertex; + ne_alias.Solid = solid; + // check for child nodes + if(!mReader->isEmptyElement()) + { + ParseHelper_Node_Enter(ne); + MACRO_NODECHECK_LOOPBEGIN("IndexedTriangleStripSet"); + // check for X3DComposedGeometryNodes + if(XML_CheckNode_NameEqual("Color")) { ParseNode_Rendering_Color(); continue; } + if(XML_CheckNode_NameEqual("ColorRGBA")) { ParseNode_Rendering_ColorRGBA(); continue; } + if(XML_CheckNode_NameEqual("Coordinate")) { ParseNode_Rendering_Coordinate(); continue; } + if(XML_CheckNode_NameEqual("Normal")) { ParseNode_Rendering_Normal(); continue; } + if(XML_CheckNode_NameEqual("TextureCoordinate")) { ParseNode_Texturing_TextureCoordinate(); continue; } + // check for X3DMetadataObject + if(!ParseHelper_CheckRead_X3DMetadataObject()) XML_CheckNode_SkipUnsupported("IndexedTriangleStripSet"); + + MACRO_NODECHECK_LOOPEND("IndexedTriangleStripSet"); + ParseHelper_Node_Exit(); + }// if(!mReader->isEmptyElement()) + else + { + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + } + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +// +// ColorCoordinateContentModel is the child-node content model corresponding to IndexedLineSet, LineSet and PointSet. ColorCoordinateContentModel can +// contain any-order Coordinate node with Color (or ColorRGBA) node. No more than one instance of any single node type is allowed. +// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model. +// +void X3DImporter::ParseNode_Rendering_LineSet() +{ +std::string use, def; +std::list vertexCount; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_REF("vertexCount", vertexCount, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_LineSet, ne); + } + else + { + // check data + if(vertexCount.size() == 0) throw DeadlyImportError("LineSet must contain not empty \"vertexCount\" attribute."); + + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Set(CX3DImporter_NodeElement::ENET_LineSet, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + CX3DImporter_NodeElement_Set& ne_alias = *((CX3DImporter_NodeElement_Set*)ne); + + ne_alias.VertexCount = vertexCount; + // create CoordIdx + size_t coord_num = 0; + + ne_alias.CoordIndex.clear(); + for(std::list::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++) + { + if(*vc_it < 2) throw DeadlyImportError("LineSet. vertexCount shall be greater than or equal to two."); + + for(int32_t i = 0; i < *vc_it; i++) ne_alias.CoordIndex.push_back(coord_num++);// add vertices indices + + ne_alias.CoordIndex.push_back(-1);// add face delimiter. + } + + // check for child nodes + if(!mReader->isEmptyElement()) + { + ParseHelper_Node_Enter(ne); + MACRO_NODECHECK_LOOPBEGIN("LineSet"); + // check for X3DComposedGeometryNodes + if(XML_CheckNode_NameEqual("Color")) { ParseNode_Rendering_Color(); continue; } + if(XML_CheckNode_NameEqual("ColorRGBA")) { ParseNode_Rendering_ColorRGBA(); continue; } + if(XML_CheckNode_NameEqual("Coordinate")) { ParseNode_Rendering_Coordinate(); continue; } + // check for X3DMetadataObject + if(!ParseHelper_CheckRead_X3DMetadataObject()) XML_CheckNode_SkipUnsupported("LineSet"); + + MACRO_NODECHECK_LOOPEND("LineSet"); + ParseHelper_Node_Exit(); + }// if(!mReader->isEmptyElement()) + else + { + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + } + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +// +// ColorCoordinateContentModel is the child-node content model corresponding to IndexedLineSet, LineSet and PointSet. ColorCoordinateContentModel can +// contain any-order Coordinate node with Color (or ColorRGBA) node. No more than one instance of any single node type is allowed. +// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model. +// +void X3DImporter::ParseNode_Rendering_PointSet() +{ +std::string use, def; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_PointSet, ne); + } + else + { + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_IndexedSet(CX3DImporter_NodeElement::ENET_PointSet, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + // check for child nodes + if(!mReader->isEmptyElement()) + { + ParseHelper_Node_Enter(ne); + MACRO_NODECHECK_LOOPBEGIN("PointSet"); + // check for X3DComposedGeometryNodes + if(XML_CheckNode_NameEqual("Color")) { ParseNode_Rendering_Color(); continue; } + if(XML_CheckNode_NameEqual("ColorRGBA")) { ParseNode_Rendering_ColorRGBA(); continue; } + if(XML_CheckNode_NameEqual("Coordinate")) { ParseNode_Rendering_Coordinate(); continue; } + // check for X3DMetadataObject + if(!ParseHelper_CheckRead_X3DMetadataObject()) XML_CheckNode_SkipUnsupported("PointSet"); + + MACRO_NODECHECK_LOOPEND("PointSet"); + ParseHelper_Node_Exit(); + }// if(!mReader->isEmptyElement()) + else + { + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + } + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +// +// ComposedGeometryContentModel is the child-node content model corresponding to X3DComposedGeometryNodes. It can contain Color (or ColorRGBA), Coordinate, +// Normal and TextureCoordinate, in any order. No more than one instance of these nodes is allowed. Multiple VertexAttribute (FloatVertexAttribute, +// Matrix3VertexAttribute, Matrix4VertexAttribute) nodes can also be contained. +// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model. +// +void X3DImporter::ParseNode_Rendering_TriangleFanSet() +{ +std::string use, def; +bool ccw = true; +bool colorPerVertex = true; +std::list fanCount; +bool normalPerVertex = true; +bool solid = true; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_REF("fanCount", fanCount, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_TriangleFanSet, ne); + } + else + { + // check data + if(fanCount.size() == 0) throw DeadlyImportError("TriangleFanSet must contain not empty \"fanCount\" attribute."); + + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Set(CX3DImporter_NodeElement::ENET_TriangleFanSet, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + CX3DImporter_NodeElement_Set& ne_alias = *((CX3DImporter_NodeElement_Set*)ne); + + ne_alias.CCW = ccw; + ne_alias.ColorPerVertex = colorPerVertex; + ne_alias.VertexCount = fanCount; + ne_alias.NormalPerVertex = normalPerVertex; + ne_alias.Solid = solid; + // create CoordIdx + size_t coord_num_first, coord_num_prev; + + ne_alias.CoordIndex.clear(); + // assign indices for first triangle + coord_num_first = 0; + coord_num_prev = 1; + for(std::list::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++) + { + if(*vc_it < 3) throw DeadlyImportError("TriangleFanSet. fanCount shall be greater than or equal to three."); + + for(int32_t vc = 2; vc < *vc_it; vc++) + { + if(ccw) + { + // 2 1 + // 0 + ne_alias.CoordIndex.push_back(coord_num_first);// first vertex is a center and always is [0]. + ne_alias.CoordIndex.push_back(coord_num_prev++); + ne_alias.CoordIndex.push_back(coord_num_prev); + } + else + { + // 1 2 + // 0 + ne_alias.CoordIndex.push_back(coord_num_first);// first vertex is a center and always is [0]. + ne_alias.CoordIndex.push_back(coord_num_prev + 1); + ne_alias.CoordIndex.push_back(coord_num_prev++); + }// if(ccw) else + + ne_alias.CoordIndex.push_back(-1);// add face delimiter. + }// for(int32_t vc = 2; vc < *vc_it; vc++) + + coord_num_prev++;// that index will be center of next fan + coord_num_first = coord_num_prev++;// forward to next point - second point of fan + }// for(std::list::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++) + // check for child nodes + if(!mReader->isEmptyElement()) + { + ParseHelper_Node_Enter(ne); + MACRO_NODECHECK_LOOPBEGIN("TriangleFanSet"); + // check for X3DComposedGeometryNodes + if(XML_CheckNode_NameEqual("Color")) { ParseNode_Rendering_Color(); continue; } + if(XML_CheckNode_NameEqual("ColorRGBA")) { ParseNode_Rendering_ColorRGBA(); continue; } + if(XML_CheckNode_NameEqual("Coordinate")) { ParseNode_Rendering_Coordinate(); continue; } + if(XML_CheckNode_NameEqual("Normal")) { ParseNode_Rendering_Normal(); continue; } + if(XML_CheckNode_NameEqual("TextureCoordinate")) { ParseNode_Texturing_TextureCoordinate(); continue; } + // check for X3DMetadataObject + if(!ParseHelper_CheckRead_X3DMetadataObject()) XML_CheckNode_SkipUnsupported("TriangleFanSet"); + + MACRO_NODECHECK_LOOPEND("TriangleFanSet"); + ParseHelper_Node_Exit(); + }// if(!mReader->isEmptyElement()) + else + { + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + } + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +// +// ComposedGeometryContentModel is the child-node content model corresponding to X3DComposedGeometryNodes. It can contain Color (or ColorRGBA), Coordinate, +// Normal and TextureCoordinate, in any order. No more than one instance of these nodes is allowed. Multiple VertexAttribute (FloatVertexAttribute, +// Matrix3VertexAttribute, Matrix4VertexAttribute) nodes can also be contained. +// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model. +// +void X3DImporter::ParseNode_Rendering_TriangleSet() +{ +std::string use, def; +bool ccw = true; +bool colorPerVertex = true; +bool normalPerVertex = true; +bool solid = true; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_TriangleSet, ne); + } + else + { + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_IndexedSet(CX3DImporter_NodeElement::ENET_TriangleSet, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + CX3DImporter_NodeElement_Set& ne_alias = *((CX3DImporter_NodeElement_Set*)ne); + + ne_alias.CCW = ccw; + ne_alias.ColorPerVertex = colorPerVertex; + ne_alias.NormalPerVertex = normalPerVertex; + ne_alias.Solid = solid; + // check for child nodes + if(!mReader->isEmptyElement()) + { + ParseHelper_Node_Enter(ne); + MACRO_NODECHECK_LOOPBEGIN("TriangleSet"); + // check for X3DComposedGeometryNodes + if(XML_CheckNode_NameEqual("Color")) { ParseNode_Rendering_Color(); continue; } + if(XML_CheckNode_NameEqual("ColorRGBA")) { ParseNode_Rendering_ColorRGBA(); continue; } + if(XML_CheckNode_NameEqual("Coordinate")) { ParseNode_Rendering_Coordinate(); continue; } + if(XML_CheckNode_NameEqual("Normal")) { ParseNode_Rendering_Normal(); continue; } + if(XML_CheckNode_NameEqual("TextureCoordinate")) { ParseNode_Texturing_TextureCoordinate(); continue; } + // check for X3DMetadataObject + if(!ParseHelper_CheckRead_X3DMetadataObject()) XML_CheckNode_SkipUnsupported("TriangleSet"); + + MACRO_NODECHECK_LOOPEND("TriangleSet"); + ParseHelper_Node_Exit(); + }// if(!mReader->isEmptyElement()) + else + { + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + } + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +// +// ComposedGeometryContentModel is the child-node content model corresponding to X3DComposedGeometryNodes. It can contain Color (or ColorRGBA), Coordinate, +// Normal and TextureCoordinate, in any order. No more than one instance of these nodes is allowed. Multiple VertexAttribute (FloatVertexAttribute, +// Matrix3VertexAttribute, Matrix4VertexAttribute) nodes can also be contained. +// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model. +// +void X3DImporter::ParseNode_Rendering_TriangleStripSet() +{ +std::string use, def; +bool ccw = true; +bool colorPerVertex = true; +std::list stripCount; +bool normalPerVertex = true; +bool solid = true; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_REF("stripCount", stripCount, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_TriangleStripSet, ne); + } + else + { + // check data + if(stripCount.size() == 0) throw DeadlyImportError("TriangleStripSet must contain not empty \"stripCount\" attribute."); + + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Set(CX3DImporter_NodeElement::ENET_TriangleStripSet, NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + CX3DImporter_NodeElement_Set& ne_alias = *((CX3DImporter_NodeElement_Set*)ne); + + ne_alias.CCW = ccw; + ne_alias.ColorPerVertex = colorPerVertex; + ne_alias.VertexCount = stripCount; + ne_alias.NormalPerVertex = normalPerVertex; + ne_alias.Solid = solid; + // create CoordIdx + size_t coord_num0, coord_num1, coord_num2;// indices of current triangle + bool odd_tri;// sequence of current triangle + size_t coord_num_sb;// index of first point of strip + + ne_alias.CoordIndex.clear(); + coord_num_sb = 0; + for(std::list::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++) + { + if(*vc_it < 3) throw DeadlyImportError("TriangleStripSet. stripCount shall be greater than or equal to three."); + + // set initial values for first triangle + coord_num0 = coord_num_sb; + coord_num1 = coord_num_sb + 1; + coord_num2 = coord_num_sb + 2; + odd_tri = true; + + for(int32_t vc = 2; vc < *vc_it; vc++) + { + if(ccw) + { + // 0 2 + // 1 + ne_alias.CoordIndex.push_back(coord_num0); + ne_alias.CoordIndex.push_back(coord_num1); + ne_alias.CoordIndex.push_back(coord_num2); + } + else + { + // 0 1 + // 2 + ne_alias.CoordIndex.push_back(coord_num0); + ne_alias.CoordIndex.push_back(coord_num2); + ne_alias.CoordIndex.push_back(coord_num1); + }// if(ccw) else + + ne_alias.CoordIndex.push_back(-1);// add face delimiter. + // prepare values for next triangle + if(odd_tri) + { + coord_num0 = coord_num2; + coord_num2++; + } + else + { + coord_num1 = coord_num2; + coord_num2 = coord_num1 + 1; + } + + odd_tri = !odd_tri; + coord_num_sb = coord_num2;// that index will be start of next strip + }// for(int32_t vc = 2; vc < *vc_it; vc++) + }// for(std::list::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++) + // check for child nodes + if(!mReader->isEmptyElement()) + { + ParseHelper_Node_Enter(ne); + MACRO_NODECHECK_LOOPBEGIN("TriangleStripSet"); + // check for X3DComposedGeometryNodes + if(XML_CheckNode_NameEqual("Color")) { ParseNode_Rendering_Color(); continue; } + if(XML_CheckNode_NameEqual("ColorRGBA")) { ParseNode_Rendering_ColorRGBA(); continue; } + if(XML_CheckNode_NameEqual("Coordinate")) { ParseNode_Rendering_Coordinate(); continue; } + if(XML_CheckNode_NameEqual("Normal")) { ParseNode_Rendering_Normal(); continue; } + if(XML_CheckNode_NameEqual("TextureCoordinate")) { ParseNode_Texturing_TextureCoordinate(); continue; } + // check for X3DMetadataObject + if(!ParseHelper_CheckRead_X3DMetadataObject()) XML_CheckNode_SkipUnsupported("TriangleStripSet"); + + MACRO_NODECHECK_LOOPEND("TriangleStripSet"); + ParseHelper_Node_Exit(); + }// if(!mReader->isEmptyElement()) + else + { + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + } + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +void X3DImporter::ParseNode_Rendering_Normal() +{ +std::string use, def; +std::list vector; +CX3DImporter_NodeElement* ne; +LogInfo("TRACE: scene rendering Normal b"); + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_REF("vector", vector, XML_ReadNode_GetAttrVal_AsListVec3f); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_Normal, ne); + } + else + { + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Normal(NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + ((CX3DImporter_NodeElement_Normal*)ne)->Value = vector; + // check for X3DMetadataObject childs. + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "Normal"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +LogInfo("TRACE: scene rendering Normal e"); +} + +}// namespace Assimp + +#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER diff --git a/code/X3DImporter_Shape.cpp b/code/X3DImporter_Shape.cpp new file mode 100644 index 000000000..26016f24f --- /dev/null +++ b/code/X3DImporter_Shape.cpp @@ -0,0 +1,209 @@ +/// \file X3DImporter_Shape.cpp +/// \brief Parsing data from nodes of "Shape" set of X3D. +/// \date 2015-2016 +/// \author nevorek@gmail.com + +#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER + +#include "X3DImporter.hpp" +#include "X3DImporter_Macro.hpp" + +namespace Assimp +{ + +// +// +// "ShapeChildContentModel is the child-node content model corresponding to X3DShapeNode. ShapeChildContentModel can contain a single Appearance node and a +// single geometry node, in any order. +// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model." +// +// A Shape node is unlit if either of the following is true: +// The shape's appearance field is NULL (default). +// The material field in the Appearance node is NULL (default). +// NOTE Geometry nodes that represent lines or points do not support lighting. +void X3DImporter::ParseNode_Shape_Shape() +{ +std::string use, def; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_Shape, ne); + } + else + { + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Shape(NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + // check for child nodes + if(!mReader->isEmptyElement()) + { + ParseHelper_Node_Enter(ne); + MACRO_NODECHECK_LOOPBEGIN("Shape"); + // check for appearance node + if(XML_CheckNode_NameEqual("Appearance")) { ParseNode_Shape_Appearance(); continue; } + // check for X3DGeometryNodes + if(XML_CheckNode_NameEqual("Arc2D")) { ParseNode_Geometry2D_Arc2D(); continue; } + if(XML_CheckNode_NameEqual("ArcClose2D")) { ParseNode_Geometry2D_ArcClose2D(); continue; } + if(XML_CheckNode_NameEqual("Circle2D")) { ParseNode_Geometry2D_Circle2D(); continue; } + if(XML_CheckNode_NameEqual("Disk2D")) { ParseNode_Geometry2D_Disk2D(); continue; } + if(XML_CheckNode_NameEqual("Polyline2D")) { ParseNode_Geometry2D_Polyline2D(); continue; } + if(XML_CheckNode_NameEqual("Polypoint2D")) { ParseNode_Geometry2D_Polypoint2D(); continue; } + if(XML_CheckNode_NameEqual("Rectangle2D")) { ParseNode_Geometry2D_Rectangle2D(); continue; } + if(XML_CheckNode_NameEqual("TriangleSet2D")) { ParseNode_Geometry2D_TriangleSet2D(); continue; } + if(XML_CheckNode_NameEqual("Box")) { ParseNode_Geometry3D_Box(); continue; } + if(XML_CheckNode_NameEqual("Cone")) { ParseNode_Geometry3D_Cone(); continue; } + if(XML_CheckNode_NameEqual("Cylinder")) { ParseNode_Geometry3D_Cylinder(); continue; } + if(XML_CheckNode_NameEqual("ElevationGrid")) { ParseNode_Geometry3D_ElevationGrid(); continue; } + if(XML_CheckNode_NameEqual("Extrusion")) { ParseNode_Geometry3D_Extrusion(); continue; } + if(XML_CheckNode_NameEqual("IndexedFaceSet")) { ParseNode_Geometry3D_IndexedFaceSet(); continue; } + if(XML_CheckNode_NameEqual("Sphere")) { ParseNode_Geometry3D_Sphere(); continue; } + if(XML_CheckNode_NameEqual("IndexedLineSet")) { ParseNode_Rendering_IndexedLineSet(); continue; } + if(XML_CheckNode_NameEqual("LineSet")) { ParseNode_Rendering_LineSet(); continue; } + if(XML_CheckNode_NameEqual("PointSet")) { ParseNode_Rendering_PointSet(); continue; } + if(XML_CheckNode_NameEqual("IndexedTriangleFanSet")) { ParseNode_Rendering_IndexedTriangleFanSet(); continue; } + if(XML_CheckNode_NameEqual("IndexedTriangleSet")) { ParseNode_Rendering_IndexedTriangleSet(); continue; } + if(XML_CheckNode_NameEqual("IndexedTriangleStripSet")) { ParseNode_Rendering_IndexedTriangleStripSet(); continue; } + if(XML_CheckNode_NameEqual("TriangleFanSet")) { ParseNode_Rendering_TriangleFanSet(); continue; } + if(XML_CheckNode_NameEqual("TriangleSet")) { ParseNode_Rendering_TriangleSet(); continue; } + if(XML_CheckNode_NameEqual("TriangleStripSet")) { ParseNode_Rendering_TriangleStripSet(); continue; } + // check for X3DMetadataObject + if(!ParseHelper_CheckRead_X3DMetadataObject()) XML_CheckNode_SkipUnsupported("Shape"); + + MACRO_NODECHECK_LOOPEND("Shape"); + ParseHelper_Node_Exit(); + }// if(!mReader->isEmptyElement()) + else + { + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + } + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +// +// "Child-node content model corresponding to X3DAppearanceChildNode. Appearance can contain FillProperties, LineProperties, Material, any Texture node and +// any TextureTransform node, in any order. No more than one instance of these nodes is allowed. Appearance may also contain multiple shaders (ComposedShader, +// PackagedShader, ProgramShader). +// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model." +// +void X3DImporter::ParseNode_Shape_Appearance() +{ +std::string use, def; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_Appearance, ne); + } + else + { + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Appearance(NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + // check for child nodes + if(!mReader->isEmptyElement()) + { + ParseHelper_Node_Enter(ne); + MACRO_NODECHECK_LOOPBEGIN("Appearance"); + if(XML_CheckNode_NameEqual("Material")) { ParseNode_Shape_Material(); continue; } + if(XML_CheckNode_NameEqual("ImageTexture")) { ParseNode_Texturing_ImageTexture(); continue; } + if(XML_CheckNode_NameEqual("TextureTransform")) { ParseNode_Texturing_TextureTransform(); continue; } + // check for X3DMetadataObject + if(!ParseHelper_CheckRead_X3DMetadataObject()) XML_CheckNode_SkipUnsupported("Appearance"); + + MACRO_NODECHECK_LOOPEND("Appearance"); + ParseHelper_Node_Exit(); + }// if(!mReader->isEmptyElement()) + else + { + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + } + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +void X3DImporter::ParseNode_Shape_Material() +{ +std::string use, def; +float ambientIntensity = 0.2; +float shininess = 0.2; +float transparency = 0; +aiColor3D diffuseColor(0.8, 0.8, 0.8); +aiColor3D emissiveColor(0, 0, 0); +aiColor3D specularColor(0, 0, 0); +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("ambientIntensity", ambientIntensity, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_RET("shininess", shininess, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_RET("transparency", transparency, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_REF("diffuseColor", diffuseColor, XML_ReadNode_GetAttrVal_AsCol3f); + MACRO_ATTRREAD_CHECK_REF("emissiveColor", emissiveColor, XML_ReadNode_GetAttrVal_AsCol3f); + MACRO_ATTRREAD_CHECK_REF("specularColor", specularColor, XML_ReadNode_GetAttrVal_AsCol3f); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_Material, ne); + } + else + { + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_Material(NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + ((CX3DImporter_NodeElement_Material*)ne)->AmbientIntensity = ambientIntensity; + ((CX3DImporter_NodeElement_Material*)ne)->Shininess = shininess; + ((CX3DImporter_NodeElement_Material*)ne)->Transparency = transparency; + ((CX3DImporter_NodeElement_Material*)ne)->DiffuseColor = diffuseColor; + ((CX3DImporter_NodeElement_Material*)ne)->EmissiveColor = emissiveColor; + ((CX3DImporter_NodeElement_Material*)ne)->SpecularColor = specularColor; + // check for child nodes + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "Material"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +}// namespace Assimp + +#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER diff --git a/code/X3DImporter_Texturing.cpp b/code/X3DImporter_Texturing.cpp new file mode 100644 index 000000000..bc4832463 --- /dev/null +++ b/code/X3DImporter_Texturing.cpp @@ -0,0 +1,156 @@ +/// \file X3DImporter_Texturing.cpp +/// \brief Parsing data from nodes of "Texturing" set of X3D. +/// \date 2015-2016 +/// \author nevorek@gmail.com + +#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER + +#include "X3DImporter.hpp" +#include "X3DImporter_Macro.hpp" + +namespace Assimp +{ + +// +// When the url field contains no values ([]), texturing is disabled. +void X3DImporter::ParseNode_Texturing_ImageTexture() +{ +std::string use, def; +bool repeatS = true; +bool repeatT = true; +std::list url; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_RET("repeatS", repeatS, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_RET("repeatT", repeatT, XML_ReadNode_GetAttrVal_AsBool); + MACRO_ATTRREAD_CHECK_REF("url", url, XML_ReadNode_GetAttrVal_AsListS); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_ImageTexture, ne); + } + else + { + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_ImageTexture(NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + ((CX3DImporter_NodeElement_ImageTexture*)ne)->RepeatS = repeatS; + ((CX3DImporter_NodeElement_ImageTexture*)ne)->RepeatT = repeatT; + // Attribute "url" can contain list of strings. But we need only one - first. + if(url.size() > 0) + ((CX3DImporter_NodeElement_ImageTexture*)ne)->URL = url.front(); + else + ((CX3DImporter_NodeElement_ImageTexture*)ne)->URL = ""; + + // check for X3DMetadataObject childs. + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "ImageTexture"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +void X3DImporter::ParseNode_Texturing_TextureCoordinate() +{ +std::string use, def; +std::list point; +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_REF("point", point, XML_ReadNode_GetAttrVal_AsListVec2f); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_TextureCoordinate, ne); + } + else + { + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_TextureCoordinate(NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + ((CX3DImporter_NodeElement_TextureCoordinate*)ne)->Value = point; + // check for X3DMetadataObject childs. + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "TextureCoordinate"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +// +void X3DImporter::ParseNode_Texturing_TextureTransform() +{ +std::string use, def; +aiVector2D center(0, 0); +float rotation = 0; +aiVector2D scale(1, 1); +aiVector2D translation(0, 0); +CX3DImporter_NodeElement* ne; + + MACRO_ATTRREAD_LOOPBEG; + MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); + MACRO_ATTRREAD_CHECK_REF("center", center, XML_ReadNode_GetAttrVal_AsVec2f); + MACRO_ATTRREAD_CHECK_RET("rotation", rotation, XML_ReadNode_GetAttrVal_AsFloat); + MACRO_ATTRREAD_CHECK_REF("scale", scale, XML_ReadNode_GetAttrVal_AsVec2f); + MACRO_ATTRREAD_CHECK_REF("translation", translation, XML_ReadNode_GetAttrVal_AsVec2f); + MACRO_ATTRREAD_LOOPEND; + + // if "USE" defined then find already defined element. + if(!use.empty()) + { + MACRO_USE_CHECKANDAPPLY(def, use, ENET_TextureTransform, ne); + } + else + { + // create and if needed - define new geometry object. + ne = new CX3DImporter_NodeElement_TextureTransform(NodeElement_Cur); + if(!def.empty()) ne->ID = def; + + ((CX3DImporter_NodeElement_TextureTransform*)ne)->Center = center; + ((CX3DImporter_NodeElement_TextureTransform*)ne)->Rotation = rotation; + ((CX3DImporter_NodeElement_TextureTransform*)ne)->Scale = scale; + ((CX3DImporter_NodeElement_TextureTransform*)ne)->Translation = translation; + // check for X3DMetadataObject childs. + if(!mReader->isEmptyElement()) + ParseNode_Metadata(ne, "TextureTransform"); + else + NodeElement_Cur->Child.push_back(ne);// add made object as child to current element + + NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph + }// if(!use.empty()) else +} + +}// namespace Assimp + +#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER From 823003ba9b16b594a7f61f259bcf148d58bc3914 Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Sun, 2 Oct 2016 02:28:06 +0300 Subject: [PATCH 2/6] [F] Fixing checking rule --- code/StandardShapes.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/code/StandardShapes.cpp b/code/StandardShapes.cpp index 943b73920..8b0b32336 100644 --- a/code/StandardShapes.cpp +++ b/code/StandardShapes.cpp @@ -121,8 +121,7 @@ void Subdivide(std::vector& positions) aiMesh* StandardShapes::MakeMesh(const std::vector& positions, unsigned int numIndices) { - if (positions.size() & numIndices || positions.empty() || !numIndices) - return NULL; + if (positions.empty() || !numIndices) return NULL; // Determine which kinds of primitives the mesh consists of aiMesh* out = new aiMesh(); From 9c0de90ede0d4ad6d9a0ced1446a4f9176ac902d Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Sun, 2 Oct 2016 03:08:34 +0300 Subject: [PATCH 3/6] [F] Fixed missed break. [F] Doc changes. [*] Removed Boost dependency. [*] Style changes. --- code/X3DImporter.cpp | 106 ++++++++++++++++--------------- code/X3DImporter.hpp | 35 +++++----- code/X3DImporter_Geometry2D.cpp | 8 +-- code/X3DImporter_Geometry3D.cpp | 16 +++-- code/X3DImporter_Group.cpp | 8 +-- code/X3DImporter_Light.cpp | 16 ++--- code/X3DImporter_Metadata.cpp | 8 +-- code/X3DImporter_Networking.cpp | 9 +-- code/X3DImporter_Node.hpp | 18 +++--- code/X3DImporter_Postprocess.cpp | 75 +++++++++++----------- code/X3DImporter_Rendering.cpp | 8 +-- code/X3DImporter_Shape.cpp | 8 +-- code/X3DImporter_Texturing.cpp | 8 +-- 13 files changed, 166 insertions(+), 157 deletions(-) diff --git a/code/X3DImporter.cpp b/code/X3DImporter.cpp index ab0b23dec..9875d0f35 100644 --- a/code/X3DImporter.cpp +++ b/code/X3DImporter.cpp @@ -1,18 +1,19 @@ -/// \file X3DImporter.hpp -/// \brief X3D-format files importer for Assimp: main algorithm implementation. -/// \date 2015-2016 -/// \author nevorek@gmail.com +/// \file X3DImporter.cpp +/// \brief X3D-format files importer for Assimp: main algorithm implementation. +/// \date 2015-2016 +/// \author smal.root@gmail.com #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER #include "X3DImporter.hpp" #include "X3DImporter_Macro.hpp" -#include "fast_atof.h" +// Header files, Assimp. #include "DefaultIOSystem.h" +#include "fast_atof.h" -#include -#include +// Header files, stdlib. +#include #include namespace Assimp @@ -35,6 +36,7 @@ const aiImporterDesc X3DImporter::Description = { void X3DImporter::Clear() { + NodeElement_Cur = nullptr; // Delete all elements if(NodeElement_List.size()) { @@ -46,7 +48,7 @@ void X3DImporter::Clear() X3DImporter::~X3DImporter() { - if(mReader != NULL) delete mReader; + if(mReader != nullptr) delete mReader; // Clear() is accounting if data already is deleted. So, just check again if all data is deleted. Clear(); } @@ -61,7 +63,7 @@ bool X3DImporter::FindNodeElement_FromRoot(const std::string& pID, const CX3DImp { if(((*it)->Type == pType) && ((*it)->ID == pID)) { - if(pElement != NULL) *pElement = *it; + if(pElement != nullptr) *pElement = *it; return true; } @@ -79,7 +81,7 @@ bool found = false;// flag: true - if requested element is found. if((pStartNode->Type == pType) && (pStartNode->ID == pID)) { found = true; - if(pElement != NULL) *pElement = pStartNode; + if(pElement != nullptr) *pElement = pStartNode; goto fne_fn_end; }// if((pStartNode->Type() == pType) && (pStartNode->ID() == pID)) @@ -102,7 +104,7 @@ CX3DImporter_NodeElement* tnd = NodeElement_Cur;// temporary pointer to node. bool static_search = false;// flag: true if searching in static node. // At first check if we have deal with static node. Go up thru parent nodes and check flag. - while(tnd != NULL) + while(tnd != nullptr) { if(tnd->Type == CX3DImporter_NodeElement::ENET_Group) { @@ -115,7 +117,7 @@ bool static_search = false;// flag: true if searching in static node. } tnd = tnd->Parent;// go up in graph. - }// while(tnd != NULL) + }// while(tnd != nullptr) // at now call appropriate search function. if(static_search) @@ -140,23 +142,23 @@ void X3DImporter::Throw_CloseNotFound(const std::string& pNode) void X3DImporter::Throw_ConvertFail_Str2ArrF(const std::string& pAttrValue) { - throw DeadlyImportError(boost::str(boost::format("In <%s> failed to convert attribute value \"%s\" from string to array of floats.") % - mReader->getNodeName() % pAttrValue)); + throw DeadlyImportError("In <" + std::string(mReader->getNodeName()) + "> failed to convert attribute value \"" + pAttrValue + + "\" from string to array of floats."); } void X3DImporter::Throw_DEF_And_USE() { - throw DeadlyImportError(boost::str(boost::format("\"DEF\" and \"USE\" can not be defined both in <%s>.") % mReader->getNodeName())); + throw DeadlyImportError("\"DEF\" and \"USE\" can not be defined both in <" + std::string(mReader->getNodeName()) + ">."); } void X3DImporter::Throw_IncorrectAttr(const std::string& pAttrName) { - throw DeadlyImportError(boost::str(boost::format("Node <%s> has incorrect attribute \"%s\".") % mReader->getNodeName() % pAttrName)); + throw DeadlyImportError("Node <" + std::string(mReader->getNodeName()) + "> has incorrect attribute \"" + pAttrName + "\"."); } void X3DImporter::Throw_IncorrectAttrValue(const std::string& pAttrName) { - throw DeadlyImportError(boost::str(boost::format("Attribute \"%s\" in node <%s> has incorrect value.") % pAttrName % mReader->getNodeName())); + throw DeadlyImportError("Attribute \"" + pAttrName + "\" in node <" + std::string(mReader->getNodeName()) + "> has incorrect value."); } void X3DImporter::Throw_MoreThanOnceDefined(const std::string& pNodeType, const std::string& pDescription) @@ -171,7 +173,7 @@ void X3DImporter::Throw_TagCountIncorrect(const std::string& pNode) void X3DImporter::Throw_USE_NotFound(const std::string& pAttrValue) { - throw DeadlyImportError(boost::str(boost::format("Not found node with name \"%s\" in <%s>.") % pAttrValue % mReader->getNodeName())); + throw DeadlyImportError("Not found node with name \"" + pAttrValue + "\" in <" + std::string(mReader->getNodeName()) + ">."); } /*********************************************************************************************************************************************/ @@ -292,10 +294,10 @@ bool close_found = false; casu_cres: - if(!found) throw DeadlyImportError(boost::str(boost::format("Unknown node \"%s\" in %s.") % nn % pParentNodeName)); + if(!found) throw DeadlyImportError("Unknown node \"" + nn + "\" in " + pParentNodeName + "."); if(close_found) - LogInfo(boost::str(boost::format("Skipping node \"%s\" in %s.") % nn % pParentNodeName)); + LogInfo("Skipping node \"" + nn + "\" in " + pParentNodeName + "."); else Throw_CloseNotFound(nn); } @@ -441,9 +443,10 @@ const char* tstr_end = tstr + strlen(tstr); do { - int32_t tval32; const char* ostr; + int32_t tval32; + tval32 = strtol10(tstr, &ostr); if(ostr == tstr) break; @@ -696,13 +699,13 @@ size_t tok_str_len; // find begin of string(element of string list): "sn". tbeg = strstr(tok_str, "\""); - if(tbeg == NULL) Throw_IncorrectAttrValue(mReader->getAttributeName(pAttrIdx)); + if(tbeg == nullptr) Throw_IncorrectAttrValue(mReader->getAttributeName(pAttrIdx)); tbeg++;// forward pointer from '\"' symbol to next after it. tok_str = tbeg; // find end of string(element of string list): "sn". tend = strstr(tok_str, "\""); - if(tend == NULL) Throw_IncorrectAttrValue(mReader->getAttributeName(pAttrIdx)); + if(tend == nullptr) Throw_IncorrectAttrValue(mReader->getAttributeName(pAttrIdx)); tok_str = tend + 1; // create storage for new string @@ -850,10 +853,10 @@ unsigned int prim_type = 0; switch(ts) { case 0: goto mg_m_err; - case 1: prim_type |= aiPrimitiveType_POINT; - case 2: prim_type |= aiPrimitiveType_LINE; - case 3: prim_type |= aiPrimitiveType_TRIANGLE; - default: prim_type |= aiPrimitiveType_POLYGON; + case 1: prim_type |= aiPrimitiveType_POINT; break; + case 2: prim_type |= aiPrimitiveType_LINE; break; + case 3: prim_type |= aiPrimitiveType_TRIANGLE; break; + default: prim_type |= aiPrimitiveType_POLYGON; break; } tface.mNumIndices = ts; @@ -899,8 +902,8 @@ std::list::const_iterator col_it = pColors.begin(); { if(pColors.size() < pMesh.mNumVertices) { - throw DeadlyImportError(boost::str(boost::format("MeshGeometry_AddColor1. Colors count(%s) can not be less than Vertices count(%s).") % - pColors.size() % pMesh.mNumVertices)); + throw DeadlyImportError("MeshGeometry_AddColor1. Colors count(" + std::to_string(pColors.size()) + ") can not be less than Vertices count(" + + std::to_string(pMesh.mNumVertices) + ")."); } // copy colors to mesh @@ -911,8 +914,8 @@ std::list::const_iterator col_it = pColors.begin(); { if(pColors.size() < pMesh.mNumFaces) { - throw DeadlyImportError(boost::str(boost::format("MeshGeometry_AddColor1. Colors count(%s) can not be less than Faces count(%s).") % - pColors.size() % pMesh.mNumFaces)); + throw DeadlyImportError("MeshGeometry_AddColor1. Colors count(" + std::to_string(pColors.size()) + ") can not be less than Faces count(" + + std::to_string(pMesh.mNumFaces) + ")."); } // copy colors to mesh @@ -959,8 +962,8 @@ std::vector col_arr_copy; // check indices array count. if(pColorIdx.size() < pCoordIdx.size()) { - throw DeadlyImportError(boost::str(boost::format("MeshGeometry_AddColor2. Colors indices count(%s) can not be less than Coords inidces count(%s).") % - pColorIdx.size() % pCoordIdx.size())); + throw DeadlyImportError("MeshGeometry_AddColor2. Colors indices count(" + std::to_string(pColorIdx.size()) + + ") can not be less than Coords inidces count(" + std::to_string(pCoordIdx.size()) + ")."); } // create list with colors for every vertex. col_tgt_arr.resize(pMesh.mNumVertices); @@ -979,8 +982,8 @@ std::vector col_arr_copy; // check indices array count. if(pColors.size() < pMesh.mNumVertices) { - throw DeadlyImportError(boost::str(boost::format("MeshGeometry_AddColor2. Colors count(%s) can not be less than Vertices count(%s).") % - pColors.size() % pMesh.mNumVertices)); + throw DeadlyImportError("MeshGeometry_AddColor2. Colors count(" + std::to_string(pColors.size()) + ") can not be less than Vertices count(" + + std::to_string(pMesh.mNumVertices) + ")."); } // create list with colors for every vertex. col_tgt_arr.resize(pMesh.mNumVertices); @@ -994,8 +997,8 @@ std::vector col_arr_copy; // check indices array count. if(pColorIdx.size() < pMesh.mNumFaces) { - throw DeadlyImportError(boost::str(boost::format("MeshGeometry_AddColor2. Colors indices count(%s) can not be less than Faces count(%s).") % - pColorIdx.size() % pMesh.mNumFaces)); + throw DeadlyImportError("MeshGeometry_AddColor2. Colors indices count(" + std::to_string(pColorIdx.size()) + + ") can not be less than Faces count(" + std::to_string(pMesh.mNumFaces) + ")."); } // create list with colors for every vertex using faces indices. col_tgt_arr.resize(pMesh.mNumFaces); @@ -1014,8 +1017,8 @@ std::vector col_arr_copy; // check indices array count. if(pColors.size() < pMesh.mNumFaces) { - throw DeadlyImportError(boost::str(boost::format("MeshGeometry_AddColor2. Colors count(%s) can not be less than Faces count(%s).") % - pColors.size() % pMesh.mNumFaces)); + throw DeadlyImportError("MeshGeometry_AddColor2. Colors count(" + std::to_string(pColors.size()) + ") can not be less than Faces count(" + + std::to_string(pMesh.mNumFaces) + ")."); } // create list with colors for every vertex using faces indices. col_tgt_arr.resize(pMesh.mNumFaces); @@ -1067,8 +1070,8 @@ std::vector norm_arr_copy; for(size_t i = 0; (i < pMesh.mNumVertices) && (i < tind.size()); i++) { if(tind[i] >= norm_arr_copy.size()) - throw DeadlyImportError(boost::str(boost::format("MeshGeometry_AddNormal. Normal index(%s) is out of range. Normals count: %s.") % - tind[i] % norm_arr_copy.size())); + throw DeadlyImportError("MeshGeometry_AddNormal. Normal index(" + std::to_string(tind[i]) + + ") is out of range. Normals count: " + std::to_string(norm_arr_copy.size()) + "."); pMesh.mNormals[i] = norm_arr_copy[tind[i]]; } @@ -1162,7 +1165,7 @@ unsigned int prim_type; for(size_t fi = 0, fi_e = faces.size(); fi < fi_e; fi++) { if(pMesh.mFaces[fi].mNumIndices != faces.at(fi).mNumIndices) - throw DeadlyImportError(boost::str(boost::format("Number of indices in texture face and mesh face must be equal. Invalid face index: %s") % fi)); + throw DeadlyImportError("Number of indices in texture face and mesh face must be equal. Invalid face index: " + std::to_string(fi) + "."); for(size_t ii = 0; ii < pMesh.mFaces[fi].mNumIndices; ii++) { @@ -1234,7 +1237,7 @@ void X3DImporter::ParseHelper_Group_Begin(const bool pStatic) CX3DImporter_NodeElement_Group* new_group = new CX3DImporter_NodeElement_Group(NodeElement_Cur, pStatic);// create new node with current node as parent. // if we are adding not the root element then add new element to current element child list. - if(NodeElement_Cur != NULL) NodeElement_Cur->Child.push_back(new_group); + if(NodeElement_Cur != nullptr) NodeElement_Cur->Child.push_back(new_group); NodeElement_List.push_back(new_group);// it's a new element - add it to list. NodeElement_Cur = new_group;// switch current element to new one. @@ -1249,7 +1252,7 @@ void X3DImporter::ParseHelper_Node_Enter(CX3DImporter_NodeElement* pNode) void X3DImporter::ParseHelper_Node_Exit() { // check if we can walk up. - if(NodeElement_Cur != NULL) NodeElement_Cur = NodeElement_Cur->Parent; + if(NodeElement_Cur != nullptr) NodeElement_Cur = NodeElement_Cur->Parent; } void X3DImporter::ParseHelper_FixTruncatedFloatString(const char* pInStr, std::string& pOutString) @@ -1282,12 +1285,12 @@ size_t instr_len; void X3DImporter::ParseFile(const std::string& pFile, IOSystem* pIOHandler) { irr::io::IrrXMLReader* OldReader = mReader;// store current XMLreader. -boost::scoped_ptr file(pIOHandler->Open(pFile, "rb")); +std::unique_ptr file(pIOHandler->Open(pFile, "rb")); // Check whether we can read from the file - if(file.get() == NULL) throw DeadlyImportError("Failed to open X3D file " + pFile + "."); + if(file.get() == nullptr) throw DeadlyImportError("Failed to open X3D file " + pFile + "."); // generate a XML reader for it - boost::scoped_ptr mIOWrapper(new CIrrXML_IOStreamReader(file.get())); + std::unique_ptr mIOWrapper(new CIrrXML_IOStreamReader(file.get())); mReader = irr::io::createIrrXMLReader(mIOWrapper.get()); if(!mReader) throw DeadlyImportError("Failed to create XML reader for file" + pFile + "."); // start reading @@ -1346,7 +1349,8 @@ bool close_found = false;// flag: true if close tag of node are found. { ms->Value.push_back(mReader->getAttributeValueSafe("content")); NodeElement_List.push_back(ms); - if(NodeElement_Cur != NULL) NodeElement_Cur->Child.push_back(ms); + if(NodeElement_Cur != nullptr) NodeElement_Cur->Child.push_back(ms); + } }// if(XML_CheckNode_NameEqual("meta")) }// if(mReader->getNodeType() == irr::io::EXN_ELEMENT) @@ -1510,11 +1514,11 @@ void X3DImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy // // at first creating root node for aiScene. pScene->mRootNode = new aiNode; - pScene->mRootNode->mParent = NULL; - + pScene->mRootNode->mParent = nullptr; + pScene->mFlags |= AI_SCENE_FLAGS_ALLOW_SHARED; //search for root node element NodeElement_Cur = NodeElement_List.front(); - while(NodeElement_Cur->Parent != NULL) NodeElement_Cur = NodeElement_Cur->Parent; + while(NodeElement_Cur->Parent != nullptr) NodeElement_Cur = NodeElement_Cur->Parent; {// fill aiScene with objects. std::list mesh_list; diff --git a/code/X3DImporter.hpp b/code/X3DImporter.hpp index 5d8b9bd1b..6e605c9dd 100644 --- a/code/X3DImporter.hpp +++ b/code/X3DImporter.hpp @@ -1,25 +1,22 @@ -/// \file X3DImporter.hpp -/// \brief X3D-format files importer for Assimp. -/// \date 2015-2016 -/// \author nevorek@gmail.com +/// \file X3DImporter.hpp +/// \brief X3D-format files importer for Assimp. +/// \date 2015-2016 +/// \author smal.root@gmail.com +// Thanks to acorn89 for support. #ifndef INCLUDED_AI_X3D_IMPORTER_H #define INCLUDED_AI_X3D_IMPORTER_H -// Pay attention - you must include some files from Assimp before including BaseImporter.h. -// magic region begin -#include +#include "X3DImporter_Node.hpp" -#include "../include/assimp/DefaultLogger.hpp" -#include "../include/assimp/importerdesc.h" -#include "../include/assimp/ProgressHandler.hpp" -#include "../include/assimp/types.h" -// magic region end +// Header files, Assimp. +#include "assimp/DefaultLogger.hpp" +#include "assimp/importerdesc.h" +#include "assimp/ProgressHandler.hpp" +#include "assimp/types.h" #include "BaseImporter.h" #include "irrXMLWrapper.h" -#include "X3DImporter_Node.hpp" - namespace Assimp { @@ -147,7 +144,7 @@ namespace Assimp /// duplicates of it )). /// /// Color for faces. -/// That's happening when attribute "colorPerVertex" is set to "false". But Assimp do not hold how many colors has mesh and reuire +/// That's happening when attribute "colorPerVertex" is set to "false". But Assimp do not hold how many colors has mesh and require /// equal length for mVertices and mColors. You will see the colors but vertices will use call which last used in "colorIdx". /// /// That's all for now. Enjoy @@ -264,19 +261,19 @@ private: /// Create filled structure with type \ref aiMaterial from \ref CX3DImporter_NodeElement. This function itseld extract /// all needed data from scene graph. /// \param [in] pNodeElement - reference to material element(). - /// \param [out] pMaterial - pointer to pointer to created material. *pMaterial must be NULL. + /// \param [out] pMaterial - pointer to pointer to created material. *pMaterial must be nullptr. void Postprocess_BuildMaterial(const CX3DImporter_NodeElement& pNodeElement, aiMaterial** pMaterial) const; /// \fn void Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeElement, aiMesh** pMesh) const /// Create filled structure with type \ref aiMaterial from \ref CX3DImporter_NodeElement. This function itseld extract /// all needed data from scene graph. /// \param [in] pNodeElement - reference to geometry object. - /// \param [out] pMesh - pointer to pointer to created mesh. *pMesh must be NULL. + /// \param [out] pMesh - pointer to pointer to created mesh. *pMesh must be nullptr. void Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeElement, aiMesh** pMesh) const; /// \fn void Postprocess_BuildNode(const CX3DImporter_NodeElement& pNodeElement, aiNode& pSceneNode, std::list& pSceneMeshList, std::list& pSceneMaterialList, std::list& pSceneLightList) const /// Create aiNode from CX3DImporter_NodeElement. Also function check children and make recursive call. - /// \param [out] pNode - pointer to pointer to created node. *pNode must be NULL. + /// \param [out] pNode - pointer to pointer to created node. *pNode must be nullptr. /// \param [in] pNodeElement - CX3DImporter_NodeElement which read. /// \param [out] pSceneNode - aiNode for filling. /// \param [out] pSceneMeshList - list with aiMesh which belong to scene. @@ -920,7 +917,7 @@ public: /// \fn X3DImporter() /// Default constructor. X3DImporter() - : NodeElement_Cur(NULL), mReader(NULL) + : NodeElement_Cur(nullptr), mReader(nullptr) {} /// \fn ~X3DImporter() diff --git a/code/X3DImporter_Geometry2D.cpp b/code/X3DImporter_Geometry2D.cpp index d4a62f58c..8e62cca20 100644 --- a/code/X3DImporter_Geometry2D.cpp +++ b/code/X3DImporter_Geometry2D.cpp @@ -1,7 +1,7 @@ -/// \file X3DImporter_Geometry2D.cpp -/// \brief Parsing data from nodes of "Geometry2D" set of X3D. -/// \date 2015-2016 -/// \author nevorek@gmail.com +/// \file X3DImporter_Geometry2D.cpp +/// \brief Parsing data from nodes of "Geometry2D" set of X3D. +/// \date 2015-2016 +/// \author smal.root@gmail.com #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER diff --git a/code/X3DImporter_Geometry3D.cpp b/code/X3DImporter_Geometry3D.cpp index 63a02b6b8..c71e08bad 100644 --- a/code/X3DImporter_Geometry3D.cpp +++ b/code/X3DImporter_Geometry3D.cpp @@ -1,12 +1,14 @@ -/// \file X3DImporter_Geometry3D.cpp -/// \brief Parsing data from nodes of "Geometry3D" set of X3D. -/// \date 2015-2016 -/// \author nevorek@gmail.com +/// \file X3DImporter_Geometry3D.cpp +/// \brief Parsing data from nodes of "Geometry3D" set of X3D. +/// \date 2015-2016 +/// \author smal.root@gmail.com #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER #include "X3DImporter.hpp" #include "X3DImporter_Macro.hpp" + +// Header files, Assimp. #include "StandardShapes.h" namespace Assimp @@ -94,6 +96,7 @@ CX3DImporter_NodeElement* ne; else { const unsigned int tess = 30;///TODO: IME tesselation factor thru ai_property + std::vector tvec;// temp array for vertices. // create and if needed - define new geometry object. @@ -166,6 +169,7 @@ CX3DImporter_NodeElement* ne; else { const unsigned int tess = 30;///TODO: IME tesselation factor thru ai_property + std::vector tside;// temp array for vertices of side. std::vector tcir;// temp array for vertices of circle. @@ -419,6 +423,7 @@ size_t cur_sz = pCurve.size(); static aiVector3D GeometryHelper_Extrusion_GetNextY(const size_t pSpine_PointIdx, const std::vector& pSpine, const bool pSpine_Closed) { const size_t spine_idx_last = pSpine.size() - 1; + aiVector3D tvec; if((pSpine_PointIdx == 0) || (pSpine_PointIdx == spine_idx_last))// at first special cases @@ -453,6 +458,7 @@ static aiVector3D GeometryHelper_Extrusion_GetNextZ(const size_t pSpine_PointIdx { const aiVector3D zero_vec(0); const size_t spine_idx_last = pSpine.size() - 1; + aiVector3D tvec; // at first special cases @@ -916,6 +922,7 @@ CX3DImporter_NodeElement* ne; else { const unsigned int tess = 3;///TODO: IME tesselation factor thru ai_property + std::vector tlist; // create and if needed - define new geometry object. @@ -941,7 +948,6 @@ CX3DImporter_NodeElement* ne; }// if(!use.empty()) else } - }// namespace Assimp #endif // !ASSIMP_BUILD_NO_X3D_IMPORTER diff --git a/code/X3DImporter_Group.cpp b/code/X3DImporter_Group.cpp index c1e7bf6d2..9b9cfb7dc 100644 --- a/code/X3DImporter_Group.cpp +++ b/code/X3DImporter_Group.cpp @@ -1,7 +1,7 @@ -/// \file X3DImporter_Group.cpp -/// \brief Parsing data from nodes of "Grouping" set of X3D. -/// \date 2015-2016 -/// \author nevorek@gmail.com +/// \file X3DImporter_Group.cpp +/// \brief Parsing data from nodes of "Grouping" set of X3D. +/// \date 2015-2016 +/// \author smal.root@gmail.com #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER diff --git a/code/X3DImporter_Light.cpp b/code/X3DImporter_Light.cpp index 0e2b1d7f6..c297d1b95 100644 --- a/code/X3DImporter_Light.cpp +++ b/code/X3DImporter_Light.cpp @@ -1,15 +1,13 @@ -/// \file X3DImporter_Light.cpp -/// \brief Parsing data from nodes of "Lighting" set of X3D. -/// \date 2015-2016 -/// \author nevorek@gmail.com +/// \file X3DImporter_Light.cpp +/// \brief Parsing data from nodes of "Lighting" set of X3D. +/// \date 2015-2016 +/// \author smal.root@gmail.com #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER #include "X3DImporter.hpp" #include "X3DImporter_Macro.hpp" -#include - namespace Assimp { @@ -58,7 +56,7 @@ CX3DImporter_NodeElement* ne; if(!def.empty()) ne->ID = def; else - ne->ID = boost::str(boost::format("DirectionalLight_%s") % (size_t)ne);// make random name + ne->ID = "DirectionalLight_" + std::to_string((size_t)ne);// make random name ((CX3DImporter_NodeElement_Light*)ne)->AmbientIntensity = ambientIntensity; ((CX3DImporter_NodeElement_Light*)ne)->Color = color; @@ -141,7 +139,7 @@ CX3DImporter_NodeElement* ne; // Assimp want a node with name similar to a light. "Why? I don't no." ) ParseHelper_Group_Begin(false); // make random name - if(ne->ID.empty()) ne->ID = boost::str(boost::format("PointLight_%s") % (size_t)ne); + if(ne->ID.empty()) ne->ID = "PointLight_" + std::to_string((size_t)ne); NodeElement_Cur->ID = ne->ID;// assign name to node and return to light element. ParseHelper_Node_Exit(); @@ -231,7 +229,7 @@ CX3DImporter_NodeElement* ne; // Assimp want a node with name similar to a light. "Why? I don't no." ) ParseHelper_Group_Begin(false); // make random name - if(ne->ID.empty()) ne->ID = boost::str(boost::format("SpotLight_%s") % (size_t)ne); + if(ne->ID.empty()) ne->ID = "SpotLight_" + std::to_string((size_t)ne); NodeElement_Cur->ID = ne->ID;// assign name to node and return to light element. ParseHelper_Node_Exit(); diff --git a/code/X3DImporter_Metadata.cpp b/code/X3DImporter_Metadata.cpp index ab5ab40d2..41f2678fa 100644 --- a/code/X3DImporter_Metadata.cpp +++ b/code/X3DImporter_Metadata.cpp @@ -1,7 +1,7 @@ -/// \file X3DImporter_Metadata.cpp -/// \brief Parsing data from nodes of "Metadata" set of X3D. -/// \date 2015-2016 -/// \author nevorek@gmail.com +/// \file X3DImporter_Metadata.cpp +/// \brief Parsing data from nodes of "Metadata" set of X3D. +/// \date 2015-2016 +/// \author smal.root@gmail.com #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER diff --git a/code/X3DImporter_Networking.cpp b/code/X3DImporter_Networking.cpp index 5d257f5f8..b70bc7c02 100644 --- a/code/X3DImporter_Networking.cpp +++ b/code/X3DImporter_Networking.cpp @@ -1,13 +1,14 @@ -/// \file X3DImporter_Rendering.cpp -/// \brief Parsing data from nodes of "Networking" set of X3D. -/// \date 2015-2016 -/// \author nevorek@gmail.com +/// \file X3DImporter_Networking.cpp +/// \brief Parsing data from nodes of "Networking" set of X3D. +/// \date 2015-2016 +/// \author smal.root@gmail.com #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER #include "X3DImporter.hpp" #include "X3DImporter_Macro.hpp" +// Header files, Assimp. #include "DefaultIOSystem.h" namespace Assimp diff --git a/code/X3DImporter_Node.hpp b/code/X3DImporter_Node.hpp index ba52e4e52..16198d1f9 100644 --- a/code/X3DImporter_Node.hpp +++ b/code/X3DImporter_Node.hpp @@ -1,17 +1,19 @@ -/// \file X3DImporter_Node.hpp -/// \brief Elements of scene graph. -/// \date 2015-2016 -/// \author nevorek@gmail.com +/// \file X3DImporter_Node.hpp +/// \brief Elements of scene graph. +/// \date 2015-2016 +/// \author smal.root@gmail.com #ifndef INCLUDED_AI_X3D_IMPORTER_NODE_H #define INCLUDED_AI_X3D_IMPORTER_NODE_H +// Header files, Assimp. +#include "assimp/scene.h" +#include "assimp/types.h" + +// Header files, stdlib. #include #include -#include "../include/assimp/types.h" -#include "../include/assimp/scene.h" - /// \class CX3DImporter_NodeElement /// Base class for elements of nodes. class CX3DImporter_NodeElement @@ -89,7 +91,7 @@ public: public: std::string ID;///< ID of the element. Can be empty. In X3D synonym for "ID" attribute. - CX3DImporter_NodeElement* Parent;///< Parrent element. If NULL then this node is root. + CX3DImporter_NodeElement* Parent;///< Parrent element. If nullptr then this node is root. std::list Child;///< Child elements. /***********************************************/ diff --git a/code/X3DImporter_Postprocess.cpp b/code/X3DImporter_Postprocess.cpp index ffb4c8e23..ba946b9a5 100644 --- a/code/X3DImporter_Postprocess.cpp +++ b/code/X3DImporter_Postprocess.cpp @@ -1,18 +1,19 @@ -/// \file X3DImporter_Postprocess.cpp -/// \brief Convert built scenegraph and objects to Assimp scenegraph. -/// \date 2015-2016 -/// \author nevorek@gmail.com +/// \file X3DImporter_Postprocess.cpp +/// \brief Convert built scenegraph and objects to Assimp scenegraph. +/// \date 2015-2016 +/// \author smal.root@gmail.com #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER #include "X3DImporter.hpp" + +// Header files, Assimp. #include "StandardShapes.h" -#include -#include - +// Header files, stdlib. #include #include +#include namespace Assimp { @@ -25,7 +26,7 @@ aiMatrix4x4 out_matr; // starting walk from current element to root cur_node = NodeElement_Cur; - if(cur_node != NULL) + if(cur_node != nullptr) { do { @@ -33,7 +34,7 @@ aiMatrix4x4 out_matr; if(cur_node->Type == CX3DImporter_NodeElement::ENET_Group) matr.push_back(((CX3DImporter_NodeElement_Group*)cur_node)->Transformation); cur_node = cur_node->Parent; - } while(cur_node != NULL); + } while(cur_node != nullptr); } // multiplicate all matrices in reverse order @@ -99,9 +100,9 @@ bool X3DImporter::PostprocessHelper_ElementIsMesh(const CX3DImporter_NodeElement void X3DImporter::Postprocess_BuildLight(const CX3DImporter_NodeElement& pNodeElement, std::list& pSceneLightList) const { -aiLight* new_light = new aiLight; const CX3DImporter_NodeElement_Light& ne = *((CX3DImporter_NodeElement_Light*)&pNodeElement); aiMatrix4x4 transform_matr = PostprocessHelper_Matrix_GlobalToCurrent(); +aiLight* new_light = new aiLight; new_light->mName = ne.ID; new_light->mColorAmbient = ne.Color * ne.AmbientIntensity; @@ -134,7 +135,7 @@ aiMatrix4x4 transform_matr = PostprocessHelper_Matrix_GlobalToCurrent(); break; default: - throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildLight. Unknown type of light: %s") % pNodeElement.Type)); + throw DeadlyImportError("Postprocess_BuildLight. Unknown type of light: " + std::to_string(pNodeElement.Type) + "."); } pSceneLightList.push_back(new_light); @@ -143,8 +144,8 @@ aiMatrix4x4 transform_matr = PostprocessHelper_Matrix_GlobalToCurrent(); void X3DImporter::Postprocess_BuildMaterial(const CX3DImporter_NodeElement& pNodeElement, aiMaterial** pMaterial) const { // check argument - if(pMaterial == NULL) throw DeadlyImportError("Postprocess_BuildMaterial. pMaterial is NULL."); - if(*pMaterial != NULL) throw DeadlyImportError("Postprocess_BuildMaterial. *pMaterial must be NULL."); + if(pMaterial == nullptr) throw DeadlyImportError("Postprocess_BuildMaterial. pMaterial is nullptr."); + if(*pMaterial != nullptr) throw DeadlyImportError("Postprocess_BuildMaterial. *pMaterial must be nullptr."); *pMaterial = new aiMaterial; aiMaterial& taimat = **pMaterial;// creating alias for convenience. @@ -196,8 +197,8 @@ void X3DImporter::Postprocess_BuildMaterial(const CX3DImporter_NodeElement& pNod void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeElement, aiMesh** pMesh) const { // check argument - if(pMesh == NULL) throw DeadlyImportError("Postprocess_BuildMesh. pMesh is NULL."); - if(*pMesh != NULL) throw DeadlyImportError("Postprocess_BuildMesh. *pMesh must be NULL."); + if(pMesh == nullptr) throw DeadlyImportError("Postprocess_BuildMesh. pMesh is nullptr."); + if(*pMesh != nullptr) throw DeadlyImportError("Postprocess_BuildMesh. *pMesh must be nullptr."); /************************************************************************************************************************************/ /************************************************************ Geometry2D ************************************************************/ @@ -256,7 +257,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate) MeshGeometry_AddTexCoord(**pMesh, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); else - throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildMesh. Unknown child of ElevationGrid: %s.") % (*ch_it)->Type)); + throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of ElevationGrid: " + std::to_string((*ch_it)->Type) + "."); }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) return;// mesh is build, nothing to do anymore. @@ -293,7 +294,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate) MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); else - throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildMesh. Unknown child of IndexedFaceSet: %s.") % (*ch_it)->Type)); + throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedFaceSet: " + std::to_string((*ch_it)->Type) + "."); }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) return;// mesh is build, nothing to do anymore. @@ -323,7 +324,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) {} // skip because already read when mesh created. else - throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildMesh. Unknown child of IndexedLineSet: %s.") % (*ch_it)->Type)); + throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedLineSet: " + std::to_string((*ch_it)->Type) + "."); }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) return;// mesh is build, nothing to do anymore. @@ -360,8 +361,8 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate) MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); else - throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildMesh. Unknown child of IndexedTriangleSet or IndexedTriangleFanSet, or \ - IndexedTriangleStripSet: %s.") % (*ch_it)->Type)); + throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedTriangleSet or IndexedTriangleFanSet, or \ + IndexedTriangleStripSet: " + std::to_string((*ch_it)->Type) + "."); }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) return;// mesh is build, nothing to do anymore. @@ -411,7 +412,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) {} // skip because already read when mesh created. else - throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildMesh. Unknown child of PointSet: %s.") % (*ch_it)->Type)); + throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of PointSet: " + std::to_string((*ch_it)->Type) + "."); }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) return;// mesh is build, nothing to do anymore. @@ -440,7 +441,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) {} // skip because already read when mesh created. else - throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildMesh. Unknown child of LineSet: %s.") % (*ch_it)->Type)); + throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of LineSet: " + std::to_string((*ch_it)->Type) + "."); }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) return;// mesh is build, nothing to do anymore. @@ -474,7 +475,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate) MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); else - throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildMesh. Unknown child of TrianlgeFanSet: %s.") % (*ch_it)->Type)); + throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TrianlgeFanSet: " + std::to_string((*ch_it)->Type) + "."); }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) return;// mesh is build, nothing to do anymore. @@ -517,7 +518,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate) MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); else - throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildMesh. Unknown child of TrianlgeSet: %s.") % (*ch_it)->Type)); + throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TrianlgeSet: " + std::to_string((*ch_it)->Type) + "."); }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) return;// mesh is build, nothing to do anymore. @@ -551,13 +552,13 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate) MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); else - throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildMesh. Unknown child of TriangleStripSet: %s.") % (*ch_it)->Type)); + throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TriangleStripSet: " + std::to_string((*ch_it)->Type) + "."); }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) return;// mesh is build, nothing to do anymore. }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleStripSet) - throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildMesh. Unknown mesh type: %s.") % pNodeElement.Type)); + throw DeadlyImportError("Postprocess_BuildMesh. Unknown mesh type: " + std::to_string(pNodeElement.Type) + "."); } void X3DImporter::Postprocess_BuildNode(const CX3DImporter_NodeElement& pNodeElement, aiNode& pSceneNode, std::list& pSceneMeshList, @@ -566,7 +567,6 @@ void X3DImporter::Postprocess_BuildNode(const CX3DImporter_NodeElement& pNodeEle std::list::const_iterator chit_begin = pNodeElement.Child.begin(); std::list::const_iterator chit_end = pNodeElement.Child.end(); std::list SceneNode_Child; -std::list SceneNode_Light; std::list SceneNode_Mesh; // At first read all metadata @@ -620,7 +620,7 @@ std::list SceneNode_Mesh; } else if(!PostprocessHelper_ElementIsMetadata((*it)->Type))// skip metadata { - throw DeadlyImportError(boost::str(boost::format("Postprocess_BuildNode. Unknown type: %s.") % (*it)->Type)); + throw DeadlyImportError("Postprocess_BuildNode. Unknown type: " + std::to_string((*it)->Type) + "."); } }// for(std::list::const_iterator it = chit_begin; it != chit_end; it++) @@ -649,8 +649,8 @@ std::list SceneNode_Mesh; void X3DImporter::Postprocess_BuildShape(const CX3DImporter_NodeElement_Shape& pShapeNodeElement, std::list& pNodeMeshInd, std::list& pSceneMeshList, std::list& pSceneMaterialList) const { -aiMaterial* tmat = NULL; -aiMesh* tmesh = NULL; +aiMaterial* tmat = nullptr; +aiMesh* tmesh = nullptr; CX3DImporter_NodeElement::EType mesh_type = CX3DImporter_NodeElement::ENET_Invalid; unsigned int mat_ind = 0; @@ -659,7 +659,7 @@ unsigned int mat_ind = 0; if(PostprocessHelper_ElementIsMesh((*it)->Type)) { Postprocess_BuildMesh(**it, &tmesh); - if(tmesh != NULL) + if(tmesh != nullptr) { // if mesh successfully built then add data about it to arrays pNodeMeshInd.push_back(pSceneMeshList.size()); @@ -671,7 +671,7 @@ unsigned int mat_ind = 0; else if((*it)->Type == CX3DImporter_NodeElement::ENET_Appearance) { Postprocess_BuildMaterial(**it, &tmat); - if(tmat != NULL) + if(tmat != nullptr) { // if material successfully built then add data about it to array mat_ind = pSceneMaterialList.size(); @@ -681,7 +681,7 @@ unsigned int mat_ind = 0; }// for(std::list::const_iterator it = pShapeNodeElement.Child.begin(); it != pShapeNodeElement.Child.end(); it++) // associate read material with read mesh. - if((tmesh != NULL) && (tmat != NULL)) + if((tmesh != nullptr) && (tmat != nullptr)) { tmesh->mMaterialIndex = mat_ind; // Check texture mapping. If material has texture but mesh has no texture coordinate then try to ask Assimp to generate texture coordinates. @@ -709,25 +709,26 @@ unsigned int mat_ind = 0; tmat->AddProperty(&tm, 1, AI_MATKEY_MAPPING_DIFFUSE(0)); }// if((tmat->GetTextureCount(aiTextureType_DIFFUSE) != 0) && !tmesh->HasTextureCoords(0)) - }// if((tmesh != NULL) && (tmat != NULL)) + }// if((tmesh != nullptr) && (tmat != nullptr)) } void X3DImporter::Postprocess_CollectMetadata(const CX3DImporter_NodeElement& pNodeElement, aiNode& pSceneNode) const { std::list meta_list; -size_t meta_idx = 0; +size_t meta_idx; PostprocessHelper_CollectMetadata(pNodeElement, meta_list);// find metadata in current node element. if(meta_list.size() > 0) { - if(pSceneNode.mMetaData != NULL) throw DeadlyImportError("Postprocess. MetaData member in node are not NULL. Something went wrong."); + if(pSceneNode.mMetaData != nullptr) throw DeadlyImportError("Postprocess. MetaData member in node are not nullptr. Something went wrong."); // copy collected metadata to output node. pSceneNode.mMetaData = new aiMetadata(); pSceneNode.mMetaData->mNumProperties = meta_list.size(); pSceneNode.mMetaData->mKeys = new aiString[pSceneNode.mMetaData->mNumProperties]; pSceneNode.mMetaData->mValues = new aiMetadataEntry[pSceneNode.mMetaData->mNumProperties]; - for(std::list::const_iterator it = meta_list.begin(); it != meta_list.end(); it++) + meta_idx = 0; + for(std::list::const_iterator it = meta_list.begin(); it != meta_list.end(); it++, meta_idx++) { CX3DImporter_NodeElement_Meta* cur_meta = (CX3DImporter_NodeElement_Meta*)*it; diff --git a/code/X3DImporter_Rendering.cpp b/code/X3DImporter_Rendering.cpp index 4dba0f8c8..bb35f0ad2 100644 --- a/code/X3DImporter_Rendering.cpp +++ b/code/X3DImporter_Rendering.cpp @@ -1,7 +1,7 @@ -/// \file X3DImporter_Rendering.cpp -/// \brief Parsing data from nodes of "Rendering" set of X3D. -/// \date 2015-2016 -/// \author nevorek@gmail.com +/// \file X3DImporter_Rendering.cpp +/// \brief Parsing data from nodes of "Rendering" set of X3D. +/// \date 2015-2016 +/// \author smal.root@gmail.com #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER diff --git a/code/X3DImporter_Shape.cpp b/code/X3DImporter_Shape.cpp index 26016f24f..d697f916d 100644 --- a/code/X3DImporter_Shape.cpp +++ b/code/X3DImporter_Shape.cpp @@ -1,7 +1,7 @@ -/// \file X3DImporter_Shape.cpp -/// \brief Parsing data from nodes of "Shape" set of X3D. -/// \date 2015-2016 -/// \author nevorek@gmail.com +/// \file X3DImporter_Shape.cpp +/// \brief Parsing data from nodes of "Shape" set of X3D. +/// \date 2015-2016 +/// \author smal.root@gmail.com #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER diff --git a/code/X3DImporter_Texturing.cpp b/code/X3DImporter_Texturing.cpp index bc4832463..006264440 100644 --- a/code/X3DImporter_Texturing.cpp +++ b/code/X3DImporter_Texturing.cpp @@ -1,7 +1,7 @@ -/// \file X3DImporter_Texturing.cpp -/// \brief Parsing data from nodes of "Texturing" set of X3D. -/// \date 2015-2016 -/// \author nevorek@gmail.com +/// \file X3DImporter_Texturing.cpp +/// \brief Parsing data from nodes of "Texturing" set of X3D. +/// \date 2015-2016 +/// \author smal.root@gmail.com #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER From 3086a07e86b73c40203ad2572326ca2adf802b91 Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Sun, 2 Oct 2016 17:27:13 +0300 Subject: [PATCH 4/6] [*] Docs and build-files fixes. --- code/CMakeLists.txt | 1 + code/X3DImporter.cpp | 2 +- code/X3DImporter_Macro.hpp | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 4c584de17..d71a1893d 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -617,6 +617,7 @@ ADD_ASSIMP_IMPORTER(X3D X3DImporter_Geometry3D.cpp X3DImporter_Group.cpp X3DImporter_Light.cpp + X3DImporter_Macro.hpp X3DImporter_Metadata.cpp X3DImporter_Networking.cpp X3DImporter_Node.hpp diff --git a/code/X3DImporter.cpp b/code/X3DImporter.cpp index 9875d0f35..2efe22e14 100644 --- a/code/X3DImporter.cpp +++ b/code/X3DImporter.cpp @@ -23,7 +23,7 @@ namespace Assimp /// Conastant which hold importer description const aiImporterDesc X3DImporter::Description = { "Extensible 3D(X3D) Importer", - "nevorek", + "smalcom", "", "See documentation in source code. Chapter: Limitations.", aiImporterFlags_SupportTextFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental, diff --git a/code/X3DImporter_Macro.hpp b/code/X3DImporter_Macro.hpp index 9a1e302fb..2107443ef 100644 --- a/code/X3DImporter_Macro.hpp +++ b/code/X3DImporter_Macro.hpp @@ -1,7 +1,7 @@ /// \file X3DImporter_Macro.hpp /// \brief Useful macrodefines. /// \date 2015-2016 -/// \author nevorek@gmail.com +/// \author smal.root@gmail.com #ifndef X3DIMPORTER_MACRO_HPP_INCLUDED #define X3DIMPORTER_MACRO_HPP_INCLUDED From 897370b6ffc099d0b0cd31c753c8b03cbf932874 Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Sun, 2 Oct 2016 19:52:24 +0300 Subject: [PATCH 5/6] [*] Pull fresh data. [F] Using ssize_t is bad idea. --- code/X3DImporter.cpp | 75 ++++++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 27 deletions(-) diff --git a/code/X3DImporter.cpp b/code/X3DImporter.cpp index 2efe22e14..5812f1018 100644 --- a/code/X3DImporter.cpp +++ b/code/X3DImporter.cpp @@ -1371,10 +1371,28 @@ bool close_found = false;// flag: true if close tag of node are found. void X3DImporter::ParseNode_Scene() { +auto GroupCounter_Increase = [](size_t& pCounter, const char* pGroupName) -> void +{ + pCounter++; + if(pCounter == 0) throw DeadlyImportError("Group counter overflow. Too much groups with type: " + std::string(pGroupName) + "."); +}; + +auto GroupCounter_Decrease = [&](size_t& pCounter, const char* pGroupName) -> void +{ + if(pCounter == 0) Throw_TagCountIncorrect(pGroupName); + + pCounter--; +}; + +const char* GroupName_Group = "Group"; +const char* GroupName_StaticGroup = "StaticGroup"; +const char* GroupName_Transform = "Transform"; +const char* GroupName_Switch = "Switch"; + bool close_found = false; -ssize_t group_cnt = 0; -ssize_t transform_cnt = 0; -ssize_t sw_cnt = 0; +size_t counter_group = 0; +size_t counter_transform = 0; +size_t counter_switch = 0; // while create static node? Because objects name used deeper in "USE" attribute can be equal to some meta in node. ParseHelper_Group_Begin(true); @@ -1386,30 +1404,33 @@ ssize_t sw_cnt = 0; { ParseNode_Shape_Shape(); } - else if(XML_CheckNode_NameEqual("Group")) + else if(XML_CheckNode_NameEqual(GroupName_Group)) { - group_cnt++; + GroupCounter_Increase(counter_group, GroupName_Group); ParseNode_Grouping_Group(); - if(mReader->isEmptyElement()) group_cnt--;// if node is empty then decrease group counter at this place. + // if node is empty then decrease group counter at this place. + if(mReader->isEmptyElement()) GroupCounter_Decrease(counter_group, GroupName_Group); } - else if(XML_CheckNode_NameEqual("StaticGroup")) + else if(XML_CheckNode_NameEqual(GroupName_StaticGroup)) { - group_cnt++; + GroupCounter_Increase(counter_group, GroupName_StaticGroup); ParseNode_Grouping_StaticGroup(); - if(mReader->isEmptyElement()) group_cnt--;// if node is empty then decrease group counter at this place. - + // if node is empty then decrease group counter at this place. + if(mReader->isEmptyElement()) GroupCounter_Decrease(counter_group, GroupName_StaticGroup); } - else if(XML_CheckNode_NameEqual("Transform")) + else if(XML_CheckNode_NameEqual(GroupName_Transform)) { - transform_cnt++; + GroupCounter_Increase(counter_transform, GroupName_Transform); ParseNode_Grouping_Transform(); - if(mReader->isEmptyElement()) transform_cnt--;// if node is empty then decrease group counter at this place. + // if node is empty then decrease group counter at this place. + if(mReader->isEmptyElement()) GroupCounter_Decrease(counter_transform, GroupName_Transform); } - else if(XML_CheckNode_NameEqual("Switch")) + else if(XML_CheckNode_NameEqual(GroupName_Switch)) { - sw_cnt++; + GroupCounter_Increase(counter_switch, GroupName_Switch); ParseNode_Grouping_Switch(); - if(mReader->isEmptyElement()) sw_cnt--;// if node is empty then decrease group counter at this place. + // if node is empty then decrease group counter at this place. + if(mReader->isEmptyElement()) GroupCounter_Decrease(counter_switch, GroupName_Switch); } else if(XML_CheckNode_NameEqual("DirectionalLight")) { @@ -1440,24 +1461,24 @@ ssize_t sw_cnt = 0; break; } - else if(XML_CheckNode_NameEqual("Group")) + else if(XML_CheckNode_NameEqual(GroupName_Group)) { - group_cnt--; + GroupCounter_Decrease(counter_group, GroupName_Group); ParseNode_Grouping_GroupEnd(); } - else if(XML_CheckNode_NameEqual("StaticGroup")) + else if(XML_CheckNode_NameEqual(GroupName_StaticGroup)) { - group_cnt--; + GroupCounter_Decrease(counter_group, GroupName_StaticGroup); ParseNode_Grouping_StaticGroupEnd(); } - else if(XML_CheckNode_NameEqual("Transform")) + else if(XML_CheckNode_NameEqual(GroupName_Transform)) { - transform_cnt--; + GroupCounter_Decrease(counter_transform, GroupName_Transform); ParseNode_Grouping_TransformEnd(); } - else if(XML_CheckNode_NameEqual("Switch")) + else if(XML_CheckNode_NameEqual(GroupName_Switch)) { - sw_cnt--; + GroupCounter_Decrease(counter_switch, GroupName_Switch); ParseNode_Grouping_SwitchEnd(); } }// if(mReader->getNodeType() == irr::io::EXN_ELEMENT) else @@ -1465,9 +1486,9 @@ ssize_t sw_cnt = 0; ParseHelper_Node_Exit(); - if(group_cnt) Throw_TagCountIncorrect("Group"); - if(transform_cnt) Throw_TagCountIncorrect("Transform"); - if(sw_cnt) Throw_TagCountIncorrect("Switch"); + if(counter_group) Throw_TagCountIncorrect("Group"); + if(counter_transform) Throw_TagCountIncorrect("Transform"); + if(counter_switch) Throw_TagCountIncorrect("Switch"); if(!close_found) Throw_CloseNotFound("Scene"); } From aeb99898d3bc0c62eb50893ad3ee47d3a29e313e Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Sun, 2 Oct 2016 20:00:57 +0300 Subject: [PATCH 6/6] [*] Set float type for constants: less warnings, less type truncations. --- code/X3DImporter_Light.cpp | 4 ++-- code/X3DImporter_Postprocess.cpp | 2 +- code/X3DImporter_Shape.cpp | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/code/X3DImporter_Light.cpp b/code/X3DImporter_Light.cpp index c297d1b95..b6f1ecaa5 100644 --- a/code/X3DImporter_Light.cpp +++ b/code/X3DImporter_Light.cpp @@ -174,9 +174,9 @@ void X3DImporter::ParseNode_Lighting_SpotLight() std::string def, use; float ambientIntensity = 0; aiVector3D attenuation(1, 0, 0); -float beamWidth = 0.7854; +float beamWidth = 0.7854f; aiColor3D color(1, 1, 1); -float cutOffAngle = 1.570796; +float cutOffAngle = 1.570796f; aiVector3D direction(0, 0, -1); bool global = true; float intensity = 1; diff --git a/code/X3DImporter_Postprocess.cpp b/code/X3DImporter_Postprocess.cpp index ba946b9a5..ddc5aa939 100644 --- a/code/X3DImporter_Postprocess.cpp +++ b/code/X3DImporter_Postprocess.cpp @@ -167,7 +167,7 @@ void X3DImporter::Postprocess_BuildMaterial(const CX3DImporter_NodeElement& pNod tvalf = 1; taimat.AddProperty(&tvalf, 1, AI_MATKEY_SHININESS_STRENGTH); taimat.AddProperty(&tnemat.Shininess, 1, AI_MATKEY_SHININESS); - tvalf = 1.0 - tnemat.Transparency; + tvalf = 1.0f - tnemat.Transparency; taimat.AddProperty(&tvalf, 1, AI_MATKEY_OPACITY); }// if((*el_it)->Type == CX3DImporter_NodeElement::ENET_Material) else if((*el_it)->Type == CX3DImporter_NodeElement::ENET_ImageTexture) diff --git a/code/X3DImporter_Shape.cpp b/code/X3DImporter_Shape.cpp index d697f916d..c974f70ce 100644 --- a/code/X3DImporter_Shape.cpp +++ b/code/X3DImporter_Shape.cpp @@ -159,10 +159,10 @@ CX3DImporter_NodeElement* ne; void X3DImporter::ParseNode_Shape_Material() { std::string use, def; -float ambientIntensity = 0.2; -float shininess = 0.2; +float ambientIntensity = 0.2f; +float shininess = 0.2f; float transparency = 0; -aiColor3D diffuseColor(0.8, 0.8, 0.8); +aiColor3D diffuseColor(0.8f, 0.8f, 0.8f); aiColor3D emissiveColor(0, 0, 0); aiColor3D specularColor(0, 0, 0); CX3DImporter_NodeElement* ne;