Merge branch 'master' into matrixIdentity

pull/5445/head
Kim Kulling 2024-02-06 20:16:28 +01:00 committed by GitHub
commit 0fdbc52274
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 373 additions and 211 deletions

View File

@ -54,7 +54,7 @@ jobs:
- name: Cache DX SDK
id: dxcache
if: contains(matrix.name, 'windows')
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: '${{ github.workspace }}/DX_SDK'
key: ${{ runner.os }}-DX_SDK

View File

@ -49,8 +49,8 @@ option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF)
IF(ASSIMP_HUNTER_ENABLED)
include("cmake-modules/HunterGate.cmake")
HunterGate(
URL "https://github.com/cpp-pm/hunter/archive/v0.24.18.tar.gz"
SHA1 "1292e4d661e1770d6d6ca08c12c07cf34a0bf718"
URL "https://github.com/cpp-pm/hunter/archive/v0.25.3.tar.gz"
SHA1 "3319fe6a3b08090df7df98dee75134d68e2ef5a3"
)
add_definitions(-DASSIMP_USE_HUNTER)
ENDIF()

View File

@ -57,6 +57,7 @@ enum class ResourceType {
RT_BaseMaterials,
RT_EmbeddedTexture2D,
RT_Texture2DGroup,
RT_ColorGroup,
RT_Unknown
}; // To be extended with other resource types (eg. material extension resources like Texture2d, Texture2dGroup...)
@ -117,6 +118,21 @@ public:
}
};
class ColorGroup : public Resource {
public:
std::vector<aiColor4D> mColors;
ColorGroup(int id) :
Resource(id){
// empty
}
~ColorGroup() override = default;
ResourceType getType() const override {
return ResourceType::RT_ColorGroup;
}
};
class BaseMaterials : public Resource {
public:
std::vector<unsigned int> mMaterialIndex;

View File

@ -98,6 +98,11 @@ namespace XmlTag {
const char *const texture_cuurd_u = "u";
const char *const texture_cuurd_v = "v";
// vertex color definitions
const char *const colorgroup = "m:colorgroup";
const char *const color_item = "m:color";
const char *const color_vaule = "color";
// Meta info tags
const char* const CONTENT_TYPES_ARCHIVE = "[Content_Types].xml";
const char* const ROOT_RELATIONSHIPS_ARCHIVE = "_rels/.rels";

View File

@ -119,9 +119,9 @@ public:
static bool IsEmbeddedTexture( const std::string &filename ) {
const std::string extension = BaseImporter::GetExtension(filename);
if (extension == "jpg" || extension == "png") {
if (extension == "jpg" || extension == "png" || extension == "jpeg") {
std::string::size_type pos = filename.find("thumbnail");
if (pos == std::string::npos) {
if (pos != std::string::npos) {
return false;
}
return true;

View File

@ -75,7 +75,7 @@ aiFace ReadTriangle(XmlNode &node, int &texId0, int &texId1, int &texId2) {
face.mIndices[1] = static_cast<unsigned int>(std::atoi(node.attribute(XmlTag::v2).as_string()));
face.mIndices[2] = static_cast<unsigned int>(std::atoi(node.attribute(XmlTag::v3).as_string()));
texId0 = texId1 = texId2 = -1;
texId0 = texId1 = texId2 = IdNotSet;
XmlParser::getIntAttribute(node, XmlTag::p1, texId0);
XmlParser::getIntAttribute(node, XmlTag::p2, texId1);
XmlParser::getIntAttribute(node, XmlTag::p3, texId2);
@ -236,6 +236,8 @@ void XmlSerializer::ImportXml(aiScene *scene) {
ReadBaseMaterials(currentNode);
} else if (currentNodeName == XmlTag::meta) {
ReadMetadata(currentNode);
} else if (currentNodeName == XmlTag::colorgroup) {
ReadColorGroup(currentNode);
}
}
StoreMaterialsInScene(scene);
@ -331,9 +333,49 @@ void XmlSerializer::ReadObject(XmlNode &node) {
if (hasPid) {
auto it = mResourcesDictionnary.find(pid);
if (hasPindex && it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_BaseMaterials) {
BaseMaterials *materials = static_cast<BaseMaterials *>(it->second);
mesh->mMaterialIndex = materials->mMaterialIndex[pindex];
if (hasPindex && it != mResourcesDictionnary.end()) {
if (it->second->getType() == ResourceType::RT_BaseMaterials) {
BaseMaterials *materials = static_cast<BaseMaterials *>(it->second);
mesh->mMaterialIndex = materials->mMaterialIndex[pindex];
} else if (it->second->getType() == ResourceType::RT_Texture2DGroup) {
Texture2DGroup *group = static_cast<Texture2DGroup *>(it->second);
if (mesh->mTextureCoords[0] == nullptr) {
mesh->mNumUVComponents[0] = 2;
for (unsigned int i = 1; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
mesh->mNumUVComponents[i] = 0;
}
const std::string name = ai_to_string(group->mTexId);
for (size_t i = 0; i < mMaterials.size(); ++i) {
if (name == mMaterials[i]->GetName().C_Str()) {
mesh->mMaterialIndex = static_cast<unsigned int>(i);
}
}
mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
for (unsigned int vertex_idx = 0; vertex_idx < mesh->mNumVertices; vertex_idx++) {
mesh->mTextureCoords[0][vertex_idx] =
aiVector3D(group->mTex2dCoords[pindex].x, group->mTex2dCoords[pindex].y, 0.0f);
}
} else {
for (unsigned int vertex_idx = 0; vertex_idx < mesh->mNumVertices; vertex_idx++) {
if (mesh->mTextureCoords[0][vertex_idx].z < 0) {
// use default
mesh->mTextureCoords[0][vertex_idx] =
aiVector3D(group->mTex2dCoords[pindex].x, group->mTex2dCoords[pindex].y, 0.0f);
}
}
}
}else if (it->second->getType() == ResourceType::RT_ColorGroup) {
if (mesh->mColors[0] == nullptr) {
mesh->mColors[0] = new aiColor4D[mesh->mNumVertices];
ColorGroup *group = static_cast<ColorGroup *>(it->second);
for (unsigned int vertex_idx = 0; vertex_idx < mesh->mNumVertices; vertex_idx++) {
mesh->mColors[0][vertex_idx] = group->mColors[pindex];
}
}
}
}
}
@ -415,27 +457,36 @@ void XmlSerializer::ImportTriangles(XmlNode &node, aiMesh *mesh) {
for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == XmlTag::triangle) {
int pid = IdNotSet, p1 = IdNotSet;
int pid = IdNotSet;
bool hasPid = getNodeAttribute(currentNode, D3MF::XmlTag::pid, pid);
bool hasP1 = getNodeAttribute(currentNode, D3MF::XmlTag::p1, p1);
int texId[3];
Texture2DGroup *group = nullptr;
aiFace face = ReadTriangle(currentNode, texId[0], texId[1], texId[2]);
if (hasPid && hasP1) {
int pindex[3];
aiFace face = ReadTriangle(currentNode, pindex[0], pindex[1], pindex[2]);
if (hasPid && (pindex[0] != IdNotSet || pindex[1] != IdNotSet || pindex[2] != IdNotSet)) {
auto it = mResourcesDictionnary.find(pid);
if (it != mResourcesDictionnary.end()) {
if (it->second->getType() == ResourceType::RT_BaseMaterials) {
BaseMaterials *baseMaterials = static_cast<BaseMaterials *>(it->second);
mesh->mMaterialIndex = baseMaterials->mMaterialIndex[p1];
auto update_material = [&](int idx) {
if (pindex[idx] != IdNotSet) {
mesh->mMaterialIndex = baseMaterials->mMaterialIndex[pindex[idx]];
}
};
update_material(0);
update_material(1);
update_material(2);
} else if (it->second->getType() == ResourceType::RT_Texture2DGroup) {
// Load texture coordinates into mesh, when any
Texture2DGroup *group = static_cast<Texture2DGroup *>(it->second); // fix bug
if (mesh->mTextureCoords[0] == nullptr) {
mesh->mNumUVComponents[0] = 2;
for (unsigned int i = 1; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
mesh->mNumUVComponents[i] = 0;
}
group = static_cast<Texture2DGroup *>(it->second);
const std::string name = ai_to_string(group->mTexId);
for (size_t i = 0; i < mMaterials.size(); ++i) {
if (name == mMaterials[i]->GetName().C_Str()) {
@ -443,21 +494,44 @@ void XmlSerializer::ImportTriangles(XmlNode &node, aiMesh *mesh) {
}
}
mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
for (unsigned int vertex_index = 0; vertex_index < mesh->mNumVertices; vertex_index++) {
mesh->mTextureCoords[0][vertex_index].z = IdNotSet;//mark not set
}
}
auto update_texture = [&](int idx) {
if (pindex[idx] != IdNotSet) {
size_t vertex_index = face.mIndices[idx];
mesh->mTextureCoords[0][vertex_index] =
aiVector3D(group->mTex2dCoords[pindex[idx]].x, group->mTex2dCoords[pindex[idx]].y, 0.0f);
}
};
update_texture(0);
update_texture(1);
update_texture(2);
} else if (it->second->getType() == ResourceType::RT_ColorGroup) {
// Load vertex color into mesh, when any
ColorGroup *group = static_cast<ColorGroup *>(it->second);
if (mesh->mColors[0] == nullptr) {
mesh->mColors[0] = new aiColor4D[mesh->mNumVertices];
}
auto update_color = [&](int idx) {
if (pindex[idx] != IdNotSet) {
size_t vertex_index = face.mIndices[idx];
mesh->mColors[0][vertex_index] = group->mColors[pindex[idx]];
}
};
update_color(0);
update_color(1);
update_color(2);
}
}
}
// Load texture coordinates into mesh, when any
if (group != nullptr) {
size_t i0 = face.mIndices[0];
size_t i1 = face.mIndices[1];
size_t i2 = face.mIndices[2];
mesh->mTextureCoords[0][i0] = aiVector3D(group->mTex2dCoords[texId[0]].x, group->mTex2dCoords[texId[0]].y, 0.0f);
mesh->mTextureCoords[0][i1] = aiVector3D(group->mTex2dCoords[texId[1]].x, group->mTex2dCoords[texId[1]].y, 0.0f);
mesh->mTextureCoords[0][i2] = aiVector3D(group->mTex2dCoords[texId[2]].x, group->mTex2dCoords[texId[2]].y, 0.0f);
}
faces.push_back(face);
}
}
@ -598,6 +672,38 @@ aiMaterial *XmlSerializer::readMaterialDef(XmlNode &node, unsigned int basemater
return material;
}
void XmlSerializer::ReadColor(XmlNode &node, ColorGroup *colorGroup) {
if (node.empty() || nullptr == colorGroup) {
return;
}
for (XmlNode currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == XmlTag::color_item) {
const char *color = currentNode.attribute(XmlTag::color_vaule).as_string();
aiColor4D color_value;
if (parseColor(color, color_value)) {
colorGroup->mColors.push_back(color_value);
}
}
}
}
void XmlSerializer::ReadColorGroup(XmlNode &node) {
if (node.empty()) {
return;
}
int id = IdNotSet;
if (!XmlParser::getIntAttribute(node, XmlTag::id, id)) {
return;
}
ColorGroup *group = new ColorGroup(id);
ReadColor(node, group);
mResourcesDictionnary.insert(std::make_pair(id, group));
}
void XmlSerializer::StoreMaterialsInScene(aiScene *scene) {
if (nullptr == scene) {
return;

View File

@ -57,6 +57,7 @@ class D3MFOpcPackage;
class Object;
class Texture2DGroup;
class EmbeddedTexture;
class ColorGroup;
class XmlSerializer {
public:
@ -78,6 +79,8 @@ private:
void ReadTextureGroup(XmlNode &node);
aiMaterial *readMaterialDef(XmlNode &node, unsigned int basematerialsId);
void StoreMaterialsInScene(aiScene *scene);
void ReadColorGroup(XmlNode &node);
void ReadColor(XmlNode &node, ColorGroup *colorGroup);
private:
struct MetaEntry {

View File

@ -1748,7 +1748,7 @@ void FBXExporter::WriteObjects ()
int64_t blendshape_uid = generate_uid();
mesh_uids.push_back(blendshape_uid);
bsnode.AddProperty(blendshape_uid);
bsnode.AddProperty(blendshape_name + FBX::SEPARATOR + "Blendshape");
bsnode.AddProperty(blendshape_name + FBX::SEPARATOR + "Geometry");
bsnode.AddProperty("Shape");
bsnode.AddChild("Version", int32_t(100));
bsnode.Begin(outstream, binary, indent);

View File

@ -3,7 +3,7 @@
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -69,14 +69,6 @@ static constexpr aiImporterDesc desc = {
"xml irrmesh"
};
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
IRRMeshImporter::IRRMeshImporter() = default;
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
IRRMeshImporter::~IRRMeshImporter() = default;
// ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file.
bool IRRMeshImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
@ -116,8 +108,9 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
// Check whether we can read from the file
if (file == nullptr)
if (file == nullptr) {
throw DeadlyImportError("Failed to open IRRMESH file ", pFile);
}
// Construct the irrXML parser
XmlParser parser;
@ -148,13 +141,11 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
// int vertexFormat = 0; // 0 = normal; 1 = 2 tcoords, 2 = tangents
bool useColors = false;
/*
** irrmesh files have a top level <mesh> owning multiple <buffer> nodes.
** Each <buffer> contains <material>, <vertices>, and <indices>
** <material> tags here directly owns the material data specs
** <vertices> are a vertex per line, contains position, UV1 coords, maybe UV2, normal, tangent, bitangent
** <boundingbox> is ignored, I think assimp recalculates those?
*/
// irrmesh files have a top level <mesh> owning multiple <buffer> nodes.
// Each <buffer> contains <material>, <vertices>, and <indices>
// <material> tags here directly owns the material data specs
// <vertices> are a vertex per line, contains position, UV1 coords, maybe UV2, normal, tangent, bitangent
// <boundingbox> is ignored, I think assimp recalculates those?
// Parse the XML file
pugi::xml_node const &meshNode = root.child("mesh");
@ -201,7 +192,6 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
// This is possible ... remove the mesh from the list and skip further reading
ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero vertices");
releaseMaterial(&curMat);
// releaseMesh(&curMesh);
continue; // Bail out early
};
@ -331,7 +321,8 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
// NOTE this might explode for UTF-16 and wchars
const char *sz = indicesNode.text().get();
const char *end = sz + std::strlen(sz) + 1;
const char *end = sz + std::strlen(sz);
// For each index loop over aiMesh faces
while (SkipSpacesAndLineEnd(&sz, end)) {
if (curFace >= faceEnd) {
@ -377,8 +368,9 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
}
}
// We should be at the end of mFaces
if (curFace != faceEnd)
if (curFace != faceEnd) {
ASSIMP_LOG_ERROR("IRRMESH: Not enough indices");
}
}
// Finish processing the mesh - do some small material workarounds
@ -388,8 +380,7 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
aiMaterial *mat = (aiMaterial *)curMat;
mat->AddProperty(&curColors[0].a, 1, AI_MATKEY_OPACITY);
}
// textMeaning = 2;
// end of previous buffer. A material and a mesh should be there
if (!curMat || !curMesh) {
ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material");

View File

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -62,8 +62,11 @@ namespace Assimp {
*/
class IRRMeshImporter : public BaseImporter, public IrrlichtBase {
public:
IRRMeshImporter();
~IRRMeshImporter() override;
/// @brief The class constructor.
IRRMeshImporter() = default;
/// @brief The class destructor.
~IRRMeshImporter() override = default;
// -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file.

View File

@ -3,7 +3,7 @@
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -155,7 +155,8 @@ const aiImporterDesc *LWSImporter::GetInfo() const {
}
static constexpr int MagicHackNo = 150392;
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
// Setup configuration properties
void LWSImporter::SetupProperties(const Importer *pImp) {
// AI_CONFIG_FAVOUR_SPEED
@ -248,13 +249,12 @@ void LWSImporter::ReadEnvelope(const LWS::Element &dad, LWO::Envelope &fill) {
// Read animation channels in the old LightWave animation format
void LWSImporter::ReadEnvelope_Old(std::list<LWS::Element>::const_iterator &it,const std::list<LWS::Element>::const_iterator &endIt,
LWS::NodeDesc &nodes, unsigned int) {
unsigned int num=0, sub_num=0;
if (++it == endIt) {
ASSIMP_LOG_ERROR("LWS: Encountered unexpected end of file while parsing object motion");
return;
}
num = strtoul10((*it).tokens[0].c_str());
const unsigned int num = strtoul10((*it).tokens[0].c_str());
for (unsigned int i = 0; i < num; ++i) {
nodes.channels.emplace_back();
LWO::Envelope &envl = nodes.channels.back();
@ -266,8 +266,8 @@ void LWSImporter::ReadEnvelope_Old(std::list<LWS::Element>::const_iterator &it,c
ASSIMP_LOG_ERROR("LWS: Encountered unexpected end of file while parsing object motion");
return;
}
sub_num = strtoul10((*it).tokens[0].c_str());
const unsigned int sub_num = strtoul10((*it).tokens[0].c_str());
for (unsigned int n = 0; n < sub_num; ++n) {
if (++it == endIt) {
ASSIMP_LOG_ERROR("LWS: Encountered unexpected end of file while parsing object motion");
@ -283,7 +283,7 @@ void LWSImporter::ReadEnvelope_Old(std::list<LWS::Element>::const_iterator &it,c
fast_atoreal_move<float>((*it).tokens[0].c_str(), f);
key.time = f;
envl.keys.push_back(key);
envl.keys.emplace_back(key);
}
}
}

View File

@ -359,10 +359,18 @@ void XFileImporter::CreateMeshes(aiScene *pScene, aiNode *pNode, const std::vect
// set up a vertex-linear array of the weights for quick searching if a bone influences a vertex
std::vector<ai_real> oldWeights(sourceMesh->mPositions.size(), 0.0);
for (unsigned int d = 0; d < obone.mWeights.size(); ++d) {
const unsigned int boneIdx = obone.mWeights[d].mVertex;
if (boneIdx < obone.mWeights.size()) {
// TODO The conditional against boneIdx which was added in commit f844c33
// TODO (https://github.com/assimp/assimp/commit/f844c3397d7726477ab0fdca8efd3df56c18366b)
// TODO causes massive breakage as detailed in:
// TODO https://github.com/assimp/assimp/issues/5332
// TODO In cases like this unit tests are less useful, since the model still has
// TODO meshes, textures, animations etc. and asserts against these values may pass;
// TODO when touching importer code, it is crucial that developers also run manual, visual
// TODO checks to ensure there's no obvious breakage _before_ commiting to main branch
//const unsigned int boneIdx = obone.mWeights[d].mVertex;
//if (boneIdx < obone.mWeights.size()) {
oldWeights[obone.mWeights[d].mVertex] = obone.mWeights[d].mWeight;
}
//}
}
// collect all vertex weights that influence a vertex in the new mesh

View File

@ -547,7 +547,7 @@ struct BufferView : public Object {
BufferViewTarget target; //! The target that the WebGL buffer should be bound to.
void Read(Value &obj, Asset &r);
uint8_t *GetPointer(size_t accOffset);
uint8_t *GetPointerAndTailSize(size_t accOffset, size_t& outTailSize);
};
//! A typed view into a BufferView. A BufferView contains raw binary data.
@ -629,7 +629,7 @@ struct Accessor : public Object {
std::vector<uint8_t> data; //!< Actual data, which may be defaulted to an array of zeros or the original data, with the sparse buffer view applied on top of it.
void PopulateData(size_t numBytes, uint8_t *bytes);
void PopulateData(size_t numBytes, const uint8_t *bytes);
void PatchData(unsigned int elementSize);
};
};

View File

@ -785,12 +785,14 @@ inline void BufferView::Read(Value &obj, Asset &r) {
}
}
inline uint8_t *BufferView::GetPointer(size_t accOffset) {
inline uint8_t *BufferView::GetPointerAndTailSize(size_t accOffset, size_t& outTailSize) {
if (!buffer) {
outTailSize = 0;
return nullptr;
}
uint8_t *basePtr = buffer->GetPointer();
uint8_t * const basePtr = buffer->GetPointer();
if (!basePtr) {
outTailSize = 0;
return nullptr;
}
@ -799,17 +801,25 @@ inline uint8_t *BufferView::GetPointer(size_t accOffset) {
const size_t begin = buffer->EncodedRegion_Current->Offset;
const size_t end = begin + buffer->EncodedRegion_Current->DecodedData_Length;
if ((offset >= begin) && (offset < end)) {
outTailSize = end - offset;
return &buffer->EncodedRegion_Current->DecodedData[offset - begin];
}
}
if (offset >= buffer->byteLength)
{
outTailSize = 0;
return nullptr;
}
outTailSize = buffer->byteLength - offset;
return basePtr + offset;
}
//
// struct Accessor
//
inline void Accessor::Sparse::PopulateData(size_t numBytes, uint8_t *bytes) {
inline void Accessor::Sparse::PopulateData(size_t numBytes, const uint8_t *bytes) {
if (bytes) {
data.assign(bytes, bytes + numBytes);
} else {
@ -818,11 +828,21 @@ inline void Accessor::Sparse::PopulateData(size_t numBytes, uint8_t *bytes) {
}
inline void Accessor::Sparse::PatchData(unsigned int elementSize) {
uint8_t *pIndices = indices->GetPointer(indicesByteOffset);
size_t indicesTailDataSize;
uint8_t *pIndices = indices->GetPointerAndTailSize(indicesByteOffset, indicesTailDataSize);
const unsigned int indexSize = int(ComponentTypeSize(indicesType));
uint8_t *indicesEnd = pIndices + count * indexSize;
uint8_t *pValues = values->GetPointer(valuesByteOffset);
if ((uint64_t)indicesEnd > (uint64_t)pIndices + indicesTailDataSize) {
throw DeadlyImportError("Invalid sparse accessor. Indices outside allocated memory.");
}
size_t valuesTailDataSize;
uint8_t* pValues = values->GetPointerAndTailSize(valuesByteOffset, valuesTailDataSize);
if (elementSize * count > valuesTailDataSize) {
throw DeadlyImportError("Invalid sparse accessor. Indices outside allocated memory.");
}
while (pIndices != indicesEnd) {
size_t offset;
switch (indicesType) {
@ -894,6 +914,9 @@ inline void Accessor::Read(Value &obj, Asset &r) {
if (Value *indicesValue = FindObject(*sparseValue, "indices")) {
//indices bufferView
Value *indiceViewID = FindUInt(*indicesValue, "bufferView");
if (!indiceViewID) {
throw DeadlyImportError("A bufferView value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
}
sparse->indices = r.bufferViews.Retrieve(indiceViewID->GetUint());
//indices byteOffset
sparse->indicesByteOffset = MemberOrDefault(*indicesValue, "byteOffset", size_t(0));
@ -909,6 +932,9 @@ inline void Accessor::Read(Value &obj, Asset &r) {
if (Value *valuesValue = FindObject(*sparseValue, "values")) {
//value bufferView
Value *valueViewID = FindUInt(*valuesValue, "bufferView");
if (!valueViewID) {
throw DeadlyImportError("A bufferView value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
}
sparse->values = r.bufferViews.Retrieve(valueViewID->GetUint());
//value byteOffset
sparse->valuesByteOffset = MemberOrDefault(*valuesValue, "byteOffset", size_t(0));
@ -918,8 +944,18 @@ inline void Accessor::Read(Value &obj, Asset &r) {
const unsigned int elementSize = GetElementSize();
const size_t dataSize = count * elementSize;
sparse->PopulateData(dataSize, bufferView ? bufferView->GetPointer(byteOffset) : nullptr);
sparse->PatchData(elementSize);
if (bufferView) {
size_t bufferViewTailSize;
const uint8_t* bufferViewPointer = bufferView->GetPointerAndTailSize(byteOffset, bufferViewTailSize);
if (dataSize > bufferViewTailSize) {
throw DeadlyImportError("Invalid buffer when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
}
sparse->PopulateData(dataSize, bufferViewPointer);
}
else {
sparse->PopulateData(dataSize, nullptr);
}
sparse->PatchData(elementSize);
}
}

View File

@ -75,124 +75,129 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) {
ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess begin");
unsigned int redundantRemoved = 0, unreferencedRemoved = 0;
if (pScene->mNumMaterials) {
// Find out which materials are referenced by meshes
std::vector<bool> abReferenced(pScene->mNumMaterials,false);
for (unsigned int i = 0;i < pScene->mNumMeshes;++i)
abReferenced[pScene->mMeshes[i]->mMaterialIndex] = true;
if (pScene->mNumMaterials == 0) {
return;
}
// Find out which materials are referenced by meshes
std::vector<bool> abReferenced(pScene->mNumMaterials,false);
for (unsigned int i = 0;i < pScene->mNumMeshes;++i)
abReferenced[pScene->mMeshes[i]->mMaterialIndex] = true;
// If a list of materials to be excluded was given, match the list with
// our imported materials and 'salt' all positive matches to ensure that
// we get unique hashes later.
if (mConfigFixedMaterials.length()) {
// If a list of materials to be excluded was given, match the list with
// our imported materials and 'salt' all positive matches to ensure that
// we get unique hashes later.
if (mConfigFixedMaterials.length()) {
std::list<std::string> strings;
ConvertListToStrings(mConfigFixedMaterials,strings);
std::list<std::string> strings;
ConvertListToStrings(mConfigFixedMaterials,strings);
for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
aiMaterial* mat = pScene->mMaterials[i];
for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
aiMaterial* mat = pScene->mMaterials[i];
aiString name;
mat->Get(AI_MATKEY_NAME,name);
aiString name;
mat->Get(AI_MATKEY_NAME,name);
if (name.length) {
std::list<std::string>::const_iterator it = std::find(strings.begin(), strings.end(), name.data);
if (it != strings.end()) {
if (name.length) {
std::list<std::string>::const_iterator it = std::find(strings.begin(), strings.end(), name.data);
if (it != strings.end()) {
// Our brilliant 'salt': A single material property with ~ as first
// character to mark it as internal and temporary.
const int dummy = 1;
((aiMaterial*)mat)->AddProperty(&dummy,1,"~RRM.UniqueMaterial",0,0);
// Our brilliant 'salt': A single material property with ~ as first
// character to mark it as internal and temporary.
const int dummy = 1;
((aiMaterial*)mat)->AddProperty(&dummy,1,"~RRM.UniqueMaterial",0,0);
// Keep this material even if no mesh references it
abReferenced[i] = true;
ASSIMP_LOG_VERBOSE_DEBUG( "Found positive match in exclusion list: \'", name.data, "\'");
}
// Keep this material even if no mesh references it
abReferenced[i] = true;
ASSIMP_LOG_VERBOSE_DEBUG( "Found positive match in exclusion list: \'", name.data, "\'");
}
}
}
}
// TODO: re-implement this algorithm to work in-place
unsigned int *aiMappingTable = new unsigned int[pScene->mNumMaterials];
for ( unsigned int i=0; i<pScene->mNumMaterials; i++ ) {
aiMappingTable[ i ] = 0;
// TODO: re-implement this algorithm to work in-place
unsigned int *aiMappingTable = new unsigned int[pScene->mNumMaterials];
for ( unsigned int i=0; i<pScene->mNumMaterials; i++ ) {
aiMappingTable[ i ] = 0;
}
unsigned int iNewNum = 0;
// Iterate through all materials and calculate a hash for them
// store all hashes in a list and so a quick search whether
// we do already have a specific hash. This allows us to
// determine which materials are identical.
uint32_t *aiHashes = new uint32_t[ pScene->mNumMaterials ];;
for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
// No mesh is referencing this material, remove it.
if (!abReferenced[i]) {
++unreferencedRemoved;
delete pScene->mMaterials[i];
pScene->mMaterials[i] = nullptr;
continue;
}
unsigned int iNewNum = 0;
// Iterate through all materials and calculate a hash for them
// store all hashes in a list and so a quick search whether
// we do already have a specific hash. This allows us to
// determine which materials are identical.
uint32_t *aiHashes = new uint32_t[ pScene->mNumMaterials ];;
for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
// No mesh is referencing this material, remove it.
if (!abReferenced[i]) {
++unreferencedRemoved;
// Check all previously mapped materials for a matching hash.
// On a match we can delete this material and just make it ref to the same index.
uint32_t me = aiHashes[i] = ComputeMaterialHash(pScene->mMaterials[i]);
for (unsigned int a = 0; a < i;++a) {
if (abReferenced[a] && me == aiHashes[a]) {
++redundantRemoved;
me = 0;
aiMappingTable[i] = aiMappingTable[a];
delete pScene->mMaterials[i];
pScene->mMaterials[i] = nullptr;
break;
}
}
// This is a new material that is referenced, add to the map.
if (me) {
aiMappingTable[i] = iNewNum++;
}
}
// If the new material count differs from the original,
// we need to rebuild the material list and remap mesh material indexes.
if (iNewNum < 1) {
//throw DeadlyImportError("No materials remaining");
return;
}
if (iNewNum != pScene->mNumMaterials) {
ai_assert(iNewNum > 0);
aiMaterial** ppcMaterials = new aiMaterial*[iNewNum];
::memset(ppcMaterials,0,sizeof(void*)*iNewNum);
for (unsigned int p = 0; p < pScene->mNumMaterials;++p)
{
// if the material is not referenced ... remove it
if (!abReferenced[p]) {
continue;
}
// Check all previously mapped materials for a matching hash.
// On a match we can delete this material and just make it ref to the same index.
uint32_t me = aiHashes[i] = ComputeMaterialHash(pScene->mMaterials[i]);
for (unsigned int a = 0; a < i;++a) {
if (abReferenced[a] && me == aiHashes[a]) {
++redundantRemoved;
me = 0;
aiMappingTable[i] = aiMappingTable[a];
delete pScene->mMaterials[i];
pScene->mMaterials[i] = nullptr;
break;
// generate new names for modified materials that had no names
const unsigned int idx = aiMappingTable[p];
if (ppcMaterials[idx]) {
aiString sz;
if( ppcMaterials[idx]->Get(AI_MATKEY_NAME, sz) != AI_SUCCESS ) {
sz.length = ::ai_snprintf(sz.data,MAXLEN,"JoinedMaterial_#%u",p);
((aiMaterial*)ppcMaterials[idx])->AddProperty(&sz,AI_MATKEY_NAME);
}
}
// This is a new material that is referenced, add to the map.
if (me) {
aiMappingTable[i] = iNewNum++;
} else {
ppcMaterials[idx] = pScene->mMaterials[p];
}
}
// If the new material count differs from the original,
// we need to rebuild the material list and remap mesh material indexes.
if(iNewNum < 1)
throw DeadlyImportError("No materials remaining");
if (iNewNum != pScene->mNumMaterials) {
ai_assert(iNewNum > 0);
aiMaterial** ppcMaterials = new aiMaterial*[iNewNum];
::memset(ppcMaterials,0,sizeof(void*)*iNewNum);
for (unsigned int p = 0; p < pScene->mNumMaterials;++p)
{
// if the material is not referenced ... remove it
if (!abReferenced[p]) {
continue;
}
// generate new names for modified materials that had no names
const unsigned int idx = aiMappingTable[p];
if (ppcMaterials[idx]) {
aiString sz;
if( ppcMaterials[idx]->Get(AI_MATKEY_NAME, sz) != AI_SUCCESS ) {
sz.length = ::ai_snprintf(sz.data,MAXLEN,"JoinedMaterial_#%u",p);
((aiMaterial*)ppcMaterials[idx])->AddProperty(&sz,AI_MATKEY_NAME);
}
} else {
ppcMaterials[idx] = pScene->mMaterials[p];
}
}
// update all material indices
for (unsigned int p = 0; p < pScene->mNumMeshes;++p) {
aiMesh* mesh = pScene->mMeshes[p];
ai_assert(nullptr != mesh);
mesh->mMaterialIndex = aiMappingTable[mesh->mMaterialIndex];
}
// delete the old material list
delete[] pScene->mMaterials;
pScene->mMaterials = ppcMaterials;
pScene->mNumMaterials = iNewNum;
// update all material indices
for (unsigned int p = 0; p < pScene->mNumMeshes;++p) {
aiMesh* mesh = pScene->mMeshes[p];
ai_assert(nullptr != mesh);
mesh->mMaterialIndex = aiMappingTable[mesh->mMaterialIndex];
}
// delete temporary storage
delete[] aiHashes;
delete[] aiMappingTable;
// delete the old material list
delete[] pScene->mMaterials;
pScene->mMaterials = ppcMaterials;
pScene->mNumMaterials = iNewNum;
}
// delete temporary storage
delete[] aiHashes;
delete[] aiMappingTable;
if (redundantRemoved == 0 && unreferencedRemoved == 0) {
ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess finished ");
} else {

View File

@ -12,7 +12,6 @@ __Importers__:
- ASE
- ASK
- B3D
- [BLEND](https://en.wikipedia.org/wiki/.blend_(file_format))
- [BVH](https://en.wikipedia.org/wiki/Biovision_Hierarchy)
- CSM
- COB
@ -66,6 +65,9 @@ __Importers__:
- XGL
- ZGL
Note: support for [BLEND](https://en.wikipedia.org/wiki/.blend_(file_format)) is deprecated.
It is too time-consuming to maintain an undocumented format which contains so much more than we need.
Additionally, some formats are supported by dependency on non-free code or external SDKs (not built by default):
- [C4D](https://en.wikipedia.org/wiki/Cinema_4D) (https://github.com/assimp/assimp/wiki/Cinema4D-&-Melange) IMporting geometry + node hierarchy are currently supported

View File

@ -518,20 +518,19 @@ int CDisplay::AddTextureToDisplayList(unsigned int iType,
return 1;
}
//-------------------------------------------------------------------------------
int CDisplay::AddMaterialToDisplayList(HTREEITEM hRoot,
unsigned int iIndex)
{
int CDisplay::AddMaterialToDisplayList(HTREEITEM hRoot, unsigned int iIndex) {
ai_assert(nullptr != hRoot);
aiMaterial* pcMat = g_pcAsset->pcScene->mMaterials[iIndex];
if (g_pcAsset->pcScene->mNumMeshes == 0) {
return -1;
}
// find the first mesh using this material index
unsigned int iMesh = 0;
for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
{
if (iIndex == g_pcAsset->pcScene->mMeshes[i]->mMaterialIndex)
{
for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i) {
if (iIndex == g_pcAsset->pcScene->mMeshes[i]->mMaterialIndex) {
iMesh = i;
break;
}
@ -540,12 +539,9 @@ int CDisplay::AddMaterialToDisplayList(HTREEITEM hRoot,
// use the name of the material, if possible
char chTemp[512];
aiString szOut;
if (AI_SUCCESS != aiGetMaterialString(pcMat,AI_MATKEY_NAME,&szOut))
{
if (AI_SUCCESS != aiGetMaterialString(pcMat,AI_MATKEY_NAME,&szOut)) {
ai_snprintf(chTemp,512,"Material %i",iIndex+1);
}
else
{
} else {
ai_snprintf(chTemp,512,"%s (%i)",szOut.data,iIndex+1);
}
TVITEMEXW tvi;
@ -577,17 +573,15 @@ int CDisplay::AddMaterialToDisplayList(HTREEITEM hRoot,
aiTextureOp eOp;
aiString szPath;
bool bNoOpacity = true;
for (unsigned int i = 0; i <= AI_TEXTURE_TYPE_MAX;++i)
{
for (unsigned int i = 0; i <= AI_TEXTURE_TYPE_MAX;++i) {
unsigned int iNum = 0;
while (true)
{
if (AI_SUCCESS != aiGetMaterialTexture(pcMat,(aiTextureType)i,iNum,
&szPath,nullptr, &iUV,&fBlend,&eOp))
{
while (true) {
if (AI_SUCCESS != aiGetMaterialTexture(pcMat,(aiTextureType)i,iNum, &szPath,nullptr, &iUV,&fBlend,&eOp)) {
break;
}
if (aiTextureType_OPACITY == i)bNoOpacity = false;
if (aiTextureType_OPACITY == i) {
bNoOpacity = false;
}
AddTextureToDisplayList(i,iNum,&szPath,hTexture,iUV,fBlend,eOp,iMesh);
++iNum;
}
@ -595,8 +589,7 @@ int CDisplay::AddMaterialToDisplayList(HTREEITEM hRoot,
AssetHelper::MeshHelper* pcMesh = g_pcAsset->apcMeshes[iMesh];
if (pcMesh->piDiffuseTexture && pcMesh->piDiffuseTexture == pcMesh->piOpacityTexture && bNoOpacity)
{
if (pcMesh->piDiffuseTexture && pcMesh->piDiffuseTexture == pcMesh->piOpacityTexture && bNoOpacity) {
// check whether the diffuse texture is not a default texture
// {9785DA94-1D96-426b-B3CB-BADC36347F5E}
@ -606,9 +599,7 @@ int CDisplay::AddMaterialToDisplayList(HTREEITEM hRoot,
uint32_t iData = 0;
DWORD dwSize = 4;
if(FAILED( pcMesh->piDiffuseTexture->GetPrivateData(guidPrivateData,&iData,&dwSize) ||
0xffffffff == iData))
{
if(FAILED( pcMesh->piDiffuseTexture->GetPrivateData(guidPrivateData,&iData,&dwSize) || 0xffffffff == iData)) {
// seems the diffuse texture contains alpha, therefore it has been
// added to the opacity channel, too. Add a special value ...
AddTextureToDisplayList(aiTextureType_OPACITY | 0x40000000,
@ -625,33 +616,26 @@ int CDisplay::AddMaterialToDisplayList(HTREEITEM hRoot,
this->AddMaterial(info);
return 1;
}
//-------------------------------------------------------------------------------
// Expand all elements in the tree-view
int CDisplay::ExpandTree()
{
int CDisplay::ExpandTree() {
// expand all materials
for (std::vector< MaterialInfo >::iterator
i = m_asMaterials.begin();
i != m_asMaterials.end();++i)
{
for (std::vector< MaterialInfo >::iterator i = m_asMaterials.begin(); i != m_asMaterials.end();++i) {
TreeView_Expand(GetDlgItem(g_hDlg,IDC_TREE1),(*i).hTreeItem,TVE_EXPAND);
}
// expand all nodes
for (std::vector< NodeInfo >::iterator
i = m_asNodes.begin();
i != m_asNodes.end();++i)
{
for (std::vector< NodeInfo >::iterator i = m_asNodes.begin(); i != m_asNodes.end();++i) {
TreeView_Expand(GetDlgItem(g_hDlg,IDC_TREE1),(*i).hTreeItem,TVE_EXPAND);
}
TreeView_Expand(GetDlgItem(g_hDlg,IDC_TREE1),m_hRoot,TVE_EXPAND);
return 1;
}
//-------------------------------------------------------------------------------
// Get image list for tree view
int CDisplay::LoadImageList(void)
{
if (!m_hImageList)
{
int CDisplay::LoadImageList() {
if (!m_hImageList) {
// First, create the image list we will need.
// FIX: Need RGB888 color space to display all colors correctly
HIMAGELIST hIml = ImageList_Create( 16,16,ILC_COLOR24, 5, 0 );
@ -682,12 +666,13 @@ int CDisplay::LoadImageList(void)
m_hImageList = hIml;
}
return 1;
}
//-------------------------------------------------------------------------------
// Fill tree view
int CDisplay::FillDisplayList(void)
{
int CDisplay::FillDisplayList(void) {
LoadImageList();
// Initialize the tree view window.
@ -713,11 +698,11 @@ int CDisplay::FillDisplayList(void)
(LPARAM)(LPTVINSERTSTRUCT)&sNew);
// add each loaded material to the tree
for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMaterials;++i)
for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMaterials; ++i)
AddMaterialToDisplayList(m_hRoot,i);
// add each mesh to the tree
for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes; ++i)
AddMeshToDisplayList(i,m_hRoot);
// now add all loaded nodes recursively
@ -729,8 +714,10 @@ int CDisplay::FillDisplayList(void)
// everything reacts a little bit slowly if D3D is rendering,
// so give GDI a small hint to leave the couch and work ;-)
UpdateWindow(g_hDlg);
return 1;
}
//-------------------------------------------------------------------------------
// Main render loop
int CDisplay::OnRender()