closes https://github.com/assimp/assimp/issues/1044: set default value in case of light intensity envelopes-

pull/3495/head
Kim Kulling 2020-11-11 19:38:42 +01:00
parent de610b8ce9
commit 456b54988a
14 changed files with 2039 additions and 2374 deletions

View File

@ -123,20 +123,20 @@ const aiImporterDesc *FBXImporter::GetInfo() const {
// ------------------------------------------------------------------------------------------------
// Setup configuration properties for the loader
void FBXImporter::SetupProperties(const Importer *pImp) {
settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
settings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true);
settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
settings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
settings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
settings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
mSettings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
mSettings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
mSettings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
mSettings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
mSettings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
mSettings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
mSettings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
mSettings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true);
mSettings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
mSettings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
mSettings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
mSettings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
mSettings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
mSettings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
}
// ------------------------------------------------------------------------------------------------
@ -181,10 +181,10 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
Parser parser(tokens, is_binary);
// take the raw parse-tree and convert it to a FBX DOM
Document doc(parser, settings);
Document doc(parser, mSettings);
// convert the FBX DOM to aiScene
ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones);
ConvertToAssimpScene(pScene, doc, mSettings.removeEmptyBones);
// size relative to cm
float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();

View File

@ -70,27 +70,16 @@ typedef class basic_formatter<char, std::char_traits<char>, std::allocator<char>
class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter> {
public:
FBXImporter();
virtual ~FBXImporter();
// --------------------
bool CanRead(const std::string &pFile,
IOSystem *pIOHandler,
bool checkSig) const;
~FBXImporter() override;
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const;
protected:
// --------------------
const aiImporterDesc *GetInfo() const;
// --------------------
void SetupProperties(const Importer *pImp);
// --------------------
void InternReadFile(const std::string &pFile,
aiScene *pScene,
IOSystem *pIOHandler);
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
private:
FBX::ImportSettings settings;
FBX::ImportSettings mSettings;
}; // !class FBXImporter
} // end of namespace Assimp

View File

@ -48,12 +48,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <functional>
#include "FBXMeshGeometry.h"
#include "FBXDocument.h"
#include "FBXImporter.h"
#include "FBXImportSettings.h"
#include "FBXDocumentUtil.h"
#include "FBXImportSettings.h"
#include "FBXImporter.h"
#include "FBXMeshGeometry.h"
namespace Assimp {
namespace FBX {
@ -61,17 +60,15 @@ namespace FBX {
using namespace Util;
// ------------------------------------------------------------------------------------------------
Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
: Object(id, element, name)
, skin()
{
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
for(const Connection* con : conns) {
const Skin* const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
if(sk) {
Geometry::Geometry(uint64_t id, const Element &element, const std::string &name, const Document &doc) :
Object(id, element, name), skin() {
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer");
for (const Connection *con : conns) {
const Skin *const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
if (sk) {
skin = sk;
}
const BlendShape* const bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry", element);
const BlendShape *const bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry", element);
if (bsp) {
blendShapes.push_back(bsp);
}
@ -79,48 +76,46 @@ Geometry::Geometry(uint64_t id, const Element& element, const std::string& name,
}
// ------------------------------------------------------------------------------------------------
Geometry::~Geometry()
{
Geometry::~Geometry() {
// empty
}
// ------------------------------------------------------------------------------------------------
const std::vector<const BlendShape*>& Geometry::GetBlendShapes() const {
const std::vector<const BlendShape *> &Geometry::GetBlendShapes() const {
return blendShapes;
}
// ------------------------------------------------------------------------------------------------
const Skin* Geometry::DeformerSkin() const {
const Skin *Geometry::DeformerSkin() const {
return skin;
}
// ------------------------------------------------------------------------------------------------
MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
: Geometry(id, element,name, doc)
{
const Scope* sc = element.Compound();
MeshGeometry::MeshGeometry(uint64_t id, const Element &element, const std::string &name, const Document &doc) :
Geometry(id, element, name, doc) {
const Scope *sc = element.Compound();
if (!sc) {
DOMError("failed to read Geometry object (class: Mesh), no data scope found");
}
// must have Mesh elements:
const Element& Vertices = GetRequiredElement(*sc,"Vertices",&element);
const Element& PolygonVertexIndex = GetRequiredElement(*sc,"PolygonVertexIndex",&element);
const Element &Vertices = GetRequiredElement(*sc, "Vertices", &element);
const Element &PolygonVertexIndex = GetRequiredElement(*sc, "PolygonVertexIndex", &element);
// optional Mesh elements:
const ElementCollection& Layer = sc->GetCollection("Layer");
const ElementCollection &Layer = sc->GetCollection("Layer");
std::vector<aiVector3D> tempVerts;
ParseVectorDataArray(tempVerts,Vertices);
ParseVectorDataArray(tempVerts, Vertices);
if(tempVerts.empty()) {
if (tempVerts.empty()) {
FBXImporter::LogWarn("encountered mesh with no vertices");
}
std::vector<int> tempFaces;
ParseVectorDataArray(tempFaces,PolygonVertexIndex);
ParseVectorDataArray(tempFaces, PolygonVertexIndex);
if(tempFaces.empty()) {
if (tempFaces.empty()) {
FBXImporter::LogWarn("encountered mesh with no faces");
}
@ -128,7 +123,7 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
m_faces.reserve(tempFaces.size() / 3);
m_mapping_offsets.resize(tempVerts.size());
m_mapping_counts.resize(tempVerts.size(),0);
m_mapping_counts.resize(tempVerts.size(), 0);
m_mappings.resize(tempFaces.size());
const size_t vertex_count = tempVerts.size();
@ -136,10 +131,10 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
// generate output vertices, computing an adjacency table to
// preserve the mapping from fbx indices to *this* indexing.
unsigned int count = 0;
for(int index : tempFaces) {
for (int index : tempFaces) {
const int absi = index < 0 ? (-index - 1) : index;
if(static_cast<size_t>(absi) >= vertex_count) {
DOMError("polygon vertex index out of range",&PolygonVertexIndex);
if (static_cast<size_t>(absi) >= vertex_count) {
DOMError("polygon vertex index out of range", &PolygonVertexIndex);
}
m_vertices.push_back(tempVerts[absi]);
@ -162,7 +157,7 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
}
cursor = 0;
for(int index : tempFaces) {
for (int index : tempFaces) {
const int absi = index < 0 ? (-index - 1) : index;
m_mappings[m_mapping_offsets[absi] + m_mapping_counts[absi]++] = cursor++;
}
@ -172,19 +167,18 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
// if settings.readAllLayers is false:
// * read only the layer with index 0, but warn about any further layers
for (ElementMap::const_iterator it = Layer.first; it != Layer.second; ++it) {
const TokenList& tokens = (*it).second->Tokens();
const TokenList &tokens = (*it).second->Tokens();
const char* err;
const char *err;
const int index = ParseTokenAsInt(*tokens[0], err);
if(err) {
DOMError(err,&element);
if (err) {
DOMError(err, &element);
}
if(doc.Settings().readAllLayers || index == 0) {
const Scope& layer = GetRequiredScope(*(*it).second);
if (doc.Settings().readAllLayers || index == 0) {
const Scope &layer = GetRequiredScope(*(*it).second);
ReadLayer(layer);
}
else {
} else {
FBXImporter::LogWarn("ignoring additional geometry layers");
}
}
@ -196,113 +190,109 @@ MeshGeometry::~MeshGeometry() {
}
// ------------------------------------------------------------------------------------------------
const std::vector<aiVector3D>& MeshGeometry::GetVertices() const {
const std::vector<aiVector3D> &MeshGeometry::GetVertices() const {
return m_vertices;
}
// ------------------------------------------------------------------------------------------------
const std::vector<aiVector3D>& MeshGeometry::GetNormals() const {
const std::vector<aiVector3D> &MeshGeometry::GetNormals() const {
return m_normals;
}
// ------------------------------------------------------------------------------------------------
const std::vector<aiVector3D>& MeshGeometry::GetTangents() const {
const std::vector<aiVector3D> &MeshGeometry::GetTangents() const {
return m_tangents;
}
// ------------------------------------------------------------------------------------------------
const std::vector<aiVector3D>& MeshGeometry::GetBinormals() const {
const std::vector<aiVector3D> &MeshGeometry::GetBinormals() const {
return m_binormals;
}
// ------------------------------------------------------------------------------------------------
const std::vector<unsigned int>& MeshGeometry::GetFaceIndexCounts() const {
const std::vector<unsigned int> &MeshGeometry::GetFaceIndexCounts() const {
return m_faces;
}
// ------------------------------------------------------------------------------------------------
const std::vector<aiVector2D>& MeshGeometry::GetTextureCoords( unsigned int index ) const {
const std::vector<aiVector2D> &MeshGeometry::GetTextureCoords(unsigned int index) const {
static const std::vector<aiVector2D> empty;
return index >= AI_MAX_NUMBER_OF_TEXTURECOORDS ? empty : m_uvs[ index ];
return index >= AI_MAX_NUMBER_OF_TEXTURECOORDS ? empty : m_uvs[index];
}
std::string MeshGeometry::GetTextureCoordChannelName( unsigned int index ) const {
return index >= AI_MAX_NUMBER_OF_TEXTURECOORDS ? "" : m_uvNames[ index ];
std::string MeshGeometry::GetTextureCoordChannelName(unsigned int index) const {
return index >= AI_MAX_NUMBER_OF_TEXTURECOORDS ? "" : m_uvNames[index];
}
const std::vector<aiColor4D>& MeshGeometry::GetVertexColors( unsigned int index ) const {
const std::vector<aiColor4D> &MeshGeometry::GetVertexColors(unsigned int index) const {
static const std::vector<aiColor4D> empty;
return index >= AI_MAX_NUMBER_OF_COLOR_SETS ? empty : m_colors[ index ];
return index >= AI_MAX_NUMBER_OF_COLOR_SETS ? empty : m_colors[index];
}
const MatIndexArray& MeshGeometry::GetMaterialIndices() const {
const MatIndexArray &MeshGeometry::GetMaterialIndices() const {
return m_materials;
}
// ------------------------------------------------------------------------------------------------
const unsigned int* MeshGeometry::ToOutputVertexIndex( unsigned int in_index, unsigned int& count ) const {
if ( in_index >= m_mapping_counts.size() ) {
const unsigned int *MeshGeometry::ToOutputVertexIndex(unsigned int in_index, unsigned int &count) const {
if (in_index >= m_mapping_counts.size()) {
return nullptr;
}
ai_assert( m_mapping_counts.size() == m_mapping_offsets.size() );
count = m_mapping_counts[ in_index ];
ai_assert(m_mapping_counts.size() == m_mapping_offsets.size());
count = m_mapping_counts[in_index];
ai_assert( m_mapping_offsets[ in_index ] + count <= m_mappings.size() );
ai_assert(m_mapping_offsets[in_index] + count <= m_mappings.size());
return &m_mappings[ m_mapping_offsets[ in_index ] ];
return &m_mappings[m_mapping_offsets[in_index]];
}
// ------------------------------------------------------------------------------------------------
unsigned int MeshGeometry::FaceForVertexIndex( unsigned int in_index ) const {
ai_assert( in_index < m_vertices.size() );
unsigned int MeshGeometry::FaceForVertexIndex(unsigned int in_index) const {
ai_assert(in_index < m_vertices.size());
// in the current conversion pattern this will only be needed if
// weights are present, so no need to always pre-compute this table
if ( m_facesVertexStartIndices.empty() ) {
m_facesVertexStartIndices.resize( m_faces.size() + 1, 0 );
if (m_facesVertexStartIndices.empty()) {
m_facesVertexStartIndices.resize(m_faces.size() + 1, 0);
std::partial_sum( m_faces.begin(), m_faces.end(), m_facesVertexStartIndices.begin() + 1 );
std::partial_sum(m_faces.begin(), m_faces.end(), m_facesVertexStartIndices.begin() + 1);
m_facesVertexStartIndices.pop_back();
}
ai_assert( m_facesVertexStartIndices.size() == m_faces.size() );
ai_assert(m_facesVertexStartIndices.size() == m_faces.size());
const std::vector<unsigned int>::iterator it = std::upper_bound(
m_facesVertexStartIndices.begin(),
m_facesVertexStartIndices.end(),
in_index
);
in_index);
return static_cast< unsigned int >( std::distance( m_facesVertexStartIndices.begin(), it - 1 ) );
return static_cast<unsigned int>(std::distance(m_facesVertexStartIndices.begin(), it - 1));
}
// ------------------------------------------------------------------------------------------------
void MeshGeometry::ReadLayer(const Scope& layer)
{
const ElementCollection& LayerElement = layer.GetCollection("LayerElement");
void MeshGeometry::ReadLayer(const Scope &layer) {
const ElementCollection &LayerElement = layer.GetCollection("LayerElement");
for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) {
const Scope& elayer = GetRequiredScope(*(*eit).second);
const Scope &elayer = GetRequiredScope(*(*eit).second);
ReadLayerElement(elayer);
}
}
// ------------------------------------------------------------------------------------------------
void MeshGeometry::ReadLayerElement(const Scope& layerElement)
{
const Element& Type = GetRequiredElement(layerElement,"Type");
const Element& TypedIndex = GetRequiredElement(layerElement,"TypedIndex");
void MeshGeometry::ReadLayerElement(const Scope &layerElement) {
const Element &Type = GetRequiredElement(layerElement, "Type");
const Element &TypedIndex = GetRequiredElement(layerElement, "TypedIndex");
const std::string& type = ParseTokenAsString(GetRequiredToken(Type,0));
const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex,0));
const std::string &type = ParseTokenAsString(GetRequiredToken(Type, 0));
const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex, 0));
const Scope& top = GetRequiredScope(element);
const Scope &top = GetRequiredScope(element);
const ElementCollection candidates = top.GetCollection(type);
for (ElementMap::const_iterator it = candidates.first; it != candidates.second; ++it) {
const int index = ParseTokenAsInt(GetRequiredToken(*(*it).second,0));
if(index == typedIndex) {
ReadVertexData(type,typedIndex,GetRequiredScope(*(*it).second));
const int index = ParseTokenAsInt(GetRequiredToken(*(*it).second, 0));
if (index == typedIndex) {
ReadVertexData(type, typedIndex, GetRequiredScope(*(*it).second));
return;
}
}
@ -312,35 +302,30 @@ void MeshGeometry::ReadLayerElement(const Scope& layerElement)
}
// ------------------------------------------------------------------------------------------------
void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scope& source)
{
const std::string& MappingInformationType = ParseTokenAsString(GetRequiredToken(
GetRequiredElement(source,"MappingInformationType"),0)
);
void MeshGeometry::ReadVertexData(const std::string &type, int index, const Scope &source) {
const std::string &MappingInformationType = ParseTokenAsString(GetRequiredToken(
GetRequiredElement(source, "MappingInformationType"), 0));
const std::string& ReferenceInformationType = ParseTokenAsString(GetRequiredToken(
GetRequiredElement(source,"ReferenceInformationType"),0)
);
const std::string &ReferenceInformationType = ParseTokenAsString(GetRequiredToken(
GetRequiredElement(source, "ReferenceInformationType"), 0));
if (type == "LayerElementUV") {
if(index >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
if (index >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
FBXImporter::LogError(Formatter::format("ignoring UV layer, maximum number of UV channels exceeded: ")
<< index << " (limit is " << AI_MAX_NUMBER_OF_TEXTURECOORDS << ")" );
<< index << " (limit is " << AI_MAX_NUMBER_OF_TEXTURECOORDS << ")");
return;
}
const Element* Name = source["Name"];
const Element *Name = source["Name"];
m_uvNames[index] = "";
if(Name) {
m_uvNames[index] = ParseTokenAsString(GetRequiredToken(*Name,0));
if (Name) {
m_uvNames[index] = ParseTokenAsString(GetRequiredToken(*Name, 0));
}
ReadVertexDataUV(m_uvs[index],source,
ReadVertexDataUV(m_uvs[index], source,
MappingInformationType,
ReferenceInformationType
);
}
else if (type == "LayerElementMaterial") {
ReferenceInformationType);
} else if (type == "LayerElementMaterial") {
if (m_materials.size() > 0) {
FBXImporter::LogError("ignoring additional material layer");
return;
@ -348,10 +333,9 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop
std::vector<int> temp_materials;
ReadVertexDataMaterials(temp_materials,source,
ReadVertexDataMaterials(temp_materials, source,
MappingInformationType,
ReferenceInformationType
);
ReferenceInformationType);
// sometimes, there will be only negative entries. Drop the material
// layer in such a case (I guess it means a default material should
@ -359,58 +343,50 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop
// avoids losing the material if there are more material layers
// coming of which at least one contains actual data (did observe
// that with one test file).
const size_t count_neg = std::count_if(temp_materials.begin(),temp_materials.end(),[](int n) { return n < 0; });
if(count_neg == temp_materials.size()) {
const size_t count_neg = std::count_if(temp_materials.begin(), temp_materials.end(), [](int n) { return n < 0; });
if (count_neg == temp_materials.size()) {
FBXImporter::LogWarn("ignoring dummy material layer (all entries -1)");
return;
}
std::swap(temp_materials, m_materials);
}
else if (type == "LayerElementNormal") {
} else if (type == "LayerElementNormal") {
if (m_normals.size() > 0) {
FBXImporter::LogError("ignoring additional normal layer");
return;
}
ReadVertexDataNormals(m_normals,source,
ReadVertexDataNormals(m_normals, source,
MappingInformationType,
ReferenceInformationType
);
}
else if (type == "LayerElementTangent") {
ReferenceInformationType);
} else if (type == "LayerElementTangent") {
if (m_tangents.size() > 0) {
FBXImporter::LogError("ignoring additional tangent layer");
return;
}
ReadVertexDataTangents(m_tangents,source,
ReadVertexDataTangents(m_tangents, source,
MappingInformationType,
ReferenceInformationType
);
}
else if (type == "LayerElementBinormal") {
ReferenceInformationType);
} else if (type == "LayerElementBinormal") {
if (m_binormals.size() > 0) {
FBXImporter::LogError("ignoring additional binormal layer");
return;
}
ReadVertexDataBinormals(m_binormals,source,
ReadVertexDataBinormals(m_binormals, source,
MappingInformationType,
ReferenceInformationType
);
}
else if (type == "LayerElementColor") {
if(index >= AI_MAX_NUMBER_OF_COLOR_SETS) {
ReferenceInformationType);
} else if (type == "LayerElementColor") {
if (index >= AI_MAX_NUMBER_OF_COLOR_SETS) {
FBXImporter::LogError(Formatter::format("ignoring vertex color layer, maximum number of color sets exceeded: ")
<< index << " (limit is " << AI_MAX_NUMBER_OF_COLOR_SETS << ")" );
<< index << " (limit is " << AI_MAX_NUMBER_OF_COLOR_SETS << ")");
return;
}
ReadVertexDataColors(m_colors[index],source,
ReadVertexDataColors(m_colors[index], source,
MappingInformationType,
ReferenceInformationType
);
ReferenceInformationType);
}
}
@ -419,21 +395,20 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop
// output is in polygon vertex order. This logic is used for reading normals, UVs, colors,
// tangents ..
template <typename T>
void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
const std::string& MappingInformationType,
const std::string& ReferenceInformationType,
const char* dataElementName,
const char* indexDataElementName,
void ResolveVertexDataArray(std::vector<T> &data_out, const Scope &source,
const std::string &MappingInformationType,
const std::string &ReferenceInformationType,
const char *dataElementName,
const char *indexDataElementName,
size_t vertex_count,
const std::vector<unsigned int>& mapping_counts,
const std::vector<unsigned int>& mapping_offsets,
const std::vector<unsigned int>& mappings)
{
const std::vector<unsigned int> &mapping_counts,
const std::vector<unsigned int> &mapping_offsets,
const std::vector<unsigned int> &mappings) {
bool isDirect = ReferenceInformationType == "Direct";
bool isIndexToDirect = ReferenceInformationType == "IndexToDirect";
// fall-back to direct data if there is no index data element
if ( isIndexToDirect && !HasElement( source, indexDataElementName ) ) {
if (isIndexToDirect && !HasElement(source, indexDataElementName)) {
isDirect = true;
isIndexToDirect = false;
}
@ -461,13 +436,12 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
data_out[mappings[j]] = tempData[i];
}
}
}
else if (MappingInformationType == "ByVertice" && isIndexToDirect) {
} else if (MappingInformationType == "ByVertice" && isIndexToDirect) {
std::vector<T> tempData;
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
std::vector<int> uvIndices;
ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
ParseVectorDataArray(uvIndices, GetRequiredElement(source, indexDataElementName));
if (uvIndices.size() != vertex_count) {
FBXImporter::LogError(Formatter::format("length of input data unexpected for ByVertice mapping: ")
@ -482,31 +456,28 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
for (unsigned int j = istart; j < iend; ++j) {
if (static_cast<size_t>(uvIndices[i]) >= tempData.size()) {
DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
DOMError("index out of range", &GetRequiredElement(source, indexDataElementName));
}
data_out[mappings[j]] = tempData[uvIndices[i]];
}
}
}
else if (MappingInformationType == "ByPolygonVertex" && isDirect) {
} else if (MappingInformationType == "ByPolygonVertex" && isDirect) {
std::vector<T> tempData;
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
if (tempData.size() != vertex_count) {
FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")
<< tempData.size() << ", expected " << vertex_count
);
<< tempData.size() << ", expected " << vertex_count);
return;
}
data_out.swap(tempData);
}
else if (MappingInformationType == "ByPolygonVertex" && isIndexToDirect) {
} else if (MappingInformationType == "ByPolygonVertex" && isIndexToDirect) {
std::vector<T> tempData;
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
std::vector<int> uvIndices;
ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
ParseVectorDataArray(uvIndices, GetRequiredElement(source, indexDataElementName));
if (uvIndices.size() != vertex_count) {
FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygonVertex mapping: ")
@ -518,30 +489,28 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
const T empty;
unsigned int next = 0;
for(int i : uvIndices) {
if ( -1 == i ) {
data_out[ next++ ] = empty;
for (int i : uvIndices) {
if (-1 == i) {
data_out[next++] = empty;
continue;
}
if (static_cast<size_t>(i) >= tempData.size()) {
DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
DOMError("index out of range", &GetRequiredElement(source, indexDataElementName));
}
data_out[next++] = tempData[i];
}
}
else {
} else {
FBXImporter::LogError(Formatter::format("ignoring vertex data channel, access type not implemented: ")
<< MappingInformationType << "," << ReferenceInformationType);
}
}
// ------------------------------------------------------------------------------------------------
void MeshGeometry::ReadVertexDataNormals(std::vector<aiVector3D>& normals_out, const Scope& source,
const std::string& MappingInformationType,
const std::string& ReferenceInformationType)
{
ResolveVertexDataArray(normals_out,source,MappingInformationType,ReferenceInformationType,
void MeshGeometry::ReadVertexDataNormals(std::vector<aiVector3D> &normals_out, const Scope &source,
const std::string &MappingInformationType,
const std::string &ReferenceInformationType) {
ResolveVertexDataArray(normals_out, source, MappingInformationType, ReferenceInformationType,
"Normals",
"NormalsIndex",
m_vertices.size(),
@ -551,11 +520,10 @@ void MeshGeometry::ReadVertexDataNormals(std::vector<aiVector3D>& normals_out, c
}
// ------------------------------------------------------------------------------------------------
void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D>& uv_out, const Scope& source,
const std::string& MappingInformationType,
const std::string& ReferenceInformationType)
{
ResolveVertexDataArray(uv_out,source,MappingInformationType,ReferenceInformationType,
void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D> &uv_out, const Scope &source,
const std::string &MappingInformationType,
const std::string &ReferenceInformationType) {
ResolveVertexDataArray(uv_out, source, MappingInformationType, ReferenceInformationType,
"UV",
"UVIndex",
m_vertices.size(),
@ -565,11 +533,10 @@ void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D>& uv_out, const Scope
}
// ------------------------------------------------------------------------------------------------
void MeshGeometry::ReadVertexDataColors(std::vector<aiColor4D>& colors_out, const Scope& source,
const std::string& MappingInformationType,
const std::string& ReferenceInformationType)
{
ResolveVertexDataArray(colors_out,source,MappingInformationType,ReferenceInformationType,
void MeshGeometry::ReadVertexDataColors(std::vector<aiColor4D> &colors_out, const Scope &source,
const std::string &MappingInformationType,
const std::string &ReferenceInformationType) {
ResolveVertexDataArray(colors_out, source, MappingInformationType, ReferenceInformationType,
"Colors",
"ColorIndex",
m_vertices.size(),
@ -582,13 +549,12 @@ void MeshGeometry::ReadVertexDataColors(std::vector<aiColor4D>& colors_out, cons
static const char *TangentIndexToken = "TangentIndex";
static const char *TangentsIndexToken = "TangentsIndex";
void MeshGeometry::ReadVertexDataTangents(std::vector<aiVector3D>& tangents_out, const Scope& source,
const std::string& MappingInformationType,
const std::string& ReferenceInformationType)
{
const char * str = source.Elements().count( "Tangents" ) > 0 ? "Tangents" : "Tangent";
const char * strIdx = source.Elements().count( "Tangents" ) > 0 ? TangentsIndexToken : TangentIndexToken;
ResolveVertexDataArray(tangents_out,source,MappingInformationType,ReferenceInformationType,
void MeshGeometry::ReadVertexDataTangents(std::vector<aiVector3D> &tangents_out, const Scope &source,
const std::string &MappingInformationType,
const std::string &ReferenceInformationType) {
const char *str = source.Elements().count("Tangents") > 0 ? "Tangents" : "Tangent";
const char *strIdx = source.Elements().count("Tangents") > 0 ? TangentsIndexToken : TangentIndexToken;
ResolveVertexDataArray(tangents_out, source, MappingInformationType, ReferenceInformationType,
str,
strIdx,
m_vertices.size(),
@ -601,13 +567,12 @@ void MeshGeometry::ReadVertexDataTangents(std::vector<aiVector3D>& tangents_out,
static const std::string BinormalIndexToken = "BinormalIndex";
static const std::string BinormalsIndexToken = "BinormalsIndex";
void MeshGeometry::ReadVertexDataBinormals(std::vector<aiVector3D>& binormals_out, const Scope& source,
const std::string& MappingInformationType,
const std::string& ReferenceInformationType)
{
const char * str = source.Elements().count( "Binormals" ) > 0 ? "Binormals" : "Binormal";
const char * strIdx = source.Elements().count( "Binormals" ) > 0 ? BinormalsIndexToken.c_str() : BinormalIndexToken.c_str();
ResolveVertexDataArray(binormals_out,source,MappingInformationType,ReferenceInformationType,
void MeshGeometry::ReadVertexDataBinormals(std::vector<aiVector3D> &binormals_out, const Scope &source,
const std::string &MappingInformationType,
const std::string &ReferenceInformationType) {
const char *str = source.Elements().count("Binormals") > 0 ? "Binormals" : "Binormal";
const char *strIdx = source.Elements().count("Binormals") > 0 ? BinormalsIndexToken.c_str() : BinormalIndexToken.c_str();
ResolveVertexDataArray(binormals_out, source, MappingInformationType, ReferenceInformationType,
str,
strIdx,
m_vertices.size(),
@ -616,22 +581,19 @@ void MeshGeometry::ReadVertexDataBinormals(std::vector<aiVector3D>& binormals_ou
m_mappings);
}
// ------------------------------------------------------------------------------------------------
void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, const Scope& source,
const std::string& MappingInformationType,
const std::string& ReferenceInformationType)
{
void MeshGeometry::ReadVertexDataMaterials(std::vector<int> &materials_out, const Scope &source,
const std::string &MappingInformationType,
const std::string &ReferenceInformationType) {
const size_t face_count = m_faces.size();
if( 0 == face_count )
{
if (0 == face_count) {
return;
}
// materials are handled separately. First of all, they are assigned per-face
// and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect
// has a slightly different meaning for materials.
ParseVectorDataArray(materials_out,GetRequiredElement(source,"Materials"));
ParseVectorDataArray(materials_out, GetRequiredElement(source, "Materials"));
if (MappingInformationType == "AllSame") {
// easy - same material for all faces
@ -648,10 +610,9 @@ void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, cons
} else if (MappingInformationType == "ByPolygon" && ReferenceInformationType == "IndexToDirect") {
materials_out.resize(face_count);
if(materials_out.size() != face_count) {
if (materials_out.size() != face_count) {
FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")
<< materials_out.size() << ", expected " << face_count
);
<< materials_out.size() << ", expected " << face_count);
return;
}
} else {
@ -660,15 +621,15 @@ void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, cons
}
}
// ------------------------------------------------------------------------------------------------
ShapeGeometry::ShapeGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
: Geometry(id, element, name, doc) {
ShapeGeometry::ShapeGeometry(uint64_t id, const Element &element, const std::string &name, const Document &doc) :
Geometry(id, element, name, doc) {
const Scope *sc = element.Compound();
if (nullptr == sc) {
DOMError("failed to read Geometry object (class: Shape), no data scope found");
}
const Element& Indexes = GetRequiredElement(*sc, "Indexes", &element);
const Element& Normals = GetRequiredElement(*sc, "Normals", &element);
const Element& Vertices = GetRequiredElement(*sc, "Vertices", &element);
const Element &Indexes = GetRequiredElement(*sc, "Indexes", &element);
const Element &Normals = GetRequiredElement(*sc, "Normals", &element);
const Element &Vertices = GetRequiredElement(*sc, "Vertices", &element);
ParseVectorDataArray(m_indices, Indexes);
ParseVectorDataArray(m_vertices, Vertices);
ParseVectorDataArray(m_normals, Normals);
@ -679,27 +640,26 @@ ShapeGeometry::~ShapeGeometry() {
// empty
}
// ------------------------------------------------------------------------------------------------
const std::vector<aiVector3D>& ShapeGeometry::GetVertices() const {
const std::vector<aiVector3D> &ShapeGeometry::GetVertices() const {
return m_vertices;
}
// ------------------------------------------------------------------------------------------------
const std::vector<aiVector3D>& ShapeGeometry::GetNormals() const {
const std::vector<aiVector3D> &ShapeGeometry::GetNormals() const {
return m_normals;
}
// ------------------------------------------------------------------------------------------------
const std::vector<unsigned int>& ShapeGeometry::GetIndices() const {
const std::vector<unsigned int> &ShapeGeometry::GetIndices() const {
return m_indices;
}
// ------------------------------------------------------------------------------------------------
LineGeometry::LineGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
: Geometry(id, element, name, doc)
{
const Scope* sc = element.Compound();
LineGeometry::LineGeometry(uint64_t id, const Element &element, const std::string &name, const Document &doc) :
Geometry(id, element, name, doc) {
const Scope *sc = element.Compound();
if (!sc) {
DOMError("failed to read Geometry object (class: Line), no data scope found");
}
const Element& Points = GetRequiredElement(*sc, "Points", &element);
const Element& PointsIndex = GetRequiredElement(*sc, "PointsIndex", &element);
const Element &Points = GetRequiredElement(*sc, "Points", &element);
const Element &PointsIndex = GetRequiredElement(*sc, "PointsIndex", &element);
ParseVectorDataArray(m_vertices, Points);
ParseVectorDataArray(m_indices, PointsIndex);
}
@ -709,14 +669,13 @@ LineGeometry::~LineGeometry() {
// empty
}
// ------------------------------------------------------------------------------------------------
const std::vector<aiVector3D>& LineGeometry::GetVertices() const {
const std::vector<aiVector3D> &LineGeometry::GetVertices() const {
return m_vertices;
}
// ------------------------------------------------------------------------------------------------
const std::vector<int>& LineGeometry::GetIndices() const {
const std::vector<int> &LineGeometry::GetIndices() const {
return m_indices;
}
} // !FBX
} // !Assimp
} // namespace FBX
} // namespace Assimp
#endif

File diff suppressed because it is too large Load Diff

View File

@ -55,20 +55,19 @@ namespace Assimp {
namespace IFC {
// ------------------------------------------------------------------------------------------------
void TempOpening::Transform(const IfcMatrix4& mat) {
if(profileMesh) {
void TempOpening::Transform(const IfcMatrix4 &mat) {
if (profileMesh) {
profileMesh->Transform(mat);
}
if(profileMesh2D) {
if (profileMesh2D) {
profileMesh2D->Transform(mat);
}
extrusionDir *= IfcMatrix3(mat);
}
// ------------------------------------------------------------------------------------------------
aiMesh* TempMesh::ToMesh()
{
ai_assert(mVerts.size() == std::accumulate(mVertcnt.begin(),mVertcnt.end(),size_t(0)));
aiMesh *TempMesh::ToMesh() {
ai_assert(mVerts.size() == std::accumulate(mVertcnt.begin(), mVertcnt.end(), size_t(0)));
if (mVerts.empty()) {
return nullptr;
@ -79,14 +78,14 @@ aiMesh* TempMesh::ToMesh()
// copy vertices
mesh->mNumVertices = static_cast<unsigned int>(mVerts.size());
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
std::copy(mVerts.begin(),mVerts.end(),mesh->mVertices);
std::copy(mVerts.begin(), mVerts.end(), mesh->mVertices);
// and build up faces
mesh->mNumFaces = static_cast<unsigned int>(mVertcnt.size());
mesh->mFaces = new aiFace[mesh->mNumFaces];
for(unsigned int i = 0,n=0, acc = 0; i < mesh->mNumFaces; ++n) {
aiFace& f = mesh->mFaces[i];
for (unsigned int i = 0, n = 0, acc = 0; i < mesh->mNumFaces; ++n) {
aiFace &f = mesh->mFaces[i];
if (!mVertcnt[n]) {
--mesh->mNumFaces;
continue;
@ -94,7 +93,7 @@ aiMesh* TempMesh::ToMesh()
f.mNumIndices = mVertcnt[n];
f.mIndices = new unsigned int[f.mNumIndices];
for(unsigned int a = 0; a < f.mNumIndices; ++a) {
for (unsigned int a = 0; a < f.mNumIndices; ++a) {
f.mIndices[a] = acc++;
}
@ -105,36 +104,31 @@ aiMesh* TempMesh::ToMesh()
}
// ------------------------------------------------------------------------------------------------
void TempMesh::Clear()
{
void TempMesh::Clear() {
mVerts.clear();
mVertcnt.clear();
}
// ------------------------------------------------------------------------------------------------
void TempMesh::Transform(const IfcMatrix4& mat)
{
for(IfcVector3& v : mVerts) {
void TempMesh::Transform(const IfcMatrix4 &mat) {
for (IfcVector3 &v : mVerts) {
v *= mat;
}
}
// ------------------------------------------------------------------------------
IfcVector3 TempMesh::Center() const
{
return (mVerts.size() == 0) ? IfcVector3(0.0f, 0.0f, 0.0f) : (std::accumulate(mVerts.begin(),mVerts.end(),IfcVector3()) / static_cast<IfcFloat>(mVerts.size()));
IfcVector3 TempMesh::Center() const {
return (mVerts.size() == 0) ? IfcVector3(0.0f, 0.0f, 0.0f) : (std::accumulate(mVerts.begin(), mVerts.end(), IfcVector3()) / static_cast<IfcFloat>(mVerts.size()));
}
// ------------------------------------------------------------------------------------------------
void TempMesh::Append(const TempMesh& other)
{
mVerts.insert(mVerts.end(),other.mVerts.begin(),other.mVerts.end());
mVertcnt.insert(mVertcnt.end(),other.mVertcnt.begin(),other.mVertcnt.end());
void TempMesh::Append(const TempMesh &other) {
mVerts.insert(mVerts.end(), other.mVerts.begin(), other.mVerts.end());
mVertcnt.insert(mVertcnt.end(), other.mVertcnt.begin(), other.mVertcnt.end());
}
// ------------------------------------------------------------------------------------------------
void TempMesh::RemoveDegenerates()
{
void TempMesh::RemoveDegenerates() {
// The strategy is simple: walk the mesh and compute normals using
// Newell's algorithm. The length of the normals gives the area
// of the polygons, which is close to zero for lines.
@ -161,52 +155,48 @@ void TempMesh::RemoveDegenerates()
++it;
}
if(drop) {
if (drop) {
IFCImporter::LogVerboseDebug("removing degenerate faces");
}
}
// ------------------------------------------------------------------------------------------------
IfcVector3 TempMesh::ComputePolygonNormal(const IfcVector3* vtcs, size_t cnt, bool normalize)
{
std::vector<IfcFloat> temp((cnt+2)*3);
for( size_t vofs = 0, i = 0; vofs < cnt; ++vofs )
{
const IfcVector3& v = vtcs[vofs];
IfcVector3 TempMesh::ComputePolygonNormal(const IfcVector3 *vtcs, size_t cnt, bool normalize) {
const size_t Capa = cnt + 2;
std::vector<IfcFloat> temp((Capa)*3);
for (size_t vofs = 0, i = 0; vofs < cnt; ++vofs) {
const IfcVector3 &v = vtcs[vofs];
temp[i++] = v.x;
temp[i++] = v.y;
temp[i++] = v.z;
}
IfcVector3 nor;
NewellNormal<3, 3, 3>(nor, static_cast<int>(cnt), &temp[0], &temp[1], &temp[2]);
NewellNormal<3, 3, 3>(nor, static_cast<int>(cnt), &temp[0], &temp[1], &temp[2], Capa);
return normalize ? nor.Normalize() : nor;
}
// ------------------------------------------------------------------------------------------------
void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals,
bool normalize,
size_t ofs) const
{
void TempMesh::ComputePolygonNormals(std::vector<IfcVector3> &normals, bool normalize, size_t ofs) const {
size_t max_vcount = 0;
std::vector<unsigned int>::const_iterator begin = mVertcnt.begin()+ofs, end = mVertcnt.end(), iit;
for(iit = begin; iit != end; ++iit) {
max_vcount = std::max(max_vcount,static_cast<size_t>(*iit));
std::vector<unsigned int>::const_iterator begin = mVertcnt.begin() + ofs, end = mVertcnt.end(), iit;
for (iit = begin; iit != end; ++iit) {
max_vcount = std::max(max_vcount, static_cast<size_t>(*iit));
}
std::vector<IfcFloat> temp((max_vcount+2)*4);
normals.reserve( normals.size() + mVertcnt.size()-ofs );
const size_t Capa = max_vcount + 2;
std::vector<IfcFloat> temp(Capa * 4);
normals.reserve(normals.size() + mVertcnt.size() - ofs);
// `NewellNormal()` currently has a relatively strange interface and need to
// re-structure things a bit to meet them.
size_t vidx = std::accumulate(mVertcnt.begin(),begin,0);
for(iit = begin; iit != end; vidx += *iit++) {
size_t vidx = std::accumulate(mVertcnt.begin(), begin, 0);
for (iit = begin; iit != end; vidx += *iit++) {
if (!*iit) {
normals.push_back(IfcVector3());
continue;
}
for(size_t vofs = 0, cnt = 0; vofs < *iit; ++vofs) {
const IfcVector3& v = mVerts[vidx+vofs];
for (size_t vofs = 0, cnt = 0; vofs < *iit; ++vofs) {
const IfcVector3 &v = mVerts[vidx + vofs];
temp[cnt++] = v.x;
temp[cnt++] = v.y;
temp[cnt++] = v.z;
@ -217,11 +207,11 @@ void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals,
}
normals.push_back(IfcVector3());
NewellNormal<4,4,4>(normals.back(),*iit,&temp[0],&temp[1],&temp[2]);
NewellNormal<4, 4, 4>(normals.back(), *iit, &temp[0], &temp[1], &temp[2], Capa);
}
if(normalize) {
for(IfcVector3& n : normals) {
if (normalize) {
for (IfcVector3 &n : normals) {
n.Normalize();
}
}
@ -229,62 +219,55 @@ void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals,
// ------------------------------------------------------------------------------------------------
// Compute the normal of the last polygon in the given mesh
IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const
{
IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const {
return ComputePolygonNormal(&mVerts[mVerts.size() - mVertcnt.back()], mVertcnt.back(), normalize);
}
struct CompareVector
{
bool operator () (const IfcVector3& a, const IfcVector3& b) const
{
struct CompareVector {
bool operator()(const IfcVector3 &a, const IfcVector3 &b) const {
IfcVector3 d = a - b;
IfcFloat eps = 1e-6;
return d.x < -eps || (std::abs(d.x) < eps && d.y < -eps) || (std::abs(d.x) < eps && std::abs(d.y) < eps && d.z < -eps);
}
};
struct FindVector
{
struct FindVector {
IfcVector3 v;
FindVector(const IfcVector3& p) : v(p) { }
bool operator () (const IfcVector3& p) { return FuzzyVectorCompare(1e-6)(p, v); }
FindVector(const IfcVector3 &p) :
v(p) {}
bool operator()(const IfcVector3 &p) { return FuzzyVectorCompare(1e-6)(p, v); }
};
// ------------------------------------------------------------------------------------------------
void TempMesh::FixupFaceOrientation()
{
void TempMesh::FixupFaceOrientation() {
const IfcVector3 vavg = Center();
// create a list of start indices for all faces to allow random access to faces
std::vector<size_t> faceStartIndices(mVertcnt.size());
for( size_t i = 0, a = 0; a < mVertcnt.size(); i += mVertcnt[a], ++a )
for (size_t i = 0, a = 0; a < mVertcnt.size(); i += mVertcnt[a], ++a)
faceStartIndices[a] = i;
// list all faces on a vertex
std::map<IfcVector3, std::vector<size_t>, CompareVector> facesByVertex;
for( size_t a = 0; a < mVertcnt.size(); ++a )
{
for( size_t b = 0; b < mVertcnt[a]; ++b )
for (size_t a = 0; a < mVertcnt.size(); ++a) {
for (size_t b = 0; b < mVertcnt[a]; ++b)
facesByVertex[mVerts[faceStartIndices[a] + b]].push_back(a);
}
// determine neighbourhood for all polys
std::vector<size_t> neighbour(mVerts.size(), SIZE_MAX);
std::vector<size_t> tempIntersect(10);
for( size_t a = 0; a < mVertcnt.size(); ++a )
{
for( size_t b = 0; b < mVertcnt[a]; ++b )
{
for (size_t a = 0; a < mVertcnt.size(); ++a) {
for (size_t b = 0; b < mVertcnt[a]; ++b) {
size_t ib = faceStartIndices[a] + b, nib = faceStartIndices[a] + (b + 1) % mVertcnt[a];
const std::vector<size_t>& facesOnB = facesByVertex[mVerts[ib]];
const std::vector<size_t>& facesOnNB = facesByVertex[mVerts[nib]];
const std::vector<size_t> &facesOnB = facesByVertex[mVerts[ib]];
const std::vector<size_t> &facesOnNB = facesByVertex[mVerts[nib]];
// there should be exactly one or two faces which appear in both lists. Our face and the other side
std::vector<size_t>::iterator sectstart = tempIntersect.begin();
std::vector<size_t>::iterator sectend = std::set_intersection(
facesOnB.begin(), facesOnB.end(), facesOnNB.begin(), facesOnNB.end(), sectstart);
if( std::distance(sectstart, sectend) != 2 )
if (std::distance(sectstart, sectend) != 2)
continue;
if( *sectstart == a )
if (*sectstart == a)
++sectstart;
neighbour[ib] = *sectstart;
}
@ -294,30 +277,31 @@ void TempMesh::FixupFaceOrientation()
// facing outwards. So we reverse this face to point outwards in relation to the center. Then we adapt neighbouring
// faces to have the same winding until all faces have been tested.
std::vector<bool> faceDone(mVertcnt.size(), false);
while( std::count(faceDone.begin(), faceDone.end(), false) != 0 )
{
while (std::count(faceDone.begin(), faceDone.end(), false) != 0) {
// find the farthest of the remaining faces
size_t farthestIndex = SIZE_MAX;
IfcFloat farthestDistance = -1.0;
for( size_t a = 0; a < mVertcnt.size(); ++a )
{
if( faceDone[a] )
for (size_t a = 0; a < mVertcnt.size(); ++a) {
if (faceDone[a])
continue;
IfcVector3 faceCenter = std::accumulate(mVerts.begin() + faceStartIndices[a],
mVerts.begin() + faceStartIndices[a] + mVertcnt[a], IfcVector3(0.0)) / IfcFloat(mVertcnt[a]);
mVerts.begin() + faceStartIndices[a] + mVertcnt[a], IfcVector3(0.0)) /
IfcFloat(mVertcnt[a]);
IfcFloat dst = (faceCenter - vavg).SquareLength();
if( dst > farthestDistance ) { farthestDistance = dst; farthestIndex = a; }
if (dst > farthestDistance) {
farthestDistance = dst;
farthestIndex = a;
}
}
// calculate its normal and reverse the poly if its facing towards the mesh center
IfcVector3 farthestNormal = ComputePolygonNormal(mVerts.data() + faceStartIndices[farthestIndex], mVertcnt[farthestIndex]);
IfcVector3 farthestCenter = std::accumulate(mVerts.begin() + faceStartIndices[farthestIndex],
mVerts.begin() + faceStartIndices[farthestIndex] + mVertcnt[farthestIndex], IfcVector3(0.0))
/ IfcFloat(mVertcnt[farthestIndex]);
mVerts.begin() + faceStartIndices[farthestIndex] + mVertcnt[farthestIndex], IfcVector3(0.0)) /
IfcFloat(mVertcnt[farthestIndex]);
// We accept a bit of negative orientation without reversing. In case of doubt, prefer the orientation given in
// the file.
if( (farthestNormal * (farthestCenter - vavg).Normalize()) < -0.4 )
{
if ((farthestNormal * (farthestCenter - vavg).Normalize()) < -0.4) {
size_t fsi = faceStartIndices[farthestIndex], fvc = mVertcnt[farthestIndex];
std::reverse(mVerts.begin() + fsi, mVerts.begin() + fsi + fvc);
std::reverse(neighbour.begin() + fsi, neighbour.begin() + fsi + fvc);
@ -326,7 +310,7 @@ void TempMesh::FixupFaceOrientation()
// Before: points A - B - C - D with edge neighbour p - q - r - s
// After: points D - C - B - A, reversed neighbours are s - r - q - p, but the should be
// r q p s
for( size_t a = 0; a < fvc - 1; ++a )
for (size_t a = 0; a < fvc - 1; ++a)
std::swap(neighbour[fsi + a], neighbour[fsi + a + 1]);
}
faceDone[farthestIndex] = true;
@ -334,21 +318,19 @@ void TempMesh::FixupFaceOrientation()
todo.push_back(farthestIndex);
// go over its neighbour faces recursively and adapt their winding order to match the farthest face
while( !todo.empty() )
{
while (!todo.empty()) {
size_t tdf = todo.back();
size_t vsi = faceStartIndices[tdf], vc = mVertcnt[tdf];
todo.pop_back();
// check its neighbours
for( size_t a = 0; a < vc; ++a )
{
for (size_t a = 0; a < vc; ++a) {
// ignore neighbours if we already checked them
size_t nbi = neighbour[vsi + a];
if( nbi == SIZE_MAX || faceDone[nbi] )
if (nbi == SIZE_MAX || faceDone[nbi])
continue;
const IfcVector3& vp = mVerts[vsi + a];
const IfcVector3 &vp = mVerts[vsi + a];
size_t nbvsi = faceStartIndices[nbi], nbvc = mVertcnt[nbi];
std::vector<IfcVector3>::iterator it = std::find_if(mVerts.begin() + nbvsi, mVerts.begin() + nbvsi + nbvc, FindVector(vp));
ai_assert(it != mVerts.begin() + nbvsi + nbvc);
@ -358,8 +340,7 @@ void TempMesh::FixupFaceOrientation()
// to reverse the neighbour
nb_vidx = (nb_vidx + 1) % nbvc;
size_t oursideidx = (a + 1) % vc;
if( FuzzyVectorCompare(1e-6)(mVerts[vsi + oursideidx], mVerts[nbvsi + nb_vidx]) )
{
if (FuzzyVectorCompare(1e-6)(mVerts[vsi + oursideidx], mVerts[nbvsi + nb_vidx])) {
std::reverse(mVerts.begin() + nbvsi, mVerts.begin() + nbvsi + nbvc);
std::reverse(neighbour.begin() + nbvsi, neighbour.begin() + nbvsi + nbvc);
for (size_t aa = 0; aa < nbvc - 1; ++aa) {
@ -381,17 +362,16 @@ void TempMesh::FixupFaceOrientation()
void TempMesh::RemoveAdjacentDuplicates() {
bool drop = false;
std::vector<IfcVector3>::iterator base = mVerts.begin();
for(unsigned int& cnt : mVertcnt) {
if (cnt < 2){
for (unsigned int &cnt : mVertcnt) {
if (cnt < 2) {
base += cnt;
continue;
}
IfcVector3 vmin,vmax;
ArrayBounds(&*base, cnt ,vmin,vmax);
IfcVector3 vmin, vmax;
ArrayBounds(&*base, cnt, vmin, vmax);
const IfcFloat epsilon = (vmax-vmin).SquareLength() / static_cast<IfcFloat>(1e9);
const IfcFloat epsilon = (vmax - vmin).SquareLength() / static_cast<IfcFloat>(1e9);
//const IfcFloat dotepsilon = 1e-9;
//// look for vertices that lie directly on the line between their predecessor and their
@ -419,153 +399,127 @@ void TempMesh::RemoveAdjacentDuplicates() {
// drop any identical, adjacent vertices. this pass will collect the dropouts
// of the previous pass as a side-effect.
FuzzyVectorCompare fz(epsilon);
std::vector<IfcVector3>::iterator end = base+cnt, e = std::unique( base, end, fz );
std::vector<IfcVector3>::iterator end = base + cnt, e = std::unique(base, end, fz);
if (e != end) {
cnt -= static_cast<unsigned int>(std::distance(e, end));
mVerts.erase(e,end);
mVerts.erase(e, end);
drop = true;
}
// check front and back vertices for this polygon
if (cnt > 1 && fz(*base,*(base+cnt-1))) {
mVerts.erase(base+ --cnt);
if (cnt > 1 && fz(*base, *(base + cnt - 1))) {
mVerts.erase(base + --cnt);
drop = true;
}
// removing adjacent duplicates shouldn't erase everything :-)
ai_assert(cnt>0);
ai_assert(cnt > 0);
base += cnt;
}
if(drop) {
if (drop) {
IFCImporter::LogVerboseDebug("removing duplicate vertices");
}
}
// ------------------------------------------------------------------------------------------------
void TempMesh::Swap(TempMesh& other)
{
void TempMesh::Swap(TempMesh &other) {
mVertcnt.swap(other.mVertcnt);
mVerts.swap(other.mVerts);
}
// ------------------------------------------------------------------------------------------------
bool IsTrue(const ::Assimp::STEP::EXPRESS::BOOLEAN& in)
{
bool IsTrue(const ::Assimp::STEP::EXPRESS::BOOLEAN &in) {
return (std::string)in == "TRUE" || (std::string)in == "T";
}
// ------------------------------------------------------------------------------------------------
IfcFloat ConvertSIPrefix(const std::string& prefix)
{
IfcFloat ConvertSIPrefix(const std::string &prefix) {
if (prefix == "EXA") {
return 1e18f;
}
else if (prefix == "PETA") {
} else if (prefix == "PETA") {
return 1e15f;
}
else if (prefix == "TERA") {
} else if (prefix == "TERA") {
return 1e12f;
}
else if (prefix == "GIGA") {
} else if (prefix == "GIGA") {
return 1e9f;
}
else if (prefix == "MEGA") {
} else if (prefix == "MEGA") {
return 1e6f;
}
else if (prefix == "KILO") {
} else if (prefix == "KILO") {
return 1e3f;
}
else if (prefix == "HECTO") {
} else if (prefix == "HECTO") {
return 1e2f;
}
else if (prefix == "DECA") {
} else if (prefix == "DECA") {
return 1e-0f;
}
else if (prefix == "DECI") {
} else if (prefix == "DECI") {
return 1e-1f;
}
else if (prefix == "CENTI") {
} else if (prefix == "CENTI") {
return 1e-2f;
}
else if (prefix == "MILLI") {
} else if (prefix == "MILLI") {
return 1e-3f;
}
else if (prefix == "MICRO") {
} else if (prefix == "MICRO") {
return 1e-6f;
}
else if (prefix == "NANO") {
} else if (prefix == "NANO") {
return 1e-9f;
}
else if (prefix == "PICO") {
} else if (prefix == "PICO") {
return 1e-12f;
}
else if (prefix == "FEMTO") {
} else if (prefix == "FEMTO") {
return 1e-15f;
}
else if (prefix == "ATTO") {
} else if (prefix == "ATTO") {
return 1e-18f;
}
else {
} else {
IFCImporter::LogError("Unrecognized SI prefix: " + prefix);
return 1;
}
}
// ------------------------------------------------------------------------------------------------
void ConvertColor(aiColor4D& out, const Schema_2x3::IfcColourRgb& in)
{
out.r = static_cast<float>( in.Red );
out.g = static_cast<float>( in.Green );
out.b = static_cast<float>( in.Blue );
out.a = static_cast<float>( 1.f );
void ConvertColor(aiColor4D &out, const Schema_2x3::IfcColourRgb &in) {
out.r = static_cast<float>(in.Red);
out.g = static_cast<float>(in.Green);
out.b = static_cast<float>(in.Blue);
out.a = static_cast<float>(1.f);
}
// ------------------------------------------------------------------------------------------------
void ConvertColor(aiColor4D& out, const Schema_2x3::IfcColourOrFactor& in,ConversionData& conv,const aiColor4D* base)
{
if (const ::Assimp::STEP::EXPRESS::REAL* const r = in.ToPtr<::Assimp::STEP::EXPRESS::REAL>()) {
void ConvertColor(aiColor4D &out, const Schema_2x3::IfcColourOrFactor &in, ConversionData &conv, const aiColor4D *base) {
if (const ::Assimp::STEP::EXPRESS::REAL *const r = in.ToPtr<::Assimp::STEP::EXPRESS::REAL>()) {
out.r = out.g = out.b = static_cast<float>(*r);
if(base) {
out.r *= static_cast<float>( base->r );
out.g *= static_cast<float>( base->g );
out.b *= static_cast<float>( base->b );
out.a = static_cast<float>( base->a );
}
else out.a = 1.0;
}
else if (const Schema_2x3::IfcColourRgb* const rgb = in.ResolveSelectPtr<Schema_2x3::IfcColourRgb>(conv.db)) {
ConvertColor(out,*rgb);
}
else {
if (base) {
out.r *= static_cast<float>(base->r);
out.g *= static_cast<float>(base->g);
out.b *= static_cast<float>(base->b);
out.a = static_cast<float>(base->a);
} else
out.a = 1.0;
} else if (const Schema_2x3::IfcColourRgb *const rgb = in.ResolveSelectPtr<Schema_2x3::IfcColourRgb>(conv.db)) {
ConvertColor(out, *rgb);
} else {
IFCImporter::LogWarn("skipping unknown IfcColourOrFactor entity");
}
}
// ------------------------------------------------------------------------------------------------
void ConvertCartesianPoint(IfcVector3& out, const Schema_2x3::IfcCartesianPoint& in)
{
void ConvertCartesianPoint(IfcVector3 &out, const Schema_2x3::IfcCartesianPoint &in) {
out = IfcVector3();
for(size_t i = 0; i < in.Coordinates.size(); ++i) {
for (size_t i = 0; i < in.Coordinates.size(); ++i) {
out[static_cast<unsigned int>(i)] = in.Coordinates[i];
}
}
// ------------------------------------------------------------------------------------------------
void ConvertVector(IfcVector3& out, const Schema_2x3::IfcVector& in)
{
ConvertDirection(out,in.Orientation);
void ConvertVector(IfcVector3 &out, const Schema_2x3::IfcVector &in) {
ConvertDirection(out, in.Orientation);
out *= in.Magnitude;
}
// ------------------------------------------------------------------------------------------------
void ConvertDirection(IfcVector3& out, const Schema_2x3::IfcDirection& in)
{
void ConvertDirection(IfcVector3 &out, const Schema_2x3::IfcDirection &in) {
out = IfcVector3();
for(size_t i = 0; i < in.DirectionRatios.size(); ++i) {
for (size_t i = 0; i < in.DirectionRatios.size(); ++i) {
out[static_cast<unsigned int>(i)] = in.DirectionRatios[i];
}
const IfcFloat len = out.Length();
if (len<1e-6) {
if (len < 1e-6) {
IFCImporter::LogWarn("direction vector magnitude too small, normalization would result in a division by zero");
return;
}
@ -573,8 +527,7 @@ void ConvertDirection(IfcVector3& out, const Schema_2x3::IfcDirection& in)
}
// ------------------------------------------------------------------------------------------------
void AssignMatrixAxes(IfcMatrix4& out, const IfcVector3& x, const IfcVector3& y, const IfcVector3& z)
{
void AssignMatrixAxes(IfcMatrix4 &out, const IfcVector3 &x, const IfcVector3 &y, const IfcVector3 &z) {
out.a1 = x.x;
out.b1 = x.y;
out.c1 = x.z;
@ -589,116 +542,105 @@ void AssignMatrixAxes(IfcMatrix4& out, const IfcVector3& x, const IfcVector3& y,
}
// ------------------------------------------------------------------------------------------------
void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement3D& in)
{
void ConvertAxisPlacement(IfcMatrix4 &out, const Schema_2x3::IfcAxis2Placement3D &in) {
IfcVector3 loc;
ConvertCartesianPoint(loc,in.Location);
ConvertCartesianPoint(loc, in.Location);
IfcVector3 z(0.f,0.f,1.f),r(1.f,0.f,0.f),x;
IfcVector3 z(0.f, 0.f, 1.f), r(1.f, 0.f, 0.f), x;
if (in.Axis) {
ConvertDirection(z,*in.Axis.Get());
ConvertDirection(z, *in.Axis.Get());
}
if (in.RefDirection) {
ConvertDirection(r,*in.RefDirection.Get());
ConvertDirection(r, *in.RefDirection.Get());
}
IfcVector3 v = r.Normalize();
IfcVector3 tmpx = z * (v*z);
IfcVector3 tmpx = z * (v * z);
x = (v-tmpx).Normalize();
IfcVector3 y = (z^x);
x = (v - tmpx).Normalize();
IfcVector3 y = (z ^ x);
IfcMatrix4::Translation(loc,out);
AssignMatrixAxes(out,x,y,z);
IfcMatrix4::Translation(loc, out);
AssignMatrixAxes(out, x, y, z);
}
// ------------------------------------------------------------------------------------------------
void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement2D& in)
{
void ConvertAxisPlacement(IfcMatrix4 &out, const Schema_2x3::IfcAxis2Placement2D &in) {
IfcVector3 loc;
ConvertCartesianPoint(loc,in.Location);
ConvertCartesianPoint(loc, in.Location);
IfcVector3 x(1.f,0.f,0.f);
IfcVector3 x(1.f, 0.f, 0.f);
if (in.RefDirection) {
ConvertDirection(x,*in.RefDirection.Get());
ConvertDirection(x, *in.RefDirection.Get());
}
const IfcVector3 y = IfcVector3(x.y,-x.x,0.f);
const IfcVector3 y = IfcVector3(x.y, -x.x, 0.f);
IfcMatrix4::Translation(loc,out);
AssignMatrixAxes(out,x,y,IfcVector3(0.f,0.f,1.f));
IfcMatrix4::Translation(loc, out);
AssignMatrixAxes(out, x, y, IfcVector3(0.f, 0.f, 1.f));
}
// ------------------------------------------------------------------------------------------------
void ConvertAxisPlacement(IfcVector3& axis, IfcVector3& pos, const Schema_2x3::IfcAxis1Placement& in)
{
ConvertCartesianPoint(pos,in.Location);
void ConvertAxisPlacement(IfcVector3 &axis, IfcVector3 &pos, const Schema_2x3::IfcAxis1Placement &in) {
ConvertCartesianPoint(pos, in.Location);
if (in.Axis) {
ConvertDirection(axis,in.Axis.Get());
}
else {
axis = IfcVector3(0.f,0.f,1.f);
ConvertDirection(axis, in.Axis.Get());
} else {
axis = IfcVector3(0.f, 0.f, 1.f);
}
}
// ------------------------------------------------------------------------------------------------
void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement& in, ConversionData& conv)
{
if(const Schema_2x3::IfcAxis2Placement3D* pl3 = in.ResolveSelectPtr<Schema_2x3::IfcAxis2Placement3D>(conv.db)) {
ConvertAxisPlacement(out,*pl3);
}
else if(const Schema_2x3::IfcAxis2Placement2D* pl2 = in.ResolveSelectPtr<Schema_2x3::IfcAxis2Placement2D>(conv.db)) {
ConvertAxisPlacement(out,*pl2);
}
else {
void ConvertAxisPlacement(IfcMatrix4 &out, const Schema_2x3::IfcAxis2Placement &in, ConversionData &conv) {
if (const Schema_2x3::IfcAxis2Placement3D *pl3 = in.ResolveSelectPtr<Schema_2x3::IfcAxis2Placement3D>(conv.db)) {
ConvertAxisPlacement(out, *pl3);
} else if (const Schema_2x3::IfcAxis2Placement2D *pl2 = in.ResolveSelectPtr<Schema_2x3::IfcAxis2Placement2D>(conv.db)) {
ConvertAxisPlacement(out, *pl2);
} else {
IFCImporter::LogWarn("skipping unknown IfcAxis2Placement entity");
}
}
// ------------------------------------------------------------------------------------------------
void ConvertTransformOperator(IfcMatrix4& out, const Schema_2x3::IfcCartesianTransformationOperator& op)
{
void ConvertTransformOperator(IfcMatrix4 &out, const Schema_2x3::IfcCartesianTransformationOperator &op) {
IfcVector3 loc;
ConvertCartesianPoint(loc,op.LocalOrigin);
ConvertCartesianPoint(loc, op.LocalOrigin);
IfcVector3 x(1.f,0.f,0.f),y(0.f,1.f,0.f),z(0.f,0.f,1.f);
IfcVector3 x(1.f, 0.f, 0.f), y(0.f, 1.f, 0.f), z(0.f, 0.f, 1.f);
if (op.Axis1) {
ConvertDirection(x,*op.Axis1.Get());
ConvertDirection(x, *op.Axis1.Get());
}
if (op.Axis2) {
ConvertDirection(y,*op.Axis2.Get());
ConvertDirection(y, *op.Axis2.Get());
}
if (const Schema_2x3::IfcCartesianTransformationOperator3D* op2 = op.ToPtr<Schema_2x3::IfcCartesianTransformationOperator3D>()) {
if(op2->Axis3) {
ConvertDirection(z,*op2->Axis3.Get());
if (const Schema_2x3::IfcCartesianTransformationOperator3D *op2 = op.ToPtr<Schema_2x3::IfcCartesianTransformationOperator3D>()) {
if (op2->Axis3) {
ConvertDirection(z, *op2->Axis3.Get());
}
}
IfcMatrix4 locm;
IfcMatrix4::Translation(loc,locm);
AssignMatrixAxes(out,x,y,z);
IfcMatrix4::Translation(loc, locm);
AssignMatrixAxes(out, x, y, z);
IfcVector3 vscale;
if (const Schema_2x3::IfcCartesianTransformationOperator3DnonUniform* nuni = op.ToPtr<Schema_2x3::IfcCartesianTransformationOperator3DnonUniform>()) {
vscale.x = nuni->Scale?op.Scale.Get():1.f;
vscale.y = nuni->Scale2?nuni->Scale2.Get():1.f;
vscale.z = nuni->Scale3?nuni->Scale3.Get():1.f;
}
else {
const IfcFloat sc = op.Scale?op.Scale.Get():1.f;
vscale = IfcVector3(sc,sc,sc);
if (const Schema_2x3::IfcCartesianTransformationOperator3DnonUniform *nuni = op.ToPtr<Schema_2x3::IfcCartesianTransformationOperator3DnonUniform>()) {
vscale.x = nuni->Scale ? op.Scale.Get() : 1.f;
vscale.y = nuni->Scale2 ? nuni->Scale2.Get() : 1.f;
vscale.z = nuni->Scale3 ? nuni->Scale3.Get() : 1.f;
} else {
const IfcFloat sc = op.Scale ? op.Scale.Get() : 1.f;
vscale = IfcVector3(sc, sc, sc);
}
IfcMatrix4 s;
IfcMatrix4::Scaling(vscale,s);
IfcMatrix4::Scaling(vscale, s);
out = locm * out * s;
}
} // ! IFC
} // ! Assimp
} // namespace IFC
} // namespace Assimp
#endif

View File

@ -43,9 +43,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @brief Implementation of the CPP-API class #Importer
*/
#include <assimp/version.h>
#include <assimp/config.h>
#include <assimp/importerdesc.h>
#include <assimp/version.h>
// ------------------------------------------------------------------------------------------------
/* Uncomment this line to prevent Assimp from catching unknown exceptions.
@ -56,35 +56,36 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// ------------------------------------------------------------------------------------------------
#ifndef ASSIMP_BUILD_DEBUG
# define ASSIMP_CATCH_GLOBAL_EXCEPTIONS
#define ASSIMP_CATCH_GLOBAL_EXCEPTIONS
#endif
// ------------------------------------------------------------------------------------------------
// Internal headers
// ------------------------------------------------------------------------------------------------
#include "Common/Importer.h"
#include "Common/BaseProcess.h"
#include "Common/DefaultProgressHandler.h"
#include "PostProcessing/ProcessHelper.h"
#include "Common/Importer.h"
#include "Common/ScenePreprocessor.h"
#include "Common/ScenePrivate.h"
#include "PostProcessing/ProcessHelper.h"
#include <assimp/BaseImporter.h>
#include <assimp/Exceptional.h>
#include <assimp/GenericProperty.h>
#include <assimp/MemoryIOWrapper.h>
#include <assimp/Profiler.h>
#include <assimp/TinyFormatter.h>
#include <assimp/Exceptional.h>
#include <assimp/Profiler.h>
#include <assimp/commonMetaData.h>
#include <set>
#include <memory>
#include <cctype>
#include <memory>
#include <set>
#include <assimp/DefaultIOStream.h>
#include <assimp/DefaultIOSystem.h>
// clang-format off
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
# include "PostProcessing/ValidateDataStructure.h"
#endif
@ -94,13 +95,14 @@ using namespace Assimp::Formatter;
namespace Assimp {
// ImporterRegistry.cpp
void GetImporterInstanceList(std::vector< BaseImporter* >& out);
void DeleteImporterInstanceList(std::vector< BaseImporter* >& out);
void GetImporterInstanceList(std::vector<BaseImporter *> &out);
void DeleteImporterInstanceList(std::vector<BaseImporter *> &out);
// PostStepRegistry.cpp
void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out);
}
void GetPostProcessingStepInstanceList(std::vector<BaseProcess *> &out);
} // namespace Assimp
// clang-format on
using namespace Assimp;
using namespace Assimp::Intern;
@ -110,43 +112,42 @@ using namespace Assimp::Intern;
// utilize our DLL heap.
// See http://www.gotw.ca/publications/mill15.htm
// ------------------------------------------------------------------------------------------------
void* AllocateFromAssimpHeap::operator new ( size_t num_bytes) {
void *AllocateFromAssimpHeap::operator new(size_t num_bytes) {
return ::operator new(num_bytes);
}
void* AllocateFromAssimpHeap::operator new ( size_t num_bytes, const std::nothrow_t& ) throw() {
void *AllocateFromAssimpHeap::operator new(size_t num_bytes, const std::nothrow_t &) throw() {
try {
return AllocateFromAssimpHeap::operator new( num_bytes );
}
catch( ... ) {
return AllocateFromAssimpHeap::operator new(num_bytes);
} catch (...) {
return nullptr;
}
}
void AllocateFromAssimpHeap::operator delete ( void* data) {
void AllocateFromAssimpHeap::operator delete(void *data) {
return ::operator delete(data);
}
void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes) {
void *AllocateFromAssimpHeap::operator new[](size_t num_bytes) {
return ::operator new[](num_bytes);
}
void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes, const std::nothrow_t& ) throw() {
void *AllocateFromAssimpHeap::operator new[](size_t num_bytes, const std::nothrow_t &) throw() {
try {
return AllocateFromAssimpHeap::operator new[]( num_bytes );
} catch( ... ) {
return AllocateFromAssimpHeap::operator new[](num_bytes);
} catch (...) {
return nullptr;
}
}
void AllocateFromAssimpHeap::operator delete[] ( void* data) {
void AllocateFromAssimpHeap::operator delete[](void *data) {
return ::operator delete[](data);
}
// ------------------------------------------------------------------------------------------------
// Importer constructor.
Importer::Importer()
: pimpl( new ImporterPimpl ) {
Importer::Importer() :
pimpl(new ImporterPimpl) {
pimpl->mScene = nullptr;
pimpl->mErrorString = "";
@ -163,7 +164,7 @@ Importer::Importer()
// Allocate a SharedPostProcessInfo object and store pointers to it in all post-process steps in the list.
pimpl->mPPShared = new SharedPostProcessInfo();
for (std::vector<BaseProcess*>::iterator it = pimpl->mPostProcessingSteps.begin();
for (std::vector<BaseProcess *>::iterator it = pimpl->mPostProcessingSteps.begin();
it != pimpl->mPostProcessingSteps.end();
++it) {
@ -178,7 +179,7 @@ Importer::~Importer() {
DeleteImporterInstanceList(pimpl->mImporter);
// Delete all post-processing plug-ins
for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); ++a ) {
for (unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); ++a) {
delete pimpl->mPostProcessingSteps[a];
}
@ -198,8 +199,8 @@ Importer::~Importer() {
// ------------------------------------------------------------------------------------------------
// Register a custom post-processing step
aiReturn Importer::RegisterPPStep(BaseProcess* pImp) {
ai_assert( nullptr != pImp );
aiReturn Importer::RegisterPPStep(BaseProcess *pImp) {
ai_assert(nullptr != pImp);
ASSIMP_BEGIN_EXCEPTION_REGION();
@ -212,7 +213,7 @@ aiReturn Importer::RegisterPPStep(BaseProcess* pImp) {
// ------------------------------------------------------------------------------------------------
// Register a custom loader plugin
aiReturn Importer::RegisterLoader(BaseImporter* pImp) {
aiReturn Importer::RegisterLoader(BaseImporter *pImp) {
ai_assert(nullptr != pImp);
ASSIMP_BEGIN_EXCEPTION_REGION();
@ -227,7 +228,7 @@ aiReturn Importer::RegisterLoader(BaseImporter* pImp) {
std::string baked;
pImp->GetExtensionList(st);
for(std::set<std::string>::const_iterator it = st.begin(); it != st.end(); ++it) {
for (std::set<std::string>::const_iterator it = st.begin(); it != st.end(); ++it) {
#ifdef ASSIMP_BUILD_DEBUG
if (IsExtensionSupported(*it)) {
@ -247,15 +248,15 @@ aiReturn Importer::RegisterLoader(BaseImporter* pImp) {
// ------------------------------------------------------------------------------------------------
// Unregister a custom loader plugin
aiReturn Importer::UnregisterLoader(BaseImporter* pImp) {
if(!pImp) {
aiReturn Importer::UnregisterLoader(BaseImporter *pImp) {
if (!pImp) {
// unregistering a nullptr importer is no problem for us ... really!
return AI_SUCCESS;
}
ASSIMP_BEGIN_EXCEPTION_REGION();
std::vector<BaseImporter*>::iterator it = std::find(pimpl->mImporter.begin(),
pimpl->mImporter.end(),pImp);
std::vector<BaseImporter *>::iterator it = std::find(pimpl->mImporter.begin(),
pimpl->mImporter.end(), pImp);
if (it != pimpl->mImporter.end()) {
pimpl->mImporter.erase(it);
@ -270,15 +271,15 @@ aiReturn Importer::UnregisterLoader(BaseImporter* pImp) {
// ------------------------------------------------------------------------------------------------
// Unregister a custom loader plugin
aiReturn Importer::UnregisterPPStep(BaseProcess* pImp) {
if(!pImp) {
aiReturn Importer::UnregisterPPStep(BaseProcess *pImp) {
if (!pImp) {
// unregistering a nullptr ppstep is no problem for us ... really!
return AI_SUCCESS;
}
ASSIMP_BEGIN_EXCEPTION_REGION();
std::vector<BaseProcess*>::iterator it = std::find(pimpl->mPostProcessingSteps.begin(),
pimpl->mPostProcessingSteps.end(),pImp);
std::vector<BaseProcess *>::iterator it = std::find(pimpl->mPostProcessingSteps.begin(),
pimpl->mPostProcessingSteps.end(), pImp);
if (it != pimpl->mPostProcessingSteps.end()) {
pimpl->mPostProcessingSteps.erase(it);
@ -293,7 +294,7 @@ aiReturn Importer::UnregisterPPStep(BaseProcess* pImp) {
// ------------------------------------------------------------------------------------------------
// Supplies a custom IO handler to the importer to open and access files.
void Importer::SetIOHandler( IOSystem* pIOHandler) {
void Importer::SetIOHandler(IOSystem *pIOHandler) {
ai_assert(nullptr != pimpl);
ASSIMP_BEGIN_EXCEPTION_REGION();
@ -312,7 +313,7 @@ void Importer::SetIOHandler( IOSystem* pIOHandler) {
// ------------------------------------------------------------------------------------------------
// Get the currently set IO handler
IOSystem* Importer::GetIOHandler() const {
IOSystem *Importer::GetIOHandler() const {
ai_assert(nullptr != pimpl);
return pimpl->mIOHandler;
@ -328,7 +329,7 @@ bool Importer::IsDefaultIOHandler() const {
// ------------------------------------------------------------------------------------------------
// Supplies a custom progress handler to get regular callbacks during importing
void Importer::SetProgressHandler ( ProgressHandler* pHandler ) {
void Importer::SetProgressHandler(ProgressHandler *pHandler) {
ai_assert(nullptr != pimpl);
ASSIMP_BEGIN_EXCEPTION_REGION();
@ -348,7 +349,7 @@ void Importer::SetProgressHandler ( ProgressHandler* pHandler ) {
// ------------------------------------------------------------------------------------------------
// Get the currently set progress handler
ProgressHandler* Importer::GetProgressHandler() const {
ProgressHandler *Importer::GetProgressHandler() const {
ai_assert(nullptr != pimpl);
return pimpl->mProgressHandler;
@ -378,7 +379,7 @@ bool _ValidateFlags(unsigned int pFlags) {
// ------------------------------------------------------------------------------------------------
// Free the current scene
void Importer::FreeScene( ) {
void Importer::FreeScene() {
ai_assert(nullptr != pimpl);
ASSIMP_BEGIN_EXCEPTION_REGION();
@ -393,14 +394,14 @@ void Importer::FreeScene( ) {
// ------------------------------------------------------------------------------------------------
// Get the current error string, if any
const char* Importer::GetErrorString() const {
const char *Importer::GetErrorString() const {
ai_assert(nullptr != pimpl);
// Must remain valid as long as ReadFile() or FreeFile() are not called
return pimpl->mErrorString.c_str();
}
const std::exception_ptr& Importer::GetException() const {
const std::exception_ptr &Importer::GetException() const {
ai_assert(nullptr != pimpl);
// Must remain valid as long as ReadFile() or FreeFile() are not called
@ -417,7 +418,7 @@ void Importer::SetExtraVerbose(bool bDo) {
// ------------------------------------------------------------------------------------------------
// Get the current scene
const aiScene* Importer::GetScene() const {
const aiScene *Importer::GetScene() const {
ai_assert(nullptr != pimpl);
return pimpl->mScene;
@ -425,17 +426,17 @@ const aiScene* Importer::GetScene() const {
// ------------------------------------------------------------------------------------------------
// Orphan the current scene and return it.
aiScene* Importer::GetOrphanedScene() {
aiScene *Importer::GetOrphanedScene() {
ai_assert(nullptr != pimpl);
aiScene* s = pimpl->mScene;
aiScene *s = pimpl->mScene;
ASSIMP_BEGIN_EXCEPTION_REGION();
pimpl->mScene = nullptr;
pimpl->mErrorString = ""; // reset error string
pimpl->mException = std::exception_ptr();
ASSIMP_END_EXCEPTION_REGION(aiScene*);
ASSIMP_END_EXCEPTION_REGION(aiScene *);
return s;
}
@ -445,7 +446,7 @@ aiScene* Importer::GetOrphanedScene() {
bool Importer::ValidateFlags(unsigned int pFlags) const {
ASSIMP_BEGIN_EXCEPTION_REGION();
// run basic checks for mutually exclusive flags
if(!_ValidateFlags(pFlags)) {
if (!_ValidateFlags(pFlags)) {
return false;
}
@ -459,13 +460,13 @@ bool Importer::ValidateFlags(unsigned int pFlags) const {
// Now iterate through all bits which are set in the flags and check whether we find at least
// one pp plugin which handles it.
for (unsigned int mask = 1; mask < (1u << (sizeof(unsigned int)*8-1));mask <<= 1) {
for (unsigned int mask = 1; mask < (1u << (sizeof(unsigned int) * 8 - 1)); mask <<= 1) {
if (pFlags & mask) {
bool have = false;
for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
if (pimpl->mPostProcessingSteps[a]-> IsActive(mask) ) {
for (unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
if (pimpl->mPostProcessingSteps[a]->IsActive(mask)) {
have = true;
break;
@ -481,10 +482,10 @@ bool Importer::ValidateFlags(unsigned int pFlags) const {
}
// ------------------------------------------------------------------------------------------------
const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
const aiScene *Importer::ReadFileFromMemory(const void *pBuffer,
size_t pLength,
unsigned int pFlags,
const char* pHint /*= ""*/) {
const char *pHint /*= ""*/) {
ai_assert(nullptr != pimpl);
ASSIMP_BEGIN_EXCEPTION_REGION();
@ -492,31 +493,31 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
pHint = "";
}
if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint ) {
if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint) {
pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()";
return nullptr;
}
// prevent deletion of the previous IOHandler
IOSystem* io = pimpl->mIOHandler;
IOSystem *io = pimpl->mIOHandler;
pimpl->mIOHandler = nullptr;
SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength,io));
SetIOHandler(new MemoryIOSystem((const uint8_t *)pBuffer, pLength, io));
// read the file and recover the previous IOSystem
static const size_t BufSize(Importer::MaxLenHint + 28);
char fbuff[BufSize];
ai_snprintf(fbuff, BufSize, "%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint);
ai_snprintf(fbuff, BufSize, "%s.%s", AI_MEMORYIO_MAGIC_FILENAME, pHint);
ReadFile(fbuff,pFlags);
ReadFile(fbuff, pFlags);
SetIOHandler(io);
ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString, pimpl->mException);
ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene *, pimpl->mErrorString, pimpl->mException);
return pimpl->mScene;
}
// ------------------------------------------------------------------------------------------------
void WriteLogOpening(const std::string& file) {
void WriteLogOpening(const std::string &file) {
ASSIMP_LOG_INFO_F("Load ", file);
@ -577,7 +578,7 @@ void WriteLogOpening(const std::string& file) {
// ------------------------------------------------------------------------------------------------
// Reads the given file and returns its contents if successful.
const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
const aiScene *Importer::ReadFile(const char *_pFile, unsigned int pFlags) {
ai_assert(nullptr != pimpl);
ASSIMP_BEGIN_EXCEPTION_REGION();
@ -604,7 +605,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
}
// First check if the file is accessible at all
if( !pimpl->mIOHandler->Exists( pFile)) {
if (!pimpl->mIOHandler->Exists(pFile)) {
pimpl->mErrorString = "Unable to open file \"" + pFile + "\".";
ASSIMP_LOG_ERROR(pimpl->mErrorString);
@ -617,11 +618,11 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
}
// Find an worker class which can handle the file
BaseImporter* imp = nullptr;
BaseImporter *imp = nullptr;
SetPropertyInteger("importerIndex", -1);
for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) {
for (unsigned int a = 0; a < pimpl->mImporter.size(); a++) {
if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, false)) {
if (pimpl->mImporter[a]->CanRead(pFile, pimpl->mIOHandler, false)) {
imp = pimpl->mImporter[a];
SetPropertyInteger("importerIndex", a);
break;
@ -633,8 +634,8 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
const std::string::size_type s = pFile.find_last_of('.');
if (s != std::string::npos) {
ASSIMP_LOG_INFO("File extension not known, trying signature-based detection");
for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) {
if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) {
for (unsigned int a = 0; a < pimpl->mImporter.size(); a++) {
if (pimpl->mImporter[a]->CanRead(pFile, pimpl->mIOHandler, true)) {
imp = pimpl->mImporter[a];
SetPropertyInteger("importerIndex", a);
break;
@ -642,7 +643,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
}
}
// Put a proper error message if no suitable importer was found
if( !imp) {
if (!imp) {
pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\".";
ASSIMP_LOG_ERROR(pimpl->mErrorString);
return nullptr;
@ -650,29 +651,28 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
}
// Get file size for progress handler
IOStream * fileIO = pimpl->mIOHandler->Open( pFile );
IOStream *fileIO = pimpl->mIOHandler->Open(pFile);
uint32_t fileSize = 0;
if (fileIO)
{
if (fileIO) {
fileSize = static_cast<uint32_t>(fileIO->FileSize());
pimpl->mIOHandler->Close( fileIO );
pimpl->mIOHandler->Close(fileIO);
}
// Dispatch the reading to the worker class for this format
const aiImporterDesc *desc( imp->GetInfo() );
std::string ext( "unknown" );
if ( nullptr != desc ) {
const aiImporterDesc *desc(imp->GetInfo());
std::string ext("unknown");
if (nullptr != desc) {
ext = desc->mName;
}
ASSIMP_LOG_INFO("Found a matching importer for this file format: " + ext + "." );
pimpl->mProgressHandler->UpdateFileRead( 0, fileSize );
ASSIMP_LOG_INFO("Found a matching importer for this file format: " + ext + ".");
pimpl->mProgressHandler->UpdateFileRead(0, fileSize);
if (profiler) {
profiler->BeginRegion("import");
}
pimpl->mScene = imp->ReadFile( this, pFile, pimpl->mIOHandler);
pimpl->mProgressHandler->UpdateFileRead( fileSize, fileSize );
pimpl->mScene = imp->ReadFile(this, pFile, pimpl->mIOHandler);
pimpl->mProgressHandler->UpdateFileRead(fileSize, fileSize);
if (profiler) {
profiler->EndRegion("import");
@ -681,7 +681,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
SetPropertyString("sourceFilePath", pFile);
// If successful, apply all active post processing steps to the imported data
if( pimpl->mScene) {
if (pimpl->mScene) {
if (!pimpl->mScene->mMetaData || !pimpl->mScene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT)) {
if (!pimpl->mScene->mMetaData) {
pimpl->mScene->mMetaData = new aiMetadata;
@ -693,7 +693,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
// The ValidateDS process is an exception. It is executed first, even before ScenePreprocessor is called.
if (pFlags & aiProcess_ValidateDataStructure) {
ValidateDSProcess ds;
ds.ExecuteOnScene (this);
ds.ExecuteOnScene(this);
if (!pimpl->mScene) {
return nullptr;
}
@ -716,7 +716,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
ApplyPostProcessing(pFlags & (~aiProcess_ValidateDataStructure));
}
// if failed, extract the error string
else if( !pimpl->mScene) {
else if (!pimpl->mScene) {
pimpl->mErrorString = imp->GetErrorText();
pimpl->mException = imp->GetException();
}
@ -732,26 +732,26 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
catch (std::exception &e) {
#if (defined _MSC_VER) && (defined _CPPRTTI)
// if we have RTTI get the full name of the exception that occurred
pimpl->mErrorString = std::string(typeid( e ).name()) + ": " + e.what();
pimpl->mErrorString = std::string(typeid(e).name()) + ": " + e.what();
#else
pimpl->mErrorString = std::string("std::exception: ") + e.what();
#endif
ASSIMP_LOG_ERROR(pimpl->mErrorString);
delete pimpl->mScene; pimpl->mScene = nullptr;
delete pimpl->mScene;
pimpl->mScene = nullptr;
}
#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
// either successful or failure - the pointer expresses it anyways
ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString, pimpl->mException);
ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene *, pimpl->mErrorString, pimpl->mException);
return pimpl->mScene;
}
// ------------------------------------------------------------------------------------------------
// Apply post-processing to the currently bound scene
const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) {
const aiScene *Importer::ApplyPostProcessing(unsigned int pFlags) {
ai_assert(nullptr != pimpl);
ASSIMP_BEGIN_EXCEPTION_REGION();
@ -774,15 +774,14 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) {
// list of post-processing steps, so we need to call it manually.
if (pFlags & aiProcess_ValidateDataStructure) {
ValidateDSProcess ds;
ds.ExecuteOnScene (this);
ds.ExecuteOnScene(this);
if (!pimpl->mScene) {
return nullptr;
}
}
#endif // no validation
#ifdef ASSIMP_BUILD_DEBUG
if (pimpl->bExtraVerbose)
{
if (pimpl->bExtraVerbose) {
#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
ASSIMP_LOG_ERROR("Verbose Import is not available due to build settings");
#endif // no validation
@ -795,21 +794,21 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) {
#endif // ! DEBUG
std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME, 0) ? new Profiler() : nullptr);
for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
BaseProcess* process = pimpl->mPostProcessingSteps[a];
pimpl->mProgressHandler->UpdatePostProcess(static_cast<int>(a), static_cast<int>(pimpl->mPostProcessingSteps.size()) );
if( process->IsActive( pFlags)) {
for (unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
BaseProcess *process = pimpl->mPostProcessingSteps[a];
pimpl->mProgressHandler->UpdatePostProcess(static_cast<int>(a), static_cast<int>(pimpl->mPostProcessingSteps.size()));
if (process->IsActive(pFlags)) {
if (profiler) {
profiler->BeginRegion("postprocess");
}
process->ExecuteOnScene ( this );
process->ExecuteOnScene(this);
if (profiler) {
profiler->EndRegion("postprocess");
}
}
if( !pimpl->mScene) {
if (!pimpl->mScene) {
break;
}
#ifdef ASSIMP_BUILD_DEBUG
@ -823,19 +822,19 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) {
ASSIMP_LOG_DEBUG("Verbose Import: re-validating data structures");
ValidateDSProcess ds;
ds.ExecuteOnScene (this);
if( !pimpl->mScene) {
ds.ExecuteOnScene(this);
if (!pimpl->mScene) {
ASSIMP_LOG_ERROR("Verbose Import: failed to re-validate data structures");
break;
}
}
#endif // ! DEBUG
}
pimpl->mProgressHandler->UpdatePostProcess( static_cast<int>(pimpl->mPostProcessingSteps.size()),
static_cast<int>(pimpl->mPostProcessingSteps.size()) );
pimpl->mProgressHandler->UpdatePostProcess(static_cast<int>(pimpl->mPostProcessingSteps.size()),
static_cast<int>(pimpl->mPostProcessingSteps.size()));
// update private scene flags
if( pimpl->mScene ) {
if (pimpl->mScene) {
ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags;
}
@ -843,19 +842,19 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) {
pimpl->mPPShared->Clean();
ASSIMP_LOG_INFO("Leaving post processing pipeline");
ASSIMP_END_EXCEPTION_REGION(const aiScene*);
ASSIMP_END_EXCEPTION_REGION(const aiScene *);
return pimpl->mScene;
}
// ------------------------------------------------------------------------------------------------
const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess, bool requestValidation ) {
const aiScene *Importer::ApplyCustomizedPostProcessing(BaseProcess *rootProcess, bool requestValidation) {
ai_assert(nullptr != pimpl);
ASSIMP_BEGIN_EXCEPTION_REGION();
// Return immediately if no scene is active
if ( nullptr == pimpl->mScene ) {
if (nullptr == pimpl->mScene) {
return nullptr;
}
@ -865,68 +864,66 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess
}
// In debug builds: run basic flag validation
ASSIMP_LOG_INFO( "Entering customized post processing pipeline" );
ASSIMP_LOG_INFO("Entering customized post processing pipeline");
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
// The ValidateDS process plays an exceptional role. It isn't contained in the global
// list of post-processing steps, so we need to call it manually.
if ( requestValidation )
{
if (requestValidation) {
ValidateDSProcess ds;
ds.ExecuteOnScene( this );
if ( !pimpl->mScene ) {
ds.ExecuteOnScene(this);
if (!pimpl->mScene) {
return nullptr;
}
}
#endif // no validation
#ifdef ASSIMP_BUILD_DEBUG
if ( pimpl->bExtraVerbose )
{
if (pimpl->bExtraVerbose) {
#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
ASSIMP_LOG_ERROR( "Verbose Import is not available due to build settings" );
ASSIMP_LOG_ERROR("Verbose Import is not available due to build settings");
#endif // no validation
}
#else
if ( pimpl->bExtraVerbose ) {
ASSIMP_LOG_WARN( "Not a debug build, ignoring extra verbose setting" );
if (pimpl->bExtraVerbose) {
ASSIMP_LOG_WARN("Not a debug build, ignoring extra verbose setting");
}
#endif // ! DEBUG
std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME, 0) ? new Profiler() : nullptr);
if ( profiler ) {
profiler->BeginRegion( "postprocess" );
if (profiler) {
profiler->BeginRegion("postprocess");
}
rootProcess->ExecuteOnScene( this );
rootProcess->ExecuteOnScene(this);
if ( profiler ) {
profiler->EndRegion( "postprocess" );
if (profiler) {
profiler->EndRegion("postprocess");
}
// If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step
if ( pimpl->bExtraVerbose || requestValidation ) {
ASSIMP_LOG_DEBUG( "Verbose Import: revalidating data structures" );
if (pimpl->bExtraVerbose || requestValidation) {
ASSIMP_LOG_DEBUG("Verbose Import: revalidating data structures");
ValidateDSProcess ds;
ds.ExecuteOnScene( this );
if ( !pimpl->mScene ) {
ASSIMP_LOG_ERROR( "Verbose Import: failed to revalidate data structures" );
ds.ExecuteOnScene(this);
if (!pimpl->mScene) {
ASSIMP_LOG_ERROR("Verbose Import: failed to revalidate data structures");
}
}
// clear any data allocated by post-process steps
pimpl->mPPShared->Clean();
ASSIMP_LOG_INFO( "Leaving customized post processing pipeline" );
ASSIMP_LOG_INFO("Leaving customized post processing pipeline");
ASSIMP_END_EXCEPTION_REGION( const aiScene* );
ASSIMP_END_EXCEPTION_REGION(const aiScene *);
return pimpl->mScene;
}
// ------------------------------------------------------------------------------------------------
// Helper function to check whether an extension is supported by ASSIMP
bool Importer::IsExtensionSupported(const char* szExtension) const {
bool Importer::IsExtensionSupported(const char *szExtension) const {
return nullptr != GetImporter(szExtension);
}
@ -938,7 +935,7 @@ size_t Importer::GetImporterCount() const {
}
// ------------------------------------------------------------------------------------------------
const aiImporterDesc* Importer::GetImporterInfo(size_t index) const {
const aiImporterDesc *Importer::GetImporterInfo(size_t index) const {
ai_assert(nullptr != pimpl);
if (index >= pimpl->mImporter.size()) {
@ -947,9 +944,8 @@ const aiImporterDesc* Importer::GetImporterInfo(size_t index) const {
return pimpl->mImporter[index]->GetInfo();
}
// ------------------------------------------------------------------------------------------------
BaseImporter* Importer::GetImporter (size_t index) const {
BaseImporter *Importer::GetImporter(size_t index) const {
ai_assert(nullptr != pimpl);
if (index >= pimpl->mImporter.size()) {
@ -960,7 +956,7 @@ BaseImporter* Importer::GetImporter (size_t index) const {
// ------------------------------------------------------------------------------------------------
// Find a loader plugin for a given file extension
BaseImporter* Importer::GetImporter (const char* szExtension) const {
BaseImporter *Importer::GetImporter(const char *szExtension) const {
ai_assert(nullptr != pimpl);
return GetImporter(GetImporterIndex(szExtension));
@ -968,29 +964,30 @@ BaseImporter* Importer::GetImporter (const char* szExtension) const {
// ------------------------------------------------------------------------------------------------
// Find a loader plugin for a given file extension
size_t Importer::GetImporterIndex (const char* szExtension) const {
size_t Importer::GetImporterIndex(const char *szExtension) const {
ai_assert(nullptr != pimpl);
ai_assert(nullptr != szExtension);
ASSIMP_BEGIN_EXCEPTION_REGION();
// skip over wildcard and dot characters at string head --
for ( ; *szExtension == '*' || *szExtension == '.'; ++szExtension );
for (; *szExtension == '*' || *szExtension == '.'; ++szExtension)
;
std::string ext(szExtension);
if (ext.empty()) {
return static_cast<size_t>(-1);
}
std::transform( ext.begin(), ext.end(), ext.begin(), ToLower<char> );
std::transform(ext.begin(), ext.end(), ext.begin(), ToLower<char>);
std::set<std::string> str;
for (std::vector<BaseImporter*>::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i) {
for (std::vector<BaseImporter *>::const_iterator i = pimpl->mImporter.begin(); i != pimpl->mImporter.end(); ++i) {
str.clear();
(*i)->GetExtensionList(str);
for (std::set<std::string>::const_iterator it = str.begin(); it != str.end(); ++it) {
if (ext == *it) {
return std::distance(static_cast< std::vector<BaseImporter*>::const_iterator >(pimpl->mImporter.begin()), i);
return std::distance(static_cast<std::vector<BaseImporter *>::const_iterator>(pimpl->mImporter.begin()), i);
}
}
}
@ -1000,18 +997,18 @@ size_t Importer::GetImporterIndex (const char* szExtension) const {
// ------------------------------------------------------------------------------------------------
// Helper function to build a list of all file extensions supported by ASSIMP
void Importer::GetExtensionList(aiString& szOut) const {
void Importer::GetExtensionList(aiString &szOut) const {
ai_assert(nullptr != pimpl);
ASSIMP_BEGIN_EXCEPTION_REGION();
std::set<std::string> str;
for (std::vector<BaseImporter*>::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i) {
for (std::vector<BaseImporter *>::const_iterator i = pimpl->mImporter.begin(); i != pimpl->mImporter.end(); ++i) {
(*i)->GetExtensionList(str);
}
// List can be empty
if( !str.empty() ) {
for (std::set<std::string>::const_iterator it = str.begin();; ) {
if (!str.empty()) {
for (std::set<std::string>::const_iterator it = str.begin();;) {
szOut.Append("*.");
szOut.Append((*it).c_str());
@ -1026,107 +1023,106 @@ void Importer::GetExtensionList(aiString& szOut) const {
// ------------------------------------------------------------------------------------------------
// Set a configuration property
bool Importer::SetPropertyInteger(const char* szName, int iValue) {
bool Importer::SetPropertyInteger(const char *szName, int iValue) {
ai_assert(nullptr != pimpl);
bool existing;
ASSIMP_BEGIN_EXCEPTION_REGION();
existing = SetGenericProperty<int>(pimpl->mIntProperties, szName,iValue);
existing = SetGenericProperty<int>(pimpl->mIntProperties, szName, iValue);
ASSIMP_END_EXCEPTION_REGION(bool);
return existing;
}
// ------------------------------------------------------------------------------------------------
// Set a configuration property
bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) {
bool Importer::SetPropertyFloat(const char *szName, ai_real iValue) {
ai_assert(nullptr != pimpl);
bool existing;
ASSIMP_BEGIN_EXCEPTION_REGION();
existing = SetGenericProperty<ai_real>(pimpl->mFloatProperties, szName,iValue);
existing = SetGenericProperty<ai_real>(pimpl->mFloatProperties, szName, iValue);
ASSIMP_END_EXCEPTION_REGION(bool);
return existing;
}
// ------------------------------------------------------------------------------------------------
// Set a configuration property
bool Importer::SetPropertyString(const char* szName, const std::string& value) {
bool Importer::SetPropertyString(const char *szName, const std::string &value) {
ai_assert(nullptr != pimpl);
bool existing;
ASSIMP_BEGIN_EXCEPTION_REGION();
existing = SetGenericProperty<std::string>(pimpl->mStringProperties, szName,value);
existing = SetGenericProperty<std::string>(pimpl->mStringProperties, szName, value);
ASSIMP_END_EXCEPTION_REGION(bool);
return existing;
}
// ------------------------------------------------------------------------------------------------
// Set a configuration property
bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) {
bool Importer::SetPropertyMatrix(const char *szName, const aiMatrix4x4 &value) {
ai_assert(nullptr != pimpl);
bool existing;
ASSIMP_BEGIN_EXCEPTION_REGION();
existing = SetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties, szName,value);
existing = SetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties, szName, value);
ASSIMP_END_EXCEPTION_REGION(bool);
return existing;
}
// ------------------------------------------------------------------------------------------------
// Get a configuration property
int Importer::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const {
int Importer::GetPropertyInteger(const char *szName, int iErrorReturn /*= 0xffffffff*/) const {
ai_assert(nullptr != pimpl);
return GetGenericProperty<int>(pimpl->mIntProperties,szName,iErrorReturn);
return GetGenericProperty<int>(pimpl->mIntProperties, szName, iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
// Get a configuration property
ai_real Importer::GetPropertyFloat(const char* szName, ai_real iErrorReturn /*= 10e10*/) const {
ai_real Importer::GetPropertyFloat(const char *szName, ai_real iErrorReturn /*= 10e10*/) const {
ai_assert(nullptr != pimpl);
return GetGenericProperty<ai_real>(pimpl->mFloatProperties,szName,iErrorReturn);
return GetGenericProperty<ai_real>(pimpl->mFloatProperties, szName, iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
// Get a configuration property
std::string Importer::GetPropertyString(const char* szName, const std::string& iErrorReturn /*= ""*/) const {
std::string Importer::GetPropertyString(const char *szName, const std::string &iErrorReturn /*= ""*/) const {
ai_assert(nullptr != pimpl);
return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn);
return GetGenericProperty<std::string>(pimpl->mStringProperties, szName, iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
// Get a configuration property
aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName, const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const {
aiMatrix4x4 Importer::GetPropertyMatrix(const char *szName, const aiMatrix4x4 &iErrorReturn /*= aiMatrix4x4()*/) const {
ai_assert(nullptr != pimpl);
return GetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties,szName,iErrorReturn);
return GetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties, szName, iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
// Get the memory requirements of a single node
inline
void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) {
if ( nullptr == pcNode ) {
inline void AddNodeWeight(unsigned int &iScene, const aiNode *pcNode) {
if (nullptr == pcNode) {
return;
}
iScene += sizeof(aiNode);
iScene += sizeof(unsigned int) * pcNode->mNumMeshes;
iScene += sizeof(void*) * pcNode->mNumChildren;
iScene += sizeof(void *) * pcNode->mNumChildren;
for (unsigned int i = 0; i < pcNode->mNumChildren;++i) {
AddNodeWeight(iScene,pcNode->mChildren[i]);
for (unsigned int i = 0; i < pcNode->mNumChildren; ++i) {
AddNodeWeight(iScene, pcNode->mChildren[i]);
}
}
// ------------------------------------------------------------------------------------------------
// Get the memory requirements of the scene
void Importer::GetMemoryRequirements(aiMemoryInfo& in) const {
void Importer::GetMemoryRequirements(aiMemoryInfo &in) const {
ai_assert(nullptr != pimpl);
in = aiMemoryInfo();
aiScene* mScene = pimpl->mScene;
aiScene *mScene = pimpl->mScene;
// return if we have no scene loaded
if (!mScene)
@ -1135,7 +1131,7 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const {
in.total = sizeof(aiScene);
// add all meshes
for (unsigned int i = 0; i < mScene->mNumMeshes;++i) {
for (unsigned int i = 0; i < mScene->mNumMeshes; ++i) {
in.meshes += sizeof(aiMesh);
if (mScene->mMeshes[i]->HasPositions()) {
in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
@ -1149,14 +1145,14 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const {
in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices * 2;
}
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) {
if (mScene->mMeshes[i]->HasVertexColors(a)) {
in.meshes += sizeof(aiColor4D) * mScene->mMeshes[i]->mNumVertices;
} else {
break;
}
}
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) {
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
if (mScene->mMeshes[i]->HasTextureCoords(a)) {
in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
} else {
@ -1164,19 +1160,19 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const {
}
}
if (mScene->mMeshes[i]->HasBones()) {
in.meshes += sizeof(void*) * mScene->mMeshes[i]->mNumBones;
for (unsigned int p = 0; p < mScene->mMeshes[i]->mNumBones;++p) {
in.meshes += sizeof(void *) * mScene->mMeshes[i]->mNumBones;
for (unsigned int p = 0; p < mScene->mMeshes[i]->mNumBones; ++p) {
in.meshes += sizeof(aiBone);
in.meshes += mScene->mMeshes[i]->mBones[p]->mNumWeights * sizeof(aiVertexWeight);
}
}
in.meshes += (sizeof(aiFace) + 3 * sizeof(unsigned int))*mScene->mMeshes[i]->mNumFaces;
in.meshes += (sizeof(aiFace) + 3 * sizeof(unsigned int)) * mScene->mMeshes[i]->mNumFaces;
}
in.total += in.meshes;
// add all embedded textures
for (unsigned int i = 0; i < mScene->mNumTextures;++i) {
const aiTexture* pc = mScene->mTextures[i];
for (unsigned int i = 0; i < mScene->mNumTextures; ++i) {
const aiTexture *pc = mScene->mTextures[i];
in.textures += sizeof(aiTexture);
if (pc->mHeight) {
in.textures += 4 * pc->mHeight * pc->mWidth;
@ -1187,13 +1183,13 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const {
in.total += in.textures;
// add all animations
for (unsigned int i = 0; i < mScene->mNumAnimations;++i) {
const aiAnimation* pc = mScene->mAnimations[i];
for (unsigned int i = 0; i < mScene->mNumAnimations; ++i) {
const aiAnimation *pc = mScene->mAnimations[i];
in.animations += sizeof(aiAnimation);
// add all bone anims
for (unsigned int a = 0; a < pc->mNumChannels; ++a) {
const aiNodeAnim* pc2 = pc->mChannels[a];
const aiNodeAnim *pc2 = pc->mChannels[a];
in.animations += sizeof(aiNodeAnim);
in.animations += pc2->mNumPositionKeys * sizeof(aiVectorKey);
in.animations += pc2->mNumScalingKeys * sizeof(aiVectorKey);
@ -1207,16 +1203,16 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const {
in.total += in.lights = sizeof(aiLight) * mScene->mNumLights;
// add all nodes
AddNodeWeight(in.nodes,mScene->mRootNode);
AddNodeWeight(in.nodes, mScene->mRootNode);
in.total += in.nodes;
// add all materials
for (unsigned int i = 0; i < mScene->mNumMaterials;++i) {
const aiMaterial* pc = mScene->mMaterials[i];
for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) {
const aiMaterial *pc = mScene->mMaterials[i];
in.materials += sizeof(aiMaterial);
in.materials += pc->mNumAllocated * sizeof(void*);
in.materials += pc->mNumAllocated * sizeof(void *);
for (unsigned int a = 0; a < pc->mNumProperties;++a) {
for (unsigned int a = 0; a < pc->mNumProperties; ++a) {
in.materials += pc->mProperties[a]->mDataLength;
}
}

View File

@ -44,20 +44,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef INCLUDED_AI_IMPORTER_H
#define INCLUDED_AI_IMPORTER_H
#include <map>
#include <vector>
#include <string>
#include <assimp/matrix4x4.h>
#include <map>
#include <string>
#include <vector>
struct aiScene;
namespace Assimp {
class ProgressHandler;
class IOSystem;
class BaseImporter;
class BaseProcess;
class SharedPostProcessInfo;
class ProgressHandler;
class IOSystem;
class BaseImporter;
class BaseProcess;
class SharedPostProcessInfo;
//! @cond never
// ---------------------------------------------------------------------------
@ -70,7 +69,7 @@ namespace Assimp {
class ImporterPimpl {
public:
// Data type to store the key hash
typedef unsigned int KeyType;
using KeyType = unsigned int;
// typedefs for our four configuration maps.
// We don't need more, so there is no need for a generic solution
@ -80,21 +79,21 @@ public:
typedef std::map<KeyType, aiMatrix4x4> MatrixPropertyMap;
/** IO handler to use for all file accesses. */
IOSystem* mIOHandler;
IOSystem *mIOHandler;
bool mIsDefaultHandler;
/** Progress handler for feedback. */
ProgressHandler* mProgressHandler;
ProgressHandler *mProgressHandler;
bool mIsDefaultProgressHandler;
/** Format-specific importer worker objects - one for each format we can read.*/
std::vector< BaseImporter* > mImporter;
std::vector<BaseImporter *> mImporter;
/** Post processing steps we can apply at the imported data. */
std::vector< BaseProcess* > mPostProcessingSteps;
std::vector<BaseProcess *> mPostProcessingSteps;
/** The imported data, if ReadFile() was successful, nullptr otherwise. */
aiScene* mScene;
aiScene *mScene;
/** The error description, if there was one. In the case of an exception,
* mException will carry the full details. */
@ -120,29 +119,27 @@ public:
bool bExtraVerbose;
/** Used by post-process steps to share data */
SharedPostProcessInfo* mPPShared;
SharedPostProcessInfo *mPPShared;
/// The default class constructor.
ImporterPimpl() AI_NO_EXCEPT;
};
inline
ImporterPimpl::ImporterPimpl() AI_NO_EXCEPT :
mIOHandler( nullptr ),
mIsDefaultHandler( false ),
mProgressHandler( nullptr ),
mIsDefaultProgressHandler( false ),
inline ImporterPimpl::ImporterPimpl() AI_NO_EXCEPT : mIOHandler(nullptr),
mIsDefaultHandler(false),
mProgressHandler(nullptr),
mIsDefaultProgressHandler(false),
mImporter(),
mPostProcessingSteps(),
mScene( nullptr ),
mScene(nullptr),
mErrorString(),
mException(),
mIntProperties(),
mFloatProperties(),
mStringProperties(),
mMatrixProperties(),
bExtraVerbose( false ),
mPPShared( nullptr ) {
bExtraVerbose(false),
mPPShared(nullptr) {
// empty
}
//! @endcond
@ -169,12 +166,12 @@ public:
ImporterPimpl::StringPropertyMap strings;
ImporterPimpl::MatrixPropertyMap matrices;
bool operator == (const PropertyMap& prop) const {
bool operator==(const PropertyMap &prop) const {
// fixme: really isocpp? gcc complains
return ints == prop.ints && floats == prop.floats && strings == prop.strings && matrices == prop.matrices;
}
bool empty () const {
bool empty() const {
return ints.empty() && floats.empty() && strings.empty() && matrices.empty();
}
};
@ -184,7 +181,7 @@ public:
/** Construct a batch loader from a given IO system to be used
* to access external files
*/
explicit BatchLoader(IOSystem* pIO, bool validate = false );
explicit BatchLoader(IOSystem *pIO, bool validate = false);
// -------------------------------------------------------------------
/** The class destructor.
@ -195,7 +192,7 @@ public:
/** Sets the validation step. True for enable validation during postprocess.
* @param enable True for validation.
*/
void setValidation( bool enabled );
void setValidation(bool enabled);
// -------------------------------------------------------------------
/** Returns the current validation step.
@ -211,11 +208,10 @@ public:
* @return 'Load request channel' - an unique ID that can later
* be used to access the imported file data.
* @see GetImport */
unsigned int AddLoadRequest (
const std::string& file,
unsigned int AddLoadRequest(
const std::string &file,
unsigned int steps = 0,
const PropertyMap *map = nullptr
);
const PropertyMap *map = nullptr);
// -------------------------------------------------------------------
/** Get an imported scene.
@ -226,9 +222,8 @@ public:
* @param which LRWC returned by AddLoadRequest().
* @return nullptr if there is no scene with this file name
* in the queue of the scene hasn't been loaded yet. */
aiScene* GetImport(
unsigned int which
);
aiScene *GetImport(
unsigned int which);
// -------------------------------------------------------------------
/** Waits until all scenes have been loaded. This returns

View File

@ -45,8 +45,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AI_POLYTOOLS_H_INCLUDED
#define AI_POLYTOOLS_H_INCLUDED
#include <assimp/material.h>
#include <assimp/ai_assert.h>
#include <assimp/material.h>
#include <assimp/vector3.h>
namespace Assimp {
@ -55,8 +56,7 @@ namespace Assimp {
* The function accepts an unconstrained template parameter for use with
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
template <typename T>
inline double GetArea2D(const T& v1, const T& v2, const T& v3)
{
inline double GetArea2D(const T &v1, const T &v2, const T &v3) {
return 0.5 * (v1.x * ((double)v3.y - v2.y) + v2.x * ((double)v1.y - v3.y) + v3.x * ((double)v2.y - v1.y));
}
@ -65,9 +65,8 @@ inline double GetArea2D(const T& v1, const T& v2, const T& v3)
* The function accepts an unconstrained template parameter for use with
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
template <typename T>
inline bool OnLeftSideOfLine2D(const T& p0, const T& p1,const T& p2)
{
return GetArea2D(p0,p2,p1) > 0;
inline bool OnLeftSideOfLine2D(const T &p0, const T &p1, const T &p2) {
return GetArea2D(p0, p2, p1) > 0;
}
// -------------------------------------------------------------------------------
@ -75,8 +74,7 @@ inline bool OnLeftSideOfLine2D(const T& p0, const T& p1,const T& p2)
* The function accepts an unconstrained template parameter for use with
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
template <typename T>
inline bool PointInTriangle2D(const T& p0, const T& p1,const T& p2, const T& pp)
{
inline bool PointInTriangle2D(const T &p0, const T &p1, const T &p2, const T &pp) {
// Point in triangle test using baryzentric coordinates
const aiVector2D v0 = p1 - p0;
const aiVector2D v1 = p2 - p0;
@ -95,7 +93,6 @@ inline bool PointInTriangle2D(const T& p0, const T& p1,const T& p2, const T& pp)
return (dot11 > 0) && (dot00 > 0) && (dot11 + dot00 < 1);
}
// -------------------------------------------------------------------------------
/** Check whether the winding order of a given polygon is counter-clockwise.
* The function accepts an unconstrained template parameter, but is intended
@ -104,7 +101,7 @@ inline bool PointInTriangle2D(const T& p0, const T& p1,const T& p2, const T& pp)
* @note Code taken from http://cgm.cs.mcgill.ca/~godfried/teaching/cg-projects/97/Ian/applet1.html and translated to C++
*/
template <typename T>
inline bool IsCCW(T* in, size_t npoints) {
inline bool IsCCW(T *in, size_t npoints) {
double aa, bb, cc, b, c, theta;
double convex_turn;
double convex_sum = 0;
@ -112,41 +109,40 @@ inline bool IsCCW(T* in, size_t npoints) {
ai_assert(npoints >= 3);
for (size_t i = 0; i < npoints - 2; i++) {
aa = ((in[i+2].x - in[i].x) * (in[i+2].x - in[i].x)) +
((-in[i+2].y + in[i].y) * (-in[i+2].y + in[i].y));
aa = ((in[i + 2].x - in[i].x) * (in[i + 2].x - in[i].x)) +
((-in[i + 2].y + in[i].y) * (-in[i + 2].y + in[i].y));
bb = ((in[i+1].x - in[i].x) * (in[i+1].x - in[i].x)) +
((-in[i+1].y + in[i].y) * (-in[i+1].y + in[i].y));
bb = ((in[i + 1].x - in[i].x) * (in[i + 1].x - in[i].x)) +
((-in[i + 1].y + in[i].y) * (-in[i + 1].y + in[i].y));
cc = ((in[i+2].x - in[i+1].x) *
(in[i+2].x - in[i+1].x)) +
((-in[i+2].y + in[i+1].y) *
(-in[i+2].y + in[i+1].y));
cc = ((in[i + 2].x - in[i + 1].x) *
(in[i + 2].x - in[i + 1].x)) +
((-in[i + 2].y + in[i + 1].y) *
(-in[i + 2].y + in[i + 1].y));
b = std::sqrt(bb);
c = std::sqrt(cc);
theta = std::acos((bb + cc - aa) / (2 * b * c));
if (OnLeftSideOfLine2D(in[i],in[i+2],in[i+1])) {
if (OnLeftSideOfLine2D(in[i], in[i + 2], in[i + 1])) {
// if (convex(in[i].x, in[i].y,
// in[i+1].x, in[i+1].y,
// in[i+2].x, in[i+2].y)) {
convex_turn = AI_MATH_PI_F - theta;
convex_sum += convex_turn;
}
else {
} else {
convex_sum -= AI_MATH_PI_F - theta;
}
}
aa = ((in[1].x - in[npoints-2].x) *
(in[1].x - in[npoints-2].x)) +
((-in[1].y + in[npoints-2].y) *
(-in[1].y + in[npoints-2].y));
aa = ((in[1].x - in[npoints - 2].x) *
(in[1].x - in[npoints - 2].x)) +
((-in[1].y + in[npoints - 2].y) *
(-in[1].y + in[npoints - 2].y));
bb = ((in[0].x - in[npoints-2].x) *
(in[0].x - in[npoints-2].x)) +
((-in[0].y + in[npoints-2].y) *
(-in[0].y + in[npoints-2].y));
bb = ((in[0].x - in[npoints - 2].x) *
(in[0].x - in[npoints - 2].x)) +
((-in[0].y + in[npoints - 2].y) *
(-in[0].y + in[npoints - 2].y));
cc = ((in[1].x - in[0].x) * (in[1].x - in[0].x)) +
((-in[1].y + in[0].y) * (-in[1].y + in[0].y));
@ -158,18 +154,16 @@ inline bool IsCCW(T* in, size_t npoints) {
//if (convex(in[npoints-2].x, in[npoints-2].y,
// in[0].x, in[0].y,
// in[1].x, in[1].y)) {
if (OnLeftSideOfLine2D(in[npoints-2],in[1],in[0])) {
if (OnLeftSideOfLine2D(in[npoints - 2], in[1], in[0])) {
convex_turn = AI_MATH_PI_F - theta;
convex_sum += convex_turn;
}
else {
} else {
convex_sum -= AI_MATH_PI_F - theta;
}
return convex_sum >= (2 * AI_MATH_PI_F);
}
// -------------------------------------------------------------------------------
/** Compute the normal of an arbitrary polygon in R3.
*
@ -185,29 +179,34 @@ inline bool IsCCW(T* in, size_t npoints) {
* @note The data arrays must have storage for at least num+2 elements. Using
* this method is much faster than the 'other' NewellNormal()
*/
template <int ofs_x, int ofs_y, int ofs_z, typename TReal>
inline void NewellNormal (aiVector3t<TReal>& out, int num, TReal* x, TReal* y, TReal* z)
{
template <size_t ofs_x, size_t ofs_y, size_t ofs_z, typename TReal>
inline void NewellNormal(aiVector3t<TReal> &out, size_t num, TReal *x, TReal *y, TReal *z, size_t bufferSize) {
ai_assert(bufferSize > num);
if (nullptr == x || nullptr == y || nullptr == z || 0 == bufferSize || 0 == num) {
return;
}
// Duplicate the first two vertices at the end
x[(num+0)*ofs_x] = x[0];
x[(num+1)*ofs_x] = x[ofs_x];
x[(num + 0) * ofs_x] = x[0];
x[(num + 1) * ofs_x] = x[ofs_x];
y[(num+0)*ofs_y] = y[0];
y[(num+1)*ofs_y] = y[ofs_y];
y[(num + 0) * ofs_y] = y[0];
y[(num + 1) * ofs_y] = y[ofs_y];
z[(num+0)*ofs_z] = z[0];
z[(num+1)*ofs_z] = z[ofs_z];
z[(num + 0) * ofs_z] = z[0];
z[(num + 1) * ofs_z] = z[ofs_z];
TReal sum_xy = 0.0, sum_yz = 0.0, sum_zx = 0.0;
TReal *xptr = x +ofs_x, *xlow = x, *xhigh = x + ofs_x*2;
TReal *yptr = y +ofs_y, *ylow = y, *yhigh = y + ofs_y*2;
TReal *zptr = z +ofs_z, *zlow = z, *zhigh = z + ofs_z*2;
TReal *xptr = x + ofs_x, *xlow = x, *xhigh = x + ofs_x * 2;
TReal *yptr = y + ofs_y, *ylow = y, *yhigh = y + ofs_y * 2;
TReal *zptr = z + ofs_z, *zlow = z, *zhigh = z + ofs_z * 2;
for (int tmp=0; tmp < num; tmp++) {
sum_xy += (*xptr) * ( (*yhigh) - (*ylow) );
sum_yz += (*yptr) * ( (*zhigh) - (*zlow) );
sum_zx += (*zptr) * ( (*xhigh) - (*xlow) );
for (size_t tmp = 0; tmp < num; ++tmp ) {
sum_xy += (*xptr) * ((*yhigh) - (*ylow));
sum_yz += (*yptr) * ((*zhigh) - (*zlow));
sum_zx += (*zptr) * ((*xhigh) - (*xlow));
xptr += ofs_x;
xlow += ofs_x;
@ -221,9 +220,9 @@ inline void NewellNormal (aiVector3t<TReal>& out, int num, TReal* x, TReal* y, T
zlow += ofs_z;
zhigh += ofs_z;
}
out = aiVector3t<TReal>(sum_yz,sum_zx,sum_xy);
out = aiVector3t<TReal>(sum_yz, sum_zx, sum_xy);
}
} // ! Assimp
} // namespace Assimp
#endif

View File

@ -60,14 +60,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_TRIANGULATE_PROCESS
#include "PostProcessing/TriangulateProcess.h"
#include "PostProcessing/ProcessHelper.h"
#include "Common/PolyTools.h"
#include "PostProcessing/ProcessHelper.h"
#include <memory>
#include <cstdint>
#include <memory>
//#define AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
//#define AI_BUILD_TRIANGULATE_DEBUG_POLYS
#define AI_BUILD_TRIANGULATE_DEBUG_POLYS
#define POLY_GRID_Y 40
#define POLY_GRID_X 70
@ -78,86 +78,91 @@ using namespace Assimp;
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
TriangulateProcess::TriangulateProcess()
{
TriangulateProcess::TriangulateProcess() {
// nothing to do here
}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
TriangulateProcess::~TriangulateProcess()
{
TriangulateProcess::~TriangulateProcess() {
// nothing to do here
}
// ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field.
bool TriangulateProcess::IsActive( unsigned int pFlags) const
{
bool TriangulateProcess::IsActive(unsigned int pFlags) const {
return (pFlags & aiProcess_Triangulate) != 0;
}
// ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data.
void TriangulateProcess::Execute( aiScene* pScene)
{
void TriangulateProcess::Execute(aiScene *pScene) {
ASSIMP_LOG_DEBUG("TriangulateProcess begin");
bool bHas = false;
for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
{
if (pScene->mMeshes[ a ]) {
if ( TriangulateMesh( pScene->mMeshes[ a ] ) ) {
for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
if (pScene->mMeshes[a]) {
if (TriangulateMesh(pScene->mMeshes[a])) {
bHas = true;
}
}
}
if ( bHas ) {
ASSIMP_LOG_INFO( "TriangulateProcess finished. All polygons have been triangulated." );
if (bHas) {
ASSIMP_LOG_INFO("TriangulateProcess finished. All polygons have been triangulated.");
} else {
ASSIMP_LOG_DEBUG( "TriangulateProcess finished. There was nothing to be done." );
ASSIMP_LOG_DEBUG("TriangulateProcess finished. There was nothing to be done.");
}
}
// ------------------------------------------------------------------------------------------------
static bool validateNumIndices(aiMesh *mesh) {
bool bNeed = false;
for (unsigned int a = 0; a < mesh->mNumFaces; a++) {
const aiFace &face = mesh->mFaces[a];
if (face.mNumIndices != 3) {
bNeed = true;
break;
}
}
return bNeed;
}
static void calulateNumOutputFaces(aiMesh *mesh, size_t &numOut, size_t &maxOut, bool &getNormals) {
numOut = maxOut = 0;
getNormals = true;
for (unsigned int a = 0; a < mesh->mNumFaces; a++) {
aiFace &face = mesh->mFaces[a];
if (face.mNumIndices <= 4) {
getNormals = false;
}
if (face.mNumIndices <= 3) {
numOut++;
} else {
numOut += face.mNumIndices - 2;
maxOut = std::max(maxOut, static_cast<size_t>(face.mNumIndices));
}
}
}
// ------------------------------------------------------------------------------------------------
// Triangulates the given mesh.
bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
{
bool TriangulateProcess::TriangulateMesh(aiMesh *pMesh) {
// Now we have aiMesh::mPrimitiveTypes, so this is only here for test cases
if (!pMesh->mPrimitiveTypes) {
bool bNeed = false;
for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
const aiFace& face = pMesh->mFaces[a];
if( face.mNumIndices != 3) {
bNeed = true;
}
}
if (!bNeed)
if (!validateNumIndices(pMesh)) {
return false;
}
else if (!(pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) {
} else if (!(pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) {
return false;
}
// Find out how many output faces we'll get
uint32_t numOut = 0, max_out = 0;
bool get_normals = true;
for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
aiFace& face = pMesh->mFaces[a];
if (face.mNumIndices <= 4) {
get_normals = false;
}
if( face.mNumIndices <= 3) {
numOut++;
}
else {
numOut += face.mNumIndices-2;
max_out = std::max(max_out,face.mNumIndices);
}
}
size_t numOut = 0, max_out = 0;
bool getNormals = true;
calulateNumOutputFaces(pMesh, numOut, max_out, getNormals);
// Just another check whether aiMesh::mPrimitiveTypes is correct
ai_assert(numOut != pMesh->mNumFaces);
@ -166,7 +171,7 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
// if we don't have normals yet, but expect them to be a cheap side
// product of triangulation anyway, allocate storage for them.
if (!pMesh->mNormals && get_normals) {
if (!pMesh->mNormals && getNormals) {
// XXX need a mechanism to inform the GenVertexNormals process to treat these normals as preprocessed per-face normals
// nor_out = pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
}
@ -175,49 +180,49 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
pMesh->mPrimitiveTypes &= ~aiPrimitiveType_POLYGON;
aiFace* out = new aiFace[numOut](), *curOut = out;
std::vector<aiVector3D> temp_verts3d(max_out+2); /* temporary storage for vertices */
std::vector<aiVector2D> temp_verts(max_out+2);
aiFace *out = new aiFace[numOut](), *curOut = out;
const size_t Capa = max_out + 2;
std::vector<aiVector3D> temp_verts3d(max_out + 2); /* temporary storage for vertices */
std::vector<aiVector2D> temp_verts(max_out + 2);
// Apply vertex colors to represent the face winding?
#ifdef AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
if (!pMesh->mColors[0])
pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices];
else
new(pMesh->mColors[0]) aiColor4D[pMesh->mNumVertices];
new (pMesh->mColors[0]) aiColor4D[pMesh->mNumVertices];
aiColor4D* clr = pMesh->mColors[0];
aiColor4D *clr = pMesh->mColors[0];
#endif
#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
FILE* fout = fopen(POLY_OUTPUT_FILE,"a");
FILE *fout = fopen(POLY_OUTPUT_FILE, "a");
#endif
const aiVector3D* verts = pMesh->mVertices;
const aiVector3D *verts = pMesh->mVertices;
// use std::unique_ptr to avoid slow std::vector<bool> specialiations
std::unique_ptr<bool[]> done(new bool[max_out]);
for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
aiFace& face = pMesh->mFaces[a];
for (unsigned int a = 0; a < pMesh->mNumFaces; a++) {
aiFace &face = pMesh->mFaces[a];
unsigned int* idx = face.mIndices;
int num = (int)face.mNumIndices, ear = 0, tmp, prev = num-1, next = 0, max = num;
unsigned int *idx = face.mIndices;
int num = (int)face.mNumIndices, ear = 0, tmp, prev = num - 1, next = 0, max = num;
// Apply vertex colors to represent the face winding?
#ifdef AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
for (unsigned int i = 0; i < face.mNumIndices; ++i) {
aiColor4D& c = clr[idx[i]];
c.r = (i+1) / (float)max;
aiColor4D &c = clr[idx[i]];
c.r = (i + 1) / (float)max;
c.b = 1.f - c.r;
}
#endif
aiFace* const last_face = curOut;
aiFace *const last_face = curOut;
// if it's a simple point,line or triangle: just copy it
if( face.mNumIndices <= 3)
{
aiFace& nface = *curOut++;
if (face.mNumIndices <= 3) {
aiFace &nface = *curOut++;
nface.mNumIndices = face.mNumIndices;
nface.mIndices = face.mIndices;
@ -225,28 +230,28 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
continue;
}
// optimized code for quadrilaterals
else if ( face.mNumIndices == 4) {
else if (face.mNumIndices == 4) {
// quads can have at maximum one concave vertex. Determine
// this vertex (if it exists) and start tri-fanning from
// it.
unsigned int start_vertex = 0;
for (unsigned int i = 0; i < 4; ++i) {
const aiVector3D& v0 = verts[face.mIndices[(i+3) % 4]];
const aiVector3D& v1 = verts[face.mIndices[(i+2) % 4]];
const aiVector3D& v2 = verts[face.mIndices[(i+1) % 4]];
const aiVector3D &v0 = verts[face.mIndices[(i + 3) % 4]];
const aiVector3D &v1 = verts[face.mIndices[(i + 2) % 4]];
const aiVector3D &v2 = verts[face.mIndices[(i + 1) % 4]];
const aiVector3D& v = verts[face.mIndices[i]];
const aiVector3D &v = verts[face.mIndices[i]];
aiVector3D left = (v0-v);
aiVector3D diag = (v1-v);
aiVector3D right = (v2-v);
aiVector3D left = (v0 - v);
aiVector3D diag = (v1 - v);
aiVector3D right = (v2 - v);
left.Normalize();
diag.Normalize();
right.Normalize();
const float angle = std::acos(left*diag) + std::acos(right*diag);
const float angle = std::acos(left * diag) + std::acos(right * diag);
if (angle > AI_MATH_PI_F) {
// this is the concave point
start_vertex = i;
@ -254,9 +259,9 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
}
}
const unsigned int temp[] = {face.mIndices[0], face.mIndices[1], face.mIndices[2], face.mIndices[3]};
const unsigned int temp[] = { face.mIndices[0], face.mIndices[1], face.mIndices[2], face.mIndices[3] };
aiFace& nface = *curOut++;
aiFace &nface = *curOut++;
nface.mNumIndices = 3;
nface.mIndices = face.mIndices;
@ -264,7 +269,7 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
nface.mIndices[1] = temp[(start_vertex + 1) % 4];
nface.mIndices[2] = temp[(start_vertex + 2) % 4];
aiFace& sface = *curOut++;
aiFace &sface = *curOut++;
sface.mNumIndices = 3;
sface.mIndices = new unsigned int[3];
@ -275,9 +280,7 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
// prevent double deletion of the indices field
face.mIndices = nullptr;
continue;
}
else
{
} else {
// A polygon with more than 3 vertices can be either concave or convex.
// Usually everything we're getting is convex and we could easily
// triangulate by tri-fanning. However, LightWave is probably the only
@ -292,38 +295,39 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
temp_verts3d[tmp] = verts[idx[tmp]];
}
// Get newell normal of the polygon. Store it for future use if it's a polygon-only mesh
// Get Newell-Normal of the polygon. Store it for future use if it's a polygon-only mesh
aiVector3D n;
NewellNormal<3,3,3>(n,max,&temp_verts3d.front().x,&temp_verts3d.front().y,&temp_verts3d.front().z);
NewellNormal<3, 3, 3>(n, max, &temp_verts3d.front().x, &temp_verts3d.front().y, &temp_verts3d.front().z, Capa);
if (nor_out) {
for (tmp = 0; tmp < max; ++tmp)
nor_out[idx[tmp]] = n;
}
// Select largest normal coordinate to ignore for projection
const float ax = (n.x>0 ? n.x : -n.x);
const float ay = (n.y>0 ? n.y : -n.y);
const float az = (n.z>0 ? n.z : -n.z);
const float ax = (n.x > 0 ? n.x : -n.x);
const float ay = (n.y > 0 ? n.y : -n.y);
const float az = (n.z > 0 ? n.z : -n.z);
unsigned int ac = 0, bc = 1; /* no z coord. projection to xy */
unsigned int ac = 0, bc = 1; // no z coord. projection to xy
float inv = n.z;
if (ax > ay) {
if (ax > az) { /* no x coord. projection to yz */
ac = 1; bc = 2;
if (ax > az) { // no x coord. projection to yz
ac = 1;
bc = 2;
inv = n.x;
}
}
else if (ay > az) { /* no y coord. projection to zy */
ac = 2; bc = 0;
} else if (ay > az) { // no y coord. projection to zy
ac = 2;
bc = 0;
inv = n.y;
}
// Swap projection axes to take the negated projection vector into account
if (inv < 0.f) {
std::swap(ac,bc);
std::swap(ac, bc);
}
for (tmp =0; tmp < max; ++tmp) {
for (tmp = 0; tmp < max; ++tmp) {
temp_verts[tmp].x = verts[idx[tmp]][ac];
temp_verts[tmp].y = verts[idx[tmp]][bc];
done[tmp] = false;
@ -331,30 +335,30 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
// plot the plane onto which we mapped the polygon to a 2D ASCII pic
aiVector2D bmin,bmax;
ArrayBounds(&temp_verts[0],max,bmin,bmax);
aiVector2D bmin, bmax;
ArrayBounds(&temp_verts[0], max, bmin, bmax);
char grid[POLY_GRID_Y][POLY_GRID_X+POLY_GRID_XPAD];
std::fill_n((char*)grid,POLY_GRID_Y*(POLY_GRID_X+POLY_GRID_XPAD),' ');
char grid[POLY_GRID_Y][POLY_GRID_X + POLY_GRID_XPAD];
std::fill_n((char *)grid, POLY_GRID_Y * (POLY_GRID_X + POLY_GRID_XPAD), ' ');
for (int i =0; i < max; ++i) {
const aiVector2D& v = (temp_verts[i] - bmin) / (bmax-bmin);
const size_t x = static_cast<size_t>(v.x*(POLY_GRID_X-1)), y = static_cast<size_t>(v.y*(POLY_GRID_Y-1));
char* loc = grid[y]+x;
for (int i = 0; i < max; ++i) {
const aiVector2D &v = (temp_verts[i] - bmin) / (bmax - bmin);
const size_t x = static_cast<size_t>(v.x * (POLY_GRID_X - 1)), y = static_cast<size_t>(v.y * (POLY_GRID_Y - 1));
char *loc = grid[y] + x;
if (grid[y][x] != ' ') {
for(;*loc != ' '; ++loc);
for (; *loc != ' '; ++loc)
;
*loc++ = '_';
}
*(loc+::ai_snprintf(loc, POLY_GRID_XPAD,"%i",i)) = ' ';
*(loc + ::ai_snprintf(loc, POLY_GRID_XPAD, "%i", i)) = ' ';
}
for(size_t y = 0; y < POLY_GRID_Y; ++y) {
grid[y][POLY_GRID_X+POLY_GRID_XPAD-1] = '\0';
fprintf(fout,"%s\n",grid[y]);
for (size_t y = 0; y < POLY_GRID_Y; ++y) {
grid[y][POLY_GRID_X + POLY_GRID_XPAD - 1] = '\0';
fprintf(fout, "%s\n", grid[y]);
}
fprintf(fout,"\ntriangulation sequence: ");
fprintf(fout, "\ntriangulation sequence: ");
#endif
//
@ -364,26 +368,27 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
// Find the next ear of the polygon
int num_found = 0;
for (ear = next;;prev = ear,ear = next) {
for (ear = next;; prev = ear, ear = next) {
// break after we looped two times without a positive match
for (next=ear+1;done[(next>=max?next=0:next)];++next);
for (next = ear + 1; done[(next >= max ? next = 0 : next)]; ++next)
;
if (next < ear) {
if (++num_found == 2) {
break;
}
}
const aiVector2D* pnt1 = &temp_verts[ear],
const aiVector2D *pnt1 = &temp_verts[ear],
*pnt0 = &temp_verts[prev],
*pnt2 = &temp_verts[next];
// Must be a convex point. Assuming ccw winding, it must be on the right of the line between p-1 and p+1.
if (OnLeftSideOfLine2D(*pnt0,*pnt2,*pnt1)) {
if (OnLeftSideOfLine2D(*pnt0, *pnt2, *pnt1)) {
continue;
}
// and no other point may be contained in this triangle
for ( tmp = 0; tmp < max; ++tmp) {
for (tmp = 0; tmp < max; ++tmp) {
// We need to compare the actual values because it's possible that multiple indexes in
// the polygon are referring to the same position. concave_polygon.obj is a sample
@ -392,8 +397,8 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
// PointInTriangle() I'm guessing that it's actually possible to construct
// input data that would cause us to end up with no ears. The problem is,
// which epsilon? If we chose a too large value, we'd get wrong results
const aiVector2D& vtmp = temp_verts[tmp];
if ( vtmp != *pnt1 && vtmp != *pnt2 && vtmp != *pnt0 && PointInTriangle2D(*pnt0,*pnt1,*pnt2,vtmp)) {
const aiVector2D &vtmp = temp_verts[tmp];
if (vtmp != *pnt1 && vtmp != *pnt2 && vtmp != *pnt0 && PointInTriangle2D(*pnt0, *pnt1, *pnt2, vtmp)) {
break;
}
}
@ -415,29 +420,13 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
ASSIMP_LOG_ERROR("Failed to triangulate polygon (no ear found). Probably not a simple polygon?");
#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
fprintf(fout,"critical error here, no ear found! ");
fprintf(fout, "critical error here, no ear found! ");
#endif
num = 0;
break;
/*curOut -= (max-num); // undo all previous work
for (tmp = 0; tmp < max-2; ++tmp) {
aiFace& nface = *curOut++;
nface.mNumIndices = 3;
if (!nface.mIndices)
nface.mIndices = new unsigned int[3];
nface.mIndices[0] = 0;
nface.mIndices[1] = tmp+1;
nface.mIndices[2] = tmp+2;
}
num = 0;
break;*/
}
aiFace& nface = *curOut++;
aiFace &nface = *curOut++;
nface.mNumIndices = 3;
if (!nface.mIndices) {
@ -455,56 +444,40 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
}
if (num > 0) {
// We have three indices forming the last 'ear' remaining. Collect them.
aiFace& nface = *curOut++;
aiFace &nface = *curOut++;
nface.mNumIndices = 3;
if (!nface.mIndices) {
nface.mIndices = new unsigned int[3];
}
for (tmp = 0; done[tmp]; ++tmp);
for (tmp = 0; done[tmp]; ++tmp)
;
nface.mIndices[0] = tmp;
for (++tmp; done[tmp]; ++tmp);
for (++tmp; done[tmp]; ++tmp)
;
nface.mIndices[1] = tmp;
for (++tmp; done[tmp]; ++tmp);
for (++tmp; done[tmp]; ++tmp)
;
nface.mIndices[2] = tmp;
}
}
#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
for(aiFace* f = last_face; f != curOut; ++f) {
unsigned int* i = f->mIndices;
fprintf(fout," (%i %i %i)",i[0],i[1],i[2]);
for (aiFace *f = last_face; f != curOut; ++f) {
unsigned int *i = f->mIndices;
fprintf(fout, " (%i %i %i)", i[0], i[1], i[2]);
}
fprintf(fout,"\n*********************************************************************\n");
fprintf(fout, "\n*********************************************************************\n");
fflush(fout);
#endif
for(aiFace* f = last_face; f != curOut; ) {
unsigned int* i = f->mIndices;
// drop dumb 0-area triangles - deactivated for now:
//FindDegenerates post processing step can do the same thing
//if (std::fabs(GetArea2D(temp_verts[i[0]],temp_verts[i[1]],temp_verts[i[2]])) < 1e-5f) {
// ASSIMP_LOG_VERBOSE_DEBUG("Dropping triangle with area 0");
// --curOut;
// delete[] f->mIndices;
// f->mIndices = nullptr;
// for(aiFace* ff = f; ff != curOut; ++ff) {
// ff->mNumIndices = (ff+1)->mNumIndices;
// ff->mIndices = (ff+1)->mIndices;
// (ff+1)->mIndices = nullptr;
// }
// continue;
//}
for (aiFace *f = last_face; f != curOut;) {
unsigned int *i = f->mIndices;
i[0] = idx[i[0]];
i[1] = idx[i[1]];
i[2] = idx[i[2]];
@ -520,11 +493,11 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
#endif
// kill the old faces
delete [] pMesh->mFaces;
delete[] pMesh->mFaces;
// ... and store the new ones
pMesh->mFaces = out;
pMesh->mNumFaces = (unsigned int)(curOut-out); /* not necessarily equal to numOut */
pMesh->mNumFaces = (unsigned int)(curOut - out); /* not necessarily equal to numOut */
return true;
}

View File

@ -96,6 +96,7 @@ SET( COMMON
unit/Common/utSpatialSort.cpp
unit/Common/utAssertHandler.cpp
unit/Common/utXmlParser.cpp
unit/Common/utPolyTools.cpp
)
SET( IMPORTERS

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,

View File

@ -43,9 +43,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AV_ANIMEVALUATOR_H_INCLUDED
#define AV_ANIMEVALUATOR_H_INCLUDED
#include <assimp/matrix4x4.h>
#include <tuple>
#include <vector>
struct aiAnimation;
namespace AssimpView {
/**
@ -74,7 +78,7 @@ public:
* the aiAnimation. */
const std::vector<aiMatrix4x4> &GetTransformations() const { return mTransforms; }
protected:
private:
const aiAnimation *mAnim;
double mLastTime;
std::vector<std::tuple<unsigned int, unsigned int, unsigned int>> mLastPositions;

File diff suppressed because it is too large Load Diff

View File

@ -47,7 +47,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AV_SCENEANIMATOR_H_INCLUDED
#define AV_SCENEANIMATOR_H_INCLUDED
#include <assimp/scene.h>
#include <map>
#include <string>
namespace AssimpView {
@ -59,7 +62,7 @@ namespace AssimpView {
struct SceneAnimNode {
std::string mName;
SceneAnimNode *mParent;
std::vector<SceneAnimNode *> mChildren;
std::vector<SceneAnimNode*> mChildren;
//! most recently calculated local transform
aiMatrix4x4 mLocalTransform;
@ -72,13 +75,23 @@ struct SceneAnimNode {
//! Default construction
SceneAnimNode() :
mName(), mParent(nullptr), mChildren(), mLocalTransform(), mGlobalTransform(), mChannelIndex(-1) {
mName(),
mParent(nullptr),
mChildren(),
mLocalTransform(),
mGlobalTransform(),
mChannelIndex(-1) {
// empty
}
//! Construction from a given name
SceneAnimNode(const std::string &pName) :
mName(pName), mParent(nullptr), mChildren(), mLocalTransform(), mGlobalTransform(), mChannelIndex(-1) {
mName(pName),
mParent(nullptr),
mChildren(),
mLocalTransform(),
mGlobalTransform(),
mChannelIndex(-1) {
// empty
}
@ -125,7 +138,7 @@ public:
// ----------------------------------------------------------------------------
/** Calculates the node transformations for the scene. Call this to get
* uptodate results before calling one of the getters.
* up-to-date results before calling one of the getters.
* @param pTime Current time. Can be an arbitrary range.
*/
void Calculate(double pTime);
@ -136,7 +149,7 @@ public:
* The returned matrix is in the node's parent's local space, just like the
* original node's transformation matrix. If the node is not animated, the
* node's original transformation is returned so that you can safely use or
* assign it to the node itsself. If there is no node with the given name,
* assign it to the node itself. If there is no node with the given name,
* the identity matrix is returned. All transformations are updated whenever
* Calculate() is called.
* @param pNodeName Name of the node
@ -151,7 +164,7 @@ public:
* The returned matrix is in world space, which is the same coordinate space
* as the transformation of the scene's root node. If the node is not animated,
* the node's original transformation is returned so that you can safely use or
* assign it to the node itsself. If there is no node with the given name, the
* assign it to the node itself. If there is no node with the given name, the
* identity matrix is returned. All transformations are updated whenever
* Calculate() is called.
* @param pNodeName Name of the node
@ -190,7 +203,7 @@ public:
/** @brief Get the current animation or NULL
*/
aiAnimation *CurrentAnim() const {
return static_cast<unsigned int>(mCurrentAnimIndex) < mScene->mNumAnimations ? mScene->mAnimations[mCurrentAnimIndex] : NULL;
return static_cast<unsigned int>(mCurrentAnimIndex) < mScene->mNumAnimations ? mScene->mAnimations[mCurrentAnimIndex] : nullptr;
}
protected: