Merge branch 'master' into master
commit
c22524351a
|
@ -42,7 +42,9 @@ Take a look into the https://github.com/assimp/assimp/blob/master/Build.md file.
|
||||||
* [.NET](https://bitbucket.org/Starnick/assimpnet/src/master/)
|
* [.NET](https://bitbucket.org/Starnick/assimpnet/src/master/)
|
||||||
* [Pascal](port/AssimpPascal/Readme.md)
|
* [Pascal](port/AssimpPascal/Readme.md)
|
||||||
* [Javascript (Alpha)](https://github.com/makc/assimp2json)
|
* [Javascript (Alpha)](https://github.com/makc/assimp2json)
|
||||||
|
* [Javascript/Node.js Interface](https://github.com/kovacsv/assimpjs)
|
||||||
* [Unity 3d Plugin](https://ricardoreis.net/trilib-2/)
|
* [Unity 3d Plugin](https://ricardoreis.net/trilib-2/)
|
||||||
|
* [Unreal Engine Plugin](https://github.com/irajsb/UE4_Assimp/)
|
||||||
* [JVM](https://github.com/kotlin-graphics/assimp) Full jvm port (current [status](https://github.com/kotlin-graphics/assimp/wiki/Status))
|
* [JVM](https://github.com/kotlin-graphics/assimp) Full jvm port (current [status](https://github.com/kotlin-graphics/assimp/wiki/Status))
|
||||||
* [HAXE-Port](https://github.com/longde123/assimp-haxe) The Assimp-HAXE-port.
|
* [HAXE-Port](https://github.com/longde123/assimp-haxe) The Assimp-HAXE-port.
|
||||||
* [Rust](https://github.com/jkvargas/russimp)
|
* [Rust](https://github.com/jkvargas/russimp)
|
||||||
|
|
|
@ -330,6 +330,7 @@ void Discreet3DSExporter::WriteMaterials() {
|
||||||
case aiShadingMode_Blinn:
|
case aiShadingMode_Blinn:
|
||||||
case aiShadingMode_CookTorrance:
|
case aiShadingMode_CookTorrance:
|
||||||
case aiShadingMode_Fresnel:
|
case aiShadingMode_Fresnel:
|
||||||
|
case aiShadingMode_PBR_BRDF: // Possibly should be Discreet3DS::Metal in some cases but this is undocumented
|
||||||
shading_mode_out = Discreet3DS::Phong;
|
shading_mode_out = Discreet3DS::Phong;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -356,7 +357,10 @@ void Discreet3DSExporter::WriteMaterials() {
|
||||||
writer.PutI2(1);
|
writer.PutI2(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteTexture(mat, aiTextureType_DIFFUSE, Discreet3DS::CHUNK_MAT_TEXTURE);
|
// Fallback to BASE_COLOR if no DIFFUSE
|
||||||
|
if (!WriteTexture(mat, aiTextureType_DIFFUSE, Discreet3DS::CHUNK_MAT_TEXTURE))
|
||||||
|
WriteTexture(mat, aiTextureType_BASE_COLOR, Discreet3DS::CHUNK_MAT_TEXTURE);
|
||||||
|
|
||||||
WriteTexture(mat, aiTextureType_HEIGHT, Discreet3DS::CHUNK_MAT_BUMPMAP);
|
WriteTexture(mat, aiTextureType_HEIGHT, Discreet3DS::CHUNK_MAT_BUMPMAP);
|
||||||
WriteTexture(mat, aiTextureType_OPACITY, Discreet3DS::CHUNK_MAT_OPACMAP);
|
WriteTexture(mat, aiTextureType_OPACITY, Discreet3DS::CHUNK_MAT_OPACMAP);
|
||||||
WriteTexture(mat, aiTextureType_SHININESS, Discreet3DS::CHUNK_MAT_MAT_SHINMAP);
|
WriteTexture(mat, aiTextureType_SHININESS, Discreet3DS::CHUNK_MAT_MAT_SHINMAP);
|
||||||
|
@ -367,20 +371,21 @@ void Discreet3DSExporter::WriteMaterials() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Discreet3DSExporter::WriteTexture(const aiMaterial &mat, aiTextureType type, uint16_t chunk_flags) {
|
// returns true if the texture existed
|
||||||
|
bool Discreet3DSExporter::WriteTexture(const aiMaterial &mat, aiTextureType type, uint16_t chunk_flags) {
|
||||||
aiString path;
|
aiString path;
|
||||||
aiTextureMapMode map_mode[2] = {
|
aiTextureMapMode map_mode[2] = {
|
||||||
aiTextureMapMode_Wrap, aiTextureMapMode_Wrap
|
aiTextureMapMode_Wrap, aiTextureMapMode_Wrap
|
||||||
};
|
};
|
||||||
ai_real blend = 1.0;
|
ai_real blend = 1.0;
|
||||||
if (mat.GetTexture(type, 0, &path, nullptr, nullptr, &blend, nullptr, map_mode) != AI_SUCCESS || !path.length) {
|
if (mat.GetTexture(type, 0, &path, nullptr, nullptr, &blend, nullptr, map_mode) != AI_SUCCESS || !path.length) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: handle embedded textures properly
|
// TODO: handle embedded textures properly
|
||||||
if (path.data[0] == '*') {
|
if (path.data[0] == '*') {
|
||||||
ASSIMP_LOG_ERROR("Ignoring embedded texture for export: ", path.C_Str());
|
ASSIMP_LOG_ERROR("Ignoring embedded texture for export: ", path.C_Str());
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ChunkWriter chunk(writer, chunk_flags);
|
ChunkWriter chunk(writer, chunk_flags);
|
||||||
|
@ -402,6 +407,7 @@ void Discreet3DSExporter::WriteTexture(const aiMaterial &mat, aiTextureType type
|
||||||
writer.PutU2(val);
|
writer.PutU2(val);
|
||||||
}
|
}
|
||||||
// TODO: export texture transformation (i.e. UV offset, scale, rotation)
|
// TODO: export texture transformation (i.e. UV offset, scale, rotation)
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -73,7 +73,7 @@ public:
|
||||||
private:
|
private:
|
||||||
void WriteMeshes();
|
void WriteMeshes();
|
||||||
void WriteMaterials();
|
void WriteMaterials();
|
||||||
void WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags);
|
bool WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags);
|
||||||
void WriteFaceMaterialChunk(const aiMesh& mesh);
|
void WriteFaceMaterialChunk(const aiMesh& mesh);
|
||||||
int WriteHierarchy(const aiNode& node, int level, int sibling_level);
|
int WriteHierarchy(const aiNode& node, int level, int sibling_level);
|
||||||
void WriteString(const std::string& s);
|
void WriteString(const std::string& s);
|
||||||
|
|
|
@ -601,7 +601,7 @@ static void WriteDump(const char *pFile, const char *cmd, const aiScene *scene,
|
||||||
ioprintf(io, "\t\t<TextureCoords num=\"%u\" set=\"%u\" name=\"%s\" num_components=\"%u\"> \n",
|
ioprintf(io, "\t\t<TextureCoords num=\"%u\" set=\"%u\" name=\"%s\" num_components=\"%u\"> \n",
|
||||||
mesh->mNumVertices,
|
mesh->mNumVertices,
|
||||||
a,
|
a,
|
||||||
mesh->mTextureCoordsNames[a].C_Str(),
|
(mesh->HasTextureCoordsName(a) ? mesh->GetTextureCoordsName(a)->C_Str() : ""),
|
||||||
mesh->mNumUVComponents[a]);
|
mesh->mNumUVComponents[a]);
|
||||||
|
|
||||||
if (!shortened) {
|
if (!shortened) {
|
||||||
|
|
|
@ -1128,7 +1128,7 @@ unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, c
|
||||||
*out_uv++ = aiVector3D(v.x, v.y, 0.0f);
|
*out_uv++ = aiVector3D(v.x, v.y, 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
out_mesh->mTextureCoordsNames[i] = mesh.GetTextureCoordChannelName(i);
|
out_mesh->SetTextureCoordsName(i, aiString(mesh.GetTextureCoordChannelName(i)));
|
||||||
|
|
||||||
out_mesh->mNumUVComponents[i] = 2;
|
out_mesh->mNumUVComponents[i] = 2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,531 @@
|
||||||
|
#include "X3DGeoHelper.h"
|
||||||
|
#include "X3DImporter.hpp"
|
||||||
|
|
||||||
|
#include <assimp/vector3.h>
|
||||||
|
#include <assimp/Exceptional.h>
|
||||||
|
#include <assimp/StringUtils.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
aiVector3D X3DGeoHelper::make_point2D(float angle, float radius) {
|
||||||
|
return aiVector3D(radius * std::cos(angle), radius * std::sin(angle), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void X3DGeoHelper::make_arc2D(float pStartAngle, float pEndAngle, float pRadius, size_t numSegments, std::list<aiVector3D> &pVertices) {
|
||||||
|
// check argument values ranges.
|
||||||
|
if ((pStartAngle < -AI_MATH_TWO_PI_F) || (pStartAngle > AI_MATH_TWO_PI_F)) {
|
||||||
|
throw DeadlyImportError("GeometryHelper_Make_Arc2D.pStartAngle");
|
||||||
|
}
|
||||||
|
if ((pEndAngle < -AI_MATH_TWO_PI_F) || (pEndAngle > AI_MATH_TWO_PI_F)) {
|
||||||
|
throw DeadlyImportError("GeometryHelper_Make_Arc2D.pEndAngle");
|
||||||
|
}
|
||||||
|
if (pRadius <= 0) {
|
||||||
|
throw DeadlyImportError("GeometryHelper_Make_Arc2D.pRadius");
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate arc angle and check type of arc
|
||||||
|
float angle_full = std::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.
|
||||||
|
float angle_step = angle_full / (float)numSegments;
|
||||||
|
// make points
|
||||||
|
for (size_t pi = 0; pi <= numSegments; pi++) {
|
||||||
|
float tangle = pStartAngle + pi * angle_step;
|
||||||
|
pVertices.emplace_back(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 X3DGeoHelper::extend_point_to_line(const std::list<aiVector3D> &pPoint, std::list<aiVector3D> &pLine) {
|
||||||
|
std::list<aiVector3D>::const_iterator pit = pPoint.begin();
|
||||||
|
std::list<aiVector3D>::const_iterator pit_last = pPoint.end();
|
||||||
|
|
||||||
|
--pit_last;
|
||||||
|
|
||||||
|
if (pPoint.size() < 2) {
|
||||||
|
throw DeadlyImportError("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 X3DGeoHelper::polylineIdx_to_lineIdx(const std::list<int32_t> &pPolylineCoordIdx, std::list<int32_t> &pLineCoordIdx) {
|
||||||
|
std::list<int32_t>::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<int32_t>::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 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)
|
||||||
|
|
||||||
|
#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 X3DGeoHelper::rect_parallel_epiped(const aiVector3D &pSize, std::list<aiVector3D> &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 X3DGeoHelper::coordIdx_str2faces_arr(const std::vector<int32_t> &pCoordIdx, std::vector<aiFace> &pFaces, unsigned int &pPrimitiveTypes) {
|
||||||
|
std::vector<int32_t> f_data(pCoordIdx);
|
||||||
|
std::vector<unsigned int> 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::vector<int32_t>::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;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
prim_type |= aiPrimitiveType_LINE;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
prim_type |= aiPrimitiveType_TRIANGLE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
prim_type |= aiPrimitiveType_POLYGON;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tface.mNumIndices = static_cast<unsigned int>(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<int32_t>::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 X3DGeoHelper::add_color(aiMesh &pMesh, const std::list<aiColor3D> &pColors, const bool pColorPerVertex) {
|
||||||
|
std::list<aiColor4D> tcol;
|
||||||
|
|
||||||
|
// create RGBA array from RGB.
|
||||||
|
for (std::list<aiColor3D>::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
|
||||||
|
add_color(pMesh, tcol, pColorPerVertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void X3DGeoHelper::add_color(aiMesh &pMesh, const std::list<aiColor4D> &pColors, const bool pColorPerVertex) {
|
||||||
|
std::list<aiColor4D>::const_iterator col_it = pColors.begin();
|
||||||
|
|
||||||
|
if (pColorPerVertex) {
|
||||||
|
if (pColors.size() < pMesh.mNumVertices) {
|
||||||
|
throw DeadlyImportError("MeshGeometry_AddColor1. Colors count(" + ai_to_string(pColors.size()) + ") can not be less than Vertices count(" +
|
||||||
|
ai_to_string(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("MeshGeometry_AddColor1. Colors count(" + ai_to_string(pColors.size()) + ") can not be less than Faces count(" +
|
||||||
|
ai_to_string(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 X3DGeoHelper::add_color(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pColorIdx,
|
||||||
|
const std::list<aiColor3D> &pColors, const bool pColorPerVertex) {
|
||||||
|
std::list<aiColor4D> tcol;
|
||||||
|
|
||||||
|
// create RGBA array from RGB.
|
||||||
|
for (std::list<aiColor3D>::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
|
||||||
|
add_color(pMesh, pCoordIdx, pColorIdx, tcol, pColorPerVertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void X3DGeoHelper::add_color(aiMesh &pMesh, const std::vector<int32_t> &coordIdx, const std::vector<int32_t> &colorIdx,
|
||||||
|
const std::list<aiColor4D> &colors, bool pColorPerVertex) {
|
||||||
|
std::vector<aiColor4D> col_tgt_arr;
|
||||||
|
std::list<aiColor4D> col_tgt_list;
|
||||||
|
std::vector<aiColor4D> col_arr_copy;
|
||||||
|
|
||||||
|
if (coordIdx.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(colors.size());
|
||||||
|
for (std::list<aiColor4D>::const_iterator it = colors.begin(); it != colors.end(); ++it) {
|
||||||
|
col_arr_copy.push_back(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pColorPerVertex) {
|
||||||
|
if (colorIdx.size() > 0) {
|
||||||
|
// check indices array count.
|
||||||
|
if (colorIdx.size() < coordIdx.size()) {
|
||||||
|
throw DeadlyImportError("MeshGeometry_AddColor2. Colors indices count(" + ai_to_string(colorIdx.size()) +
|
||||||
|
") can not be less than Coords indices count(" + ai_to_string(coordIdx.size()) + ").");
|
||||||
|
}
|
||||||
|
// create list with colors for every vertex.
|
||||||
|
col_tgt_arr.resize(pMesh.mNumVertices);
|
||||||
|
for (std::vector<int32_t>::const_iterator colidx_it = colorIdx.begin(), coordidx_it = coordIdx.begin(); colidx_it != colorIdx.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 (colors.size() < pMesh.mNumVertices) {
|
||||||
|
throw DeadlyImportError("MeshGeometry_AddColor2. Colors count(" + ai_to_string(colors.size()) + ") can not be less than Vertices count(" +
|
||||||
|
ai_to_string(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 (colorIdx.size() > 0) {
|
||||||
|
// check indices array count.
|
||||||
|
if (colorIdx.size() < pMesh.mNumFaces) {
|
||||||
|
throw DeadlyImportError("MeshGeometry_AddColor2. Colors indices count(" + ai_to_string(colorIdx.size()) +
|
||||||
|
") can not be less than Faces count(" + ai_to_string(pMesh.mNumFaces) + ").");
|
||||||
|
}
|
||||||
|
// create list with colors for every vertex using faces indices.
|
||||||
|
col_tgt_arr.resize(pMesh.mNumFaces);
|
||||||
|
|
||||||
|
std::vector<int32_t>::const_iterator colidx_it = colorIdx.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 (colors.size() < pMesh.mNumFaces) {
|
||||||
|
throw DeadlyImportError("MeshGeometry_AddColor2. Colors count(" + ai_to_string(colors.size()) + ") can not be less than Faces count(" +
|
||||||
|
ai_to_string(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<aiColor4D>::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.
|
||||||
|
add_color(pMesh, col_tgt_list, pColorPerVertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void X3DGeoHelper::add_normal(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pNormalIdx,
|
||||||
|
const std::list<aiVector3D> &pNormals, const bool pNormalPerVertex) {
|
||||||
|
std::vector<size_t> tind;
|
||||||
|
std::vector<aiVector3D> norm_arr_copy;
|
||||||
|
|
||||||
|
// copy list to array because we are need indexed access to normals.
|
||||||
|
norm_arr_copy.reserve(pNormals.size());
|
||||||
|
for (std::list<aiVector3D>::const_iterator it = pNormals.begin(); it != pNormals.end(); ++it) {
|
||||||
|
norm_arr_copy.push_back(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pNormalPerVertex) {
|
||||||
|
if (pNormalIdx.size() > 0) {
|
||||||
|
// check indices array count.
|
||||||
|
if (pNormalIdx.size() != pCoordIdx.size()) throw DeadlyImportError("Normals and Coords inidces count must be equal.");
|
||||||
|
|
||||||
|
tind.reserve(pNormalIdx.size());
|
||||||
|
for (std::vector<int32_t>::const_iterator it = pNormalIdx.begin(); it != pNormalIdx.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("MeshGeometry_AddNormal. Normal index(" + ai_to_string(tind[i]) +
|
||||||
|
") is out of range. Normals count: " + ai_to_string(norm_arr_copy.size()) + ".");
|
||||||
|
|
||||||
|
pMesh.mNormals[i] = norm_arr_copy[tind[i]];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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];
|
||||||
|
std::list<aiVector3D>::const_iterator norm_it = pNormals.begin();
|
||||||
|
for (size_t i = 0; i < pMesh.mNumVertices; i++)
|
||||||
|
pMesh.mNormals[i] = *norm_it++;
|
||||||
|
}
|
||||||
|
} // 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::vector<int32_t>::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 X3DGeoHelper::add_normal(aiMesh &pMesh, const std::list<aiVector3D> &pNormals, const bool pNormalPerVertex) {
|
||||||
|
std::list<aiVector3D>::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 X3DGeoHelper::add_tex_coord(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pTexCoordIdx,
|
||||||
|
const std::list<aiVector2D> &pTexCoords) {
|
||||||
|
std::vector<aiVector3D> texcoord_arr_copy;
|
||||||
|
std::vector<aiFace> 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<aiVector2D>::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); ++it) {
|
||||||
|
texcoord_arr_copy.push_back(aiVector3D((*it).x, (*it).y, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pTexCoordIdx.size() > 0) {
|
||||||
|
coordIdx_str2faces_arr(pTexCoordIdx, faces, prim_type);
|
||||||
|
if (faces.empty()) {
|
||||||
|
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 {
|
||||||
|
coordIdx_str2faces_arr(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("Number of indices in texture face and mesh face must be equal. Invalid face index: " + ai_to_string(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 X3DGeoHelper::add_tex_coord(aiMesh &pMesh, const std::list<aiVector2D> &pTexCoords) {
|
||||||
|
std::vector<aiVector3D> 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<aiVector2D>::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 *X3DGeoHelper::make_mesh(const std::vector<int32_t> &pCoordIdx, const std::list<aiVector3D> &pVertices) {
|
||||||
|
std::vector<aiFace> faces;
|
||||||
|
unsigned int prim_type = 0;
|
||||||
|
|
||||||
|
// create faces array from input string with vertices indices.
|
||||||
|
X3DGeoHelper::coordIdx_str2faces_arr(pCoordIdx, faces, prim_type);
|
||||||
|
if (!faces.size()) {
|
||||||
|
throw DeadlyImportError("Failed to create mesh, faces list is empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create new mesh and copy geometry data.
|
||||||
|
//
|
||||||
|
aiMesh *tmesh = new aiMesh;
|
||||||
|
size_t ts = faces.size();
|
||||||
|
// faces
|
||||||
|
tmesh->mFaces = new aiFace[ts];
|
||||||
|
tmesh->mNumFaces = static_cast<unsigned int>(ts);
|
||||||
|
for (size_t i = 0; i < ts; i++)
|
||||||
|
tmesh->mFaces[i] = faces.at(i);
|
||||||
|
|
||||||
|
// vertices
|
||||||
|
std::list<aiVector3D>::const_iterator vit = pVertices.begin();
|
||||||
|
|
||||||
|
ts = pVertices.size();
|
||||||
|
tmesh->mVertices = new aiVector3D[ts];
|
||||||
|
tmesh->mNumVertices = static_cast<unsigned int>(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Assimp
|
|
@ -0,0 +1,39 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <assimp/vector2.h>
|
||||||
|
#include <assimp/vector3.h>
|
||||||
|
#include <assimp/color4.h>
|
||||||
|
#include <assimp/types.h>
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
struct aiFace;
|
||||||
|
struct aiMesh;
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
class X3DGeoHelper {
|
||||||
|
public:
|
||||||
|
static aiVector3D make_point2D(float angle, float radius);
|
||||||
|
static void make_arc2D(float pStartAngle, float pEndAngle, float pRadius, size_t numSegments, std::list<aiVector3D> &pVertices);
|
||||||
|
static void extend_point_to_line(const std::list<aiVector3D> &pPoint, std::list<aiVector3D> &pLine);
|
||||||
|
static void polylineIdx_to_lineIdx(const std::list<int32_t> &pPolylineCoordIdx, std::list<int32_t> &pLineCoordIdx);
|
||||||
|
static void rect_parallel_epiped(const aiVector3D &pSize, std::list<aiVector3D> &pVertices);
|
||||||
|
static void coordIdx_str2faces_arr(const std::vector<int32_t> &pCoordIdx, std::vector<aiFace> &pFaces, unsigned int &pPrimitiveTypes);
|
||||||
|
static void add_color(aiMesh &pMesh, const std::list<aiColor3D> &pColors, const bool pColorPerVertex);
|
||||||
|
static void add_color(aiMesh &pMesh, const std::list<aiColor4D> &pColors, const bool pColorPerVertex);
|
||||||
|
static void add_color(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pColorIdx,
|
||||||
|
const std::list<aiColor3D> &pColors, const bool pColorPerVertex);
|
||||||
|
static void add_color(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pColorIdx,
|
||||||
|
const std::list<aiColor4D> &pColors, const bool pColorPerVertex);
|
||||||
|
static void add_normal(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pNormalIdx,
|
||||||
|
const std::list<aiVector3D> &pNormals, const bool pNormalPerVertex);
|
||||||
|
static void add_normal(aiMesh &pMesh, const std::list<aiVector3D> &pNormals, const bool pNormalPerVertex);
|
||||||
|
static void add_tex_coord(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pTexCoordIdx,
|
||||||
|
const std::list<aiVector2D> &pTexCoords);
|
||||||
|
static void add_tex_coord(aiMesh &pMesh, const std::list<aiVector2D> &pTexCoords);
|
||||||
|
static aiMesh *make_mesh(const std::vector<int32_t> &pCoordIdx, const std::list<aiVector3D> &pVertices);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Assimp
|
|
@ -46,16 +46,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
|
||||||
|
|
||||||
#include "X3DImporter.hpp"
|
#include "X3DImporter.hpp"
|
||||||
#include <assimp/StringUtils.h>
|
#include "X3DImporter_Macro.hpp"
|
||||||
|
|
||||||
// Header files, Assimp.
|
|
||||||
#include <assimp/DefaultIOSystem.h>
|
#include <assimp/DefaultIOSystem.h>
|
||||||
#include <assimp/fast_atof.h>
|
|
||||||
|
|
||||||
// Header files, stdlib.
|
// Header files, stdlib.
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
|
@ -73,60 +70,119 @@ const aiImporterDesc X3DImporter::Description = {
|
||||||
"x3d x3db"
|
"x3d x3db"
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WordIterator {
|
bool X3DImporter::isNodeEmpty(XmlNode &node) {
|
||||||
using iterator_category = std::input_iterator_tag;
|
return node.first_child().empty();
|
||||||
using value_type = const char *;
|
}
|
||||||
using difference_type = ptrdiff_t;
|
|
||||||
using pointer = value_type *;
|
|
||||||
using reference = value_type &;
|
|
||||||
|
|
||||||
static const char *whitespace;
|
void X3DImporter::checkNodeMustBeEmpty(XmlNode &node) {
|
||||||
const char *mStart, *mEnd;
|
if (!isNodeEmpty(node)) throw DeadlyImportError(std::string("Node <") + node.name() + "> must be empty.");
|
||||||
|
}
|
||||||
|
|
||||||
WordIterator(const char *start, const char *end) :
|
void X3DImporter::skipUnsupportedNode(const std::string &pParentNodeName, XmlNode &node) {
|
||||||
mStart(start),
|
static const size_t Uns_Skip_Len = 192;
|
||||||
mEnd(end) {
|
static const char *Uns_Skip[Uns_Skip_Len] = {
|
||||||
mStart = start + ::strspn(start, whitespace);
|
// CAD geometry component
|
||||||
if (mStart >= mEnd) {
|
"CADAssembly", "CADFace", "CADLayer", "CADPart", "IndexedQuadSet", "QuadSet",
|
||||||
mStart = 0;
|
// 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
|
||||||
|
"EXPORT", "IMPORT", "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"
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::string nn = node.name();
|
||||||
|
|
||||||
|
if (nn.empty()) {
|
||||||
|
const std::string nv = node.value();
|
||||||
|
if (!nv.empty()) {
|
||||||
|
LogInfo("Ignoring comment \"" + nv + "\" in " + pParentNodeName + ".");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WordIterator() :
|
|
||||||
mStart(0),
|
|
||||||
mEnd(0) {}
|
|
||||||
WordIterator(const WordIterator &other) :
|
|
||||||
mStart(other.mStart),
|
|
||||||
mEnd(other.mEnd) {}
|
|
||||||
WordIterator &operator=(const WordIterator &other) {
|
|
||||||
mStart = other.mStart;
|
|
||||||
mEnd = other.mEnd;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const WordIterator &other) const { return mStart == other.mStart; }
|
bool found = false;
|
||||||
|
|
||||||
bool operator!=(const WordIterator &other) const { return mStart != other.mStart; }
|
for (size_t i = 0; i < Uns_Skip_Len; i++) {
|
||||||
|
if (nn == Uns_Skip[i]) {
|
||||||
WordIterator &operator++() {
|
found = true;
|
||||||
mStart += strcspn(mStart, whitespace);
|
|
||||||
mStart += strspn(mStart, whitespace);
|
|
||||||
if (mStart >= mEnd) {
|
|
||||||
mStart = 0;
|
|
||||||
}
|
}
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
WordIterator operator++(int) {
|
|
||||||
WordIterator result(*this);
|
|
||||||
++(*this);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
const char *operator*() const { return mStart; }
|
|
||||||
};
|
|
||||||
|
|
||||||
const char *WordIterator::whitespace = ", \t\r\n";
|
if (!found) throw DeadlyImportError("Unknown node \"" + nn + "\" in " + pParentNodeName + ".");
|
||||||
|
|
||||||
|
LogInfo("Skipping node \"" + nn + "\" in " + pParentNodeName + ".");
|
||||||
|
}
|
||||||
|
|
||||||
X3DImporter::X3DImporter() :
|
X3DImporter::X3DImporter() :
|
||||||
mNodeElementCur(nullptr) {
|
mNodeElementCur(nullptr),
|
||||||
|
mScene(nullptr),
|
||||||
|
mpIOHandler(nullptr) {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,10 +209,31 @@ void X3DImporter::ParseFile(const std::string &file, IOSystem *pIOHandler) {
|
||||||
std::unique_ptr<IOStream> fileStream(pIOHandler->Open(file, mode));
|
std::unique_ptr<IOStream> fileStream(pIOHandler->Open(file, mode));
|
||||||
if (!fileStream.get()) {
|
if (!fileStream.get()) {
|
||||||
throw DeadlyImportError("Failed to open file " + file + ".");
|
throw DeadlyImportError("Failed to open file " + file + ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XmlParser theParser;
|
||||||
|
if (!theParser.parse(fileStream.get())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlNode *node = theParser.findNode("X3D");
|
||||||
|
if (nullptr == node) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto ¤tNode : node->children()) {
|
||||||
|
const std::string ¤tName = currentNode.name();
|
||||||
|
if (currentName == "head") {
|
||||||
|
readHead(currentNode);
|
||||||
|
} else if (currentName == "Scene") {
|
||||||
|
readScene(currentNode);
|
||||||
|
} else {
|
||||||
|
skipUnsupportedNode("X3D", currentNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool X3DImporter::CanRead( const std::string &pFile, IOSystem * /*pIOHandler*/, bool checkSig ) const {
|
bool X3DImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool checkSig) const {
|
||||||
if (checkSig) {
|
if (checkSig) {
|
||||||
std::string::size_type pos = pFile.find_last_of(".x3d");
|
std::string::size_type pos = pFile.find_last_of(".x3d");
|
||||||
if (pos != std::string::npos) {
|
if (pos != std::string::npos) {
|
||||||
|
@ -167,19 +244,244 @@ bool X3DImporter::CanRead( const std::string &pFile, IOSystem * /*pIOHandler*/,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void X3DImporter::InternReadFile( const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler ) {
|
void X3DImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
|
||||||
|
mpIOHandler = pIOHandler;
|
||||||
|
|
||||||
|
Clear();
|
||||||
std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
|
std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
throw DeadlyImportError("Could not open file for reading");
|
throw DeadlyImportError("Could not open file for reading");
|
||||||
}
|
}
|
||||||
|
std::string::size_type slashPos = pFile.find_last_of("\\/");
|
||||||
|
|
||||||
|
mScene = pScene;
|
||||||
pScene->mRootNode = new aiNode(pFile);
|
pScene->mRootNode = new aiNode(pFile);
|
||||||
|
pScene->mRootNode->mParent = nullptr;
|
||||||
|
pScene->mFlags |= AI_SCENE_FLAGS_ALLOW_SHARED;
|
||||||
|
|
||||||
|
pIOHandler->PushDirectory(slashPos == std::string::npos ? std::string() : pFile.substr(0, slashPos + 1));
|
||||||
|
ParseFile(pFile, pIOHandler);
|
||||||
|
pIOHandler->PopDirectory();
|
||||||
|
|
||||||
|
//search for root node element
|
||||||
|
|
||||||
|
mNodeElementCur = NodeElement_List.front();
|
||||||
|
while (mNodeElementCur->Parent != nullptr) {
|
||||||
|
mNodeElementCur = mNodeElementCur->Parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // fill aiScene with objects.
|
||||||
|
std::list<aiMesh *> mesh_list;
|
||||||
|
std::list<aiMaterial *> mat_list;
|
||||||
|
std::list<aiLight *> light_list;
|
||||||
|
|
||||||
|
// create nodes tree
|
||||||
|
Postprocess_BuildNode(*mNodeElementCur, *pScene->mRootNode, mesh_list, mat_list, light_list);
|
||||||
|
// copy needed data to scene
|
||||||
|
if (!mesh_list.empty()) {
|
||||||
|
std::list<aiMesh *>::const_iterator it = mesh_list.begin();
|
||||||
|
|
||||||
|
pScene->mNumMeshes = static_cast<unsigned int>(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.empty()) {
|
||||||
|
std::list<aiMaterial *>::const_iterator it = mat_list.begin();
|
||||||
|
|
||||||
|
pScene->mNumMaterials = static_cast<unsigned int>(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.empty()) {
|
||||||
|
std::list<aiLight *>::const_iterator it = light_list.begin();
|
||||||
|
|
||||||
|
pScene->mNumLights = static_cast<unsigned int>(light_list.size());
|
||||||
|
pScene->mLights = new aiLight *[pScene->mNumLights];
|
||||||
|
for (size_t i = 0; i < pScene->mNumLights; i++)
|
||||||
|
pScene->mLights[i] = *it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const aiImporterDesc *X3DImporter::GetInfo() const {
|
const aiImporterDesc *X3DImporter::GetInfo() const {
|
||||||
return &Description;
|
return &Description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct meta_entry {
|
||||||
|
std::string name;
|
||||||
|
std::string value;
|
||||||
|
};
|
||||||
|
|
||||||
|
void X3DImporter::readHead(XmlNode &node) {
|
||||||
|
std::vector<meta_entry> metaArray;
|
||||||
|
for (auto currentNode : node.children()) {
|
||||||
|
const std::string ¤tName = currentNode.name();
|
||||||
|
if (currentName == "meta") {
|
||||||
|
//checkNodeMustBeEmpty(node);
|
||||||
|
meta_entry entry;
|
||||||
|
if (XmlParser::getStdStrAttribute(currentNode, "name", entry.name)) {
|
||||||
|
XmlParser::getStdStrAttribute(currentNode, "content", entry.value);
|
||||||
|
metaArray.emplace_back(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: check if other node types in head should be supported
|
||||||
|
}
|
||||||
|
mScene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(metaArray.size()));
|
||||||
|
unsigned int i = 0;
|
||||||
|
for (auto currentMeta : metaArray) {
|
||||||
|
mScene->mMetaData->Set(i, currentMeta.name, aiString(currentMeta.value));
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void X3DImporter::readChildNodes(XmlNode &node, const std::string &pParentNodeName) {
|
||||||
|
if (node.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (auto currentNode : node.children()) {
|
||||||
|
const std::string ¤tName = currentNode.name();
|
||||||
|
if (currentName == "Shape")
|
||||||
|
readShape(currentNode);
|
||||||
|
else if (currentName == "Group") {
|
||||||
|
startReadGroup(currentNode);
|
||||||
|
readChildNodes(currentNode, "Group");
|
||||||
|
endReadGroup();
|
||||||
|
} else if (currentName == "StaticGroup") {
|
||||||
|
startReadStaticGroup(currentNode);
|
||||||
|
readChildNodes(currentNode, "StaticGroup");
|
||||||
|
endReadStaticGroup();
|
||||||
|
} else if (currentName == "Transform") {
|
||||||
|
startReadTransform(currentNode);
|
||||||
|
readChildNodes(currentNode, "Transform");
|
||||||
|
endReadTransform();
|
||||||
|
} else if (currentName == "Switch") {
|
||||||
|
startReadSwitch(currentNode);
|
||||||
|
readChildNodes(currentNode, "Switch");
|
||||||
|
endReadSwitch();
|
||||||
|
} else if (currentName == "DirectionalLight") {
|
||||||
|
readDirectionalLight(currentNode);
|
||||||
|
} else if (currentName == "PointLight") {
|
||||||
|
readPointLight(currentNode);
|
||||||
|
} else if (currentName == "SpotLight") {
|
||||||
|
readSpotLight(currentNode);
|
||||||
|
} else if (currentName == "Inline") {
|
||||||
|
readInline(currentNode);
|
||||||
|
} else if (!checkForMetadataNode(currentNode)) {
|
||||||
|
skipUnsupportedNode(pParentNodeName, currentNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void X3DImporter::readScene(XmlNode &node) {
|
||||||
|
ParseHelper_Group_Begin(true);
|
||||||
|
readChildNodes(node, "Scene");
|
||||||
|
ParseHelper_Node_Exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************************************************/
|
||||||
|
/************************************************************ Functions: find set ************************************************************/
|
||||||
|
/*********************************************************************************************************************************************/
|
||||||
|
|
||||||
|
bool X3DImporter::FindNodeElement_FromRoot(const std::string &pID, const X3DElemType pType, X3DNodeElementBase **pElement) {
|
||||||
|
for (std::list<X3DNodeElementBase *>::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); ++it) {
|
||||||
|
if (((*it)->Type == pType) && ((*it)->ID == pID)) {
|
||||||
|
if (pElement != nullptr) *pElement = *it;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // for(std::list<CX3DImporter_NodeElement*>::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); it++)
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X3DImporter::FindNodeElement_FromNode(X3DNodeElementBase *pStartNode, const std::string &pID,
|
||||||
|
const X3DElemType pType, X3DNodeElementBase **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 != nullptr) {
|
||||||
|
*pElement = pStartNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto fne_fn_end;
|
||||||
|
} // if((pStartNode->Type() == pType) && (pStartNode->ID() == pID))
|
||||||
|
|
||||||
|
// Check childs of pStartNode.
|
||||||
|
for (std::list<X3DNodeElementBase *>::iterator ch_it = pStartNode->Children.begin(); ch_it != pStartNode->Children.end(); ++ch_it) {
|
||||||
|
found = FindNodeElement_FromNode(*ch_it, pID, pType, pElement);
|
||||||
|
if (found) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} // for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = it->Children.begin(); ch_it != it->Children.end(); ch_it++)
|
||||||
|
|
||||||
|
fne_fn_end:
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X3DImporter::FindNodeElement(const std::string &pID, const X3DElemType pType, X3DNodeElementBase **pElement) {
|
||||||
|
X3DNodeElementBase *tnd = mNodeElementCur; // 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 through parent nodes and check flag.
|
||||||
|
while (tnd != nullptr) {
|
||||||
|
if (tnd->Type == X3DElemType::ENET_Group) {
|
||||||
|
if (((X3DNodeElementGroup *)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 != nullptr)
|
||||||
|
|
||||||
|
// at now call appropriate search function.
|
||||||
|
if (static_search) {
|
||||||
|
return FindNodeElement_FromNode(tnd, pID, pType, pElement);
|
||||||
|
} else {
|
||||||
|
return FindNodeElement_FromRoot(pID, pType, pElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************************************************/
|
||||||
|
/************************************************************ Functions: parse set ***********************************************************/
|
||||||
|
/*********************************************************************************************************************************************/
|
||||||
|
|
||||||
|
void X3DImporter::ParseHelper_Group_Begin(const bool pStatic) {
|
||||||
|
X3DNodeElementGroup *new_group = new X3DNodeElementGroup(mNodeElementCur, 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 (mNodeElementCur != nullptr) {
|
||||||
|
mNodeElementCur->Children.push_back(new_group);
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeElement_List.push_back(new_group); // it's a new element - add it to list.
|
||||||
|
mNodeElementCur = new_group; // switch current element to new one.
|
||||||
|
}
|
||||||
|
|
||||||
|
void X3DImporter::ParseHelper_Node_Enter(X3DNodeElementBase *pNode) {
|
||||||
|
ai_assert(nullptr != pNode);
|
||||||
|
|
||||||
|
mNodeElementCur->Children.push_back(pNode); // add new element to current element child list.
|
||||||
|
mNodeElementCur = pNode; // switch current element to new one.
|
||||||
|
}
|
||||||
|
|
||||||
|
void X3DImporter::ParseHelper_Node_Exit() {
|
||||||
|
// check if we can walk up.
|
||||||
|
if (mNodeElementCur != nullptr) {
|
||||||
|
mNodeElementCur = mNodeElementCur->Parent;
|
||||||
|
} else {
|
||||||
|
int i = 0;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER
|
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER
|
||||||
|
|
||||||
|
} // namespace Assimp
|
||||||
|
|
|
@ -38,16 +38,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
/// \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
|
#ifndef INCLUDED_AI_X3D_IMPORTER_H
|
||||||
#define INCLUDED_AI_X3D_IMPORTER_H
|
#define INCLUDED_AI_X3D_IMPORTER_H
|
||||||
|
|
||||||
// Header files, Assimp.
|
#include "X3DImporter_Node.hpp"
|
||||||
|
|
||||||
#include <assimp/BaseImporter.h>
|
#include <assimp/BaseImporter.h>
|
||||||
#include <assimp/XmlParser.h>
|
#include <assimp/XmlParser.h>
|
||||||
#include <assimp/importerdesc.h>
|
#include <assimp/importerdesc.h>
|
||||||
|
@ -57,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <assimp/ProgressHandler.hpp>
|
#include <assimp/ProgressHandler.hpp>
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
|
@ -73,6 +69,21 @@ inline void Throw_ConvertFail_Str2ArrF(const std::string &nodeName, const std::s
|
||||||
"\" from string to array of floats.");
|
"\" from string to array of floats.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void Throw_ConvertFail_Str2ArrD(const std::string &nodeName, const std::string &pAttrValue) {
|
||||||
|
throw DeadlyImportError("In <" + nodeName + "> failed to convert attribute value \"" + pAttrValue +
|
||||||
|
"\" from string to array of doubles.");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Throw_ConvertFail_Str2ArrB(const std::string &nodeName, const std::string &pAttrValue) {
|
||||||
|
throw DeadlyImportError("In <" + nodeName + "> failed to convert attribute value \"" + pAttrValue +
|
||||||
|
"\" from string to array of booleans.");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Throw_ConvertFail_Str2ArrI(const std::string &nodeName, const std::string &pAttrValue) {
|
||||||
|
throw DeadlyImportError("In <" + nodeName + "> failed to convert attribute value \"" + pAttrValue +
|
||||||
|
"\" from string to array of integers.");
|
||||||
|
}
|
||||||
|
|
||||||
inline void Throw_DEF_And_USE(const std::string &nodeName) {
|
inline void Throw_DEF_And_USE(const std::string &nodeName) {
|
||||||
throw DeadlyImportError("\"DEF\" and \"USE\" can not be defined both in <" + nodeName + ">.");
|
throw DeadlyImportError("\"DEF\" and \"USE\" can not be defined both in <" + nodeName + ">.");
|
||||||
}
|
}
|
||||||
|
@ -230,61 +241,8 @@ inline void LogInfo(const std::string &message) {
|
||||||
///
|
///
|
||||||
/// That's all for now. Enjoy
|
/// That's all for now. Enjoy
|
||||||
///
|
///
|
||||||
enum class X3DElemType {
|
|
||||||
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.
|
using X3DElementList = std::list<X3DNodeElementBase *>;
|
||||||
};
|
|
||||||
|
|
||||||
struct X3DNodeElementBase {
|
|
||||||
X3DNodeElementBase *Parent;
|
|
||||||
std::string ID;
|
|
||||||
std::list<X3DNodeElementBase *> Child;
|
|
||||||
X3DElemType Type;
|
|
||||||
};
|
|
||||||
|
|
||||||
class X3DImporter : public BaseImporter {
|
class X3DImporter : public BaseImporter {
|
||||||
public:
|
public:
|
||||||
|
@ -312,8 +270,112 @@ public:
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
X3DNodeElementBase *MACRO_USE_CHECKANDAPPLY(XmlNode &node, std::string pDEF, std::string pUSE, X3DElemType pType, X3DNodeElementBase *pNE);
|
||||||
|
bool isNodeEmpty(XmlNode &node);
|
||||||
|
void checkNodeMustBeEmpty(XmlNode &node);
|
||||||
|
void skipUnsupportedNode(const std::string &pParentNodeName, XmlNode &node);
|
||||||
|
void readHead(XmlNode &node);
|
||||||
|
void readChildNodes(XmlNode &node, const std::string &pParentNodeName);
|
||||||
|
void readScene(XmlNode &node);
|
||||||
|
|
||||||
|
bool FindNodeElement_FromRoot(const std::string &pID, const X3DElemType pType, X3DNodeElementBase **pElement);
|
||||||
|
bool FindNodeElement_FromNode(X3DNodeElementBase *pStartNode, const std::string &pID,
|
||||||
|
const X3DElemType pType, X3DNodeElementBase **pElement);
|
||||||
|
bool FindNodeElement(const std::string &pID, const X3DElemType pType, X3DNodeElementBase **pElement);
|
||||||
|
void ParseHelper_Group_Begin(const bool pStatic = false);
|
||||||
|
void ParseHelper_Node_Enter(X3DNodeElementBase *pNode);
|
||||||
|
void ParseHelper_Node_Exit();
|
||||||
|
|
||||||
|
// 2D geometry
|
||||||
|
void readArc2D(XmlNode &node);
|
||||||
|
void readArcClose2D(XmlNode &node);
|
||||||
|
void readCircle2D(XmlNode &node);
|
||||||
|
void readDisk2D(XmlNode &node);
|
||||||
|
void readPolyline2D(XmlNode &node);
|
||||||
|
void readPolypoint2D(XmlNode &node);
|
||||||
|
void readRectangle2D(XmlNode &node);
|
||||||
|
void readTriangleSet2D(XmlNode &node);
|
||||||
|
|
||||||
|
// 3D geometry
|
||||||
|
void readBox(XmlNode &node);
|
||||||
|
void readCone(XmlNode &node);
|
||||||
|
void readCylinder(XmlNode &node);
|
||||||
|
void readElevationGrid(XmlNode &node);
|
||||||
|
void readExtrusion(XmlNode &node);
|
||||||
|
void readIndexedFaceSet(XmlNode &node);
|
||||||
|
void readSphere(XmlNode &node);
|
||||||
|
|
||||||
|
// group
|
||||||
|
void startReadGroup(XmlNode &node);
|
||||||
|
void endReadGroup();
|
||||||
|
void startReadStaticGroup(XmlNode &node);
|
||||||
|
void endReadStaticGroup();
|
||||||
|
void startReadSwitch(XmlNode &node);
|
||||||
|
void endReadSwitch();
|
||||||
|
void startReadTransform(XmlNode &node);
|
||||||
|
void endReadTransform();
|
||||||
|
|
||||||
|
// light
|
||||||
|
void readDirectionalLight(XmlNode &node);
|
||||||
|
void readPointLight(XmlNode &node);
|
||||||
|
void readSpotLight(XmlNode &node);
|
||||||
|
|
||||||
|
// metadata
|
||||||
|
bool checkForMetadataNode(XmlNode &node);
|
||||||
|
void childrenReadMetadata(XmlNode &node, X3DNodeElementBase *pParentElement, const std::string &pNodeName);
|
||||||
|
void readMetadataBoolean(XmlNode &node);
|
||||||
|
void readMetadataDouble(XmlNode &node);
|
||||||
|
void readMetadataFloat(XmlNode &node);
|
||||||
|
void readMetadataInteger(XmlNode &node);
|
||||||
|
void readMetadataSet(XmlNode &node);
|
||||||
|
void readMetadataString(XmlNode &node);
|
||||||
|
|
||||||
|
// networking
|
||||||
|
void readInline(XmlNode &node);
|
||||||
|
|
||||||
|
// postprocessing
|
||||||
|
aiMatrix4x4 PostprocessHelper_Matrix_GlobalToCurrent() const;
|
||||||
|
void PostprocessHelper_CollectMetadata(const X3DNodeElementBase &pNodeElement, std::list<X3DNodeElementBase *> &pList) const;
|
||||||
|
bool PostprocessHelper_ElementIsMetadata(const X3DElemType pType) const;
|
||||||
|
bool PostprocessHelper_ElementIsMesh(const X3DElemType pType) const;
|
||||||
|
void Postprocess_BuildLight(const X3DNodeElementBase &pNodeElement, std::list<aiLight *> &pSceneLightList) const;
|
||||||
|
void Postprocess_BuildMaterial(const X3DNodeElementBase &pNodeElement, aiMaterial **pMaterial) const;
|
||||||
|
void Postprocess_BuildMesh(const X3DNodeElementBase &pNodeElement, aiMesh **pMesh) const;
|
||||||
|
void Postprocess_BuildNode(const X3DNodeElementBase &pNodeElement, aiNode &pSceneNode, std::list<aiMesh *> &pSceneMeshList,
|
||||||
|
std::list<aiMaterial *> &pSceneMaterialList, std::list<aiLight *> &pSceneLightList) const;
|
||||||
|
void Postprocess_BuildShape(const X3DNodeElementShape &pShapeNodeElement, std::list<unsigned int> &pNodeMeshInd,
|
||||||
|
std::list<aiMesh *> &pSceneMeshList, std::list<aiMaterial *> &pSceneMaterialList) const;
|
||||||
|
void Postprocess_CollectMetadata(const X3DNodeElementBase &pNodeElement, aiNode &pSceneNode) const;
|
||||||
|
|
||||||
|
// rendering
|
||||||
|
void readColor(XmlNode &node);
|
||||||
|
void readColorRGBA(XmlNode &node);
|
||||||
|
void readCoordinate(XmlNode &node);
|
||||||
|
void readIndexedLineSet(XmlNode &node);
|
||||||
|
void readIndexedTriangleFanSet(XmlNode &node);
|
||||||
|
void readIndexedTriangleSet(XmlNode &node);
|
||||||
|
void readIndexedTriangleStripSet(XmlNode &node);
|
||||||
|
void readLineSet(XmlNode &node);
|
||||||
|
void readPointSet(XmlNode &node);
|
||||||
|
void readTriangleFanSet(XmlNode &node);
|
||||||
|
void readTriangleSet(XmlNode &node);
|
||||||
|
void readTriangleStripSet(XmlNode &node);
|
||||||
|
void readNormal(XmlNode &node);
|
||||||
|
|
||||||
|
// shape
|
||||||
|
void readShape(XmlNode &node);
|
||||||
|
void readAppearance(XmlNode &node);
|
||||||
|
void readMaterial(XmlNode &node);
|
||||||
|
|
||||||
|
// texturing
|
||||||
|
void readImageTexture(XmlNode &node);
|
||||||
|
void readTextureCoordinate(XmlNode &node);
|
||||||
|
void readTextureTransform(XmlNode &node);
|
||||||
|
|
||||||
static const aiImporterDesc Description;
|
static const aiImporterDesc Description;
|
||||||
X3DNodeElementBase *mNodeElementCur; ///< Current element.
|
X3DNodeElementBase *mNodeElementCur;
|
||||||
|
aiScene *mScene;
|
||||||
|
IOSystem *mpIOHandler;
|
||||||
}; // class X3DImporter
|
}; // class X3DImporter
|
||||||
|
|
||||||
} // namespace Assimp
|
} // namespace Assimp
|
||||||
|
|
|
@ -0,0 +1,467 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2019, 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 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
|
||||||
|
|
||||||
|
#include "X3DImporter.hpp"
|
||||||
|
#include "X3DImporter_Macro.hpp"
|
||||||
|
#include "X3DXmlHelper.h"
|
||||||
|
#include "X3DGeoHelper.h"
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
// <Arc2D
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// endAngle="1.570796" SFFloat [initializeOnly]
|
||||||
|
// radius="1" SFFloat [initializeOnly]
|
||||||
|
// startAngle="0" SFFloat [initializeOnly]
|
||||||
|
// />
|
||||||
|
// 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::readArc2D(XmlNode &node) {
|
||||||
|
std::string def, use;
|
||||||
|
float endAngle = AI_MATH_HALF_PI_F;
|
||||||
|
float radius = 1;
|
||||||
|
float startAngle = 0;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getFloatAttribute(node, "endAngle", endAngle);
|
||||||
|
XmlParser::getFloatAttribute(node, "radius", radius);
|
||||||
|
XmlParser::getFloatAttribute(node, "startAngle", startAngle);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Arc2D, ne);
|
||||||
|
} else {
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_Arc2D, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
// create point list of geometry object and convert it to line set.
|
||||||
|
std::list<aiVector3D> tlist;
|
||||||
|
|
||||||
|
X3DGeoHelper::make_arc2D(startAngle, endAngle, radius, 10, tlist); ///TODO: IME - AI_CONFIG for NumSeg
|
||||||
|
X3DGeoHelper::extend_point_to_line(tlist, ((X3DNodeElementGeometry2D *)ne)->Vertices);
|
||||||
|
((X3DNodeElementGeometry2D *)ne)->NumIndices = 2;
|
||||||
|
// check for X3DMetadataObject childs.
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "Arc2D");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <ArcClose2D
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// closureType="PIE" SFString [initializeOnly], {"PIE", "CHORD"}
|
||||||
|
// endAngle="1.570796" SFFloat [initializeOnly]
|
||||||
|
// radius="1" SFFloat [initializeOnly]
|
||||||
|
// solid="false" SFBool [initializeOnly]
|
||||||
|
// startAngle="0" SFFloat [initializeOnly]
|
||||||
|
// />
|
||||||
|
// 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::readArcClose2D(XmlNode &node) {
|
||||||
|
std::string def, use;
|
||||||
|
std::string closureType("PIE");
|
||||||
|
float endAngle = AI_MATH_HALF_PI_F;
|
||||||
|
float radius = 1;
|
||||||
|
bool solid = false;
|
||||||
|
float startAngle = 0;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getStdStrAttribute(node, "closureType", closureType);
|
||||||
|
XmlParser::getFloatAttribute(node, "endAngle", endAngle);
|
||||||
|
XmlParser::getFloatAttribute(node, "endAngle", endAngle);
|
||||||
|
XmlParser::getFloatAttribute(node, "radius", radius);
|
||||||
|
XmlParser::getBoolAttribute(node, "solid", solid);
|
||||||
|
XmlParser::getFloatAttribute(node, "startAngle", startAngle);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_ArcClose2D, ne);
|
||||||
|
} else {
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_ArcClose2D, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
((X3DNodeElementGeometry2D *)ne)->Solid = solid;
|
||||||
|
// create point list of geometry object.
|
||||||
|
X3DGeoHelper::make_arc2D(startAngle, endAngle, radius, 10, ((X3DNodeElementGeometry2D *)ne)->Vertices); ///TODO: IME - AI_CONFIG for NumSeg
|
||||||
|
// add chord or two radiuses only if not a circle was defined
|
||||||
|
if (!((std::fabs(endAngle - startAngle) >= AI_MATH_TWO_PI_F) || (endAngle == startAngle))) {
|
||||||
|
std::list<aiVector3D> &vlist = ((X3DNodeElementGeometry2D *)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("ArcClose2D", "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).
|
||||||
|
}
|
||||||
|
|
||||||
|
((X3DNodeElementGeometry2D *)ne)->NumIndices = ((X3DNodeElementGeometry2D *)ne)->Vertices.size();
|
||||||
|
// check for X3DMetadataObject childs.
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "ArcClose2D");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <Circle2D
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// radius="1" SFFloat [initializeOnly]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readCircle2D(XmlNode &node) {
|
||||||
|
std::string def, use;
|
||||||
|
float radius = 1;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getFloatAttribute(node, "radius", radius);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Circle2D, ne);
|
||||||
|
} else {
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_Circle2D, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
// create point list of geometry object and convert it to line set.
|
||||||
|
std::list<aiVector3D> tlist;
|
||||||
|
|
||||||
|
X3DGeoHelper::make_arc2D(0, 0, radius, 10, tlist); ///TODO: IME - AI_CONFIG for NumSeg
|
||||||
|
X3DGeoHelper::extend_point_to_line(tlist, ((X3DNodeElementGeometry2D *)ne)->Vertices);
|
||||||
|
((X3DNodeElementGeometry2D *)ne)->NumIndices = 2;
|
||||||
|
// check for X3DMetadataObject childs.
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "Circle2D");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <Disk2D
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// innerRadius="0" SFFloat [initializeOnly]
|
||||||
|
// outerRadius="1" SFFloat [initializeOnly]
|
||||||
|
// solid="false" SFBool [initializeOnly]
|
||||||
|
// />
|
||||||
|
// 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::readDisk2D(XmlNode &node) {
|
||||||
|
std::string def, use;
|
||||||
|
float innerRadius = 0;
|
||||||
|
float outerRadius = 1;
|
||||||
|
bool solid = false;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getFloatAttribute(node, "innerRadius", innerRadius);
|
||||||
|
XmlParser::getFloatAttribute(node, "outerRadius", outerRadius);
|
||||||
|
XmlParser::getBoolAttribute(node, "solid", solid);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Disk2D, ne);
|
||||||
|
} else {
|
||||||
|
std::list<aiVector3D> tlist_o, tlist_i;
|
||||||
|
|
||||||
|
if (innerRadius > outerRadius) Throw_IncorrectAttrValue("Disk2D", "innerRadius");
|
||||||
|
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_Disk2D, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
// create point list of geometry object.
|
||||||
|
///TODO: IME - AI_CONFIG for NumSeg
|
||||||
|
X3DGeoHelper::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.
|
||||||
|
((X3DNodeElementGeometry2D *)ne)->Vertices = tlist_o;
|
||||||
|
((X3DNodeElementGeometry2D *)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.
|
||||||
|
X3DGeoHelper::extend_point_to_line(tlist_o, ((X3DNodeElementGeometry2D *)ne)->Vertices);
|
||||||
|
((X3DNodeElementGeometry2D *)ne)->NumIndices = 2;
|
||||||
|
} else { // make disk
|
||||||
|
std::list<aiVector3D> &vlist = ((X3DNodeElementGeometry2D *)ne)->Vertices; // just short alias.
|
||||||
|
|
||||||
|
X3DGeoHelper::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<aiVector3D>::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
|
||||||
|
|
||||||
|
((X3DNodeElementGeometry2D *)ne)->NumIndices = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
((X3DNodeElementGeometry2D *)ne)->Solid = solid;
|
||||||
|
// check for X3DMetadataObject childs.
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "Disk2D");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <Polyline2D
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// lineSegments="" MFVec2F [intializeOnly]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readPolyline2D(XmlNode &node) {
|
||||||
|
std::string def, use;
|
||||||
|
std::list<aiVector2D> lineSegments;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
X3DXmlHelper::getVector2DListAttribute(node, "lineSegments", lineSegments);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Polyline2D, ne);
|
||||||
|
} else {
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_Polyline2D, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
//
|
||||||
|
// convert read point list of geometry object to line set.
|
||||||
|
//
|
||||||
|
std::list<aiVector3D> tlist;
|
||||||
|
|
||||||
|
// convert vec2 to vec3
|
||||||
|
for (std::list<aiVector2D>::iterator it2 = lineSegments.begin(); it2 != lineSegments.end(); ++it2)
|
||||||
|
tlist.push_back(aiVector3D(it2->x, it2->y, 0));
|
||||||
|
|
||||||
|
// convert point set to line set
|
||||||
|
X3DGeoHelper::extend_point_to_line(tlist, ((X3DNodeElementGeometry2D *)ne)->Vertices);
|
||||||
|
((X3DNodeElementGeometry2D *)ne)->NumIndices = 2;
|
||||||
|
// check for X3DMetadataObject childs.
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "Polyline2D");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <Polypoint2D
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// point="" MFVec2F [inputOutput]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readPolypoint2D(XmlNode &node) {
|
||||||
|
std::string def, use;
|
||||||
|
std::list<aiVector2D> point;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
X3DXmlHelper::getVector2DListAttribute(node, "point", point);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Polypoint2D, ne);
|
||||||
|
} else {
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_Polypoint2D, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
// convert vec2 to vec3
|
||||||
|
for (std::list<aiVector2D>::iterator it2 = point.begin(); it2 != point.end(); ++it2) {
|
||||||
|
((X3DNodeElementGeometry2D *)ne)->Vertices.push_back(aiVector3D(it2->x, it2->y, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
((X3DNodeElementGeometry2D *)ne)->NumIndices = 1;
|
||||||
|
// check for X3DMetadataObject childs.
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "Polypoint2D");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <Rectangle2D
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// size="2 2" SFVec2f [initializeOnly]
|
||||||
|
// solid="false" SFBool [initializeOnly]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readRectangle2D(XmlNode &node) {
|
||||||
|
std::string def, use;
|
||||||
|
aiVector2D size(2, 2);
|
||||||
|
bool solid = false;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
X3DXmlHelper::getVector2DAttribute(node, "size", size);
|
||||||
|
XmlParser::getBoolAttribute(node, "solid", solid);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Rectangle2D, ne);
|
||||||
|
} else {
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_Rectangle2D, mNodeElementCur);
|
||||||
|
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<aiVector3D> &vlist = ((X3DNodeElementGeometry2D *)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
|
||||||
|
((X3DNodeElementGeometry2D *)ne)->Solid = solid;
|
||||||
|
((X3DNodeElementGeometry2D *)ne)->NumIndices = 4;
|
||||||
|
// check for X3DMetadataObject childs.
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "Rectangle2D");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <TriangleSet2D
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// solid="false" SFBool [initializeOnly]
|
||||||
|
// vertices="" MFVec2F [inputOutput]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readTriangleSet2D(XmlNode &node) {
|
||||||
|
std::string def, use;
|
||||||
|
bool solid = false;
|
||||||
|
std::list<aiVector2D> vertices;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
X3DXmlHelper::getVector2DListAttribute(node, "vertices", vertices);
|
||||||
|
XmlParser::getBoolAttribute(node, "solid", solid);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, 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 X3DNodeElementGeometry2D(X3DElemType::ENET_TriangleSet2D, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
// convert vec2 to vec3
|
||||||
|
for (std::list<aiVector2D>::iterator it2 = vertices.begin(); it2 != vertices.end(); ++it2) {
|
||||||
|
((X3DNodeElementGeometry2D *)ne)->Vertices.push_back(aiVector3D(it2->x, it2->y, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
((X3DNodeElementGeometry2D *)ne)->Solid = solid;
|
||||||
|
((X3DNodeElementGeometry2D *)ne)->NumIndices = 3;
|
||||||
|
// check for X3DMetadataObject childs.
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "TriangleSet2D");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
|
@ -0,0 +1,918 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2019, 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 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 "X3DGeoHelper.h"
|
||||||
|
#include "X3DImporter.hpp"
|
||||||
|
#include "X3DImporter_Macro.hpp"
|
||||||
|
#include "X3DXmlHelper.h"
|
||||||
|
|
||||||
|
// Header files, Assimp.
|
||||||
|
#include <assimp/StandardShapes.h>
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
// <Box
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// size="2 2 2" SFVec3f [initializeOnly]
|
||||||
|
// solid="true" SFBool [initializeOnly]
|
||||||
|
// />
|
||||||
|
// 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::readBox(XmlNode &node) {
|
||||||
|
std::string def, use;
|
||||||
|
bool solid = true;
|
||||||
|
aiVector3D size(2, 2, 2);
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
X3DXmlHelper::getVector3DAttribute(node, "size", size);
|
||||||
|
XmlParser::getBoolAttribute(node, "solid", solid);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Box, ne);
|
||||||
|
} else {
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementGeometry3D(X3DElemType::ENET_Box, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
X3DGeoHelper::rect_parallel_epiped(size, ((X3DNodeElementGeometry3D *)ne)->Vertices); // get quad list
|
||||||
|
((X3DNodeElementGeometry3D *)ne)->Solid = solid;
|
||||||
|
((X3DNodeElementGeometry3D *)ne)->NumIndices = 4;
|
||||||
|
// check for X3DMetadataObject childs.
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "Box");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <Cone
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// bottom="true" SFBool [initializeOnly]
|
||||||
|
// bottomRadius="1" SFloat [initializeOnly]
|
||||||
|
// height="2" SFloat [initializeOnly]
|
||||||
|
// side="true" SFBool [initializeOnly]
|
||||||
|
// solid="true" SFBool [initializeOnly]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readCone(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
bool bottom = true;
|
||||||
|
float bottomRadius = 1;
|
||||||
|
float height = 2;
|
||||||
|
bool side = true;
|
||||||
|
bool solid = true;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getBoolAttribute(node, "solid", solid);
|
||||||
|
XmlParser::getBoolAttribute(node, "side", side);
|
||||||
|
XmlParser::getBoolAttribute(node, "bottom", bottom);
|
||||||
|
XmlParser::getFloatAttribute(node, "height", height);
|
||||||
|
XmlParser::getFloatAttribute(node, "bottomRadius", bottomRadius);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Cone, ne);
|
||||||
|
} else {
|
||||||
|
const unsigned int tess = 30; ///TODO: IME tessellation factor through ai_property
|
||||||
|
|
||||||
|
std::vector<aiVector3D> tvec; // temp array for vertices.
|
||||||
|
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementGeometry3D(X3DElemType::ENET_Cone, mNodeElementCur);
|
||||||
|
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<aiVector3D>::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<aiVector3D>::iterator it = tvec.begin(); it != tvec.end(); ++it)
|
||||||
|
((X3DNodeElementGeometry3D *)ne)->Vertices.push_back(*it);
|
||||||
|
|
||||||
|
((X3DNodeElementGeometry3D *)ne)->Solid = solid;
|
||||||
|
((X3DNodeElementGeometry3D *)ne)->NumIndices = 3;
|
||||||
|
// check for X3DMetadataObject childs.
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "Cone");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <Cylinder
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// bottom="true" SFBool [initializeOnly]
|
||||||
|
// height="2" SFloat [initializeOnly]
|
||||||
|
// radius="1" SFloat [initializeOnly]
|
||||||
|
// side="true" SFBool [initializeOnly]
|
||||||
|
// solid="true" SFBool [initializeOnly]
|
||||||
|
// top="true" SFBool [initializeOnly]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readCylinder(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
bool bottom = true;
|
||||||
|
float height = 2;
|
||||||
|
float radius = 1;
|
||||||
|
bool side = true;
|
||||||
|
bool solid = true;
|
||||||
|
bool top = true;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getFloatAttribute(node, "radius", radius);
|
||||||
|
XmlParser::getBoolAttribute(node, "solid", solid);
|
||||||
|
XmlParser::getBoolAttribute(node, "bottom", bottom);
|
||||||
|
XmlParser::getBoolAttribute(node, "top", top);
|
||||||
|
XmlParser::getBoolAttribute(node, "side", side);
|
||||||
|
XmlParser::getFloatAttribute(node, "height", height);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Cylinder, ne);
|
||||||
|
} else {
|
||||||
|
const unsigned int tess = 30; ///TODO: IME tessellation factor through ai_property
|
||||||
|
|
||||||
|
std::vector<aiVector3D> tside; // temp array for vertices of side.
|
||||||
|
std::vector<aiVector3D> tcir; // temp array for vertices of circle.
|
||||||
|
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementGeometry3D(X3DElemType::ENET_Cylinder, mNodeElementCur);
|
||||||
|
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<aiVector3D> &vlist = ((X3DNodeElementGeometry3D *)ne)->Vertices; // just short alias.
|
||||||
|
|
||||||
|
for (std::vector<aiVector3D>::iterator it = tside.begin(); it != tside.end(); ++it)
|
||||||
|
vlist.push_back(*it);
|
||||||
|
|
||||||
|
if (top) {
|
||||||
|
for (std::vector<aiVector3D>::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<aiVector3D>::iterator it = tcir.begin(); it != tcir.end(); ++it) {
|
||||||
|
(*it).y = -height; // y - because circle made in oXZ.
|
||||||
|
vlist.push_back(*it);
|
||||||
|
}
|
||||||
|
} // if(top)
|
||||||
|
|
||||||
|
((X3DNodeElementGeometry3D *)ne)->Solid = solid;
|
||||||
|
((X3DNodeElementGeometry3D *)ne)->NumIndices = 3;
|
||||||
|
// check for X3DMetadataObject childs.
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "Cylinder");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <ElevationGrid
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// ccw="true" SFBool [initializeOnly]
|
||||||
|
// colorPerVertex="true" SFBool [initializeOnly]
|
||||||
|
// creaseAngle="0" SFloat [initializeOnly]
|
||||||
|
// height="" MFloat [initializeOnly]
|
||||||
|
// normalPerVertex="true" SFBool [initializeOnly]
|
||||||
|
// solid="true" SFBool [initializeOnly]
|
||||||
|
// xDimension="0" SFInt32 [initializeOnly]
|
||||||
|
// xSpacing="1.0" SFloat [initializeOnly]
|
||||||
|
// zDimension="0" SFInt32 [initializeOnly]
|
||||||
|
// zSpacing="1.0" SFloat [initializeOnly]
|
||||||
|
// >
|
||||||
|
// <!-- ColorNormalTexCoordContentModel -->
|
||||||
|
// 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.
|
||||||
|
// </ElevationGrid>
|
||||||
|
// 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::readElevationGrid(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
bool ccw = true;
|
||||||
|
bool colorPerVertex = true;
|
||||||
|
float creaseAngle = 0;
|
||||||
|
std::vector<float> height;
|
||||||
|
bool normalPerVertex = true;
|
||||||
|
bool solid = true;
|
||||||
|
int32_t xDimension = 0;
|
||||||
|
float xSpacing = 1;
|
||||||
|
int32_t zDimension = 0;
|
||||||
|
float zSpacing = 1;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getBoolAttribute(node, "solid", solid);
|
||||||
|
XmlParser::getBoolAttribute(node, "ccw", ccw);
|
||||||
|
XmlParser::getBoolAttribute(node, "colorPerVertex", colorPerVertex);
|
||||||
|
XmlParser::getBoolAttribute(node, "normalPerVertex", normalPerVertex);
|
||||||
|
XmlParser::getFloatAttribute(node, "creaseAngle", creaseAngle);
|
||||||
|
X3DXmlHelper::getFloatArrayAttribute(node, "height", height);
|
||||||
|
XmlParser::getIntAttribute(node, "xDimension", xDimension);
|
||||||
|
XmlParser::getFloatAttribute(node, "xSpacing", xSpacing);
|
||||||
|
XmlParser::getIntAttribute(node, "zDimension", zDimension);
|
||||||
|
XmlParser::getFloatAttribute(node, "zSpacing", zSpacing);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_ElevationGrid, ne);
|
||||||
|
} else {
|
||||||
|
if ((xSpacing == 0.0f) || (zSpacing == 0.0f)) throw DeadlyImportError("Spacing in <ElevationGrid> must be grater than zero.");
|
||||||
|
if ((xDimension <= 0) || (zDimension <= 0)) throw DeadlyImportError("Dimension in <ElevationGrid> must be grater than zero.");
|
||||||
|
if ((size_t)(xDimension * zDimension) != height.size()) DeadlyImportError("Heights count must be equal to \"xDimension * zDimension\" in <ElevationGrid>");
|
||||||
|
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementElevationGrid(X3DElemType::ENET_ElevationGrid, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
X3DNodeElementElevationGrid &grid_alias = *((X3DNodeElementElevationGrid *)ne); // create alias for conveience
|
||||||
|
|
||||||
|
{ // create grid vertices list
|
||||||
|
std::vector<float>::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.
|
||||||
|
{
|
||||||
|
((X3DNodeElementElevationGrid *)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(static_cast<int32_t>(i));
|
||||||
|
grid_alias.CoordIdx.push_back(static_cast<int32_t>(i + 1));
|
||||||
|
grid_alias.CoordIdx.push_back(-1);
|
||||||
|
}
|
||||||
|
} else // two or more elements in every dimension is set. create quad set.
|
||||||
|
{
|
||||||
|
((X3DNodeElementElevationGrid *)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 (!isNodeEmpty(node)) {
|
||||||
|
ParseHelper_Node_Enter(ne);
|
||||||
|
for (auto currentChildNode : node.children()) {
|
||||||
|
const std::string ¤tChildName = currentChildNode.name();
|
||||||
|
// check for X3DComposedGeometryNodes
|
||||||
|
if (currentChildName == "Color")
|
||||||
|
readColor(currentChildNode);
|
||||||
|
else if (currentChildName == "ColorRGBA")
|
||||||
|
readColorRGBA(currentChildNode);
|
||||||
|
else if (currentChildName == "Normal")
|
||||||
|
readNormal(currentChildNode);
|
||||||
|
else if (currentChildName == "TextureCoordinate")
|
||||||
|
readTextureCoordinate(currentChildNode);
|
||||||
|
// check for X3DMetadataObject
|
||||||
|
else if (!checkForMetadataNode(currentChildNode))
|
||||||
|
skipUnsupportedNode("ElevationGrid", currentChildNode);
|
||||||
|
}
|
||||||
|
ParseHelper_Node_Exit();
|
||||||
|
} // if(!mReader->isEmptyElement())
|
||||||
|
else {
|
||||||
|
mNodeElementCur->Children.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 <typename TVector>
|
||||||
|
static void GeometryHelper_Extrusion_CurveIsClosed(std::vector<TVector> &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<aiVector3D> &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 dropping 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<aiVector3D> &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 through 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
// <Extrusion
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// beginCap="true" SFBool [initializeOnly]
|
||||||
|
// ccw="true" SFBool [initializeOnly]
|
||||||
|
// convex="true" SFBool [initializeOnly]
|
||||||
|
// creaseAngle="0.0" SFloat [initializeOnly]
|
||||||
|
// crossSection="1 1 1 -1 -1 -1 -1 1 1 1" MFVec2f [initializeOnly]
|
||||||
|
// endCap="true" SFBool [initializeOnly]
|
||||||
|
// orientation="0 0 1 0" MFRotation [initializeOnly]
|
||||||
|
// scale="1 1" MFVec2f [initializeOnly]
|
||||||
|
// solid="true" SFBool [initializeOnly]
|
||||||
|
// spine="0 0 0 0 1 0" MFVec3f [initializeOnly]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readExtrusion(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
bool beginCap = true;
|
||||||
|
bool ccw = true;
|
||||||
|
bool convex = true;
|
||||||
|
float creaseAngle = 0;
|
||||||
|
std::vector<aiVector2D> crossSection;
|
||||||
|
bool endCap = true;
|
||||||
|
std::vector<float> orientation;
|
||||||
|
std::vector<aiVector2D> scale;
|
||||||
|
bool solid = true;
|
||||||
|
std::vector<aiVector3D> spine;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getBoolAttribute(node, "beginCap", beginCap);
|
||||||
|
XmlParser::getBoolAttribute(node, "ccw", ccw);
|
||||||
|
XmlParser::getBoolAttribute(node, "convex", convex);
|
||||||
|
XmlParser::getFloatAttribute(node, "creaseAngle", creaseAngle);
|
||||||
|
X3DXmlHelper::getVector2DArrayAttribute(node, "crossSection", crossSection);
|
||||||
|
XmlParser::getBoolAttribute(node, "endCap", endCap);
|
||||||
|
X3DXmlHelper::getFloatArrayAttribute(node, "orientation", orientation);
|
||||||
|
X3DXmlHelper::getVector2DArrayAttribute(node, "scale", scale);
|
||||||
|
XmlParser::getBoolAttribute(node, "solid", solid);
|
||||||
|
X3DXmlHelper::getVector3DArrayAttribute(node, "spine", spine);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, 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 <Extrusion> 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 X3DNodeElementIndexedSet(X3DElemType::ENET_Extrusion, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
X3DNodeElementIndexedSet &ext_alias = *((X3DNodeElementIndexedSet *)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, transferred 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<aiMatrix3x3> basis_arr; // array of basises. ROW_a - X, ROW_b - Y, ROW_c - Z.
|
||||||
|
std::vector<std::vector<aiVector3D>> 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<aiVector3D> 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 transferred 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(static_cast<int32_t>(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(static_cast<int32_t>(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,
|
||||||
|
static_cast<int32_t>(spi * cr_sz + cri),
|
||||||
|
static_cast<int32_t>(right_col * cr_sz + cri),
|
||||||
|
static_cast<int32_t>(right_col * cr_sz + cri + 1),
|
||||||
|
static_cast<int32_t>(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,
|
||||||
|
static_cast<int32_t>(spi * cr_sz + cri),
|
||||||
|
static_cast<int32_t>(right_col * cr_sz + cri),
|
||||||
|
static_cast<int32_t>(right_col * cr_sz + 0),
|
||||||
|
static_cast<int32_t>(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.emplace_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 (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "Extrusion");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <IndexedFaceSet
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// ccw="true" SFBool [initializeOnly]
|
||||||
|
// colorIndex="" MFInt32 [initializeOnly]
|
||||||
|
// colorPerVertex="true" SFBool [initializeOnly]
|
||||||
|
// convex="true" SFBool [initializeOnly]
|
||||||
|
// coordIndex="" MFInt32 [initializeOnly]
|
||||||
|
// creaseAngle="0" SFFloat [initializeOnly]
|
||||||
|
// normalIndex="" MFInt32 [initializeOnly]
|
||||||
|
// normalPerVertex="true" SFBool [initializeOnly]
|
||||||
|
// solid="true" SFBool [initializeOnly]
|
||||||
|
// texCoordIndex="" MFInt32 [initializeOnly]
|
||||||
|
// >
|
||||||
|
// <!-- ComposedGeometryContentModel -->
|
||||||
|
// 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.
|
||||||
|
// </IndexedFaceSet>
|
||||||
|
void X3DImporter::readIndexedFaceSet(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
bool ccw = true;
|
||||||
|
std::vector<int32_t> colorIndex;
|
||||||
|
bool colorPerVertex = true;
|
||||||
|
bool convex = true;
|
||||||
|
std::vector<int32_t> coordIndex;
|
||||||
|
float creaseAngle = 0;
|
||||||
|
std::vector<int32_t> normalIndex;
|
||||||
|
bool normalPerVertex = true;
|
||||||
|
bool solid = true;
|
||||||
|
std::vector<int32_t> texCoordIndex;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getBoolAttribute(node, "ccw", ccw);
|
||||||
|
X3DXmlHelper::getInt32ArrayAttribute(node, "colorIndex", colorIndex);
|
||||||
|
XmlParser::getBoolAttribute(node, "colorPerVertex", colorPerVertex);
|
||||||
|
XmlParser::getBoolAttribute(node, "convex", convex);
|
||||||
|
X3DXmlHelper::getInt32ArrayAttribute(node, "coordIndex", coordIndex);
|
||||||
|
XmlParser::getFloatAttribute(node, "creaseAngle", creaseAngle);
|
||||||
|
X3DXmlHelper::getInt32ArrayAttribute(node, "normalIndex", normalIndex);
|
||||||
|
XmlParser::getBoolAttribute(node, "normalPerVertex", normalPerVertex);
|
||||||
|
XmlParser::getBoolAttribute(node, "solid", solid);
|
||||||
|
X3DXmlHelper::getInt32ArrayAttribute(node, "texCoordIndex", texCoordIndex);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, 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 X3DNodeElementIndexedSet(X3DElemType::ENET_IndexedFaceSet, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
X3DNodeElementIndexedSet &ne_alias = *((X3DNodeElementIndexedSet *)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 (!isNodeEmpty(node)) {
|
||||||
|
ParseHelper_Node_Enter(ne);
|
||||||
|
for (auto currentChildNode : node.children()) {
|
||||||
|
const std::string ¤tChildName = currentChildNode.name();
|
||||||
|
// check for X3DComposedGeometryNodes
|
||||||
|
if (currentChildName == "Color")
|
||||||
|
readColor(currentChildNode);
|
||||||
|
else if (currentChildName == "ColorRGBA")
|
||||||
|
readColorRGBA(currentChildNode);
|
||||||
|
else if (currentChildName == "Coordinate")
|
||||||
|
readCoordinate(currentChildNode);
|
||||||
|
else if (currentChildName == "Normal")
|
||||||
|
readNormal(currentChildNode);
|
||||||
|
else if (currentChildName == "TextureCoordinate")
|
||||||
|
readTextureCoordinate(currentChildNode);
|
||||||
|
// check for X3DMetadataObject
|
||||||
|
else if (!checkForMetadataNode(currentChildNode))
|
||||||
|
skipUnsupportedNode("IndexedFaceSet", currentChildNode);
|
||||||
|
}
|
||||||
|
ParseHelper_Node_Exit();
|
||||||
|
} // if(!isNodeEmpty(node))
|
||||||
|
else {
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <Sphere
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// radius="1" SFloat [initializeOnly]
|
||||||
|
// solid="true" SFBool [initializeOnly]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readSphere(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
ai_real radius = 1;
|
||||||
|
bool solid = true;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getFloatAttribute(node, "radius", radius);
|
||||||
|
XmlParser::getBoolAttribute(node, "solid", solid);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Sphere, ne);
|
||||||
|
} else {
|
||||||
|
const unsigned int tess = 3; ///TODO: IME tessellation factor through ai_property
|
||||||
|
|
||||||
|
std::vector<aiVector3D> tlist;
|
||||||
|
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementGeometry3D(X3DElemType::ENET_Sphere, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
StandardShapes::MakeSphere(tess, tlist);
|
||||||
|
// copy data from temp array and apply scale
|
||||||
|
for (std::vector<aiVector3D>::iterator it = tlist.begin(); it != tlist.end(); ++it) {
|
||||||
|
aiVector3D v = *it;
|
||||||
|
((X3DNodeElementGeometry3D *)ne)->Vertices.emplace_back(v * radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
((X3DNodeElementGeometry3D *)ne)->Solid = solid;
|
||||||
|
((X3DNodeElementGeometry3D *)ne)->NumIndices = 3;
|
||||||
|
// check for X3DMetadataObject childs.
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "Sphere");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
|
@ -0,0 +1,272 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2019, 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 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
|
||||||
|
|
||||||
|
#include "X3DImporter.hpp"
|
||||||
|
#include "X3DImporter_Macro.hpp"
|
||||||
|
#include "X3DXmlHelper.h"
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
// <Group
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// bboxCenter="0 0 0" SFVec3f [initializeOnly]
|
||||||
|
// bboxSize="-1 -1 -1" SFVec3f [initializeOnly]
|
||||||
|
// >
|
||||||
|
// <\!-- ChildContentModel -->
|
||||||
|
// 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.
|
||||||
|
// </Group>
|
||||||
|
// A Group node contains children nodes without introducing a new transformation. It is equivalent to a Transform node containing an identity transform.
|
||||||
|
void X3DImporter::startReadGroup(XmlNode &node) {
|
||||||
|
std::string def, use;
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
X3DNodeElementBase *ne = nullptr;
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, 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()) mNodeElementCur->ID = def;
|
||||||
|
// in grouping set of nodes check X3DMetadataObject is not needed, because it is done in <Scene> parser function.
|
||||||
|
|
||||||
|
// for empty element exit from node in that place
|
||||||
|
if (isNodeEmpty(node)) ParseHelper_Node_Exit();
|
||||||
|
} // if(!use.empty()) else
|
||||||
|
}
|
||||||
|
|
||||||
|
void X3DImporter::endReadGroup() {
|
||||||
|
ParseHelper_Node_Exit(); // go up in scene graph
|
||||||
|
}
|
||||||
|
|
||||||
|
// <StaticGroup
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// bboxCenter="0 0 0" SFVec3f [initializeOnly]
|
||||||
|
// bboxSize="-1 -1 -1" SFVec3f [initializeOnly]
|
||||||
|
// >
|
||||||
|
// <\!-- ChildContentModel -->
|
||||||
|
// 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.
|
||||||
|
// </StaticGroup>
|
||||||
|
// 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::startReadStaticGroup(XmlNode &node) {
|
||||||
|
std::string def, use;
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
X3DNodeElementBase *ne = nullptr;
|
||||||
|
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, 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()) mNodeElementCur->ID = def;
|
||||||
|
// in grouping set of nodes check X3DMetadataObject is not needed, because it is done in <Scene> parser function.
|
||||||
|
|
||||||
|
// for empty element exit from node in that place
|
||||||
|
if (isNodeEmpty(node)) ParseHelper_Node_Exit();
|
||||||
|
} // if(!use.empty()) else
|
||||||
|
}
|
||||||
|
|
||||||
|
void X3DImporter::endReadStaticGroup() {
|
||||||
|
ParseHelper_Node_Exit(); // go up in scene graph
|
||||||
|
}
|
||||||
|
|
||||||
|
// <Switch
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// bboxCenter="0 0 0" SFVec3f [initializeOnly]
|
||||||
|
// bboxSize="-1 -1 -1" SFVec3f [initializeOnly]
|
||||||
|
// whichChoice="-1" SFInt32 [inputOutput]
|
||||||
|
// >
|
||||||
|
// <\!-- ChildContentModel -->
|
||||||
|
// 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.
|
||||||
|
// </Switch>
|
||||||
|
// 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::startReadSwitch(XmlNode &node) {
|
||||||
|
std::string def, use;
|
||||||
|
int32_t whichChoice = -1;
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getIntAttribute(node, "whichChoice", whichChoice);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
X3DNodeElementBase *ne=nullptr;
|
||||||
|
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, 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()) mNodeElementCur->ID = def;
|
||||||
|
|
||||||
|
// also set values specific to this type of group
|
||||||
|
((X3DNodeElementGroup *)mNodeElementCur)->UseChoice = true;
|
||||||
|
((X3DNodeElementGroup *)mNodeElementCur)->Choice = whichChoice;
|
||||||
|
// in grouping set of nodes check X3DMetadataObject is not needed, because it is done in <Scene> parser function.
|
||||||
|
|
||||||
|
// for empty element exit from node in that place
|
||||||
|
if (isNodeEmpty(node)) ParseHelper_Node_Exit();
|
||||||
|
} // if(!use.empty()) else
|
||||||
|
}
|
||||||
|
|
||||||
|
void X3DImporter::endReadSwitch() {
|
||||||
|
// just exit from node. Defined choice will be accepted at postprocessing stage.
|
||||||
|
ParseHelper_Node_Exit(); // go up in scene graph
|
||||||
|
}
|
||||||
|
|
||||||
|
// <Transform
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// bboxCenter="0 0 0" SFVec3f [initializeOnly]
|
||||||
|
// bboxSize="-1 -1 -1" SFVec3f [initializeOnly]
|
||||||
|
// center="0 0 0" SFVec3f [inputOutput]
|
||||||
|
// rotation="0 0 1 0" SFRotation [inputOutput]
|
||||||
|
// scale="1 1 1" SFVec3f [inputOutput]
|
||||||
|
// scaleOrientation="0 0 1 0" SFRotation [inputOutput]
|
||||||
|
// translation="0 0 0" SFVec3f [inputOutput]
|
||||||
|
// >
|
||||||
|
// <\!-- ChildContentModel -->
|
||||||
|
// 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.
|
||||||
|
// </Transform>
|
||||||
|
// 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::startReadTransform(XmlNode &node) {
|
||||||
|
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_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
X3DXmlHelper::getVector3DAttribute(node, "center", center);
|
||||||
|
X3DXmlHelper::getVector3DAttribute(node, "scale", scale);
|
||||||
|
X3DXmlHelper::getVector3DAttribute(node, "translation", translation);
|
||||||
|
std::vector<float> tvec;
|
||||||
|
if (X3DXmlHelper::getFloatArrayAttribute(node, "rotation", tvec)) {
|
||||||
|
if (tvec.size() != 4) throw DeadlyImportError("<Transform>: rotation vector must have 4 elements.");
|
||||||
|
memcpy(rotation, tvec.data(), sizeof(rotation));
|
||||||
|
tvec.clear();
|
||||||
|
}
|
||||||
|
if (X3DXmlHelper::getFloatArrayAttribute(node, "scaleOrientation", tvec)) {
|
||||||
|
if (tvec.size() != 4) throw DeadlyImportError("<Transform>: scaleOrientation vector must have 4 elements.");
|
||||||
|
memcpy(scale_orientation, tvec.data(), sizeof(scale_orientation));
|
||||||
|
tvec.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, 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()) {
|
||||||
|
mNodeElementCur->ID = def;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// also set values specific to this type of group
|
||||||
|
//
|
||||||
|
// calculate transformation 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
|
||||||
|
((X3DNodeElementGroup *)mNodeElementCur)->Transformation = matr;
|
||||||
|
// in grouping set of nodes check X3DMetadataObject is not needed, because it is done in <Scene> parser function.
|
||||||
|
|
||||||
|
// for empty element exit from node in that place
|
||||||
|
if (isNodeEmpty(node)) {
|
||||||
|
ParseHelper_Node_Exit();
|
||||||
|
}
|
||||||
|
} // if(!use.empty()) else
|
||||||
|
}
|
||||||
|
|
||||||
|
void X3DImporter::endReadTransform() {
|
||||||
|
ParseHelper_Node_Exit(); // go up in scene graph
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Assimp
|
||||||
|
|
||||||
|
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER
|
|
@ -0,0 +1,270 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2019, 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 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 "X3DXmlHelper.h"
|
||||||
|
#include <assimp/StringUtils.h>
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
// <DirectionalLight
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// ambientIntensity="0" SFFloat [inputOutput]
|
||||||
|
// color="1 1 1" SFColor [inputOutput]
|
||||||
|
// direction="0 0 -1" SFVec3f [inputOutput]
|
||||||
|
// global="false" SFBool [inputOutput]
|
||||||
|
// intensity="1" SFFloat [inputOutput]
|
||||||
|
// on="true" SFBool [inputOutput]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readDirectionalLight(XmlNode &node) {
|
||||||
|
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;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getFloatAttribute(node, "ambientIntensity", ambientIntensity);
|
||||||
|
X3DXmlHelper::getColor3DAttribute(node, "color", color);
|
||||||
|
X3DXmlHelper::getVector3DAttribute(node, "direction", direction);
|
||||||
|
XmlParser::getBoolAttribute(node, "global", global);
|
||||||
|
XmlParser::getFloatAttribute(node, "intensity", intensity);
|
||||||
|
XmlParser::getBoolAttribute(node, "on", on);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_DirectionalLight, ne);
|
||||||
|
} else {
|
||||||
|
if (on) {
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementLight(X3DElemType::ENET_DirectionalLight, mNodeElementCur);
|
||||||
|
if (!def.empty())
|
||||||
|
ne->ID = def;
|
||||||
|
else
|
||||||
|
ne->ID = "DirectionalLight_" + ai_to_string((size_t)ne); // make random name
|
||||||
|
|
||||||
|
((X3DNodeElementLight *)ne)->AmbientIntensity = ambientIntensity;
|
||||||
|
((X3DNodeElementLight *)ne)->Color = color;
|
||||||
|
((X3DNodeElementLight *)ne)->Direction = direction;
|
||||||
|
((X3DNodeElementLight *)ne)->Global = global;
|
||||||
|
((X3DNodeElementLight *)ne)->Intensity = intensity;
|
||||||
|
// Assimp want a node with name similar to a light. "Why? I don't no." )
|
||||||
|
ParseHelper_Group_Begin(false);
|
||||||
|
|
||||||
|
mNodeElementCur->ID = ne->ID; // assign name to node and return to light element.
|
||||||
|
ParseHelper_Node_Exit();
|
||||||
|
// check for child nodes
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "DirectionalLight");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <PointLight
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// ambientIntensity="0" SFFloat [inputOutput]
|
||||||
|
// attenuation="1 0 0" SFVec3f [inputOutput]
|
||||||
|
// color="1 1 1" SFColor [inputOutput]
|
||||||
|
// global="true" SFBool [inputOutput]
|
||||||
|
// intensity="1" SFFloat [inputOutput]
|
||||||
|
// location="0 0 0" SFVec3f [inputOutput]
|
||||||
|
// on="true" SFBool [inputOutput]
|
||||||
|
// radius="100" SFFloat [inputOutput]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readPointLight(XmlNode &node) {
|
||||||
|
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;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getFloatAttribute(node, "ambientIntensity", ambientIntensity);
|
||||||
|
X3DXmlHelper::getVector3DAttribute(node, "attenuation", attenuation);
|
||||||
|
X3DXmlHelper::getColor3DAttribute(node, "color", color);
|
||||||
|
XmlParser::getBoolAttribute(node, "global", global);
|
||||||
|
XmlParser::getFloatAttribute(node, "intensity", intensity);
|
||||||
|
X3DXmlHelper::getVector3DAttribute(node, "location", location);
|
||||||
|
XmlParser::getBoolAttribute(node, "on", on);
|
||||||
|
XmlParser::getFloatAttribute(node, "radius", radius);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_PointLight, ne);
|
||||||
|
} else {
|
||||||
|
if (on) {
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementLight(X3DElemType::ENET_PointLight, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
((X3DNodeElementLight *)ne)->AmbientIntensity = ambientIntensity;
|
||||||
|
((X3DNodeElementLight *)ne)->Attenuation = attenuation;
|
||||||
|
((X3DNodeElementLight *)ne)->Color = color;
|
||||||
|
((X3DNodeElementLight *)ne)->Global = global;
|
||||||
|
((X3DNodeElementLight *)ne)->Intensity = intensity;
|
||||||
|
((X3DNodeElementLight *)ne)->Location = location;
|
||||||
|
((X3DNodeElementLight *)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 = "PointLight_" + ai_to_string((size_t)ne);
|
||||||
|
|
||||||
|
mNodeElementCur->ID = ne->ID; // assign name to node and return to light element.
|
||||||
|
ParseHelper_Node_Exit();
|
||||||
|
// check for child nodes
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "PointLight");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <SpotLight
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// ambientIntensity="0" SFFloat [inputOutput]
|
||||||
|
// attenuation="1 0 0" SFVec3f [inputOutput]
|
||||||
|
// beamWidth="0.7854" SFFloat [inputOutput]
|
||||||
|
// color="1 1 1" SFColor [inputOutput]
|
||||||
|
// cutOffAngle="1.570796" SFFloat [inputOutput]
|
||||||
|
// direction="0 0 -1" SFVec3f [inputOutput]
|
||||||
|
// global="true" SFBool [inputOutput]
|
||||||
|
// intensity="1" SFFloat [inputOutput]
|
||||||
|
// location="0 0 0" SFVec3f [inputOutput]
|
||||||
|
// on="true" SFBool [inputOutput]
|
||||||
|
// radius="100" SFFloat [inputOutput]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readSpotLight(XmlNode &node) {
|
||||||
|
std::string def, use;
|
||||||
|
float ambientIntensity = 0;
|
||||||
|
aiVector3D attenuation(1, 0, 0);
|
||||||
|
float beamWidth = 0.7854f;
|
||||||
|
aiColor3D color(1, 1, 1);
|
||||||
|
float cutOffAngle = 1.570796f;
|
||||||
|
aiVector3D direction(0, 0, -1);
|
||||||
|
bool global = true;
|
||||||
|
float intensity = 1;
|
||||||
|
aiVector3D location(0, 0, 0);
|
||||||
|
bool on = true;
|
||||||
|
float radius = 100;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getFloatAttribute(node, "ambientIntensity", ambientIntensity);
|
||||||
|
X3DXmlHelper::getVector3DAttribute(node, "attenuation", attenuation);
|
||||||
|
XmlParser::getFloatAttribute(node, "beamWidth", beamWidth);
|
||||||
|
X3DXmlHelper::getColor3DAttribute(node, "color", color);
|
||||||
|
XmlParser::getFloatAttribute(node, "cutOffAngle", cutOffAngle);
|
||||||
|
X3DXmlHelper::getVector3DAttribute(node, "direction", direction);
|
||||||
|
XmlParser::getBoolAttribute(node, "global", global);
|
||||||
|
XmlParser::getFloatAttribute(node, "intensity", intensity);
|
||||||
|
X3DXmlHelper::getVector3DAttribute(node, "location", location);
|
||||||
|
XmlParser::getBoolAttribute(node, "on", on);
|
||||||
|
XmlParser::getFloatAttribute(node, "radius", radius);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_SpotLight, ne);
|
||||||
|
} else {
|
||||||
|
if (on) {
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementLight(X3DElemType::ENET_SpotLight, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
if (beamWidth > cutOffAngle) beamWidth = cutOffAngle;
|
||||||
|
|
||||||
|
((X3DNodeElementLight *)ne)->AmbientIntensity = ambientIntensity;
|
||||||
|
((X3DNodeElementLight *)ne)->Attenuation = attenuation;
|
||||||
|
((X3DNodeElementLight *)ne)->BeamWidth = beamWidth;
|
||||||
|
((X3DNodeElementLight *)ne)->Color = color;
|
||||||
|
((X3DNodeElementLight *)ne)->CutOffAngle = cutOffAngle;
|
||||||
|
((X3DNodeElementLight *)ne)->Direction = direction;
|
||||||
|
((X3DNodeElementLight *)ne)->Global = global;
|
||||||
|
((X3DNodeElementLight *)ne)->Intensity = intensity;
|
||||||
|
((X3DNodeElementLight *)ne)->Location = location;
|
||||||
|
((X3DNodeElementLight *)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 = "SpotLight_" + ai_to_string((size_t)ne);
|
||||||
|
|
||||||
|
mNodeElementCur->ID = ne->ID; // assign name to node and return to light element.
|
||||||
|
ParseHelper_Node_Exit();
|
||||||
|
// check for child nodes
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "SpotLight");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2019, 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 X3DImporter_Macro.hpp
|
||||||
|
/// \brief Useful macrodefines.
|
||||||
|
/// \date 2015-2016
|
||||||
|
/// \author smal.root@gmail.com
|
||||||
|
|
||||||
|
#ifndef X3DIMPORTER_MACRO_HPP_INCLUDED
|
||||||
|
#define X3DIMPORTER_MACRO_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <assimp/XmlParser.h>
|
||||||
|
#include "X3DImporter.hpp"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
/// Used for regular checking while attribute "USE" is defined.
|
||||||
|
/// \param [in] pNode - pugi xml node to read.
|
||||||
|
/// \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.
|
||||||
|
inline X3DNodeElementBase *X3DImporter::MACRO_USE_CHECKANDAPPLY(XmlNode &node, std::string pDEF, std::string pUSE, X3DElemType pType, X3DNodeElementBase *pNE) {
|
||||||
|
if (nullptr == mNodeElementCur) {
|
||||||
|
printf("here\n");
|
||||||
|
}
|
||||||
|
checkNodeMustBeEmpty(node);
|
||||||
|
if (!pDEF.empty())
|
||||||
|
Assimp::Throw_DEF_And_USE(node.name());
|
||||||
|
if (!FindNodeElement(pUSE, pType, &pNE))
|
||||||
|
Assimp::Throw_USE_NotFound(node.name(), pUSE);
|
||||||
|
mNodeElementCur->Children.push_back(pNE); /* add found object as child to current element */
|
||||||
|
|
||||||
|
return pNE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Assimp
|
||||||
|
|
||||||
|
/// \def MACRO_ATTRREAD_CHECKUSEDEF_RET
|
||||||
|
/// Compact variant for checking "USE" and "DEF".
|
||||||
|
/// \param [in] pNode - pugi xml node to read.
|
||||||
|
/// \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(pNode, pDEF_Var, pUSE_Var) \
|
||||||
|
do { \
|
||||||
|
XmlParser::getStdStrAttribute(pNode, "DEF", pDEF_Var); \
|
||||||
|
XmlParser::getStdStrAttribute(pNode, "USE", pUSE_Var); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
/// \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
|
|
@ -0,0 +1,255 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2019, 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 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
|
||||||
|
|
||||||
|
#include "X3DImporter.hpp"
|
||||||
|
#include "X3DImporter_Macro.hpp"
|
||||||
|
#include "X3DXmlHelper.h"
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
bool X3DImporter::checkForMetadataNode(XmlNode &node) {
|
||||||
|
const std::string &name = node.name();
|
||||||
|
if (name == "MetadataBoolean") {
|
||||||
|
readMetadataBoolean(node);
|
||||||
|
} else if (name == "MetadataDouble") {
|
||||||
|
readMetadataDouble(node);
|
||||||
|
} else if (name == "MetadataFloat") {
|
||||||
|
readMetadataFloat(node);
|
||||||
|
} else if (name == "MetadataInteger") {
|
||||||
|
readMetadataInteger(node);
|
||||||
|
} else if (name == "MetadataSet") {
|
||||||
|
readMetadataSet(node);
|
||||||
|
} else if (name == "MetadataString") {
|
||||||
|
readMetadataString(node);
|
||||||
|
} else
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void X3DImporter::childrenReadMetadata(XmlNode &node, X3DNodeElementBase *pParentElement, const std::string &pNodeName) {
|
||||||
|
ParseHelper_Node_Enter(pParentElement);
|
||||||
|
for (auto childNode : node.children()) {
|
||||||
|
if (!checkForMetadataNode(childNode)) skipUnsupportedNode(pNodeName, childNode);
|
||||||
|
}
|
||||||
|
ParseHelper_Node_Exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \def MACRO_METADATA_FINDCREATE(pDEF_Var, pUSE_Var, pReference, pValue, pNE, pMetaName)
|
||||||
|
/// Find element by "USE" or create new one.
|
||||||
|
/// \param [in] pNode - pugi xml node to read.
|
||||||
|
/// \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(pNode, pDEF_Var, pUSE_Var, pReference, pValue, pNE, pMetaClass, pMetaName, pType) \
|
||||||
|
/* if "USE" defined then find already defined element. */ \
|
||||||
|
if (!pUSE_Var.empty()) { \
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(pNode, pDEF_Var, pUSE_Var, pType, pNE); \
|
||||||
|
} else { \
|
||||||
|
pNE = new pMetaClass(mNodeElementCur); \
|
||||||
|
if (!pDEF_Var.empty()) pNE->ID = pDEF_Var; \
|
||||||
|
\
|
||||||
|
((pMetaClass *)pNE)->Reference = pReference; \
|
||||||
|
((pMetaClass *)pNE)->Value = pValue; \
|
||||||
|
/* also metadata node can contain childs */ \
|
||||||
|
if (!isNodeEmpty(pNode)) \
|
||||||
|
childrenReadMetadata(pNode, pNE, pMetaName); /* in that case node element will be added to child elements list of current node. */ \
|
||||||
|
else \
|
||||||
|
mNodeElementCur->Children.push_back(pNE); /* else - add element to child list manually */ \
|
||||||
|
\
|
||||||
|
NodeElement_List.push_back(pNE); /* add new element to elements list. */ \
|
||||||
|
} /* if(!pUSE_Var.empty()) else */ \
|
||||||
|
\
|
||||||
|
do { \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
// <MetadataBoolean
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// name="" SFString [inputOutput]
|
||||||
|
// reference="" SFString [inputOutput]
|
||||||
|
// value="" MFBool [inputOutput]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readMetadataBoolean(XmlNode &node) {
|
||||||
|
std::string def, use;
|
||||||
|
std::string name, reference;
|
||||||
|
std::vector<bool> value;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getStdStrAttribute(node, "name", name);
|
||||||
|
XmlParser::getStdStrAttribute(node, "reference", reference);
|
||||||
|
X3DXmlHelper::getBooleanArrayAttribute(node, "value", value);
|
||||||
|
|
||||||
|
MACRO_METADATA_FINDCREATE(node, def, use, reference, value, ne, X3DNodeElementMetaBoolean, "MetadataBoolean", ENET_MetaBoolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
// <MetadataDouble
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// name="" SFString [inputOutput]
|
||||||
|
// reference="" SFString [inputOutput]
|
||||||
|
// value="" MFDouble [inputOutput]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readMetadataDouble(XmlNode &node) {
|
||||||
|
std::string def, use;
|
||||||
|
std::string name, reference;
|
||||||
|
std::vector<double> value;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getStdStrAttribute(node, "name", name);
|
||||||
|
XmlParser::getStdStrAttribute(node, "reference", reference);
|
||||||
|
X3DXmlHelper::getDoubleArrayAttribute(node, "value", value);
|
||||||
|
|
||||||
|
MACRO_METADATA_FINDCREATE(node, def, use, reference, value, ne, X3DNodeElementMetaDouble, "MetadataDouble", ENET_MetaDouble);
|
||||||
|
}
|
||||||
|
|
||||||
|
// <MetadataFloat
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// name="" SFString [inputOutput]
|
||||||
|
// reference="" SFString [inputOutput]
|
||||||
|
// value="" MFFloat [inputOutput]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readMetadataFloat(XmlNode &node) {
|
||||||
|
std::string def, use;
|
||||||
|
std::string name, reference;
|
||||||
|
std::vector<float> value;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getStdStrAttribute(node, "name", name);
|
||||||
|
XmlParser::getStdStrAttribute(node, "reference", reference);
|
||||||
|
X3DXmlHelper::getFloatArrayAttribute(node, "value", value);
|
||||||
|
|
||||||
|
MACRO_METADATA_FINDCREATE(node, def, use, reference, value, ne, X3DNodeElementMetaFloat, "MetadataFloat", ENET_MetaFloat);
|
||||||
|
}
|
||||||
|
|
||||||
|
// <MetadataInteger
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// name="" SFString [inputOutput]
|
||||||
|
// reference="" SFString [inputOutput]
|
||||||
|
// value="" MFInteger [inputOutput]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readMetadataInteger(XmlNode &node) {
|
||||||
|
std::string def, use;
|
||||||
|
std::string name, reference;
|
||||||
|
std::vector<int32_t> value;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getStdStrAttribute(node, "name", name);
|
||||||
|
XmlParser::getStdStrAttribute(node, "reference", reference);
|
||||||
|
X3DXmlHelper::getInt32ArrayAttribute(node, "value", value);
|
||||||
|
|
||||||
|
MACRO_METADATA_FINDCREATE(node, def, use, reference, value, ne, X3DNodeElementMetaInt, "MetadataInteger", ENET_MetaInteger);
|
||||||
|
}
|
||||||
|
|
||||||
|
// <MetadataSet
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// name="" SFString [inputOutput]
|
||||||
|
// reference="" SFString [inputOutput]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readMetadataSet(XmlNode &node) {
|
||||||
|
std::string def, use;
|
||||||
|
std::string name, reference;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getStdStrAttribute(node, "name", name);
|
||||||
|
XmlParser::getStdStrAttribute(node, "reference", reference);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_MetaSet, ne);
|
||||||
|
} else {
|
||||||
|
ne = new X3DNodeElementMetaSet(mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
((X3DNodeElementMetaSet *)ne)->Reference = reference;
|
||||||
|
// also metadata node can contain children
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "MetadataSet");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <MetadataString
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// name="" SFString [inputOutput]
|
||||||
|
// reference="" SFString [inputOutput]
|
||||||
|
// value="" MFString [inputOutput]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readMetadataString(XmlNode &node) {
|
||||||
|
std::string def, use;
|
||||||
|
std::string name, reference;
|
||||||
|
std::vector<std::string> value;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getStdStrAttribute(node, "name", name);
|
||||||
|
XmlParser::getStdStrAttribute(node, "reference", reference);
|
||||||
|
X3DXmlHelper::getStringArrayAttribute(node, "value", value);
|
||||||
|
|
||||||
|
MACRO_METADATA_FINDCREATE(node, def, use, reference, value, ne, X3DNodeElementMetaString, "MetadataString", ENET_MetaString);
|
||||||
|
}
|
||||||
|
|
||||||
|
}// namespace Assimp
|
||||||
|
|
||||||
|
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER
|
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2019, 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 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"
|
||||||
|
#include "X3DXmlHelper.h"
|
||||||
|
|
||||||
|
// Header files, Assimp.
|
||||||
|
#include <assimp/DefaultIOSystem.h>
|
||||||
|
|
||||||
|
//#include <regex>
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
//static std::regex pattern_parentDir(R"((^|/)[^/]+/../)");
|
||||||
|
static std::string parentDir("/../");
|
||||||
|
|
||||||
|
// <Inline
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// bboxCenter="0 0 0" SFVec3f [initializeOnly]
|
||||||
|
// bboxSize="-1 -1 -1" SFVec3f [initializeOnly]
|
||||||
|
// load="true" SFBool [inputOutput]
|
||||||
|
// url="" MFString [inputOutput]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readInline(XmlNode &node) {
|
||||||
|
std::string def, use;
|
||||||
|
bool load = true;
|
||||||
|
std::list<std::string> url;
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getBoolAttribute(node, "load", load);
|
||||||
|
X3DXmlHelper::getStringListAttribute(node, "url", url);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
X3DNodeElementBase *ne = nullptr;
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, 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()) mNodeElementCur->ID = def;
|
||||||
|
|
||||||
|
if (load && !url.empty()) {
|
||||||
|
std::string full_path = mpIOHandler->CurrentDirectory() + url.front();
|
||||||
|
|
||||||
|
//full_path = std::regex_replace(full_path, pattern_parentDir, "$1");
|
||||||
|
for (std::string::size_type pos = full_path.find(parentDir); pos != std::string::npos; pos = full_path.find(parentDir, pos)) {
|
||||||
|
if (pos > 0) {
|
||||||
|
std::string::size_type pos2 = full_path.rfind('/', pos - 1);
|
||||||
|
if (pos2 != std::string::npos) {
|
||||||
|
full_path.erase(pos2, pos - pos2 + 3);
|
||||||
|
pos = pos2;
|
||||||
|
} else {
|
||||||
|
full_path.erase(0, pos + 4);
|
||||||
|
pos = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pos += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Attribute "url" can contain list of strings. But we need only one - first.
|
||||||
|
std::string::size_type slashPos = full_path.find_last_of("\\/");
|
||||||
|
mpIOHandler->PushDirectory(slashPos == std::string::npos ? std::string() : full_path.substr(0, slashPos + 1));
|
||||||
|
ParseFile(full_path, mpIOHandler);
|
||||||
|
mpIOHandler->PopDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for X3DMetadataObject childs.
|
||||||
|
if (!isNodeEmpty(node)) childrenReadMetadata(node, mNodeElementCur, "Inline");
|
||||||
|
|
||||||
|
// exit from node in that place
|
||||||
|
ParseHelper_Node_Exit();
|
||||||
|
} // if(!use.empty()) else
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Assimp
|
||||||
|
|
||||||
|
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER
|
|
@ -0,0 +1,463 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2019, 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 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/types.h>
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
enum X3DElemType {
|
||||||
|
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.
|
||||||
|
};
|
||||||
|
|
||||||
|
struct X3DNodeElementBase {
|
||||||
|
X3DNodeElementBase *Parent;
|
||||||
|
std::string ID;
|
||||||
|
std::list<X3DNodeElementBase *> Children;
|
||||||
|
X3DElemType Type;
|
||||||
|
|
||||||
|
virtual ~X3DNodeElementBase() {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
X3DNodeElementBase(X3DElemType type, X3DNodeElementBase *pParent) :
|
||||||
|
Parent(pParent), Type(type) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// This struct hold <Color> value.
|
||||||
|
struct X3DNodeElementColor : X3DNodeElementBase {
|
||||||
|
std::list<aiColor3D> Value; ///< Stored value.
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
/// \param [in] pParent - pointer to parent node.
|
||||||
|
X3DNodeElementColor(X3DNodeElementBase *pParent) :
|
||||||
|
X3DNodeElementBase(X3DElemType::ENET_Color, pParent) {}
|
||||||
|
|
||||||
|
}; // struct X3DNodeElementColor
|
||||||
|
|
||||||
|
/// This struct hold <ColorRGBA> value.
|
||||||
|
struct X3DNodeElementColorRGBA : X3DNodeElementBase {
|
||||||
|
std::list<aiColor4D> Value; ///< Stored value.
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
/// \param [in] pParent - pointer to parent node.
|
||||||
|
X3DNodeElementColorRGBA(X3DNodeElementBase *pParent) :
|
||||||
|
X3DNodeElementBase(X3DElemType::ENET_ColorRGBA, pParent) {}
|
||||||
|
|
||||||
|
}; // struct X3DNodeElementColorRGBA
|
||||||
|
|
||||||
|
/// This struct hold <Coordinate> value.
|
||||||
|
struct X3DNodeElementCoordinate : public X3DNodeElementBase {
|
||||||
|
std::list<aiVector3D> Value; ///< Stored value.
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
/// \param [in] pParent - pointer to parent node.
|
||||||
|
X3DNodeElementCoordinate(X3DNodeElementBase *pParent) :
|
||||||
|
X3DNodeElementBase(X3DElemType::ENET_Coordinate, pParent) {}
|
||||||
|
|
||||||
|
}; // struct X3DNodeElementCoordinate
|
||||||
|
|
||||||
|
/// This struct hold <Normal> value.
|
||||||
|
struct X3DNodeElementNormal : X3DNodeElementBase {
|
||||||
|
std::list<aiVector3D> Value; ///< Stored value.
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
/// \param [in] pParent - pointer to parent node.
|
||||||
|
X3DNodeElementNormal(X3DNodeElementBase *pParent) :
|
||||||
|
X3DNodeElementBase(X3DElemType::ENET_Normal, pParent) {}
|
||||||
|
|
||||||
|
}; // struct X3DNodeElementNormal
|
||||||
|
|
||||||
|
/// This struct hold <TextureCoordinate> value.
|
||||||
|
struct X3DNodeElementTextureCoordinate : X3DNodeElementBase {
|
||||||
|
std::list<aiVector2D> Value; ///< Stored value.
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
/// \param [in] pParent - pointer to parent node.
|
||||||
|
X3DNodeElementTextureCoordinate(X3DNodeElementBase *pParent) :
|
||||||
|
X3DNodeElementBase(X3DElemType::ENET_TextureCoordinate, pParent) {}
|
||||||
|
|
||||||
|
}; // struct X3DNodeElementTextureCoordinate
|
||||||
|
|
||||||
|
/// Two-dimensional figure.
|
||||||
|
struct X3DNodeElementGeometry2D : X3DNodeElementBase {
|
||||||
|
std::list<aiVector3D> 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.
|
||||||
|
|
||||||
|
/// Constructor.
|
||||||
|
/// \param [in] pParent - pointer to parent node.
|
||||||
|
/// \param [in] pType - type of geometry object.
|
||||||
|
X3DNodeElementGeometry2D(X3DElemType pType, X3DNodeElementBase *pParent) :
|
||||||
|
X3DNodeElementBase(pType, pParent), Solid(true) {}
|
||||||
|
|
||||||
|
}; // class X3DNodeElementGeometry2D
|
||||||
|
|
||||||
|
/// Three-dimensional body.
|
||||||
|
struct X3DNodeElementGeometry3D : X3DNodeElementBase {
|
||||||
|
std::list<aiVector3D> 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.
|
||||||
|
|
||||||
|
/// Constructor.
|
||||||
|
/// \param [in] pParent - pointer to parent node.
|
||||||
|
/// \param [in] pType - type of geometry object.
|
||||||
|
X3DNodeElementGeometry3D(X3DElemType pType, X3DNodeElementBase *pParent) :
|
||||||
|
X3DNodeElementBase(pType, pParent), Vertices(), NumIndices(0), Solid(true) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
}; // class X3DNodeElementGeometry3D
|
||||||
|
|
||||||
|
/// Uniform rectangular grid of varying height.
|
||||||
|
struct X3DNodeElementElevationGrid : X3DNodeElementGeometry3D {
|
||||||
|
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).
|
||||||
|
/// 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::vector<int32_t> CoordIdx; ///< Coordinates list by faces. In X3D format: "-1" - delimiter for faces.
|
||||||
|
|
||||||
|
/// Constructor.
|
||||||
|
/// \param [in] pParent - pointer to parent node.
|
||||||
|
/// \param [in] pType - type of geometry object.
|
||||||
|
X3DNodeElementElevationGrid(X3DElemType pType, X3DNodeElementBase *pParent) :
|
||||||
|
X3DNodeElementGeometry3D(pType, pParent) {}
|
||||||
|
}; // class X3DNodeElementIndexedSet
|
||||||
|
|
||||||
|
/// Shape with indexed vertices.
|
||||||
|
struct X3DNodeElementIndexedSet : public X3DNodeElementGeometry3D {
|
||||||
|
/// 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::vector<int32_t> ColorIndex; ///< Field to specify the polygonal faces by indexing into the <Color> or <ColorRGBA>.
|
||||||
|
bool ColorPerVertex; ///< If true then colors are defined for every vertex, else for every face(line).
|
||||||
|
/// 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::vector<int32_t> CoordIndex; ///< Field to specify the polygonal faces by indexing into the <Coordinate>.
|
||||||
|
/// 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::vector<int32_t> NormalIndex; ///< Field to specify the polygonal faces by indexing into the <Normal>.
|
||||||
|
bool NormalPerVertex; ///< If true then normals are defined for every vertex, else for every face(line).
|
||||||
|
std::vector<int32_t> TexCoordIndex; ///< Field to specify the polygonal faces by indexing into the <TextureCoordinate>.
|
||||||
|
|
||||||
|
/// Constructor.
|
||||||
|
/// \param [in] pParent - pointer to parent node.
|
||||||
|
/// \param [in] pType - type of geometry object.
|
||||||
|
X3DNodeElementIndexedSet(X3DElemType pType, X3DNodeElementBase *pParent) :
|
||||||
|
X3DNodeElementGeometry3D(pType, pParent) {}
|
||||||
|
}; // class X3DNodeElementIndexedSet
|
||||||
|
|
||||||
|
/// Shape with set of vertices.
|
||||||
|
struct X3DNodeElementSet : X3DNodeElementGeometry3D {
|
||||||
|
/// 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::vector<int32_t> CoordIndex; ///< Field to specify the polygonal faces by indexing into the <Coordinate>.
|
||||||
|
std::vector<int32_t> NormalIndex; ///< Field to specify the polygonal faces by indexing into the <Normal>.
|
||||||
|
std::vector<int32_t> TexCoordIndex; ///< Field to specify the polygonal faces by indexing into the <TextureCoordinate>.
|
||||||
|
std::vector<int32_t> VertexCount; ///< Field describes how many vertices are to be used in each polyline(polygon) from the <Coordinate> field.
|
||||||
|
|
||||||
|
/// Constructor.
|
||||||
|
/// \param [in] pParent - pointer to parent node.
|
||||||
|
/// \param [in] pType - type of geometry object.
|
||||||
|
X3DNodeElementSet(X3DElemType type, X3DNodeElementBase *pParent) :
|
||||||
|
X3DNodeElementGeometry3D(type, pParent) {}
|
||||||
|
|
||||||
|
}; // class X3DNodeElementSet
|
||||||
|
|
||||||
|
/// This struct hold <Shape> value.
|
||||||
|
struct X3DNodeElementShape : X3DNodeElementBase {
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
/// \param [in] pParent - pointer to parent node.
|
||||||
|
X3DNodeElementShape(X3DNodeElementBase *pParent) :
|
||||||
|
X3DNodeElementBase(X3DElemType::ENET_Shape, pParent) {}
|
||||||
|
}; // struct X3DNodeElementShape
|
||||||
|
|
||||||
|
/// This struct hold <Appearance> value.
|
||||||
|
struct X3DNodeElementAppearance : public X3DNodeElementBase {
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
/// \param [in] pParent - pointer to parent node.
|
||||||
|
X3DNodeElementAppearance(X3DNodeElementBase *pParent) :
|
||||||
|
X3DNodeElementBase(X3DElemType::ENET_Appearance, pParent) {}
|
||||||
|
|
||||||
|
}; // struct X3DNodeElementAppearance
|
||||||
|
|
||||||
|
struct X3DNodeElementMaterial : public X3DNodeElementBase {
|
||||||
|
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.
|
||||||
|
|
||||||
|
/// Constructor.
|
||||||
|
/// \param [in] pParent - pointer to parent node.
|
||||||
|
/// \param [in] pType - type of geometry object.
|
||||||
|
X3DNodeElementMaterial(X3DNodeElementBase *pParent) :
|
||||||
|
X3DNodeElementBase(X3DElemType::ENET_Material, pParent),
|
||||||
|
AmbientIntensity(0.0f),
|
||||||
|
DiffuseColor(),
|
||||||
|
EmissiveColor(),
|
||||||
|
Shininess(0.0f),
|
||||||
|
SpecularColor(),
|
||||||
|
Transparency(1.0f) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
}; // class X3DNodeElementMaterial
|
||||||
|
|
||||||
|
/// This struct hold <ImageTexture> value.
|
||||||
|
struct X3DNodeElementImageTexture : X3DNodeElementBase {
|
||||||
|
/// 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.
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
/// \param [in] pParent - pointer to parent node.
|
||||||
|
X3DNodeElementImageTexture(X3DNodeElementBase *pParent) :
|
||||||
|
X3DNodeElementBase(X3DElemType::ENET_ImageTexture, pParent) {}
|
||||||
|
|
||||||
|
}; // struct X3DNodeElementImageTexture
|
||||||
|
|
||||||
|
/// This struct hold <TextureTransform> value.
|
||||||
|
struct X3DNodeElementTextureTransform : X3DNodeElementBase {
|
||||||
|
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.
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
/// \param [in] pParent - pointer to parent node.
|
||||||
|
X3DNodeElementTextureTransform(X3DNodeElementBase *pParent) :
|
||||||
|
X3DNodeElementBase(X3DElemType::ENET_TextureTransform, pParent) {}
|
||||||
|
|
||||||
|
}; // struct X3DNodeElementTextureTransform
|
||||||
|
|
||||||
|
struct X3DNodeElementGroup : X3DNodeElementBase {
|
||||||
|
aiMatrix4x4 Transformation; ///< Transformation matrix.
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
|
||||||
|
/// Constructor.
|
||||||
|
/// \param [in] pParent - pointer to parent node.
|
||||||
|
/// \param [in] pStatic - static node flag.
|
||||||
|
X3DNodeElementGroup(X3DNodeElementBase *pParent, const bool pStatic = false) :
|
||||||
|
X3DNodeElementBase(X3DElemType::ENET_Group, pParent), Static(pStatic), UseChoice(false) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct X3DNodeElementMeta : X3DNodeElementBase {
|
||||||
|
std::string Name; ///< Name of metadata object.
|
||||||
|
std::string Reference;
|
||||||
|
|
||||||
|
virtual ~X3DNodeElementMeta() {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
X3DNodeElementMeta(X3DElemType type, X3DNodeElementBase *parent) :
|
||||||
|
X3DNodeElementBase(type, parent) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct X3DNodeElementMetaBoolean : X3DNodeElementMeta {
|
||||||
|
std::vector<bool> Value; ///< Stored value.
|
||||||
|
|
||||||
|
explicit X3DNodeElementMetaBoolean(X3DNodeElementBase *pParent) :
|
||||||
|
X3DNodeElementMeta(X3DElemType::ENET_MetaBoolean, pParent) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct X3DNodeElementMetaDouble : X3DNodeElementMeta {
|
||||||
|
std::vector<double> Value; ///< Stored value.
|
||||||
|
|
||||||
|
explicit X3DNodeElementMetaDouble(X3DNodeElementBase *pParent) :
|
||||||
|
X3DNodeElementMeta(X3DElemType::ENET_MetaDouble, pParent) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct X3DNodeElementMetaFloat : public X3DNodeElementMeta {
|
||||||
|
std::vector<float> Value; ///< Stored value.
|
||||||
|
|
||||||
|
explicit X3DNodeElementMetaFloat(X3DNodeElementBase *pParent) :
|
||||||
|
X3DNodeElementMeta(X3DElemType::ENET_MetaFloat, pParent) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct X3DNodeElementMetaInt : public X3DNodeElementMeta {
|
||||||
|
std::vector<int32_t> Value; ///< Stored value.
|
||||||
|
|
||||||
|
explicit X3DNodeElementMetaInt(X3DNodeElementBase *pParent) :
|
||||||
|
X3DNodeElementMeta(X3DElemType::ENET_MetaInteger, pParent) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct X3DNodeElementMetaSet : public X3DNodeElementMeta {
|
||||||
|
std::list<X3DNodeElementMeta> Value; ///< Stored value.
|
||||||
|
|
||||||
|
explicit X3DNodeElementMetaSet(X3DNodeElementBase *pParent) :
|
||||||
|
X3DNodeElementMeta(X3DElemType::ENET_MetaSet, pParent) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct X3DNodeElementMetaString : X3DNodeElementMeta {
|
||||||
|
std::vector<std::string> Value; ///< Stored value.
|
||||||
|
|
||||||
|
explicit X3DNodeElementMetaString(X3DNodeElementBase *pParent) :
|
||||||
|
X3DNodeElementMeta(X3DElemType::ENET_MetaString, pParent) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \struct X3DNodeElementLight
|
||||||
|
/// This struct hold <TextureTransform> value.
|
||||||
|
struct X3DNodeElementLight : X3DNodeElementBase {
|
||||||
|
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).
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
/// \param [in] pParent - pointer to parent node.
|
||||||
|
/// \param [in] pLightType - type of the light source.
|
||||||
|
X3DNodeElementLight(X3DElemType pLightType, X3DNodeElementBase *pParent) :
|
||||||
|
X3DNodeElementBase(pLightType, pParent) {}
|
||||||
|
|
||||||
|
}; // struct X3DNodeElementLight
|
||||||
|
|
||||||
|
#endif // INCLUDED_AI_X3D_IMPORTER_NODE_H
|
|
@ -0,0 +1,731 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2019, 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 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 "X3DGeoHelper.h"
|
||||||
|
#include "X3DImporter.hpp"
|
||||||
|
|
||||||
|
// Header files, Assimp.
|
||||||
|
#include <assimp/StandardShapes.h>
|
||||||
|
#include <assimp/StringUtils.h>
|
||||||
|
#include <assimp/ai_assert.h>
|
||||||
|
|
||||||
|
// Header files, stdlib.
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
aiMatrix4x4 X3DImporter::PostprocessHelper_Matrix_GlobalToCurrent() const {
|
||||||
|
X3DNodeElementBase *cur_node;
|
||||||
|
std::list<aiMatrix4x4> matr;
|
||||||
|
aiMatrix4x4 out_matr;
|
||||||
|
|
||||||
|
// starting walk from current element to root
|
||||||
|
cur_node = mNodeElementCur;
|
||||||
|
if (cur_node != nullptr) {
|
||||||
|
do {
|
||||||
|
// if cur_node is group then store group transformation matrix in list.
|
||||||
|
if (cur_node->Type == X3DElemType::ENET_Group) matr.push_back(((X3DNodeElementGroup *)cur_node)->Transformation);
|
||||||
|
|
||||||
|
cur_node = cur_node->Parent;
|
||||||
|
} while (cur_node != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// multiplicate all matrices in reverse order
|
||||||
|
for (std::list<aiMatrix4x4>::reverse_iterator rit = matr.rbegin(); rit != matr.rend(); ++rit)
|
||||||
|
out_matr = out_matr * (*rit);
|
||||||
|
|
||||||
|
return out_matr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void X3DImporter::PostprocessHelper_CollectMetadata(const X3DNodeElementBase &pNodeElement, std::list<X3DNodeElementBase *> &pList) const {
|
||||||
|
// walk through childs and find for metadata.
|
||||||
|
for (std::list<X3DNodeElementBase *>::const_iterator el_it = pNodeElement.Children.begin(); el_it != pNodeElement.Children.end(); ++el_it) {
|
||||||
|
if (((*el_it)->Type == X3DElemType::ENET_MetaBoolean) || ((*el_it)->Type == X3DElemType::ENET_MetaDouble) ||
|
||||||
|
((*el_it)->Type == X3DElemType::ENET_MetaFloat) || ((*el_it)->Type == X3DElemType::ENET_MetaInteger) ||
|
||||||
|
((*el_it)->Type == X3DElemType::ENET_MetaString)) {
|
||||||
|
pList.push_back(*el_it);
|
||||||
|
} else if ((*el_it)->Type == X3DElemType::ENET_MetaSet) {
|
||||||
|
PostprocessHelper_CollectMetadata(**el_it, pList);
|
||||||
|
}
|
||||||
|
} // for(std::list<X3DNodeElementBase*>::const_iterator el_it = pNodeElement.Children.begin(); el_it != pNodeElement.Children.end(); el_it++)
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X3DImporter::PostprocessHelper_ElementIsMetadata(const X3DElemType pType) const {
|
||||||
|
if ((pType == X3DElemType::ENET_MetaBoolean) || (pType == X3DElemType::ENET_MetaDouble) ||
|
||||||
|
(pType == X3DElemType::ENET_MetaFloat) || (pType == X3DElemType::ENET_MetaInteger) ||
|
||||||
|
(pType == X3DElemType::ENET_MetaString) || (pType == X3DElemType::ENET_MetaSet)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X3DImporter::PostprocessHelper_ElementIsMesh(const X3DElemType pType) const {
|
||||||
|
if ((pType == X3DElemType::ENET_Arc2D) || (pType == X3DElemType::ENET_ArcClose2D) ||
|
||||||
|
(pType == X3DElemType::ENET_Box) || (pType == X3DElemType::ENET_Circle2D) ||
|
||||||
|
(pType == X3DElemType::ENET_Cone) || (pType == X3DElemType::ENET_Cylinder) ||
|
||||||
|
(pType == X3DElemType::ENET_Disk2D) || (pType == X3DElemType::ENET_ElevationGrid) ||
|
||||||
|
(pType == X3DElemType::ENET_Extrusion) || (pType == X3DElemType::ENET_IndexedFaceSet) ||
|
||||||
|
(pType == X3DElemType::ENET_IndexedLineSet) || (pType == X3DElemType::ENET_IndexedTriangleFanSet) ||
|
||||||
|
(pType == X3DElemType::ENET_IndexedTriangleSet) || (pType == X3DElemType::ENET_IndexedTriangleStripSet) ||
|
||||||
|
(pType == X3DElemType::ENET_PointSet) || (pType == X3DElemType::ENET_LineSet) ||
|
||||||
|
(pType == X3DElemType::ENET_Polyline2D) || (pType == X3DElemType::ENET_Polypoint2D) ||
|
||||||
|
(pType == X3DElemType::ENET_Rectangle2D) || (pType == X3DElemType::ENET_Sphere) ||
|
||||||
|
(pType == X3DElemType::ENET_TriangleFanSet) || (pType == X3DElemType::ENET_TriangleSet) ||
|
||||||
|
(pType == X3DElemType::ENET_TriangleSet2D) || (pType == X3DElemType::ENET_TriangleStripSet)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void X3DImporter::Postprocess_BuildLight(const X3DNodeElementBase &pNodeElement, std::list<aiLight *> &pSceneLightList) const {
|
||||||
|
const X3DNodeElementLight &ne = *((X3DNodeElementLight *)&pNodeElement);
|
||||||
|
aiMatrix4x4 transform_matr = PostprocessHelper_Matrix_GlobalToCurrent();
|
||||||
|
aiLight *new_light = new aiLight;
|
||||||
|
|
||||||
|
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 X3DElemType::ENET_DirectionalLight:
|
||||||
|
new_light->mType = aiLightSource_DIRECTIONAL;
|
||||||
|
new_light->mDirection = ne.Direction, new_light->mDirection *= transform_matr;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case X3DElemType::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 X3DElemType::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("Postprocess_BuildLight. Unknown type of light: " + ai_to_string(pNodeElement.Type) + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
pSceneLightList.push_back(new_light);
|
||||||
|
}
|
||||||
|
|
||||||
|
void X3DImporter::Postprocess_BuildMaterial(const X3DNodeElementBase &pNodeElement, aiMaterial **pMaterial) const {
|
||||||
|
// check argument
|
||||||
|
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.
|
||||||
|
|
||||||
|
// at this point pNodeElement point to <Appearance> node. Walk through childs and add all stored data.
|
||||||
|
for (std::list<X3DNodeElementBase *>::const_iterator el_it = pNodeElement.Children.begin(); el_it != pNodeElement.Children.end(); ++el_it) {
|
||||||
|
if ((*el_it)->Type == X3DElemType::ENET_Material) {
|
||||||
|
aiColor3D tcol3;
|
||||||
|
float tvalf;
|
||||||
|
X3DNodeElementMaterial &tnemat = *((X3DNodeElementMaterial *)*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.0f - tnemat.Transparency;
|
||||||
|
taimat.AddProperty(&tvalf, 1, AI_MATKEY_OPACITY);
|
||||||
|
} // if((*el_it)->Type == X3DElemType::ENET_Material)
|
||||||
|
else if ((*el_it)->Type == X3DElemType::ENET_ImageTexture) {
|
||||||
|
X3DNodeElementImageTexture &tnetex = *((X3DNodeElementImageTexture *)*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 == X3DElemType::ENET_ImageTexture)
|
||||||
|
else if ((*el_it)->Type == X3DElemType::ENET_TextureTransform) {
|
||||||
|
aiUVTransform trans;
|
||||||
|
X3DNodeElementTextureTransform &tnetextr = *((X3DNodeElementTextureTransform *)*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 == X3DElemType::ENET_TextureTransform)
|
||||||
|
} // for(std::list<X3DNodeElementBase*>::const_iterator el_it = pNodeElement.Children.begin(); el_it != pNodeElement.Children.end(); el_it++)
|
||||||
|
}
|
||||||
|
|
||||||
|
void X3DImporter::Postprocess_BuildMesh(const X3DNodeElementBase &pNodeElement, aiMesh **pMesh) const {
|
||||||
|
// check argument
|
||||||
|
if (pMesh == nullptr) throw DeadlyImportError("Postprocess_BuildMesh. pMesh is nullptr.");
|
||||||
|
if (*pMesh != nullptr) throw DeadlyImportError("Postprocess_BuildMesh. *pMesh must be nullptr.");
|
||||||
|
|
||||||
|
/************************************************************************************************************************************/
|
||||||
|
/************************************************************ Geometry2D ************************************************************/
|
||||||
|
/************************************************************************************************************************************/
|
||||||
|
if ((pNodeElement.Type == X3DElemType::ENET_Arc2D) || (pNodeElement.Type == X3DElemType::ENET_ArcClose2D) ||
|
||||||
|
(pNodeElement.Type == X3DElemType::ENET_Circle2D) || (pNodeElement.Type == X3DElemType::ENET_Disk2D) ||
|
||||||
|
(pNodeElement.Type == X3DElemType::ENET_Polyline2D) || (pNodeElement.Type == X3DElemType::ENET_Polypoint2D) ||
|
||||||
|
(pNodeElement.Type == X3DElemType::ENET_Rectangle2D) || (pNodeElement.Type == X3DElemType::ENET_TriangleSet2D)) {
|
||||||
|
X3DNodeElementGeometry2D &tnemesh = *((X3DNodeElementGeometry2D *)&pNodeElement); // create alias for convenience
|
||||||
|
std::vector<aiVector3D> tarr;
|
||||||
|
|
||||||
|
tarr.reserve(tnemesh.Vertices.size());
|
||||||
|
for (std::list<aiVector3D>::iterator it = tnemesh.Vertices.begin(); it != tnemesh.Vertices.end(); ++it)
|
||||||
|
tarr.push_back(*it);
|
||||||
|
*pMesh = StandardShapes::MakeMesh(tarr, static_cast<unsigned int>(tnemesh.NumIndices)); // create mesh from vertices using Assimp help.
|
||||||
|
|
||||||
|
return; // mesh is build, nothing to do anymore.
|
||||||
|
}
|
||||||
|
/************************************************************************************************************************************/
|
||||||
|
/************************************************************ Geometry3D ************************************************************/
|
||||||
|
/************************************************************************************************************************************/
|
||||||
|
//
|
||||||
|
// Predefined figures
|
||||||
|
//
|
||||||
|
if ((pNodeElement.Type == X3DElemType::ENET_Box) || (pNodeElement.Type == X3DElemType::ENET_Cone) ||
|
||||||
|
(pNodeElement.Type == X3DElemType::ENET_Cylinder) || (pNodeElement.Type == X3DElemType::ENET_Sphere)) {
|
||||||
|
X3DNodeElementGeometry3D &tnemesh = *((X3DNodeElementGeometry3D *)&pNodeElement); // create alias for convenience
|
||||||
|
std::vector<aiVector3D> tarr;
|
||||||
|
|
||||||
|
tarr.reserve(tnemesh.Vertices.size());
|
||||||
|
for (std::list<aiVector3D>::iterator it = tnemesh.Vertices.begin(); it != tnemesh.Vertices.end(); ++it)
|
||||||
|
tarr.push_back(*it);
|
||||||
|
|
||||||
|
*pMesh = StandardShapes::MakeMesh(tarr, static_cast<unsigned int>(tnemesh.NumIndices)); // create mesh from vertices using Assimp help.
|
||||||
|
|
||||||
|
return; // mesh is build, nothing to do anymore.
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Parametric figures
|
||||||
|
//
|
||||||
|
if (pNodeElement.Type == X3DElemType::ENET_ElevationGrid) {
|
||||||
|
X3DNodeElementElevationGrid &tnemesh = *((X3DNodeElementElevationGrid *)&pNodeElement); // create alias for convenience
|
||||||
|
|
||||||
|
// at first create mesh from existing vertices.
|
||||||
|
*pMesh = X3DGeoHelper::make_mesh(tnemesh.CoordIdx, tnemesh.Vertices);
|
||||||
|
// copy additional information from children
|
||||||
|
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
|
||||||
|
if ((*ch_it)->Type == X3DElemType::ENET_Color)
|
||||||
|
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColor *)*ch_it)->Value, tnemesh.ColorPerVertex);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_ColorRGBA)
|
||||||
|
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColorRGBA *)*ch_it)->Value, tnemesh.ColorPerVertex);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_Normal)
|
||||||
|
X3DGeoHelper::add_normal(**pMesh, ((X3DNodeElementNormal *)*ch_it)->Value, tnemesh.NormalPerVertex);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_TextureCoordinate)
|
||||||
|
X3DGeoHelper::add_tex_coord(**pMesh, ((X3DNodeElementTextureCoordinate *)*ch_it)->Value);
|
||||||
|
else
|
||||||
|
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of ElevationGrid: " + ai_to_string((*ch_it)->Type) + ".");
|
||||||
|
} // for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it)
|
||||||
|
|
||||||
|
return; // mesh is build, nothing to do anymore.
|
||||||
|
} // if(pNodeElement.Type == X3DElemType::ENET_ElevationGrid)
|
||||||
|
//
|
||||||
|
// Indexed primitives sets
|
||||||
|
//
|
||||||
|
if (pNodeElement.Type == X3DElemType::ENET_IndexedFaceSet) {
|
||||||
|
X3DNodeElementIndexedSet &tnemesh = *((X3DNodeElementIndexedSet *)&pNodeElement); // create alias for convenience
|
||||||
|
|
||||||
|
// at first search for <Coordinate> node and create mesh.
|
||||||
|
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
|
||||||
|
if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
|
||||||
|
*pMesh = X3DGeoHelper::make_mesh(tnemesh.CoordIndex, ((X3DNodeElementCoordinate *)*ch_it)->Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy additional information from children
|
||||||
|
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
|
||||||
|
if ((*ch_it)->Type == X3DElemType::ENET_Color)
|
||||||
|
X3DGeoHelper::add_color(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((X3DNodeElementColor *)*ch_it)->Value, tnemesh.ColorPerVertex);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_ColorRGBA)
|
||||||
|
X3DGeoHelper::add_color(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((X3DNodeElementColorRGBA *)*ch_it)->Value,
|
||||||
|
tnemesh.ColorPerVertex);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
|
||||||
|
} // skip because already read when mesh created.
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_Normal)
|
||||||
|
X3DGeoHelper::add_normal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((X3DNodeElementNormal *)*ch_it)->Value,
|
||||||
|
tnemesh.NormalPerVertex);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_TextureCoordinate)
|
||||||
|
X3DGeoHelper::add_tex_coord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((X3DNodeElementTextureCoordinate *)*ch_it)->Value);
|
||||||
|
else
|
||||||
|
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedFaceSet: " + ai_to_string((*ch_it)->Type) + ".");
|
||||||
|
} // for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it)
|
||||||
|
|
||||||
|
return; // mesh is build, nothing to do anymore.
|
||||||
|
} // if(pNodeElement.Type == X3DElemType::ENET_IndexedFaceSet)
|
||||||
|
|
||||||
|
if (pNodeElement.Type == X3DElemType::ENET_IndexedLineSet) {
|
||||||
|
X3DNodeElementIndexedSet &tnemesh = *((X3DNodeElementIndexedSet *)&pNodeElement); // create alias for convenience
|
||||||
|
|
||||||
|
// at first search for <Coordinate> node and create mesh.
|
||||||
|
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
|
||||||
|
if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
|
||||||
|
*pMesh = X3DGeoHelper::make_mesh(tnemesh.CoordIndex, ((X3DNodeElementCoordinate *)*ch_it)->Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy additional information from children
|
||||||
|
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
|
||||||
|
ai_assert(*pMesh);
|
||||||
|
if ((*ch_it)->Type == X3DElemType::ENET_Color)
|
||||||
|
X3DGeoHelper::add_color(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((X3DNodeElementColor *)*ch_it)->Value, tnemesh.ColorPerVertex);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_ColorRGBA)
|
||||||
|
X3DGeoHelper::add_color(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((X3DNodeElementColorRGBA *)*ch_it)->Value,
|
||||||
|
tnemesh.ColorPerVertex);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
|
||||||
|
} // skip because already read when mesh created.
|
||||||
|
else
|
||||||
|
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedLineSet: " + ai_to_string((*ch_it)->Type) + ".");
|
||||||
|
} // for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it)
|
||||||
|
|
||||||
|
return; // mesh is build, nothing to do anymore.
|
||||||
|
} // if(pNodeElement.Type == X3DElemType::ENET_IndexedLineSet)
|
||||||
|
|
||||||
|
if ((pNodeElement.Type == X3DElemType::ENET_IndexedTriangleSet) ||
|
||||||
|
(pNodeElement.Type == X3DElemType::ENET_IndexedTriangleFanSet) ||
|
||||||
|
(pNodeElement.Type == X3DElemType::ENET_IndexedTriangleStripSet)) {
|
||||||
|
X3DNodeElementIndexedSet &tnemesh = *((X3DNodeElementIndexedSet *)&pNodeElement); // create alias for convenience
|
||||||
|
|
||||||
|
// at first search for <Coordinate> node and create mesh.
|
||||||
|
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
|
||||||
|
if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
|
||||||
|
*pMesh = X3DGeoHelper::make_mesh(tnemesh.CoordIndex, ((X3DNodeElementCoordinate *)*ch_it)->Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy additional information from children
|
||||||
|
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
|
||||||
|
ai_assert(*pMesh);
|
||||||
|
if ((*ch_it)->Type == X3DElemType::ENET_Color)
|
||||||
|
X3DGeoHelper::add_color(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((X3DNodeElementColor *)*ch_it)->Value, tnemesh.ColorPerVertex);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_ColorRGBA)
|
||||||
|
X3DGeoHelper::add_color(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((X3DNodeElementColorRGBA *)*ch_it)->Value,
|
||||||
|
tnemesh.ColorPerVertex);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
|
||||||
|
} // skip because already read when mesh created.
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_Normal)
|
||||||
|
X3DGeoHelper::add_normal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((X3DNodeElementNormal *)*ch_it)->Value,
|
||||||
|
tnemesh.NormalPerVertex);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_TextureCoordinate)
|
||||||
|
X3DGeoHelper::add_tex_coord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((X3DNodeElementTextureCoordinate *)*ch_it)->Value);
|
||||||
|
else
|
||||||
|
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedTriangleSet or IndexedTriangleFanSet, or \
|
||||||
|
IndexedTriangleStripSet: " +
|
||||||
|
ai_to_string((*ch_it)->Type) + ".");
|
||||||
|
} // for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it)
|
||||||
|
|
||||||
|
return; // mesh is build, nothing to do anymore.
|
||||||
|
} // if((pNodeElement.Type == X3DElemType::ENET_IndexedTriangleFanSet) || (pNodeElement.Type == X3DElemType::ENET_IndexedTriangleStripSet))
|
||||||
|
|
||||||
|
if (pNodeElement.Type == X3DElemType::ENET_Extrusion) {
|
||||||
|
X3DNodeElementIndexedSet &tnemesh = *((X3DNodeElementIndexedSet *)&pNodeElement); // create alias for convenience
|
||||||
|
|
||||||
|
*pMesh = X3DGeoHelper::make_mesh(tnemesh.CoordIndex, tnemesh.Vertices);
|
||||||
|
|
||||||
|
return; // mesh is build, nothing to do anymore.
|
||||||
|
} // if(pNodeElement.Type == X3DElemType::ENET_Extrusion)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Primitives sets
|
||||||
|
//
|
||||||
|
if (pNodeElement.Type == X3DElemType::ENET_PointSet) {
|
||||||
|
X3DNodeElementSet &tnemesh = *((X3DNodeElementSet *)&pNodeElement); // create alias for convenience
|
||||||
|
|
||||||
|
// at first search for <Coordinate> node and create mesh.
|
||||||
|
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
|
||||||
|
if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
|
||||||
|
std::vector<aiVector3D> vec_copy;
|
||||||
|
|
||||||
|
vec_copy.reserve(((X3DNodeElementCoordinate *)*ch_it)->Value.size());
|
||||||
|
for (std::list<aiVector3D>::const_iterator it = ((X3DNodeElementCoordinate *)*ch_it)->Value.begin();
|
||||||
|
it != ((X3DNodeElementCoordinate *)*ch_it)->Value.end(); ++it) {
|
||||||
|
vec_copy.push_back(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
*pMesh = StandardShapes::MakeMesh(vec_copy, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy additional information from children
|
||||||
|
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
|
||||||
|
ai_assert(*pMesh);
|
||||||
|
if ((*ch_it)->Type == X3DElemType::ENET_Color)
|
||||||
|
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColor *)*ch_it)->Value, true);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_ColorRGBA)
|
||||||
|
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColorRGBA *)*ch_it)->Value, true);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
|
||||||
|
} // skip because already read when mesh created.
|
||||||
|
else
|
||||||
|
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of PointSet: " + ai_to_string((*ch_it)->Type) + ".");
|
||||||
|
} // for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it)
|
||||||
|
|
||||||
|
return; // mesh is build, nothing to do anymore.
|
||||||
|
} // if(pNodeElement.Type == X3DElemType::ENET_PointSet)
|
||||||
|
|
||||||
|
if (pNodeElement.Type == X3DElemType::ENET_LineSet) {
|
||||||
|
X3DNodeElementSet &tnemesh = *((X3DNodeElementSet *)&pNodeElement); // create alias for convenience
|
||||||
|
|
||||||
|
// at first search for <Coordinate> node and create mesh.
|
||||||
|
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
|
||||||
|
if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
|
||||||
|
*pMesh = X3DGeoHelper::make_mesh(tnemesh.CoordIndex, ((X3DNodeElementCoordinate *)*ch_it)->Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy additional information from children
|
||||||
|
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
|
||||||
|
ai_assert(*pMesh);
|
||||||
|
if ((*ch_it)->Type == X3DElemType::ENET_Color)
|
||||||
|
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColor *)*ch_it)->Value, true);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_ColorRGBA)
|
||||||
|
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColorRGBA *)*ch_it)->Value, true);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
|
||||||
|
} // skip because already read when mesh created.
|
||||||
|
else
|
||||||
|
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of LineSet: " + ai_to_string((*ch_it)->Type) + ".");
|
||||||
|
} // for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it)
|
||||||
|
|
||||||
|
return; // mesh is build, nothing to do anymore.
|
||||||
|
} // if(pNodeElement.Type == X3DElemType::ENET_LineSet)
|
||||||
|
|
||||||
|
if (pNodeElement.Type == X3DElemType::ENET_TriangleFanSet) {
|
||||||
|
X3DNodeElementSet &tnemesh = *((X3DNodeElementSet *)&pNodeElement); // create alias for convenience
|
||||||
|
|
||||||
|
// at first search for <Coordinate> node and create mesh.
|
||||||
|
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
|
||||||
|
if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
|
||||||
|
*pMesh = X3DGeoHelper::make_mesh(tnemesh.CoordIndex, ((X3DNodeElementCoordinate *)*ch_it)->Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy additional information from children
|
||||||
|
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
|
||||||
|
if (nullptr == *pMesh) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((*ch_it)->Type == X3DElemType::ENET_Color)
|
||||||
|
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColor *)*ch_it)->Value, tnemesh.ColorPerVertex);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_ColorRGBA)
|
||||||
|
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColorRGBA *)*ch_it)->Value, tnemesh.ColorPerVertex);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
|
||||||
|
} // skip because already read when mesh created.
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_Normal)
|
||||||
|
X3DGeoHelper::add_normal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((X3DNodeElementNormal *)*ch_it)->Value,
|
||||||
|
tnemesh.NormalPerVertex);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_TextureCoordinate)
|
||||||
|
X3DGeoHelper::add_tex_coord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((X3DNodeElementTextureCoordinate *)*ch_it)->Value);
|
||||||
|
else
|
||||||
|
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TrianlgeFanSet: " + ai_to_string((*ch_it)->Type) + ".");
|
||||||
|
} // for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it)
|
||||||
|
|
||||||
|
return; // mesh is build, nothing to do anymore.
|
||||||
|
} // if(pNodeElement.Type == X3DElemType::ENET_TriangleFanSet)
|
||||||
|
|
||||||
|
if (pNodeElement.Type == X3DElemType::ENET_TriangleSet) {
|
||||||
|
X3DNodeElementSet &tnemesh = *((X3DNodeElementSet *)&pNodeElement); // create alias for convenience
|
||||||
|
|
||||||
|
// at first search for <Coordinate> node and create mesh.
|
||||||
|
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
|
||||||
|
if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
|
||||||
|
std::vector<aiVector3D> vec_copy;
|
||||||
|
|
||||||
|
vec_copy.reserve(((X3DNodeElementCoordinate *)*ch_it)->Value.size());
|
||||||
|
for (std::list<aiVector3D>::const_iterator it = ((X3DNodeElementCoordinate *)*ch_it)->Value.begin();
|
||||||
|
it != ((X3DNodeElementCoordinate *)*ch_it)->Value.end(); ++it) {
|
||||||
|
vec_copy.push_back(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
*pMesh = StandardShapes::MakeMesh(vec_copy, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy additional information from children
|
||||||
|
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
|
||||||
|
ai_assert(*pMesh);
|
||||||
|
if ((*ch_it)->Type == X3DElemType::ENET_Color)
|
||||||
|
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColor *)*ch_it)->Value, tnemesh.ColorPerVertex);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_ColorRGBA)
|
||||||
|
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColorRGBA *)*ch_it)->Value, tnemesh.ColorPerVertex);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
|
||||||
|
} // skip because already read when mesh created.
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_Normal)
|
||||||
|
X3DGeoHelper::add_normal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((X3DNodeElementNormal *)*ch_it)->Value,
|
||||||
|
tnemesh.NormalPerVertex);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_TextureCoordinate)
|
||||||
|
X3DGeoHelper::add_tex_coord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((X3DNodeElementTextureCoordinate *)*ch_it)->Value);
|
||||||
|
else
|
||||||
|
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TrianlgeSet: " + ai_to_string((*ch_it)->Type) + ".");
|
||||||
|
} // for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it)
|
||||||
|
|
||||||
|
return; // mesh is build, nothing to do anymore.
|
||||||
|
} // if(pNodeElement.Type == X3DElemType::ENET_TriangleSet)
|
||||||
|
|
||||||
|
if (pNodeElement.Type == X3DElemType::ENET_TriangleStripSet) {
|
||||||
|
X3DNodeElementSet &tnemesh = *((X3DNodeElementSet *)&pNodeElement); // create alias for convenience
|
||||||
|
|
||||||
|
// at first search for <Coordinate> node and create mesh.
|
||||||
|
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
|
||||||
|
if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
|
||||||
|
*pMesh = X3DGeoHelper::make_mesh(tnemesh.CoordIndex, ((X3DNodeElementCoordinate *)*ch_it)->Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy additional information from children
|
||||||
|
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
|
||||||
|
ai_assert(*pMesh);
|
||||||
|
if ((*ch_it)->Type == X3DElemType::ENET_Color)
|
||||||
|
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColor *)*ch_it)->Value, tnemesh.ColorPerVertex);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_ColorRGBA)
|
||||||
|
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColorRGBA *)*ch_it)->Value, tnemesh.ColorPerVertex);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
|
||||||
|
} // skip because already read when mesh created.
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_Normal)
|
||||||
|
X3DGeoHelper::add_normal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((X3DNodeElementNormal *)*ch_it)->Value,
|
||||||
|
tnemesh.NormalPerVertex);
|
||||||
|
else if ((*ch_it)->Type == X3DElemType::ENET_TextureCoordinate)
|
||||||
|
X3DGeoHelper::add_tex_coord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((X3DNodeElementTextureCoordinate *)*ch_it)->Value);
|
||||||
|
else
|
||||||
|
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TriangleStripSet: " + ai_to_string((*ch_it)->Type) + ".");
|
||||||
|
} // for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it)
|
||||||
|
|
||||||
|
return; // mesh is build, nothing to do anymore.
|
||||||
|
} // if(pNodeElement.Type == X3DElemType::ENET_TriangleStripSet)
|
||||||
|
|
||||||
|
throw DeadlyImportError("Postprocess_BuildMesh. Unknown mesh type: " + ai_to_string(pNodeElement.Type) + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
void X3DImporter::Postprocess_BuildNode(const X3DNodeElementBase &pNodeElement, aiNode &pSceneNode, std::list<aiMesh *> &pSceneMeshList,
|
||||||
|
std::list<aiMaterial *> &pSceneMaterialList, std::list<aiLight *> &pSceneLightList) const {
|
||||||
|
std::list<X3DNodeElementBase *>::const_iterator chit_begin = pNodeElement.Children.begin();
|
||||||
|
std::list<X3DNodeElementBase *>::const_iterator chit_end = pNodeElement.Children.end();
|
||||||
|
std::list<aiNode *> SceneNode_Child;
|
||||||
|
std::list<unsigned int> 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 == X3DElemType::ENET_Group) {
|
||||||
|
const X3DNodeElementGroup &tne_group = *((X3DNodeElementGroup *)&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.Children.size())) {
|
||||||
|
chit_begin = pNodeElement.Children.end();
|
||||||
|
chit_end = pNodeElement.Children.end();
|
||||||
|
} else {
|
||||||
|
for (size_t i = 0; i < (size_t)tne_group.Choice; i++)
|
||||||
|
++chit_begin; // forward iterator to chosen node.
|
||||||
|
|
||||||
|
chit_end = chit_begin;
|
||||||
|
++chit_end; // point end iterator to next element after chosen node.
|
||||||
|
}
|
||||||
|
} // if(tne_group.UseChoice)
|
||||||
|
} // if(pNodeElement.Type == X3DElemType::ENET_Group)
|
||||||
|
|
||||||
|
// Reserve memory for fast access and check children.
|
||||||
|
for (std::list<X3DNodeElementBase *>::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 == X3DElemType::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 == X3DElemType::ENET_Shape) {
|
||||||
|
// shape can contain only one geometry and one appearance nodes.
|
||||||
|
Postprocess_BuildShape(*((X3DNodeElementShape *)*it), SceneNode_Mesh, pSceneMeshList, pSceneMaterialList);
|
||||||
|
} else if (((*it)->Type == X3DElemType::ENET_DirectionalLight) || ((*it)->Type == X3DElemType::ENET_PointLight) ||
|
||||||
|
((*it)->Type == X3DElemType::ENET_SpotLight)) {
|
||||||
|
Postprocess_BuildLight(*((X3DNodeElementLight *)*it), pSceneLightList);
|
||||||
|
} else if (!PostprocessHelper_ElementIsMetadata((*it)->Type)) // skip metadata
|
||||||
|
{
|
||||||
|
throw DeadlyImportError("Postprocess_BuildNode. Unknown type: " + ai_to_string((*it)->Type) + ".");
|
||||||
|
}
|
||||||
|
} // for(std::list<X3DNodeElementBase*>::const_iterator it = chit_begin; it != chit_end; it++)
|
||||||
|
|
||||||
|
// copy data about children and meshes to aiNode.
|
||||||
|
if (!SceneNode_Child.empty()) {
|
||||||
|
std::list<aiNode *>::const_iterator it = SceneNode_Child.begin();
|
||||||
|
|
||||||
|
pSceneNode.mNumChildren = static_cast<unsigned int>(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.empty()) {
|
||||||
|
std::list<unsigned int>::const_iterator it = SceneNode_Mesh.begin();
|
||||||
|
|
||||||
|
pSceneNode.mNumMeshes = static_cast<unsigned int>(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 X3DNodeElementShape &pShapeNodeElement, std::list<unsigned int> &pNodeMeshInd,
|
||||||
|
std::list<aiMesh *> &pSceneMeshList, std::list<aiMaterial *> &pSceneMaterialList) const {
|
||||||
|
aiMaterial *tmat = nullptr;
|
||||||
|
aiMesh *tmesh = nullptr;
|
||||||
|
X3DElemType mesh_type = X3DElemType::ENET_Invalid;
|
||||||
|
unsigned int mat_ind = 0;
|
||||||
|
|
||||||
|
for (std::list<X3DNodeElementBase *>::const_iterator it = pShapeNodeElement.Children.begin(); it != pShapeNodeElement.Children.end(); ++it) {
|
||||||
|
if (PostprocessHelper_ElementIsMesh((*it)->Type)) {
|
||||||
|
Postprocess_BuildMesh(**it, &tmesh);
|
||||||
|
if (tmesh != nullptr) {
|
||||||
|
// if mesh successfully built then add data about it to arrays
|
||||||
|
pNodeMeshInd.push_back(static_cast<unsigned int>(pSceneMeshList.size()));
|
||||||
|
pSceneMeshList.push_back(tmesh);
|
||||||
|
// keep mesh type. Need above for texture coordinate generation.
|
||||||
|
mesh_type = (*it)->Type;
|
||||||
|
}
|
||||||
|
} else if ((*it)->Type == X3DElemType::ENET_Appearance) {
|
||||||
|
Postprocess_BuildMaterial(**it, &tmat);
|
||||||
|
if (tmat != nullptr) {
|
||||||
|
// if material successfully built then add data about it to array
|
||||||
|
mat_ind = static_cast<unsigned int>(pSceneMaterialList.size());
|
||||||
|
pSceneMaterialList.push_back(tmat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // for(std::list<X3DNodeElementBase*>::const_iterator it = pShapeNodeElement.Children.begin(); it != pShapeNodeElement.Children.end(); it++)
|
||||||
|
|
||||||
|
// associate read material with read mesh.
|
||||||
|
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.
|
||||||
|
if ((tmat->GetTextureCount(aiTextureType_DIFFUSE) != 0) && !tmesh->HasTextureCoords(0)) {
|
||||||
|
int32_t tm;
|
||||||
|
aiVector3D tvec3;
|
||||||
|
|
||||||
|
switch (mesh_type) {
|
||||||
|
case X3DElemType::ENET_Box:
|
||||||
|
tm = aiTextureMapping_BOX;
|
||||||
|
break;
|
||||||
|
case X3DElemType::ENET_Cone:
|
||||||
|
case X3DElemType::ENET_Cylinder:
|
||||||
|
tm = aiTextureMapping_CYLINDER;
|
||||||
|
break;
|
||||||
|
case X3DElemType::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 != nullptr) && (tmat != nullptr))
|
||||||
|
}
|
||||||
|
|
||||||
|
void X3DImporter::Postprocess_CollectMetadata(const X3DNodeElementBase &pNodeElement, aiNode &pSceneNode) const {
|
||||||
|
std::list<X3DNodeElementBase *> meta_list;
|
||||||
|
size_t meta_idx;
|
||||||
|
|
||||||
|
PostprocessHelper_CollectMetadata(pNodeElement, meta_list); // find metadata in current node element.
|
||||||
|
if (!meta_list.empty()) {
|
||||||
|
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 = aiMetadata::Alloc(static_cast<unsigned int>(meta_list.size()));
|
||||||
|
meta_idx = 0;
|
||||||
|
for (std::list<X3DNodeElementBase *>::const_iterator it = meta_list.begin(); it != meta_list.end(); ++it, ++meta_idx) {
|
||||||
|
X3DNodeElementMeta *cur_meta = (X3DNodeElementMeta *)*it;
|
||||||
|
|
||||||
|
// due to limitations we can add only first element of value list.
|
||||||
|
// Add an element according to its type.
|
||||||
|
if ((*it)->Type == X3DElemType::ENET_MetaBoolean) {
|
||||||
|
if (((X3DNodeElementMetaBoolean *)cur_meta)->Value.size() > 0)
|
||||||
|
pSceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx), cur_meta->Name, *(((X3DNodeElementMetaBoolean *)cur_meta)->Value.begin()) == true);
|
||||||
|
} else if ((*it)->Type == X3DElemType::ENET_MetaDouble) {
|
||||||
|
if (((X3DNodeElementMetaDouble *)cur_meta)->Value.size() > 0)
|
||||||
|
pSceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx), cur_meta->Name, (float)*(((X3DNodeElementMetaDouble *)cur_meta)->Value.begin()));
|
||||||
|
} else if ((*it)->Type == X3DElemType::ENET_MetaFloat) {
|
||||||
|
if (((X3DNodeElementMetaFloat *)cur_meta)->Value.size() > 0)
|
||||||
|
pSceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx), cur_meta->Name, *(((X3DNodeElementMetaFloat *)cur_meta)->Value.begin()));
|
||||||
|
} else if ((*it)->Type == X3DElemType::ENET_MetaInteger) {
|
||||||
|
if (((X3DNodeElementMetaInt *)cur_meta)->Value.size() > 0)
|
||||||
|
pSceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx), cur_meta->Name, *(((X3DNodeElementMetaInt *)cur_meta)->Value.begin()));
|
||||||
|
} else if ((*it)->Type == X3DElemType::ENET_MetaString) {
|
||||||
|
if (((X3DNodeElementMetaString *)cur_meta)->Value.size() > 0) {
|
||||||
|
aiString tstr(((X3DNodeElementMetaString *)cur_meta)->Value.begin()->data());
|
||||||
|
|
||||||
|
pSceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx), cur_meta->Name, tstr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw DeadlyImportError("Postprocess. Unknown metadata type.");
|
||||||
|
} // if((*it)->Type == X3DElemType::ENET_Meta*) else
|
||||||
|
} // for(std::list<X3DNodeElementBase*>::const_iterator it = meta_list.begin(); it != meta_list.end(); it++)
|
||||||
|
} // if( !meta_list.empty() )
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Assimp
|
||||||
|
|
||||||
|
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER
|
|
@ -0,0 +1,993 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2019, 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 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
|
||||||
|
|
||||||
|
#include "X3DImporter.hpp"
|
||||||
|
#include "X3DImporter_Macro.hpp"
|
||||||
|
#include "X3DXmlHelper.h"
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
// <Color
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// color="" MFColor [inputOutput]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readColor(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
std::list<aiColor3D> color;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
X3DXmlHelper::getColor3DListAttribute(node, "color", color);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Color, ne);
|
||||||
|
} else {
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementColor(mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
((X3DNodeElementColor *)ne)->Value = color;
|
||||||
|
// check for X3DMetadataObject childs.
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "Color");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <ColorRGBA
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// color="" MFColorRGBA [inputOutput]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readColorRGBA(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
std::list<aiColor4D> color;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
X3DXmlHelper::getColor4DListAttribute(node, "color", color);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_ColorRGBA, ne);
|
||||||
|
} else {
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementColorRGBA(mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
((X3DNodeElementColorRGBA *)ne)->Value = color;
|
||||||
|
// check for X3DMetadataObject childs.
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "ColorRGBA");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <Coordinate
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// point="" MFVec3f [inputOutput]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readCoordinate(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
std::list<aiVector3D> point;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
X3DXmlHelper::getVector3DListAttribute(node, "point", point);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Coordinate, ne);
|
||||||
|
} else {
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementCoordinate(mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
((X3DNodeElementCoordinate *)ne)->Value = point;
|
||||||
|
// check for X3DMetadataObject childs.
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "Coordinate");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <IndexedLineSet
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// colorIndex="" MFInt32 [initializeOnly]
|
||||||
|
// colorPerVertex="true" SFBool [initializeOnly]
|
||||||
|
// coordIndex="" MFInt32 [initializeOnly]
|
||||||
|
// >
|
||||||
|
// <!-- ColorCoordinateContentModel -->
|
||||||
|
// 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.
|
||||||
|
// </IndexedLineSet>
|
||||||
|
void X3DImporter::readIndexedLineSet(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
std::vector<int32_t> colorIndex;
|
||||||
|
bool colorPerVertex = true;
|
||||||
|
std::vector<int32_t> coordIndex;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
X3DXmlHelper::getInt32ArrayAttribute(node, "colorIndex", colorIndex);
|
||||||
|
XmlParser::getBoolAttribute(node, "colorPerVertex", colorPerVertex);
|
||||||
|
X3DXmlHelper::getInt32ArrayAttribute(node, "coordIndex", coordIndex);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, 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 X3DNodeElementIndexedSet(X3DElemType::ENET_IndexedLineSet, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
X3DNodeElementIndexedSet &ne_alias = *((X3DNodeElementIndexedSet *)ne);
|
||||||
|
|
||||||
|
ne_alias.ColorIndex = colorIndex;
|
||||||
|
ne_alias.ColorPerVertex = colorPerVertex;
|
||||||
|
ne_alias.CoordIndex = coordIndex;
|
||||||
|
// check for child nodes
|
||||||
|
if (!isNodeEmpty(node)) {
|
||||||
|
ParseHelper_Node_Enter(ne);
|
||||||
|
for (auto currentChildNode : node.children()) {
|
||||||
|
const std::string ¤tChildName = currentChildNode.name();
|
||||||
|
// check for Color and Coordinate nodes
|
||||||
|
if (currentChildName == "Color")
|
||||||
|
readColor(currentChildNode);
|
||||||
|
else if (currentChildName == "ColorRGBA")
|
||||||
|
readColorRGBA(currentChildNode);
|
||||||
|
else if (currentChildName == "Coordinate")
|
||||||
|
readCoordinate(currentChildNode);
|
||||||
|
// check for X3DMetadataObject
|
||||||
|
else if (!checkForMetadataNode(currentChildNode))
|
||||||
|
skipUnsupportedNode("IndexedLineSet", currentChildNode);
|
||||||
|
}
|
||||||
|
ParseHelper_Node_Exit();
|
||||||
|
} // if(!isNodeEmpty(node))
|
||||||
|
else {
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <IndexedTriangleFanSet
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// ccw="true" SFBool [initializeOnly]
|
||||||
|
// colorPerVertex="true" SFBool [initializeOnly]
|
||||||
|
// index="" MFInt32 [initializeOnly]
|
||||||
|
// normalPerVertex="true" SFBool [initializeOnly]
|
||||||
|
// solid="true" SFBool [initializeOnly]
|
||||||
|
// >
|
||||||
|
// <!-- ComposedGeometryContentModel -->
|
||||||
|
// 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.
|
||||||
|
// </IndexedTriangleFanSet>
|
||||||
|
void X3DImporter::readIndexedTriangleFanSet(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
bool ccw = true;
|
||||||
|
bool colorPerVertex = true;
|
||||||
|
std::vector<int32_t> index;
|
||||||
|
bool normalPerVertex = true;
|
||||||
|
bool solid = true;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getBoolAttribute(node, "ccw", ccw);
|
||||||
|
XmlParser::getBoolAttribute(node, "colorPerVertex", colorPerVertex);
|
||||||
|
X3DXmlHelper::getInt32ArrayAttribute(node, "index", index);
|
||||||
|
XmlParser::getBoolAttribute(node, "normalPerVertex", normalPerVertex);
|
||||||
|
XmlParser::getBoolAttribute(node, "solid", solid);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, 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 X3DNodeElementIndexedSet(X3DElemType::ENET_IndexedTriangleFanSet, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
X3DNodeElementIndexedSet &ne_alias = *((X3DNodeElementIndexedSet *)ne);
|
||||||
|
|
||||||
|
ne_alias.CCW = ccw;
|
||||||
|
ne_alias.ColorPerVertex = colorPerVertex;
|
||||||
|
ne_alias.NormalPerVertex = normalPerVertex;
|
||||||
|
ne_alias.Solid = solid;
|
||||||
|
|
||||||
|
ne_alias.CoordIndex.clear();
|
||||||
|
int counter = 0;
|
||||||
|
int32_t idx[3];
|
||||||
|
for (std::vector<int32_t>::const_iterator idx_it = index.begin(); idx_it != index.end(); ++idx_it) {
|
||||||
|
idx[2] = *idx_it;
|
||||||
|
if (idx[2] < 0) {
|
||||||
|
counter = 0;
|
||||||
|
} else {
|
||||||
|
if (counter >= 2) {
|
||||||
|
if (ccw) {
|
||||||
|
ne_alias.CoordIndex.push_back(idx[0]);
|
||||||
|
ne_alias.CoordIndex.push_back(idx[1]);
|
||||||
|
ne_alias.CoordIndex.push_back(idx[2]);
|
||||||
|
} else {
|
||||||
|
ne_alias.CoordIndex.push_back(idx[0]);
|
||||||
|
ne_alias.CoordIndex.push_back(idx[2]);
|
||||||
|
ne_alias.CoordIndex.push_back(idx[1]);
|
||||||
|
}
|
||||||
|
ne_alias.CoordIndex.push_back(-1);
|
||||||
|
idx[1] = idx[2];
|
||||||
|
} else {
|
||||||
|
idx[counter] = idx[2];
|
||||||
|
}
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
} // for(std::list<int32_t>::const_iterator idx_it = index.begin(); idx_it != ne_alias.index.end(); idx_it++)
|
||||||
|
|
||||||
|
// check for child nodes
|
||||||
|
if (!isNodeEmpty(node)) {
|
||||||
|
ParseHelper_Node_Enter(ne);
|
||||||
|
for (auto currentChildNode : node.children()) {
|
||||||
|
const std::string ¤tChildName = currentChildNode.name();
|
||||||
|
// check for X3DComposedGeometryNodes
|
||||||
|
if (currentChildName == "Color")
|
||||||
|
readColor(currentChildNode);
|
||||||
|
else if (currentChildName == "ColorRGBA")
|
||||||
|
readColorRGBA(currentChildNode);
|
||||||
|
else if (currentChildName == "Coordinate")
|
||||||
|
readCoordinate(currentChildNode);
|
||||||
|
else if (currentChildName == "Normal")
|
||||||
|
readNormal(currentChildNode);
|
||||||
|
else if (currentChildName == "TextureCoordinate")
|
||||||
|
readTextureCoordinate(currentChildNode);
|
||||||
|
// check for X3DMetadataObject
|
||||||
|
else if (!checkForMetadataNode(currentChildNode))
|
||||||
|
skipUnsupportedNode("IndexedTriangleFanSet", currentChildNode);
|
||||||
|
}
|
||||||
|
ParseHelper_Node_Exit();
|
||||||
|
} // if(!isNodeEmpty(node))
|
||||||
|
else {
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <IndexedTriangleSet
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// ccw="true" SFBool [initializeOnly]
|
||||||
|
// colorPerVertex="true" SFBool [initializeOnly]
|
||||||
|
// index="" MFInt32 [initializeOnly]
|
||||||
|
// normalPerVertex="true" SFBool [initializeOnly]
|
||||||
|
// solid="true" SFBool [initializeOnly]
|
||||||
|
// >
|
||||||
|
// <!-- ComposedGeometryContentModel -->
|
||||||
|
// 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.
|
||||||
|
// </IndexedTriangleSet>
|
||||||
|
void X3DImporter::readIndexedTriangleSet(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
bool ccw = true;
|
||||||
|
bool colorPerVertex = true;
|
||||||
|
std::vector<int32_t> index;
|
||||||
|
bool normalPerVertex = true;
|
||||||
|
bool solid = true;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getBoolAttribute(node, "ccw", ccw);
|
||||||
|
XmlParser::getBoolAttribute(node, "colorPerVertex", colorPerVertex);
|
||||||
|
X3DXmlHelper::getInt32ArrayAttribute(node, "index", index);
|
||||||
|
XmlParser::getBoolAttribute(node, "normalPerVertex", normalPerVertex);
|
||||||
|
XmlParser::getBoolAttribute(node, "solid", solid);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, 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 X3DNodeElementIndexedSet(X3DElemType::ENET_IndexedTriangleSet, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
X3DNodeElementIndexedSet &ne_alias = *((X3DNodeElementIndexedSet *)ne);
|
||||||
|
|
||||||
|
ne_alias.CCW = ccw;
|
||||||
|
ne_alias.ColorPerVertex = colorPerVertex;
|
||||||
|
ne_alias.NormalPerVertex = normalPerVertex;
|
||||||
|
ne_alias.Solid = solid;
|
||||||
|
|
||||||
|
ne_alias.CoordIndex.clear();
|
||||||
|
int counter = 0;
|
||||||
|
int32_t idx[3];
|
||||||
|
for (std::vector<int32_t>::const_iterator idx_it = index.begin(); idx_it != index.end(); ++idx_it) {
|
||||||
|
idx[counter++] = *idx_it;
|
||||||
|
if (counter > 2) {
|
||||||
|
counter = 0;
|
||||||
|
if (ccw) {
|
||||||
|
ne_alias.CoordIndex.push_back(idx[0]);
|
||||||
|
ne_alias.CoordIndex.push_back(idx[1]);
|
||||||
|
ne_alias.CoordIndex.push_back(idx[2]);
|
||||||
|
} else {
|
||||||
|
ne_alias.CoordIndex.push_back(idx[0]);
|
||||||
|
ne_alias.CoordIndex.push_back(idx[2]);
|
||||||
|
ne_alias.CoordIndex.push_back(idx[1]);
|
||||||
|
}
|
||||||
|
ne_alias.CoordIndex.push_back(-1);
|
||||||
|
}
|
||||||
|
} // for(std::list<int32_t>::const_iterator idx_it = index.begin(); idx_it != ne_alias.index.end(); idx_it++)
|
||||||
|
|
||||||
|
// check for child nodes
|
||||||
|
if (!isNodeEmpty(node)) {
|
||||||
|
ParseHelper_Node_Enter(ne);
|
||||||
|
for (auto currentChildNode : node.children()) {
|
||||||
|
const std::string ¤tChildName = currentChildNode.name();
|
||||||
|
// check for X3DComposedGeometryNodes
|
||||||
|
if (currentChildName == "Color")
|
||||||
|
readColor(currentChildNode);
|
||||||
|
else if (currentChildName == "ColorRGBA")
|
||||||
|
readColorRGBA(currentChildNode);
|
||||||
|
else if (currentChildName == "Coordinate")
|
||||||
|
readCoordinate(currentChildNode);
|
||||||
|
else if (currentChildName == "Normal")
|
||||||
|
readNormal(currentChildNode);
|
||||||
|
else if (currentChildName == "TextureCoordinate")
|
||||||
|
readTextureCoordinate(currentChildNode);
|
||||||
|
// check for X3DMetadataObject
|
||||||
|
else if (!checkForMetadataNode(currentChildNode))
|
||||||
|
skipUnsupportedNode("IndexedTriangleSet", currentChildNode);
|
||||||
|
}
|
||||||
|
ParseHelper_Node_Exit();
|
||||||
|
} // if(!isNodeEmpty(node))
|
||||||
|
else {
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <IndexedTriangleStripSet
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// ccw="true" SFBool [initializeOnly]
|
||||||
|
// colorPerVertex="true" SFBool [initializeOnly]
|
||||||
|
// index="" MFInt32 [initializeOnly]
|
||||||
|
// normalPerVertex="true" SFBool [initializeOnly]
|
||||||
|
// solid="true" SFBool [initializeOnly]
|
||||||
|
// >
|
||||||
|
// <!-- ComposedGeometryContentModel -->
|
||||||
|
// 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.
|
||||||
|
// </IndexedTriangleStripSet>
|
||||||
|
void X3DImporter::readIndexedTriangleStripSet(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
bool ccw = true;
|
||||||
|
bool colorPerVertex = true;
|
||||||
|
std::vector<int32_t> index;
|
||||||
|
bool normalPerVertex = true;
|
||||||
|
bool solid = true;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getBoolAttribute(node, "ccw", ccw);
|
||||||
|
XmlParser::getBoolAttribute(node, "colorPerVertex", colorPerVertex);
|
||||||
|
X3DXmlHelper::getInt32ArrayAttribute(node, "index", index);
|
||||||
|
XmlParser::getBoolAttribute(node, "normalPerVertex", normalPerVertex);
|
||||||
|
XmlParser::getBoolAttribute(node, "solid", solid);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_IndexedTriangleStripSet, ne);
|
||||||
|
} else {
|
||||||
|
// check data
|
||||||
|
if (index.empty()) {
|
||||||
|
throw DeadlyImportError("IndexedTriangleStripSet must contain not empty \"index\" attribute.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementIndexedSet(X3DElemType::ENET_IndexedTriangleStripSet, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
X3DNodeElementIndexedSet &ne_alias = *((X3DNodeElementIndexedSet *)ne);
|
||||||
|
|
||||||
|
ne_alias.CCW = ccw;
|
||||||
|
ne_alias.ColorPerVertex = colorPerVertex;
|
||||||
|
ne_alias.NormalPerVertex = normalPerVertex;
|
||||||
|
ne_alias.Solid = solid;
|
||||||
|
|
||||||
|
ne_alias.CoordIndex.clear();
|
||||||
|
int counter = 0;
|
||||||
|
int32_t idx[3];
|
||||||
|
for (std::vector<int32_t>::const_iterator idx_it = index.begin(); idx_it != index.end(); ++idx_it) {
|
||||||
|
idx[2] = *idx_it;
|
||||||
|
if (idx[2] < 0) {
|
||||||
|
counter = 0;
|
||||||
|
} else {
|
||||||
|
if (counter >= 2) {
|
||||||
|
if (ccw) {
|
||||||
|
ne_alias.CoordIndex.push_back(idx[0]);
|
||||||
|
ne_alias.CoordIndex.push_back(idx[1]);
|
||||||
|
ne_alias.CoordIndex.push_back(idx[2]);
|
||||||
|
} else {
|
||||||
|
ne_alias.CoordIndex.push_back(idx[0]);
|
||||||
|
ne_alias.CoordIndex.push_back(idx[2]);
|
||||||
|
ne_alias.CoordIndex.push_back(idx[1]);
|
||||||
|
}
|
||||||
|
ne_alias.CoordIndex.push_back(-1);
|
||||||
|
}
|
||||||
|
idx[counter & 1] = idx[2];
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
} // for(std::list<int32_t>::const_iterator idx_it = index.begin(); idx_it != ne_alias.index.end(); idx_it++)
|
||||||
|
|
||||||
|
// check for child nodes
|
||||||
|
if (!isNodeEmpty(node)) {
|
||||||
|
ParseHelper_Node_Enter(ne);
|
||||||
|
for (auto currentChildNode : node.children()) {
|
||||||
|
const std::string ¤tChildName = currentChildNode.name();
|
||||||
|
// check for X3DComposedGeometryNodes
|
||||||
|
if (currentChildName == "Color")
|
||||||
|
readColor(currentChildNode);
|
||||||
|
else if (currentChildName == "ColorRGBA")
|
||||||
|
readColorRGBA(currentChildNode);
|
||||||
|
else if (currentChildName == "Coordinate")
|
||||||
|
readCoordinate(currentChildNode);
|
||||||
|
else if (currentChildName == "Normal")
|
||||||
|
readNormal(currentChildNode);
|
||||||
|
else if (currentChildName == "TextureCoordinate")
|
||||||
|
readTextureCoordinate(currentChildNode);
|
||||||
|
// check for X3DMetadataObject
|
||||||
|
else if (!checkForMetadataNode(currentChildNode))
|
||||||
|
skipUnsupportedNode("IndexedTriangleStripSet", currentChildNode);
|
||||||
|
}
|
||||||
|
ParseHelper_Node_Exit();
|
||||||
|
} // if(!isNodeEmpty(node))
|
||||||
|
else {
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <LineSet
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// vertexCount="" MFInt32 [initializeOnly]
|
||||||
|
// >
|
||||||
|
// <!-- ColorCoordinateContentModel -->
|
||||||
|
// 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.
|
||||||
|
// </LineSet>
|
||||||
|
void X3DImporter::readLineSet(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
std::vector<int32_t> vertexCount;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
X3DXmlHelper::getInt32ArrayAttribute(node, "vertexCount", vertexCount);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_LineSet, ne);
|
||||||
|
} else {
|
||||||
|
// check data
|
||||||
|
if (vertexCount.empty()) {
|
||||||
|
throw DeadlyImportError("LineSet must contain not empty \"vertexCount\" attribute.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementSet(X3DElemType::ENET_LineSet, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
X3DNodeElementSet &ne_alias = *((X3DNodeElementSet *)ne);
|
||||||
|
|
||||||
|
ne_alias.VertexCount = vertexCount;
|
||||||
|
// create CoordIdx
|
||||||
|
size_t coord_num = 0;
|
||||||
|
|
||||||
|
ne_alias.CoordIndex.clear();
|
||||||
|
for (std::vector<int32_t>::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(static_cast<int32_t>(coord_num++)); // add vertices indices
|
||||||
|
|
||||||
|
ne_alias.CoordIndex.push_back(-1); // add face delimiter.
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for child nodes
|
||||||
|
if (!isNodeEmpty(node)) {
|
||||||
|
ParseHelper_Node_Enter(ne);
|
||||||
|
for (auto currentChildNode : node.children()) {
|
||||||
|
const std::string ¤tChildName = currentChildNode.name();
|
||||||
|
// check for X3DComposedGeometryNodes
|
||||||
|
if (currentChildName == "Color")
|
||||||
|
readColor(currentChildNode);
|
||||||
|
else if (currentChildName == "ColorRGBA")
|
||||||
|
readColorRGBA(currentChildNode);
|
||||||
|
else if (currentChildName == "Coordinate")
|
||||||
|
readCoordinate(currentChildNode);
|
||||||
|
// check for X3DMetadataObject
|
||||||
|
else if (!checkForMetadataNode(currentChildNode))
|
||||||
|
skipUnsupportedNode("LineSet", currentChildNode);
|
||||||
|
}
|
||||||
|
ParseHelper_Node_Exit();
|
||||||
|
} // if(!isNodeEmpty(node))
|
||||||
|
else {
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <PointSet
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// >
|
||||||
|
// <!-- ColorCoordinateContentModel -->
|
||||||
|
// 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.
|
||||||
|
// </PointSet>
|
||||||
|
void X3DImporter::readPointSet(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_PointSet, ne);
|
||||||
|
} else {
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementIndexedSet(X3DElemType::ENET_PointSet, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
// check for child nodes
|
||||||
|
if (!isNodeEmpty(node)) {
|
||||||
|
ParseHelper_Node_Enter(ne);
|
||||||
|
for (auto currentChildNode : node.children()) {
|
||||||
|
const std::string ¤tChildName = currentChildNode.name();
|
||||||
|
// check for X3DComposedGeometryNodes
|
||||||
|
if (currentChildName == "Color")
|
||||||
|
readColor(currentChildNode);
|
||||||
|
else if (currentChildName == "ColorRGBA")
|
||||||
|
readColorRGBA(currentChildNode);
|
||||||
|
else if (currentChildName == "Coordinate")
|
||||||
|
readCoordinate(currentChildNode);
|
||||||
|
// check for X3DMetadataObject
|
||||||
|
else if (!checkForMetadataNode(currentChildNode))
|
||||||
|
skipUnsupportedNode("PointSet", currentChildNode);
|
||||||
|
}
|
||||||
|
ParseHelper_Node_Exit();
|
||||||
|
} // if(!isNodeEmpty(node))
|
||||||
|
else {
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <TriangleFanSet
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// ccw="true" SFBool [initializeOnly]
|
||||||
|
// colorPerVertex="true" SFBool [initializeOnly]
|
||||||
|
// fanCount="" MFInt32 [inputOutput]
|
||||||
|
// normalPerVertex="true" SFBool [initializeOnly]
|
||||||
|
// solid="true" SFBool [initializeOnly]
|
||||||
|
// >
|
||||||
|
// <!-- ComposedGeometryContentModel -->
|
||||||
|
// 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.
|
||||||
|
// </TriangleFanSet>
|
||||||
|
void X3DImporter::readTriangleFanSet(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
bool ccw = true;
|
||||||
|
bool colorPerVertex = true;
|
||||||
|
std::vector<int32_t> fanCount;
|
||||||
|
bool normalPerVertex = true;
|
||||||
|
bool solid = true;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getBoolAttribute(node, "ccw", ccw);
|
||||||
|
XmlParser::getBoolAttribute(node, "colorPerVertex", colorPerVertex);
|
||||||
|
X3DXmlHelper::getInt32ArrayAttribute(node, "fanCount", fanCount);
|
||||||
|
XmlParser::getBoolAttribute(node, "normalPerVertex", normalPerVertex);
|
||||||
|
XmlParser::getBoolAttribute(node, "solid", solid);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_TriangleFanSet, ne);
|
||||||
|
} else {
|
||||||
|
// check data
|
||||||
|
if (fanCount.empty()) {
|
||||||
|
throw DeadlyImportError("TriangleFanSet must contain not empty \"fanCount\" attribute.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementSet(X3DElemType::ENET_TriangleFanSet, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
X3DNodeElementSet &ne_alias = *((X3DNodeElementSet *)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::vector<int32_t>::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(static_cast<int32_t>(coord_num_first)); // first vertex is a center and always is [0].
|
||||||
|
ne_alias.CoordIndex.push_back(static_cast<int32_t>(coord_num_prev++));
|
||||||
|
ne_alias.CoordIndex.push_back(static_cast<int32_t>(coord_num_prev));
|
||||||
|
} else {
|
||||||
|
// 1 2
|
||||||
|
// 0
|
||||||
|
ne_alias.CoordIndex.push_back(static_cast<int32_t>(coord_num_first)); // first vertex is a center and always is [0].
|
||||||
|
ne_alias.CoordIndex.push_back(static_cast<int32_t>(coord_num_prev + 1));
|
||||||
|
ne_alias.CoordIndex.push_back(static_cast<int32_t>(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<int32_t>::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++)
|
||||||
|
// check for child nodes
|
||||||
|
if (!isNodeEmpty(node)) {
|
||||||
|
ParseHelper_Node_Enter(ne);
|
||||||
|
for (auto currentChildNode : node.children()) {
|
||||||
|
const std::string ¤tChildName = currentChildNode.name();
|
||||||
|
// check for X3DComposedGeometryNodes
|
||||||
|
if (currentChildName == "Color")
|
||||||
|
readColor(currentChildNode);
|
||||||
|
else if (currentChildName == "ColorRGBA")
|
||||||
|
readColorRGBA(currentChildNode);
|
||||||
|
else if (currentChildName == "Coordinate")
|
||||||
|
readCoordinate(currentChildNode);
|
||||||
|
else if (currentChildName == "Normal")
|
||||||
|
readNormal(currentChildNode);
|
||||||
|
else if (currentChildName == "TextureCoordinate")
|
||||||
|
readTextureCoordinate(currentChildNode);
|
||||||
|
// check for X3DMetadataObject
|
||||||
|
else if (!checkForMetadataNode(currentChildNode))
|
||||||
|
skipUnsupportedNode("TriangleFanSet", currentChildNode);
|
||||||
|
}
|
||||||
|
ParseHelper_Node_Exit();
|
||||||
|
} // if(!isNodeEmpty(node))
|
||||||
|
else {
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <TriangleSet
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// ccw="true" SFBool [initializeOnly]
|
||||||
|
// colorPerVertex="true" SFBool [initializeOnly]
|
||||||
|
// normalPerVertex="true" SFBool [initializeOnly]
|
||||||
|
// solid="true" SFBool [initializeOnly]
|
||||||
|
// >
|
||||||
|
// <!-- ComposedGeometryContentModel -->
|
||||||
|
// 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.
|
||||||
|
// </TriangleSet>
|
||||||
|
void X3DImporter::readTriangleSet(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
bool ccw = true;
|
||||||
|
bool colorPerVertex = true;
|
||||||
|
bool normalPerVertex = true;
|
||||||
|
bool solid = true;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getBoolAttribute(node, "ccw", ccw);
|
||||||
|
XmlParser::getBoolAttribute(node, "colorPerVertex", colorPerVertex);
|
||||||
|
XmlParser::getBoolAttribute(node, "normalPerVertex", normalPerVertex);
|
||||||
|
XmlParser::getBoolAttribute(node, "solid", solid);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_TriangleSet, ne);
|
||||||
|
} else {
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementIndexedSet(X3DElemType::ENET_TriangleSet, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
X3DNodeElementSet &ne_alias = *((X3DNodeElementSet *)ne);
|
||||||
|
|
||||||
|
ne_alias.CCW = ccw;
|
||||||
|
ne_alias.ColorPerVertex = colorPerVertex;
|
||||||
|
ne_alias.NormalPerVertex = normalPerVertex;
|
||||||
|
ne_alias.Solid = solid;
|
||||||
|
// check for child nodes
|
||||||
|
if (!isNodeEmpty(node)) {
|
||||||
|
ParseHelper_Node_Enter(ne);
|
||||||
|
for (auto currentChildNode : node.children()) {
|
||||||
|
const std::string ¤tChildName = currentChildNode.name();
|
||||||
|
// check for X3DComposedGeometryNodes
|
||||||
|
if (currentChildName == "Color")
|
||||||
|
readColor(currentChildNode);
|
||||||
|
else if (currentChildName == "ColorRGBA")
|
||||||
|
readColorRGBA(currentChildNode);
|
||||||
|
else if (currentChildName == "Coordinate")
|
||||||
|
readCoordinate(currentChildNode);
|
||||||
|
else if (currentChildName == "Normal")
|
||||||
|
readNormal(currentChildNode);
|
||||||
|
else if (currentChildName == "TextureCoordinate")
|
||||||
|
readTextureCoordinate(currentChildNode);
|
||||||
|
// check for X3DMetadataObject
|
||||||
|
else if (!checkForMetadataNode(currentChildNode))
|
||||||
|
skipUnsupportedNode("TriangleSet", currentChildNode);
|
||||||
|
}
|
||||||
|
ParseHelper_Node_Exit();
|
||||||
|
} // if(!isNodeEmpty(node))
|
||||||
|
else {
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <TriangleStripSet
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// ccw="true" SFBool [initializeOnly]
|
||||||
|
// colorPerVertex="true" SFBool [initializeOnly]
|
||||||
|
// normalPerVertex="true" SFBool [initializeOnly]
|
||||||
|
// solid="true" SFBool [initializeOnly]
|
||||||
|
// stripCount="" MFInt32 [inputOutput]
|
||||||
|
// >
|
||||||
|
// <!-- ComposedGeometryContentModel -->
|
||||||
|
// 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.
|
||||||
|
// </TriangleStripSet>
|
||||||
|
void X3DImporter::readTriangleStripSet(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
bool ccw = true;
|
||||||
|
bool colorPerVertex = true;
|
||||||
|
std::vector<int32_t> stripCount;
|
||||||
|
bool normalPerVertex = true;
|
||||||
|
bool solid = true;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getBoolAttribute(node, "ccw", ccw);
|
||||||
|
XmlParser::getBoolAttribute(node, "colorPerVertex", colorPerVertex);
|
||||||
|
X3DXmlHelper::getInt32ArrayAttribute(node, "stripCount", stripCount);
|
||||||
|
XmlParser::getBoolAttribute(node, "normalPerVertex", normalPerVertex);
|
||||||
|
XmlParser::getBoolAttribute(node, "solid", solid);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, 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 X3DNodeElementSet(X3DElemType::ENET_TriangleStripSet, mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
X3DNodeElementSet &ne_alias = *((X3DNodeElementSet *)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::vector<int32_t>::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(static_cast<int32_t>(coord_num0));
|
||||||
|
ne_alias.CoordIndex.push_back(static_cast<int32_t>(coord_num1));
|
||||||
|
ne_alias.CoordIndex.push_back(static_cast<int32_t>(coord_num2));
|
||||||
|
} else {
|
||||||
|
// 0 1
|
||||||
|
// 2
|
||||||
|
ne_alias.CoordIndex.push_back(static_cast<int32_t>(coord_num0));
|
||||||
|
ne_alias.CoordIndex.push_back(static_cast<int32_t>(coord_num2));
|
||||||
|
ne_alias.CoordIndex.push_back(static_cast<int32_t>(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<int32_t>::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++)
|
||||||
|
// check for child nodes
|
||||||
|
if (!isNodeEmpty(node)) {
|
||||||
|
ParseHelper_Node_Enter(ne);
|
||||||
|
for (auto currentChildNode : node.children()) {
|
||||||
|
const std::string ¤tChildName = currentChildNode.name();
|
||||||
|
// check for X3DComposedGeometryNodes
|
||||||
|
if (currentChildName == "Color")
|
||||||
|
readColor(currentChildNode);
|
||||||
|
else if (currentChildName == "ColorRGBA")
|
||||||
|
readColorRGBA(currentChildNode);
|
||||||
|
else if (currentChildName == "Coordinate")
|
||||||
|
readCoordinate(currentChildNode);
|
||||||
|
else if (currentChildName == "Normal")
|
||||||
|
readNormal(currentChildNode);
|
||||||
|
else if (currentChildName == "TextureCoordinate")
|
||||||
|
readTextureCoordinate(currentChildNode);
|
||||||
|
// check for X3DMetadataObject
|
||||||
|
else if (!checkForMetadataNode(currentChildNode))
|
||||||
|
skipUnsupportedNode("TriangleStripSet", currentChildNode);
|
||||||
|
}
|
||||||
|
ParseHelper_Node_Exit();
|
||||||
|
} // if(!isNodeEmpty(node))
|
||||||
|
else {
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <Normal
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// vector="" MFVec3f [inputOutput]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readNormal(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
std::list<aiVector3D> vector;
|
||||||
|
X3DNodeElementBase *ne=nullptr;
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
X3DXmlHelper::getVector3DListAttribute(node, "vector", vector);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Normal, ne);
|
||||||
|
} else {
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementNormal(mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
((X3DNodeElementNormal *)ne)->Value = vector;
|
||||||
|
// check for X3DMetadataObject childs.
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "Normal");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
|
@ -0,0 +1,241 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2019, 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 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
|
||||||
|
|
||||||
|
#include "X3DImporter.hpp"
|
||||||
|
#include "X3DImporter_Macro.hpp"
|
||||||
|
#include "X3DXmlHelper.h"
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
void X3DImporter::readShape(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Shape, ne);
|
||||||
|
} else {
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementShape(mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
// check for child nodes
|
||||||
|
if (!isNodeEmpty(node)) {
|
||||||
|
ParseHelper_Node_Enter(ne);
|
||||||
|
for (auto currentChildNode : node.children()) {
|
||||||
|
const std::string ¤tChildName = currentChildNode.name();
|
||||||
|
// check for appearance node
|
||||||
|
if (currentChildName == "Appearance") readAppearance(currentChildNode);
|
||||||
|
// check for X3DGeometryNodes
|
||||||
|
else if (currentChildName == "Arc2D")
|
||||||
|
readArc2D(currentChildNode);
|
||||||
|
else if (currentChildName == "ArcClose2D")
|
||||||
|
readArcClose2D(currentChildNode);
|
||||||
|
else if (currentChildName == "Circle2D")
|
||||||
|
readCircle2D(currentChildNode);
|
||||||
|
else if (currentChildName == "Disk2D")
|
||||||
|
readDisk2D(currentChildNode);
|
||||||
|
else if (currentChildName == "Polyline2D")
|
||||||
|
readPolyline2D(currentChildNode);
|
||||||
|
else if (currentChildName == "Polypoint2D")
|
||||||
|
readPolypoint2D(currentChildNode);
|
||||||
|
else if (currentChildName == "Rectangle2D")
|
||||||
|
readRectangle2D(currentChildNode);
|
||||||
|
else if (currentChildName == "TriangleSet2D")
|
||||||
|
readTriangleSet2D(currentChildNode);
|
||||||
|
else if (currentChildName == "Box")
|
||||||
|
readBox(currentChildNode);
|
||||||
|
else if (currentChildName == "Cone")
|
||||||
|
readCone(currentChildNode);
|
||||||
|
else if (currentChildName == "Cylinder")
|
||||||
|
readCylinder(currentChildNode);
|
||||||
|
else if (currentChildName == "ElevationGrid")
|
||||||
|
readElevationGrid(currentChildNode);
|
||||||
|
else if (currentChildName == "Extrusion")
|
||||||
|
readExtrusion(currentChildNode);
|
||||||
|
else if (currentChildName == "IndexedFaceSet")
|
||||||
|
readIndexedFaceSet(currentChildNode);
|
||||||
|
else if (currentChildName == "Sphere")
|
||||||
|
readSphere(currentChildNode);
|
||||||
|
else if (currentChildName == "IndexedLineSet")
|
||||||
|
readIndexedLineSet(currentChildNode);
|
||||||
|
else if (currentChildName == "LineSet")
|
||||||
|
readLineSet(currentChildNode);
|
||||||
|
else if (currentChildName == "PointSet")
|
||||||
|
readPointSet(currentChildNode);
|
||||||
|
else if (currentChildName == "IndexedTriangleFanSet")
|
||||||
|
readIndexedTriangleFanSet(currentChildNode);
|
||||||
|
else if (currentChildName == "IndexedTriangleSet")
|
||||||
|
readIndexedTriangleSet(currentChildNode);
|
||||||
|
else if (currentChildName == "IndexedTriangleStripSet")
|
||||||
|
readIndexedTriangleStripSet(currentChildNode);
|
||||||
|
else if (currentChildName == "TriangleFanSet")
|
||||||
|
readTriangleFanSet(currentChildNode);
|
||||||
|
else if (currentChildName == "TriangleSet")
|
||||||
|
readTriangleSet(currentChildNode);
|
||||||
|
// check for X3DMetadataObject
|
||||||
|
else if (!checkForMetadataNode(currentChildNode))
|
||||||
|
skipUnsupportedNode("Shape", currentChildNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseHelper_Node_Exit();
|
||||||
|
} // if (!isNodeEmpty(node))
|
||||||
|
else {
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <Appearance
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// >
|
||||||
|
// <!-- AppearanceChildContentModel -->
|
||||||
|
// "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."
|
||||||
|
// </Appearance>
|
||||||
|
void X3DImporter::readAppearance(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Appearance, ne);
|
||||||
|
} else {
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementAppearance(mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
// check for child nodes
|
||||||
|
if (!isNodeEmpty(node)) {
|
||||||
|
ParseHelper_Node_Enter(ne);
|
||||||
|
for (auto currentChildNode : node.children()) {
|
||||||
|
const std::string ¤tChildName = currentChildNode.name();
|
||||||
|
if (currentChildName == "Material")
|
||||||
|
readMaterial(currentChildNode);
|
||||||
|
else if (currentChildName == "ImageTexture")
|
||||||
|
readImageTexture(currentChildNode);
|
||||||
|
else if (currentChildName == "TextureTransform")
|
||||||
|
readTextureTransform(currentChildNode);
|
||||||
|
// check for X3DMetadataObject
|
||||||
|
else if (!checkForMetadataNode(currentChildNode))
|
||||||
|
skipUnsupportedNode("Appearance", currentChildNode);
|
||||||
|
}
|
||||||
|
ParseHelper_Node_Exit();
|
||||||
|
} // if(!isNodeEmpty(node))
|
||||||
|
else {
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <Material
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// ambientIntensity="0.2" SFFloat [inputOutput]
|
||||||
|
// diffuseColor="0.8 0.8 0.8" SFColor [inputOutput]
|
||||||
|
// emissiveColor="0 0 0" SFColor [inputOutput]
|
||||||
|
// shininess="0.2" SFFloat [inputOutput]
|
||||||
|
// specularColor="0 0 0" SFColor [inputOutput]
|
||||||
|
// transparency="0" SFFloat [inputOutput]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readMaterial(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
float ambientIntensity = 0.2f;
|
||||||
|
float shininess = 0.2f;
|
||||||
|
float transparency = 0;
|
||||||
|
aiColor3D diffuseColor(0.8f, 0.8f, 0.8f);
|
||||||
|
aiColor3D emissiveColor(0, 0, 0);
|
||||||
|
aiColor3D specularColor(0, 0, 0);
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getFloatAttribute(node, "ambientIntensity", ambientIntensity);
|
||||||
|
XmlParser::getFloatAttribute(node, "shininess", shininess);
|
||||||
|
XmlParser::getFloatAttribute(node, "transparency", transparency);
|
||||||
|
X3DXmlHelper::getColor3DAttribute(node, "diffuseColor", diffuseColor);
|
||||||
|
X3DXmlHelper::getColor3DAttribute(node, "emissiveColor", emissiveColor);
|
||||||
|
X3DXmlHelper::getColor3DAttribute(node, "specularColor", specularColor);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Material, ne);
|
||||||
|
} else {
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementMaterial(mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
((X3DNodeElementMaterial *)ne)->AmbientIntensity = ambientIntensity;
|
||||||
|
((X3DNodeElementMaterial *)ne)->Shininess = shininess;
|
||||||
|
((X3DNodeElementMaterial *)ne)->Transparency = transparency;
|
||||||
|
((X3DNodeElementMaterial *)ne)->DiffuseColor = diffuseColor;
|
||||||
|
((X3DNodeElementMaterial *)ne)->EmissiveColor = emissiveColor;
|
||||||
|
((X3DNodeElementMaterial *)ne)->SpecularColor = specularColor;
|
||||||
|
// check for child nodes
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "Material");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
|
@ -0,0 +1,179 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2019, 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 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
|
||||||
|
|
||||||
|
#include "X3DImporter.hpp"
|
||||||
|
#include "X3DImporter_Macro.hpp"
|
||||||
|
#include "X3DXmlHelper.h"
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
// <ImageTexture
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// repeatS="true" SFBool
|
||||||
|
// repeatT="true" SFBool
|
||||||
|
// url="" MFString
|
||||||
|
// />
|
||||||
|
// When the url field contains no values ([]), texturing is disabled.
|
||||||
|
void X3DImporter::readImageTexture(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
bool repeatS = true;
|
||||||
|
bool repeatT = true;
|
||||||
|
std::list<std::string> url;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
XmlParser::getBoolAttribute(node, "repeatS", repeatS);
|
||||||
|
XmlParser::getBoolAttribute(node, "repeatT", repeatT);
|
||||||
|
X3DXmlHelper::getStringListAttribute(node, "url", url);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_ImageTexture, ne);
|
||||||
|
} else {
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementImageTexture(mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
((X3DNodeElementImageTexture *)ne)->RepeatS = repeatS;
|
||||||
|
((X3DNodeElementImageTexture *)ne)->RepeatT = repeatT;
|
||||||
|
// Attribute "url" can contain list of strings. But we need only one - first.
|
||||||
|
if (!url.empty())
|
||||||
|
((X3DNodeElementImageTexture *)ne)->URL = url.front();
|
||||||
|
else
|
||||||
|
((X3DNodeElementImageTexture *)ne)->URL = "";
|
||||||
|
|
||||||
|
// check for X3DMetadataObject childs.
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "ImageTexture");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <TextureCoordinate
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// point="" MFVec3f [inputOutput]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readTextureCoordinate(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
std::list<aiVector2D> point;
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
X3DXmlHelper::getVector2DListAttribute(node, "point", point);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_TextureCoordinate, ne);
|
||||||
|
} else {
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementTextureCoordinate(mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
((X3DNodeElementTextureCoordinate *)ne)->Value = point;
|
||||||
|
// check for X3DMetadataObject childs.
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "TextureCoordinate");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// <TextureTransform
|
||||||
|
// DEF="" ID
|
||||||
|
// USE="" IDREF
|
||||||
|
// center="0 0" SFVec2f [inputOutput]
|
||||||
|
// rotation="0" SFFloat [inputOutput]
|
||||||
|
// scale="1 1" SFVec2f [inputOutput]
|
||||||
|
// translation="0 0" SFVec2f [inputOutput]
|
||||||
|
// />
|
||||||
|
void X3DImporter::readTextureTransform(XmlNode &node) {
|
||||||
|
std::string use, def;
|
||||||
|
aiVector2D center(0, 0);
|
||||||
|
float rotation = 0;
|
||||||
|
aiVector2D scale(1, 1);
|
||||||
|
aiVector2D translation(0, 0);
|
||||||
|
X3DNodeElementBase *ne(nullptr);
|
||||||
|
|
||||||
|
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
|
||||||
|
X3DXmlHelper::getVector2DAttribute(node, "center", center);
|
||||||
|
XmlParser::getFloatAttribute(node, "rotation", rotation);
|
||||||
|
X3DXmlHelper::getVector2DAttribute(node, "scale", scale);
|
||||||
|
X3DXmlHelper::getVector2DAttribute(node, "translation", translation);
|
||||||
|
|
||||||
|
// if "USE" defined then find already defined element.
|
||||||
|
if (!use.empty()) {
|
||||||
|
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_TextureTransform, ne);
|
||||||
|
} else {
|
||||||
|
// create and if needed - define new geometry object.
|
||||||
|
ne = new X3DNodeElementTextureTransform(mNodeElementCur);
|
||||||
|
if (!def.empty()) ne->ID = def;
|
||||||
|
|
||||||
|
((X3DNodeElementTextureTransform *)ne)->Center = center;
|
||||||
|
((X3DNodeElementTextureTransform *)ne)->Rotation = rotation;
|
||||||
|
((X3DNodeElementTextureTransform *)ne)->Scale = scale;
|
||||||
|
((X3DNodeElementTextureTransform *)ne)->Translation = translation;
|
||||||
|
// check for X3DMetadataObject childs.
|
||||||
|
if (!isNodeEmpty(node))
|
||||||
|
childrenReadMetadata(node, ne, "TextureTransform");
|
||||||
|
else
|
||||||
|
mNodeElementCur->Children.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
|
|
@ -0,0 +1,294 @@
|
||||||
|
#include "X3DXmlHelper.h"
|
||||||
|
#include "X3DImporter.hpp"
|
||||||
|
|
||||||
|
#include <assimp/ParsingUtils.h>
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
bool X3DXmlHelper::getColor3DAttribute(XmlNode &node, const char *attributeName, aiColor3D &color) {
|
||||||
|
std::string val;
|
||||||
|
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
|
||||||
|
std::vector<std::string> values;
|
||||||
|
tokenize<std::string>(val, values, " ");
|
||||||
|
if (values.size() != 3) {
|
||||||
|
Throw_ConvertFail_Str2ArrF(node.name(), attributeName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto it = values.begin();
|
||||||
|
color.r = stof(*it++);
|
||||||
|
color.g = stof(*it++);
|
||||||
|
color.b = stof(*it);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X3DXmlHelper::getVector2DAttribute(XmlNode &node, const char *attributeName, aiVector2D &color) {
|
||||||
|
std::string val;
|
||||||
|
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
|
||||||
|
std::vector<std::string> values;
|
||||||
|
tokenize<std::string>(val, values, " ");
|
||||||
|
if (values.size() != 2) {
|
||||||
|
Throw_ConvertFail_Str2ArrF(node.name(), attributeName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto it = values.begin();
|
||||||
|
color.x = stof(*it++);
|
||||||
|
color.y = stof(*it);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X3DXmlHelper::getVector3DAttribute(XmlNode &node, const char *attributeName, aiVector3D &color) {
|
||||||
|
std::string val;
|
||||||
|
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
|
||||||
|
std::vector<std::string> values;
|
||||||
|
tokenize<std::string>(val, values, " ");
|
||||||
|
if (values.size() != 3) {
|
||||||
|
Throw_ConvertFail_Str2ArrF(node.name(), attributeName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto it = values.begin();
|
||||||
|
color.x = stof(*it++);
|
||||||
|
color.y = stof(*it++);
|
||||||
|
color.z = stof(*it);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X3DXmlHelper::getBooleanArrayAttribute(XmlNode &node, const char *attributeName, std::vector<bool> &boolArray) {
|
||||||
|
std::string val;
|
||||||
|
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
|
||||||
|
std::vector<std::string> values;
|
||||||
|
tokenize<std::string>(val, values, " ");
|
||||||
|
auto it = values.begin();
|
||||||
|
while (it != values.end()) {
|
||||||
|
auto s = *it++;
|
||||||
|
if (!s.empty())
|
||||||
|
boolArray.push_back(s[0] == 't' || s[0] == '1');
|
||||||
|
else
|
||||||
|
Throw_ConvertFail_Str2ArrB(node.name(), attributeName);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X3DXmlHelper::getDoubleArrayAttribute(XmlNode &node, const char *attributeName, std::vector<double> &doubleArray) {
|
||||||
|
std::string val;
|
||||||
|
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
|
||||||
|
std::vector<std::string> values;
|
||||||
|
tokenize<std::string>(val, values, " ");
|
||||||
|
auto it = values.begin();
|
||||||
|
while (it != values.end()) {
|
||||||
|
auto s = *it++;
|
||||||
|
if (!s.empty())
|
||||||
|
doubleArray.push_back(atof(s.c_str()));
|
||||||
|
else
|
||||||
|
Throw_ConvertFail_Str2ArrD(node.name(), attributeName);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X3DXmlHelper::getFloatArrayAttribute(XmlNode &node, const char *attributeName, std::vector<float> &floatArray) {
|
||||||
|
std::string val;
|
||||||
|
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
|
||||||
|
std::vector<std::string> values;
|
||||||
|
tokenize<std::string>(val, values, " ");
|
||||||
|
auto it = values.begin();
|
||||||
|
while (it != values.end()) {
|
||||||
|
auto s = *it++;
|
||||||
|
if (!s.empty())
|
||||||
|
floatArray.push_back((float)atof(s.c_str()));
|
||||||
|
else
|
||||||
|
Throw_ConvertFail_Str2ArrF(node.name(), attributeName);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X3DXmlHelper::getInt32ArrayAttribute(XmlNode &node, const char *attributeName, std::vector<int32_t> &intArray) {
|
||||||
|
std::string val;
|
||||||
|
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
|
||||||
|
std::vector<std::string> values;
|
||||||
|
tokenize<std::string>(val, values, " ");
|
||||||
|
auto it = values.begin();
|
||||||
|
while (it != values.end()) {
|
||||||
|
auto s = *it++;
|
||||||
|
if (!s.empty())
|
||||||
|
intArray.push_back((int32_t)atof(s.c_str()));
|
||||||
|
else
|
||||||
|
Throw_ConvertFail_Str2ArrI(node.name(), attributeName);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X3DXmlHelper::getStringListAttribute(XmlNode &node, const char *attributeName, std::list<std::string> &stringList) {
|
||||||
|
std::string val;
|
||||||
|
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
|
||||||
|
std::vector<std::string> values;
|
||||||
|
tokenize<std::string>(val, values, " ");
|
||||||
|
auto it = values.begin();
|
||||||
|
std::string currentConcat = "";
|
||||||
|
bool inQuotes = false;
|
||||||
|
while (it != values.end()) {
|
||||||
|
auto s = *it++;
|
||||||
|
if (!s.empty()) {
|
||||||
|
if (inQuotes) {
|
||||||
|
if (*(s.rbegin()) == '"') {
|
||||||
|
stringList.push_back(currentConcat + s.substr(0, s.length() - 1));
|
||||||
|
currentConcat = "";
|
||||||
|
inQuotes = false;
|
||||||
|
} else {
|
||||||
|
currentConcat += " " + s;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (s[0] == '"') {
|
||||||
|
currentConcat = s.substr(1);
|
||||||
|
inQuotes = true;
|
||||||
|
} else {
|
||||||
|
stringList.push_back(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!inQuotes)
|
||||||
|
Throw_ConvertFail_Str2ArrI(node.name(), attributeName);
|
||||||
|
}
|
||||||
|
if (inQuotes) Throw_ConvertFail_Str2ArrI(node.name(), attributeName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X3DXmlHelper::getStringArrayAttribute(XmlNode &node, const char *attributeName, std::vector<std::string> &stringArray) {
|
||||||
|
std::list<std::string> tlist;
|
||||||
|
|
||||||
|
if (getStringListAttribute(node, attributeName, tlist)) {
|
||||||
|
if (!tlist.empty()) {
|
||||||
|
stringArray.reserve(tlist.size());
|
||||||
|
for (std::list<std::string>::iterator it = tlist.begin(); it != tlist.end(); ++it) {
|
||||||
|
stringArray.push_back(*it);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X3DXmlHelper::getVector2DListAttribute(XmlNode &node, const char *attributeName, std::list<aiVector2D> &vectorList) {
|
||||||
|
std::string val;
|
||||||
|
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
|
||||||
|
std::vector<std::string> values;
|
||||||
|
tokenize<std::string>(val, values, " ");
|
||||||
|
if (values.size() % 2) Throw_ConvertFail_Str2ArrF(node.name(), attributeName);
|
||||||
|
auto it = values.begin();
|
||||||
|
while (it != values.end()) {
|
||||||
|
aiVector2D tvec;
|
||||||
|
|
||||||
|
tvec.x = (float)atof((*it++).c_str());
|
||||||
|
tvec.y = (float)atof((*it++).c_str());
|
||||||
|
vectorList.push_back(tvec);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X3DXmlHelper::getVector2DArrayAttribute(XmlNode &node, const char *attributeName, std::vector<aiVector2D> &vectorArray) {
|
||||||
|
std::list<aiVector2D> tlist;
|
||||||
|
|
||||||
|
if (getVector2DListAttribute(node, attributeName, tlist)) {
|
||||||
|
if (!tlist.empty()) {
|
||||||
|
vectorArray.reserve(tlist.size());
|
||||||
|
for (std::list<aiVector2D>::iterator it = tlist.begin(); it != tlist.end(); ++it) {
|
||||||
|
vectorArray.push_back(*it);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X3DXmlHelper::getVector3DListAttribute(XmlNode &node, const char *attributeName, std::list<aiVector3D> &vectorList) {
|
||||||
|
std::string val;
|
||||||
|
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
|
||||||
|
std::vector<std::string> values;
|
||||||
|
tokenize<std::string>(val, values, " ");
|
||||||
|
if (values.size() % 3 != 0) Throw_ConvertFail_Str2ArrF(node.name(), attributeName);
|
||||||
|
auto it = values.begin();
|
||||||
|
while (it != values.end()) {
|
||||||
|
aiVector3D tvec;
|
||||||
|
|
||||||
|
tvec.x = (float)atof((*it++).c_str());
|
||||||
|
tvec.y = (float)atof((*it++).c_str());
|
||||||
|
tvec.z = (float)atof((*it++).c_str());
|
||||||
|
vectorList.push_back(tvec);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X3DXmlHelper::getVector3DArrayAttribute(XmlNode &node, const char *attributeName, std::vector<aiVector3D> &vectorArray) {
|
||||||
|
std::list<aiVector3D> tlist;
|
||||||
|
|
||||||
|
if (getVector3DListAttribute(node, attributeName, tlist)) {
|
||||||
|
if (!tlist.empty()) {
|
||||||
|
vectorArray.reserve(tlist.size());
|
||||||
|
for (std::list<aiVector3D>::iterator it = tlist.begin(); it != tlist.end(); ++it) {
|
||||||
|
vectorArray.push_back(*it);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X3DXmlHelper::getColor3DListAttribute(XmlNode &node, const char *attributeName, std::list<aiColor3D> &colorList) {
|
||||||
|
std::string val;
|
||||||
|
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
|
||||||
|
std::vector<std::string> values;
|
||||||
|
tokenize<std::string>(val, values, " ");
|
||||||
|
if (values.size() % 3 != 0) Throw_ConvertFail_Str2ArrF(node.name(), attributeName);
|
||||||
|
auto it = values.begin();
|
||||||
|
while (it != values.end()) {
|
||||||
|
aiColor3D tvec;
|
||||||
|
|
||||||
|
tvec.r = (float)atof((*it++).c_str());
|
||||||
|
tvec.g = (float)atof((*it++).c_str());
|
||||||
|
tvec.b = (float)atof((*it++).c_str());
|
||||||
|
colorList.push_back(tvec);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X3DXmlHelper::getColor4DListAttribute(XmlNode &node, const char *attributeName, std::list<aiColor4D> &colorList) {
|
||||||
|
std::string val;
|
||||||
|
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
|
||||||
|
std::vector<std::string> values;
|
||||||
|
tokenize<std::string>(val, values, " ");
|
||||||
|
if (values.size() % 4 != 0) Throw_ConvertFail_Str2ArrF(node.name(), attributeName);
|
||||||
|
auto it = values.begin();
|
||||||
|
while (it != values.end()) {
|
||||||
|
aiColor4D tvec;
|
||||||
|
|
||||||
|
tvec.r = (float)atof((*it++).c_str());
|
||||||
|
tvec.g = (float)atof((*it++).c_str());
|
||||||
|
tvec.b = (float)atof((*it++).c_str());
|
||||||
|
tvec.a = (float)atof((*it++).c_str());
|
||||||
|
colorList.push_back(tvec);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Assimp
|
|
@ -0,0 +1,30 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <assimp/XmlParser.h>
|
||||||
|
#include <assimp/types.h>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
class X3DXmlHelper {
|
||||||
|
public:
|
||||||
|
static bool getColor3DAttribute(XmlNode &node, const char *attributeName, aiColor3D &color);
|
||||||
|
static bool getVector2DAttribute(XmlNode &node, const char *attributeName, aiVector2D &vector);
|
||||||
|
static bool getVector3DAttribute(XmlNode &node, const char *attributeName, aiVector3D &vector);
|
||||||
|
|
||||||
|
static bool getBooleanArrayAttribute(XmlNode &node, const char *attributeName, std::vector<bool> &boolArray);
|
||||||
|
static bool getDoubleArrayAttribute(XmlNode &node, const char *attributeName, std::vector<double> &doubleArray);
|
||||||
|
static bool getFloatArrayAttribute(XmlNode &node, const char *attributeName, std::vector<float> &floatArray);
|
||||||
|
static bool getInt32ArrayAttribute(XmlNode &node, const char *attributeName, std::vector<int32_t> &intArray);
|
||||||
|
static bool getStringListAttribute(XmlNode &node, const char *attributeName, std::list<std::string> &stringArray);
|
||||||
|
static bool getStringArrayAttribute(XmlNode &node, const char *attributeName, std::vector<std::string> &stringArray);
|
||||||
|
|
||||||
|
static bool getVector2DListAttribute(XmlNode &node, const char *attributeName, std::list<aiVector2D> &vectorList);
|
||||||
|
static bool getVector2DArrayAttribute(XmlNode &node, const char *attributeName, std::vector<aiVector2D> &vectorArray);
|
||||||
|
static bool getVector3DListAttribute(XmlNode &node, const char *attributeName, std::list<aiVector3D> &vectorList);
|
||||||
|
static bool getVector3DArrayAttribute(XmlNode &node, const char *attributeName, std::vector<aiVector3D> &vectorArray);
|
||||||
|
static bool getColor3DListAttribute(XmlNode &node, const char *attributeName, std::list<aiColor3D> &colorList);
|
||||||
|
static bool getColor4DListAttribute(XmlNode &node, const char *attributeName, std::list<aiColor4D> &colorList);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Assimp
|
|
@ -39,8 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <assimp/StringUtils.h>
|
|
||||||
#include <assimp/MemoryIOWrapper.h>
|
#include <assimp/MemoryIOWrapper.h>
|
||||||
|
#include <assimp/StringUtils.h>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
// Header files, Assimp
|
// Header files, Assimp
|
||||||
|
@ -57,11 +57,10 @@ using namespace glTFCommon;
|
||||||
namespace glTF {
|
namespace glTF {
|
||||||
|
|
||||||
#if _MSC_VER
|
#if _MSC_VER
|
||||||
# pragma warning(push)
|
#pragma warning(push)
|
||||||
# pragma warning(disable : 4706)
|
#pragma warning(disable : 4706)
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// LazyDict methods
|
// LazyDict methods
|
||||||
//
|
//
|
||||||
|
@ -214,9 +213,10 @@ inline void Buffer::Read(Value &obj, Asset &r) {
|
||||||
} else { // Local file
|
} else { // Local file
|
||||||
if (byteLength > 0) {
|
if (byteLength > 0) {
|
||||||
std::string dir = !r.mCurrentAssetDir.empty() ? (
|
std::string dir = !r.mCurrentAssetDir.empty() ? (
|
||||||
r.mCurrentAssetDir.back() == '/' ?
|
r.mCurrentAssetDir.back() == '/' ?
|
||||||
r.mCurrentAssetDir : r.mCurrentAssetDir + '/'
|
r.mCurrentAssetDir :
|
||||||
) : "";
|
r.mCurrentAssetDir + '/') :
|
||||||
|
"";
|
||||||
|
|
||||||
IOStream *file = r.OpenFile(dir + uri, "rb");
|
IOStream *file = r.OpenFile(dir + uri, "rb");
|
||||||
if (file) {
|
if (file) {
|
||||||
|
@ -734,8 +734,8 @@ inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) {
|
||||||
ASSIMP_LOG_INFO("GLTF: Decompressing Open3DGC data.");
|
ASSIMP_LOG_INFO("GLTF: Decompressing Open3DGC data.");
|
||||||
|
|
||||||
/************** Read data from JSON-document **************/
|
/************** Read data from JSON-document **************/
|
||||||
#define MESH_READ_COMPRESSEDDATA_MEMBER(pFieldName, pOut) \
|
#define MESH_READ_COMPRESSEDDATA_MEMBER(pFieldName, pOut) \
|
||||||
if (!ReadMember(*comp_data, pFieldName, pOut)) { \
|
if (!ReadMember(*comp_data, pFieldName, pOut)) { \
|
||||||
throw DeadlyImportError("GLTF: \"compressedData\" must has \"", pFieldName, "\"."); \
|
throw DeadlyImportError("GLTF: \"compressedData\" must has \"", pFieldName, "\"."); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -771,8 +771,7 @@ inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) {
|
||||||
Decode_O3DGC(*ext_o3dgc, pAsset_Root);
|
Decode_O3DGC(*ext_o3dgc, pAsset_Root);
|
||||||
Extension.push_back(ext_o3dgc); // store info in mesh extensions list.
|
Extension.push_back(ext_o3dgc); // store info in mesh extensions list.
|
||||||
} // if(it_memb->name.GetString() == "Open3DGC-compression")
|
} // if(it_memb->name.GetString() == "Open3DGC-compression")
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
throw DeadlyImportError("GLTF: Unknown mesh extension: \"", it_memb->name.GetString(), "\".");
|
throw DeadlyImportError("GLTF: Unknown mesh extension: \"", it_memb->name.GetString(), "\".");
|
||||||
}
|
}
|
||||||
} // for(Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); json_extensions++)
|
} // for(Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); json_extensions++)
|
||||||
|
@ -842,21 +841,21 @@ inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DG
|
||||||
size_t tval = ifs.GetNFloatAttribute(static_cast<unsigned long>(idx));
|
size_t tval = ifs.GetNFloatAttribute(static_cast<unsigned long>(idx));
|
||||||
|
|
||||||
switch (ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))) {
|
switch (ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))) {
|
||||||
case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD:
|
case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD:
|
||||||
// Check situation when encoded data contain texture coordinates but primitive not.
|
// Check situation when encoded data contain texture coordinates but primitive not.
|
||||||
if (idx_texcoord < primitives[0].attributes.texcoord.size()) {
|
if (idx_texcoord < primitives[0].attributes.texcoord.size()) {
|
||||||
if (primitives[0].attributes.texcoord[idx]->count != tval)
|
if (primitives[0].attributes.texcoord[idx]->count != tval)
|
||||||
throw DeadlyImportError("GLTF: Open3DGC. Compressed texture coordinates count (", ai_to_string(tval),
|
throw DeadlyImportError("GLTF: Open3DGC. Compressed texture coordinates count (", ai_to_string(tval),
|
||||||
") not equal to uncompressed (", ai_to_string(primitives[0].attributes.texcoord[idx]->count), ").");
|
") not equal to uncompressed (", ai_to_string(primitives[0].attributes.texcoord[idx]->count), ").");
|
||||||
|
|
||||||
idx_texcoord++;
|
idx_texcoord++;
|
||||||
} else {
|
} else {
|
||||||
ifs.SetNFloatAttribute(static_cast<unsigned long>(idx), 0ul); // Disable decoding this attribute.
|
ifs.SetNFloatAttribute(static_cast<unsigned long>(idx), 0ul); // Disable decoding this attribute.
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: ", ai_to_string(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))));
|
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: ", ai_to_string(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))));
|
||||||
}
|
}
|
||||||
|
|
||||||
tval *= ifs.GetFloatAttributeDim(static_cast<unsigned long>(idx)) * sizeof(o3dgc::Real); // After checking count of objects we can get size of array.
|
tval *= ifs.GetFloatAttributeDim(static_cast<unsigned long>(idx)) * sizeof(o3dgc::Real); // After checking count of objects we can get size of array.
|
||||||
|
@ -868,14 +867,14 @@ inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DG
|
||||||
// size = number_of_elements * components_per_element * size_of_component. See float attributes note.
|
// size = number_of_elements * components_per_element * size_of_component. See float attributes note.
|
||||||
size_t tval = ifs.GetNIntAttribute(static_cast<unsigned long>(idx));
|
size_t tval = ifs.GetNIntAttribute(static_cast<unsigned long>(idx));
|
||||||
switch (ifs.GetIntAttributeType(static_cast<unsigned long>(idx))) {
|
switch (ifs.GetIntAttributeType(static_cast<unsigned long>(idx))) {
|
||||||
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_UNKOWN:
|
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_UNKOWN:
|
||||||
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX:
|
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX:
|
||||||
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_JOINT_ID:
|
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_JOINT_ID:
|
||||||
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX_BUFFER_ID:
|
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX_BUFFER_ID:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: ", ai_to_string(ifs.GetIntAttributeType(static_cast<unsigned long>(idx))));
|
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: ", ai_to_string(ifs.GetIntAttributeType(static_cast<unsigned long>(idx))));
|
||||||
}
|
}
|
||||||
|
|
||||||
tval *= ifs.GetIntAttributeDim(static_cast<unsigned long>(idx)) * sizeof(long); // See float attributes note.
|
tval *= ifs.GetIntAttributeDim(static_cast<unsigned long>(idx)) * sizeof(long); // See float attributes note.
|
||||||
|
@ -901,30 +900,30 @@ inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DG
|
||||||
|
|
||||||
for (size_t idx = 0, idx_end = size_floatattr.size(), idx_texcoord = 0; idx < idx_end; idx++) {
|
for (size_t idx = 0, idx_end = size_floatattr.size(), idx_texcoord = 0; idx < idx_end; idx++) {
|
||||||
switch (ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))) {
|
switch (ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))) {
|
||||||
case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD:
|
case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD:
|
||||||
if (idx_texcoord < primitives[0].attributes.texcoord.size()) {
|
if (idx_texcoord < primitives[0].attributes.texcoord.size()) {
|
||||||
// See above about absent attributes.
|
// See above about absent attributes.
|
||||||
ifs.SetFloatAttribute(static_cast<unsigned long>(idx), (o3dgc::Real *const)(decoded_data + get_buf_offset(primitives[0].attributes.texcoord[idx])));
|
ifs.SetFloatAttribute(static_cast<unsigned long>(idx), (o3dgc::Real *const)(decoded_data + get_buf_offset(primitives[0].attributes.texcoord[idx])));
|
||||||
idx_texcoord++;
|
idx_texcoord++;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: ", ai_to_string(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))));
|
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: ", ai_to_string(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t idx = 0, idx_end = size_intattr.size(); idx < idx_end; idx++) {
|
for (size_t idx = 0, idx_end = size_intattr.size(); idx < idx_end; idx++) {
|
||||||
switch (ifs.GetIntAttributeType(static_cast<unsigned int>(idx))) {
|
switch (ifs.GetIntAttributeType(static_cast<unsigned int>(idx))) {
|
||||||
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_UNKOWN:
|
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_UNKOWN:
|
||||||
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX:
|
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX:
|
||||||
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_JOINT_ID:
|
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_JOINT_ID:
|
||||||
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX_BUFFER_ID:
|
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX_BUFFER_ID:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// ifs.SetIntAttribute(idx, (long* const)(decoded_data + get_buf_offset(primitives[0].attributes.joint)));
|
// ifs.SetIntAttribute(idx, (long* const)(decoded_data + get_buf_offset(primitives[0].attributes.joint)));
|
||||||
default:
|
default:
|
||||||
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: ", ai_to_string(ifs.GetIntAttributeType(static_cast<unsigned long>(idx))));
|
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: ", ai_to_string(ifs.GetIntAttributeType(static_cast<unsigned long>(idx))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1148,7 +1147,8 @@ inline void Asset::ReadBinaryHeader(IOStream &stream) {
|
||||||
AI_SWAP4(header.length);
|
AI_SWAP4(header.length);
|
||||||
AI_SWAP4(header.sceneLength);
|
AI_SWAP4(header.sceneLength);
|
||||||
|
|
||||||
mSceneLength = static_cast<size_t>(header.sceneLength);
|
static_assert(std::numeric_limits<uint32_t>::max() <= std::numeric_limits<size_t>::max(), "size_t must be at least 32bits");
|
||||||
|
mSceneLength = static_cast<size_t>(header.sceneLength); // Can't be larger than 4GB (max. uint32_t)
|
||||||
|
|
||||||
mBodyOffset = sizeof(header) + mSceneLength;
|
mBodyOffset = sizeof(header) + mSceneLength;
|
||||||
mBodyOffset = (mBodyOffset + 3) & ~3; // Round up to next multiple of 4
|
mBodyOffset = (mBodyOffset + 3) & ~3; // Round up to next multiple of 4
|
||||||
|
@ -1179,8 +1179,17 @@ inline void Asset::Load(const std::string &pFile, bool isBinary) {
|
||||||
mBodyLength = 0;
|
mBodyLength = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// read the scene data
|
// Smallest legal JSON file is "{}" Smallest loadable glTF file is larger than that but catch it later
|
||||||
|
if (mSceneLength < 2) {
|
||||||
|
throw DeadlyImportError("GLTF: No JSON file contents");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Binary format only supports up to 4GB of JSON so limit it there to avoid extreme memory allocation
|
||||||
|
if (mSceneLength >= std::numeric_limits<uint32_t>::max()) {
|
||||||
|
throw DeadlyImportError("GLTF: JSON size greater than 4GB");
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the scene data, ensure null termination
|
||||||
std::vector<char> sceneData(mSceneLength + 1);
|
std::vector<char> sceneData(mSceneLength + 1);
|
||||||
sceneData[mSceneLength] = '\0';
|
sceneData[mSceneLength] = '\0';
|
||||||
|
|
||||||
|
@ -1258,7 +1267,7 @@ inline void Asset::ReadExtensionsUsed(Document &doc) {
|
||||||
#undef CHECK_EXT
|
#undef CHECK_EXT
|
||||||
}
|
}
|
||||||
|
|
||||||
inline IOStream *Asset::OpenFile(const std::string& path, const char *mode, bool absolute) {
|
inline IOStream *Asset::OpenFile(const std::string &path, const char *mode, bool absolute) {
|
||||||
#ifdef ASSIMP_API
|
#ifdef ASSIMP_API
|
||||||
(void)absolute;
|
(void)absolute;
|
||||||
return mIOSystem->Open(path, mode);
|
return mIOSystem->Open(path, mode);
|
||||||
|
@ -1300,7 +1309,7 @@ inline std::string Asset::FindUniqueID(const std::string &str, const char *suffi
|
||||||
}
|
}
|
||||||
|
|
||||||
#if _MSC_VER
|
#if _MSC_VER
|
||||||
# pragma warning(pop)
|
#pragma warning(pop)
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
} // namespace glTF
|
} // namespace glTF
|
||||||
|
|
|
@ -322,8 +322,8 @@ void glTFExporter::GetTexSampler(const aiMaterial* mat, glTF::TexProperty& prop)
|
||||||
prop.texture->sampler->minFilter = SamplerMinFilter_Linear;
|
prop.texture->sampler->minFilter = SamplerMinFilter_Linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
void glTFExporter::GetMatColorOrTex(const aiMaterial* mat, glTF::TexProperty& prop, const char* propName, int type, int idx, aiTextureType tt)
|
void glTFExporter::GetMatColorOrTex(const aiMaterial* mat, glTF::TexProperty& prop,
|
||||||
{
|
const char* propName, int type, int idx, aiTextureType tt) {
|
||||||
aiString tex;
|
aiString tex;
|
||||||
aiColor4D col;
|
aiColor4D col;
|
||||||
if (mat->GetTextureCount(tt) > 0) {
|
if (mat->GetTextureCount(tt) > 0) {
|
||||||
|
@ -370,7 +370,10 @@ void glTFExporter::GetMatColorOrTex(const aiMaterial* mat, glTF::TexProperty& pr
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mat->Get(propName, type, idx, col) == AI_SUCCESS) {
|
if (mat->Get(propName, type, idx, col) == AI_SUCCESS) {
|
||||||
prop.color[0] = col.r; prop.color[1] = col.g; prop.color[2] = col.b; prop.color[3] = col.a;
|
prop.color[0] = col.r;
|
||||||
|
prop.color[1] = col.g;
|
||||||
|
prop.color[2] = col.b;
|
||||||
|
prop.color[3] = col.a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -197,18 +197,18 @@ inline void SetDecodedIndexBuffer_Draco(const draco::Mesh &dracoMesh, Mesh::Prim
|
||||||
|
|
||||||
// Not same size, convert
|
// Not same size, convert
|
||||||
switch (componentBytes) {
|
switch (componentBytes) {
|
||||||
case sizeof(uint32_t):
|
case sizeof(uint32_t):
|
||||||
CopyFaceIndex_Draco<uint32_t>(*decodedIndexBuffer, dracoMesh);
|
CopyFaceIndex_Draco<uint32_t>(*decodedIndexBuffer, dracoMesh);
|
||||||
break;
|
break;
|
||||||
case sizeof(uint16_t):
|
case sizeof(uint16_t):
|
||||||
CopyFaceIndex_Draco<uint16_t>(*decodedIndexBuffer, dracoMesh);
|
CopyFaceIndex_Draco<uint16_t>(*decodedIndexBuffer, dracoMesh);
|
||||||
break;
|
break;
|
||||||
case sizeof(uint8_t):
|
case sizeof(uint8_t):
|
||||||
CopyFaceIndex_Draco<uint8_t>(*decodedIndexBuffer, dracoMesh);
|
CopyFaceIndex_Draco<uint8_t>(*decodedIndexBuffer, dracoMesh);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ai_assert(false);
|
ai_assert(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign this alternate data buffer to the accessor
|
// Assign this alternate data buffer to the accessor
|
||||||
|
@ -247,27 +247,27 @@ inline void SetDecodedAttributeBuffer_Draco(const draco::Mesh &dracoMesh, uint32
|
||||||
decodedAttribBuffer->Grow(dracoMesh.num_points() * pDracoAttribute->num_components() * componentBytes);
|
decodedAttribBuffer->Grow(dracoMesh.num_points() * pDracoAttribute->num_components() * componentBytes);
|
||||||
|
|
||||||
switch (accessor.componentType) {
|
switch (accessor.componentType) {
|
||||||
case ComponentType_BYTE:
|
case ComponentType_BYTE:
|
||||||
GetAttributeForAllPoints_Draco<int8_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
|
GetAttributeForAllPoints_Draco<int8_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
|
||||||
break;
|
break;
|
||||||
case ComponentType_UNSIGNED_BYTE:
|
case ComponentType_UNSIGNED_BYTE:
|
||||||
GetAttributeForAllPoints_Draco<uint8_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
|
GetAttributeForAllPoints_Draco<uint8_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
|
||||||
break;
|
break;
|
||||||
case ComponentType_SHORT:
|
case ComponentType_SHORT:
|
||||||
GetAttributeForAllPoints_Draco<int16_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
|
GetAttributeForAllPoints_Draco<int16_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
|
||||||
break;
|
break;
|
||||||
case ComponentType_UNSIGNED_SHORT:
|
case ComponentType_UNSIGNED_SHORT:
|
||||||
GetAttributeForAllPoints_Draco<uint16_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
|
GetAttributeForAllPoints_Draco<uint16_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
|
||||||
break;
|
break;
|
||||||
case ComponentType_UNSIGNED_INT:
|
case ComponentType_UNSIGNED_INT:
|
||||||
GetAttributeForAllPoints_Draco<uint32_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
|
GetAttributeForAllPoints_Draco<uint32_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
|
||||||
break;
|
break;
|
||||||
case ComponentType_FLOAT:
|
case ComponentType_FLOAT:
|
||||||
GetAttributeForAllPoints_Draco<float>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
|
GetAttributeForAllPoints_Draco<float>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ai_assert(false);
|
ai_assert(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign this alternate data buffer to the accessor
|
// Assign this alternate data buffer to the accessor
|
||||||
|
@ -299,7 +299,7 @@ inline LazyDict<T>::~LazyDict() {
|
||||||
template <class T>
|
template <class T>
|
||||||
inline void LazyDict<T>::AttachToDocument(Document &doc) {
|
inline void LazyDict<T>::AttachToDocument(Document &doc) {
|
||||||
Value *container = nullptr;
|
Value *container = nullptr;
|
||||||
const char* context = nullptr;
|
const char *context = nullptr;
|
||||||
|
|
||||||
if (mExtId) {
|
if (mExtId) {
|
||||||
if (Value *exts = FindObject(doc, "extensions")) {
|
if (Value *exts = FindObject(doc, "extensions")) {
|
||||||
|
@ -721,18 +721,18 @@ inline void Accessor::Sparse::PatchData(unsigned int elementSize) {
|
||||||
while (pIndices != indicesEnd) {
|
while (pIndices != indicesEnd) {
|
||||||
size_t offset;
|
size_t offset;
|
||||||
switch (indicesType) {
|
switch (indicesType) {
|
||||||
case ComponentType_UNSIGNED_BYTE:
|
case ComponentType_UNSIGNED_BYTE:
|
||||||
offset = *pIndices;
|
offset = *pIndices;
|
||||||
break;
|
break;
|
||||||
case ComponentType_UNSIGNED_SHORT:
|
case ComponentType_UNSIGNED_SHORT:
|
||||||
offset = *reinterpret_cast<uint16_t *>(pIndices);
|
offset = *reinterpret_cast<uint16_t *>(pIndices);
|
||||||
break;
|
break;
|
||||||
case ComponentType_UNSIGNED_INT:
|
case ComponentType_UNSIGNED_INT:
|
||||||
offset = *reinterpret_cast<uint32_t *>(pIndices);
|
offset = *reinterpret_cast<uint32_t *>(pIndices);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// have fun with float and negative values from signed types as indices.
|
// have fun with float and negative values from signed types as indices.
|
||||||
throw DeadlyImportError("Unsupported component type in index.");
|
throw DeadlyImportError("Unsupported component type in index.");
|
||||||
}
|
}
|
||||||
|
|
||||||
offset *= elementSize;
|
offset *= elementSize;
|
||||||
|
@ -751,9 +751,8 @@ inline void Accessor::Read(Value &obj, Asset &r) {
|
||||||
byteOffset = MemberOrDefault(obj, "byteOffset", size_t(0));
|
byteOffset = MemberOrDefault(obj, "byteOffset", size_t(0));
|
||||||
componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE);
|
componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE);
|
||||||
{
|
{
|
||||||
const Value* countValue = FindUInt(obj, "count");
|
const Value *countValue = FindUInt(obj, "count");
|
||||||
if (!countValue)
|
if (!countValue) {
|
||||||
{
|
|
||||||
throw DeadlyImportError("A count value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
|
throw DeadlyImportError("A count value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
|
||||||
}
|
}
|
||||||
count = countValue->GetUint();
|
count = countValue->GetUint();
|
||||||
|
@ -1777,9 +1776,9 @@ inline void Asset::ReadBinaryHeader(IOStream &stream, std::vector<char> &sceneDa
|
||||||
throw DeadlyImportError("GLTF: JSON chunk missing");
|
throw DeadlyImportError("GLTF: JSON chunk missing");
|
||||||
}
|
}
|
||||||
|
|
||||||
// read the scene data
|
// read the scene data, ensure null termination
|
||||||
|
static_assert(std::numeric_limits<uint32_t>::max() <= std::numeric_limits<size_t>::max(), "size_t must be at least 32bits");
|
||||||
mSceneLength = chunk.chunkLength;
|
mSceneLength = chunk.chunkLength; // Can't be larger than 4GB (max. uint32_t)
|
||||||
sceneData.resize(mSceneLength + 1);
|
sceneData.resize(mSceneLength + 1);
|
||||||
sceneData[mSceneLength] = '\0';
|
sceneData[mSceneLength] = '\0';
|
||||||
|
|
||||||
|
@ -1836,8 +1835,12 @@ inline void Asset::Load(const std::string &pFile, bool isBinary) {
|
||||||
mSceneLength = stream->FileSize();
|
mSceneLength = stream->FileSize();
|
||||||
mBodyLength = 0;
|
mBodyLength = 0;
|
||||||
|
|
||||||
// read the scene data
|
// Binary format only supports up to 4GB of JSON, use that as a maximum
|
||||||
|
if (mSceneLength >= std::numeric_limits<uint32_t>::max()) {
|
||||||
|
throw DeadlyImportError("GLTF: JSON size greater than 4GB");
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the scene data, ensure null termination
|
||||||
sceneData.resize(mSceneLength + 1);
|
sceneData.resize(mSceneLength + 1);
|
||||||
sceneData[mSceneLength] = '\0';
|
sceneData[mSceneLength] = '\0';
|
||||||
|
|
||||||
|
@ -1846,6 +1849,11 @@ inline void Asset::Load(const std::string &pFile, bool isBinary) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Smallest legal JSON file is "{}" Smallest loadable glTF file is larger than that but catch it later
|
||||||
|
if (mSceneLength < 2) {
|
||||||
|
throw DeadlyImportError("GLTF: No JSON file contents");
|
||||||
|
}
|
||||||
|
|
||||||
// parse the JSON document
|
// parse the JSON document
|
||||||
ASSIMP_LOG_DEBUG("Parsing GLTF2 JSON");
|
ASSIMP_LOG_DEBUG("Parsing GLTF2 JSON");
|
||||||
Document doc;
|
Document doc;
|
||||||
|
@ -1974,7 +1982,7 @@ inline void Asset::ReadExtensionsUsed(Document &doc) {
|
||||||
#undef CHECK_EXT
|
#undef CHECK_EXT
|
||||||
}
|
}
|
||||||
|
|
||||||
inline IOStream *Asset::OpenFile(const std::string& path, const char *mode, bool /*absolute*/) {
|
inline IOStream *Asset::OpenFile(const std::string &path, const char *mode, bool /*absolute*/) {
|
||||||
#ifdef ASSIMP_API
|
#ifdef ASSIMP_API
|
||||||
return mIOSystem->Open(path, mode);
|
return mIOSystem->Open(path, mode);
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -1395,15 +1395,15 @@ inline Ref<Accessor> GetSamplerInputRef(Asset &asset, std::string &animId, Ref<B
|
||||||
inline void ExtractTranslationSampler(Asset &asset, std::string &animId, Ref<Buffer> &buffer, const aiNodeAnim *nodeChannel, float ticksPerSecond, Animation::Sampler &sampler) {
|
inline void ExtractTranslationSampler(Asset &asset, std::string &animId, Ref<Buffer> &buffer, const aiNodeAnim *nodeChannel, float ticksPerSecond, Animation::Sampler &sampler) {
|
||||||
const unsigned int numKeyframes = nodeChannel->mNumPositionKeys;
|
const unsigned int numKeyframes = nodeChannel->mNumPositionKeys;
|
||||||
|
|
||||||
std::vector<float> times(numKeyframes);
|
std::vector<ai_real> times(numKeyframes);
|
||||||
std::vector<float> values(numKeyframes * 3);
|
std::vector<ai_real> values(numKeyframes * 3);
|
||||||
for (unsigned int i = 0; i < numKeyframes; ++i) {
|
for (unsigned int i = 0; i < numKeyframes; ++i) {
|
||||||
const aiVectorKey &key = nodeChannel->mPositionKeys[i];
|
const aiVectorKey &key = nodeChannel->mPositionKeys[i];
|
||||||
// mTime is measured in ticks, but GLTF time is measured in seconds, so convert.
|
// mTime is measured in ticks, but GLTF time is measured in seconds, so convert.
|
||||||
times[i] = static_cast<float>(key.mTime / ticksPerSecond);
|
times[i] = static_cast<float>(key.mTime / ticksPerSecond);
|
||||||
values[(i * 3) + 0] = key.mValue.x;
|
values[(i * 3) + 0] = (ai_real) key.mValue.x;
|
||||||
values[(i * 3) + 1] = key.mValue.y;
|
values[(i * 3) + 1] = (ai_real) key.mValue.y;
|
||||||
values[(i * 3) + 2] = key.mValue.z;
|
values[(i * 3) + 2] = (ai_real) key.mValue.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
sampler.input = GetSamplerInputRef(asset, animId, buffer, times);
|
sampler.input = GetSamplerInputRef(asset, animId, buffer, times);
|
||||||
|
@ -1414,15 +1414,15 @@ inline void ExtractTranslationSampler(Asset &asset, std::string &animId, Ref<Buf
|
||||||
inline void ExtractScaleSampler(Asset &asset, std::string &animId, Ref<Buffer> &buffer, const aiNodeAnim *nodeChannel, float ticksPerSecond, Animation::Sampler &sampler) {
|
inline void ExtractScaleSampler(Asset &asset, std::string &animId, Ref<Buffer> &buffer, const aiNodeAnim *nodeChannel, float ticksPerSecond, Animation::Sampler &sampler) {
|
||||||
const unsigned int numKeyframes = nodeChannel->mNumScalingKeys;
|
const unsigned int numKeyframes = nodeChannel->mNumScalingKeys;
|
||||||
|
|
||||||
std::vector<float> times(numKeyframes);
|
std::vector<ai_real> times(numKeyframes);
|
||||||
std::vector<float> values(numKeyframes * 3);
|
std::vector<ai_real> values(numKeyframes * 3);
|
||||||
for (unsigned int i = 0; i < numKeyframes; ++i) {
|
for (unsigned int i = 0; i < numKeyframes; ++i) {
|
||||||
const aiVectorKey &key = nodeChannel->mScalingKeys[i];
|
const aiVectorKey &key = nodeChannel->mScalingKeys[i];
|
||||||
// mTime is measured in ticks, but GLTF time is measured in seconds, so convert.
|
// mTime is measured in ticks, but GLTF time is measured in seconds, so convert.
|
||||||
times[i] = static_cast<float>(key.mTime / ticksPerSecond);
|
times[i] = static_cast<float>(key.mTime / ticksPerSecond);
|
||||||
values[(i * 3) + 0] = key.mValue.x;
|
values[(i * 3) + 0] = (ai_real) key.mValue.x;
|
||||||
values[(i * 3) + 1] = key.mValue.y;
|
values[(i * 3) + 1] = (ai_real) key.mValue.y;
|
||||||
values[(i * 3) + 2] = key.mValue.z;
|
values[(i * 3) + 2] = (ai_real) key.mValue.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
sampler.input = GetSamplerInputRef(asset, animId, buffer, times);
|
sampler.input = GetSamplerInputRef(asset, animId, buffer, times);
|
||||||
|
@ -1433,16 +1433,16 @@ inline void ExtractScaleSampler(Asset &asset, std::string &animId, Ref<Buffer> &
|
||||||
inline void ExtractRotationSampler(Asset &asset, std::string &animId, Ref<Buffer> &buffer, const aiNodeAnim *nodeChannel, float ticksPerSecond, Animation::Sampler &sampler) {
|
inline void ExtractRotationSampler(Asset &asset, std::string &animId, Ref<Buffer> &buffer, const aiNodeAnim *nodeChannel, float ticksPerSecond, Animation::Sampler &sampler) {
|
||||||
const unsigned int numKeyframes = nodeChannel->mNumRotationKeys;
|
const unsigned int numKeyframes = nodeChannel->mNumRotationKeys;
|
||||||
|
|
||||||
std::vector<float> times(numKeyframes);
|
std::vector<ai_real> times(numKeyframes);
|
||||||
std::vector<float> values(numKeyframes * 4);
|
std::vector<ai_real> values(numKeyframes * 4);
|
||||||
for (unsigned int i = 0; i < numKeyframes; ++i) {
|
for (unsigned int i = 0; i < numKeyframes; ++i) {
|
||||||
const aiQuatKey &key = nodeChannel->mRotationKeys[i];
|
const aiQuatKey &key = nodeChannel->mRotationKeys[i];
|
||||||
// mTime is measured in ticks, but GLTF time is measured in seconds, so convert.
|
// mTime is measured in ticks, but GLTF time is measured in seconds, so convert.
|
||||||
times[i] = static_cast<float>(key.mTime / ticksPerSecond);
|
times[i] = static_cast<float>(key.mTime / ticksPerSecond);
|
||||||
values[(i * 4) + 0] = key.mValue.x;
|
values[(i * 4) + 0] = (ai_real) key.mValue.x;
|
||||||
values[(i * 4) + 1] = key.mValue.y;
|
values[(i * 4) + 1] = (ai_real) key.mValue.y;
|
||||||
values[(i * 4) + 2] = key.mValue.z;
|
values[(i * 4) + 2] = (ai_real) key.mValue.z;
|
||||||
values[(i * 4) + 3] = key.mValue.w;
|
values[(i * 4) + 3] = (ai_real) key.mValue.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
sampler.input = GetSamplerInputRef(asset, animId, buffer, times);
|
sampler.input = GetSamplerInputRef(asset, animId, buffer, times);
|
||||||
|
@ -1500,7 +1500,7 @@ void glTF2Exporter::ExportAnimations() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assimp documentation staes this is not used (not implemented)
|
// Assimp documentation states this is not used (not implemented)
|
||||||
// for (unsigned int channelIndex = 0; channelIndex < anim->mNumMeshChannels; ++channelIndex) {
|
// for (unsigned int channelIndex = 0; channelIndex < anim->mNumMeshChannels; ++channelIndex) {
|
||||||
// const aiMeshAnim* meshChannel = anim->mMeshChannels[channelIndex];
|
// const aiMeshAnim* meshChannel = anim->mMeshChannels[channelIndex];
|
||||||
// }
|
// }
|
||||||
|
|
|
@ -799,7 +799,23 @@ ADD_ASSIMP_IMPORTER( X
|
||||||
|
|
||||||
ADD_ASSIMP_IMPORTER( X3D
|
ADD_ASSIMP_IMPORTER( X3D
|
||||||
AssetLib/X3D/X3DImporter.cpp
|
AssetLib/X3D/X3DImporter.cpp
|
||||||
|
AssetLib/X3D/X3DImporter_Geometry2D.cpp
|
||||||
|
AssetLib/X3D/X3DImporter_Geometry3D.cpp
|
||||||
|
AssetLib/X3D/X3DImporter_Group.cpp
|
||||||
|
AssetLib/X3D/X3DImporter_Light.cpp
|
||||||
|
AssetLib/X3D/X3DImporter_Metadata.cpp
|
||||||
|
AssetLib/X3D/X3DImporter_Networking.cpp
|
||||||
|
AssetLib/X3D/X3DImporter_Postprocess.cpp
|
||||||
|
AssetLib/X3D/X3DImporter_Rendering.cpp
|
||||||
|
AssetLib/X3D/X3DImporter_Shape.cpp
|
||||||
|
AssetLib/X3D/X3DImporter_Texturing.cpp
|
||||||
AssetLib/X3D/X3DImporter.hpp
|
AssetLib/X3D/X3DImporter.hpp
|
||||||
|
AssetLib/X3D/X3DImporter_Macro.hpp
|
||||||
|
AssetLib/X3D/X3DImporter_Node.hpp
|
||||||
|
AssetLib/X3D/X3DGeoHelper.cpp
|
||||||
|
AssetLib/X3D/X3DGeoHelper.h
|
||||||
|
AssetLib/X3D/X3DXmlHelper.cpp
|
||||||
|
AssetLib/X3D/X3DXmlHelper.h
|
||||||
)
|
)
|
||||||
|
|
||||||
ADD_ASSIMP_IMPORTER( GLTF
|
ADD_ASSIMP_IMPORTER( GLTF
|
||||||
|
|
|
@ -366,9 +366,7 @@ void GetImporterInstanceList(std::vector<BaseImporter *> &out) {
|
||||||
out.push_back(new D3MFImporter());
|
out.push_back(new D3MFImporter());
|
||||||
#endif
|
#endif
|
||||||
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
|
||||||
if (devImportersEnabled) { // https://github.com/assimp/assimp/issues/3647
|
out.push_back(new X3DImporter());
|
||||||
out.push_back(new X3DImporter());
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
#ifndef ASSIMP_BUILD_NO_MMD_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_MMD_IMPORTER
|
||||||
out.push_back(new MMDImporter());
|
out.push_back(new MMDImporter());
|
||||||
|
|
|
@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
|
||||||
|
|
||||||
Copyright (c) 2006-2021, assimp team
|
Copyright (c) 2006-2021, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
@ -42,25 +40,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
#include <assimp/scene.h>
|
#include <assimp/scene.h>
|
||||||
|
|
||||||
aiNode::aiNode()
|
aiNode::aiNode() :
|
||||||
: mName()
|
mName(""),
|
||||||
, mParent(nullptr)
|
mParent(nullptr),
|
||||||
, mNumChildren(0)
|
mNumChildren(0),
|
||||||
, mChildren(nullptr)
|
mChildren(nullptr),
|
||||||
, mNumMeshes(0)
|
mNumMeshes(0),
|
||||||
, mMeshes(nullptr)
|
mMeshes(nullptr),
|
||||||
, mMetaData(nullptr) {
|
mMetaData(nullptr) {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
aiNode::aiNode(const std::string& name)
|
aiNode::aiNode(const std::string &name) :
|
||||||
: mName(name)
|
mName(name),
|
||||||
, mParent(nullptr)
|
mParent(nullptr),
|
||||||
, mNumChildren(0)
|
mNumChildren(0),
|
||||||
, mChildren(nullptr)
|
mChildren(nullptr),
|
||||||
, mNumMeshes(0)
|
mNumMeshes(0),
|
||||||
, mMeshes(nullptr)
|
mMeshes(nullptr),
|
||||||
, mMetaData(nullptr) {
|
mMetaData(nullptr) {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,8 +66,7 @@ aiNode::aiNode(const std::string& name)
|
||||||
aiNode::~aiNode() {
|
aiNode::~aiNode() {
|
||||||
// delete all children recursively
|
// delete all children recursively
|
||||||
// to make sure we won't crash if the data is invalid ...
|
// to make sure we won't crash if the data is invalid ...
|
||||||
if (mNumChildren && mChildren)
|
if (mNumChildren && mChildren) {
|
||||||
{
|
|
||||||
for (unsigned int a = 0; a < mNumChildren; a++)
|
for (unsigned int a = 0; a < mNumChildren; a++)
|
||||||
delete mChildren[a];
|
delete mChildren[a];
|
||||||
}
|
}
|
||||||
|
@ -78,7 +75,7 @@ aiNode::~aiNode() {
|
||||||
delete mMetaData;
|
delete mMetaData;
|
||||||
}
|
}
|
||||||
|
|
||||||
const aiNode *aiNode::FindNode(const char* name) const {
|
const aiNode *aiNode::FindNode(const char *name) const {
|
||||||
if (nullptr == name) {
|
if (nullptr == name) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -86,7 +83,7 @@ const aiNode *aiNode::FindNode(const char* name) const {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
for (unsigned int i = 0; i < mNumChildren; ++i) {
|
for (unsigned int i = 0; i < mNumChildren; ++i) {
|
||||||
const aiNode* const p = mChildren[i]->FindNode(name);
|
const aiNode *const p = mChildren[i]->FindNode(name);
|
||||||
if (p) {
|
if (p) {
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -95,11 +92,10 @@ const aiNode *aiNode::FindNode(const char* name) const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
aiNode *aiNode::FindNode(const char* name) {
|
aiNode *aiNode::FindNode(const char *name) {
|
||||||
if (!::strcmp(mName.data, name))return this;
|
if (!::strcmp(mName.data, name)) return this;
|
||||||
for (unsigned int i = 0; i < mNumChildren; ++i)
|
for (unsigned int i = 0; i < mNumChildren; ++i) {
|
||||||
{
|
aiNode *const p = mChildren[i]->FindNode(name);
|
||||||
aiNode* const p = mChildren[i]->FindNode(name);
|
|
||||||
if (p) {
|
if (p) {
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -121,17 +117,16 @@ void aiNode::addChildren(unsigned int numChildren, aiNode **children) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mNumChildren > 0) {
|
if (mNumChildren > 0) {
|
||||||
aiNode **tmp = new aiNode*[mNumChildren];
|
aiNode **tmp = new aiNode *[mNumChildren];
|
||||||
::memcpy(tmp, mChildren, sizeof(aiNode*) * mNumChildren);
|
::memcpy(tmp, mChildren, sizeof(aiNode *) * mNumChildren);
|
||||||
delete[] mChildren;
|
delete[] mChildren;
|
||||||
mChildren = new aiNode*[mNumChildren + numChildren];
|
mChildren = new aiNode *[mNumChildren + numChildren];
|
||||||
::memcpy(mChildren, tmp, sizeof(aiNode*) * mNumChildren);
|
::memcpy(mChildren, tmp, sizeof(aiNode *) * mNumChildren);
|
||||||
::memcpy(&mChildren[mNumChildren], children, sizeof(aiNode*)* numChildren);
|
::memcpy(&mChildren[mNumChildren], children, sizeof(aiNode *) * numChildren);
|
||||||
mNumChildren += numChildren;
|
mNumChildren += numChildren;
|
||||||
delete[] tmp;
|
delete[] tmp;
|
||||||
}
|
} else {
|
||||||
else {
|
mChildren = new aiNode *[numChildren];
|
||||||
mChildren = new aiNode*[numChildren];
|
|
||||||
for (unsigned int i = 0; i < numChildren; i++) {
|
for (unsigned int i = 0; i < numChildren; i++) {
|
||||||
mChildren[i] = children[i];
|
mChildren[i] = children[i];
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,12 +133,12 @@ inline ::aiQuatKey max(const ::aiQuatKey &a, const ::aiQuatKey &b) {
|
||||||
|
|
||||||
// std::min for aiVertexWeight
|
// std::min for aiVertexWeight
|
||||||
inline ::aiVertexWeight min(const ::aiVertexWeight &a, const ::aiVertexWeight &b) {
|
inline ::aiVertexWeight min(const ::aiVertexWeight &a, const ::aiVertexWeight &b) {
|
||||||
return ::aiVertexWeight(min(a.mVertexId, b.mVertexId), min(a.mWeight, b.mWeight));
|
return ::aiVertexWeight(min(a.mVertexId, b.mVertexId),static_cast<ai_real>(min(a.mWeight, b.mWeight)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// std::max for aiVertexWeight
|
// std::max for aiVertexWeight
|
||||||
inline ::aiVertexWeight max(const ::aiVertexWeight &a, const ::aiVertexWeight &b) {
|
inline ::aiVertexWeight max(const ::aiVertexWeight &a, const ::aiVertexWeight &b) {
|
||||||
return ::aiVertexWeight(max(a.mVertexId, b.mVertexId), max(a.mWeight, b.mWeight));
|
return ::aiVertexWeight(max(a.mVertexId, b.mVertexId), static_cast<ai_real>(max(a.mWeight, b.mWeight)));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end namespace std
|
} // end namespace std
|
||||||
|
@ -244,7 +244,7 @@ inline void ArrayBounds(const T *in, unsigned int size, T &min, T &max) {
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
/** Little helper function to calculate the quadratic difference
|
/** Little helper function to calculate the quadratic difference
|
||||||
* of two colours.
|
* of two colors.
|
||||||
* @param pColor1 First color
|
* @param pColor1 First color
|
||||||
* @param pColor2 second color
|
* @param pColor2 second color
|
||||||
* @return Quadratic color difference */
|
* @return Quadratic color difference */
|
||||||
|
@ -313,8 +313,8 @@ ai_real ComputePositionEpsilon(const aiMesh *const *pMeshes, size_t num);
|
||||||
unsigned int GetMeshVFormatUnique(const aiMesh *pcMesh);
|
unsigned int GetMeshVFormatUnique(const aiMesh *pcMesh);
|
||||||
|
|
||||||
// defs for ComputeVertexBoneWeightTable()
|
// defs for ComputeVertexBoneWeightTable()
|
||||||
typedef std::pair<unsigned int, float> PerVertexWeight;
|
using PerVertexWeight = std::pair<unsigned int, float>;
|
||||||
typedef std::vector<PerVertexWeight> VertexWeightTable;
|
using VertexWeightTable = std::vector<PerVertexWeight>;
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
// Compute a per-vertex bone weight table
|
// Compute a per-vertex bone weight table
|
||||||
|
@ -332,7 +332,7 @@ const char *MappingTypeToString(aiTextureMapping in);
|
||||||
aiMesh *MakeSubmesh(const aiMesh *superMesh, const std::vector<unsigned int> &subMeshFaces, unsigned int subFlags);
|
aiMesh *MakeSubmesh(const aiMesh *superMesh, const std::vector<unsigned int> &subMeshFaces, unsigned int subFlags);
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
// Utility postprocess step to share the spatial sort tree between
|
// Utility post-process step to share the spatial sort tree between
|
||||||
// all steps which use it to speedup its computations.
|
// all steps which use it to speedup its computations.
|
||||||
class ComputeSpatialSortProcess : public BaseProcess {
|
class ComputeSpatialSortProcess : public BaseProcess {
|
||||||
bool IsActive(unsigned int pFlags) const {
|
bool IsActive(unsigned int pFlags) const {
|
||||||
|
@ -372,4 +372,5 @@ class DestroySpatialSortProcess : public BaseProcess {
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Assimp
|
} // namespace Assimp
|
||||||
|
|
||||||
#endif // !! AI_PROCESS_HELPER_H_INCLUDED
|
#endif // !! AI_PROCESS_HELPER_H_INCLUDED
|
||||||
|
|
|
@ -681,10 +681,6 @@ struct aiMesh {
|
||||||
*/
|
*/
|
||||||
C_STRUCT aiVector3D *mTextureCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
C_STRUCT aiVector3D *mTextureCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
||||||
|
|
||||||
/** Vertex stream names.
|
|
||||||
*/
|
|
||||||
C_STRUCT aiString mTextureCoordsNames[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
|
||||||
|
|
||||||
/** Specifies the number of components for a given UV channel.
|
/** Specifies the number of components for a given UV channel.
|
||||||
* Up to three channels are supported (UVW, for accessing volume
|
* Up to three channels are supported (UVW, for accessing volume
|
||||||
* or cube maps). If the value is 2 for a given channel n, the
|
* or cube maps). If the value is 2 for a given channel n, the
|
||||||
|
@ -752,6 +748,10 @@ struct aiMesh {
|
||||||
*/
|
*/
|
||||||
C_STRUCT aiAABB mAABB;
|
C_STRUCT aiAABB mAABB;
|
||||||
|
|
||||||
|
/** Vertex UV stream names. Pointer to array of size AI_MAX_NUMBER_OF_TEXTURECOORDS
|
||||||
|
*/
|
||||||
|
C_STRUCT aiString **mTextureCoordsNames;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
//! Default constructor. Initializes all members to 0
|
//! Default constructor. Initializes all members to 0
|
||||||
|
@ -773,7 +773,8 @@ struct aiMesh {
|
||||||
mNumAnimMeshes(0),
|
mNumAnimMeshes(0),
|
||||||
mAnimMeshes(nullptr),
|
mAnimMeshes(nullptr),
|
||||||
mMethod(0),
|
mMethod(0),
|
||||||
mAABB() {
|
mAABB(),
|
||||||
|
mTextureCoordsNames(nullptr) {
|
||||||
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
|
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
|
||||||
mNumUVComponents[a] = 0;
|
mNumUVComponents[a] = 0;
|
||||||
mTextureCoords[a] = nullptr;
|
mTextureCoords[a] = nullptr;
|
||||||
|
@ -793,6 +794,14 @@ struct aiMesh {
|
||||||
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) {
|
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) {
|
||||||
delete[] mTextureCoords[a];
|
delete[] mTextureCoords[a];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mTextureCoordsNames) {
|
||||||
|
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) {
|
||||||
|
delete mTextureCoordsNames[a];
|
||||||
|
}
|
||||||
|
delete[] mTextureCoordsNames;
|
||||||
|
}
|
||||||
|
|
||||||
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++) {
|
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++) {
|
||||||
delete[] mColors[a];
|
delete[] mColors[a];
|
||||||
}
|
}
|
||||||
|
@ -878,6 +887,52 @@ struct aiMesh {
|
||||||
return mBones != nullptr && mNumBones > 0;
|
return mBones != nullptr && mNumBones > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Check whether the mesh contains a texture coordinate set name
|
||||||
|
//! \param pIndex Index of the texture coordinates set
|
||||||
|
bool HasTextureCoordsName(unsigned int pIndex) const {
|
||||||
|
if (mTextureCoordsNames == nullptr || pIndex >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return mTextureCoordsNames[pIndex] != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Set a texture coordinate set name
|
||||||
|
//! \param pIndex Index of the texture coordinates set
|
||||||
|
//! \param texCoordsName name of the texture coordinate set
|
||||||
|
void SetTextureCoordsName(unsigned int pIndex, const aiString &texCoordsName) {
|
||||||
|
if (pIndex >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mTextureCoordsNames == nullptr) {
|
||||||
|
// Construct and null-init array
|
||||||
|
mTextureCoordsNames = new aiString *[AI_MAX_NUMBER_OF_TEXTURECOORDS] {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (texCoordsName.length == 0) {
|
||||||
|
delete mTextureCoordsNames[pIndex];
|
||||||
|
mTextureCoordsNames[pIndex] = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mTextureCoordsNames[pIndex] == nullptr) {
|
||||||
|
mTextureCoordsNames[pIndex] = new aiString(texCoordsName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*mTextureCoordsNames[pIndex] = texCoordsName;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Get a texture coordinate set name
|
||||||
|
//! \param pIndex Index of the texture coordinates set
|
||||||
|
const aiString *GetTextureCoordsName(unsigned int pIndex) const {
|
||||||
|
if (mTextureCoordsNames == nullptr || pIndex >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mTextureCoordsNames[pIndex];
|
||||||
|
}
|
||||||
|
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -90,6 +90,7 @@ SET( COMMON
|
||||||
unit/utProfiler.cpp
|
unit/utProfiler.cpp
|
||||||
unit/utSharedPPData.cpp
|
unit/utSharedPPData.cpp
|
||||||
unit/utStringUtils.cpp
|
unit/utStringUtils.cpp
|
||||||
|
unit/Common/utMesh.cpp
|
||||||
unit/Common/utStandardShapes.cpp
|
unit/Common/utStandardShapes.cpp
|
||||||
unit/Common/uiScene.cpp
|
unit/Common/uiScene.cpp
|
||||||
unit/Common/utLineSplitter.cpp
|
unit/Common/utLineSplitter.cpp
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.0//EN" "https://www.web3d.org/specifications/x3d-3.0.dtd">
|
||||||
|
<X3D profile='Immersive' version='3.0' xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance' xsd:noNamespaceSchemaLocation='https://www.web3d.org/specifications/x3d-3.0.xsd'>
|
||||||
|
<!-- X3D™ is a trademark of the Web3D Consortium Incorporated, standing for Extensible 3D Graphics (X3D). -->
|
||||||
|
<head>
|
||||||
|
<meta content='HelloX3dTrademark.x3d' name='title'/>
|
||||||
|
<meta content='Don Brutzman' name='creator'/>
|
||||||
|
<meta content='6 June 2001' name='created'/>
|
||||||
|
<meta content='20 October 2019' name='modified'/>
|
||||||
|
<meta content='Simple example showing spinning globe and X3D&#8482; trademark text. X3D (tm) is a trademark of the Web3D Consortium Inc. X3D stands for Extensible 3D Graphics (X3D), an encoding of VRML using XML. X3D has been defined since 1998. Trademark registration pending. VRML is the Virtual Reality Modeling Language (VRML), International Standard ISO/IEC 14772-1:1997. XML is the Extensible Markup Language (XML), a Recommendation of the World Wide Web Consortium (W3C).' name='description'/>
|
||||||
|
<meta content='HelloX3dTrademark.png' name='Image'/>
|
||||||
|
<meta content='https://www.web3d.org' name='reference'/>
|
||||||
|
<meta content='https://www.web3d.org/x3d' name='reference'/>
|
||||||
|
<meta content='https://www.web3d.org/Specifications/VRML97' name='reference'/>
|
||||||
|
<meta content='http://www.w3.org/XML' name='reference'/>
|
||||||
|
<meta content='https://www.web3d.org/x3d/content/examples/Basic/development/HelloX3dTrademark.x3d' name='identifier'/>
|
||||||
|
<meta content='X3D-Edit 3.3, https://savage.nps.edu/X3D-Edit' name='generator'/>
|
||||||
|
<meta content='../license.html' name='license'/>
|
||||||
|
</head>
|
||||||
|
<Scene>
|
||||||
|
<WorldInfo info='"an introductory scene"' title='Hello X3D&#8482; Trademark (tm)'/>
|
||||||
|
<Viewpoint description='Hello, world' orientation='0 1 0 3.14159' position='0 0 -8'/>
|
||||||
|
<Transform DEF='EarthCoordinateSystem'>
|
||||||
|
<Group DEF='MiniWorld'>
|
||||||
|
<Shape>
|
||||||
|
<Appearance>
|
||||||
|
<ImageTexture url='"earth-topo.png" "earth-topo.gif" "earth-topo-small.gif" "https://www.web3d.org/x3d/content/examples/Basic/development/earth-topo.png" "https://www.web3d.org/x3d/content/examples/Basic/development/earth-topo.gif" "https://www.web3d.org/x3d/content/examples/Basic/development/earth-topo-small.gif"'/>
|
||||||
|
</Appearance>
|
||||||
|
<Sphere DEF='GlobeNotToScale'/>
|
||||||
|
</Shape>
|
||||||
|
</Group>
|
||||||
|
<Transform DEF='SimpleGeoStationarySatellite' scale='0.1 0.3 0.1' translation='0 0 4'>
|
||||||
|
<Shape>
|
||||||
|
<Appearance>
|
||||||
|
<Material diffuseColor='0.9 0.1 0.1'/>
|
||||||
|
</Appearance>
|
||||||
|
<Text string='"Hello" "X3D Trademark (tm)"'>
|
||||||
|
<FontStyle justify='"MIDDLE" "MIDDLE"' size='3'/>
|
||||||
|
</Text>
|
||||||
|
</Shape>
|
||||||
|
</Transform>
|
||||||
|
</Transform>
|
||||||
|
<TimeSensor DEF='OrbitalTimeInterval' cycleInterval='12.0' loop='true'/>
|
||||||
|
<OrientationInterpolator DEF='SpinThoseThings' key='0.00 0.25 0.50 0.75 1.00' keyValue='0 1 0 0 0 1 0 1.57079 0 1 0 3.14159 0 1 0 4.7123889 0 1 0 6.2831852'/>
|
||||||
|
<ROUTE fromField='fraction_changed' fromNode='OrbitalTimeInterval' toField='set_fraction' toNode='SpinThoseThings'/>
|
||||||
|
<ROUTE fromField='value_changed' fromNode='SpinThoseThings' toField='rotation' toNode='EarthCoordinateSystem'/>
|
||||||
|
</Scene>
|
||||||
|
</X3D>
|
BIN
test/test.3mf
BIN
test/test.3mf
Binary file not shown.
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2021, 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.
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "UnitTestPCH.h"
|
||||||
|
|
||||||
|
#include <assimp/mesh.h>
|
||||||
|
|
||||||
|
using namespace Assimp;
|
||||||
|
|
||||||
|
class utMesh : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
aiMesh* mesh = nullptr;
|
||||||
|
|
||||||
|
void SetUp() override {
|
||||||
|
mesh = new aiMesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown() override {
|
||||||
|
delete mesh;
|
||||||
|
mesh = nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(utMesh, emptyMeshHasNoContentTest) {
|
||||||
|
EXPECT_EQ(0, mesh->mName.length);
|
||||||
|
EXPECT_FALSE(mesh->HasPositions());
|
||||||
|
EXPECT_FALSE(mesh->HasFaces());
|
||||||
|
EXPECT_FALSE(mesh->HasNormals());
|
||||||
|
EXPECT_FALSE(mesh->HasTangentsAndBitangents());
|
||||||
|
EXPECT_FALSE(mesh->HasVertexColors(0));
|
||||||
|
EXPECT_FALSE(mesh->HasVertexColors(AI_MAX_NUMBER_OF_COLOR_SETS));
|
||||||
|
EXPECT_FALSE(mesh->HasTextureCoords(0));
|
||||||
|
EXPECT_FALSE(mesh->HasTextureCoords(AI_MAX_NUMBER_OF_TEXTURECOORDS));
|
||||||
|
EXPECT_EQ(0, mesh->GetNumUVChannels());
|
||||||
|
EXPECT_EQ(0, mesh->GetNumColorChannels());
|
||||||
|
EXPECT_FALSE(mesh->HasBones());
|
||||||
|
EXPECT_FALSE(mesh->HasTextureCoordsName(0));
|
||||||
|
EXPECT_FALSE(mesh->HasTextureCoordsName(AI_MAX_NUMBER_OF_TEXTURECOORDS));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(utMesh, setTextureCoordsName) {
|
||||||
|
EXPECT_FALSE(mesh->HasTextureCoordsName(0));
|
||||||
|
const aiString texcoords_name("texcoord_name");
|
||||||
|
mesh->SetTextureCoordsName(0, texcoords_name);
|
||||||
|
EXPECT_TRUE(mesh->HasTextureCoordsName(0));
|
||||||
|
EXPECT_FALSE(mesh->HasTextureCoordsName(1));
|
||||||
|
ASSERT_NE(nullptr, mesh->mTextureCoordsNames);
|
||||||
|
ASSERT_NE(nullptr, mesh->mTextureCoordsNames[0]);
|
||||||
|
EXPECT_STREQ(texcoords_name.C_Str(), mesh->mTextureCoordsNames[0]->C_Str());
|
||||||
|
EXPECT_STREQ(texcoords_name.C_Str(), mesh->GetTextureCoordsName(0)->C_Str());
|
||||||
|
|
||||||
|
// Now clear the name
|
||||||
|
mesh->SetTextureCoordsName(0, aiString());
|
||||||
|
EXPECT_FALSE(mesh->HasTextureCoordsName(0));
|
||||||
|
ASSERT_NE(nullptr, mesh->mTextureCoordsNames);
|
||||||
|
EXPECT_EQ(nullptr, mesh->mTextureCoordsNames[0]);
|
||||||
|
EXPECT_EQ(nullptr, mesh->GetTextureCoordsName(0));
|
||||||
|
}
|
|
@ -49,10 +49,10 @@ using namespace Assimp;
|
||||||
|
|
||||||
class utX3DImportExport : public AbstractImportExportBase {
|
class utX3DImportExport : public AbstractImportExportBase {
|
||||||
public:
|
public:
|
||||||
virtual bool importerTest() {
|
bool importerTest() override {
|
||||||
Assimp::Importer importer;
|
Assimp::Importer importer;
|
||||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/X3D/ComputerKeyboard.x3d", aiProcess_ValidateDataStructure);
|
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/X3D/HelloX3dTrademark.x3d", aiProcess_ValidateDataStructure);
|
||||||
return nullptr == scene;
|
return nullptr != scene;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue