Merge branch 'master' into master

pull/5450/head
sSsA01 2024-02-06 17:49:07 +09:00 committed by GitHub
commit 37bd87a4f6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 317 additions and 136 deletions

View File

@ -54,7 +54,7 @@ jobs:
- name: Cache DX SDK - name: Cache DX SDK
id: dxcache id: dxcache
if: contains(matrix.name, 'windows') if: contains(matrix.name, 'windows')
uses: actions/cache@v3 uses: actions/cache@v4
with: with:
path: '${{ github.workspace }}/DX_SDK' path: '${{ github.workspace }}/DX_SDK'
key: ${{ runner.os }}-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) IF(ASSIMP_HUNTER_ENABLED)
include("cmake-modules/HunterGate.cmake") include("cmake-modules/HunterGate.cmake")
HunterGate( HunterGate(
URL "https://github.com/cpp-pm/hunter/archive/v0.24.18.tar.gz" URL "https://github.com/cpp-pm/hunter/archive/v0.25.3.tar.gz"
SHA1 "1292e4d661e1770d6d6ca08c12c07cf34a0bf718" SHA1 "3319fe6a3b08090df7df98dee75134d68e2ef5a3"
) )
add_definitions(-DASSIMP_USE_HUNTER) add_definitions(-DASSIMP_USE_HUNTER)
ENDIF() ENDIF()

View File

@ -57,6 +57,7 @@ enum class ResourceType {
RT_BaseMaterials, RT_BaseMaterials,
RT_EmbeddedTexture2D, RT_EmbeddedTexture2D,
RT_Texture2DGroup, RT_Texture2DGroup,
RT_ColorGroup,
RT_Unknown RT_Unknown
}; // To be extended with other resource types (eg. material extension resources like Texture2d, Texture2dGroup...) }; // 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 { class BaseMaterials : public Resource {
public: public:
std::vector<unsigned int> mMaterialIndex; 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_u = "u";
const char *const texture_cuurd_v = "v"; 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 // Meta info tags
const char* const CONTENT_TYPES_ARCHIVE = "[Content_Types].xml"; const char* const CONTENT_TYPES_ARCHIVE = "[Content_Types].xml";
const char* const ROOT_RELATIONSHIPS_ARCHIVE = "_rels/.rels"; const char* const ROOT_RELATIONSHIPS_ARCHIVE = "_rels/.rels";

View File

@ -119,9 +119,9 @@ public:
static bool IsEmbeddedTexture( const std::string &filename ) { static bool IsEmbeddedTexture( const std::string &filename ) {
const std::string extension = BaseImporter::GetExtension(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"); std::string::size_type pos = filename.find("thumbnail");
if (pos == std::string::npos) { if (pos != std::string::npos) {
return false; return false;
} }
return true; 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[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())); 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::p1, texId0);
XmlParser::getIntAttribute(node, XmlTag::p2, texId1); XmlParser::getIntAttribute(node, XmlTag::p2, texId1);
XmlParser::getIntAttribute(node, XmlTag::p3, texId2); XmlParser::getIntAttribute(node, XmlTag::p3, texId2);
@ -236,6 +236,8 @@ void XmlSerializer::ImportXml(aiScene *scene) {
ReadBaseMaterials(currentNode); ReadBaseMaterials(currentNode);
} else if (currentNodeName == XmlTag::meta) { } else if (currentNodeName == XmlTag::meta) {
ReadMetadata(currentNode); ReadMetadata(currentNode);
} else if (currentNodeName == XmlTag::colorgroup) {
ReadColorGroup(currentNode);
} }
} }
StoreMaterialsInScene(scene); StoreMaterialsInScene(scene);
@ -331,9 +333,49 @@ void XmlSerializer::ReadObject(XmlNode &node) {
if (hasPid) { if (hasPid) {
auto it = mResourcesDictionnary.find(pid); auto it = mResourcesDictionnary.find(pid);
if (hasPindex && it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_BaseMaterials) { if (hasPindex && it != mResourcesDictionnary.end()) {
BaseMaterials *materials = static_cast<BaseMaterials *>(it->second); if (it->second->getType() == ResourceType::RT_BaseMaterials) {
mesh->mMaterialIndex = materials->mMaterialIndex[pindex]; 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()) { for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name(); const std::string currentName = currentNode.name();
if (currentName == XmlTag::triangle) { if (currentName == XmlTag::triangle) {
int pid = IdNotSet, p1 = IdNotSet; int pid = IdNotSet;
bool hasPid = getNodeAttribute(currentNode, D3MF::XmlTag::pid, pid); bool hasPid = getNodeAttribute(currentNode, D3MF::XmlTag::pid, pid);
bool hasP1 = getNodeAttribute(currentNode, D3MF::XmlTag::p1, p1);
int texId[3]; int pindex[3];
Texture2DGroup *group = nullptr; aiFace face = ReadTriangle(currentNode, pindex[0], pindex[1], pindex[2]);
aiFace face = ReadTriangle(currentNode, texId[0], texId[1], texId[2]); if (hasPid && (pindex[0] != IdNotSet || pindex[1] != IdNotSet || pindex[2] != IdNotSet)) {
if (hasPid && hasP1) {
auto it = mResourcesDictionnary.find(pid); auto it = mResourcesDictionnary.find(pid);
if (it != mResourcesDictionnary.end()) { if (it != mResourcesDictionnary.end()) {
if (it->second->getType() == ResourceType::RT_BaseMaterials) { if (it->second->getType() == ResourceType::RT_BaseMaterials) {
BaseMaterials *baseMaterials = static_cast<BaseMaterials *>(it->second); 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) { } 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) { if (mesh->mTextureCoords[0] == nullptr) {
mesh->mNumUVComponents[0] = 2; mesh->mNumUVComponents[0] = 2;
for (unsigned int i = 1; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { for (unsigned int i = 1; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
mesh->mNumUVComponents[i] = 0; mesh->mNumUVComponents[i] = 0;
} }
group = static_cast<Texture2DGroup *>(it->second);
const std::string name = ai_to_string(group->mTexId); const std::string name = ai_to_string(group->mTexId);
for (size_t i = 0; i < mMaterials.size(); ++i) { for (size_t i = 0; i < mMaterials.size(); ++i) {
if (name == mMaterials[i]->GetName().C_Str()) { 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]; 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); faces.push_back(face);
} }
} }
@ -598,6 +672,38 @@ aiMaterial *XmlSerializer::readMaterialDef(XmlNode &node, unsigned int basemater
return material; 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) { void XmlSerializer::StoreMaterialsInScene(aiScene *scene) {
if (nullptr == scene) { if (nullptr == scene) {
return; return;

View File

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

View File

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

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 // 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); std::vector<ai_real> oldWeights(sourceMesh->mPositions.size(), 0.0);
for (unsigned int d = 0; d < obone.mWeights.size(); ++d) { for (unsigned int d = 0; d < obone.mWeights.size(); ++d) {
const unsigned int boneIdx = obone.mWeights[d].mVertex; // TODO The conditional against boneIdx which was added in commit f844c33
if (boneIdx < obone.mWeights.size()) { // 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; oldWeights[obone.mWeights[d].mVertex] = obone.mWeights[d].mWeight;
} //}
} }
// collect all vertex weights that influence a vertex in the new mesh // 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. BufferViewTarget target; //! The target that the WebGL buffer should be bound to.
void Read(Value &obj, Asset &r); 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. //! 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. 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); 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) { if (!buffer) {
outTailSize = 0;
return nullptr; return nullptr;
} }
uint8_t *basePtr = buffer->GetPointer(); uint8_t * const basePtr = buffer->GetPointer();
if (!basePtr) { if (!basePtr) {
outTailSize = 0;
return nullptr; 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 begin = buffer->EncodedRegion_Current->Offset;
const size_t end = begin + buffer->EncodedRegion_Current->DecodedData_Length; const size_t end = begin + buffer->EncodedRegion_Current->DecodedData_Length;
if ((offset >= begin) && (offset < end)) { if ((offset >= begin) && (offset < end)) {
outTailSize = end - offset;
return &buffer->EncodedRegion_Current->DecodedData[offset - begin]; return &buffer->EncodedRegion_Current->DecodedData[offset - begin];
} }
} }
if (offset >= buffer->byteLength)
{
outTailSize = 0;
return nullptr;
}
outTailSize = buffer->byteLength - offset;
return basePtr + offset; return basePtr + offset;
} }
// //
// struct Accessor // 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) { if (bytes) {
data.assign(bytes, bytes + numBytes); data.assign(bytes, bytes + numBytes);
} else { } else {
@ -818,11 +828,21 @@ inline void Accessor::Sparse::PopulateData(size_t numBytes, uint8_t *bytes) {
} }
inline void Accessor::Sparse::PatchData(unsigned int elementSize) { 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)); const unsigned int indexSize = int(ComponentTypeSize(indicesType));
uint8_t *indicesEnd = pIndices + count * indexSize; 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) { while (pIndices != indicesEnd) {
size_t offset; size_t offset;
switch (indicesType) { switch (indicesType) {
@ -894,6 +914,9 @@ inline void Accessor::Read(Value &obj, Asset &r) {
if (Value *indicesValue = FindObject(*sparseValue, "indices")) { if (Value *indicesValue = FindObject(*sparseValue, "indices")) {
//indices bufferView //indices bufferView
Value *indiceViewID = FindUInt(*indicesValue, "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()); sparse->indices = r.bufferViews.Retrieve(indiceViewID->GetUint());
//indices byteOffset //indices byteOffset
sparse->indicesByteOffset = MemberOrDefault(*indicesValue, "byteOffset", size_t(0)); 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")) { if (Value *valuesValue = FindObject(*sparseValue, "values")) {
//value bufferView //value bufferView
Value *valueViewID = FindUInt(*valuesValue, "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()); sparse->values = r.bufferViews.Retrieve(valueViewID->GetUint());
//value byteOffset //value byteOffset
sparse->valuesByteOffset = MemberOrDefault(*valuesValue, "byteOffset", size_t(0)); 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 unsigned int elementSize = GetElementSize();
const size_t dataSize = count * elementSize; const size_t dataSize = count * elementSize;
sparse->PopulateData(dataSize, bufferView ? bufferView->GetPointer(byteOffset) : nullptr); if (bufferView) {
sparse->PatchData(elementSize); 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"); ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess begin");
unsigned int redundantRemoved = 0, unreferencedRemoved = 0; unsigned int redundantRemoved = 0, unreferencedRemoved = 0;
if (pScene->mNumMaterials) { if (pScene->mNumMaterials == 0) {
// Find out which materials are referenced by meshes return;
std::vector<bool> abReferenced(pScene->mNumMaterials,false); }
for (unsigned int i = 0;i < pScene->mNumMeshes;++i)
abReferenced[pScene->mMeshes[i]->mMaterialIndex] = true; // 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 // 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 // our imported materials and 'salt' all positive matches to ensure that
// we get unique hashes later. // we get unique hashes later.
if (mConfigFixedMaterials.length()) { if (mConfigFixedMaterials.length()) {
std::list<std::string> strings; std::list<std::string> strings;
ConvertListToStrings(mConfigFixedMaterials,strings); ConvertListToStrings(mConfigFixedMaterials,strings);
for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
aiMaterial* mat = pScene->mMaterials[i]; aiMaterial* mat = pScene->mMaterials[i];
aiString name; aiString name;
mat->Get(AI_MATKEY_NAME,name); mat->Get(AI_MATKEY_NAME,name);
if (name.length) { if (name.length) {
std::list<std::string>::const_iterator it = std::find(strings.begin(), strings.end(), name.data); std::list<std::string>::const_iterator it = std::find(strings.begin(), strings.end(), name.data);
if (it != strings.end()) { if (it != strings.end()) {
// Our brilliant 'salt': A single material property with ~ as first // Our brilliant 'salt': A single material property with ~ as first
// character to mark it as internal and temporary. // character to mark it as internal and temporary.
const int dummy = 1; const int dummy = 1;
((aiMaterial*)mat)->AddProperty(&dummy,1,"~RRM.UniqueMaterial",0,0); ((aiMaterial*)mat)->AddProperty(&dummy,1,"~RRM.UniqueMaterial",0,0);
// Keep this material even if no mesh references it // Keep this material even if no mesh references it
abReferenced[i] = true; abReferenced[i] = true;
ASSIMP_LOG_VERBOSE_DEBUG( "Found positive match in exclusion list: \'", name.data, "\'"); ASSIMP_LOG_VERBOSE_DEBUG( "Found positive match in exclusion list: \'", name.data, "\'");
}
} }
} }
} }
}
// TODO: re-implement this algorithm to work in-place // TODO: re-implement this algorithm to work in-place
unsigned int *aiMappingTable = new unsigned int[pScene->mNumMaterials]; unsigned int *aiMappingTable = new unsigned int[pScene->mNumMaterials];
for ( unsigned int i=0; i<pScene->mNumMaterials; i++ ) { for ( unsigned int i=0; i<pScene->mNumMaterials; i++ ) {
aiMappingTable[ i ] = 0; 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 // Check all previously mapped materials for a matching hash.
// store all hashes in a list and so a quick search whether // On a match we can delete this material and just make it ref to the same index.
// we do already have a specific hash. This allows us to uint32_t me = aiHashes[i] = ComputeMaterialHash(pScene->mMaterials[i]);
// determine which materials are identical. for (unsigned int a = 0; a < i;++a) {
uint32_t *aiHashes = new uint32_t[ pScene->mNumMaterials ];; if (abReferenced[a] && me == aiHashes[a]) {
for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { ++redundantRemoved;
// No mesh is referencing this material, remove it. me = 0;
if (!abReferenced[i]) { aiMappingTable[i] = aiMappingTable[a];
++unreferencedRemoved;
delete pScene->mMaterials[i]; delete pScene->mMaterials[i];
pScene->mMaterials[i] = nullptr; 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; continue;
} }
// Check all previously mapped materials for a matching hash. // generate new names for modified materials that had no names
// On a match we can delete this material and just make it ref to the same index. const unsigned int idx = aiMappingTable[p];
uint32_t me = aiHashes[i] = ComputeMaterialHash(pScene->mMaterials[i]); if (ppcMaterials[idx]) {
for (unsigned int a = 0; a < i;++a) { aiString sz;
if (abReferenced[a] && me == aiHashes[a]) { if( ppcMaterials[idx]->Get(AI_MATKEY_NAME, sz) != AI_SUCCESS ) {
++redundantRemoved; sz.length = ::ai_snprintf(sz.data,MAXLEN,"JoinedMaterial_#%u",p);
me = 0; ((aiMaterial*)ppcMaterials[idx])->AddProperty(&sz,AI_MATKEY_NAME);
aiMappingTable[i] = aiMappingTable[a];
delete pScene->mMaterials[i];
pScene->mMaterials[i] = nullptr;
break;
} }
} } else {
// This is a new material that is referenced, add to the map. ppcMaterials[idx] = pScene->mMaterials[p];
if (me) {
aiMappingTable[i] = iNewNum++;
} }
} }
// If the new material count differs from the original, // update all material indices
// we need to rebuild the material list and remap mesh material indexes. for (unsigned int p = 0; p < pScene->mNumMeshes;++p) {
if(iNewNum < 1) aiMesh* mesh = pScene->mMeshes[p];
throw DeadlyImportError("No materials remaining"); ai_assert(nullptr != mesh);
if (iNewNum != pScene->mNumMaterials) { mesh->mMaterialIndex = aiMappingTable[mesh->mMaterialIndex];
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;
} }
// delete temporary storage // delete the old material list
delete[] aiHashes; delete[] pScene->mMaterials;
delete[] aiMappingTable; pScene->mMaterials = ppcMaterials;
pScene->mNumMaterials = iNewNum;
} }
// delete temporary storage
delete[] aiHashes;
delete[] aiMappingTable;
if (redundantRemoved == 0 && unreferencedRemoved == 0) { if (redundantRemoved == 0 && unreferencedRemoved == 0) {
ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess finished "); ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess finished ");
} else { } else {

View File

@ -12,7 +12,6 @@ __Importers__:
- ASE - ASE
- ASK - ASK
- B3D - B3D
- [BLEND](https://en.wikipedia.org/wiki/.blend_(file_format))
- [BVH](https://en.wikipedia.org/wiki/Biovision_Hierarchy) - [BVH](https://en.wikipedia.org/wiki/Biovision_Hierarchy)
- CSM - CSM
- COB - COB
@ -66,6 +65,9 @@ __Importers__:
- XGL - XGL
- ZGL - 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): 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 - [C4D](https://en.wikipedia.org/wiki/Cinema_4D) (https://github.com/assimp/assimp/wiki/Cinema4D-&-Melange) IMporting geometry + node hierarchy are currently supported