summaryrefslogtreecommitdiff
path: root/src/mesh/assimp-master/code/AssetLib/OpenGEX/OpenGEXImporter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesh/assimp-master/code/AssetLib/OpenGEX/OpenGEXImporter.cpp')
-rw-r--r--src/mesh/assimp-master/code/AssetLib/OpenGEX/OpenGEXImporter.cpp1326
1 files changed, 1326 insertions, 0 deletions
diff --git a/src/mesh/assimp-master/code/AssetLib/OpenGEX/OpenGEXImporter.cpp b/src/mesh/assimp-master/code/AssetLib/OpenGEX/OpenGEXImporter.cpp
new file mode 100644
index 0000000..c8e4793
--- /dev/null
+++ b/src/mesh/assimp-master/code/AssetLib/OpenGEX/OpenGEXImporter.cpp
@@ -0,0 +1,1326 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2022, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+#ifndef ASSIMP_BUILD_NO_OPENGEX_IMPORTER
+
+#include "AssetLib/OpenGEX/OpenGEXImporter.h"
+#include "PostProcessing/MakeVerboseFormat.h"
+
+#include <assimp/DefaultIOSystem.h>
+#include <assimp/StringComparison.h>
+#include <assimp/StringUtils.h>
+#include <assimp/DefaultLogger.hpp>
+#include <assimp/ai_assert.h>
+#include <assimp/importerdesc.h>
+#include <assimp/scene.h>
+#include <openddlparser/OpenDDLParser.h>
+
+static const aiImporterDesc desc = {
+ "Open Game Engine Exchange",
+ "",
+ "",
+ "",
+ aiImporterFlags_SupportTextFlavour,
+ 0,
+ 0,
+ 0,
+ 0,
+ "ogex"
+};
+
+namespace Grammar {
+ static const char* MetricType = "Metric";
+ static const char *Metric_DistanceType = "distance";
+ static const char *Metric_AngleType = "angle";
+ static const char *Metric_TimeType = "time";
+ static const char *Metric_UpType = "up";
+ static const char *NameType = "Name";
+ static const char *ObjectRefType = "ObjectRef";
+ static const char *MaterialRefType = "MaterialRef";
+ static const char *MetricKeyType = "key";
+ static const char *GeometryNodeType = "GeometryNode";
+ static const char *CameraNodeType = "CameraNode";
+ static const char *LightNodeType = "LightNode";
+ static const char *GeometryObjectType = "GeometryObject";
+ static const char *CameraObjectType = "CameraObject";
+ static const char *LightObjectType = "LightObject";
+ static const char *TransformType = "Transform";
+ static const char *MeshType = "Mesh";
+ static const char *VertexArrayType = "VertexArray";
+ static const char *IndexArrayType = "IndexArray";
+ static const char *MaterialType = "Material";
+ static const char *ColorType = "Color";
+ static const char *ParamType = "Param";
+ static const char *TextureType = "Texture";
+ static const char *AttenType = "Atten";
+
+ static const char *DiffuseColorToken = "diffuse";
+ static const char *SpecularColorToken = "specular";
+ static const char *EmissionColorToken = "emission";
+
+ static const char *DiffuseTextureToken = "diffuse";
+ static const char *DiffuseSpecularTextureToken = "specular";
+ static const char *SpecularPowerTextureToken = "specular_power";
+ static const char *EmissionTextureToken = "emission";
+ static const char *OpacyTextureToken = "opacity";
+ static const char *TransparencyTextureToken = "transparency";
+ static const char *NormalTextureToken = "normal";
+
+ enum TokenType {
+ NoneType = -1,
+ MetricToken,
+ NameToken,
+ ObjectRefToken,
+ MaterialRefToken,
+ MetricKeyToken,
+ GeometryNodeToken,
+ CameraNodeToken,
+ LightNodeToken,
+ GeometryObjectToken,
+ CameraObjectToken,
+ LightObjectToken,
+ TransformToken,
+ MeshToken,
+ VertexArrayToken,
+ IndexArrayToken,
+ MaterialToken,
+ ColorToken,
+ ParamToken,
+ TextureToken,
+ AttenToken
+ };
+
+ static const std::string ValidMetricToken[4] = {
+ Metric_DistanceType,
+ Metric_AngleType,
+ Metric_TimeType,
+ Metric_UpType
+ };
+
+ static int isValidMetricType(const char *token) {
+ if (nullptr == token) {
+ return false;
+ }
+
+ int idx(-1);
+ for (size_t i = 0; i < 4; i++) {
+ if (ValidMetricToken[i] == token) {
+ idx = (int)i;
+ break;
+ }
+ }
+
+ return idx;
+ }
+
+ static TokenType matchTokenType(const char *tokenType) {
+ if (MetricType == tokenType) {
+ return MetricToken;
+ } else if (NameType == tokenType) {
+ return NameToken;
+ } else if (ObjectRefType == tokenType) {
+ return ObjectRefToken;
+ } else if (MaterialRefType == tokenType) {
+ return MaterialRefToken;
+ } else if (MetricKeyType == tokenType) {
+ return MetricKeyToken;
+ } else if (GeometryNodeType == tokenType) {
+ return GeometryNodeToken;
+ } else if (CameraNodeType == tokenType) {
+ return CameraNodeToken;
+ } else if (LightNodeType == tokenType) {
+ return LightNodeToken;
+ } else if (GeometryObjectType == tokenType) {
+ return GeometryObjectToken;
+ } else if (CameraObjectType == tokenType) {
+ return CameraObjectToken;
+ } else if (LightObjectType == tokenType) {
+ return LightObjectToken;
+ } else if (TransformType == tokenType) {
+ return TransformToken;
+ } else if (MeshType == tokenType) {
+ return MeshToken;
+ } else if (VertexArrayType == tokenType) {
+ return VertexArrayToken;
+ } else if (IndexArrayType == tokenType) {
+ return IndexArrayToken;
+ } else if (MaterialType == tokenType) {
+ return MaterialToken;
+ } else if (ColorType == tokenType) {
+ return ColorToken;
+ } else if (ParamType == tokenType) {
+ return ParamToken;
+ } else if (TextureType == tokenType) {
+ return TextureToken;
+ } else if (AttenType == tokenType) {
+ return AttenToken;
+ }
+
+ return NoneType;
+ }
+} // Namespace Grammar
+
+namespace Assimp {
+namespace OpenGEX {
+
+USE_ODDLPARSER_NS
+
+//------------------------------------------------------------------------------------------------
+static void propId2StdString(Property *prop, std::string &name, std::string &key) {
+ name = key = std::string();
+ if (nullptr == prop) {
+ return;
+ }
+
+ if (nullptr != prop->m_key) {
+#ifdef ASSIMP_USE_HUNTER
+ name = prop->m_key->m_text.m_buffer;
+#else
+ name = prop->m_key->m_buffer;
+#endif
+ if (Value::ValueType::ddl_string == prop->m_value->m_type) {
+ key = prop->m_value->getString();
+ }
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+static void logDDLParserMessage (LogSeverity severity, const std::string &rawmsg) {
+ std::string msg = ai_str_toprintable(rawmsg);
+ switch (severity) {
+ case ddl_debug_msg: ASSIMP_LOG_DEBUG(msg); break;
+ case ddl_info_msg: ASSIMP_LOG_INFO(msg); break;
+ case ddl_warn_msg: ASSIMP_LOG_WARN(msg); break;
+ case ddl_error_msg: ASSIMP_LOG_ERROR(msg); break;
+ default: ASSIMP_LOG_VERBOSE_DEBUG(msg); break;
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+OpenGEXImporter::VertexContainer::VertexContainer() :
+ m_numColors(0), m_colors(nullptr), m_numUVComps(), m_textureCoords() {
+ // empty
+}
+
+//------------------------------------------------------------------------------------------------
+OpenGEXImporter::VertexContainer::~VertexContainer() {
+ delete[] m_colors;
+
+ for (auto &texcoords : m_textureCoords) {
+ delete[] texcoords;
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+OpenGEXImporter::RefInfo::RefInfo(aiNode *node, Type type, std::vector<std::string> &names) :
+ m_node(node),
+ m_type(type),
+ m_Names(names) {
+ // empty
+}
+
+//------------------------------------------------------------------------------------------------
+OpenGEXImporter::RefInfo::~RefInfo() {
+ // empty
+}
+
+//------------------------------------------------------------------------------------------------
+OpenGEXImporter::OpenGEXImporter() :
+ m_root(nullptr),
+ m_nodeChildMap(),
+ m_meshCache(),
+ m_mesh2refMap(),
+ m_material2refMap(),
+ m_ctx(nullptr),
+ m_metrics(),
+ m_currentNode(nullptr),
+ m_currentVertices(),
+ m_currentMesh(nullptr),
+ m_currentMaterial(nullptr),
+ m_currentLight(nullptr),
+ m_currentCamera(nullptr),
+ m_tokenType(Grammar::NoneType),
+ m_materialCache(),
+ m_cameraCache(),
+ m_lightCache(),
+ m_nodeStack(),
+ m_unresolvedRefStack() {
+ // empty
+}
+
+//------------------------------------------------------------------------------------------------
+OpenGEXImporter::~OpenGEXImporter() {
+}
+
+//------------------------------------------------------------------------------------------------
+bool OpenGEXImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool /*checkSig*/) const {
+ static const char *tokens[] = { "Metric", "GeometryNode", "VertexArray (attrib", "IndexArray" };
+ return SearchFileHeaderForToken(pIOHandler, file, tokens, AI_COUNT_OF(tokens));
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::InternReadFile(const std::string &filename, aiScene *pScene, IOSystem *pIOHandler) {
+ // open source file
+ IOStream *file = pIOHandler->Open(filename, "rb");
+ if (!file) {
+ throw DeadlyImportError("Failed to open file ", filename);
+ }
+
+ std::vector<char> buffer;
+ TextFileToBuffer(file, buffer);
+ pIOHandler->Close(file);
+
+ OpenDDLParser myParser;
+ myParser.setLogCallback(&logDDLParserMessage);
+ myParser.setBuffer(&buffer[0], buffer.size());
+ bool success(myParser.parse());
+ if (success) {
+ m_ctx = myParser.getContext();
+ pScene->mRootNode = new aiNode;
+ pScene->mRootNode->mName.Set(filename);
+ handleNodes(m_ctx->m_root, pScene);
+ }
+
+ copyMeshes(pScene);
+ copyCameras(pScene);
+ copyLights(pScene);
+ copyMaterials(pScene);
+ resolveReferences();
+ createNodeTree(pScene);
+}
+
+//------------------------------------------------------------------------------------------------
+const aiImporterDesc *OpenGEXImporter::GetInfo() const {
+ return &desc;
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::SetupProperties(const Importer *pImp) {
+ if (nullptr == pImp) {
+ return;
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleNodes(DDLNode *node, aiScene *pScene) {
+ if (nullptr == node) {
+ return;
+ }
+
+ DDLNode::DllNodeList children = node->getChildNodeList();
+ for (DDLNode::DllNodeList::iterator it = children.begin(); it != children.end(); ++it) {
+ Grammar::TokenType tokenType(Grammar::matchTokenType((*it)->getType().c_str()));
+ switch (tokenType) {
+ case Grammar::MetricToken:
+ handleMetricNode(*it, pScene);
+ break;
+
+ case Grammar::NameToken:
+ handleNameNode(*it, pScene);
+ break;
+
+ case Grammar::ObjectRefToken:
+ handleObjectRefNode(*it, pScene);
+ break;
+
+ case Grammar::MaterialRefToken:
+ handleMaterialRefNode(*it, pScene);
+ break;
+
+ case Grammar::MetricKeyToken:
+ break;
+
+ case Grammar::GeometryNodeToken:
+ handleGeometryNode(*it, pScene);
+ break;
+
+ case Grammar::CameraNodeToken:
+ handleCameraNode(*it, pScene);
+ break;
+
+ case Grammar::LightNodeToken:
+ handleLightNode(*it, pScene);
+ break;
+
+ case Grammar::GeometryObjectToken:
+ handleGeometryObject(*it, pScene);
+ break;
+
+ case Grammar::CameraObjectToken:
+ handleCameraObject(*it, pScene);
+ break;
+
+ case Grammar::LightObjectToken:
+ handleLightObject(*it, pScene);
+ break;
+
+ case Grammar::TransformToken:
+ handleTransformNode(*it, pScene);
+ break;
+
+ case Grammar::MeshToken:
+ handleMeshNode(*it, pScene);
+ break;
+
+ case Grammar::VertexArrayToken:
+ handleVertexArrayNode(*it, pScene);
+ break;
+
+ case Grammar::IndexArrayToken:
+ handleIndexArrayNode(*it, pScene);
+ break;
+
+ case Grammar::MaterialToken:
+ handleMaterialNode(*it, pScene);
+ break;
+
+ case Grammar::ColorToken:
+ handleColorNode(*it, pScene);
+ break;
+
+ case Grammar::ParamToken:
+ handleParamNode(*it, pScene);
+ break;
+
+ case Grammar::TextureToken:
+ handleTextureNode(*it, pScene);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleMetricNode(DDLNode *node, aiScene * /*pScene*/) {
+ if (nullptr == node || nullptr == m_ctx) {
+ return;
+ }
+
+ if (m_ctx->m_root != node->getParent()) {
+ return;
+ }
+
+ Property *prop(node->getProperties());
+ while (nullptr != prop) {
+ if (nullptr != prop->m_key) {
+ if (Value::ValueType::ddl_string == prop->m_value->m_type) {
+ std::string valName((char *)prop->m_value->m_data);
+ int type(Grammar::isValidMetricType(valName.c_str()));
+ if (Grammar::NoneType != type) {
+ Value *val(node->getValue());
+ if (nullptr != val) {
+ if (Value::ValueType::ddl_float == val->m_type) {
+ m_metrics[type].m_floatValue = val->getFloat();
+ } else if (Value::ValueType::ddl_int32 == val->m_type) {
+ m_metrics[type].m_intValue = val->getInt32();
+ } else if (Value::ValueType::ddl_string == val->m_type) {
+ m_metrics[type].m_stringValue = std::string(val->getString());
+ } else {
+ throw DeadlyImportError("OpenGEX: invalid data type for Metric node.");
+ }
+ }
+ }
+ }
+ }
+ prop = prop->m_next;
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleNameNode(DDLNode *node, aiScene * /*pScene*/) {
+ if (nullptr == m_currentNode) {
+ throw DeadlyImportError("No current node for name.");
+ return;
+ }
+
+ Value *val(node->getValue());
+ if (nullptr != val) {
+ if (Value::ValueType::ddl_string != val->m_type) {
+ throw DeadlyImportError("OpenGEX: invalid data type for value in node name.");
+ return;
+ }
+
+ const std::string name(val->getString());
+ if (m_tokenType == Grammar::GeometryNodeToken || m_tokenType == Grammar::LightNodeToken || m_tokenType == Grammar::CameraNodeToken) {
+ m_currentNode->mName.Set(name.c_str());
+ } else if (m_tokenType == Grammar::MaterialToken) {
+ aiString aiName;
+ aiName.Set(name);
+ m_currentMaterial->AddProperty(&aiName, AI_MATKEY_NAME);
+ m_material2refMap[name] = m_materialCache.size() - 1;
+ }
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+static void getRefNames(DDLNode *node, std::vector<std::string> &names) {
+ ai_assert(nullptr != node);
+
+ Reference *ref = node->getReferences();
+ if (nullptr != ref) {
+ for (size_t i = 0; i < ref->m_numRefs; i++) {
+ Name *currentName(ref->m_referencedName[i]);
+ if (nullptr != currentName && nullptr != currentName->m_id) {
+#ifdef ASSIMP_USE_HUNTER
+ const std::string name(currentName->m_id->m_text.m_buffer);
+#else
+ const std::string name(currentName->m_id->m_buffer);
+#endif
+ if (!name.empty()) {
+ names.push_back(name);
+ }
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleObjectRefNode(DDLNode *node, aiScene * /*pScene*/) {
+ if (nullptr == m_currentNode) {
+ throw DeadlyImportError("No parent node for name.");
+ return;
+ }
+
+ std::vector<std::string> objRefNames;
+ getRefNames(node, objRefNames);
+
+ // when we are dealing with a geometry node prepare the mesh cache
+ if (m_tokenType == Grammar::GeometryNodeToken) {
+ m_currentNode->mNumMeshes = static_cast<unsigned int>(objRefNames.size());
+ m_currentNode->mMeshes = new unsigned int[objRefNames.size()];
+ if (!objRefNames.empty()) {
+ m_unresolvedRefStack.push_back(std::unique_ptr<RefInfo>(new RefInfo(m_currentNode, RefInfo::MeshRef, objRefNames)));
+ }
+ } else if (m_tokenType == Grammar::LightNodeToken) {
+ // TODO!
+ } else if (m_tokenType == Grammar::CameraNodeToken) {
+ // TODO!
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleMaterialRefNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
+ if (nullptr == m_currentNode) {
+ throw DeadlyImportError("No parent node for name.");
+ return;
+ }
+
+ std::vector<std::string> matRefNames;
+ getRefNames(node, matRefNames);
+ if (!matRefNames.empty()) {
+ m_unresolvedRefStack.push_back(std::unique_ptr<RefInfo>(new RefInfo(m_currentNode, RefInfo::MaterialRef, matRefNames)));
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleGeometryNode(DDLNode *node, aiScene *pScene) {
+ aiNode *newNode = new aiNode;
+ pushNode(newNode, pScene);
+ m_tokenType = Grammar::GeometryNodeToken;
+ m_currentNode = newNode;
+ handleNodes(node, pScene);
+
+ popNode();
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleCameraNode(DDLNode *node, aiScene *pScene) {
+ aiCamera *camera(new aiCamera);
+ m_cameraCache.push_back(camera);
+ m_currentCamera = camera;
+
+ aiNode *newNode = new aiNode;
+ pushNode(newNode, pScene);
+ m_tokenType = Grammar::CameraNodeToken;
+ m_currentNode = newNode;
+
+ handleNodes(node, pScene);
+
+ popNode();
+
+ m_currentCamera->mName.Set(newNode->mName.C_Str());
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleLightNode(ODDLParser::DDLNode *node, aiScene *pScene) {
+ aiLight *light(new aiLight);
+ m_lightCache.push_back(light);
+ m_currentLight = light;
+
+ aiNode *newNode = new aiNode;
+ m_tokenType = Grammar::LightNodeToken;
+ m_currentNode = newNode;
+ pushNode(newNode, pScene);
+
+ handleNodes(node, pScene);
+
+ popNode();
+
+ m_currentLight->mName.Set(newNode->mName.C_Str());
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleGeometryObject(DDLNode *node, aiScene *pScene) {
+ // parameters will be parsed normally in the tree, so just go for it
+ handleNodes(node, pScene);
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleCameraObject(ODDLParser::DDLNode *node, aiScene *pScene) {
+ // parameters will be parsed normally in the tree, so just go for it
+
+ handleNodes(node, pScene);
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleLightObject(ODDLParser::DDLNode *node, aiScene *pScene) {
+ aiLight *light(new aiLight);
+ m_lightCache.push_back(light);
+ std::string objName = node->getName();
+ if (!objName.empty()) {
+ light->mName.Set(objName);
+ }
+ m_currentLight = light;
+
+ Property *prop(node->findPropertyByName("type"));
+ if (nullptr != prop) {
+ if (nullptr != prop->m_value) {
+ std::string typeStr(prop->m_value->getString());
+ if ("point" == typeStr) {
+ m_currentLight->mType = aiLightSource_POINT;
+ } else if ("spot" == typeStr) {
+ m_currentLight->mType = aiLightSource_SPOT;
+ } else if ("infinite" == typeStr) {
+ m_currentLight->mType = aiLightSource_DIRECTIONAL;
+ }
+ }
+ }
+
+ // parameters will be parsed normally in the tree, so just go for it
+ handleNodes(node, pScene);
+}
+
+//------------------------------------------------------------------------------------------------
+static void setMatrix(aiNode *node, DataArrayList *transformData) {
+ ai_assert(nullptr != node);
+ ai_assert(nullptr != transformData);
+
+ float m[16];
+ size_t i(1);
+ Value *next(transformData->m_dataList->m_next);
+ m[0] = transformData->m_dataList->getFloat();
+ while (next != nullptr) {
+ m[i] = next->getFloat();
+ next = next->m_next;
+ i++;
+ }
+
+ ai_assert(i == 16);
+
+ node->mTransformation.a1 = m[0];
+ node->mTransformation.a2 = m[4];
+ node->mTransformation.a3 = m[8];
+ node->mTransformation.a4 = m[12];
+
+ node->mTransformation.b1 = m[1];
+ node->mTransformation.b2 = m[5];
+ node->mTransformation.b3 = m[9];
+ node->mTransformation.b4 = m[13];
+
+ node->mTransformation.c1 = m[2];
+ node->mTransformation.c2 = m[6];
+ node->mTransformation.c3 = m[10];
+ node->mTransformation.c4 = m[14];
+
+ node->mTransformation.d1 = m[3];
+ node->mTransformation.d2 = m[7];
+ node->mTransformation.d3 = m[11];
+ node->mTransformation.d4 = m[15];
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleTransformNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
+ if (nullptr == m_currentNode) {
+ throw DeadlyImportError("No parent node for name.");
+ return;
+ }
+
+ DataArrayList *transformData(node->getDataArrayList());
+ if (nullptr != transformData) {
+ if (transformData->m_numItems != 16) {
+ throw DeadlyImportError("Invalid number of data for transform matrix.");
+ return;
+ }
+ setMatrix(m_currentNode, transformData);
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleMeshNode(ODDLParser::DDLNode *node, aiScene *pScene) {
+ m_currentMesh = new aiMesh;
+ const size_t meshidx(m_meshCache.size());
+ // ownership is transferred but a reference remains in m_currentMesh
+ m_meshCache.emplace_back(m_currentMesh);
+
+ Property *prop = node->getProperties();
+ if (nullptr != prop) {
+ std::string propName, propKey;
+ propId2StdString(prop, propName, propKey);
+ if ("primitive" == propName) {
+ if ("points" == propKey) {
+ m_currentMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
+ } else if ("lines" == propKey) {
+ m_currentMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
+ } else if ("triangles" == propKey) {
+ m_currentMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
+ } else if ("quads" == propKey) {
+ m_currentMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
+ } else {
+ ASSIMP_LOG_WARN(propKey, " is not supported primitive type.");
+ }
+ }
+ }
+
+ handleNodes(node, pScene);
+
+ DDLNode *parent(node->getParent());
+ if (nullptr != parent) {
+ const std::string &name = parent->getName();
+ m_mesh2refMap[name] = meshidx;
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+enum MeshAttribute {
+ None,
+ Position,
+ Color,
+ Normal,
+ TexCoord
+};
+
+constexpr auto PosToken = "position";
+constexpr auto ColToken = "color";
+constexpr auto NormalToken = "normal";
+constexpr auto TexCoordToken = "texcoord";
+
+//------------------------------------------------------------------------------------------------
+static MeshAttribute getAttributeByName(const char *attribName) {
+ ai_assert(nullptr != attribName);
+
+ if (0 == strcmp(PosToken, attribName)) {
+ return Position;
+ } else if (0 == strcmp(ColToken, attribName)) {
+ return Color;
+ } else if (0 == strcmp(NormalToken, attribName)) {
+ return Normal;
+ } else if (0 == strcmp(TexCoordToken, attribName)) {
+ return TexCoord;
+ }
+
+ return None;
+}
+
+//------------------------------------------------------------------------------------------------
+static void fillVector3(aiVector3D *vec3, Value *vals) {
+ ai_assert(nullptr != vec3);
+ ai_assert(nullptr != vals);
+
+ float x(0.0f), y(0.0f), z(0.0f);
+ Value *next(vals);
+ x = next->getFloat();
+ next = next->m_next;
+ y = next->getFloat();
+ next = next->m_next;
+ if (nullptr != next) {
+ z = next->getFloat();
+ }
+
+ vec3->Set(x, y, z);
+}
+
+//------------------------------------------------------------------------------------------------
+static void fillColor4(aiColor4D *col4, Value *vals) {
+ ai_assert(nullptr != col4);
+ ai_assert(nullptr != vals);
+
+ Value *next(vals);
+ col4->r = next->getFloat();
+ next = next->m_next;
+ if (!next) {
+ throw DeadlyImportError("OpenGEX: Not enough values to fill 4-element color, only 1");
+ }
+
+ col4->g = next->getFloat();
+ next = next->m_next;
+ if (!next) {
+ throw DeadlyImportError("OpenGEX: Not enough values to fill 4-element color, only 2");
+ }
+
+ col4->b = next->getFloat();
+ next = next->m_next;
+ if (!next) {
+ throw DeadlyImportError("OpenGEX: Not enough values to fill 4-element color, only 3");
+ }
+
+ col4->a = next->getFloat();
+}
+
+//------------------------------------------------------------------------------------------------
+static size_t countDataArrayListItems(DataArrayList *vaList) {
+ size_t numItems(0);
+ if (nullptr == vaList) {
+ return numItems;
+ }
+
+ DataArrayList *next(vaList);
+ while (nullptr != next) {
+ if (nullptr != vaList->m_dataList) {
+ numItems++;
+ }
+ next = next->m_next;
+ }
+
+ return numItems;
+}
+
+//------------------------------------------------------------------------------------------------
+static void copyVectorArray(size_t numItems, DataArrayList *vaList, aiVector3D *vectorArray) {
+ for (size_t i = 0; i < numItems; i++) {
+ Value *next(vaList->m_dataList);
+ fillVector3(&vectorArray[i], next);
+ vaList = vaList->m_next;
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+static void copyColor4DArray(size_t numItems, DataArrayList *vaList, aiColor4D *colArray) {
+ for (size_t i = 0; i < numItems; i++) {
+ Value *next(vaList->m_dataList);
+ fillColor4(&colArray[i], next);
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleVertexArrayNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
+ if (nullptr == node) {
+ throw DeadlyImportError("No parent node for name.");
+ return;
+ }
+
+ Property *prop = node->getProperties();
+ if (nullptr != prop) {
+ std::string propName, propKey;
+ propId2StdString(prop, propName, propKey);
+ MeshAttribute attribType(getAttributeByName(propKey.c_str()));
+ if (None == attribType) {
+ return;
+ }
+
+ DataArrayList *vaList = node->getDataArrayList();
+ if (nullptr == vaList) {
+ return;
+ }
+
+ const size_t numItems(countDataArrayListItems(vaList));
+
+ if (Position == attribType) {
+ m_currentVertices.m_vertices.resize(numItems);
+ copyVectorArray(numItems, vaList, m_currentVertices.m_vertices.data());
+ } else if (Color == attribType) {
+ m_currentVertices.m_numColors = numItems;
+ m_currentVertices.m_colors = new aiColor4D[numItems];
+ copyColor4DArray(numItems, vaList, m_currentVertices.m_colors);
+ } else if (Normal == attribType) {
+ m_currentVertices.m_normals.resize(numItems);
+ copyVectorArray(numItems, vaList, m_currentVertices.m_normals.data());
+ } else if (TexCoord == attribType) {
+ m_currentVertices.m_numUVComps[0] = numItems;
+ m_currentVertices.m_textureCoords[0] = new aiVector3D[numItems];
+ copyVectorArray(numItems, vaList, m_currentVertices.m_textureCoords[0]);
+ }
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleIndexArrayNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
+ if (nullptr == node) {
+ throw DeadlyImportError("No parent node for name.");
+ return;
+ }
+
+ if (nullptr == m_currentMesh) {
+ throw DeadlyImportError("No current mesh for index data found.");
+ return;
+ }
+
+ DataArrayList *vaList = node->getDataArrayList();
+ if (nullptr == vaList) {
+ return;
+ }
+
+ const size_t numItems(countDataArrayListItems(vaList));
+ m_currentMesh->mNumFaces = static_cast<unsigned int>(numItems);
+ m_currentMesh->mFaces = new aiFace[numItems];
+ m_currentMesh->mNumVertices = static_cast<unsigned int>(numItems * 3);
+ m_currentMesh->mVertices = new aiVector3D[m_currentMesh->mNumVertices];
+ bool hasColors(false);
+ if (m_currentVertices.m_numColors > 0) {
+ m_currentMesh->mColors[0] = new aiColor4D[m_currentVertices.m_numColors];
+ hasColors = true;
+ }
+ bool hasNormalCoords(false);
+ if (!m_currentVertices.m_normals.empty()) {
+ m_currentMesh->mNormals = new aiVector3D[m_currentMesh->mNumVertices];
+ hasNormalCoords = true;
+ }
+ bool hasTexCoords(false);
+ if (m_currentVertices.m_numUVComps[0] > 0) {
+ m_currentMesh->mTextureCoords[0] = new aiVector3D[m_currentMesh->mNumVertices];
+ hasTexCoords = true;
+ }
+
+ unsigned int index(0);
+ for (size_t i = 0; i < m_currentMesh->mNumFaces; i++) {
+ aiFace &current(m_currentMesh->mFaces[i]);
+ current.mNumIndices = 3;
+ current.mIndices = new unsigned int[current.mNumIndices];
+ Value *next(vaList->m_dataList);
+ for (size_t indices = 0; indices < current.mNumIndices; indices++) {
+ const int idx(next->getUnsignedInt32());
+ ai_assert(static_cast<size_t>(idx) <= m_currentVertices.m_vertices.size());
+ ai_assert(index < m_currentMesh->mNumVertices);
+ aiVector3D &pos = (m_currentVertices.m_vertices[idx]);
+ m_currentMesh->mVertices[index].Set(pos.x, pos.y, pos.z);
+ if (hasColors) {
+ aiColor4D &col = m_currentVertices.m_colors[idx];
+ m_currentMesh->mColors[0][index] = col;
+ }
+ if (hasNormalCoords) {
+ aiVector3D &normal = (m_currentVertices.m_normals[idx]);
+ m_currentMesh->mNormals[index].Set(normal.x, normal.y, normal.z);
+ }
+ if (hasTexCoords) {
+ aiVector3D &tex = (m_currentVertices.m_textureCoords[0][idx]);
+ m_currentMesh->mTextureCoords[0][index].Set(tex.x, tex.y, tex.z);
+ }
+ current.mIndices[indices] = index;
+ index++;
+
+ next = next->m_next;
+ }
+ vaList = vaList->m_next;
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+static void getColorRGB3(aiColor3D *pColor, DataArrayList *colList) {
+ if (nullptr == pColor || nullptr == colList) {
+ return;
+ }
+
+ ai_assert(3 == colList->m_numItems);
+ Value *val(colList->m_dataList);
+ pColor->r = val->getFloat();
+ val = val->getNext();
+ pColor->g = val->getFloat();
+ val = val->getNext();
+ pColor->b = val->getFloat();
+}
+
+//------------------------------------------------------------------------------------------------
+static void getColorRGB4(aiColor4D *pColor, DataArrayList *colList) {
+ if (nullptr == pColor || nullptr == colList) {
+ return;
+ }
+
+ ai_assert(4 == colList->m_numItems);
+ Value *val(colList->m_dataList);
+ pColor->r = val->getFloat();
+ val = val->getNext();
+ pColor->g = val->getFloat();
+ val = val->getNext();
+ pColor->b = val->getFloat();
+ val = val->getNext();
+ pColor->a = val->getFloat();
+}
+
+//------------------------------------------------------------------------------------------------
+enum ColorType {
+ NoneColor = 0,
+ DiffuseColor,
+ SpecularColor,
+ EmissionColor,
+ LightColor
+};
+
+//------------------------------------------------------------------------------------------------
+static ColorType getColorType(Text *id) {
+ if (nullptr == id) {
+ return NoneColor;
+ }
+
+ if (*id == Grammar::DiffuseColorToken) {
+ return DiffuseColor;
+ } else if (*id == Grammar::SpecularColorToken) {
+ return SpecularColor;
+ } else if (*id == Grammar::EmissionColorToken) {
+ return EmissionColor;
+ } else if (*id == "light") {
+ return LightColor;
+ }
+
+ return NoneColor;
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleMaterialNode(ODDLParser::DDLNode *node, aiScene *pScene) {
+ m_currentMaterial = new aiMaterial;
+ m_materialCache.push_back(m_currentMaterial);
+ m_tokenType = Grammar::MaterialToken;
+ handleNodes(node, pScene);
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleColorNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
+ if (nullptr == node) {
+ return;
+ }
+
+ Property *prop = node->findPropertyByName("attrib");
+ if (nullptr != prop) {
+ if (nullptr != prop->m_value) {
+ DataArrayList *colList(node->getDataArrayList());
+ if (nullptr == colList) {
+ return;
+ }
+ aiColor3D col;
+ if (3 == colList->m_numItems) {
+ aiColor3D col3;
+ getColorRGB3(&col3, colList);
+ col = col3;
+ } else {
+ aiColor4D col4;
+ getColorRGB4(&col4, colList);
+ col.r = col4.r;
+ col.g = col4.g;
+ col.b = col4.b;
+ }
+#ifdef ASSIMP_USE_HUNTER
+ const ColorType colType(getColorType(&prop->m_key->m_text));
+#else
+ const ColorType colType(getColorType(prop->m_key));
+#endif
+ if (DiffuseColor == colType) {
+ m_currentMaterial->AddProperty(&col, 1, AI_MATKEY_COLOR_DIFFUSE);
+ } else if (SpecularColor == colType) {
+ m_currentMaterial->AddProperty(&col, 1, AI_MATKEY_COLOR_SPECULAR);
+ } else if (EmissionColor == colType) {
+ m_currentMaterial->AddProperty(&col, 1, AI_MATKEY_COLOR_EMISSIVE);
+ } else if (LightColor == colType) {
+ m_currentLight->mColorDiffuse = col;
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleTextureNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
+ if (nullptr == node) {
+ return;
+ }
+
+ Property *prop = node->findPropertyByName("attrib");
+ if (nullptr != prop) {
+ if (nullptr != prop->m_value) {
+ Value *val(node->getValue());
+ if (nullptr != val) {
+ aiString tex;
+ tex.Set(val->getString());
+ if (prop->m_value->getString() == Grammar::DiffuseTextureToken) {
+ m_currentMaterial->AddProperty(&tex, AI_MATKEY_TEXTURE_DIFFUSE(0));
+ } else if (prop->m_value->getString() == Grammar::DiffuseSpecularTextureToken) {
+ m_currentMaterial->AddProperty(&tex, AI_MATKEY_TEXTURE_SPECULAR(0));
+ } else if (prop->m_value->getString() == Grammar::SpecularPowerTextureToken) {
+ m_currentMaterial->AddProperty(&tex, AI_MATKEY_TEXTURE_SPECULAR(0));
+ } else if (prop->m_value->getString() == Grammar::EmissionTextureToken) {
+ m_currentMaterial->AddProperty(&tex, AI_MATKEY_TEXTURE_EMISSIVE(0));
+ } else if (prop->m_value->getString() == Grammar::OpacyTextureToken) {
+ m_currentMaterial->AddProperty(&tex, AI_MATKEY_TEXTURE_OPACITY(0));
+ } else if (prop->m_value->getString() == Grammar::TransparencyTextureToken) {
+ // ToDo!
+ // m_currentMaterial->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE( 0 ) );
+ } else if (prop->m_value->getString() == Grammar::NormalTextureToken) {
+ m_currentMaterial->AddProperty(&tex, AI_MATKEY_TEXTURE_NORMALS(0));
+ } else {
+ ai_assert(false);
+ }
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleParamNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
+ if (nullptr == node) {
+ return;
+ }
+
+ Property *prop = node->findPropertyByName("attrib");
+ if (nullptr == prop) {
+ return;
+ }
+
+ if (nullptr != prop->m_value) {
+ Value *val(node->getValue());
+ if (nullptr == val) {
+ return;
+ }
+ const float floatVal(val->getFloat());
+ if (0 == ASSIMP_strincmp("fov", prop->m_value->getString(), 3)) {
+ m_currentCamera->mHorizontalFOV = floatVal;
+ } else if (0 == ASSIMP_strincmp("near", prop->m_value->getString(), 4)) {
+ m_currentCamera->mClipPlaneNear = floatVal;
+ } else if (0 == ASSIMP_strincmp("far", prop->m_value->getString(), 3)) {
+ m_currentCamera->mClipPlaneFar = floatVal;
+ }
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleAttenNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
+ if (nullptr == node) {
+ return;
+ }
+
+ Property *prop = node->findPropertyByName("curve");
+ if (nullptr != prop) {
+ if (nullptr != prop->m_value) {
+ Value *val(node->getValue());
+ const float floatVal(val->getFloat());
+ if (0 == strncmp("scale", prop->m_value->getString(), strlen("scale"))) {
+ m_currentLight->mAttenuationQuadratic = floatVal;
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::copyMeshes(aiScene *pScene) {
+ ai_assert(nullptr != pScene);
+
+ if (m_meshCache.empty()) {
+ return;
+ }
+
+ pScene->mNumMeshes = static_cast<unsigned int>(m_meshCache.size());
+ pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
+ for (unsigned int i = 0; i < pScene->mNumMeshes; i++) {
+ pScene->mMeshes[i] = m_meshCache[i].release();
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::copyCameras(aiScene *pScene) {
+ ai_assert(nullptr != pScene);
+
+ if (m_cameraCache.empty()) {
+ return;
+ }
+
+ pScene->mNumCameras = static_cast<unsigned int>(m_cameraCache.size());
+ pScene->mCameras = new aiCamera *[pScene->mNumCameras];
+ std::copy(m_cameraCache.begin(), m_cameraCache.end(), pScene->mCameras);
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::copyLights(aiScene *pScene) {
+ ai_assert(nullptr != pScene);
+
+ if (m_lightCache.empty()) {
+ return;
+ }
+
+ pScene->mNumLights = static_cast<unsigned int>(m_lightCache.size());
+ pScene->mLights = new aiLight *[pScene->mNumLights];
+ std::copy(m_lightCache.begin(), m_lightCache.end(), pScene->mLights);
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::copyMaterials(aiScene *pScene) {
+ ai_assert(nullptr != pScene);
+
+ if (m_materialCache.empty()) {
+ return;
+ }
+
+ pScene->mNumMaterials = static_cast<unsigned int>(m_materialCache.size());
+ pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
+ std::copy(m_materialCache.begin(), m_materialCache.end(), pScene->mMaterials);
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::resolveReferences() {
+ if (m_unresolvedRefStack.empty()) {
+ return;
+ }
+
+ RefInfo *currentRefInfo(nullptr);
+ for (auto it = m_unresolvedRefStack.begin(); it != m_unresolvedRefStack.end(); ++it) {
+ currentRefInfo = it->get();
+ if (nullptr != currentRefInfo) {
+ aiNode *node(currentRefInfo->m_node);
+ if (RefInfo::MeshRef == currentRefInfo->m_type) {
+ for (size_t i = 0; i < currentRefInfo->m_Names.size(); ++i) {
+ const std::string &name(currentRefInfo->m_Names[i]);
+ ReferenceMap::const_iterator curIt(m_mesh2refMap.find(name));
+ if (m_mesh2refMap.end() != curIt) {
+ unsigned int meshIdx = static_cast<unsigned int>(m_mesh2refMap[name]);
+ node->mMeshes[i] = meshIdx;
+ }
+ }
+ } else if (RefInfo::MaterialRef == currentRefInfo->m_type) {
+ for (size_t i = 0; i < currentRefInfo->m_Names.size(); ++i) {
+ const std::string name(currentRefInfo->m_Names[i]);
+ ReferenceMap::const_iterator curIt(m_material2refMap.find(name));
+ if (m_material2refMap.end() != curIt) {
+ if (nullptr != m_currentMesh) {
+ unsigned int matIdx = static_cast<unsigned int>(m_material2refMap[name]);
+ if (m_currentMesh->mMaterialIndex != 0) {
+ ASSIMP_LOG_WARN("Override of material reference in current mesh by material reference.");
+ }
+ m_currentMesh->mMaterialIndex = matIdx;
+ } else {
+ ASSIMP_LOG_WARN("Cannot resolve material reference, because no current mesh is there.");
+ }
+ }
+ }
+ } else {
+ throw DeadlyImportError("Unknown reference info to resolve.");
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::createNodeTree(aiScene *pScene) {
+ if (nullptr == m_root) {
+ return;
+ }
+
+ if (m_root->m_children.empty()) {
+ return;
+ }
+
+ pScene->mRootNode->mNumChildren = static_cast<unsigned int>(m_root->m_children.size());
+ pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren];
+ std::copy(m_root->m_children.begin(), m_root->m_children.end(), pScene->mRootNode->mChildren);
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::pushNode(aiNode *node, aiScene *pScene) {
+ ai_assert(nullptr != pScene);
+
+ if (nullptr == node) {
+ return;
+ }
+
+ ChildInfo *info(nullptr);
+ if (m_nodeStack.empty()) {
+ node->mParent = pScene->mRootNode;
+ NodeChildMap::iterator it(m_nodeChildMap.find(node->mParent));
+ if (m_nodeChildMap.end() == it) {
+ info = new ChildInfo;
+ m_root = info;
+ m_nodeChildMap[node->mParent] = std::unique_ptr<ChildInfo>(info);
+ } else {
+ info = it->second.get();
+ }
+ info->m_children.push_back(node);
+ } else {
+ aiNode *parent(m_nodeStack.back());
+ ai_assert(nullptr != parent);
+ node->mParent = parent;
+ NodeChildMap::iterator it(m_nodeChildMap.find(node->mParent));
+ if (m_nodeChildMap.end() == it) {
+ info = new ChildInfo;
+ m_nodeChildMap[node->mParent] = std::unique_ptr<ChildInfo>(info);
+ } else {
+ info = it->second.get();
+ }
+ info->m_children.push_back(node);
+ }
+ m_nodeStack.push_back(node);
+}
+
+//------------------------------------------------------------------------------------------------
+aiNode *OpenGEXImporter::popNode() {
+ if (m_nodeStack.empty()) {
+ return nullptr;
+ }
+
+ aiNode *node(top());
+ m_nodeStack.pop_back();
+
+ return node;
+}
+
+//------------------------------------------------------------------------------------------------
+aiNode *OpenGEXImporter::top() const {
+ if (m_nodeStack.empty()) {
+ return nullptr;
+ }
+
+ return m_nodeStack.back();
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::clearNodeStack() {
+ m_nodeStack.clear();
+}
+
+//------------------------------------------------------------------------------------------------
+
+} // Namespace OpenGEX
+} // Namespace Assimp
+
+#endif // ASSIMP_BUILD_NO_OPENGEX_IMPORTER