Merge branch 'master' into master
commit
37bd87a4f6
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 ¤tNode : node.children()) {
|
for (XmlNode ¤tNode : 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;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue