summaryrefslogtreecommitdiff
path: root/libs/assimp/code/AssetLib/NFF/NFFLoader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/assimp/code/AssetLib/NFF/NFFLoader.cpp')
-rw-r--r--libs/assimp/code/AssetLib/NFF/NFFLoader.cpp1168
1 files changed, 0 insertions, 1168 deletions
diff --git a/libs/assimp/code/AssetLib/NFF/NFFLoader.cpp b/libs/assimp/code/AssetLib/NFF/NFFLoader.cpp
deleted file mode 100644
index 48271d1..0000000
--- a/libs/assimp/code/AssetLib/NFF/NFFLoader.cpp
+++ /dev/null
@@ -1,1168 +0,0 @@
-/*
----------------------------------------------------------------------------
-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.
----------------------------------------------------------------------------
-*/
-
-/** @file Implementation of the STL importer class */
-
-#ifndef ASSIMP_BUILD_NO_NFF_IMPORTER
-
-// internal headers
-#include "NFFLoader.h"
-#include <assimp/ParsingUtils.h>
-#include <assimp/RemoveComments.h>
-#include <assimp/StandardShapes.h>
-#include <assimp/fast_atof.h>
-#include <assimp/importerdesc.h>
-#include <assimp/qnan.h>
-#include <assimp/scene.h>
-#include <assimp/DefaultLogger.hpp>
-#include <assimp/IOSystem.hpp>
-#include <memory>
-
-using namespace Assimp;
-
-static const aiImporterDesc desc = {
- "Neutral File Format Importer",
- "",
- "",
- "",
- aiImporterFlags_SupportBinaryFlavour,
- 0,
- 0,
- 0,
- 0,
- "enff nff"
-};
-
-// ------------------------------------------------------------------------------------------------
-// Constructor to be privately used by Importer
-NFFImporter::NFFImporter() {}
-
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-NFFImporter::~NFFImporter() {}
-
-// ------------------------------------------------------------------------------------------------
-// Returns whether the class can handle the format of the given file.
-bool NFFImporter::CanRead(const std::string & pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
- return SimpleExtensionCheck(pFile, "nff", "enff");
-}
-
-// ------------------------------------------------------------------------------------------------
-// Get the list of all supported file extensions
-const aiImporterDesc *NFFImporter::GetInfo() const {
- return &desc;
-}
-
-// ------------------------------------------------------------------------------------------------
-#define AI_NFF_PARSE_FLOAT(f) \
- SkipSpaces(&sz); \
- if (!::IsLineEnd(*sz)) sz = fast_atoreal_move<ai_real>(sz, (ai_real &)f);
-
-// ------------------------------------------------------------------------------------------------
-#define AI_NFF_PARSE_TRIPLE(v) \
- AI_NFF_PARSE_FLOAT(v[0]) \
- AI_NFF_PARSE_FLOAT(v[1]) \
- AI_NFF_PARSE_FLOAT(v[2])
-
-// ------------------------------------------------------------------------------------------------
-#define AI_NFF_PARSE_SHAPE_INFORMATION() \
- aiVector3D center, radius(1.0f, get_qnan(), get_qnan()); \
- AI_NFF_PARSE_TRIPLE(center); \
- AI_NFF_PARSE_TRIPLE(radius); \
- if (is_qnan(radius.z)) radius.z = radius.x; \
- if (is_qnan(radius.y)) radius.y = radius.x; \
- curMesh.radius = radius; \
- curMesh.center = center;
-
-// ------------------------------------------------------------------------------------------------
-#define AI_NFF2_GET_NEXT_TOKEN() \
- do { \
- if (!GetNextLine(buffer, line)) { \
- ASSIMP_LOG_WARN("NFF2: Unexpected EOF, can't read next token"); \
- break; \
- } \
- SkipSpaces(line, &sz); \
- } while (IsLineEnd(*sz))
-
-// ------------------------------------------------------------------------------------------------
-// Loads the material table for the NFF2 file format from an external file
-void NFFImporter::LoadNFF2MaterialTable(std::vector<ShadingInfo> &output,
- const std::string &path, IOSystem *pIOHandler) {
- std::unique_ptr<IOStream> file(pIOHandler->Open(path, "rb"));
-
- // Check whether we can read from the file
- if (!file.get()) {
- ASSIMP_LOG_ERROR("NFF2: Unable to open material library ", path, ".");
- return;
- }
-
- // get the size of the file
- const unsigned int m = (unsigned int)file->FileSize();
-
- // allocate storage and copy the contents of the file to a memory buffer
- // (terminate it with zero)
- std::vector<char> mBuffer2(m + 1);
- TextFileToBuffer(file.get(), mBuffer2);
- const char *buffer = &mBuffer2[0];
-
- // First of all: remove all comments from the file
- CommentRemover::RemoveLineComments("//", &mBuffer2[0]);
-
- // The file should start with the magic sequence "mat"
- if (!TokenMatch(buffer, "mat", 3)) {
- ASSIMP_LOG_ERROR("NFF2: Not a valid material library ", path, ".");
- return;
- }
-
- ShadingInfo *curShader = nullptr;
-
- // No read the file line per line
- char line[4096];
- const char *sz;
- while (GetNextLine(buffer, line)) {
- SkipSpaces(line, &sz);
-
- // 'version' defines the version of the file format
- if (TokenMatch(sz, "version", 7)) {
- ASSIMP_LOG_INFO("NFF (Sense8) material library file format: ", std::string(sz));
- }
- // 'matdef' starts a new material in the file
- else if (TokenMatch(sz, "matdef", 6)) {
- // add a new material to the list
- output.push_back(ShadingInfo());
- curShader = &output.back();
-
- // parse the name of the material
- } else if (!TokenMatch(sz, "valid", 5)) {
- // check whether we have an active material at the moment
- if (!IsLineEnd(*sz)) {
- if (!curShader) {
- ASSIMP_LOG_ERROR("NFF2 material library: Found element ", sz, "but there is no active material");
- continue;
- }
- } else
- continue;
-
- // now read the material property and determine its type
- aiColor3D c;
- if (TokenMatch(sz, "ambient", 7)) {
- AI_NFF_PARSE_TRIPLE(c);
- curShader->ambient = c;
- } else if (TokenMatch(sz, "diffuse", 7) || TokenMatch(sz, "ambientdiffuse", 14) /* correct? */) {
- AI_NFF_PARSE_TRIPLE(c);
- curShader->diffuse = curShader->ambient = c;
- } else if (TokenMatch(sz, "specular", 8)) {
- AI_NFF_PARSE_TRIPLE(c);
- curShader->specular = c;
- } else if (TokenMatch(sz, "emission", 8)) {
- AI_NFF_PARSE_TRIPLE(c);
- curShader->emissive = c;
- } else if (TokenMatch(sz, "shininess", 9)) {
- AI_NFF_PARSE_FLOAT(curShader->shininess);
- } else if (TokenMatch(sz, "opacity", 7)) {
- AI_NFF_PARSE_FLOAT(curShader->opacity);
- }
- }
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-// Imports the given file into the given scene structure.
-void NFFImporter::InternReadFile(const std::string &pFile,
- aiScene *pScene, IOSystem *pIOHandler) {
- std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
-
- // Check whether we can read from the file
- if (!file.get())
- throw DeadlyImportError("Failed to open NFF file ", pFile, ".");
-
- // allocate storage and copy the contents of the file to a memory buffer
- // (terminate it with zero)
- std::vector<char> mBuffer2;
- TextFileToBuffer(file.get(), mBuffer2);
- const char *buffer = &mBuffer2[0];
-
- // mesh arrays - separate here to make the handling of the pointers below easier.
- std::vector<MeshInfo> meshes;
- std::vector<MeshInfo> meshesWithNormals;
- std::vector<MeshInfo> meshesWithUVCoords;
- std::vector<MeshInfo> meshesLocked;
-
- char line[4096];
- const char *sz;
-
- // camera parameters
- aiVector3D camPos, camUp(0.f, 1.f, 0.f), camLookAt(0.f, 0.f, 1.f);
- ai_real angle = 45.f;
- aiVector2D resolution;
-
- bool hasCam = false;
-
- MeshInfo *currentMeshWithNormals = nullptr;
- MeshInfo *currentMesh = nullptr;
- MeshInfo *currentMeshWithUVCoords = nullptr;
-
- ShadingInfo s; // current material info
-
- // degree of tessellation
- unsigned int iTesselation = 4;
-
- // some temporary variables we need to parse the file
- unsigned int sphere = 0,
- cylinder = 0,
- cone = 0,
- numNamed = 0,
- dodecahedron = 0,
- octahedron = 0,
- tetrahedron = 0,
- hexahedron = 0;
-
- // lights imported from the file
- std::vector<Light> lights;
-
- // check whether this is the NFF2 file format
- if (TokenMatch(buffer, "nff", 3)) {
- const ai_real qnan = get_qnan();
- const aiColor4D cQNAN = aiColor4D(qnan, 0.f, 0.f, 1.f);
- const aiVector3D vQNAN = aiVector3D(qnan, 0.f, 0.f);
-
- // another NFF file format ... just a raw parser has been implemented
- // no support for further details, I don't think it is worth the effort
- // http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/nff/nff2.html
- // http://www.netghost.narod.ru/gff/graphics/summary/sense8.htm
-
- // First of all: remove all comments from the file
- CommentRemover::RemoveLineComments("//", &mBuffer2[0]);
-
- while (GetNextLine(buffer, line)) {
- SkipSpaces(line, &sz);
- if (TokenMatch(sz, "version", 7)) {
- ASSIMP_LOG_INFO("NFF (Sense8) file format: ", sz);
- } else if (TokenMatch(sz, "viewpos", 7)) {
- AI_NFF_PARSE_TRIPLE(camPos);
- hasCam = true;
- } else if (TokenMatch(sz, "viewdir", 7)) {
- AI_NFF_PARSE_TRIPLE(camLookAt);
- hasCam = true;
- }
- // This starts a new object section
- else if (!IsSpaceOrNewLine(*sz)) {
- unsigned int subMeshIdx = 0;
-
- // read the name of the object, skip all spaces
- // at the end of it.
- const char *sz3 = sz;
- while (!IsSpaceOrNewLine(*sz))
- ++sz;
- std::string objectName = std::string(sz3, (unsigned int)(sz - sz3));
-
- const unsigned int objStart = (unsigned int)meshes.size();
-
- // There could be a material table in a separate file
- std::vector<ShadingInfo> materialTable;
- while (true) {
- AI_NFF2_GET_NEXT_TOKEN();
-
- // material table - an external file
- if (TokenMatch(sz, "mtable", 6)) {
- SkipSpaces(&sz);
- sz3 = sz;
- while (!IsSpaceOrNewLine(*sz))
- ++sz;
- const unsigned int diff = (unsigned int)(sz - sz3);
- if (!diff)
- ASSIMP_LOG_WARN("NFF2: Found empty mtable token");
- else {
- // The material table has the file extension .mat.
- // If it is not there, we need to append it
- std::string path = std::string(sz3, diff);
- if (std::string::npos == path.find_last_of(".mat")) {
- path.append(".mat");
- }
-
- // Now extract the working directory from the path to
- // this file and append the material library filename
- // to it.
- std::string::size_type sepPos;
- if ((std::string::npos == (sepPos = path.find_last_of('\\')) || !sepPos) &&
- (std::string::npos == (sepPos = path.find_last_of('/')) || !sepPos)) {
- sepPos = pFile.find_last_of('\\');
- if (std::string::npos == sepPos) {
- sepPos = pFile.find_last_of('/');
- }
- if (std::string::npos != sepPos) {
- path = pFile.substr(0, sepPos + 1) + path;
- }
- }
- LoadNFF2MaterialTable(materialTable, path, pIOHandler);
- }
- } else
- break;
- }
-
- // read the numbr of vertices
- unsigned int num = ::strtoul10(sz, &sz);
-
- // temporary storage
- std::vector<aiColor4D> tempColors;
- std::vector<aiVector3D> tempPositions, tempTextureCoords, tempNormals;
-
- bool hasNormals = false, hasUVs = false, hasColor = false;
-
- tempPositions.reserve(num);
- tempColors.reserve(num);
- tempNormals.reserve(num);
- tempTextureCoords.reserve(num);
- for (unsigned int i = 0; i < num; ++i) {
- AI_NFF2_GET_NEXT_TOKEN();
- aiVector3D v;
- AI_NFF_PARSE_TRIPLE(v);
- tempPositions.push_back(v);
-
- // parse all other attributes in the line
- while (true) {
- SkipSpaces(&sz);
- if (IsLineEnd(*sz)) break;
-
- // color definition
- if (TokenMatch(sz, "0x", 2)) {
- hasColor = true;
- unsigned int numIdx = ::strtoul16(sz, &sz);
- aiColor4D clr;
- clr.a = 1.f;
-
- // 0xRRGGBB
- clr.r = ((numIdx >> 16u) & 0xff) / 255.f;
- clr.g = ((numIdx >> 8u) & 0xff) / 255.f;
- clr.b = ((numIdx)&0xff) / 255.f;
- tempColors.push_back(clr);
- }
- // normal vector
- else if (TokenMatch(sz, "norm", 4)) {
- hasNormals = true;
- AI_NFF_PARSE_TRIPLE(v);
- tempNormals.push_back(v);
- }
- // UV coordinate
- else if (TokenMatch(sz, "uv", 2)) {
- hasUVs = true;
- AI_NFF_PARSE_FLOAT(v.x);
- AI_NFF_PARSE_FLOAT(v.y);
- v.z = 0.f;
- tempTextureCoords.push_back(v);
- }
- }
-
- // fill in dummies for all attributes that have not been set
- if (tempNormals.size() != tempPositions.size())
- tempNormals.push_back(vQNAN);
-
- if (tempTextureCoords.size() != tempPositions.size())
- tempTextureCoords.push_back(vQNAN);
-
- if (tempColors.size() != tempPositions.size())
- tempColors.push_back(cQNAN);
- }
-
- AI_NFF2_GET_NEXT_TOKEN();
- if (!num) throw DeadlyImportError("NFF2: There are zero vertices");
- num = ::strtoul10(sz, &sz);
-
- std::vector<unsigned int> tempIdx;
- tempIdx.reserve(10);
- for (unsigned int i = 0; i < num; ++i) {
- AI_NFF2_GET_NEXT_TOKEN();
- SkipSpaces(line, &sz);
- unsigned int numIdx = ::strtoul10(sz, &sz);
-
- // read all faces indices
- if (numIdx) {
- // mesh.faces.push_back(numIdx);
- // tempIdx.erase(tempIdx.begin(),tempIdx.end());
- tempIdx.resize(numIdx);
-
- for (unsigned int a = 0; a < numIdx; ++a) {
- SkipSpaces(sz, &sz);
- unsigned int m = ::strtoul10(sz, &sz);
- if (m >= (unsigned int)tempPositions.size()) {
- ASSIMP_LOG_ERROR("NFF2: Vertex index overflow");
- m = 0;
- }
- // mesh.vertices.push_back (tempPositions[idx]);
- tempIdx[a] = m;
- }
- }
-
- // build a temporary shader object for the face.
- ShadingInfo shader;
- unsigned int matIdx = 0;
-
- // white material color - we have vertex colors
- shader.color = aiColor3D(1.f, 1.f, 1.f);
- aiColor4D c = aiColor4D(1.f, 1.f, 1.f, 1.f);
- while (true) {
- SkipSpaces(sz, &sz);
- if (IsLineEnd(*sz)) break;
-
- // per-polygon colors
- if (TokenMatch(sz, "0x", 2)) {
- hasColor = true;
- const char *sz2 = sz;
- numIdx = ::strtoul16(sz, &sz);
- const unsigned int diff = (unsigned int)(sz - sz2);
-
- // 0xRRGGBB
- if (diff > 3) {
- c.r = ((numIdx >> 16u) & 0xff) / 255.f;
- c.g = ((numIdx >> 8u) & 0xff) / 255.f;
- c.b = ((numIdx)&0xff) / 255.f;
- }
- // 0xRGB
- else {
- c.r = ((numIdx >> 8u) & 0xf) / 16.f;
- c.g = ((numIdx >> 4u) & 0xf) / 16.f;
- c.b = ((numIdx)&0xf) / 16.f;
- }
- }
- // TODO - implement texture mapping here
-#if 0
- // mirror vertex texture coordinate?
- else if (TokenMatch(sz,"mirror",6))
- {
- }
- // texture coordinate scaling
- else if (TokenMatch(sz,"scale",5))
- {
- }
- // texture coordinate translation
- else if (TokenMatch(sz,"trans",5))
- {
- }
- // texture coordinate rotation angle
- else if (TokenMatch(sz,"rot",3))
- {
- }
-#endif
-
- // texture file name for this polygon + mapping information
- else if ('_' == sz[0]) {
- // get mapping information
- switch (sz[1]) {
- case 'v':
- case 'V':
-
- shader.shaded = false;
- break;
-
- case 't':
- case 'T':
- case 'u':
- case 'U':
-
- ASSIMP_LOG_WARN("Unsupported NFF2 texture attribute: trans");
- };
- if (!sz[1] || '_' != sz[2]) {
- ASSIMP_LOG_WARN("NFF2: Expected underscore after texture attributes");
- continue;
- }
- const char *sz2 = sz + 3;
- while (!IsSpaceOrNewLine(*sz))
- ++sz;
- const unsigned int diff = (unsigned int)(sz - sz2);
- if (diff) shader.texFile = std::string(sz2, diff);
- }
-
- // Two-sided material?
- else if (TokenMatch(sz, "both", 4)) {
- shader.twoSided = true;
- }
-
- // Material ID?
- else if (!materialTable.empty() && TokenMatch(sz, "matid", 5)) {
- SkipSpaces(&sz);
- matIdx = ::strtoul10(sz, &sz);
- if (matIdx >= materialTable.size()) {
- ASSIMP_LOG_ERROR("NFF2: Material index overflow.");
- matIdx = 0;
- }
-
- // now combine our current shader with the shader we
- // read from the material table.
- ShadingInfo &mat = materialTable[matIdx];
- shader.ambient = mat.ambient;
- shader.diffuse = mat.diffuse;
- shader.emissive = mat.emissive;
- shader.opacity = mat.opacity;
- shader.specular = mat.specular;
- shader.shininess = mat.shininess;
- } else
- SkipToken(sz);
- }
-
- // search the list of all shaders we have for this object whether
- // there is an identical one. In this case, we append our mesh
- // data to it.
- MeshInfo *mesh = nullptr;
- for (std::vector<MeshInfo>::iterator it = meshes.begin() + objStart, end = meshes.end();
- it != end; ++it) {
- if ((*it).shader == shader && (*it).matIndex == matIdx) {
- // we have one, we can append our data to it
- mesh = &(*it);
- }
- }
- if (!mesh) {
- meshes.push_back(MeshInfo(PatchType_Simple, false));
- mesh = &meshes.back();
- mesh->matIndex = matIdx;
-
- // We need to add a new mesh to the list. We assign
- // an unique name to it to make sure the scene will
- // pass the validation step for the moment.
- // TODO: fix naming of objects in the scenegraph later
- if (objectName.length()) {
- ::strcpy(mesh->name, objectName.c_str());
- ASSIMP_itoa10(&mesh->name[objectName.length()], 30, subMeshIdx++);
- }
-
- // copy the shader to the mesh.
- mesh->shader = shader;
- }
-
- // fill the mesh with data
- if (!tempIdx.empty()) {
- mesh->faces.push_back((unsigned int)tempIdx.size());
- for (std::vector<unsigned int>::const_iterator it = tempIdx.begin(), end = tempIdx.end();
- it != end; ++it) {
- unsigned int m = *it;
-
- // copy colors -vertex color specifications override polygon color specifications
- if (hasColor) {
- const aiColor4D &clr = tempColors[m];
- mesh->colors.push_back((is_qnan(clr.r) ? c : clr));
- }
-
- // positions should always be there
- mesh->vertices.push_back(tempPositions[m]);
-
- // copy normal vectors
- if (hasNormals)
- mesh->normals.push_back(tempNormals[m]);
-
- // copy texture coordinates
- if (hasUVs)
- mesh->uvs.push_back(tempTextureCoords[m]);
- }
- }
- }
- if (!num) throw DeadlyImportError("NFF2: There are zero faces");
- }
- }
- camLookAt = camLookAt + camPos;
- } else // "Normal" Neutral file format that is quite more common
- {
- while (GetNextLine(buffer, line)) {
- sz = line;
- if ('p' == line[0] || TokenMatch(sz, "tpp", 3)) {
- MeshInfo *out = nullptr;
-
- // 'tpp' - texture polygon patch primitive
- if ('t' == line[0]) {
- currentMeshWithUVCoords = nullptr;
- for (auto &mesh : meshesWithUVCoords) {
- if (mesh.shader == s) {
- currentMeshWithUVCoords = &mesh;
- break;
- }
- }
-
- if (!currentMeshWithUVCoords) {
- meshesWithUVCoords.push_back(MeshInfo(PatchType_UVAndNormals));
- currentMeshWithUVCoords = &meshesWithUVCoords.back();
- currentMeshWithUVCoords->shader = s;
- }
- out = currentMeshWithUVCoords;
- }
- // 'pp' - polygon patch primitive
- else if ('p' == line[1]) {
- currentMeshWithNormals = nullptr;
- for (auto &mesh : meshesWithNormals) {
- if (mesh.shader == s) {
- currentMeshWithNormals = &mesh;
- break;
- }
- }
-
- if (!currentMeshWithNormals) {
- meshesWithNormals.push_back(MeshInfo(PatchType_Normals));
- currentMeshWithNormals = &meshesWithNormals.back();
- currentMeshWithNormals->shader = s;
- }
- sz = &line[2];
- out = currentMeshWithNormals;
- }
- // 'p' - polygon primitive
- else {
- currentMesh = nullptr;
- for (auto &mesh : meshes) {
- if (mesh.shader == s) {
- currentMesh = &mesh;
- break;
- }
- }
-
- if (!currentMesh) {
- meshes.push_back(MeshInfo(PatchType_Simple));
- currentMesh = &meshes.back();
- currentMesh->shader = s;
- }
- sz = &line[1];
- out = currentMesh;
- }
- SkipSpaces(sz, &sz);
- unsigned int m = strtoul10(sz);
-
- // ---- flip the face order
- out->vertices.resize(out->vertices.size() + m);
- if (out != currentMesh) {
- out->normals.resize(out->vertices.size());
- }
- if (out == currentMeshWithUVCoords) {
- out->uvs.resize(out->vertices.size());
- }
- for (unsigned int n = 0; n < m; ++n) {
- if (!GetNextLine(buffer, line)) {
- ASSIMP_LOG_ERROR("NFF: Unexpected EOF was encountered. Patch definition incomplete");
- continue;
- }
-
- aiVector3D v;
- sz = &line[0];
- AI_NFF_PARSE_TRIPLE(v);
- out->vertices[out->vertices.size() - n - 1] = v;
-
- if (out != currentMesh) {
- AI_NFF_PARSE_TRIPLE(v);
- out->normals[out->vertices.size() - n - 1] = v;
- }
- if (out == currentMeshWithUVCoords) {
- // FIX: in one test file this wraps over multiple lines
- SkipSpaces(&sz);
- if (IsLineEnd(*sz)) {
- GetNextLine(buffer, line);
- sz = line;
- }
- AI_NFF_PARSE_FLOAT(v.x);
- SkipSpaces(&sz);
- if (IsLineEnd(*sz)) {
- GetNextLine(buffer, line);
- sz = line;
- }
- AI_NFF_PARSE_FLOAT(v.y);
- v.y = 1.f - v.y;
- out->uvs[out->vertices.size() - n - 1] = v;
- }
- }
- out->faces.push_back(m);
- }
- // 'f' - shading information block
- else if (TokenMatch(sz, "f", 1)) {
- ai_real d;
-
- // read the RGB colors
- AI_NFF_PARSE_TRIPLE(s.color);
-
- // read the other properties
- AI_NFF_PARSE_FLOAT(s.diffuse.r);
- AI_NFF_PARSE_FLOAT(s.specular.r);
- AI_NFF_PARSE_FLOAT(d); // skip shininess and transmittance
- AI_NFF_PARSE_FLOAT(d);
- AI_NFF_PARSE_FLOAT(s.refracti);
-
- // NFF2 uses full colors here so we need to use them too
- // although NFF uses simple scaling factors
- s.diffuse.g = s.diffuse.b = s.diffuse.r;
- s.specular.g = s.specular.b = s.specular.r;
-
- // if the next one is NOT a number we assume it is a texture file name
- // this feature is used by some NFF files on the internet and it has
- // been implemented as it can be really useful
- SkipSpaces(&sz);
- if (!IsNumeric(*sz)) {
- // TODO: Support full file names with spaces and quotation marks ...
- const char *p = sz;
- while (!IsSpaceOrNewLine(*sz))
- ++sz;
-
- unsigned int diff = (unsigned int)(sz - p);
- if (diff) {
- s.texFile = std::string(p, diff);
- }
- } else {
- AI_NFF_PARSE_FLOAT(s.ambient); // optional
- }
- }
- // 'shader' - other way to specify a texture
- else if (TokenMatch(sz, "shader", 6)) {
- SkipSpaces(&sz);
- const char *old = sz;
- while (!IsSpaceOrNewLine(*sz))
- ++sz;
- s.texFile = std::string(old, (uintptr_t)sz - (uintptr_t)old);
- }
- // 'l' - light source
- else if (TokenMatch(sz, "l", 1)) {
- lights.push_back(Light());
- Light &light = lights.back();
-
- AI_NFF_PARSE_TRIPLE(light.position);
- AI_NFF_PARSE_FLOAT(light.intensity);
- AI_NFF_PARSE_TRIPLE(light.color);
- }
- // 's' - sphere
- else if (TokenMatch(sz, "s", 1)) {
- meshesLocked.push_back(MeshInfo(PatchType_Simple, true));
- MeshInfo &curMesh = meshesLocked.back();
- curMesh.shader = s;
- curMesh.shader.mapping = aiTextureMapping_SPHERE;
-
- AI_NFF_PARSE_SHAPE_INFORMATION();
-
- // we don't need scaling or translation here - we do it in the node's transform
- StandardShapes::MakeSphere(iTesselation, curMesh.vertices);
- curMesh.faces.resize(curMesh.vertices.size() / 3, 3);
-
- // generate a name for the mesh
- ::ai_snprintf(curMesh.name, MeshInfo::MaxNameLen, "sphere_%i", sphere++);
- }
- // 'dod' - dodecahedron
- else if (TokenMatch(sz, "dod", 3)) {
- meshesLocked.push_back(MeshInfo(PatchType_Simple, true));
- MeshInfo &curMesh = meshesLocked.back();
- curMesh.shader = s;
- curMesh.shader.mapping = aiTextureMapping_SPHERE;
-
- AI_NFF_PARSE_SHAPE_INFORMATION();
-
- // we don't need scaling or translation here - we do it in the node's transform
- StandardShapes::MakeDodecahedron(curMesh.vertices);
- curMesh.faces.resize(curMesh.vertices.size() / 3, 3);
-
- // generate a name for the mesh
- ::ai_snprintf(curMesh.name, 128, "dodecahedron_%i", dodecahedron++);
- }
-
- // 'oct' - octahedron
- else if (TokenMatch(sz, "oct", 3)) {
- meshesLocked.push_back(MeshInfo(PatchType_Simple, true));
- MeshInfo &curMesh = meshesLocked.back();
- curMesh.shader = s;
- curMesh.shader.mapping = aiTextureMapping_SPHERE;
-
- AI_NFF_PARSE_SHAPE_INFORMATION();
-
- // we don't need scaling or translation here - we do it in the node's transform
- StandardShapes::MakeOctahedron(curMesh.vertices);
- curMesh.faces.resize(curMesh.vertices.size() / 3, 3);
-
- // generate a name for the mesh
- ::ai_snprintf(curMesh.name, MeshInfo::MaxNameLen, "octahedron_%i", octahedron++);
- }
-
- // 'tet' - tetrahedron
- else if (TokenMatch(sz, "tet", 3)) {
- meshesLocked.push_back(MeshInfo(PatchType_Simple, true));
- MeshInfo &curMesh = meshesLocked.back();
- curMesh.shader = s;
- curMesh.shader.mapping = aiTextureMapping_SPHERE;
-
- AI_NFF_PARSE_SHAPE_INFORMATION();
-
- // we don't need scaling or translation here - we do it in the node's transform
- StandardShapes::MakeTetrahedron(curMesh.vertices);
- curMesh.faces.resize(curMesh.vertices.size() / 3, 3);
-
- // generate a name for the mesh
- ::ai_snprintf(curMesh.name, MeshInfo::MaxNameLen, "tetrahedron_%i", tetrahedron++);
- }
-
- // 'hex' - hexahedron
- else if (TokenMatch(sz, "hex", 3)) {
- meshesLocked.push_back(MeshInfo(PatchType_Simple, true));
- MeshInfo &curMesh = meshesLocked.back();
- curMesh.shader = s;
- curMesh.shader.mapping = aiTextureMapping_BOX;
-
- AI_NFF_PARSE_SHAPE_INFORMATION();
-
- // we don't need scaling or translation here - we do it in the node's transform
- StandardShapes::MakeHexahedron(curMesh.vertices);
- curMesh.faces.resize(curMesh.vertices.size() / 3, 3);
-
- // generate a name for the mesh
- ::ai_snprintf(curMesh.name, MeshInfo::MaxNameLen, "hexahedron_%i", hexahedron++);
- }
- // 'c' - cone
- else if (TokenMatch(sz, "c", 1)) {
- meshesLocked.push_back(MeshInfo(PatchType_Simple, true));
- MeshInfo &curMesh = meshesLocked.back();
- curMesh.shader = s;
- curMesh.shader.mapping = aiTextureMapping_CYLINDER;
-
- if (!GetNextLine(buffer, line)) {
- ASSIMP_LOG_ERROR("NFF: Unexpected end of file (cone definition not complete)");
- break;
- }
- sz = line;
-
- // read the two center points and the respective radii
- aiVector3D center1, center2;
- ai_real radius1 = 0.f, radius2 = 0.f;
- AI_NFF_PARSE_TRIPLE(center1);
- AI_NFF_PARSE_FLOAT(radius1);
-
- if (!GetNextLine(buffer, line)) {
- ASSIMP_LOG_ERROR("NFF: Unexpected end of file (cone definition not complete)");
- break;
- }
- sz = line;
-
- AI_NFF_PARSE_TRIPLE(center2);
- AI_NFF_PARSE_FLOAT(radius2);
-
- // compute the center point of the cone/cylinder -
- // it is its local transformation origin
- curMesh.dir = center2 - center1;
- curMesh.center = center1 + curMesh.dir / (ai_real)2.0;
-
- ai_real f;
- if ((f = curMesh.dir.Length()) < 10e-3f) {
- ASSIMP_LOG_ERROR("NFF: Cone height is close to zero");
- continue;
- }
- curMesh.dir /= f; // normalize
-
- // generate the cone - it consists of simple triangles
- StandardShapes::MakeCone(f, radius1, radius2,
- integer_pow(4, iTesselation), curMesh.vertices);
-
- // MakeCone() returns tris
- curMesh.faces.resize(curMesh.vertices.size() / 3, 3);
-
- // generate a name for the mesh. 'cone' if it a cone,
- // 'cylinder' if it is a cylinder. Funny, isn't it?
- if (radius1 != radius2) {
- ::ai_snprintf(curMesh.name, MeshInfo::MaxNameLen, "cone_%i", cone++);
- } else {
- ::ai_snprintf(curMesh.name, MeshInfo::MaxNameLen, "cylinder_%i", cylinder++);
- }
- }
- // 'tess' - tessellation
- else if (TokenMatch(sz, "tess", 4)) {
- SkipSpaces(&sz);
- iTesselation = strtoul10(sz);
- }
- // 'from' - camera position
- else if (TokenMatch(sz, "from", 4)) {
- AI_NFF_PARSE_TRIPLE(camPos);
- hasCam = true;
- }
- // 'at' - camera look-at vector
- else if (TokenMatch(sz, "at", 2)) {
- AI_NFF_PARSE_TRIPLE(camLookAt);
- hasCam = true;
- }
- // 'up' - camera up vector
- else if (TokenMatch(sz, "up", 2)) {
- AI_NFF_PARSE_TRIPLE(camUp);
- hasCam = true;
- }
- // 'angle' - (half?) camera field of view
- else if (TokenMatch(sz, "angle", 5)) {
- AI_NFF_PARSE_FLOAT(angle);
- hasCam = true;
- }
- // 'resolution' - used to compute the screen aspect
- else if (TokenMatch(sz, "resolution", 10)) {
- AI_NFF_PARSE_FLOAT(resolution.x);
- AI_NFF_PARSE_FLOAT(resolution.y);
- hasCam = true;
- }
- // 'pb' - bezier patch. Not supported yet
- else if (TokenMatch(sz, "pb", 2)) {
- ASSIMP_LOG_ERROR("NFF: Encountered unsupported ID: bezier patch");
- }
- // 'pn' - NURBS. Not supported yet
- else if (TokenMatch(sz, "pn", 2) || TokenMatch(sz, "pnn", 3)) {
- ASSIMP_LOG_ERROR("NFF: Encountered unsupported ID: NURBS");
- }
- // '' - comment
- else if ('#' == line[0]) {
- const char *space;
- SkipSpaces(&line[1], &space);
- if (!IsLineEnd(*space)) {
- ASSIMP_LOG_INFO(space);
- }
- }
- }
- }
-
- // copy all arrays into one large
- meshes.reserve(meshes.size() + meshesLocked.size() + meshesWithNormals.size() + meshesWithUVCoords.size());
- meshes.insert(meshes.end(), meshesLocked.begin(), meshesLocked.end());
- meshes.insert(meshes.end(), meshesWithNormals.begin(), meshesWithNormals.end());
- meshes.insert(meshes.end(), meshesWithUVCoords.begin(), meshesWithUVCoords.end());
-
- // now generate output meshes. first find out how many meshes we'll need
- std::vector<MeshInfo>::const_iterator it = meshes.begin(), end = meshes.end();
- for (; it != end; ++it) {
- if (!(*it).faces.empty()) {
- ++pScene->mNumMeshes;
- if ((*it).name[0]) ++numNamed;
- }
- }
-
- // generate a dummy root node - assign all unnamed elements such
- // as polygons and polygon patches to the root node and generate
- // sub nodes for named objects such as spheres and cones.
- aiNode *const root = new aiNode();
- root->mName.Set("<NFF_Root>");
- root->mNumChildren = numNamed + (hasCam ? 1 : 0) + (unsigned int)lights.size();
- root->mNumMeshes = pScene->mNumMeshes - numNamed;
-
- aiNode **ppcChildren = nullptr;
- unsigned int *pMeshes = nullptr;
- if (root->mNumMeshes)
- pMeshes = root->mMeshes = new unsigned int[root->mNumMeshes];
- if (root->mNumChildren)
- ppcChildren = root->mChildren = new aiNode *[root->mNumChildren];
-
- // generate the camera
- if (hasCam) {
- ai_assert(ppcChildren);
- aiNode *nd = new aiNode();
- *ppcChildren = nd;
- nd->mName.Set("<NFF_Camera>");
- nd->mParent = root;
-
- // allocate the camera in the scene
- pScene->mNumCameras = 1;
- pScene->mCameras = new aiCamera *[1];
- aiCamera *c = pScene->mCameras[0] = new aiCamera;
-
- c->mName = nd->mName; // make sure the names are identical
- c->mHorizontalFOV = AI_DEG_TO_RAD(angle);
- c->mLookAt = camLookAt - camPos;
- c->mPosition = camPos;
- c->mUp = camUp;
-
- // If the resolution is not specified in the file, we
- // need to set 1.0 as aspect.
- c->mAspect = (!resolution.y ? 0.f : resolution.x / resolution.y);
- ++ppcChildren;
- }
-
- // generate light sources
- if (!lights.empty()) {
- ai_assert(ppcChildren);
- pScene->mNumLights = (unsigned int)lights.size();
- pScene->mLights = new aiLight *[pScene->mNumLights];
- for (unsigned int i = 0; i < pScene->mNumLights; ++i, ++ppcChildren) {
- const Light &l = lights[i];
-
- aiNode *nd = new aiNode();
- *ppcChildren = nd;
- nd->mParent = root;
-
- nd->mName.length = ::ai_snprintf(nd->mName.data, 1024, "<NFF_Light%u>", i);
-
- // allocate the light in the scene data structure
- aiLight *out = pScene->mLights[i] = new aiLight();
- out->mName = nd->mName; // make sure the names are identical
- out->mType = aiLightSource_POINT;
- out->mColorDiffuse = out->mColorSpecular = l.color * l.intensity;
- out->mPosition = l.position;
- }
- }
-
- if (!pScene->mNumMeshes) throw DeadlyImportError("NFF: No meshes loaded");
- pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
- pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials = pScene->mNumMeshes];
- unsigned int m = 0;
- for (it = meshes.begin(); it != end; ++it) {
- if ((*it).faces.empty()) continue;
-
- const MeshInfo &src = *it;
- aiMesh *const mesh = pScene->mMeshes[m] = new aiMesh();
- mesh->mNumVertices = (unsigned int)src.vertices.size();
- mesh->mNumFaces = (unsigned int)src.faces.size();
-
- // Generate sub nodes for named meshes
- if (src.name[0] && nullptr != ppcChildren) {
- aiNode *const node = *ppcChildren = new aiNode();
- node->mParent = root;
- node->mNumMeshes = 1;
- node->mMeshes = new unsigned int[1];
- node->mMeshes[0] = m;
- node->mName.Set(src.name);
-
- // setup the transformation matrix of the node
- aiMatrix4x4::FromToMatrix(aiVector3D(0.f, 1.f, 0.f),
- src.dir, node->mTransformation);
-
- aiMatrix4x4 &mat = node->mTransformation;
- mat.a1 *= src.radius.x;
- mat.b1 *= src.radius.x;
- mat.c1 *= src.radius.x;
- mat.a2 *= src.radius.y;
- mat.b2 *= src.radius.y;
- mat.c2 *= src.radius.y;
- mat.a3 *= src.radius.z;
- mat.b3 *= src.radius.z;
- mat.c3 *= src.radius.z;
- mat.a4 = src.center.x;
- mat.b4 = src.center.y;
- mat.c4 = src.center.z;
-
- ++ppcChildren;
- } else {
- *pMeshes++ = m;
- }
-
- // copy vertex positions
- mesh->mVertices = new aiVector3D[mesh->mNumVertices];
- ::memcpy(mesh->mVertices, &src.vertices[0],
- sizeof(aiVector3D) * mesh->mNumVertices);
-
- // NFF2: there could be vertex colors
- if (!src.colors.empty()) {
- ai_assert(src.colors.size() == src.vertices.size());
-
- // copy vertex colors
- mesh->mColors[0] = new aiColor4D[mesh->mNumVertices];
- ::memcpy(mesh->mColors[0], &src.colors[0],
- sizeof(aiColor4D) * mesh->mNumVertices);
- }
-
- if (!src.normals.empty()) {
- ai_assert(src.normals.size() == src.vertices.size());
-
- // copy normal vectors
- mesh->mNormals = new aiVector3D[mesh->mNumVertices];
- ::memcpy(mesh->mNormals, &src.normals[0],
- sizeof(aiVector3D) * mesh->mNumVertices);
- }
-
- if (!src.uvs.empty()) {
- ai_assert(src.uvs.size() == src.vertices.size());
-
- // copy texture coordinates
- mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
- ::memcpy(mesh->mTextureCoords[0], &src.uvs[0],
- sizeof(aiVector3D) * mesh->mNumVertices);
- }
-
- // generate faces
- unsigned int p = 0;
- aiFace *pFace = mesh->mFaces = new aiFace[mesh->mNumFaces];
- for (std::vector<unsigned int>::const_iterator it2 = src.faces.begin(),
- end2 = src.faces.end();
- it2 != end2; ++it2, ++pFace) {
- pFace->mIndices = new unsigned int[pFace->mNumIndices = *it2];
- for (unsigned int o = 0; o < pFace->mNumIndices; ++o)
- pFace->mIndices[o] = p++;
- }
-
- // generate a material for the mesh
- aiMaterial *pcMat = (aiMaterial *)(pScene->mMaterials[m] = new aiMaterial());
-
- mesh->mMaterialIndex = m++;
-
- aiString matName;
- matName.Set(AI_DEFAULT_MATERIAL_NAME);
- pcMat->AddProperty(&matName, AI_MATKEY_NAME);
-
- // FIX: Ignore diffuse == 0
- aiColor3D c = src.shader.color * (src.shader.diffuse.r ? src.shader.diffuse : aiColor3D(1.f, 1.f, 1.f));
- pcMat->AddProperty(&c, 1, AI_MATKEY_COLOR_DIFFUSE);
- c = src.shader.color * src.shader.specular;
- pcMat->AddProperty(&c, 1, AI_MATKEY_COLOR_SPECULAR);
-
- // NFF2 - default values for NFF
- pcMat->AddProperty(&src.shader.ambient, 1, AI_MATKEY_COLOR_AMBIENT);
- pcMat->AddProperty(&src.shader.emissive, 1, AI_MATKEY_COLOR_EMISSIVE);
- pcMat->AddProperty(&src.shader.opacity, 1, AI_MATKEY_OPACITY);
-
- // setup the first texture layer, if existing
- if (src.shader.texFile.length()) {
- matName.Set(src.shader.texFile);
- pcMat->AddProperty(&matName, AI_MATKEY_TEXTURE_DIFFUSE(0));
-
- if (aiTextureMapping_UV != src.shader.mapping) {
-
- aiVector3D v(0.f, -1.f, 0.f);
- pcMat->AddProperty(&v, 1, AI_MATKEY_TEXMAP_AXIS_DIFFUSE(0));
- pcMat->AddProperty((int *)&src.shader.mapping, 1, AI_MATKEY_MAPPING_DIFFUSE(0));
- }
- }
-
- // setup the name of the material
- if (src.shader.name.length()) {
- matName.Set(src.shader.texFile);
- pcMat->AddProperty(&matName, AI_MATKEY_NAME);
- }
-
- // setup some more material properties that are specific to NFF2
- int i;
- if (src.shader.twoSided) {
- i = 1;
- pcMat->AddProperty(&i, 1, AI_MATKEY_TWOSIDED);
- }
- i = (src.shader.shaded ? aiShadingMode_Gouraud : aiShadingMode_NoShading);
- if (src.shader.shininess) {
- i = aiShadingMode_Phong;
- pcMat->AddProperty(&src.shader.shininess, 1, AI_MATKEY_SHININESS);
- }
- pcMat->AddProperty(&i, 1, AI_MATKEY_SHADING_MODEL);
- }
- pScene->mRootNode = root;
-}
-
-#endif // !! ASSIMP_BUILD_NO_NFF_IMPORTER