From 87e2d3a54de9379675d0cf8899ebd1e2db750902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gy=C3=B6rgy=20Straub?= <> Date: Mon, 30 Mar 2020 14:30:33 +0100 Subject: [PATCH 01/39] Added support for glTF2 sparse accessors. Refactored Accessors, pulling out reusable bits between those and sparse accessors' indices / values. --- code/glTF2/glTF2Asset.h | 88 +++++++++++++++++++++++++++++--- code/glTF2/glTF2Asset.inl | 102 +++++++++++++++++++++++++++----------- 2 files changed, 154 insertions(+), 36 deletions(-) diff --git a/code/glTF2/glTF2Asset.h b/code/glTF2/glTF2Asset.h index c27522df3..1df87ace3 100644 --- a/code/glTF2/glTF2Asset.h +++ b/code/glTF2/glTF2Asset.h @@ -357,24 +357,46 @@ struct Object { // Classes for each glTF top-level object type // +//! Base class for types that access binary data from a BufferView, such as accessors +//! or sparse accessors' indices. +//! N.B. not a virtual class. All owned pointers to BufferViewClient instances should +//! be to their most derived types (which may of course be just BufferViewClient). +struct BufferViewClient : public Object { + Ref bufferView; //!< The ID of the bufferView. (required) + size_t byteOffset; //!< The offset relative to the start of the bufferView in bytes. (required) + + inline uint8_t *GetPointer(); + + void Read(Value &obj, Asset &r); +}; + +//! BufferViewClient with component type information. +//! N.B. not a virtual class. All owned pointers to ComponentTypedBufferViewClient +//! instances should be to their most derived types (which may of course be just +//! ComponentTypedBufferViewClient). +struct ComponentTypedBufferViewClient : public BufferViewClient { + ComponentType componentType; //!< The datatype of components in the attribute. (required) + + unsigned int GetBytesPerComponent(); + + void Read(Value &obj, Asset &r); +}; + //! A typed view into a BufferView. A BufferView contains raw binary data. //! An accessor provides a typed view into a BufferView or a subset of a BufferView //! similar to how WebGL's vertexAttribPointer() defines an attribute in a buffer. -struct Accessor : public Object { - Ref bufferView; //!< The ID of the bufferView. (required) - size_t byteOffset; //!< The offset relative to the start of the bufferView in bytes. (required) - ComponentType componentType; //!< The datatype of components in the attribute. (required) +struct Accessor : public ComponentTypedBufferViewClient { + struct Sparse; + size_t count; //!< The number of attributes referenced by this accessor. (required) AttribType::Value type; //!< Specifies if the attribute is a scalar, vector, or matrix. (required) std::vector max; //!< Maximum value of each component in this attribute. std::vector min; //!< Minimum value of each component in this attribute. + std::unique_ptr sparse; //!< Sparse accessor information unsigned int GetNumComponents(); - unsigned int GetBytesPerComponent(); unsigned int GetElementSize(); - inline uint8_t *GetPointer(); - template bool ExtractData(T *&outData); @@ -405,11 +427,63 @@ struct Accessor : public Object { } }; + //! Sparse accessor information + struct Sparse { + size_t count; + ComponentTypedBufferViewClient indices; + BufferViewClient values; + + std::vector 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. + + inline void PopulateData(size_t numBytes, uint8_t *bytes) { + if (bytes) { + data.assign(bytes, bytes + numBytes); + } else { + data.resize(numBytes, 0x00); + } + } + + inline void PatchData(unsigned int elementSize) + { + uint8_t *pIndices = indices.GetPointer(); + const unsigned int indexSize = indices.GetBytesPerComponent(); + uint8_t *indicesEnd = pIndices + count * indexSize; + + uint8_t *pValues = values.GetPointer(); + while (pIndices != indicesEnd) { + size_t offset; + switch (indices.componentType) { + case ComponentType_UNSIGNED_BYTE: + offset = *pIndices; + break; + case ComponentType_UNSIGNED_SHORT: + offset = *reinterpret_cast(pIndices); + break; + case ComponentType_UNSIGNED_INT: + offset = *reinterpret_cast(pIndices); + break; + default: + // have fun with float and negative values from signed types as indices. + throw DeadlyImportError("Unsupported component type in index."); + } + + offset *= elementSize; + std::memcpy(data.data() + offset, pValues, elementSize); + + pValues += elementSize; + pIndices += indexSize; + } + } + }; + inline Indexer GetIndexer() { return Indexer(*this); } Accessor() {} + + inline uint8_t *GetPointer(); + void Read(Value &obj, Asset &r); }; diff --git a/code/glTF2/glTF2Asset.inl b/code/glTF2/glTF2Asset.inl index f9c3aa805..79725bace 100644 --- a/code/glTF2/glTF2Asset.inl +++ b/code/glTF2/glTF2Asset.inl @@ -540,36 +540,10 @@ inline void BufferView::Read(Value &obj, Asset &r) { } // -// struct Accessor +// struct BufferViewClient // -inline void Accessor::Read(Value &obj, Asset &r) { - - if (Value *bufferViewVal = FindUInt(obj, "bufferView")) { - bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint()); - } - - byteOffset = MemberOrDefault(obj, "byteOffset", size_t(0)); - componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE); - count = MemberOrDefault(obj, "count", size_t(0)); - - const char *typestr; - type = ReadMember(obj, "type", typestr) ? AttribType::FromString(typestr) : AttribType::SCALAR; -} - -inline unsigned int Accessor::GetNumComponents() { - return AttribType::GetNumComponents(type); -} - -inline unsigned int Accessor::GetBytesPerComponent() { - return int(ComponentTypeSize(componentType)); -} - -inline unsigned int Accessor::GetElementSize() { - return GetNumComponents() * GetBytesPerComponent(); -} - -inline uint8_t *Accessor::GetPointer() { +inline uint8_t *BufferViewClient::GetPointer() { if (!bufferView || !bufferView->buffer) return 0; uint8_t *basePtr = bufferView->buffer->GetPointer(); if (!basePtr) return 0; @@ -588,6 +562,76 @@ inline uint8_t *Accessor::GetPointer() { return basePtr + offset; } +inline void BufferViewClient::Read(Value &obj, Asset &r) { + + if (Value *bufferViewVal = FindUInt(obj, "bufferView")) { + bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint()); + } + + byteOffset = MemberOrDefault(obj, "byteOffset", size_t(0)); +} + +// +// struct ComponentTypedBufferViewClient +// + +inline unsigned int ComponentTypedBufferViewClient::GetBytesPerComponent() { + return int(ComponentTypeSize(componentType)); +} + +inline void ComponentTypedBufferViewClient::Read(Value &obj, Asset &r) { + + BufferViewClient::Read(obj, r); + + componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE); +} + +// +// struct Accessor +// + +inline uint8_t *Accessor::GetPointer() { + if (!sparse) return BufferViewClient::GetPointer(); + + return sparse->data.data(); +} + +inline void Accessor::Read(Value &obj, Asset &r) { + + ComponentTypedBufferViewClient::Read(obj, r); + + count = MemberOrDefault(obj, "count", size_t(0)); + + const char *typestr; + type = ReadMember(obj, "type", typestr) ? AttribType::FromString(typestr) : AttribType::SCALAR; + + if (Value *sparseValue = FindObject(obj, "sparse")) { + sparse.reset(new Sparse); + ReadMember(*sparseValue, "count", sparse->count); + + if (Value *indicesValue = FindObject(*sparseValue, "indices")) { + sparse->indices.Read(*indicesValue, r); + } + + if (Value *valuesValue = FindObject(*sparseValue, "values")) { + sparse->values.Read(*valuesValue, r); + } + + const unsigned int elementSize = GetElementSize(); + const size_t dataSize = count * elementSize; + sparse->PopulateData(dataSize, BufferViewClient::GetPointer()); + sparse->PatchData(elementSize); + } +} + +inline unsigned int Accessor::GetNumComponents() { + return AttribType::GetNumComponents(type); +} + +inline unsigned int Accessor::GetElementSize() { + return GetNumComponents() * GetBytesPerComponent(); +} + namespace { inline void CopyData(size_t count, const uint8_t *src, size_t src_stride, @@ -621,7 +665,7 @@ bool Accessor::ExtractData(T *&outData) { const size_t targetElemSize = sizeof(T); ai_assert(elemSize <= targetElemSize); - ai_assert(count * stride <= bufferView->byteLength); + ai_assert(count * stride <= (bufferView ? bufferView->byteLength : sparse->data.size())); outData = new T[count]; if (stride == elemSize && targetElemSize == elemSize) { From 45e33ce1bf8ed719531aa0a71c2f63bf26d16a13 Mon Sep 17 00:00:00 2001 From: David Golembiowski Date: Fri, 24 Apr 2020 16:36:44 -0400 Subject: [PATCH 02/39] first commit --- port/AssimpRs/Cargo.toml | 9 +++++++++ port/AssimpRs/src/lib.rs | 7 +++++++ 2 files changed, 16 insertions(+) create mode 100644 port/AssimpRs/Cargo.toml create mode 100644 port/AssimpRs/src/lib.rs diff --git a/port/AssimpRs/Cargo.toml b/port/AssimpRs/Cargo.toml new file mode 100644 index 000000000..705699b23 --- /dev/null +++ b/port/AssimpRs/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "AssimpRs" +version = "0.1.0" +authors = ["David Golembiowski "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/port/AssimpRs/src/lib.rs b/port/AssimpRs/src/lib.rs new file mode 100644 index 000000000..31e1bb209 --- /dev/null +++ b/port/AssimpRs/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} From df57ee6cb618a45872210f2a9019cc0b866ca6ca Mon Sep 17 00:00:00 2001 From: David Golembiowski Date: Fri, 24 Apr 2020 16:49:38 -0400 Subject: [PATCH 03/39] laying out the submodules --- port/AssimpRs/src/camera/mod.rs | 0 port/AssimpRs/src/core/mod.rs | 0 port/AssimpRs/src/errors/mod.rs | 0 port/AssimpRs/src/formats/mod.rs | 0 port/AssimpRs/src/material/mod.rs | 0 port/AssimpRs/src/postprocess/mod.rs | 0 port/AssimpRs/src/shims/mod.rs | 0 port/AssimpRs/src/socket/mod.rs | 0 port/AssimpRs/src/structs/mod.rs | 0 9 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 port/AssimpRs/src/camera/mod.rs create mode 100644 port/AssimpRs/src/core/mod.rs create mode 100644 port/AssimpRs/src/errors/mod.rs create mode 100644 port/AssimpRs/src/formats/mod.rs create mode 100644 port/AssimpRs/src/material/mod.rs create mode 100644 port/AssimpRs/src/postprocess/mod.rs create mode 100644 port/AssimpRs/src/shims/mod.rs create mode 100644 port/AssimpRs/src/socket/mod.rs create mode 100644 port/AssimpRs/src/structs/mod.rs diff --git a/port/AssimpRs/src/camera/mod.rs b/port/AssimpRs/src/camera/mod.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/AssimpRs/src/core/mod.rs b/port/AssimpRs/src/core/mod.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/AssimpRs/src/errors/mod.rs b/port/AssimpRs/src/errors/mod.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/AssimpRs/src/formats/mod.rs b/port/AssimpRs/src/formats/mod.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/AssimpRs/src/material/mod.rs b/port/AssimpRs/src/material/mod.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/AssimpRs/src/postprocess/mod.rs b/port/AssimpRs/src/postprocess/mod.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/AssimpRs/src/shims/mod.rs b/port/AssimpRs/src/shims/mod.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/AssimpRs/src/socket/mod.rs b/port/AssimpRs/src/socket/mod.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/AssimpRs/src/structs/mod.rs b/port/AssimpRs/src/structs/mod.rs new file mode 100644 index 000000000..e69de29bb From 5d05c536e7a6421b347142450f5149058c1f48d2 Mon Sep 17 00:00:00 2001 From: David Golembiowski Date: Fri, 24 Apr 2020 17:02:36 -0400 Subject: [PATCH 04/39] updated gitignore and made port library name compliant with cargo --- port/AssimpRs/Cargo.toml | 9 --------- port/AssimpRs/src/camera/mod.rs | 0 port/AssimpRs/src/core/mod.rs | 0 port/AssimpRs/src/errors/mod.rs | 0 port/AssimpRs/src/formats/mod.rs | 0 port/AssimpRs/src/lib.rs | 7 ------- port/AssimpRs/src/material/mod.rs | 0 port/AssimpRs/src/postprocess/mod.rs | 0 port/AssimpRs/src/shims/mod.rs | 0 port/AssimpRs/src/socket/mod.rs | 0 port/AssimpRs/src/structs/mod.rs | 0 11 files changed, 16 deletions(-) delete mode 100644 port/AssimpRs/Cargo.toml delete mode 100644 port/AssimpRs/src/camera/mod.rs delete mode 100644 port/AssimpRs/src/core/mod.rs delete mode 100644 port/AssimpRs/src/errors/mod.rs delete mode 100644 port/AssimpRs/src/formats/mod.rs delete mode 100644 port/AssimpRs/src/lib.rs delete mode 100644 port/AssimpRs/src/material/mod.rs delete mode 100644 port/AssimpRs/src/postprocess/mod.rs delete mode 100644 port/AssimpRs/src/shims/mod.rs delete mode 100644 port/AssimpRs/src/socket/mod.rs delete mode 100644 port/AssimpRs/src/structs/mod.rs diff --git a/port/AssimpRs/Cargo.toml b/port/AssimpRs/Cargo.toml deleted file mode 100644 index 705699b23..000000000 --- a/port/AssimpRs/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "AssimpRs" -version = "0.1.0" -authors = ["David Golembiowski "] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/port/AssimpRs/src/camera/mod.rs b/port/AssimpRs/src/camera/mod.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/port/AssimpRs/src/core/mod.rs b/port/AssimpRs/src/core/mod.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/port/AssimpRs/src/errors/mod.rs b/port/AssimpRs/src/errors/mod.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/port/AssimpRs/src/formats/mod.rs b/port/AssimpRs/src/formats/mod.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/port/AssimpRs/src/lib.rs b/port/AssimpRs/src/lib.rs deleted file mode 100644 index 31e1bb209..000000000 --- a/port/AssimpRs/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} diff --git a/port/AssimpRs/src/material/mod.rs b/port/AssimpRs/src/material/mod.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/port/AssimpRs/src/postprocess/mod.rs b/port/AssimpRs/src/postprocess/mod.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/port/AssimpRs/src/shims/mod.rs b/port/AssimpRs/src/shims/mod.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/port/AssimpRs/src/socket/mod.rs b/port/AssimpRs/src/socket/mod.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/port/AssimpRs/src/structs/mod.rs b/port/AssimpRs/src/structs/mod.rs deleted file mode 100644 index e69de29bb..000000000 From 6363bf34c0f80ac41acd4fbd0a8b1b11f2533654 Mon Sep 17 00:00:00 2001 From: David Golembiowski Date: Fri, 24 Apr 2020 17:03:41 -0400 Subject: [PATCH 05/39] see git commit message rust-port 5d05c536 --- .gitignore | 6 ++++++ port/assimp_rs/Cargo.lock | 6 ++++++ port/assimp_rs/Cargo.toml | 9 +++++++++ port/assimp_rs/src/camera/mod.rs | 0 port/assimp_rs/src/core/mod.rs | 0 port/assimp_rs/src/errors/mod.rs | 0 port/assimp_rs/src/formats/mod.rs | 0 port/assimp_rs/src/lib.rs | 17 +++++++++++++++++ port/assimp_rs/src/material/mod.rs | 0 port/assimp_rs/src/postprocess/mod.rs | 0 port/assimp_rs/src/shims/mod.rs | 0 port/assimp_rs/src/socket/mod.rs | 0 port/assimp_rs/src/structs/mod.rs | 0 13 files changed, 38 insertions(+) create mode 100644 port/assimp_rs/Cargo.lock create mode 100644 port/assimp_rs/Cargo.toml create mode 100644 port/assimp_rs/src/camera/mod.rs create mode 100644 port/assimp_rs/src/core/mod.rs create mode 100644 port/assimp_rs/src/errors/mod.rs create mode 100644 port/assimp_rs/src/formats/mod.rs create mode 100644 port/assimp_rs/src/lib.rs create mode 100644 port/assimp_rs/src/material/mod.rs create mode 100644 port/assimp_rs/src/postprocess/mod.rs create mode 100644 port/assimp_rs/src/shims/mod.rs create mode 100644 port/assimp_rs/src/socket/mod.rs create mode 100644 port/assimp_rs/src/structs/mod.rs diff --git a/.gitignore b/.gitignore index e975976bf..fe59f9a70 100644 --- a/.gitignore +++ b/.gitignore @@ -79,6 +79,12 @@ test/gtest/src/gtest-stamp/Debug/ tools/assimp_view/assimp_viewer.vcxproj.user *.pyc +### Rust ### +# Generated by Cargo; will have compiled files and executables +port/assimp_rs/target/ +# Backup files generated by rustfmt +port/assimp_rs/**/*.rs.bk + # Unix editor backups *~ test/gtest/src/gtest-stamp/gtest-gitinfo.txt diff --git a/port/assimp_rs/Cargo.lock b/port/assimp_rs/Cargo.lock new file mode 100644 index 000000000..4f571f362 --- /dev/null +++ b/port/assimp_rs/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "assimp_rs" +version = "0.1.0" + diff --git a/port/assimp_rs/Cargo.toml b/port/assimp_rs/Cargo.toml new file mode 100644 index 000000000..073a2b283 --- /dev/null +++ b/port/assimp_rs/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "assimp_rs" +version = "0.1.0" +authors = ["David Golembiowski "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/port/assimp_rs/src/camera/mod.rs b/port/assimp_rs/src/camera/mod.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/core/mod.rs b/port/assimp_rs/src/core/mod.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/errors/mod.rs b/port/assimp_rs/src/errors/mod.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/formats/mod.rs b/port/assimp_rs/src/formats/mod.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/lib.rs b/port/assimp_rs/src/lib.rs new file mode 100644 index 000000000..dbb648876 --- /dev/null +++ b/port/assimp_rs/src/lib.rs @@ -0,0 +1,17 @@ +pub mod camera; +pub mod core; +pub mod errors; +pub mod formats; +pub mod material; +pub mod postprocess; +pub mod shims; +pub mod socket; +pub mod structs; + +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(true, true); + } +} diff --git a/port/assimp_rs/src/material/mod.rs b/port/assimp_rs/src/material/mod.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/postprocess/mod.rs b/port/assimp_rs/src/postprocess/mod.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/shims/mod.rs b/port/assimp_rs/src/shims/mod.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/socket/mod.rs b/port/assimp_rs/src/socket/mod.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/mod.rs b/port/assimp_rs/src/structs/mod.rs new file mode 100644 index 000000000..e69de29bb From 2108e08c900a624ae9a0a858860e7932635ee9a9 Mon Sep 17 00:00:00 2001 From: David Golembiowski Date: Fri, 24 Apr 2020 18:15:51 -0400 Subject: [PATCH 06/39] adding structs --- port/assimp_rs/src/structs/mod.rs | 61 +++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/port/assimp_rs/src/structs/mod.rs b/port/assimp_rs/src/structs/mod.rs index e69de29bb..fd9087648 100644 --- a/port/assimp_rs/src/structs/mod.rs +++ b/port/assimp_rs/src/structs/mod.rs @@ -0,0 +1,61 @@ +mod anim; +/* Animation + * NodeAnim + * MeshAnim + * MeshMorphAnim + */ +mod blob; +/* ExportDataBlob + */ +mod vec; +/* Vector2d + * Vector3d + * */ +mod matrix; +/* Matrix3by3 + * Matrix4by4 + */ +mod camera; +/* Camera */ +mod color; +/* Color3d + * Color4d + */ +mod key; +/* MeshKey + * MeshMorphKey + * QuatKey + * VectorKey + */ +mod texel; +mod plane; +mod string; +/* String + */ +mod material; +/* Material + * MaterialPropery + * MaterialPropertyString + */ +mod mem; +mod quaternion; +mod face; +mod vertex_weight; +mod mesh; +/* Mesh + */ +mod meta; +/* Metadata + * MetadataEntry + */ +mod node; +/* Node + * */ +mod light; +mod texture; +mod ray; +mod transform; +/* UVTransform */ +mod bone; +mod scene; +/* Scene */ From 060c45fcf3b4019446560c079adafb8a5b894f40 Mon Sep 17 00:00:00 2001 From: David Golembiowski Date: Fri, 24 Apr 2020 22:15:32 -0400 Subject: [PATCH 07/39] initial layout for anim.rs --- port/assimp_rs/src/structs/anim.rs | 44 ++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 port/assimp_rs/src/structs/anim.rs diff --git a/port/assimp_rs/src/structs/anim.rs b/port/assimp_rs/src/structs/anim.rs new file mode 100644 index 000000000..5374151eb --- /dev/null +++ b/port/assimp_rs/src/structs/anim.rs @@ -0,0 +1,44 @@ +pub struct Animation<'mA, 'mMA, 'nA> { + /* The name of the animation. If the modeling package this data was + * exported from does support only a single animation channel, this + * name is usually empty (length is zero). + */ + m_name: Option, + // Duration of the animation in ticks + m_duration: f64, + // Ticks per second. Zero (0.000... ticks/second) if not + // specified in the imported file + m_ticks_per_second: Option, + /* Number of bone animation channels. + Each channel affects a single node. + */ + m_num_channels: u64, + /* Node animation channels. Each channel + affects a single node. + ?? -> The array is m_num_channels in size. + (maybe refine to a derivative type of usize?) + */ + m_channels: &'nA NodeAnim, + /* Number of mesh animation channels. Each + channel affects a single mesh and defines + vertex-based animation. + */ + m_num_mesh_channels: u64, + /* The mesh animation channels. Each channel + affects a single mesh. + The array is m_num_mesh_channels in size + (maybe refine to a derivative of usize?) + */ + m_mesh_channels: &'mA MeshAnim, + /* The number of mesh animation channels. Each channel + affects a single mesh and defines some morphing animation. + */ + m_num_morph_mesh_channels: u64, + /* The morph mesh animation channels. Each channel affects a single mesh. + The array is mNumMorphMeshChannels in size. + */ + m_morph_mesh_channels: &'mMA MeshMorphAnim +} +pub struct NodeAnim {} +pub struct MeshAnim {} +pub struct MeshMorphAnim {} From e438310d8cc3718fdc32d62462b8217569f9c766 Mon Sep 17 00:00:00 2001 From: David Golembiowski Date: Sat, 25 Apr 2020 00:12:58 -0400 Subject: [PATCH 08/39] should have added these earlier --- port/assimp_rs/src/structs/blob.rs | 0 port/assimp_rs/src/structs/bone.rs | 0 port/assimp_rs/src/structs/camera.rs | 0 port/assimp_rs/src/structs/color.rs | 0 port/assimp_rs/src/structs/face.rs | 0 port/assimp_rs/src/structs/key.rs | 0 port/assimp_rs/src/structs/light.rs | 0 port/assimp_rs/src/structs/material.rs | 0 port/assimp_rs/src/structs/matrix.rs | 0 port/assimp_rs/src/structs/mem.rs | 0 port/assimp_rs/src/structs/mesh.rs | 0 port/assimp_rs/src/structs/meta.rs | 0 port/assimp_rs/src/structs/node.rs | 0 port/assimp_rs/src/structs/plane.rs | 0 port/assimp_rs/src/structs/quaternion.rs | 0 port/assimp_rs/src/structs/ray.rs | 0 port/assimp_rs/src/structs/scene.rs | 0 port/assimp_rs/src/structs/string.rs | 0 port/assimp_rs/src/structs/texel.rs | 0 port/assimp_rs/src/structs/texture.rs | 0 port/assimp_rs/src/structs/transform.rs | 0 port/assimp_rs/src/structs/vec.rs | 0 port/assimp_rs/src/structs/vertex_weight.rs | 0 23 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 port/assimp_rs/src/structs/blob.rs create mode 100644 port/assimp_rs/src/structs/bone.rs create mode 100644 port/assimp_rs/src/structs/camera.rs create mode 100644 port/assimp_rs/src/structs/color.rs create mode 100644 port/assimp_rs/src/structs/face.rs create mode 100644 port/assimp_rs/src/structs/key.rs create mode 100644 port/assimp_rs/src/structs/light.rs create mode 100644 port/assimp_rs/src/structs/material.rs create mode 100644 port/assimp_rs/src/structs/matrix.rs create mode 100644 port/assimp_rs/src/structs/mem.rs create mode 100644 port/assimp_rs/src/structs/mesh.rs create mode 100644 port/assimp_rs/src/structs/meta.rs create mode 100644 port/assimp_rs/src/structs/node.rs create mode 100644 port/assimp_rs/src/structs/plane.rs create mode 100644 port/assimp_rs/src/structs/quaternion.rs create mode 100644 port/assimp_rs/src/structs/ray.rs create mode 100644 port/assimp_rs/src/structs/scene.rs create mode 100644 port/assimp_rs/src/structs/string.rs create mode 100644 port/assimp_rs/src/structs/texel.rs create mode 100644 port/assimp_rs/src/structs/texture.rs create mode 100644 port/assimp_rs/src/structs/transform.rs create mode 100644 port/assimp_rs/src/structs/vec.rs create mode 100644 port/assimp_rs/src/structs/vertex_weight.rs diff --git a/port/assimp_rs/src/structs/blob.rs b/port/assimp_rs/src/structs/blob.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/bone.rs b/port/assimp_rs/src/structs/bone.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/camera.rs b/port/assimp_rs/src/structs/camera.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/color.rs b/port/assimp_rs/src/structs/color.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/face.rs b/port/assimp_rs/src/structs/face.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/key.rs b/port/assimp_rs/src/structs/key.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/light.rs b/port/assimp_rs/src/structs/light.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/material.rs b/port/assimp_rs/src/structs/material.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/matrix.rs b/port/assimp_rs/src/structs/matrix.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/mem.rs b/port/assimp_rs/src/structs/mem.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/mesh.rs b/port/assimp_rs/src/structs/mesh.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/meta.rs b/port/assimp_rs/src/structs/meta.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/node.rs b/port/assimp_rs/src/structs/node.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/plane.rs b/port/assimp_rs/src/structs/plane.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/quaternion.rs b/port/assimp_rs/src/structs/quaternion.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/ray.rs b/port/assimp_rs/src/structs/ray.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/scene.rs b/port/assimp_rs/src/structs/scene.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/string.rs b/port/assimp_rs/src/structs/string.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/texel.rs b/port/assimp_rs/src/structs/texel.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/texture.rs b/port/assimp_rs/src/structs/texture.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/transform.rs b/port/assimp_rs/src/structs/transform.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/vec.rs b/port/assimp_rs/src/structs/vec.rs new file mode 100644 index 000000000..e69de29bb diff --git a/port/assimp_rs/src/structs/vertex_weight.rs b/port/assimp_rs/src/structs/vertex_weight.rs new file mode 100644 index 000000000..e69de29bb From 629320a3a0b8ae742b8c1760f49f63cd698c4fa9 Mon Sep 17 00:00:00 2001 From: Inho Lee Date: Mon, 27 Apr 2020 11:52:04 +0200 Subject: [PATCH 09/39] Add timescale for collada --- code/Collada/ColladaExporter.cpp | 4 +++- code/Collada/ColladaLoader.cpp | 10 ++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/code/Collada/ColladaExporter.cpp b/code/Collada/ColladaExporter.cpp index e27e7aa90..cb5d8323b 100644 --- a/code/Collada/ColladaExporter.cpp +++ b/code/Collada/ColladaExporter.cpp @@ -1314,6 +1314,8 @@ void ColladaExporter::WriteSceneLibrary() // ------------------------------------------------------------------------------------------------ void ColladaExporter::WriteAnimationLibrary(size_t pIndex) { + static const float kSecondsFromMilliseconds = .001f; + const aiAnimation * anim = mScene->mAnimations[pIndex]; if ( anim->mNumChannels == 0 && anim->mNumMeshChannels == 0 && anim->mNumMorphMeshChannels ==0 ) @@ -1351,7 +1353,7 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex) std::vector frames; for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) { - frames.push_back(static_cast(nodeAnim->mPositionKeys[i].mTime)); + frames.push_back(static_cast(nodeAnim->mPositionKeys[i].mTime) * kSecondsFromMilliseconds); } WriteFloatArray(cur_node_idstr, FloatType_Time, (const ai_real *)frames.data(), frames.size()); diff --git a/code/Collada/ColladaLoader.cpp b/code/Collada/ColladaLoader.cpp index b78fc0e3b..e93550116 100644 --- a/code/Collada/ColladaLoader.cpp +++ b/code/Collada/ColladaLoader.cpp @@ -107,6 +107,8 @@ ColladaLoader::~ColladaLoader() { // empty } +static const float kMillisecondsFromSeconds = 1000.f; + // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. bool ColladaLoader::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { @@ -1420,9 +1422,9 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse double time = double(mat.d4); // remember? time is stored in mat.d4 mat.d4 = 1.0f; - dstAnim->mPositionKeys[a].mTime = time; - dstAnim->mRotationKeys[a].mTime = time; - dstAnim->mScalingKeys[a].mTime = time; + dstAnim->mPositionKeys[a].mTime = time * kMillisecondsFromSeconds ; + dstAnim->mRotationKeys[a].mTime = time * kMillisecondsFromSeconds ; + dstAnim->mScalingKeys[a].mTime = time * kMillisecondsFromSeconds ; mat.Decompose(dstAnim->mScalingKeys[a].mValue, dstAnim->mRotationKeys[a].mValue, dstAnim->mPositionKeys[a].mValue); } @@ -1484,7 +1486,7 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse morphAnim->mKeys[key].mValues = new unsigned int[morphChannels.size()]; morphAnim->mKeys[key].mWeights = new double[morphChannels.size()]; - morphAnim->mKeys[key].mTime = morphTimeValues[key].mTime; + morphAnim->mKeys[key].mTime = morphTimeValues[key].mTime * kMillisecondsFromSeconds ; for (unsigned int valueIndex = 0; valueIndex < morphChannels.size(); valueIndex++) { morphAnim->mKeys[key].mValues[valueIndex] = valueIndex; From b0c97118946c2d138985df1908638614350c1863 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Mon, 27 Apr 2020 15:16:57 +0200 Subject: [PATCH 10/39] Small format finding --- code/Collada/ColladaExporter.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/Collada/ColladaExporter.cpp b/code/Collada/ColladaExporter.cpp index cb5d8323b..6faa229c8 100644 --- a/code/Collada/ColladaExporter.cpp +++ b/code/Collada/ColladaExporter.cpp @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2020, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -1316,10 +1315,11 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex) { static const float kSecondsFromMilliseconds = .001f; - const aiAnimation * anim = mScene->mAnimations[pIndex]; + const aiAnimation * anim = mScene->mAnimations[pIndex]; - if ( anim->mNumChannels == 0 && anim->mNumMeshChannels == 0 && anim->mNumMorphMeshChannels ==0 ) - return; + if ( anim->mNumChannels == 0 && anim->mNumMeshChannels == 0 && anim->mNumMorphMeshChannels ==0 ) { + return; + } const std::string animation_name_escaped = XMLEscape( anim->mName.C_Str() ); std::string idstr = anim->mName.C_Str(); From 81abd90ee1c25bff7b2f70db29a83216be00d11c Mon Sep 17 00:00:00 2001 From: Paul Arden Date: Tue, 28 Apr 2020 10:07:56 +1000 Subject: [PATCH 11/39] Fix reading of orthographic camera data. Fixes #3028. --- code/glTF2/glTF2Asset.inl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/glTF2/glTF2Asset.inl b/code/glTF2/glTF2Asset.inl index ed23b388a..ea0b17dcd 100644 --- a/code/glTF2/glTF2Asset.inl +++ b/code/glTF2/glTF2Asset.inl @@ -1068,10 +1068,10 @@ inline void Camera::Read(Value &obj, Asset & /*r*/) { cameraProperties.perspective.zfar = MemberOrDefault(*it, "zfar", 100.f); cameraProperties.perspective.znear = MemberOrDefault(*it, "znear", 0.01f); } else { - cameraProperties.ortographic.xmag = MemberOrDefault(obj, "xmag", 1.f); - cameraProperties.ortographic.ymag = MemberOrDefault(obj, "ymag", 1.f); - cameraProperties.ortographic.zfar = MemberOrDefault(obj, "zfar", 100.f); - cameraProperties.ortographic.znear = MemberOrDefault(obj, "znear", 0.01f); + cameraProperties.ortographic.xmag = MemberOrDefault(*it, "xmag", 1.f); + cameraProperties.ortographic.ymag = MemberOrDefault(*it, "ymag", 1.f); + cameraProperties.ortographic.zfar = MemberOrDefault(*it, "zfar", 100.f); + cameraProperties.ortographic.znear = MemberOrDefault(*it, "znear", 0.01f); } } From 4dfdbbf171674756f281dbad07e335bb5e4d989d Mon Sep 17 00:00:00 2001 From: qarmin Date: Tue, 28 Apr 2020 20:31:59 +0200 Subject: [PATCH 12/39] Check index before using --- code/glTF/glTFCommon.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/glTF/glTFCommon.cpp b/code/glTF/glTFCommon.cpp index 1c662a16a..17da49fb8 100644 --- a/code/glTF/glTFCommon.cpp +++ b/code/glTF/glTFCommon.cpp @@ -145,13 +145,13 @@ bool ParseDataURI(const char *const_uri, size_t uriLen, DataURI &out) { size_t i = 5, j; if (uri[i] != ';' && uri[i] != ',') { // has media type? uri[1] = char(i); - for (; uri[i] != ';' && uri[i] != ',' && i < uriLen; ++i) { + for (;i < uriLen && uri[i] != ';' && uri[i] != ','; ++i) { // nothing to do! } } - while (uri[i] == ';' && i < uriLen) { + while (i < uriLen && uri[i] == ';') { uri[i++] = '\0'; - for (j = i; uri[i] != ';' && uri[i] != ',' && i < uriLen; ++i) { + for (j = i; i < uriLen && uri[i] != ';' && uri[i] != ','; ++i) { // nothing to do! } From 2c6ac23a4e04127838b03eb4589861d9e22ef0f4 Mon Sep 17 00:00:00 2001 From: RichardTea <31507749+RichardTea@users.noreply.github.com> Date: Tue, 28 Apr 2020 17:46:07 +0100 Subject: [PATCH 13/39] Apply Assimp clangformat to touched Collada files --- code/Collada/ColladaExporter.cpp | 1545 ++++++++++++++--------------- code/Collada/ColladaExporter.h | 135 +-- code/Collada/ColladaHelper.cpp | 23 +- code/Collada/ColladaHelper.h | 403 ++++---- code/Collada/ColladaLoader.cpp | 692 ++++++------- code/Collada/ColladaParser.cpp | 1572 +++++++++++------------------- code/Collada/ColladaParser.h | 503 +++++----- 7 files changed, 2103 insertions(+), 2770 deletions(-) diff --git a/code/Collada/ColladaExporter.cpp b/code/Collada/ColladaExporter.cpp index e27e7aa90..0026fda26 100644 --- a/code/Collada/ColladaExporter.cpp +++ b/code/Collada/ColladaExporter.cpp @@ -45,24 +45,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ColladaExporter.h" #include -#include +#include #include -#include #include #include #include -#include -#include -#include +#include +#include #include +#include +#include #include -#include #include +#include +#include #include #include -#include using namespace Assimp; @@ -70,32 +70,32 @@ namespace Assimp { // ------------------------------------------------------------------------------------------------ // Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp -void ExportSceneCollada(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) { +void ExportSceneCollada(const char *pFile, IOSystem *pIOSystem, const aiScene *pScene, const ExportProperties * /*pProperties*/) { std::string path = DefaultIOSystem::absolutePath(std::string(pFile)); std::string file = DefaultIOSystem::completeBaseName(std::string(pFile)); // invoke the exporter - ColladaExporter iDoTheExportThing( pScene, pIOSystem, path, file); - + ColladaExporter iDoTheExportThing(pScene, pIOSystem, path, file); + if (iDoTheExportThing.mOutput.fail()) { throw DeadlyExportError("output data creation failed. Most likely the file became too large: " + std::string(pFile)); } // we're still here - export successfully completed. Write result to the given IOSYstem - std::unique_ptr outfile (pIOSystem->Open(pFile,"wt")); - if(outfile == NULL) { + std::unique_ptr outfile(pIOSystem->Open(pFile, "wt")); + if (outfile == NULL) { throw DeadlyExportError("could not open output .dae file: " + std::string(pFile)); } // XXX maybe use a small wrapper around IOStream that behaves like std::stringstream in order to avoid the extra copy. - outfile->Write( iDoTheExportThing.mOutput.str().c_str(), static_cast(iDoTheExportThing.mOutput.tellp()),1); + outfile->Write(iDoTheExportThing.mOutput.str().c_str(), static_cast(iDoTheExportThing.mOutput.tellp()), 1); } } // end of namespace Assimp // ------------------------------------------------------------------------------------------------ // Encodes a string into a valid XML ID using the xsd:ID schema qualifications. -static const std::string XMLIDEncode(const std::string& name) { +static const std::string XMLIDEncode(const std::string &name) { const char XML_ID_CHARS[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-."; const unsigned int XML_ID_CHARS_COUNT = sizeof(XML_ID_CHARS) / sizeof(char); @@ -115,7 +115,7 @@ static const std::string XMLIDEncode(const std::string& name) { if (strchr(XML_ID_CHARS, *it) != nullptr) { idEncoded << *it; } else { - // Select placeholder character based on invalid character to prevent name collisions + // Select placeholder character based on invalid character to prevent name collisions idEncoded << XML_ID_CHARS[(*it) % XML_ID_CHARS_COUNT]; } } @@ -125,12 +125,12 @@ static const std::string XMLIDEncode(const std::string& name) { // ------------------------------------------------------------------------------------------------ // Constructor for a specific scene to export -ColladaExporter::ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file) -: mIOSystem(pIOSystem) -, mPath(path) -, mFile(file) { +ColladaExporter::ColladaExporter(const aiScene *pScene, IOSystem *pIOSystem, const std::string &path, const std::string &file) : + mIOSystem(pIOSystem), + mPath(path), + mFile(file) { // make sure that all formatting happens using the standard, C locale and not the user's current locale - mOutput.imbue( std::locale("C") ); + mOutput.imbue(std::locale("C")); mOutput.precision(ASSIMP_AI_REAL_TEXT_PRECISION); mScene = pScene; @@ -146,7 +146,7 @@ ColladaExporter::ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, co // ------------------------------------------------------------------------------------------------ // Destructor ColladaExporter::~ColladaExporter() { - if ( mSceneOwned ) { + if (mSceneOwned) { delete mScene; } } @@ -170,9 +170,9 @@ void ColladaExporter::WriteFile() { WriteControllerLibrary(); WriteSceneLibrary(); - - // customized, Writes the animation library - WriteAnimationsLibrary(); + + // customized, Writes the animation library + WriteAnimationsLibrary(); // useless Collada fu at the end, just in case we haven't had enough indirections, yet. mOutput << startstr << "" << endstr; @@ -189,17 +189,17 @@ void ColladaExporter::WriteFile() { void ColladaExporter::WriteHeader() { static const ai_real epsilon = Math::getEpsilon(); static const aiQuaternion x_rot(aiMatrix3x3( - 0, -1, 0, - 1, 0, 0, - 0, 0, 1)); + 0, -1, 0, + 1, 0, 0, + 0, 0, 1)); static const aiQuaternion y_rot(aiMatrix3x3( - 1, 0, 0, - 0, 1, 0, - 0, 0, 1)); + 1, 0, 0, + 0, 1, 0, + 0, 0, 1)); static const aiQuaternion z_rot(aiMatrix3x3( - 1, 0, 0, - 0, 0, 1, - 0, -1, 0)); + 1, 0, 0, + 0, 0, 1, + 0, -1, 0)); static const unsigned int date_nb_chars = 20; char date_str[date_nb_chars]; @@ -215,39 +215,39 @@ void ColladaExporter::WriteHeader() { bool add_root_node = false; ai_real scale = 1.0; - if(std::abs(scaling.x - scaling.y) <= epsilon && std::abs(scaling.x - scaling.z) <= epsilon && std::abs(scaling.y - scaling.z) <= epsilon) { - scale = (ai_real) ((((double) scaling.x) + ((double) scaling.y) + ((double) scaling.z)) / 3.0); + if (std::abs(scaling.x - scaling.y) <= epsilon && std::abs(scaling.x - scaling.z) <= epsilon && std::abs(scaling.y - scaling.z) <= epsilon) { + scale = (ai_real)((((double)scaling.x) + ((double)scaling.y) + ((double)scaling.z)) / 3.0); } else { add_root_node = true; } std::string up_axis = "Y_UP"; - if(rotation.Equal(x_rot, epsilon)) { + if (rotation.Equal(x_rot, epsilon)) { up_axis = "X_UP"; - } else if(rotation.Equal(y_rot, epsilon)) { + } else if (rotation.Equal(y_rot, epsilon)) { up_axis = "Y_UP"; - } else if(rotation.Equal(z_rot, epsilon)) { + } else if (rotation.Equal(z_rot, epsilon)) { up_axis = "Z_UP"; } else { add_root_node = true; } - if(! position.Equal(aiVector3D(0, 0, 0))) { + if (!position.Equal(aiVector3D(0, 0, 0))) { add_root_node = true; } - if(mScene->mRootNode->mNumChildren == 0) { + if (mScene->mRootNode->mNumChildren == 0) { add_root_node = true; } - if(add_root_node) { - aiScene* scene; + if (add_root_node) { + aiScene *scene; SceneCombiner::CopyScene(&scene, mScene); - aiNode* root = new aiNode("Scene"); + aiNode *root = new aiNode("Scene"); root->mNumChildren = 1; - root->mChildren = new aiNode*[root->mNumChildren]; + root->mChildren = new aiNode *[root->mNumChildren]; root->mChildren[0] = scene->mRootNode; scene->mRootNode->mParent = root; @@ -266,20 +266,24 @@ void ColladaExporter::WriteHeader() { PushTag(); // If no Scene metadata, use root node metadata - aiMetadata* meta = mScene->mMetaData; + aiMetadata *meta = mScene->mMetaData; if (nullptr == meta) { meta = mScene->mRootNode->mMetaData; } aiString value; if (!meta || !meta->Get("Author", value)) { - mOutput << startstr << "" << "Assimp" << "" << endstr; + mOutput << startstr << "" + << "Assimp" + << "" << endstr; } else { mOutput << startstr << "" << XMLEscape(value.C_Str()) << "" << endstr; } if (nullptr == meta || !meta->Get(AI_METADATA_SOURCE_GENERATOR, value)) { - mOutput << startstr << "" << "Assimp Exporter" << "" << endstr; + mOutput << startstr << "" + << "Assimp Exporter" + << "" << endstr; } else { mOutput << startstr << "" << XMLEscape(value.C_Str()) << "" << endstr; } @@ -336,26 +340,26 @@ void ColladaExporter::WriteTextures() { char str[buffer_size]; if (mScene->HasTextures()) { - for(unsigned int i = 0; i < mScene->mNumTextures; i++) { + for (unsigned int i = 0; i < mScene->mNumTextures; i++) { // It would be great to be able to create a directory in portable standard C++, but it's not the case, // so we just write the textures in the current directory. - aiTexture* texture = mScene->mTextures[i]; - if ( nullptr == texture ) { + aiTexture *texture = mScene->mTextures[i]; + if (nullptr == texture) { continue; } ASSIMP_itoa10(str, buffer_size, i + 1); - std::string name = mFile + "_texture_" + (i < 1000 ? "0" : "") + (i < 100 ? "0" : "") + (i < 10 ? "0" : "") + str + "." + ((const char*) texture->achFormatHint); + std::string name = mFile + "_texture_" + (i < 1000 ? "0" : "") + (i < 100 ? "0" : "") + (i < 10 ? "0" : "") + str + "." + ((const char *)texture->achFormatHint); std::unique_ptr outfile(mIOSystem->Open(mPath + mIOSystem->getOsSeparator() + name, "wb")); - if(outfile == NULL) { + if (outfile == NULL) { throw DeadlyExportError("could not open output texture file: " + mPath + name); } - if(texture->mHeight == 0) { - outfile->Write((void*) texture->pcData, texture->mWidth, 1); + if (texture->mHeight == 0) { + outfile->Write((void *)texture->pcData, texture->mWidth, 1); } else { Bitmap::Save(texture, outfile.get()); } @@ -370,21 +374,20 @@ void ColladaExporter::WriteTextures() { // ------------------------------------------------------------------------------------------------ // Write the embedded textures void ColladaExporter::WriteCamerasLibrary() { - if(mScene->HasCameras()) { + if (mScene->HasCameras()) { mOutput << startstr << "" << endstr; PushTag(); - for( size_t a = 0; a < mScene->mNumCameras; ++a) - WriteCamera( a); + for (size_t a = 0; a < mScene->mNumCameras; ++a) + WriteCamera(a); PopTag(); mOutput << startstr << "" << endstr; - } } -void ColladaExporter::WriteCamera(size_t pIndex){ +void ColladaExporter::WriteCamera(size_t pIndex) { const aiCamera *cam = mScene->mCameras[pIndex]; const std::string cameraName = XMLEscape(cam->mName.C_Str()); @@ -400,18 +403,17 @@ void ColladaExporter::WriteCamera(size_t pIndex){ //always perspective mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << ""<< - AI_RAD_TO_DEG(cam->mHorizontalFOV) - <<"" << endstr; + mOutput << startstr << "" << AI_RAD_TO_DEG(cam->mHorizontalFOV) + << "" << endstr; mOutput << startstr << "" - << cam->mAspect - << "" << endstr; + << cam->mAspect + << "" << endstr; mOutput << startstr << "" - << cam->mClipPlaneNear - << "" << endstr; + << cam->mClipPlaneNear + << "" << endstr; mOutput << startstr << "" - << cam->mClipPlaneFar - << "" << endstr; + << cam->mClipPlaneFar + << "" << endstr; PopTag(); mOutput << startstr << "" << endstr; PopTag(); @@ -420,28 +422,25 @@ void ColladaExporter::WriteCamera(size_t pIndex){ mOutput << startstr << "" << endstr; PopTag(); mOutput << startstr << "" << endstr; - } - // ------------------------------------------------------------------------------------------------ // Write the embedded textures void ColladaExporter::WriteLightsLibrary() { - if(mScene->HasLights()) { + if (mScene->HasLights()) { mOutput << startstr << "" << endstr; PushTag(); - for( size_t a = 0; a < mScene->mNumLights; ++a) - WriteLight( a); + for (size_t a = 0; a < mScene->mNumLights; ++a) + WriteLight(a); PopTag(); mOutput << startstr << "" << endstr; - } } -void ColladaExporter::WriteLight(size_t pIndex){ +void ColladaExporter::WriteLight(size_t pIndex) { const aiLight *light = mScene->mLights[pIndex]; const std::string lightName = XMLEscape(light->mName.C_Str()); @@ -452,116 +451,111 @@ void ColladaExporter::WriteLight(size_t pIndex){ PushTag(); mOutput << startstr << "" << endstr; PushTag(); - switch(light->mType){ - case aiLightSource_AMBIENT: - WriteAmbienttLight(light); - break; - case aiLightSource_DIRECTIONAL: - WriteDirectionalLight(light); - break; - case aiLightSource_POINT: - WritePointLight(light); - break; - case aiLightSource_SPOT: - WriteSpotLight(light); - break; - case aiLightSource_AREA: - case aiLightSource_UNDEFINED: - case _aiLightSource_Force32Bit: - break; + switch (light->mType) { + case aiLightSource_AMBIENT: + WriteAmbienttLight(light); + break; + case aiLightSource_DIRECTIONAL: + WriteDirectionalLight(light); + break; + case aiLightSource_POINT: + WritePointLight(light); + break; + case aiLightSource_SPOT: + WriteSpotLight(light); + break; + case aiLightSource_AREA: + case aiLightSource_UNDEFINED: + case _aiLightSource_Force32Bit: + break; } PopTag(); mOutput << startstr << "" << endstr; PopTag(); mOutput << startstr << "" << endstr; - } -void ColladaExporter::WritePointLight(const aiLight *const light){ - const aiColor3D &color= light->mColorDiffuse; +void ColladaExporter::WritePointLight(const aiLight *const light) { + const aiColor3D &color = light->mColorDiffuse; mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" - << color.r<<" "<" << endstr; + << color.r << " " << color.g << " " << color.b + << "" << endstr; mOutput << startstr << "" - << light->mAttenuationConstant - <<"" << endstr; + << light->mAttenuationConstant + << "" << endstr; mOutput << startstr << "" - << light->mAttenuationLinear - <<"" << endstr; + << light->mAttenuationLinear + << "" << endstr; mOutput << startstr << "" - << light->mAttenuationQuadratic - <<"" << endstr; + << light->mAttenuationQuadratic + << "" << endstr; PopTag(); mOutput << startstr << "" << endstr; - } -void ColladaExporter::WriteDirectionalLight(const aiLight *const light){ - const aiColor3D &color= light->mColorDiffuse; +void ColladaExporter::WriteDirectionalLight(const aiLight *const light) { + const aiColor3D &color = light->mColorDiffuse; mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" - << color.r<<" "<" << endstr; + << color.r << " " << color.g << " " << color.b + << "" << endstr; PopTag(); mOutput << startstr << "" << endstr; - } -void ColladaExporter::WriteSpotLight(const aiLight *const light){ +void ColladaExporter::WriteSpotLight(const aiLight *const light) { - const aiColor3D &color= light->mColorDiffuse; + const aiColor3D &color = light->mColorDiffuse; mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" - << color.r<<" "<" << endstr; + << color.r << " " << color.g << " " << color.b + << "" << endstr; mOutput << startstr << "" - << light->mAttenuationConstant - <<"" << endstr; + << light->mAttenuationConstant + << "" << endstr; mOutput << startstr << "" - << light->mAttenuationLinear - <<"" << endstr; + << light->mAttenuationLinear + << "" << endstr; mOutput << startstr << "" - << light->mAttenuationQuadratic - <<"" << endstr; + << light->mAttenuationQuadratic + << "" << endstr; /* out->mAngleOuterCone = AI_DEG_TO_RAD (std::acos(std::pow(0.1f,1.f/srcLight->mFalloffExponent))+ srcLight->mFalloffAngle); */ const ai_real fallOffAngle = AI_RAD_TO_DEG(light->mAngleInnerCone); - mOutput << startstr <<"" - << fallOffAngle - <<"" << endstr; - double temp = light->mAngleOuterCone-light->mAngleInnerCone; + mOutput << startstr << "" + << fallOffAngle + << "" << endstr; + double temp = light->mAngleOuterCone - light->mAngleInnerCone; temp = std::cos(temp); - temp = std::log(temp)/std::log(0.1); - temp = 1/temp; + temp = std::log(temp) / std::log(0.1); + temp = 1 / temp; mOutput << startstr << "" - << temp - <<"" << endstr; - + << temp + << "" << endstr; PopTag(); mOutput << startstr << "" << endstr; - } -void ColladaExporter::WriteAmbienttLight(const aiLight *const light){ +void ColladaExporter::WriteAmbienttLight(const aiLight *const light) { - const aiColor3D &color= light->mColorAmbient; + const aiColor3D &color = light->mColorAmbient; mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" - << color.r<<" "<" << endstr; + << color.r << " " << color.g << " " << color.b + << "" << endstr; PopTag(); mOutput << startstr << "" << endstr; @@ -569,130 +563,121 @@ void ColladaExporter::WriteAmbienttLight(const aiLight *const light){ // ------------------------------------------------------------------------------------------------ // Reads a single surface entry from the given material keys -void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, - aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex) { - if( pSrcMat->GetTextureCount( pTexture) > 0 ) { - aiString texfile; - unsigned int uvChannel = 0; - pSrcMat->GetTexture( pTexture, 0, &texfile, NULL, &uvChannel); +void ColladaExporter::ReadMaterialSurface(Surface &poSurface, const aiMaterial *pSrcMat, + aiTextureType pTexture, const char *pKey, size_t pType, size_t pIndex) { + if (pSrcMat->GetTextureCount(pTexture) > 0) { + aiString texfile; + unsigned int uvChannel = 0; + pSrcMat->GetTexture(pTexture, 0, &texfile, NULL, &uvChannel); - std::string index_str(texfile.C_Str()); + std::string index_str(texfile.C_Str()); - if(index_str.size() != 0 && index_str[0] == '*') { - unsigned int index; + if (index_str.size() != 0 && index_str[0] == '*') { + unsigned int index; - index_str = index_str.substr(1, std::string::npos); + index_str = index_str.substr(1, std::string::npos); - try { - index = (unsigned int) strtoul10_64(index_str.c_str()); - } catch(std::exception& error) { - throw DeadlyExportError(error.what()); - } + try { + index = (unsigned int)strtoul10_64(index_str.c_str()); + } catch (std::exception &error) { + throw DeadlyExportError(error.what()); + } - std::map::const_iterator name = textures.find(index); + std::map::const_iterator name = textures.find(index); - if(name != textures.end()) { - poSurface.texture = name->second; + if (name != textures.end()) { + poSurface.texture = name->second; + } else { + throw DeadlyExportError("could not find embedded texture at index " + index_str); + } } else { - throw DeadlyExportError("could not find embedded texture at index " + index_str); + poSurface.texture = texfile.C_Str(); } - } else { - poSurface.texture = texfile.C_Str(); - } - poSurface.channel = uvChannel; - poSurface.exist = true; - } else { - if( pKey ) - poSurface.exist = pSrcMat->Get( pKey, static_cast(pType), static_cast(pIndex), poSurface.color) == aiReturn_SUCCESS; - } + poSurface.channel = uvChannel; + poSurface.exist = true; + } else { + if (pKey) + poSurface.exist = pSrcMat->Get(pKey, static_cast(pType), static_cast(pIndex), poSurface.color) == aiReturn_SUCCESS; + } } // ------------------------------------------------------------------------------------------------ // Reimplementation of isalnum(,C locale), because AppVeyor does not see standard version. static bool isalnum_C(char c) { - return ( nullptr != strchr("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",c) ); + return (nullptr != strchr("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", c)); } // ------------------------------------------------------------------------------------------------ // Writes an image entry for the given surface -void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::string& pNameAdd) { - if( !pSurface.texture.empty() ) - { - mOutput << startstr << "" << endstr; - PushTag(); - mOutput << startstr << ""; +void ColladaExporter::WriteImageEntry(const Surface &pSurface, const std::string &pNameAdd) { + if (!pSurface.texture.empty()) { + mOutput << startstr << "" << endstr; + PushTag(); + mOutput << startstr << ""; - // URL encode image file name first, then XML encode on top - std::stringstream imageUrlEncoded; - for( std::string::const_iterator it = pSurface.texture.begin(); it != pSurface.texture.end(); ++it ) - { - if( isalnum_C( (unsigned char) *it) || *it == ':' || *it == '_' || *it == '-' || *it == '.' || *it == '/' || *it == '\\' ) - imageUrlEncoded << *it; - else - imageUrlEncoded << '%' << std::hex << size_t( (unsigned char) *it) << std::dec; + // URL encode image file name first, then XML encode on top + std::stringstream imageUrlEncoded; + for (std::string::const_iterator it = pSurface.texture.begin(); it != pSurface.texture.end(); ++it) { + if (isalnum_C((unsigned char)*it) || *it == ':' || *it == '_' || *it == '-' || *it == '.' || *it == '/' || *it == '\\') + imageUrlEncoded << *it; + else + imageUrlEncoded << '%' << std::hex << size_t((unsigned char)*it) << std::dec; + } + mOutput << XMLEscape(imageUrlEncoded.str()); + mOutput << "" << endstr; + PopTag(); + mOutput << startstr << "" << endstr; } - mOutput << XMLEscape(imageUrlEncoded.str()); - mOutput << "" << endstr; - PopTag(); - mOutput << startstr << "" << endstr; - } } // ------------------------------------------------------------------------------------------------ // Writes a color-or-texture entry into an effect definition -void ColladaExporter::WriteTextureColorEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pImageName) -{ - if(pSurface.exist) { - mOutput << startstr << "<" << pTypeName << ">" << endstr; - PushTag(); - if( pSurface.texture.empty() ) - { - mOutput << startstr << "" << pSurface.color.r << " " << pSurface.color.g << " " << pSurface.color.b << " " << pSurface.color.a << "" << endstr; +void ColladaExporter::WriteTextureColorEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &pImageName) { + if (pSurface.exist) { + mOutput << startstr << "<" << pTypeName << ">" << endstr; + PushTag(); + if (pSurface.texture.empty()) { + mOutput << startstr << "" << pSurface.color.r << " " << pSurface.color.g << " " << pSurface.color.b << " " << pSurface.color.a << "" << endstr; + } else { + mOutput << startstr << "" << endstr; + } + PopTag(); + mOutput << startstr << "" << endstr; } - else - { - mOutput << startstr << "" << endstr; - } - PopTag(); - mOutput << startstr << "" << endstr; - } } // ------------------------------------------------------------------------------------------------ // Writes the two parameters necessary for referencing a texture in an effect entry -void ColladaExporter::WriteTextureParamEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pMatName) -{ - // if surface is a texture, write out the sampler and the surface parameters necessary to reference the texture - if( !pSurface.texture.empty() ) - { - mOutput << startstr << "" << endstr; - PushTag(); - mOutput << startstr << "" << endstr; - PushTag(); - mOutput << startstr << "" << XMLIDEncode(pMatName) << "-" << pTypeName << "-image" << endstr; - PopTag(); - mOutput << startstr << "" << endstr; - PopTag(); - mOutput << startstr << "" << endstr; +void ColladaExporter::WriteTextureParamEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &pMatName) { + // if surface is a texture, write out the sampler and the surface parameters necessary to reference the texture + if (!pSurface.texture.empty()) { + mOutput << startstr << "" << endstr; + PushTag(); + mOutput << startstr << "" << endstr; + PushTag(); + mOutput << startstr << "" << XMLIDEncode(pMatName) << "-" << pTypeName << "-image" << endstr; + PopTag(); + mOutput << startstr << "" << endstr; + PopTag(); + mOutput << startstr << "" << endstr; - mOutput << startstr << "" << endstr; - PushTag(); - mOutput << startstr << "" << endstr; - PushTag(); - mOutput << startstr << "" << XMLIDEncode(pMatName) << "-" << pTypeName << "-surface" << endstr; - PopTag(); - mOutput << startstr << "" << endstr; - PopTag(); - mOutput << startstr << "" << endstr; - } + mOutput << startstr << "" << endstr; + PushTag(); + mOutput << startstr << "" << endstr; + PushTag(); + mOutput << startstr << "" << XMLIDEncode(pMatName) << "-" << pTypeName << "-surface" << endstr; + PopTag(); + mOutput << startstr << "" << endstr; + PopTag(); + mOutput << startstr << "" << endstr; + } } // ------------------------------------------------------------------------------------------------ // Writes a scalar property -void ColladaExporter::WriteFloatEntry( const Property& pProperty, const std::string& pTypeName) -{ - if(pProperty.exist) { +void ColladaExporter::WriteFloatEntry(const Property &pProperty, const std::string &pTypeName) { + if (pProperty.exist) { mOutput << startstr << "<" << pTypeName << ">" << endstr; PushTag(); mOutput << startstr << "" << pProperty.value << "" << endstr; @@ -703,170 +688,162 @@ void ColladaExporter::WriteFloatEntry( const Property& pProperty, const std::str // ------------------------------------------------------------------------------------------------ // Writes the material setup -void ColladaExporter::WriteMaterials() -{ - materials.resize( mScene->mNumMaterials); +void ColladaExporter::WriteMaterials() { + materials.resize(mScene->mNumMaterials); - /// collect all materials from the scene - size_t numTextures = 0; - for( size_t a = 0; a < mScene->mNumMaterials; ++a ) - { - const aiMaterial* mat = mScene->mMaterials[a]; + /// collect all materials from the scene + size_t numTextures = 0; + for (size_t a = 0; a < mScene->mNumMaterials; ++a) { + const aiMaterial *mat = mScene->mMaterials[a]; - aiString name; - if( mat->Get( AI_MATKEY_NAME, name) != aiReturn_SUCCESS ) { - name = "mat"; - materials[a].name = std::string( "m") + to_string(a) + name.C_Str(); - } else { - // try to use the material's name if no other material has already taken it, else append # - std::string testName = name.C_Str(); - size_t materialCountWithThisName = 0; - for( size_t i = 0; i < a; i ++ ) { - if( materials[i].name == testName ) { - materialCountWithThisName ++; + aiString name; + if (mat->Get(AI_MATKEY_NAME, name) != aiReturn_SUCCESS) { + name = "mat"; + materials[a].name = std::string("m") + to_string(a) + name.C_Str(); + } else { + // try to use the material's name if no other material has already taken it, else append # + std::string testName = name.C_Str(); + size_t materialCountWithThisName = 0; + for (size_t i = 0; i < a; i++) { + if (materials[i].name == testName) { + materialCountWithThisName++; + } + } + if (materialCountWithThisName == 0) { + materials[a].name = name.C_Str(); + } else { + materials[a].name = std::string(name.C_Str()) + to_string(materialCountWithThisName); + } } - } - if( materialCountWithThisName == 0 ) { - materials[a].name = name.C_Str(); - } else { - materials[a].name = std::string(name.C_Str()) + to_string(materialCountWithThisName); - } - } - aiShadingMode shading = aiShadingMode_Flat; - materials[a].shading_model = "phong"; - if(mat->Get( AI_MATKEY_SHADING_MODEL, shading) == aiReturn_SUCCESS) { - if(shading == aiShadingMode_Phong) { - materials[a].shading_model = "phong"; - } else if(shading == aiShadingMode_Blinn) { - materials[a].shading_model = "blinn"; - } else if(shading == aiShadingMode_NoShading) { - materials[a].shading_model = "constant"; - } else if(shading == aiShadingMode_Gouraud) { - materials[a].shading_model = "lambert"; + aiShadingMode shading = aiShadingMode_Flat; + materials[a].shading_model = "phong"; + if (mat->Get(AI_MATKEY_SHADING_MODEL, shading) == aiReturn_SUCCESS) { + if (shading == aiShadingMode_Phong) { + materials[a].shading_model = "phong"; + } else if (shading == aiShadingMode_Blinn) { + materials[a].shading_model = "blinn"; + } else if (shading == aiShadingMode_NoShading) { + materials[a].shading_model = "constant"; + } else if (shading == aiShadingMode_Gouraud) { + materials[a].shading_model = "lambert"; + } } + + ReadMaterialSurface(materials[a].ambient, mat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT); + if (!materials[a].ambient.texture.empty()) numTextures++; + ReadMaterialSurface(materials[a].diffuse, mat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE); + if (!materials[a].diffuse.texture.empty()) numTextures++; + ReadMaterialSurface(materials[a].specular, mat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR); + if (!materials[a].specular.texture.empty()) numTextures++; + ReadMaterialSurface(materials[a].emissive, mat, aiTextureType_EMISSIVE, AI_MATKEY_COLOR_EMISSIVE); + if (!materials[a].emissive.texture.empty()) numTextures++; + ReadMaterialSurface(materials[a].reflective, mat, aiTextureType_REFLECTION, AI_MATKEY_COLOR_REFLECTIVE); + if (!materials[a].reflective.texture.empty()) numTextures++; + ReadMaterialSurface(materials[a].transparent, mat, aiTextureType_OPACITY, AI_MATKEY_COLOR_TRANSPARENT); + if (!materials[a].transparent.texture.empty()) numTextures++; + ReadMaterialSurface(materials[a].normal, mat, aiTextureType_NORMALS, NULL, 0, 0); + if (!materials[a].normal.texture.empty()) numTextures++; + + materials[a].shininess.exist = mat->Get(AI_MATKEY_SHININESS, materials[a].shininess.value) == aiReturn_SUCCESS; + materials[a].transparency.exist = mat->Get(AI_MATKEY_OPACITY, materials[a].transparency.value) == aiReturn_SUCCESS; + materials[a].index_refraction.exist = mat->Get(AI_MATKEY_REFRACTI, materials[a].index_refraction.value) == aiReturn_SUCCESS; } - ReadMaterialSurface( materials[a].ambient, mat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT); - if( !materials[a].ambient.texture.empty() ) numTextures++; - ReadMaterialSurface( materials[a].diffuse, mat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE); - if( !materials[a].diffuse.texture.empty() ) numTextures++; - ReadMaterialSurface( materials[a].specular, mat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR); - if( !materials[a].specular.texture.empty() ) numTextures++; - ReadMaterialSurface( materials[a].emissive, mat, aiTextureType_EMISSIVE, AI_MATKEY_COLOR_EMISSIVE); - if( !materials[a].emissive.texture.empty() ) numTextures++; - ReadMaterialSurface( materials[a].reflective, mat, aiTextureType_REFLECTION, AI_MATKEY_COLOR_REFLECTIVE); - if( !materials[a].reflective.texture.empty() ) numTextures++; - ReadMaterialSurface( materials[a].transparent, mat, aiTextureType_OPACITY, AI_MATKEY_COLOR_TRANSPARENT); - if( !materials[a].transparent.texture.empty() ) numTextures++; - ReadMaterialSurface( materials[a].normal, mat, aiTextureType_NORMALS, NULL, 0, 0); - if( !materials[a].normal.texture.empty() ) numTextures++; - - materials[a].shininess.exist = mat->Get( AI_MATKEY_SHININESS, materials[a].shininess.value) == aiReturn_SUCCESS; - materials[a].transparency.exist = mat->Get( AI_MATKEY_OPACITY, materials[a].transparency.value) == aiReturn_SUCCESS; - materials[a].index_refraction.exist = mat->Get( AI_MATKEY_REFRACTI, materials[a].index_refraction.value) == aiReturn_SUCCESS; - } - - // output textures if present - if( numTextures > 0 ) - { - mOutput << startstr << "" << endstr; - PushTag(); - for( std::vector::const_iterator it = materials.begin(); it != materials.end(); ++it ) - { - const Material& mat = *it; - WriteImageEntry( mat.ambient, mat.name + "-ambient-image"); - WriteImageEntry( mat.diffuse, mat.name + "-diffuse-image"); - WriteImageEntry( mat.specular, mat.name + "-specular-image"); - WriteImageEntry( mat.emissive, mat.name + "-emission-image"); - WriteImageEntry( mat.reflective, mat.name + "-reflective-image"); - WriteImageEntry( mat.transparent, mat.name + "-transparent-image"); - WriteImageEntry( mat.normal, mat.name + "-normal-image"); + // output textures if present + if (numTextures > 0) { + mOutput << startstr << "" << endstr; + PushTag(); + for (std::vector::const_iterator it = materials.begin(); it != materials.end(); ++it) { + const Material &mat = *it; + WriteImageEntry(mat.ambient, mat.name + "-ambient-image"); + WriteImageEntry(mat.diffuse, mat.name + "-diffuse-image"); + WriteImageEntry(mat.specular, mat.name + "-specular-image"); + WriteImageEntry(mat.emissive, mat.name + "-emission-image"); + WriteImageEntry(mat.reflective, mat.name + "-reflective-image"); + WriteImageEntry(mat.transparent, mat.name + "-transparent-image"); + WriteImageEntry(mat.normal, mat.name + "-normal-image"); + } + PopTag(); + mOutput << startstr << "" << endstr; } - PopTag(); - mOutput << startstr << "" << endstr; - } - // output effects - those are the actual carriers of information - if( !materials.empty() ) - { - mOutput << startstr << "" << endstr; - PushTag(); - for( std::vector::const_iterator it = materials.begin(); it != materials.end(); ++it ) - { - const Material& mat = *it; - // this is so ridiculous it must be right - mOutput << startstr << "" << endstr; - PushTag(); - mOutput << startstr << "" << endstr; - PushTag(); + // output effects - those are the actual carriers of information + if (!materials.empty()) { + mOutput << startstr << "" << endstr; + PushTag(); + for (std::vector::const_iterator it = materials.begin(); it != materials.end(); ++it) { + const Material &mat = *it; + // this is so ridiculous it must be right + mOutput << startstr << "" << endstr; + PushTag(); + mOutput << startstr << "" << endstr; + PushTag(); - // write sampler- and surface params for the texture entries - WriteTextureParamEntry( mat.emissive, "emission", mat.name); - WriteTextureParamEntry( mat.ambient, "ambient", mat.name); - WriteTextureParamEntry( mat.diffuse, "diffuse", mat.name); - WriteTextureParamEntry( mat.specular, "specular", mat.name); - WriteTextureParamEntry( mat.reflective, "reflective", mat.name); - WriteTextureParamEntry( mat.transparent, "transparent", mat.name); - WriteTextureParamEntry( mat.normal, "normal", mat.name); + // write sampler- and surface params for the texture entries + WriteTextureParamEntry(mat.emissive, "emission", mat.name); + WriteTextureParamEntry(mat.ambient, "ambient", mat.name); + WriteTextureParamEntry(mat.diffuse, "diffuse", mat.name); + WriteTextureParamEntry(mat.specular, "specular", mat.name); + WriteTextureParamEntry(mat.reflective, "reflective", mat.name); + WriteTextureParamEntry(mat.transparent, "transparent", mat.name); + WriteTextureParamEntry(mat.normal, "normal", mat.name); - mOutput << startstr << "" << endstr; - PushTag(); - mOutput << startstr << "<" << mat.shading_model << ">" << endstr; - PushTag(); + mOutput << startstr << "" << endstr; + PushTag(); + mOutput << startstr << "<" << mat.shading_model << ">" << endstr; + PushTag(); - WriteTextureColorEntry( mat.emissive, "emission", mat.name + "-emission-sampler"); - WriteTextureColorEntry( mat.ambient, "ambient", mat.name + "-ambient-sampler"); - WriteTextureColorEntry( mat.diffuse, "diffuse", mat.name + "-diffuse-sampler"); - WriteTextureColorEntry( mat.specular, "specular", mat.name + "-specular-sampler"); - WriteFloatEntry(mat.shininess, "shininess"); - WriteTextureColorEntry( mat.reflective, "reflective", mat.name + "-reflective-sampler"); - WriteTextureColorEntry( mat.transparent, "transparent", mat.name + "-transparent-sampler"); - WriteFloatEntry(mat.transparency, "transparency"); - WriteFloatEntry(mat.index_refraction, "index_of_refraction"); + WriteTextureColorEntry(mat.emissive, "emission", mat.name + "-emission-sampler"); + WriteTextureColorEntry(mat.ambient, "ambient", mat.name + "-ambient-sampler"); + WriteTextureColorEntry(mat.diffuse, "diffuse", mat.name + "-diffuse-sampler"); + WriteTextureColorEntry(mat.specular, "specular", mat.name + "-specular-sampler"); + WriteFloatEntry(mat.shininess, "shininess"); + WriteTextureColorEntry(mat.reflective, "reflective", mat.name + "-reflective-sampler"); + WriteTextureColorEntry(mat.transparent, "transparent", mat.name + "-transparent-sampler"); + WriteFloatEntry(mat.transparency, "transparency"); + WriteFloatEntry(mat.index_refraction, "index_of_refraction"); - if(! mat.normal.texture.empty()) { - WriteTextureColorEntry( mat.normal, "bump", mat.name + "-normal-sampler"); - } + if (!mat.normal.texture.empty()) { + WriteTextureColorEntry(mat.normal, "bump", mat.name + "-normal-sampler"); + } - PopTag(); - mOutput << startstr << "" << endstr; - PopTag(); - mOutput << startstr << "" << endstr; - PopTag(); - mOutput << startstr << "" << endstr; - PopTag(); - mOutput << startstr << "" << endstr; + PopTag(); + mOutput << startstr << "" << endstr; + PopTag(); + mOutput << startstr << "" << endstr; + PopTag(); + mOutput << startstr << "" << endstr; + PopTag(); + mOutput << startstr << "" << endstr; + } + PopTag(); + mOutput << startstr << "" << endstr; + + // write materials - they're just effect references + mOutput << startstr << "" << endstr; + PushTag(); + for (std::vector::const_iterator it = materials.begin(); it != materials.end(); ++it) { + const Material &mat = *it; + mOutput << startstr << "" << endstr; + PushTag(); + mOutput << startstr << "" << endstr; + PopTag(); + mOutput << startstr << "" << endstr; + } + PopTag(); + mOutput << startstr << "" << endstr; } - PopTag(); - mOutput << startstr << "" << endstr; - - // write materials - they're just effect references - mOutput << startstr << "" << endstr; - PushTag(); - for( std::vector::const_iterator it = materials.begin(); it != materials.end(); ++it ) - { - const Material& mat = *it; - mOutput << startstr << "" << endstr; - PushTag(); - mOutput << startstr << "" << endstr; - PopTag(); - mOutput << startstr << "" << endstr; - } - PopTag(); - mOutput << startstr << "" << endstr; - } } // ------------------------------------------------------------------------------------------------ // Writes the controller library -void ColladaExporter::WriteControllerLibrary() -{ +void ColladaExporter::WriteControllerLibrary() { mOutput << startstr << "" << endstr; PushTag(); - - for( size_t a = 0; a < mScene->mNumMeshes; ++a) { - WriteController( a); + + for (size_t a = 0; a < mScene->mNumMeshes; ++a) { + WriteController(a); } PopTag(); @@ -875,20 +852,19 @@ void ColladaExporter::WriteControllerLibrary() // ------------------------------------------------------------------------------------------------ // Writes a skin controller of the given mesh -void ColladaExporter::WriteController( size_t pIndex) -{ - const aiMesh* mesh = mScene->mMeshes[pIndex]; +void ColladaExporter::WriteController(size_t pIndex) { + const aiMesh *mesh = mScene->mMeshes[pIndex]; const std::string idstr = mesh->mName.length == 0 ? GetMeshId(pIndex) : mesh->mName.C_Str(); const std::string idstrEscaped = XMLIDEncode(idstr); - if ( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 ) + if (mesh->mNumFaces == 0 || mesh->mNumVertices == 0) return; - if ( mesh->mNumBones == 0 ) + if (mesh->mNumBones == 0) return; mOutput << startstr << ""<< endstr; + mOutput << "name=\"skinCluster" << pIndex << "\">" << endstr; PushTag(); mOutput << startstr << "" << endstr; @@ -913,14 +889,14 @@ void ColladaExporter::WriteController( size_t pIndex) mOutput << startstr << "mNumBones << "\">"; - for( size_t i = 0; i < mesh->mNumBones; ++i ) + for (size_t i = 0; i < mesh->mNumBones; ++i) mOutput << XMLIDEncode(mesh->mBones[i]->mName.C_Str()) << " "; mOutput << "" << endstr; mOutput << startstr << "" << endstr; PushTag(); - + mOutput << startstr << "mNumBones << "\" stride=\"" << 1 << "\">" << endstr; PushTag(); @@ -937,21 +913,21 @@ void ColladaExporter::WriteController( size_t pIndex) std::vector bind_poses; bind_poses.reserve(mesh->mNumBones * 16); - for(unsigned int i = 0; i < mesh->mNumBones; ++i) - for( unsigned int j = 0; j < 4; ++j) + for (unsigned int i = 0; i < mesh->mNumBones; ++i) + for (unsigned int j = 0; j < 4; ++j) bind_poses.insert(bind_poses.end(), mesh->mBones[i]->mOffsetMatrix[j], mesh->mBones[i]->mOffsetMatrix[j] + 4); - WriteFloatArray( idstr + "-skin-bind_poses", FloatType_Mat4x4, (const ai_real*) bind_poses.data(), bind_poses.size() / 16); + WriteFloatArray(idstr + "-skin-bind_poses", FloatType_Mat4x4, (const ai_real *)bind_poses.data(), bind_poses.size() / 16); bind_poses.clear(); - + std::vector skin_weights; skin_weights.reserve(mesh->mNumVertices * mesh->mNumBones); - for( size_t i = 0; i < mesh->mNumBones; ++i) - for( size_t j = 0; j < mesh->mBones[i]->mNumWeights; ++j) + for (size_t i = 0; i < mesh->mNumBones; ++i) + for (size_t j = 0; j < mesh->mBones[i]->mNumWeights; ++j) skin_weights.push_back(mesh->mBones[i]->mWeights[j].mWeight); - WriteFloatArray( idstr + "-skin-weights", FloatType_Weight, (const ai_real*) skin_weights.data(), skin_weights.size()); + WriteFloatArray(idstr + "-skin-weights", FloatType_Weight, (const ai_real *)skin_weights.data(), skin_weights.size()); skin_weights.clear(); @@ -973,11 +949,11 @@ void ColladaExporter::WriteController( size_t pIndex) mOutput << startstr << ""; std::vector num_influences(mesh->mNumVertices, (ai_uint)0); - for( size_t i = 0; i < mesh->mNumBones; ++i) - for( size_t j = 0; j < mesh->mBones[i]->mNumWeights; ++j) + for (size_t i = 0; i < mesh->mNumBones; ++i) + for (size_t j = 0; j < mesh->mBones[i]->mNumWeights; ++j) ++num_influences[mesh->mBones[i]->mWeights[j].mVertexId]; - for( size_t i = 0; i < mesh->mNumVertices; ++i) + for (size_t i = 0; i < mesh->mNumVertices; ++i) mOutput << num_influences[i] << " "; mOutput << "" << endstr; @@ -987,22 +963,18 @@ void ColladaExporter::WriteController( size_t pIndex) ai_uint joint_weight_indices_length = 0; std::vector accum_influences; accum_influences.reserve(num_influences.size()); - for( size_t i = 0; i < num_influences.size(); ++i) - { + for (size_t i = 0; i < num_influences.size(); ++i) { accum_influences.push_back(joint_weight_indices_length); joint_weight_indices_length += num_influences[i]; } ai_uint weight_index = 0; std::vector joint_weight_indices(2 * joint_weight_indices_length, (ai_int)-1); - for( unsigned int i = 0; i < mesh->mNumBones; ++i) - for( unsigned j = 0; j < mesh->mBones[i]->mNumWeights; ++j) - { + for (unsigned int i = 0; i < mesh->mNumBones; ++i) + for (unsigned j = 0; j < mesh->mBones[i]->mNumWeights; ++j) { unsigned int vId = mesh->mBones[i]->mWeights[j].mVertexId; - for( ai_uint k = 0; k < num_influences[vId]; ++k) - { - if (joint_weight_indices[2 * (accum_influences[vId] + k)] == -1) - { + for (ai_uint k = 0; k < num_influences[vId]; ++k) { + if (joint_weight_indices[2 * (accum_influences[vId] + k)] == -1) { joint_weight_indices[2 * (accum_influences[vId] + k)] = i; joint_weight_indices[2 * (accum_influences[vId] + k) + 1] = weight_index; break; @@ -1011,7 +983,7 @@ void ColladaExporter::WriteController( size_t pIndex) ++weight_index; } - for( size_t i = 0; i < joint_weight_indices.size(); ++i) + for (size_t i = 0; i < joint_weight_indices.size(); ++i) mOutput << joint_weight_indices[i] << " "; num_influences.clear(); @@ -1025,20 +997,19 @@ void ColladaExporter::WriteController( size_t pIndex) PopTag(); mOutput << startstr << "" << endstr; - + PopTag(); mOutput << startstr << "" << endstr; } // ------------------------------------------------------------------------------------------------ // Writes the geometry library -void ColladaExporter::WriteGeometryLibrary() -{ +void ColladaExporter::WriteGeometryLibrary() { mOutput << startstr << "" << endstr; PushTag(); - for( size_t a = 0; a < mScene->mNumMeshes; ++a) - WriteGeometry( a); + for (size_t a = 0; a < mScene->mNumMeshes; ++a) + WriteGeometry(a); PopTag(); mOutput << startstr << "" << endstr; @@ -1046,14 +1017,13 @@ void ColladaExporter::WriteGeometryLibrary() // ------------------------------------------------------------------------------------------------ // Writes the given mesh -void ColladaExporter::WriteGeometry( size_t pIndex) -{ - const aiMesh* mesh = mScene->mMeshes[pIndex]; +void ColladaExporter::WriteGeometry(size_t pIndex) { + const aiMesh *mesh = mScene->mMeshes[pIndex]; const std::string idstr = mesh->mName.length == 0 ? GetMeshId(pIndex) : mesh->mName.C_Str(); const std::string geometryName = XMLEscape(idstr); const std::string geometryId = XMLIDEncode(idstr); - if ( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 ) + if (mesh->mNumFaces == 0 || mesh->mNumVertices == 0) return; // opening tag @@ -1064,31 +1034,29 @@ void ColladaExporter::WriteGeometry( size_t pIndex) PushTag(); // Positions - WriteFloatArray( idstr + "-positions", FloatType_Vector, (ai_real*) mesh->mVertices, mesh->mNumVertices); + WriteFloatArray(idstr + "-positions", FloatType_Vector, (ai_real *)mesh->mVertices, mesh->mNumVertices); // Normals, if any - if( mesh->HasNormals() ) - WriteFloatArray( idstr + "-normals", FloatType_Vector, (ai_real*) mesh->mNormals, mesh->mNumVertices); + if (mesh->HasNormals()) + WriteFloatArray(idstr + "-normals", FloatType_Vector, (ai_real *)mesh->mNormals, mesh->mNumVertices); // texture coords - for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) - { - if( mesh->HasTextureCoords(static_cast(a)) ) - { - WriteFloatArray( idstr + "-tex" + to_string(a), mesh->mNumUVComponents[a] == 3 ? FloatType_TexCoord3 : FloatType_TexCoord2, - (ai_real*) mesh->mTextureCoords[a], mesh->mNumVertices); + for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { + if (mesh->HasTextureCoords(static_cast(a))) { + WriteFloatArray(idstr + "-tex" + to_string(a), mesh->mNumUVComponents[a] == 3 ? FloatType_TexCoord3 : FloatType_TexCoord2, + (ai_real *)mesh->mTextureCoords[a], mesh->mNumVertices); } } // vertex colors - for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) - { - if( mesh->HasVertexColors(static_cast(a)) ) - WriteFloatArray( idstr + "-color" + to_string(a), FloatType_Color, (ai_real*) mesh->mColors[a], mesh->mNumVertices); + for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { + if (mesh->HasVertexColors(static_cast(a))) + WriteFloatArray(idstr + "-color" + to_string(a), FloatType_Color, (ai_real *)mesh->mColors[a], mesh->mNumVertices); } // assemble vertex structure // Only write input for POSITION since we will write other as shared inputs in polygon definition - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" << endstr; PopTag(); @@ -1097,37 +1065,38 @@ void ColladaExporter::WriteGeometry( size_t pIndex) // count the number of lines, triangles and polygon meshes int countLines = 0; int countPoly = 0; - for( size_t a = 0; a < mesh->mNumFaces; ++a ) - { - if (mesh->mFaces[a].mNumIndices == 2) countLines++; - else if (mesh->mFaces[a].mNumIndices >= 3) countPoly++; + for (size_t a = 0; a < mesh->mNumFaces; ++a) { + if (mesh->mFaces[a].mNumIndices == 2) + countLines++; + else if (mesh->mFaces[a].mNumIndices >= 3) + countPoly++; } // lines - if (countLines) - { + if (countLines) { mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" << endstr; - if( mesh->HasNormals() ) + if (mesh->HasNormals()) mOutput << startstr << "" << endstr; - for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) - { - if( mesh->HasTextureCoords(static_cast(a)) ) - mOutput << startstr << "" << endstr; + for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { + if (mesh->HasTextureCoords(static_cast(a))) + mOutput << startstr << "" << endstr; } - for( size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a ) - { - if( mesh->HasVertexColors(static_cast(a) ) ) - mOutput << startstr << "" << endstr; + for (size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) { + if (mesh->HasVertexColors(static_cast(a))) + mOutput << startstr << "" << endstr; } mOutput << startstr << "

"; - for( size_t a = 0; a < mesh->mNumFaces; ++a ) - { - const aiFace& face = mesh->mFaces[a]; + for (size_t a = 0; a < mesh->mNumFaces; ++a) { + const aiFace &face = mesh->mFaces[a]; if (face.mNumIndices != 2) continue; - for( size_t b = 0; b < face.mNumIndices; ++b ) + for (size_t b = 0; b < face.mNumIndices; ++b) mOutput << face.mIndices[b] << " "; } mOutput << "

" << endstr; @@ -1138,38 +1107,37 @@ void ColladaExporter::WriteGeometry( size_t pIndex) // triangle - don't use it, because compatibility problems // polygons - if (countPoly) - { + if (countPoly) { mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" << endstr; - if( mesh->HasNormals() ) + if (mesh->HasNormals()) mOutput << startstr << "" << endstr; - for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) - { - if( mesh->HasTextureCoords(static_cast(a)) ) - mOutput << startstr << "" << endstr; + for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { + if (mesh->HasTextureCoords(static_cast(a))) + mOutput << startstr << "" << endstr; } - for( size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a ) - { - if( mesh->HasVertexColors(static_cast(a) ) ) - mOutput << startstr << "" << endstr; + for (size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) { + if (mesh->HasVertexColors(static_cast(a))) + mOutput << startstr << "" << endstr; } mOutput << startstr << ""; - for( size_t a = 0; a < mesh->mNumFaces; ++a ) - { + for (size_t a = 0; a < mesh->mNumFaces; ++a) { if (mesh->mFaces[a].mNumIndices < 3) continue; mOutput << mesh->mFaces[a].mNumIndices << " "; } mOutput << "" << endstr; mOutput << startstr << "

"; - for( size_t a = 0; a < mesh->mNumFaces; ++a ) - { - const aiFace& face = mesh->mFaces[a]; + for (size_t a = 0; a < mesh->mNumFaces; ++a) { + const aiFace &face = mesh->mFaces[a]; if (face.mNumIndices < 3) continue; - for( size_t b = 0; b < face.mNumIndices; ++b ) + for (size_t b = 0; b < face.mNumIndices; ++b) mOutput << face.mIndices[b] << " "; } mOutput << "

" << endstr; @@ -1186,20 +1154,18 @@ void ColladaExporter::WriteGeometry( size_t pIndex) // ------------------------------------------------------------------------------------------------ // Writes a float array of the given type -void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataType pType, const ai_real* pData, size_t pElementCount) -{ +void ColladaExporter::WriteFloatArray(const std::string &pIdString, FloatDataType pType, const ai_real *pData, size_t pElementCount) { size_t floatsPerElement = 0; - switch( pType ) - { - case FloatType_Vector: floatsPerElement = 3; break; - case FloatType_TexCoord2: floatsPerElement = 2; break; - case FloatType_TexCoord3: floatsPerElement = 3; break; - case FloatType_Color: floatsPerElement = 3; break; - case FloatType_Mat4x4: floatsPerElement = 16; break; - case FloatType_Weight: floatsPerElement = 1; break; - case FloatType_Time: floatsPerElement = 1; break; - default: - return; + switch (pType) { + case FloatType_Vector: floatsPerElement = 3; break; + case FloatType_TexCoord2: floatsPerElement = 2; break; + case FloatType_TexCoord3: floatsPerElement = 3; break; + case FloatType_Color: floatsPerElement = 3; break; + case FloatType_Mat4x4: floatsPerElement = 16; break; + case FloatType_Weight: floatsPerElement = 1; break; + case FloatType_Time: floatsPerElement = 1; break; + default: + return; } std::string arrayId = XMLIDEncode(pIdString) + "-array"; @@ -1211,26 +1177,19 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy mOutput << startstr << " "; PushTag(); - if( pType == FloatType_TexCoord2 ) - { - for( size_t a = 0; a < pElementCount; ++a ) - { - mOutput << pData[a*3+0] << " "; - mOutput << pData[a*3+1] << " "; + if (pType == FloatType_TexCoord2) { + for (size_t a = 0; a < pElementCount; ++a) { + mOutput << pData[a * 3 + 0] << " "; + mOutput << pData[a * 3 + 1] << " "; } - } - else if( pType == FloatType_Color ) - { - for( size_t a = 0; a < pElementCount; ++a ) - { - mOutput << pData[a*4+0] << " "; - mOutput << pData[a*4+1] << " "; - mOutput << pData[a*4+2] << " "; + } else if (pType == FloatType_Color) { + for (size_t a = 0; a < pElementCount; ++a) { + mOutput << pData[a * 4 + 0] << " "; + mOutput << pData[a * 4 + 1] << " "; + mOutput << pData[a * 4 + 2] << " "; } - } - else - { - for( size_t a = 0; a < pElementCount * floatsPerElement; ++a ) + } else { + for (size_t a = 0; a < pElementCount * floatsPerElement; ++a) mOutput << pData[a] << " "; } mOutput << "" << endstr; @@ -1242,45 +1201,43 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy mOutput << startstr << "" << endstr; PushTag(); - switch( pType ) - { - case FloatType_Vector: - mOutput << startstr << "" << endstr; - mOutput << startstr << "" << endstr; - mOutput << startstr << "" << endstr; - break; + switch (pType) { + case FloatType_Vector: + mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; + break; - case FloatType_TexCoord2: - mOutput << startstr << "" << endstr; - mOutput << startstr << "" << endstr; - break; + case FloatType_TexCoord2: + mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; + break; - case FloatType_TexCoord3: - mOutput << startstr << "" << endstr; - mOutput << startstr << "" << endstr; - mOutput << startstr << "" << endstr; - break; + case FloatType_TexCoord3: + mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; + break; - case FloatType_Color: - mOutput << startstr << "" << endstr; - mOutput << startstr << "" << endstr; - mOutput << startstr << "" << endstr; - break; + case FloatType_Color: + mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; + break; - case FloatType_Mat4x4: - mOutput << startstr << "" << endstr; - break; + case FloatType_Mat4x4: + mOutput << startstr << "" << endstr; + break; - case FloatType_Weight: - mOutput << startstr << "" << endstr; - break; + case FloatType_Weight: + mOutput << startstr << "" << endstr; + break; - // customized, add animation related - case FloatType_Time: - mOutput << startstr << "" << endstr; - break; - - } + // customized, add animation related + case FloatType_Time: + mOutput << startstr << "" << endstr; + break; + } PopTag(); mOutput << startstr << "" << endstr; @@ -1292,8 +1249,7 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy // ------------------------------------------------------------------------------------------------ // Writes the scene library -void ColladaExporter::WriteSceneLibrary() -{ +void ColladaExporter::WriteSceneLibrary() { const std::string sceneName = XMLEscape(mScene->mRootNode->mName.C_Str()); const std::string sceneId = XMLIDEncode(mScene->mRootNode->mName.C_Str()); @@ -1303,8 +1259,8 @@ void ColladaExporter::WriteSceneLibrary() PushTag(); // start recursive write at the root node - for( size_t a = 0; a < mScene->mRootNode->mNumChildren; ++a ) - WriteNode( mScene, mScene->mRootNode->mChildren[a]); + for (size_t a = 0; a < mScene->mRootNode->mNumChildren; ++a) + WriteNode(mScene, mScene->mRootNode->mChildren[a]); PopTag(); mOutput << startstr << "" << endstr; @@ -1312,182 +1268,180 @@ void ColladaExporter::WriteSceneLibrary() mOutput << startstr << "" << endstr; } // ------------------------------------------------------------------------------------------------ -void ColladaExporter::WriteAnimationLibrary(size_t pIndex) -{ - const aiAnimation * anim = mScene->mAnimations[pIndex]; - - if ( anim->mNumChannels == 0 && anim->mNumMeshChannels == 0 && anim->mNumMorphMeshChannels ==0 ) - return; - - const std::string animation_name_escaped = XMLEscape( anim->mName.C_Str() ); - std::string idstr = anim->mName.C_Str(); - std::string ending = std::string( "AnimId" ) + to_string(pIndex); - if (idstr.length() >= ending.length()) { - if (0 != idstr.compare (idstr.length() - ending.length(), ending.length(), ending)) { - idstr = idstr + ending; - } - } else { - idstr = idstr + ending; - } +void ColladaExporter::WriteAnimationLibrary(size_t pIndex) { + const aiAnimation *anim = mScene->mAnimations[pIndex]; - const std::string idstrEscaped = XMLIDEncode(idstr); - - mOutput << startstr << "" << endstr; - PushTag(); + if (anim->mNumChannels == 0 && anim->mNumMeshChannels == 0 && anim->mNumMorphMeshChannels == 0) + return; + + const std::string animation_name_escaped = XMLEscape(anim->mName.C_Str()); + std::string idstr = anim->mName.C_Str(); + std::string ending = std::string("AnimId") + to_string(pIndex); + if (idstr.length() >= ending.length()) { + if (0 != idstr.compare(idstr.length() - ending.length(), ending.length(), ending)) { + idstr = idstr + ending; + } + } else { + idstr = idstr + ending; + } + + const std::string idstrEscaped = XMLIDEncode(idstr); + + mOutput << startstr << "" << endstr; + PushTag(); std::string cur_node_idstr; - for (size_t a = 0; a < anim->mNumChannels; ++a) { - const aiNodeAnim * nodeAnim = anim->mChannels[a]; - - // sanity check + for (size_t a = 0; a < anim->mNumChannels; ++a) { + const aiNodeAnim *nodeAnim = anim->mChannels[a]; + + // sanity check if (nodeAnim->mNumPositionKeys != nodeAnim->mNumScalingKeys || nodeAnim->mNumPositionKeys != nodeAnim->mNumRotationKeys) { continue; } - - { + + { cur_node_idstr.clear(); cur_node_idstr += nodeAnim->mNodeName.data; cur_node_idstr += std::string("_matrix-input"); - std::vector frames; - for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) { - frames.push_back(static_cast(nodeAnim->mPositionKeys[i].mTime)); - } - - WriteFloatArray(cur_node_idstr, FloatType_Time, (const ai_real *)frames.data(), frames.size()); - frames.clear(); - } - - { + std::vector frames; + for (size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) { + frames.push_back(static_cast(nodeAnim->mPositionKeys[i].mTime)); + } + + WriteFloatArray(cur_node_idstr, FloatType_Time, (const ai_real *)frames.data(), frames.size()); + frames.clear(); + } + + { cur_node_idstr.clear(); cur_node_idstr += nodeAnim->mNodeName.data; cur_node_idstr += std::string("_matrix-output"); - - std::vector keyframes; - keyframes.reserve(nodeAnim->mNumPositionKeys * 16); - for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) { - aiVector3D Scaling = nodeAnim->mScalingKeys[i].mValue; - aiMatrix4x4 ScalingM; // identity - ScalingM[0][0] = Scaling.x; ScalingM[1][1] = Scaling.y; ScalingM[2][2] = Scaling.z; - - aiQuaternion RotationQ = nodeAnim->mRotationKeys[i].mValue; - aiMatrix4x4 s = aiMatrix4x4( RotationQ.GetMatrix() ); - aiMatrix4x4 RotationM(s.a1, s.a2, s.a3, 0, s.b1, s.b2, s.b3, 0, s.c1, s.c2, s.c3, 0, 0, 0, 0, 1); - - aiVector3D Translation = nodeAnim->mPositionKeys[i].mValue; - aiMatrix4x4 TranslationM; // identity - TranslationM[0][3] = Translation.x; TranslationM[1][3] = Translation.y; TranslationM[2][3] = Translation.z; - - // Combine the above transformations - aiMatrix4x4 mat = TranslationM * RotationM * ScalingM; - - for( unsigned int j = 0; j < 4; ++j) { - keyframes.insert(keyframes.end(), mat[j], mat[j] + 4); + + std::vector keyframes; + keyframes.reserve(nodeAnim->mNumPositionKeys * 16); + for (size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) { + aiVector3D Scaling = nodeAnim->mScalingKeys[i].mValue; + aiMatrix4x4 ScalingM; // identity + ScalingM[0][0] = Scaling.x; + ScalingM[1][1] = Scaling.y; + ScalingM[2][2] = Scaling.z; + + aiQuaternion RotationQ = nodeAnim->mRotationKeys[i].mValue; + aiMatrix4x4 s = aiMatrix4x4(RotationQ.GetMatrix()); + aiMatrix4x4 RotationM(s.a1, s.a2, s.a3, 0, s.b1, s.b2, s.b3, 0, s.c1, s.c2, s.c3, 0, 0, 0, 0, 1); + + aiVector3D Translation = nodeAnim->mPositionKeys[i].mValue; + aiMatrix4x4 TranslationM; // identity + TranslationM[0][3] = Translation.x; + TranslationM[1][3] = Translation.y; + TranslationM[2][3] = Translation.z; + + // Combine the above transformations + aiMatrix4x4 mat = TranslationM * RotationM * ScalingM; + + for (unsigned int j = 0; j < 4; ++j) { + keyframes.insert(keyframes.end(), mat[j], mat[j] + 4); } - } - - WriteFloatArray(cur_node_idstr, FloatType_Mat4x4, (const ai_real *)keyframes.data(), keyframes.size() / 16); - } - - { - std::vector names; - for ( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) { - if ( nodeAnim->mPreState == aiAnimBehaviour_DEFAULT - || nodeAnim->mPreState == aiAnimBehaviour_LINEAR - || nodeAnim->mPreState == aiAnimBehaviour_REPEAT - ) { - names.push_back( "LINEAR" ); - } else if (nodeAnim->mPostState == aiAnimBehaviour_CONSTANT) { - names.push_back( "STEP" ); - } - } - - const std::string cur_node_idstr2 = nodeAnim->mNodeName.data + std::string("_matrix-interpolation"); - std::string arrayId = XMLIDEncode(cur_node_idstr2) + "-array"; - - mOutput << startstr << "" << endstr; - PushTag(); - - // source array - mOutput << startstr << " "; - for( size_t aa = 0; aa < names.size(); ++aa ) { - mOutput << names[aa] << " "; } - mOutput << "" << endstr; - - mOutput << startstr << "" << endstr; - PushTag(); - mOutput << startstr << "" << endstr; - PushTag(); - - mOutput << startstr << "" << endstr; - - PopTag(); - mOutput << startstr << "" << endstr; - - PopTag(); - mOutput << startstr << "" << endstr; + WriteFloatArray(cur_node_idstr, FloatType_Mat4x4, (const ai_real *)keyframes.data(), keyframes.size() / 16); + } - PopTag(); - mOutput << startstr << "" << endstr; - } - } - - for (size_t a = 0; a < anim->mNumChannels; ++a) { - const aiNodeAnim * nodeAnim = anim->mChannels[a]; - - { - // samplers - const std::string node_idstr = nodeAnim->mNodeName.data + std::string("_matrix-sampler"); - mOutput << startstr << "" << endstr; - PushTag(); - - mOutput << startstr << "mNodeName.data + std::string("_matrix-input") ) << "\"/>" << endstr; - mOutput << startstr << "mNodeName.data + std::string("_matrix-output") ) << "\"/>" << endstr; - mOutput << startstr << "mNodeName.data + std::string("_matrix-interpolation") ) << "\"/>" << endstr; - - PopTag(); - mOutput << startstr << "" << endstr; - } - } - - for (size_t a = 0; a < anim->mNumChannels; ++a) { - const aiNodeAnim * nodeAnim = anim->mChannels[a]; - - { - // channels - mOutput << startstr << "mNodeName.data + std::string("_matrix-sampler") ) << "\" target=\"" << XMLIDEncode(nodeAnim->mNodeName.data) << "/matrix\"/>" << endstr; - } - } - - PopTag(); - mOutput << startstr << "" << endstr; - + { + std::vector names; + for (size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) { + if (nodeAnim->mPreState == aiAnimBehaviour_DEFAULT || nodeAnim->mPreState == aiAnimBehaviour_LINEAR || nodeAnim->mPreState == aiAnimBehaviour_REPEAT) { + names.push_back("LINEAR"); + } else if (nodeAnim->mPostState == aiAnimBehaviour_CONSTANT) { + names.push_back("STEP"); + } + } + + const std::string cur_node_idstr2 = nodeAnim->mNodeName.data + std::string("_matrix-interpolation"); + std::string arrayId = XMLIDEncode(cur_node_idstr2) + "-array"; + + mOutput << startstr << "" << endstr; + PushTag(); + + // source array + mOutput << startstr << " "; + for (size_t aa = 0; aa < names.size(); ++aa) { + mOutput << names[aa] << " "; + } + mOutput << "" << endstr; + + mOutput << startstr << "" << endstr; + PushTag(); + + mOutput << startstr << "" << endstr; + PushTag(); + + mOutput << startstr << "" << endstr; + + PopTag(); + mOutput << startstr << "" << endstr; + + PopTag(); + mOutput << startstr << "" << endstr; + + PopTag(); + mOutput << startstr << "" << endstr; + } + } + + for (size_t a = 0; a < anim->mNumChannels; ++a) { + const aiNodeAnim *nodeAnim = anim->mChannels[a]; + + { + // samplers + const std::string node_idstr = nodeAnim->mNodeName.data + std::string("_matrix-sampler"); + mOutput << startstr << "" << endstr; + PushTag(); + + mOutput << startstr << "mNodeName.data + std::string("_matrix-input")) << "\"/>" << endstr; + mOutput << startstr << "mNodeName.data + std::string("_matrix-output")) << "\"/>" << endstr; + mOutput << startstr << "mNodeName.data + std::string("_matrix-interpolation")) << "\"/>" << endstr; + + PopTag(); + mOutput << startstr << "" << endstr; + } + } + + for (size_t a = 0; a < anim->mNumChannels; ++a) { + const aiNodeAnim *nodeAnim = anim->mChannels[a]; + + { + // channels + mOutput << startstr << "mNodeName.data + std::string("_matrix-sampler")) << "\" target=\"" << XMLIDEncode(nodeAnim->mNodeName.data) << "/matrix\"/>" << endstr; + } + } + + PopTag(); + mOutput << startstr << "" << endstr; } // ------------------------------------------------------------------------------------------------ -void ColladaExporter::WriteAnimationsLibrary() -{ - if ( mScene->mNumAnimations > 0 ) { - mOutput << startstr << "" << endstr; - PushTag(); - - // start recursive write at the root node - for( size_t a = 0; a < mScene->mNumAnimations; ++a) - WriteAnimationLibrary( a ); +void ColladaExporter::WriteAnimationsLibrary() { + if (mScene->mNumAnimations > 0) { + mOutput << startstr << "" << endstr; + PushTag(); - PopTag(); - mOutput << startstr << "" << endstr; - } + // start recursive write at the root node + for (size_t a = 0; a < mScene->mNumAnimations; ++a) + WriteAnimationLibrary(a); + + PopTag(); + mOutput << startstr << "" << endstr; + } } // ------------------------------------------------------------------------------------------------ // Helper to find a bone by name in the scene -aiBone* findBone( const aiScene* scene, const char * name) { - for (size_t m=0; mmNumMeshes; m++) { - aiMesh * mesh = scene->mMeshes[m]; - for (size_t b=0; bmNumBones; b++) { - aiBone * bone = mesh->mBones[b]; +aiBone *findBone(const aiScene *scene, const char *name) { + for (size_t m = 0; m < scene->mNumMeshes; m++) { + aiMesh *mesh = scene->mMeshes[m]; + for (size_t b = 0; b < mesh->mNumBones; b++) { + aiBone *bone = mesh->mBones[b]; if (0 == strcmp(name, bone->mName.C_Str())) { return bone; } @@ -1497,65 +1451,61 @@ aiBone* findBone( const aiScene* scene, const char * name) { } // ------------------------------------------------------------------------------------------------ -const aiNode * findBoneNode( const aiNode* aNode, const aiBone* bone) -{ - if ( aNode && bone && aNode->mName == bone->mName ) { - return aNode; - } - - if ( aNode && bone ) { - for (unsigned int i=0; i < aNode->mNumChildren; ++i) { - aiNode * aChild = aNode->mChildren[i]; - const aiNode * foundFromChild = 0; - if ( aChild ) { - foundFromChild = findBoneNode( aChild, bone ); - if ( foundFromChild ) return foundFromChild; - } - } - } - - return NULL; +const aiNode *findBoneNode(const aiNode *aNode, const aiBone *bone) { + if (aNode && bone && aNode->mName == bone->mName) { + return aNode; + } + + if (aNode && bone) { + for (unsigned int i = 0; i < aNode->mNumChildren; ++i) { + aiNode *aChild = aNode->mChildren[i]; + const aiNode *foundFromChild = 0; + if (aChild) { + foundFromChild = findBoneNode(aChild, bone); + if (foundFromChild) return foundFromChild; + } + } + } + + return NULL; } -const aiNode * findSkeletonRootNode( const aiScene* scene, const aiMesh * mesh) -{ - std::set topParentBoneNodes; - if ( mesh && mesh->mNumBones > 0 ) { - for (unsigned int i=0; i < mesh->mNumBones; ++i) { - aiBone * bone = mesh->mBones[i]; +const aiNode *findSkeletonRootNode(const aiScene *scene, const aiMesh *mesh) { + std::set topParentBoneNodes; + if (mesh && mesh->mNumBones > 0) { + for (unsigned int i = 0; i < mesh->mNumBones; ++i) { + aiBone *bone = mesh->mBones[i]; - const aiNode * node = findBoneNode( scene->mRootNode, bone); - if ( node ) { - while ( node->mParent && findBone(scene, node->mParent->mName.C_Str() ) != 0 ) { - node = node->mParent; - } - topParentBoneNodes.insert( node ); - } - } - } - - if ( !topParentBoneNodes.empty() ) { - const aiNode * parentBoneNode = *topParentBoneNodes.begin(); - if ( topParentBoneNodes.size() == 1 ) { - return parentBoneNode; - } else { - for (auto it : topParentBoneNodes) { - if ( it->mParent ) return it->mParent; - } - return parentBoneNode; - } - } - - return NULL; + const aiNode *node = findBoneNode(scene->mRootNode, bone); + if (node) { + while (node->mParent && findBone(scene, node->mParent->mName.C_Str()) != 0) { + node = node->mParent; + } + topParentBoneNodes.insert(node); + } + } + } + + if (!topParentBoneNodes.empty()) { + const aiNode *parentBoneNode = *topParentBoneNodes.begin(); + if (topParentBoneNodes.size() == 1) { + return parentBoneNode; + } else { + for (auto it : topParentBoneNodes) { + if (it->mParent) return it->mParent; + } + return parentBoneNode; + } + } + + return NULL; } // ------------------------------------------------------------------------------------------------ // Recursively writes the given node -void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode) -{ +void ColladaExporter::WriteNode(const aiScene *pScene, aiNode *pNode) { // the node must have a name - if (pNode->mName.length == 0) - { + if (pNode->mName.length == 0) { std::stringstream ss; ss << "Node_" << pNode; pNode->mName.Set(ss.str()); @@ -1563,7 +1513,7 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode) // If the node is associated with a bone, it is a joint node (JOINT) // otherwise it is a normal node (NODE) - const char * node_type; + const char *node_type; bool is_joint, is_skeleton_root = false; if (nullptr == findBone(pScene, pNode->mName.C_Str())) { node_type = "NODE"; @@ -1578,14 +1528,14 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode) const std::string node_id = XMLIDEncode(pNode->mName.data); const std::string node_name = XMLEscape(pNode->mName.data); - mOutput << startstr << "" << endstr; @@ -1599,8 +1549,8 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode) // When importing from Collada, the mLookAt is set to 0, 0, -1, and the node transform is unchanged. // When importing from a different format, mLookAt is set to 0, 0, 1. Therefore, the local camera // coordinate system must be changed to matche the Collada specification. - for (size_t i = 0; imNumCameras; i++){ - if (mScene->mCameras[i]->mName == pNode->mName){ + for (size_t i = 0; i < mScene->mNumCameras; i++) { + if (mScene->mCameras[i]->mName == pNode->mName) { aiMatrix4x4 sourceView; mScene->mCameras[i]->GetCameraMatrix(sourceView); @@ -1610,95 +1560,90 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode) break; } } - - // customized, sid should be 'matrix' to match with loader code. + + // customized, sid should be 'matrix' to match with loader code. //mOutput << startstr << ""; - mOutput << startstr << ""; - + mOutput << startstr << ""; + mOutput << mat.a1 << " " << mat.a2 << " " << mat.a3 << " " << mat.a4 << " "; mOutput << mat.b1 << " " << mat.b2 << " " << mat.b3 << " " << mat.b4 << " "; mOutput << mat.c1 << " " << mat.c2 << " " << mat.c3 << " " << mat.c4 << " "; mOutput << mat.d1 << " " << mat.d2 << " " << mat.d3 << " " << mat.d4; mOutput << "" << endstr; - if(pNode->mNumMeshes==0){ + if (pNode->mNumMeshes == 0) { //check if it is a camera node - for(size_t i=0; imNumCameras; i++){ - if(mScene->mCameras[i]->mName == pNode->mName){ - mOutput << startstr <<"" << endstr; + for (size_t i = 0; i < mScene->mNumCameras; i++) { + if (mScene->mCameras[i]->mName == pNode->mName) { + mOutput << startstr << "" << endstr; break; } } //check if it is a light node - for(size_t i=0; imNumLights; i++){ - if(mScene->mLights[i]->mName == pNode->mName){ - mOutput << startstr <<"" << endstr; + for (size_t i = 0; i < mScene->mNumLights; i++) { + if (mScene->mLights[i]->mName == pNode->mName) { + mOutput << startstr << "" << endstr; break; } } - }else - // instance every geometry - for( size_t a = 0; a < pNode->mNumMeshes; ++a ) - { - const aiMesh* mesh = mScene->mMeshes[pNode->mMeshes[a]]; - // do not instantiate mesh if empty. I wonder how this could happen - if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 ) - continue; + } else + // instance every geometry + for (size_t a = 0; a < pNode->mNumMeshes; ++a) { + const aiMesh *mesh = mScene->mMeshes[pNode->mMeshes[a]]; + // do not instantiate mesh if empty. I wonder how this could happen + if (mesh->mNumFaces == 0 || mesh->mNumVertices == 0) + continue; - const std::string meshName = mesh->mName.length == 0 ? GetMeshId(pNode->mMeshes[a]) : mesh->mName.C_Str(); + const std::string meshName = mesh->mName.length == 0 ? GetMeshId(pNode->mMeshes[a]) : mesh->mName.C_Str(); - if( mesh->mNumBones == 0 ) - { - mOutput << startstr << "" << endstr; + if (mesh->mNumBones == 0) { + mOutput << startstr << "" << endstr; + PushTag(); + } else { + mOutput << startstr + << "" + << endstr; + PushTag(); + + // note! this mFoundSkeletonRootNodeID some how affects animation, it makes the mesh attaches to armature skeleton root node. + // use the first bone to find skeleton root + const aiNode *skeletonRootBoneNode = findSkeletonRootNode(pScene, mesh); + if (skeletonRootBoneNode) { + mFoundSkeletonRootNodeID = XMLIDEncode(skeletonRootBoneNode->mName.C_Str()); + } + mOutput << startstr << "#" << mFoundSkeletonRootNodeID << "" << endstr; + } + mOutput << startstr << "" << endstr; PushTag(); - } - else - { - mOutput << startstr - << "" - << endstr; + mOutput << startstr << "" << endstr; PushTag(); + mOutput << startstr << "mMaterialIndex].name) << "\">" << endstr; + PushTag(); + for (size_t aa = 0; aa < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++aa) { + if (mesh->HasTextureCoords(static_cast(aa))) + // semantic as in + // input_semantic as in + // input_set as in + mOutput << startstr << "" << endstr; + } + PopTag(); + mOutput << startstr << "" << endstr; + PopTag(); + mOutput << startstr << "" << endstr; + PopTag(); + mOutput << startstr << "" << endstr; - // note! this mFoundSkeletonRootNodeID some how affects animation, it makes the mesh attaches to armature skeleton root node. - // use the first bone to find skeleton root - const aiNode * skeletonRootBoneNode = findSkeletonRootNode( pScene, mesh ); - if ( skeletonRootBoneNode ) { - mFoundSkeletonRootNodeID = XMLIDEncode( skeletonRootBoneNode->mName.C_Str() ); - } - mOutput << startstr << "#" << mFoundSkeletonRootNodeID << "" << endstr; + PopTag(); + if (mesh->mNumBones == 0) + mOutput << startstr << "" << endstr; + else + mOutput << startstr << "" << endstr; } - mOutput << startstr << "" << endstr; - PushTag(); - mOutput << startstr << "" << endstr; - PushTag(); - mOutput << startstr << "mMaterialIndex].name) << "\">" << endstr; - PushTag(); - for( size_t aa = 0; aa < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++aa ) - { - if( mesh->HasTextureCoords( static_cast(aa) ) ) - // semantic as in - // input_semantic as in - // input_set as in - mOutput << startstr << "" << endstr; - } - PopTag(); - mOutput << startstr << "" << endstr; - PopTag(); - mOutput << startstr << "" << endstr; - PopTag(); - mOutput << startstr << "" << endstr; - - PopTag(); - if( mesh->mNumBones == 0) - mOutput << startstr << "" << endstr; - else - mOutput << startstr << "" << endstr; - } // recurse into subnodes - for( size_t a = 0; a < pNode->mNumChildren; ++a ) - WriteNode( pScene, pNode->mChildren[a]); + for (size_t a = 0; a < pNode->mNumChildren; ++a) + WriteNode(pScene, pNode->mChildren[a]); PopTag(); mOutput << startstr << "" << endstr; diff --git a/code/Collada/ColladaExporter.h b/code/Collada/ColladaExporter.h index f6c66e279..fa7e6ee80 100644 --- a/code/Collada/ColladaExporter.h +++ b/code/Collada/ColladaExporter.h @@ -47,29 +47,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_COLLADAEXPORTER_H_INC #include +#include #include #include -#include #include +#include #include #include -#include #include struct aiScene; struct aiNode; -namespace Assimp -{ +namespace Assimp { /// Helper class to export a given scene to a Collada file. Just for my personal /// comfort when implementing it. -class ColladaExporter -{ +class ColladaExporter { public: /// Constructor for a specific scene to export - ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file); + ColladaExporter(const aiScene *pScene, IOSystem *pIOSystem, const std::string &path, const std::string &file); /// Destructor virtual ~ColladaExporter(); @@ -107,43 +105,49 @@ protected: void WriteControllerLibrary(); /// Writes a skin controller of the given mesh - void WriteController( size_t pIndex); + void WriteController(size_t pIndex); /// Writes the geometry library void WriteGeometryLibrary(); /// Writes the given mesh - void WriteGeometry( size_t pIndex); + void WriteGeometry(size_t pIndex); //enum FloatDataType { FloatType_Vector, FloatType_TexCoord2, FloatType_TexCoord3, FloatType_Color, FloatType_Mat4x4, FloatType_Weight }; // customized to add animation related type - enum FloatDataType { FloatType_Vector, FloatType_TexCoord2, FloatType_TexCoord3, FloatType_Color, FloatType_Mat4x4, FloatType_Weight, FloatType_Time }; + enum FloatDataType { FloatType_Vector, + FloatType_TexCoord2, + FloatType_TexCoord3, + FloatType_Color, + FloatType_Mat4x4, + FloatType_Weight, + FloatType_Time }; /// Writes a float array of the given type - void WriteFloatArray( const std::string& pIdString, FloatDataType pType, const ai_real* pData, size_t pElementCount); + void WriteFloatArray(const std::string &pIdString, FloatDataType pType, const ai_real *pData, size_t pElementCount); /// Writes the scene library void WriteSceneLibrary(); - // customized, Writes the animation library - void WriteAnimationsLibrary(); - void WriteAnimationLibrary( size_t pIndex); - std::string mFoundSkeletonRootNodeID = "skeleton_root"; // will be replaced by found node id in the WriteNode call. - + // customized, Writes the animation library + void WriteAnimationsLibrary(); + void WriteAnimationLibrary(size_t pIndex); + std::string mFoundSkeletonRootNodeID = "skeleton_root"; // will be replaced by found node id in the WriteNode call. + /// Recursively writes the given node - void WriteNode( const aiScene* scene, aiNode* pNode); + void WriteNode(const aiScene *scene, aiNode *pNode); /// Enters a new xml element, which increases the indentation - void PushTag() { startstr.append( " "); } + void PushTag() { startstr.append(" "); } /// Leaves an element, decreasing the indentation - void PopTag() { - ai_assert( startstr.length() > 1); - startstr.erase( startstr.length() - 2); + void PopTag() { + ai_assert(startstr.length() > 1); + startstr.erase(startstr.length() - 2); } /// Creates a mesh ID for the given mesh - std::string GetMeshId( size_t pIndex) const { - return std::string( "meshId" ) + to_string(pIndex); + std::string GetMeshId(size_t pIndex) const { + return std::string("meshId") + to_string(pIndex); } public: @@ -151,7 +155,7 @@ public: std::stringstream mOutput; /// The IOSystem for output - IOSystem* mIOSystem; + IOSystem *mIOSystem; /// Path of the directory where the scene will be exported const std::string mPath; @@ -160,7 +164,7 @@ public: const std::string mFile; /// The scene to be written - const aiScene* mScene; + const aiScene *mScene; bool mSceneOwned; /// current line start string, contains the current indentation for simple stream insertion @@ -168,55 +172,54 @@ public: /// current line end string for simple stream insertion std::string endstr; - // pair of color and texture - texture precedences color - struct Surface - { - bool exist; - aiColor4D color; - std::string texture; - size_t channel; - Surface() { exist = false; channel = 0; } - }; + // pair of color and texture - texture precedences color + struct Surface { + bool exist; + aiColor4D color; + std::string texture; + size_t channel; + Surface() { + exist = false; + channel = 0; + } + }; - struct Property - { - bool exist; - ai_real value; - Property() - : exist(false) - , value(0.0) - {} - }; + struct Property { + bool exist; + ai_real value; + Property() : + exist(false), + value(0.0) {} + }; - // summarize a material in an convenient way. - struct Material - { - std::string name; - std::string shading_model; - Surface ambient, diffuse, specular, emissive, reflective, transparent, normal; - Property shininess, transparency, index_refraction; + // summarize a material in an convenient way. + struct Material { + std::string name; + std::string shading_model; + Surface ambient, diffuse, specular, emissive, reflective, transparent, normal; + Property shininess, transparency, index_refraction; - Material() {} - }; + Material() {} + }; - std::vector materials; + std::vector materials; - std::map textures; + std::map textures; public: - /// Dammit C++ - y u no compile two-pass? No I have to add all methods below the struct definitions - /// Reads a single surface entry from the given material keys - void ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex); - /// Writes an image entry for the given surface - void WriteImageEntry( const Surface& pSurface, const std::string& pNameAdd); - /// Writes the two parameters necessary for referencing a texture in an effect entry - void WriteTextureParamEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pMatName); - /// Writes a color-or-texture entry into an effect definition - void WriteTextureColorEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pImageName); - /// Writes a scalar property - void WriteFloatEntry( const Property& pProperty, const std::string& pTypeName); + /// Dammit C++ - y u no compile two-pass? No I have to add all methods below the struct definitions + /// Reads a single surface entry from the given material keys + void ReadMaterialSurface(Surface &poSurface, const aiMaterial *pSrcMat, aiTextureType pTexture, const char *pKey, size_t pType, size_t pIndex); + /// Writes an image entry for the given surface + void WriteImageEntry(const Surface &pSurface, const std::string &pNameAdd); + /// Writes the two parameters necessary for referencing a texture in an effect entry + void WriteTextureParamEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &pMatName); + /// Writes a color-or-texture entry into an effect definition + void WriteTextureColorEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &pImageName); + /// Writes a scalar property + void WriteFloatEntry(const Property &pProperty, const std::string &pTypeName); }; -} +} // namespace Assimp #endif // !! AI_COLLADAEXPORTER_H_INC diff --git a/code/Collada/ColladaHelper.cpp b/code/Collada/ColladaHelper.cpp index 6f1fed366..50d70e640 100644 --- a/code/Collada/ColladaHelper.cpp +++ b/code/Collada/ColladaHelper.cpp @@ -43,8 +43,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ColladaHelper.h" -#include #include +#include namespace Assimp { namespace Collada { @@ -63,42 +63,35 @@ const MetaKeyPairVector &GetColladaAssimpMetaKeys() { const MetaKeyPairVector MakeColladaAssimpMetaKeysCamelCase() { MetaKeyPairVector result = MakeColladaAssimpMetaKeys(); - for (auto &val : result) - { + for (auto &val : result) { ToCamelCase(val.first); } return result; }; -const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase() -{ +const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase() { static const MetaKeyPairVector result = MakeColladaAssimpMetaKeysCamelCase(); return result; } // ------------------------------------------------------------------------------------------------ // Convert underscore_separated to CamelCase: "authoring_tool" becomes "AuthoringTool" -void ToCamelCase(std::string &text) -{ +void ToCamelCase(std::string &text) { if (text.empty()) return; // Capitalise first character auto it = text.begin(); (*it) = ToUpper(*it); ++it; - for (/*started above*/ ; it != text.end(); /*iterated below*/) - { - if ((*it) == '_') - { + for (/*started above*/; it != text.end(); /*iterated below*/) { + if ((*it) == '_') { it = text.erase(it); if (it != text.end()) (*it) = ToUpper(*it); - } - else - { + } else { // Make lower case (*it) = ToLower(*it); - ++it; + ++it; } } } diff --git a/code/Collada/ColladaHelper.h b/code/Collada/ColladaHelper.h index c6e2e7ddd..3eb073cd9 100644 --- a/code/Collada/ColladaHelper.h +++ b/code/Collada/ColladaHelper.h @@ -45,31 +45,28 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_COLLADAHELPER_H_INC #define AI_COLLADAHELPER_H_INC -#include -#include -#include -#include #include -#include #include +#include +#include +#include +#include +#include struct aiMaterial; -namespace Assimp { -namespace Collada { +namespace Assimp { +namespace Collada { /** Collada file versions which evolved during the years ... */ -enum FormatVersion -{ +enum FormatVersion { FV_1_5_n, FV_1_4_n, FV_1_3_n }; - /** Transformation types that can be applied to a node */ -enum TransformType -{ +enum TransformType { TF_LOOKAT, TF_ROTATE, TF_TRANSLATE, @@ -79,10 +76,9 @@ enum TransformType }; /** Different types of input data to a vertex or face */ -enum InputType -{ +enum InputType { IT_Invalid, - IT_Vertex, // special type for per-index data referring to the element carrying the per-vertex data. + IT_Vertex, // special type for per-index data referring to the element carrying the per-vertex data. IT_Position, IT_Normal, IT_Texcoord, @@ -92,15 +88,13 @@ enum InputType }; /** Supported controller types */ -enum ControllerType -{ +enum ControllerType { Skin, Morph }; /** Supported morph methods */ -enum MorphMethod -{ +enum MorphMethod { Normalized, Relative }; @@ -118,24 +112,21 @@ const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase(); void ToCamelCase(std::string &text); /** Contains all data for one of the different transformation types */ -struct Transform -{ - std::string mID; ///< SID of the transform step, by which anim channels address their target node +struct Transform { + std::string mID; ///< SID of the transform step, by which anim channels address their target node TransformType mType; ai_real f[16]; ///< Interpretation of data depends on the type of the transformation }; /** A collada camera. */ -struct Camera -{ - Camera() - : mOrtho (false) - , mHorFov (10e10f) - , mVerFov (10e10f) - , mAspect (10e10f) - , mZNear (0.1f) - , mZFar (1000.f) - {} +struct Camera { + Camera() : + mOrtho(false), + mHorFov(10e10f), + mVerFov(10e10f), + mAspect(10e10f), + mZNear(0.1f), + mZFar(1000.f) {} // Name of camera std::string mName; @@ -159,19 +150,17 @@ struct Camera #define ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET 1e9f /** A collada light source. */ -struct Light -{ - Light() - : mType (aiLightSource_UNDEFINED) - , mAttConstant (1.f) - , mAttLinear (0.f) - , mAttQuadratic (0.f) - , mFalloffAngle (180.f) - , mFalloffExponent (0.f) - , mPenumbraAngle (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET) - , mOuterAngle (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET) - , mIntensity (1.f) - {} +struct Light { + Light() : + mType(aiLightSource_UNDEFINED), + mAttConstant(1.f), + mAttLinear(0.f), + mAttQuadratic(0.f), + mFalloffAngle(180.f), + mFalloffExponent(0.f), + mPenumbraAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET), + mOuterAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET), + mIntensity(1.f) {} //! Type of the light source aiLightSourceType + ambient unsigned int mType; @@ -180,7 +169,7 @@ struct Light aiColor3D mColor; //! Light attenuation - ai_real mAttConstant,mAttLinear,mAttQuadratic; + ai_real mAttConstant, mAttLinear, mAttQuadratic; //! Spot light falloff ai_real mFalloffAngle; @@ -198,12 +187,10 @@ struct Light }; /** Short vertex index description */ -struct InputSemanticMapEntry -{ - InputSemanticMapEntry() - : mSet(0) - , mType(IT_Invalid) - {} +struct InputSemanticMapEntry { + InputSemanticMapEntry() : + mSet(0), + mType(IT_Invalid) {} //! Index of set, optional unsigned int mSet; @@ -213,8 +200,7 @@ struct InputSemanticMapEntry }; /** Table to map from effect to vertex input semantics */ -struct SemanticMappingTable -{ +struct SemanticMappingTable { //! Name of material std::string mMatName; @@ -222,7 +208,7 @@ struct SemanticMappingTable std::map mMap; //! For std::find - bool operator == (const std::string& s) const { + bool operator==(const std::string &s) const { return s == mMatName; } }; @@ -230,8 +216,7 @@ struct SemanticMappingTable /** A reference to a mesh inside a node, including materials assigned to the various subgroups. * The ID refers to either a mesh or a controller which specifies the mesh */ -struct MeshInstance -{ +struct MeshInstance { ///< ID of the mesh or controller to be instanced std::string mMeshOrController; @@ -240,34 +225,30 @@ struct MeshInstance }; /** A reference to a camera inside a node*/ -struct CameraInstance -{ - ///< ID of the camera +struct CameraInstance { + ///< ID of the camera std::string mCamera; }; /** A reference to a light inside a node*/ -struct LightInstance -{ - ///< ID of the camera +struct LightInstance { + ///< ID of the camera std::string mLight; }; /** A reference to a node inside a node*/ -struct NodeInstance -{ - ///< ID of the node +struct NodeInstance { + ///< ID of the node std::string mNode; }; /** A node in a scene hierarchy */ -struct Node -{ +struct Node { std::string mName; std::string mID; std::string mSID; - Node* mParent; - std::vector mChildren; + Node *mParent; + std::vector mChildren; /** Operations in order to calculate the resulting transformation to parent. */ std::vector mTransforms; @@ -288,77 +269,78 @@ struct Node std::string mPrimaryCamera; //! Constructor. Begin with a zero parent - Node() - : mParent( nullptr ){ + Node() : + mParent(nullptr) { // empty } //! Destructor: delete all children subsequently ~Node() { - for( std::vector::iterator it = mChildren.begin(); it != mChildren.end(); ++it) + for (std::vector::iterator it = mChildren.begin(); it != mChildren.end(); ++it) delete *it; } }; /** Data source array: either floats or strings */ -struct Data -{ +struct Data { bool mIsStringArray; std::vector mValues; std::vector mStrings; }; /** Accessor to a data array */ -struct Accessor -{ - size_t mCount; // in number of objects - size_t mSize; // size of an object, in elements (floats or strings, mostly 1) - size_t mOffset; // in number of values - size_t mStride; // Stride in number of values +struct Accessor { + size_t mCount; // in number of objects + size_t mSize; // size of an object, in elements (floats or strings, mostly 1) + size_t mOffset; // in number of values + size_t mStride; // Stride in number of values std::vector mParams; // names of the data streams in the accessors. Empty string tells to ignore. size_t mSubOffset[4]; // Suboffset inside the object for the common 4 elements. For a vector, that's XYZ, for a color RGBA and so on. - // For example, SubOffset[0] denotes which of the values inside the object is the vector X component. - std::string mSource; // URL of the source array - mutable const Data* mData; // Pointer to the source array, if resolved. NULL else + // For example, SubOffset[0] denotes which of the values inside the object is the vector X component. + std::string mSource; // URL of the source array + mutable const Data *mData; // Pointer to the source array, if resolved. NULL else - Accessor() - { - mCount = 0; mSize = 0; mOffset = 0; mStride = 0; mData = NULL; + Accessor() { + mCount = 0; + mSize = 0; + mOffset = 0; + mStride = 0; + mData = NULL; mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0; } }; /** A single face in a mesh */ -struct Face -{ +struct Face { std::vector mIndices; }; /** An input channel for mesh data, referring to a single accessor */ -struct InputChannel -{ - InputType mType; // Type of the data - size_t mIndex; // Optional index, if multiple sets of the same data type are given - size_t mOffset; // Index offset in the indices array of per-face indices. Don't ask, can't explain that any better. +struct InputChannel { + InputType mType; // Type of the data + size_t mIndex; // Optional index, if multiple sets of the same data type are given + size_t mOffset; // Index offset in the indices array of per-face indices. Don't ask, can't explain that any better. std::string mAccessor; // ID of the accessor where to read the actual values from. - mutable const Accessor* mResolved; // Pointer to the accessor, if resolved. NULL else + mutable const Accessor *mResolved; // Pointer to the accessor, if resolved. NULL else - InputChannel() { mType = IT_Invalid; mIndex = 0; mOffset = 0; mResolved = NULL; } + InputChannel() { + mType = IT_Invalid; + mIndex = 0; + mOffset = 0; + mResolved = NULL; + } }; /** Subset of a mesh with a certain material */ -struct SubMesh -{ +struct SubMesh { std::string mMaterial; ///< subgroup identifier size_t mNumFaces; ///< number of faces in this submesh }; /** Contains data for a single mesh */ -struct Mesh -{ - Mesh() - { - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) +struct Mesh { + Mesh() { + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) mNumUVComponents[i] = 2; } @@ -377,7 +359,7 @@ struct Mesh std::vector mTangents; std::vector mBitangents; std::vector mTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS]; - std::vector mColors[AI_MAX_NUMBER_OF_COLOR_SETS]; + std::vector mColors[AI_MAX_NUMBER_OF_COLOR_SETS]; unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS]; @@ -394,8 +376,7 @@ struct Mesh }; /** Which type of primitives the ReadPrimitives() function is going to read */ -enum PrimitiveType -{ +enum PrimitiveType { Prim_Invalid, Prim_Lines, Prim_LineStrip, @@ -407,8 +388,7 @@ enum PrimitiveType }; /** A skeleton controller to deform a mesh with the use of joints */ -struct Controller -{ +struct Controller { // controller type ControllerType mType; @@ -436,36 +416,32 @@ struct Controller std::vector mWeightCounts; // JointIndex-WeightIndex pairs for all vertices - std::vector< std::pair > mWeights; + std::vector> mWeights; std::string mMorphTarget; std::string mMorphWeight; }; /** A collada material. Pretty much the only member is a reference to an effect. */ -struct Material -{ +struct Material { std::string mName; std::string mEffect; }; /** Type of the effect param */ -enum ParamType -{ +enum ParamType { Param_Sampler, Param_Surface }; /** A param for an effect. Might be of several types, but they all just refer to each other, so I summarize them */ -struct EffectParam -{ +struct EffectParam { ParamType mType; std::string mReference; // to which other thing the param is referring to. }; /** Shading type supported by the standard effect spec of Collada */ -enum ShadeType -{ +enum ShadeType { Shade_Invalid, Shade_Constant, Shade_Lambert, @@ -474,18 +450,16 @@ enum ShadeType }; /** Represents a texture sampler in collada */ -struct Sampler -{ - Sampler() - : mWrapU (true) - , mWrapV (true) - , mMirrorU () - , mMirrorV () - , mOp (aiTextureOp_Multiply) - , mUVId (UINT_MAX) - , mWeighting (1.f) - , mMixWithPrevious (1.f) - {} +struct Sampler { + Sampler() : + mWrapU(true), + mWrapV(true), + mMirrorU(), + mMirrorV(), + mOp(aiTextureOp_Multiply), + mUVId(UINT_MAX), + mWeighting(1.f), + mMixWithPrevious(1.f) {} /** Name of image reference */ @@ -537,18 +511,17 @@ struct Sampler /** A collada effect. Can contain about anything according to the Collada spec, but we limit our version to a reasonable subset. */ -struct Effect -{ +struct Effect { // Shading mode ShadeType mShadeType; // Colors aiColor4D mEmissive, mAmbient, mDiffuse, mSpecular, - mTransparent, mReflective; + mTransparent, mReflective; // Textures Sampler mTexEmissive, mTexAmbient, mTexDiffuse, mTexSpecular, - mTexTransparent, mTexBump, mTexReflective; + mTexTransparent, mTexBump, mTexReflective; // Scalar factory ai_real mShininess, mRefractIndex, mReflectivity; @@ -566,30 +539,28 @@ struct Effect // Double-sided? bool mDoubleSided, mWireframe, mFaceted; - Effect() - : mShadeType (Shade_Phong) - , mEmissive ( 0, 0, 0, 1) - , mAmbient ( 0.1f, 0.1f, 0.1f, 1) - , mDiffuse ( 0.6f, 0.6f, 0.6f, 1) - , mSpecular ( 0.4f, 0.4f, 0.4f, 1) - , mTransparent ( 0, 0, 0, 1) - , mShininess (10.0f) - , mRefractIndex (1.f) - , mReflectivity (0.f) - , mTransparency (1.f) - , mHasTransparency (false) - , mRGBTransparency(false) - , mInvertTransparency(false) - , mDoubleSided (false) - , mWireframe (false) - , mFaceted (false) - { + Effect() : + mShadeType(Shade_Phong), + mEmissive(0, 0, 0, 1), + mAmbient(0.1f, 0.1f, 0.1f, 1), + mDiffuse(0.6f, 0.6f, 0.6f, 1), + mSpecular(0.4f, 0.4f, 0.4f, 1), + mTransparent(0, 0, 0, 1), + mShininess(10.0f), + mRefractIndex(1.f), + mReflectivity(0.f), + mTransparency(1.f), + mHasTransparency(false), + mRGBTransparency(false), + mInvertTransparency(false), + mDoubleSided(false), + mWireframe(false), + mFaceted(false) { } }; /** An image, meaning texture */ -struct Image -{ +struct Image { std::string mFileName; /** Embedded image data */ @@ -600,8 +571,7 @@ struct Image }; /** An animation channel. */ -struct AnimationChannel -{ +struct AnimationChannel { /** URL of the data to animate. Could be about anything, but we support only the * "NodeID/TransformID.SubElement" notation */ @@ -620,8 +590,7 @@ struct AnimationChannel }; /** An animation. Container for 0-x animation channels or 0-x animations */ -struct Animation -{ +struct Animation { /** Anim name */ std::string mName; @@ -629,96 +598,86 @@ struct Animation std::vector mChannels; /** the sub-animations, if any */ - std::vector mSubAnims; + std::vector mSubAnims; /** Destructor */ - ~Animation() - { - for( std::vector::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) + ~Animation() { + for (std::vector::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) delete *it; } - /** Collect all channels in the animation hierarchy into a single channel list. */ - void CollectChannelsRecursively(std::vector &channels) - { - channels.insert(channels.end(), mChannels.begin(), mChannels.end()); + /** Collect all channels in the animation hierarchy into a single channel list. */ + void CollectChannelsRecursively(std::vector &channels) { + channels.insert(channels.end(), mChannels.begin(), mChannels.end()); - for (std::vector::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) - { - Animation *pAnim = (*it); + for (std::vector::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) { + Animation *pAnim = (*it); - pAnim->CollectChannelsRecursively(channels); - } - } + pAnim->CollectChannelsRecursively(channels); + } + } - /** Combine all single-channel animations' channel into the same (parent) animation channel list. */ - void CombineSingleChannelAnimations() - { - CombineSingleChannelAnimationsRecursively(this); - } + /** Combine all single-channel animations' channel into the same (parent) animation channel list. */ + void CombineSingleChannelAnimations() { + CombineSingleChannelAnimationsRecursively(this); + } - void CombineSingleChannelAnimationsRecursively(Animation *pParent) - { - std::set childrenTargets; - bool childrenAnimationsHaveDifferentChannels = true; + void CombineSingleChannelAnimationsRecursively(Animation *pParent) { + std::set childrenTargets; + bool childrenAnimationsHaveDifferentChannels = true; - for (std::vector::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) - { - Animation *anim = *it; - CombineSingleChannelAnimationsRecursively(anim); + for (std::vector::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) { + Animation *anim = *it; + CombineSingleChannelAnimationsRecursively(anim); - if (childrenAnimationsHaveDifferentChannels && anim->mChannels.size() == 1 && - childrenTargets.find(anim->mChannels[0].mTarget) == childrenTargets.end()) { - childrenTargets.insert(anim->mChannels[0].mTarget); - } else { - childrenAnimationsHaveDifferentChannels = false; - } + if (childrenAnimationsHaveDifferentChannels && anim->mChannels.size() == 1 && + childrenTargets.find(anim->mChannels[0].mTarget) == childrenTargets.end()) { + childrenTargets.insert(anim->mChannels[0].mTarget); + } else { + childrenAnimationsHaveDifferentChannels = false; + } - ++it; - } + ++it; + } - // We only want to combine animations if they have different channels - if (childrenAnimationsHaveDifferentChannels) - { - for (std::vector::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) - { - Animation *anim = *it; + // We only want to combine animations if they have different channels + if (childrenAnimationsHaveDifferentChannels) { + for (std::vector::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) { + Animation *anim = *it; - pParent->mChannels.push_back(anim->mChannels[0]); + pParent->mChannels.push_back(anim->mChannels[0]); - it = pParent->mSubAnims.erase(it); + it = pParent->mSubAnims.erase(it); - delete anim; - continue; - } - } - } + delete anim; + continue; + } + } + } }; /** Description of a collada animation channel which has been determined to affect the current node */ -struct ChannelEntry -{ - const Collada::AnimationChannel* mChannel; ///> the source channel +struct ChannelEntry { + const Collada::AnimationChannel *mChannel; ///> the source channel std::string mTargetId; - std::string mTransformId; // the ID of the transformation step of the node which is influenced + std::string mTransformId; // the ID of the transformation step of the node which is influenced size_t mTransformIndex; // Index into the node's transform chain to apply the channel to size_t mSubElement; // starting index inside the transform data // resolved data references - const Collada::Accessor* mTimeAccessor; ///> Collada accessor to the time values - const Collada::Data* mTimeData; ///> Source data array for the time values - const Collada::Accessor* mValueAccessor; ///> Collada accessor to the key value values - const Collada::Data* mValueData; ///> Source datat array for the key value values + const Collada::Accessor *mTimeAccessor; ///> Collada accessor to the time values + const Collada::Data *mTimeData; ///> Source data array for the time values + const Collada::Accessor *mValueAccessor; ///> Collada accessor to the key value values + const Collada::Data *mValueData; ///> Source datat array for the key value values - ChannelEntry() - : mChannel() - , mTransformIndex() - , mSubElement() - , mTimeAccessor() - , mTimeData() - , mValueAccessor() - , mValueData() - {} + ChannelEntry() : + mChannel(), + mTransformIndex(), + mSubElement(), + mTimeAccessor(), + mTimeData(), + mValueAccessor(), + mValueData() {} }; } // end of namespace Collada diff --git a/code/Collada/ColladaLoader.cpp b/code/Collada/ColladaLoader.cpp index b78fc0e3b..44d65e40d 100644 --- a/code/Collada/ColladaLoader.cpp +++ b/code/Collada/ColladaLoader.cpp @@ -46,27 +46,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ColladaLoader.h" #include "ColladaParser.h" +#include #include +#include #include #include #include -#include -#include -#include +#include #include #include -#include #include +#include -#include "time.h" #include "math.h" +#include "time.h" #include -#include #include +#include namespace Assimp { - + using namespace Assimp::Formatter; static const aiImporterDesc desc = { @@ -84,20 +84,20 @@ static const aiImporterDesc desc = { // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer -ColladaLoader::ColladaLoader() - : mFileName() - , mMeshIndexByID() - , mMaterialIndexByName() - , mMeshes() - , newMats() - , mCameras() - , mLights() - , mTextures() - , mAnims() - , noSkeletonMesh(false) - , ignoreUpDirection(false) - , useColladaName(false) - , mNodeNameCounter(0) { +ColladaLoader::ColladaLoader() : + mFileName(), + mMeshIndexByID(), + mMaterialIndexByName(), + mMeshes(), + newMats(), + mCameras(), + mLights(), + mTextures(), + mAnims(), + noSkeletonMesh(false), + ignoreUpDirection(false), + useColladaName(false), + mNodeNameCounter(0) { // empty } @@ -109,7 +109,7 @@ ColladaLoader::~ColladaLoader() { // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool ColladaLoader::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { +bool ColladaLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { // check file extension const std::string extension = GetExtension(pFile); @@ -137,7 +137,7 @@ bool ColladaLoader::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool if (!pIOHandler) { return true; } - static const char* tokens[] = { "GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0; ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION, 0) != 0; useColladaName = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES, 0) != 0; @@ -153,13 +153,13 @@ void ColladaLoader::SetupProperties(const Importer* pImp) { // ------------------------------------------------------------------------------------------------ // Get file extension list -const aiImporterDesc* ColladaLoader::GetInfo() const { +const aiImporterDesc *ColladaLoader::GetInfo() const { return &desc; } // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. -void ColladaLoader::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) { +void ColladaLoader::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { mFileName = pFile; // clean all member arrays - just for safety, it should work even if we did not @@ -176,14 +176,13 @@ void ColladaLoader::InternReadFile(const std::string& pFile, aiScene* pScene, IO // parse the input file ColladaParser parser(pIOHandler, pFile); - - if( !parser.mRootNode) { - throw DeadlyImportError( "Collada: File came out empty. Something is wrong here."); + if (!parser.mRootNode) { + throw DeadlyImportError("Collada: File came out empty. Something is wrong here."); } // reserve some storage to avoid unnecessary reallocs - newMats.reserve(parser.mMaterialLibrary.size()*2u); - mMeshes.reserve(parser.mMeshLibrary.size()*2u); + newMats.reserve(parser.mMaterialLibrary.size() * 2u); + mMeshes.reserve(parser.mMeshLibrary.size() * 2u); mCameras.reserve(parser.mCameraLibrary.size()); mLights.reserve(parser.mLightLibrary.size()); @@ -199,24 +198,24 @@ void ColladaLoader::InternReadFile(const std::string& pFile, aiScene* pScene, IO // Apply unit-size scale calculation - pScene->mRootNode->mTransformation *= aiMatrix4x4(parser.mUnitSize, 0, 0, 0, - 0, parser.mUnitSize, 0, 0, - 0, 0, parser.mUnitSize, 0, - 0, 0, 0, 1); - if( !ignoreUpDirection ) { + pScene->mRootNode->mTransformation *= aiMatrix4x4(parser.mUnitSize, 0, 0, 0, + 0, parser.mUnitSize, 0, 0, + 0, 0, parser.mUnitSize, 0, + 0, 0, 0, 1); + if (!ignoreUpDirection) { // Convert to Y_UP, if different orientation - if( parser.mUpDirection == ColladaParser::UP_X) { + if (parser.mUpDirection == ColladaParser::UP_X) { pScene->mRootNode->mTransformation *= aiMatrix4x4( - 0, -1, 0, 0, - 1, 0, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1); - } else if( parser.mUpDirection == ColladaParser::UP_Z) { + 0, -1, 0, 0, + 1, 0, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); + } else if (parser.mUpDirection == ColladaParser::UP_Z) { pScene->mRootNode->mTransformation *= aiMatrix4x4( - 1, 0, 0, 0, - 0, 0, 1, 0, - 0, -1, 0, 0, - 0, 0, 0, 1); + 1, 0, 0, 0, + 0, 0, 1, 0, + 0, -1, 0, 0, + 0, 0, 0, 1); } } @@ -249,7 +248,7 @@ void ColladaLoader::InternReadFile(const std::string& pFile, aiScene* pScene, IO StoreAnimations(pScene, parser); // If no meshes have been loaded, it's probably just an animated skeleton. - if ( 0u == pScene->mNumMeshes) { + if (0u == pScene->mNumMeshes) { if (!noSkeletonMesh) { SkeletonMeshBuilder hero(pScene); @@ -260,9 +259,9 @@ void ColladaLoader::InternReadFile(const std::string& pFile, aiScene* pScene, IO // ------------------------------------------------------------------------------------------------ // Recursively constructs a scene node for the given parser node and returns it. -aiNode* ColladaLoader::BuildHierarchy(const ColladaParser& pParser, const Collada::Node* pNode) { +aiNode *ColladaLoader::BuildHierarchy(const ColladaParser &pParser, const Collada::Node *pNode) { // create a node for it - aiNode* node = new aiNode(); + aiNode *node = new aiNode(); // find a name for the new node. It's more complicated than you might think node->mName.Set(FindNameForNode(pNode)); @@ -271,12 +270,12 @@ aiNode* ColladaLoader::BuildHierarchy(const ColladaParser& pParser, const Collad node->mTransformation = pParser.CalculateResultTransform(pNode->mTransforms); // now resolve node instances - std::vector instances; + std::vector instances; ResolveNodeInstances(pParser, pNode, instances); // add children. first the *real* ones node->mNumChildren = static_cast(pNode->mChildren.size() + instances.size()); - node->mChildren = new aiNode*[node->mNumChildren]; + node->mChildren = new aiNode *[node->mNumChildren]; for (size_t a = 0; a < pNode->mChildren.size(); ++a) { node->mChildren[a] = BuildHierarchy(pParser, pNode->mChildren[a]); @@ -303,8 +302,8 @@ aiNode* ColladaLoader::BuildHierarchy(const ColladaParser& pParser, const Collad // ------------------------------------------------------------------------------------------------ // Resolve node instances -void ColladaLoader::ResolveNodeInstances(const ColladaParser& pParser, const Collada::Node* pNode, - std::vector& resolved) { +void ColladaLoader::ResolveNodeInstances(const ColladaParser &pParser, const Collada::Node *pNode, + std::vector &resolved) { // reserve enough storage resolved.reserve(pNode->mNodeInstances.size()); @@ -312,7 +311,7 @@ void ColladaLoader::ResolveNodeInstances(const ColladaParser& pParser, const Col for (const auto &nodeInst : pNode->mNodeInstances) { // find the corresponding node in the library const ColladaParser::NodeLibrary::const_iterator itt = pParser.mNodeLibrary.find(nodeInst.mNode); - const Collada::Node* nd = itt == pParser.mNodeLibrary.end() ? NULL : (*itt).second; + const Collada::Node *nd = itt == pParser.mNodeLibrary.end() ? NULL : (*itt).second; // FIX for http://sourceforge.net/tracker/?func=detail&aid=3054873&group_id=226462&atid=1067632 // need to check for both name and ID to catch all. To avoid breaking valid files, @@ -331,9 +330,9 @@ void ColladaLoader::ResolveNodeInstances(const ColladaParser& pParser, const Col // ------------------------------------------------------------------------------------------------ // Resolve UV channels -void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler, +void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler &sampler, - const Collada::SemanticMappingTable& table) { + const Collada::SemanticMappingTable &table) { std::map::const_iterator it = table.mMap.find(sampler.mUVChannel); if (it != table.mMap.end()) { if (it->second.mType != Collada::IT_Texcoord) { @@ -346,18 +345,18 @@ void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler // ------------------------------------------------------------------------------------------------ // Builds lights for the given node and references them -void ColladaLoader::BuildLightsForNode(const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget) { - for (const Collada::LightInstance& lid : pNode->mLights) { +void ColladaLoader::BuildLightsForNode(const ColladaParser &pParser, const Collada::Node *pNode, aiNode *pTarget) { + for (const Collada::LightInstance &lid : pNode->mLights) { // find the referred light ColladaParser::LightLibrary::const_iterator srcLightIt = pParser.mLightLibrary.find(lid.mLight); if (srcLightIt == pParser.mLightLibrary.end()) { ASSIMP_LOG_WARN_F("Collada: Unable to find light for ID \"", lid.mLight, "\". Skipping."); continue; } - const Collada::Light* srcLight = &srcLightIt->second; + const Collada::Light *srcLight = &srcLightIt->second; // now fill our ai data structure - aiLight* out = new aiLight(); + aiLight *out = new aiLight(); out->mName = pTarget->mName; out->mType = (aiLightSourceType)srcLight->mType; @@ -368,14 +367,13 @@ void ColladaLoader::BuildLightsForNode(const ColladaParser& pParser, const Colla out->mAttenuationLinear = srcLight->mAttLinear; out->mAttenuationQuadratic = srcLight->mAttQuadratic; - out->mColorDiffuse = out->mColorSpecular = out->mColorAmbient = srcLight->mColor*srcLight->mIntensity; + out->mColorDiffuse = out->mColorSpecular = out->mColorAmbient = srcLight->mColor * srcLight->mIntensity; if (out->mType == aiLightSource_AMBIENT) { out->mColorDiffuse = out->mColorSpecular = aiColor3D(0, 0, 0); - out->mColorAmbient = srcLight->mColor*srcLight->mIntensity; - } - else { + out->mColorAmbient = srcLight->mColor * srcLight->mIntensity; + } else { // collada doesn't differentiate between these color types - out->mColorDiffuse = out->mColorSpecular = srcLight->mColor*srcLight->mIntensity; + out->mColorDiffuse = out->mColorSpecular = srcLight->mColor * srcLight->mIntensity; out->mColorAmbient = aiColor3D(0, 0, 0); } @@ -390,15 +388,13 @@ void ColladaLoader::BuildLightsForNode(const ColladaParser& pParser, const Colla // Need to rely on falloff_exponent. I don't know how to interpret it, so I need to guess .... // epsilon chosen to be 0.1 out->mAngleOuterCone = std::acos(std::pow(0.1f, 1.f / srcLight->mFalloffExponent)) + - out->mAngleInnerCone; - } - else { + out->mAngleInnerCone; + } else { out->mAngleOuterCone = out->mAngleInnerCone + AI_DEG_TO_RAD(srcLight->mPenumbraAngle); if (out->mAngleOuterCone < out->mAngleInnerCone) std::swap(out->mAngleInnerCone, out->mAngleOuterCone); } - } - else { + } else { out->mAngleOuterCone = AI_DEG_TO_RAD(srcLight->mOuterAngle); } } @@ -410,15 +406,15 @@ void ColladaLoader::BuildLightsForNode(const ColladaParser& pParser, const Colla // ------------------------------------------------------------------------------------------------ // Builds cameras for the given node and references them -void ColladaLoader::BuildCamerasForNode(const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget) { - for (const Collada::CameraInstance& cid : pNode->mCameras) { +void ColladaLoader::BuildCamerasForNode(const ColladaParser &pParser, const Collada::Node *pNode, aiNode *pTarget) { + for (const Collada::CameraInstance &cid : pNode->mCameras) { // find the referred light ColladaParser::CameraLibrary::const_iterator srcCameraIt = pParser.mCameraLibrary.find(cid.mCamera); if (srcCameraIt == pParser.mCameraLibrary.end()) { ASSIMP_LOG_WARN_F("Collada: Unable to find camera for ID \"", cid.mCamera, "\". Skipping."); continue; } - const Collada::Camera* srcCamera = &srcCameraIt->second; + const Collada::Camera *srcCamera = &srcCameraIt->second; // orthographic cameras not yet supported in Assimp if (srcCamera->mOrtho) { @@ -426,7 +422,7 @@ void ColladaLoader::BuildCamerasForNode(const ColladaParser& pParser, const Coll } // now fill our ai data structure - aiCamera* out = new aiCamera(); + aiCamera *out = new aiCamera(); out->mName = pTarget->mName; // collada cameras point in -Z by default, rest is specified in node transform @@ -447,12 +443,12 @@ void ColladaLoader::BuildCamerasForNode(const ColladaParser& pParser, const Coll if (srcCamera->mVerFov != 10e10f && srcCamera->mAspect == 10e10f) { out->mAspect = std::tan(AI_DEG_TO_RAD(srcCamera->mHorFov)) / - std::tan(AI_DEG_TO_RAD(srcCamera->mVerFov)); + std::tan(AI_DEG_TO_RAD(srcCamera->mVerFov)); } - } else if (srcCamera->mAspect != 10e10f && srcCamera->mVerFov != 10e10f) { + } else if (srcCamera->mAspect != 10e10f && srcCamera->mVerFov != 10e10f) { out->mHorizontalFOV = 2.0f * AI_RAD_TO_DEG(std::atan(srcCamera->mAspect * - std::tan(AI_DEG_TO_RAD(srcCamera->mVerFov) * 0.5f))); + std::tan(AI_DEG_TO_RAD(srcCamera->mVerFov) * 0.5f))); } // Collada uses degrees, we use radians @@ -465,15 +461,15 @@ void ColladaLoader::BuildCamerasForNode(const ColladaParser& pParser, const Coll // ------------------------------------------------------------------------------------------------ // Builds meshes for the given node and references them -void ColladaLoader::BuildMeshesForNode(const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget) { +void ColladaLoader::BuildMeshesForNode(const ColladaParser &pParser, const Collada::Node *pNode, aiNode *pTarget) { // accumulated mesh references by this node std::vector newMeshRefs; newMeshRefs.reserve(pNode->mMeshes.size()); // add a mesh for each subgroup in each collada mesh - for (const Collada::MeshInstance& mid : pNode->mMeshes) { - const Collada::Mesh* srcMesh = nullptr; - const Collada::Controller* srcController = nullptr; + for (const Collada::MeshInstance &mid : pNode->mMeshes) { + const Collada::Mesh *srcMesh = nullptr; + const Collada::Controller *srcController = nullptr; // find the referred mesh ColladaParser::MeshLibrary::const_iterator srcMeshIt = pParser.mMeshLibrary.find(mid.mMeshOrController); @@ -488,13 +484,11 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser& pParser, const Colla } } - - if( nullptr == srcMesh) { - ASSIMP_LOG_WARN_F( "Collada: Unable to find geometry for ID \"", mid.mMeshOrController, "\". Skipping." ); + if (nullptr == srcMesh) { + ASSIMP_LOG_WARN_F("Collada: Unable to find geometry for ID \"", mid.mMeshOrController, "\". Skipping."); continue; } - } - else { + } else { // ID found in the mesh library -> direct reference to an unskinned mesh srcMesh = srcMeshIt->second; } @@ -502,23 +496,22 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser& pParser, const Colla // build a mesh for each of its subgroups size_t vertexStart = 0, faceStart = 0; for (size_t sm = 0; sm < srcMesh->mSubMeshes.size(); ++sm) { - const Collada::SubMesh& submesh = srcMesh->mSubMeshes[sm]; + const Collada::SubMesh &submesh = srcMesh->mSubMeshes[sm]; if (submesh.mNumFaces == 0) { continue; } // find material assigned to this submesh std::string meshMaterial; - std::map::const_iterator meshMatIt = mid.mMaterials.find(submesh.mMaterial); + std::map::const_iterator meshMatIt = mid.mMaterials.find(submesh.mMaterial); - const Collada::SemanticMappingTable* table = nullptr; + const Collada::SemanticMappingTable *table = nullptr; if (meshMatIt != mid.mMaterials.end()) { table = &meshMatIt->second; meshMaterial = table->mMatName; - } - else { + } else { ASSIMP_LOG_WARN_F("Collada: No material specified for subgroup <", submesh.mMaterial, "> in geometry <", - mid.mMeshOrController, ">."); + mid.mMeshOrController, ">."); if (!mid.mMaterials.empty()) { meshMaterial = mid.mMaterials.begin()->second.mMatName; } @@ -533,7 +526,7 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser& pParser, const Colla } if (table && !table->mMap.empty()) { - std::pair& mat = newMats[matIdx]; + std::pair &mat = newMats[matIdx]; // Iterate through all texture channels assigned to the effect and // check whether we have mapping information for it. @@ -552,16 +545,16 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser& pParser, const Colla std::map::const_iterator dstMeshIt = mMeshIndexByID.find(index); if (dstMeshIt != mMeshIndexByID.end()) { newMeshRefs.push_back(dstMeshIt->second); - } - else { + } else { // else we have to add the mesh to the collection and store its newly assigned index at the node - aiMesh* dstMesh = CreateMesh(pParser, srcMesh, submesh, srcController, vertexStart, faceStart); + aiMesh *dstMesh = CreateMesh(pParser, srcMesh, submesh, srcController, vertexStart, faceStart); // store the mesh, and store its new index in the node newMeshRefs.push_back(mMeshes.size()); mMeshIndexByID[index] = mMeshes.size(); mMeshes.push_back(dstMesh); - vertexStart += dstMesh->mNumVertices; faceStart += submesh.mNumFaces; + vertexStart += dstMesh->mNumVertices; + faceStart += submesh.mNumFaces; // assign the material index dstMesh->mMaterialIndex = matIdx; @@ -576,7 +569,7 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser& pParser, const Colla pTarget->mNumMeshes = static_cast(newMeshRefs.size()); if (newMeshRefs.size()) { struct UIntTypeConverter { - unsigned int operator()(const size_t& v) const { + unsigned int operator()(const size_t &v) const { return static_cast(v); } }; @@ -588,7 +581,7 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser& pParser, const Colla // ------------------------------------------------------------------------------------------------ // Find mesh from either meshes or morph target meshes -aiMesh *ColladaLoader::findMesh(const std::string& meshid) { +aiMesh *ColladaLoader::findMesh(const std::string &meshid) { for (unsigned int i = 0; i < mMeshes.size(); ++i) { if (std::string(mMeshes[i]->mName.data) == meshid) { return mMeshes[i]; @@ -606,43 +599,39 @@ aiMesh *ColladaLoader::findMesh(const std::string& meshid) { // ------------------------------------------------------------------------------------------------ // Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh -aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh, - const Collada::Controller* pSrcController, size_t pStartVertex, size_t pStartFace) { +aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::Mesh *pSrcMesh, const Collada::SubMesh &pSubMesh, + const Collada::Controller *pSrcController, size_t pStartVertex, size_t pStartFace) { std::unique_ptr dstMesh(new aiMesh); dstMesh->mName = pSrcMesh->mName; // count the vertices addressed by its faces const size_t numVertices = std::accumulate(pSrcMesh->mFaceSize.begin() + pStartFace, - pSrcMesh->mFaceSize.begin() + pStartFace + pSubMesh.mNumFaces, size_t(0)); + pSrcMesh->mFaceSize.begin() + pStartFace + pSubMesh.mNumFaces, size_t(0)); // copy positions dstMesh->mNumVertices = static_cast(numVertices); dstMesh->mVertices = new aiVector3D[numVertices]; - std::copy(pSrcMesh->mPositions.begin() + pStartVertex, pSrcMesh->mPositions.begin() + - pStartVertex + numVertices, dstMesh->mVertices); + std::copy(pSrcMesh->mPositions.begin() + pStartVertex, pSrcMesh->mPositions.begin() + pStartVertex + numVertices, dstMesh->mVertices); // normals, if given. HACK: (thom) Due to the glorious Collada spec we never // know if we have the same number of normals as there are positions. So we // also ignore any vertex attribute if it has a different count if (pSrcMesh->mNormals.size() >= pStartVertex + numVertices) { dstMesh->mNormals = new aiVector3D[numVertices]; - std::copy(pSrcMesh->mNormals.begin() + pStartVertex, pSrcMesh->mNormals.begin() + - pStartVertex + numVertices, dstMesh->mNormals); + std::copy(pSrcMesh->mNormals.begin() + pStartVertex, pSrcMesh->mNormals.begin() + pStartVertex + numVertices, dstMesh->mNormals); } // tangents, if given. if (pSrcMesh->mTangents.size() >= pStartVertex + numVertices) { dstMesh->mTangents = new aiVector3D[numVertices]; - std::copy(pSrcMesh->mTangents.begin() + pStartVertex, pSrcMesh->mTangents.begin() + - pStartVertex + numVertices, dstMesh->mTangents); + std::copy(pSrcMesh->mTangents.begin() + pStartVertex, pSrcMesh->mTangents.begin() + pStartVertex + numVertices, dstMesh->mTangents); } // bitangents, if given. if (pSrcMesh->mBitangents.size() >= pStartVertex + numVertices) { dstMesh->mBitangents = new aiVector3D[numVertices]; - std::copy(pSrcMesh->mBitangents.begin() + pStartVertex, pSrcMesh->mBitangents.begin() + - pStartVertex + numVertices, dstMesh->mBitangents); + std::copy(pSrcMesh->mBitangents.begin() + pStartVertex, pSrcMesh->mBitangents.begin() + pStartVertex + numVertices, dstMesh->mBitangents); } // same for texturecoords, as many as we have @@ -674,7 +663,7 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M dstMesh->mFaces = new aiFace[dstMesh->mNumFaces]; for (size_t a = 0; a < dstMesh->mNumFaces; ++a) { size_t s = pSrcMesh->mFaceSize[pStartFace + a]; - aiFace& face = dstMesh->mFaces[a]; + aiFace &face = dstMesh->mFaces[a]; face.mNumIndices = static_cast(s); face.mIndices = new unsigned int[s]; for (size_t b = 0; b < s; ++b) { @@ -683,20 +672,20 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M } // create morph target meshes if any - std::vector targetMeshes; + std::vector targetMeshes; std::vector targetWeights; Collada::MorphMethod method = Collada::Normalized; for (std::map::const_iterator it = pParser.mControllerLibrary.begin(); - it != pParser.mControllerLibrary.end(); ++it) { + it != pParser.mControllerLibrary.end(); ++it) { const Collada::Controller &c = it->second; - const Collada::Mesh* baseMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, c.mMeshId); + const Collada::Mesh *baseMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, c.mMeshId); if (c.mType == Collada::Morph && baseMesh->mName == pSrcMesh->mName) { - const Collada::Accessor& targetAccessor = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, c.mMorphTarget); - const Collada::Accessor& weightAccessor = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, c.mMorphWeight); - const Collada::Data& targetData = pParser.ResolveLibraryReference(pParser.mDataLibrary, targetAccessor.mSource); - const Collada::Data& weightData = pParser.ResolveLibraryReference(pParser.mDataLibrary, weightAccessor.mSource); + const Collada::Accessor &targetAccessor = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, c.mMorphTarget); + const Collada::Accessor &weightAccessor = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, c.mMorphWeight); + const Collada::Data &targetData = pParser.ResolveLibraryReference(pParser.mDataLibrary, targetAccessor.mSource); + const Collada::Data &weightData = pParser.ResolveLibraryReference(pParser.mDataLibrary, weightAccessor.mSource); // take method method = c.mMethod; @@ -709,7 +698,7 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M } for (unsigned int i = 0; i < targetData.mStrings.size(); ++i) { - const Collada::Mesh* targetMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, targetData.mStrings.at(i)); + const Collada::Mesh *targetMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, targetData.mStrings.at(i)); aiMesh *aimesh = findMesh(targetMesh->mName); if (!aimesh) { @@ -727,19 +716,17 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M } } if (targetMeshes.size() > 0 && targetWeights.size() == targetMeshes.size()) { - std::vector animMeshes; + std::vector animMeshes; for (unsigned int i = 0; i < targetMeshes.size(); ++i) { - aiMesh* targetMesh = targetMeshes.at(i); + aiMesh *targetMesh = targetMeshes.at(i); aiAnimMesh *animMesh = aiCreateAnimMesh(targetMesh); float weight = targetWeights[i]; animMesh->mWeight = weight == 0 ? 1.0f : weight; animMesh->mName = targetMesh->mName; animMeshes.push_back(animMesh); } - dstMesh->mMethod = (method == Collada::Relative) - ? aiMorphingMethod_MORPH_RELATIVE - : aiMorphingMethod_MORPH_NORMALIZED; - dstMesh->mAnimMeshes = new aiAnimMesh*[animMeshes.size()]; + dstMesh->mMethod = (method == Collada::Relative) ? aiMorphingMethod_MORPH_RELATIVE : aiMorphingMethod_MORPH_NORMALIZED; + dstMesh->mAnimMeshes = new aiAnimMesh *[animMeshes.size()]; dstMesh->mNumAnimMeshes = static_cast(animMeshes.size()); for (unsigned int i = 0; i < animMeshes.size(); ++i) { dstMesh->mAnimMeshes[i] = animMeshes.at(i); @@ -749,18 +736,18 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M // create bones if given if (pSrcController && pSrcController->mType == Collada::Skin) { // resolve references - joint names - const Collada::Accessor& jointNamesAcc = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, pSrcController->mJointNameSource); - const Collada::Data& jointNames = pParser.ResolveLibraryReference(pParser.mDataLibrary, jointNamesAcc.mSource); + const Collada::Accessor &jointNamesAcc = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, pSrcController->mJointNameSource); + const Collada::Data &jointNames = pParser.ResolveLibraryReference(pParser.mDataLibrary, jointNamesAcc.mSource); // joint offset matrices - const Collada::Accessor& jointMatrixAcc = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, pSrcController->mJointOffsetMatrixSource); - const Collada::Data& jointMatrices = pParser.ResolveLibraryReference(pParser.mDataLibrary, jointMatrixAcc.mSource); + const Collada::Accessor &jointMatrixAcc = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, pSrcController->mJointOffsetMatrixSource); + const Collada::Data &jointMatrices = pParser.ResolveLibraryReference(pParser.mDataLibrary, jointMatrixAcc.mSource); // joint vertex_weight name list - should refer to the same list as the joint names above. If not, report and reconsider - const Collada::Accessor& weightNamesAcc = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, pSrcController->mWeightInputJoints.mAccessor); + const Collada::Accessor &weightNamesAcc = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, pSrcController->mWeightInputJoints.mAccessor); if (&weightNamesAcc != &jointNamesAcc) throw DeadlyImportError("Temporary implementational laziness. If you read this, please report to the author."); // vertex weights - const Collada::Accessor& weightsAcc = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, pSrcController->mWeightInputWeights.mAccessor); - const Collada::Data& weights = pParser.ResolveLibraryReference(pParser.mDataLibrary, weightsAcc.mSource); + const Collada::Accessor &weightsAcc = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, pSrcController->mWeightInputWeights.mAccessor); + const Collada::Data &weights = pParser.ResolveLibraryReference(pParser.mDataLibrary, weightsAcc.mSource); if (!jointNames.mIsStringArray || jointMatrices.mIsStringArray || weights.mIsStringArray) throw DeadlyImportError("Data type mismatch while resolving mesh joints"); @@ -770,10 +757,10 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M // create containers to collect the weights for each bone size_t numBones = jointNames.mStrings.size(); - std::vector > dstBones(numBones); + std::vector> dstBones(numBones); // build a temporary array of pointers to the start of each vertex's weights - typedef std::vector< std::pair > IndexPairVector; + typedef std::vector> IndexPairVector; std::vector weightStartPerVertex; weightStartPerVertex.resize(pSrcController->mWeightCounts.size(), pSrcController->mWeights.end()); @@ -792,18 +779,16 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M IndexPairVector::const_iterator iit = weightStartPerVertex[orgIndex]; size_t pairCount = pSrcController->mWeightCounts[orgIndex]; - - for( size_t b = 0; b < pairCount; ++b, ++iit) { + for (size_t b = 0; b < pairCount; ++b, ++iit) { const size_t jointIndex = iit->first; - const size_t vertexIndex = iit->second; + const size_t vertexIndex = iit->second; ai_real weight = 1.0f; if (!weights.mValues.empty()) { weight = ReadFloat(weightsAcc, weights, vertexIndex, 0); } // one day I gonna kill that XSI Collada exporter - if (weight > 0.0f) - { + if (weight > 0.0f) { aiVertexWeight w; w.mVertexId = static_cast(a - pStartVertex); w.mWeight = weight; @@ -814,24 +799,24 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M // count the number of bones which influence vertices of the current submesh size_t numRemainingBones = 0; - for( std::vector >::const_iterator it = dstBones.begin(); it != dstBones.end(); ++it) { - if( it->size() > 0) { + for (std::vector>::const_iterator it = dstBones.begin(); it != dstBones.end(); ++it) { + if (it->size() > 0) { ++numRemainingBones; } } // create bone array and copy bone weights one by one dstMesh->mNumBones = static_cast(numRemainingBones); - dstMesh->mBones = new aiBone*[numRemainingBones]; + dstMesh->mBones = new aiBone *[numRemainingBones]; size_t boneCount = 0; - for( size_t a = 0; a < numBones; ++a) { + for (size_t a = 0; a < numBones; ++a) { // omit bones without weights - if( dstBones[a].empty() ) { + if (dstBones[a].empty()) { continue; } // create bone with its weights - aiBone* bone = new aiBone; + aiBone *bone = new aiBone; bone->mName = ReadString(jointNamesAcc, jointNames, a); bone->mOffsetMatrix.a1 = ReadFloat(jointMatrixAcc, jointMatrices, a, 0); bone->mOffsetMatrix.a2 = ReadFloat(jointMatrixAcc, jointMatrices, a, 1); @@ -873,16 +858,16 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M // Therefore I added a little name replacement here: I search for the bone's node by either name, ID or SID, // and replace the bone's name by the node's name so that the user can use the standard // find-by-name method to associate nodes with bones. - const Collada::Node* bnode = FindNode( pParser.mRootNode, bone->mName.data); - if( !bnode) { - bnode = FindNodeBySID( pParser.mRootNode, bone->mName.data); + const Collada::Node *bnode = FindNode(pParser.mRootNode, bone->mName.data); + if (!bnode) { + bnode = FindNodeBySID(pParser.mRootNode, bone->mName.data); } // assign the name that we would have assigned for the source node - if( bnode) { - bone->mName.Set( FindNameForNode( bnode)); + if (bnode) { + bone->mName.Set(FindNameForNode(bnode)); } else { - ASSIMP_LOG_WARN_F( "ColladaLoader::CreateMesh(): could not find corresponding node for joint \"", bone->mName.data, "\"." ); + ASSIMP_LOG_WARN_F("ColladaLoader::CreateMesh(): could not find corresponding node for joint \"", bone->mName.data, "\"."); } // and insert bone @@ -895,61 +880,61 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M // ------------------------------------------------------------------------------------------------ // Stores all meshes in the given scene -void ColladaLoader::StoreSceneMeshes( aiScene* pScene) { +void ColladaLoader::StoreSceneMeshes(aiScene *pScene) { pScene->mNumMeshes = static_cast(mMeshes.size()); - if( mMeshes.empty() ) { + if (mMeshes.empty()) { return; } - pScene->mMeshes = new aiMesh*[mMeshes.size()]; - std::copy( mMeshes.begin(), mMeshes.end(), pScene->mMeshes); + pScene->mMeshes = new aiMesh *[mMeshes.size()]; + std::copy(mMeshes.begin(), mMeshes.end(), pScene->mMeshes); mMeshes.clear(); } // ------------------------------------------------------------------------------------------------ // Stores all cameras in the given scene -void ColladaLoader::StoreSceneCameras( aiScene* pScene) { +void ColladaLoader::StoreSceneCameras(aiScene *pScene) { pScene->mNumCameras = static_cast(mCameras.size()); - if( mCameras.empty() ) { + if (mCameras.empty()) { return; } - pScene->mCameras = new aiCamera*[mCameras.size()]; - std::copy( mCameras.begin(), mCameras.end(), pScene->mCameras); + pScene->mCameras = new aiCamera *[mCameras.size()]; + std::copy(mCameras.begin(), mCameras.end(), pScene->mCameras); mCameras.clear(); } // ------------------------------------------------------------------------------------------------ // Stores all lights in the given scene -void ColladaLoader::StoreSceneLights( aiScene* pScene) { +void ColladaLoader::StoreSceneLights(aiScene *pScene) { pScene->mNumLights = static_cast(mLights.size()); - if( mLights.empty() ) { + if (mLights.empty()) { return; } - pScene->mLights = new aiLight*[mLights.size()]; - std::copy( mLights.begin(), mLights.end(), pScene->mLights); + pScene->mLights = new aiLight *[mLights.size()]; + std::copy(mLights.begin(), mLights.end(), pScene->mLights); mLights.clear(); } // ------------------------------------------------------------------------------------------------ // Stores all textures in the given scene -void ColladaLoader::StoreSceneTextures( aiScene* pScene) { +void ColladaLoader::StoreSceneTextures(aiScene *pScene) { pScene->mNumTextures = static_cast(mTextures.size()); - if( mTextures.empty() ) { + if (mTextures.empty()) { return; } - pScene->mTextures = new aiTexture*[mTextures.size()]; - std::copy( mTextures.begin(), mTextures.end(), pScene->mTextures); + pScene->mTextures = new aiTexture *[mTextures.size()]; + std::copy(mTextures.begin(), mTextures.end(), pScene->mTextures); mTextures.clear(); } // ------------------------------------------------------------------------------------------------ // Stores all materials in the given scene -void ColladaLoader::StoreSceneMaterials( aiScene* pScene) { +void ColladaLoader::StoreSceneMaterials(aiScene *pScene) { pScene->mNumMaterials = static_cast(newMats.size()); - if (newMats.empty() ) { + if (newMats.empty()) { return; } - pScene->mMaterials = new aiMaterial*[newMats.size()]; - for (unsigned int i = 0; i < newMats.size();++i) { + pScene->mMaterials = new aiMaterial *[newMats.size()]; + for (unsigned int i = 0; i < newMats.size(); ++i) { pScene->mMaterials[i] = newMats[i].second; } newMats.clear(); @@ -957,53 +942,51 @@ void ColladaLoader::StoreSceneMaterials( aiScene* pScene) { // ------------------------------------------------------------------------------------------------ // Stores all animations -void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pParser) { +void ColladaLoader::StoreAnimations(aiScene *pScene, const ColladaParser &pParser) { // recursively collect all animations from the collada scene StoreAnimations(pScene, pParser, &pParser.mAnims, ""); // catch special case: many animations with the same length, each affecting only a single node. // we need to unite all those single-node-anims to a proper combined animation - for(size_t a = 0; a < mAnims.size(); ++a) { - aiAnimation* templateAnim = mAnims[a]; + for (size_t a = 0; a < mAnims.size(); ++a) { + aiAnimation *templateAnim = mAnims[a]; if (templateAnim->mNumChannels == 1) { // search for other single-channel-anims with the same duration std::vector collectedAnimIndices; - for( size_t b = a+1; b < mAnims.size(); ++b) { - aiAnimation* other = mAnims[b]; + for (size_t b = a + 1; b < mAnims.size(); ++b) { + aiAnimation *other = mAnims[b]; if (other->mNumChannels == 1 && other->mDuration == templateAnim->mDuration && - other->mTicksPerSecond == templateAnim->mTicksPerSecond) - collectedAnimIndices.push_back(b); + other->mTicksPerSecond == templateAnim->mTicksPerSecond) + collectedAnimIndices.push_back(b); } - // We only want to combine the animations if they have different channels - std::set animTargets; - animTargets.insert(templateAnim->mChannels[0]->mNodeName.C_Str()); - bool collectedAnimationsHaveDifferentChannels = true; - for (size_t b = 0; b < collectedAnimIndices.size(); ++b) - { - aiAnimation* srcAnimation = mAnims[collectedAnimIndices[b]]; - std::string channelName = std::string(srcAnimation->mChannels[0]->mNodeName.C_Str()); - if (animTargets.find(channelName) == animTargets.end()) { - animTargets.insert(channelName); - } else { - collectedAnimationsHaveDifferentChannels = false; - break; - } - } + // We only want to combine the animations if they have different channels + std::set animTargets; + animTargets.insert(templateAnim->mChannels[0]->mNodeName.C_Str()); + bool collectedAnimationsHaveDifferentChannels = true; + for (size_t b = 0; b < collectedAnimIndices.size(); ++b) { + aiAnimation *srcAnimation = mAnims[collectedAnimIndices[b]]; + std::string channelName = std::string(srcAnimation->mChannels[0]->mNodeName.C_Str()); + if (animTargets.find(channelName) == animTargets.end()) { + animTargets.insert(channelName); + } else { + collectedAnimationsHaveDifferentChannels = false; + break; + } + } - if (!collectedAnimationsHaveDifferentChannels) - continue; + if (!collectedAnimationsHaveDifferentChannels) + continue; // if there are other animations which fit the template anim, combine all channels into a single anim - if (!collectedAnimIndices.empty()) - { - aiAnimation* combinedAnim = new aiAnimation(); + if (!collectedAnimIndices.empty()) { + aiAnimation *combinedAnim = new aiAnimation(); combinedAnim->mName = aiString(std::string("combinedAnim_") + char('0' + a)); combinedAnim->mDuration = templateAnim->mDuration; combinedAnim->mTicksPerSecond = templateAnim->mTicksPerSecond; combinedAnim->mNumChannels = static_cast(collectedAnimIndices.size() + 1); - combinedAnim->mChannels = new aiNodeAnim*[combinedAnim->mNumChannels]; + combinedAnim->mChannels = new aiNodeAnim *[combinedAnim->mNumChannels]; // add the template anim as first channel by moving its aiNodeAnim to the combined animation combinedAnim->mChannels[0] = templateAnim->mChannels[0]; templateAnim->mChannels[0] = NULL; @@ -1012,9 +995,8 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars mAnims[a] = combinedAnim; // move the memory of all other anims to the combined anim and erase them from the source anims - for (size_t b = 0; b < collectedAnimIndices.size(); ++b) - { - aiAnimation* srcAnimation = mAnims[collectedAnimIndices[b]]; + for (size_t b = 0; b < collectedAnimIndices.size(); ++b) { + aiAnimation *srcAnimation = mAnims[collectedAnimIndices[b]]; combinedAnim->mChannels[1 + b] = srcAnimation->mChannels[0]; srcAnimation->mChannels[0] = NULL; delete srcAnimation; @@ -1022,8 +1004,7 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars // in a second go, delete all the single-channel-anims that we've stripped from their channels // back to front to preserve indices - you know, removing an element from a vector moves all elements behind the removed one - while (!collectedAnimIndices.empty()) - { + while (!collectedAnimIndices.empty()) { mAnims.erase(mAnims.begin() + collectedAnimIndices.back()); collectedAnimIndices.pop_back(); } @@ -1032,10 +1013,9 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars } // now store all anims in the scene - if (!mAnims.empty()) - { + if (!mAnims.empty()) { pScene->mNumAnimations = static_cast(mAnims.size()); - pScene->mAnimations = new aiAnimation*[mAnims.size()]; + pScene->mAnimations = new aiAnimation *[mAnims.size()]; std::copy(mAnims.begin(), mAnims.end(), pScene->mAnimations); } @@ -1044,12 +1024,11 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars // ------------------------------------------------------------------------------------------------ // Constructs the animations for the given source anim -void ColladaLoader::StoreAnimations(aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string &pPrefix) -{ +void ColladaLoader::StoreAnimations(aiScene *pScene, const ColladaParser &pParser, const Collada::Animation *pSrcAnim, const std::string &pPrefix) { std::string animName = pPrefix.empty() ? pSrcAnim->mName : pPrefix + "_" + pSrcAnim->mName; // create nested animations, if given - for (std::vector::const_iterator it = pSrcAnim->mSubAnims.begin(); it != pSrcAnim->mSubAnims.end(); ++it) + for (std::vector::const_iterator it = pSrcAnim->mSubAnims.begin(); it != pSrcAnim->mSubAnims.end(); ++it) StoreAnimations(pScene, pParser, *it, animName); // create animation channels, if any @@ -1057,47 +1036,38 @@ void ColladaLoader::StoreAnimations(aiScene* pScene, const ColladaParser& pParse CreateAnimation(pScene, pParser, pSrcAnim, animName); } -struct MorphTimeValues -{ +struct MorphTimeValues { float mTime; - struct key - { + struct key { float mWeight; unsigned int mValue; }; std::vector mKeys; }; -void insertMorphTimeValue(std::vector &values, float time, float weight, unsigned int value) -{ +void insertMorphTimeValue(std::vector &values, float time, float weight, unsigned int value) { MorphTimeValues::key k; k.mValue = value; k.mWeight = weight; - if (values.size() == 0 || time < values[0].mTime) - { + if (values.size() == 0 || time < values[0].mTime) { MorphTimeValues val; val.mTime = time; val.mKeys.push_back(k); values.insert(values.begin(), val); return; } - if (time > values.back().mTime) - { + if (time > values.back().mTime) { MorphTimeValues val; val.mTime = time; val.mKeys.push_back(k); values.insert(values.end(), val); return; } - for (unsigned int i = 0; i < values.size(); i++) - { - if (std::abs(time - values[i].mTime) < 1e-6f) - { + for (unsigned int i = 0; i < values.size(); i++) { + if (std::abs(time - values[i].mTime) < 1e-6f) { values[i].mKeys.push_back(k); return; - } - else if (time > values[i].mTime && time < values[i + 1].mTime) - { + } else if (time > values[i].mTime && time < values[i + 1].mTime) { MorphTimeValues val; val.mTime = time; val.mKeys.push_back(k); @@ -1108,10 +1078,8 @@ void insertMorphTimeValue(std::vector &values, float time, floa // should not get here } -float getWeightAtKey(const std::vector &values, int key, unsigned int value) -{ - for (unsigned int i = 0; i < values[key].mKeys.size(); i++) - { +float getWeightAtKey(const std::vector &values, int key, unsigned int value) { + for (unsigned int i = 0; i < values[key].mKeys.size(); i++) { if (values[key].mKeys[i].mValue == value) return values[key].mKeys[i].mWeight; } @@ -1122,23 +1090,21 @@ float getWeightAtKey(const std::vector &values, int key, unsign // ------------------------------------------------------------------------------------------------ // Constructs the animation for the given source anim -void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string& pName) -{ +void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParser, const Collada::Animation *pSrcAnim, const std::string &pName) { // collect a list of animatable nodes - std::vector nodes; + std::vector nodes; CollectNodes(pScene->mRootNode, nodes); - std::vector anims; - std::vector morphAnims; + std::vector anims; + std::vector morphAnims; - for (std::vector::const_iterator nit = nodes.begin(); nit != nodes.end(); ++nit) - { + for (std::vector::const_iterator nit = nodes.begin(); nit != nodes.end(); ++nit) { // find all the collada anim channels which refer to the current node std::vector entries; std::string nodeName = (*nit)->mName.data; // find the collada node corresponding to the aiNode - const Collada::Node* srcNode = FindNode(pParser.mRootNode, nodeName); + const Collada::Node *srcNode = FindNode(pParser.mRootNode, nodeName); // ai_assert( srcNode != NULL); if (!srcNode) continue; @@ -1146,16 +1112,14 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse // now check all channels if they affect the current node std::string targetID, subElement; for (std::vector::const_iterator cit = pSrcAnim->mChannels.begin(); - cit != pSrcAnim->mChannels.end(); ++cit) - { - const Collada::AnimationChannel& srcChannel = *cit; + cit != pSrcAnim->mChannels.end(); ++cit) { + const Collada::AnimationChannel &srcChannel = *cit; Collada::ChannelEntry entry; // we expect the animation target to be of type "nodeName/transformID.subElement". Ignore all others // find the slash that separates the node name - there should be only one std::string::size_type slashPos = srcChannel.mTarget.find('/'); - if (slashPos == std::string::npos) - { + if (slashPos == std::string::npos) { std::string::size_type targetPos = srcChannel.mTarget.find(srcNode->mID); if (targetPos == std::string::npos) continue; @@ -1163,7 +1127,7 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse // not node transform, but something else. store as unknown animation channel for now entry.mChannel = &(*cit); entry.mTargetId = srcChannel.mTarget.substr(targetPos + pSrcAnim->mName.length(), - srcChannel.mTarget.length() - targetPos - pSrcAnim->mName.length()); + srcChannel.mTarget.length() - targetPos - pSrcAnim->mName.length()); if (entry.mTargetId.front() == '-') entry.mTargetId = entry.mTargetId.substr(1); entries.push_back(entry); @@ -1179,8 +1143,7 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse // find the dot that separates the transformID - there should be only one or zero std::string::size_type dotPos = srcChannel.mTarget.find('.'); - if (dotPos != std::string::npos) - { + if (dotPos != std::string::npos) { if (srcChannel.mTarget.find('.', dotPos + 1) != std::string::npos) continue; @@ -1198,15 +1161,13 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse entry.mSubElement = 2; else ASSIMP_LOG_WARN_F("Unknown anim subelement <", subElement, ">. Ignoring"); - } - else { + } else { // no subelement following, transformId is remaining string entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1); } std::string::size_type bracketPos = srcChannel.mTarget.find('('); - if (bracketPos != std::string::npos) - { + if (bracketPos != std::string::npos) { entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1, bracketPos - slashPos - 1); subElement.clear(); subElement = srcChannel.mTarget.substr(bracketPos); @@ -1251,14 +1212,11 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse if (srcNode->mTransforms[a].mID == entry.mTransformId) entry.mTransformIndex = a; - if (entry.mTransformIndex == SIZE_MAX) - { - if (entry.mTransformId.find("morph-weights") != std::string::npos) - { + if (entry.mTransformIndex == SIZE_MAX) { + if (entry.mTransformId.find("morph-weights") != std::string::npos) { entry.mTargetId = entry.mTransformId; entry.mTransformId = ""; - } - else + } else continue; } @@ -1272,9 +1230,8 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse // resolve the data pointers for all anim channels. Find the minimum time while we're at it ai_real startTime = ai_real(1e20), endTime = ai_real(-1e20); - for (std::vector::iterator it = entries.begin(); it != entries.end(); ++it) - { - Collada::ChannelEntry& e = *it; + for (std::vector::iterator it = entries.begin(); it != entries.end(); ++it) { + Collada::ChannelEntry &e = *it; e.mTimeAccessor = &pParser.ResolveLibraryReference(pParser.mAccessorLibrary, e.mChannel->mSourceTimes); e.mTimeData = &pParser.ResolveLibraryReference(pParser.mDataLibrary, e.mTimeAccessor->mSource); e.mValueAccessor = &pParser.ResolveLibraryReference(pParser.mAccessorLibrary, e.mChannel->mSourceValues); @@ -1284,8 +1241,7 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse if (e.mTimeAccessor->mCount != e.mValueAccessor->mCount) throw DeadlyImportError(format() << "Time count / value count mismatch in animation channel \"" << e.mChannel->mTarget << "\"."); - if (e.mTimeAccessor->mCount > 0) - { + if (e.mTimeAccessor->mCount > 0) { // find bounding times startTime = std::min(startTime, ReadFloat(*e.mTimeAccessor, *e.mTimeData, 0, 0)); endTime = std::max(endTime, ReadFloat(*e.mTimeAccessor, *e.mTimeData, e.mTimeAccessor->mCount - 1, 0)); @@ -1293,25 +1249,21 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse } std::vector resultTrafos; - if (!entries.empty() && entries.front().mTimeAccessor->mCount > 0) - { + if (!entries.empty() && entries.front().mTimeAccessor->mCount > 0) { // create a local transformation chain of the node's transforms std::vector transforms = srcNode->mTransforms; // now for every unique point in time, find or interpolate the key values for that time // and apply them to the transform chain. Then the node's present transformation can be calculated. ai_real time = startTime; - while (1) - { - for (std::vector::iterator it = entries.begin(); it != entries.end(); ++it) - { - Collada::ChannelEntry& e = *it; + while (1) { + for (std::vector::iterator it = entries.begin(); it != entries.end(); ++it) { + Collada::ChannelEntry &e = *it; // find the keyframe behind the current point in time size_t pos = 0; ai_real postTime = 0.0; - while (1) - { + while (1) { if (pos >= e.mTimeAccessor->mCount) break; postTime = ReadFloat(*e.mTimeAccessor, *e.mTimeData, pos, 0); @@ -1328,13 +1280,11 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse temp[c] = ReadFloat(*e.mValueAccessor, *e.mValueData, pos, c); // if not exactly at the key time, interpolate with previous value set - if (postTime > time && pos > 0) - { + if (postTime > time && pos > 0) { ai_real preTime = ReadFloat(*e.mTimeAccessor, *e.mTimeData, pos - 1, 0); ai_real factor = (time - postTime) / (preTime - postTime); - for (size_t c = 0; c < e.mValueAccessor->mSize; ++c) - { + for (size_t c = 0; c < e.mValueAccessor->mSize; ++c) { ai_real v = ReadFloat(*e.mValueAccessor, *e.mValueData, pos - 1, c); temp[c] += (v - temp[c]) * factor; } @@ -1353,17 +1303,14 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse // find next point in time to evaluate. That's the closest frame larger than the current in any channel ai_real nextTime = ai_real(1e20); - for (std::vector::iterator it = entries.begin(); it != entries.end(); ++it) - { - Collada::ChannelEntry& channelElement = *it; + for (std::vector::iterator it = entries.begin(); it != entries.end(); ++it) { + Collada::ChannelEntry &channelElement = *it; // find the next time value larger than the current size_t pos = 0; - while (pos < channelElement.mTimeAccessor->mCount) - { + while (pos < channelElement.mTimeAccessor->mCount) { const ai_real t = ReadFloat(*channelElement.mTimeAccessor, *channelElement.mTimeData, pos, 0); - if (t > time) - { + if (t > time) { nextTime = std::min(nextTime, t); break; } @@ -1400,12 +1347,11 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse } // there should be some keyframes, but we aren't that fixated on valid input data -// ai_assert( resultTrafos.size() > 0); + // ai_assert( resultTrafos.size() > 0); // build an animation channel for the given node out of these trafo keys - if (!resultTrafos.empty()) - { - aiNodeAnim* dstAnim = new aiNodeAnim; + if (!resultTrafos.empty()) { + aiNodeAnim *dstAnim = new aiNodeAnim; dstAnim->mNodeName = nodeName; dstAnim->mNumPositionKeys = static_cast(resultTrafos.size()); dstAnim->mNumRotationKeys = static_cast(resultTrafos.size()); @@ -1414,8 +1360,7 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse dstAnim->mRotationKeys = new aiQuatKey[resultTrafos.size()]; dstAnim->mScalingKeys = new aiVectorKey[resultTrafos.size()]; - for (size_t a = 0; a < resultTrafos.size(); ++a) - { + for (size_t a = 0; a < resultTrafos.size(); ++a) { aiMatrix4x4 mat = resultTrafos[a]; double time = double(mat.d4); // remember? time is stored in mat.d4 mat.d4 = 1.0f; @@ -1427,18 +1372,14 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse } anims.push_back(dstAnim); - } - else - { + } else { ASSIMP_LOG_WARN("Collada loader: found empty animation channel, ignored. Please check your exporter."); } - if (!entries.empty() && entries.front().mTimeAccessor->mCount > 0) - { + if (!entries.empty() && entries.front().mTimeAccessor->mCount > 0) { std::vector morphChannels; - for (std::vector::iterator it = entries.begin(); it != entries.end(); ++it) - { - Collada::ChannelEntry& e = *it; + for (std::vector::iterator it = entries.begin(); it != entries.end(); ++it) { + Collada::ChannelEntry &e = *it; // skip non-transform types if (e.mTargetId.empty()) @@ -1447,8 +1388,7 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse if (e.mTargetId.find("morph-weights") != std::string::npos) morphChannels.push_back(e); } - if (morphChannels.size() > 0) - { + if (morphChannels.size() > 0) { // either 1) morph weight animation count should contain morph target count channels // or 2) one channel with morph target count arrays // assume first @@ -1459,9 +1399,8 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse std::vector morphTimeValues; int morphAnimChannelIndex = 0; - for (std::vector::iterator it = morphChannels.begin(); it != morphChannels.end(); ++it) - { - Collada::ChannelEntry& e = *it; + for (std::vector::iterator it = morphChannels.begin(); it != morphChannels.end(); ++it) { + Collada::ChannelEntry &e = *it; std::string::size_type apos = e.mTargetId.find('('); std::string::size_type bpos = e.mTargetId.find(')'); if (apos == std::string::npos || bpos == std::string::npos) @@ -1478,15 +1417,13 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse morphAnim->mNumKeys = static_cast(morphTimeValues.size()); morphAnim->mKeys = new aiMeshMorphKey[morphAnim->mNumKeys]; - for (unsigned int key = 0; key < morphAnim->mNumKeys; key++) - { + for (unsigned int key = 0; key < morphAnim->mNumKeys; key++) { morphAnim->mKeys[key].mNumValuesAndWeights = static_cast(morphChannels.size()); morphAnim->mKeys[key].mValues = new unsigned int[morphChannels.size()]; morphAnim->mKeys[key].mWeights = new double[morphChannels.size()]; morphAnim->mKeys[key].mTime = morphTimeValues[key].mTime; - for (unsigned int valueIndex = 0; valueIndex < morphChannels.size(); valueIndex++) - { + for (unsigned int valueIndex = 0; valueIndex < morphChannels.size(); valueIndex++) { morphAnim->mKeys[key].mValues[valueIndex] = valueIndex; morphAnim->mKeys[key].mWeights[valueIndex] = getWeightAtKey(morphTimeValues, key, valueIndex); } @@ -1497,31 +1434,26 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse } } - if (!anims.empty() || !morphAnims.empty()) - { - aiAnimation* anim = new aiAnimation; + if (!anims.empty() || !morphAnims.empty()) { + aiAnimation *anim = new aiAnimation; anim->mName.Set(pName); anim->mNumChannels = static_cast(anims.size()); - if (anim->mNumChannels > 0) - { - anim->mChannels = new aiNodeAnim*[anims.size()]; + if (anim->mNumChannels > 0) { + anim->mChannels = new aiNodeAnim *[anims.size()]; std::copy(anims.begin(), anims.end(), anim->mChannels); } anim->mNumMorphMeshChannels = static_cast(morphAnims.size()); - if (anim->mNumMorphMeshChannels > 0) - { - anim->mMorphMeshChannels = new aiMeshMorphAnim*[anim->mNumMorphMeshChannels]; + if (anim->mNumMorphMeshChannels > 0) { + anim->mMorphMeshChannels = new aiMeshMorphAnim *[anim->mNumMorphMeshChannels]; std::copy(morphAnims.begin(), morphAnims.end(), anim->mMorphMeshChannels); } anim->mDuration = 0.0f; - for (size_t a = 0; a < anims.size(); ++a) - { + for (size_t a = 0; a < anims.size(); ++a) { anim->mDuration = std::max(anim->mDuration, anims[a]->mPositionKeys[anims[a]->mNumPositionKeys - 1].mTime); anim->mDuration = std::max(anim->mDuration, anims[a]->mRotationKeys[anims[a]->mNumRotationKeys - 1].mTime); anim->mDuration = std::max(anim->mDuration, anims[a]->mScalingKeys[anims[a]->mNumScalingKeys - 1].mTime); } - for (size_t a = 0; a < morphAnims.size(); ++a) - { + for (size_t a = 0; a < morphAnims.size(); ++a) { anim->mDuration = std::max(anim->mDuration, morphAnims[a]->mKeys[morphAnims[a]->mNumKeys - 1].mTime); } anim->mTicksPerSecond = 1; @@ -1531,11 +1463,10 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse // ------------------------------------------------------------------------------------------------ // Add a texture to a material structure -void ColladaLoader::AddTexture(aiMaterial& mat, const ColladaParser& pParser, - const Collada::Effect& effect, - const Collada::Sampler& sampler, - aiTextureType type, unsigned int idx) -{ +void ColladaLoader::AddTexture(aiMaterial &mat, const ColladaParser &pParser, + const Collada::Effect &effect, + const Collada::Sampler &sampler, + aiTextureType type, unsigned int idx) { // first of all, basic file name const aiString name = FindFilenameForEffectTexture(pParser, effect, sampler.mName); mat.AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, type, idx); @@ -1559,15 +1490,15 @@ void ColladaLoader::AddTexture(aiMaterial& mat, const ColladaParser& pParser, // UV transformation mat.AddProperty(&sampler.mTransform, 1, - _AI_MATKEY_UVTRANSFORM_BASE, type, idx); + _AI_MATKEY_UVTRANSFORM_BASE, type, idx); // Blend mode - mat.AddProperty((int*)&sampler.mOp, 1, - _AI_MATKEY_TEXBLEND_BASE, type, idx); + mat.AddProperty((int *)&sampler.mOp, 1, + _AI_MATKEY_TEXBLEND_BASE, type, idx); // Blend factor - mat.AddProperty((ai_real*)&sampler.mWeighting, 1, - _AI_MATKEY_TEXBLEND_BASE, type, idx); + mat.AddProperty((ai_real *)&sampler.mWeighting, 1, + _AI_MATKEY_TEXBLEND_BASE, type, idx); // UV source index ... if we didn't resolve the mapping, it is actually just // a guess but it works in most cases. We search for the frst occurrence of a @@ -1594,20 +1525,17 @@ void ColladaLoader::AddTexture(aiMaterial& mat, const ColladaParser& pParser, // ------------------------------------------------------------------------------------------------ // Fills materials from the collada material definitions -void ColladaLoader::FillMaterials(const ColladaParser& pParser, aiScene* /*pScene*/) -{ - for (auto &elem : newMats) - { - aiMaterial& mat = (aiMaterial&)*elem.second; - Collada::Effect& effect = *elem.first; +void ColladaLoader::FillMaterials(const ColladaParser &pParser, aiScene * /*pScene*/) { + for (auto &elem : newMats) { + aiMaterial &mat = (aiMaterial &)*elem.second; + Collada::Effect &effect = *elem.first; // resolve shading mode int shadeMode; if (effect.mFaceted) /* fixme */ shadeMode = aiShadingMode_Flat; else { - switch (effect.mShadeType) - { + switch (effect.mShadeType) { case Collada::Shade_Constant: shadeMode = aiShadingMode_NoShading; break; @@ -1657,17 +1585,14 @@ void ColladaLoader::FillMaterials(const ColladaParser& pParser, aiScene* /*pScen // handle RGB transparency completely, cf Collada specs 1.5.0 pages 249 and 304 if (effect.mRGBTransparency) { // use luminance as defined by ISO/CIE color standards (see ITU-R Recommendation BT.709-4) - effect.mTransparency *= ( - 0.212671f * effect.mTransparent.r + - 0.715160f * effect.mTransparent.g + - 0.072169f * effect.mTransparent.b - ); + effect.mTransparency *= (0.212671f * effect.mTransparent.r + + 0.715160f * effect.mTransparent.g + + 0.072169f * effect.mTransparent.b); effect.mTransparent.a = 1.f; mat.AddProperty(&effect.mTransparent, 1, AI_MATKEY_COLOR_TRANSPARENT); - } - else { + } else { effect.mTransparency *= effect.mTransparent.a; } @@ -1709,27 +1634,26 @@ void ColladaLoader::FillMaterials(const ColladaParser& pParser, aiScene* /*pScen // ------------------------------------------------------------------------------------------------ // Constructs materials from the collada material definitions -void ColladaLoader::BuildMaterials(ColladaParser& pParser, aiScene* /*pScene*/) -{ +void ColladaLoader::BuildMaterials(ColladaParser &pParser, aiScene * /*pScene*/) { newMats.reserve(pParser.mMaterialLibrary.size()); for (ColladaParser::MaterialLibrary::const_iterator matIt = pParser.mMaterialLibrary.begin(); - matIt != pParser.mMaterialLibrary.end(); ++matIt) { - const Collada::Material& material = matIt->second; + matIt != pParser.mMaterialLibrary.end(); ++matIt) { + const Collada::Material &material = matIt->second; // a material is only a reference to an effect ColladaParser::EffectLibrary::iterator effIt = pParser.mEffectLibrary.find(material.mEffect); if (effIt == pParser.mEffectLibrary.end()) continue; - Collada::Effect& effect = effIt->second; + Collada::Effect &effect = effIt->second; // create material - aiMaterial* mat = new aiMaterial; + aiMaterial *mat = new aiMaterial; aiString name(material.mName.empty() ? matIt->first : material.mName); mat->AddProperty(&name, AI_MATKEY_NAME); // store the material mMaterialIndexByName[matIt->first] = newMats.size(); - newMats.push_back(std::pair(&effect, mat)); + newMats.push_back(std::pair(&effect, mat)); } // ScenePreprocessor generates a default material automatically if none is there. // All further code here in this loader works well without a valid material so @@ -1755,16 +1679,14 @@ void ColladaLoader::BuildMaterials(ColladaParser& pParser, aiScene* /*pScene*/) // ------------------------------------------------------------------------------------------------ // Resolves the texture name for the given effect texture entry -// and loads the texture data -aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParser, - const Collada::Effect& pEffect, const std::string& pName) -{ +// and loads the texture data +aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser &pParser, + const Collada::Effect &pEffect, const std::string &pName) { aiString result; // recurse through the param references until we end up at an image std::string name = pName; - while (1) - { + while (1) { // the given string is a param entry. Find it Collada::Effect::ParamLibrary::const_iterator it = pEffect.mParams.find(name); // if not found, we're at the end of the recursion. The resulting string should be the image ID @@ -1777,8 +1699,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParse // find the image referred by this name in the image library of the scene ColladaParser::ImageLibrary::const_iterator imIt = pParser.mImageLibrary.find(name); - if (imIt == pParser.mImageLibrary.end()) - { + if (imIt == pParser.mImageLibrary.end()) { ASSIMP_LOG_WARN_F("Collada: Unable to resolve effect texture entry \"", pName, "\", ended up at ID \"", name, "\"."); //set default texture file name @@ -1788,18 +1709,16 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParse } // if this is an embedded texture image setup an aiTexture for it - if (!imIt->second.mImageData.empty()) - { - aiTexture* tex = new aiTexture(); + if (!imIt->second.mImageData.empty()) { + aiTexture *tex = new aiTexture(); // Store embedded texture name reference tex->mFilename.Set(imIt->second.mFileName.c_str()); result.Set(imIt->second.mFileName); // TODO: check the possibility of using the flag "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING" -// result.data[0] = '*'; -// result.length = 1 + ASSIMP_itoa10(result.data + 1, static_cast(MAXLEN - 1), static_cast(mTextures.size())); - + // result.data[0] = '*'; + // result.length = 1 + ASSIMP_itoa10(result.data + 1, static_cast(MAXLEN - 1), static_cast(mTextures.size())); // setup format hint if (imIt->second.mEmbeddedFormat.length() >= HINTMAXTEXTURELEN) { @@ -1810,14 +1729,12 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParse // and copy texture data tex->mHeight = 0; tex->mWidth = static_cast(imIt->second.mImageData.size()); - tex->pcData = (aiTexel*)new char[tex->mWidth]; + tex->pcData = (aiTexel *)new char[tex->mWidth]; memcpy(tex->pcData, &imIt->second.mImageData[0], tex->mWidth); // and add this texture to the list mTextures.push_back(tex); - } - else - { + } else { if (imIt->second.mFileName.empty()) { throw DeadlyImportError("Collada: Invalid texture, no data or file reference given"); } @@ -1829,8 +1746,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParse // ------------------------------------------------------------------------------------------------ // Reads a float value from an accessor and its data array. -ai_real ColladaLoader::ReadFloat(const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex, size_t pOffset) const -{ +ai_real ColladaLoader::ReadFloat(const Collada::Accessor &pAccessor, const Collada::Data &pData, size_t pIndex, size_t pOffset) const { // FIXME: (thom) Test for data type here in every access? For the moment, I leave this to the caller size_t pos = pAccessor.mStride * pIndex + pAccessor.mOffset + pOffset; ai_assert(pos < pData.mValues.size()); @@ -1839,8 +1755,7 @@ ai_real ColladaLoader::ReadFloat(const Collada::Accessor& pAccessor, const Colla // ------------------------------------------------------------------------------------------------ // Reads a string value from an accessor and its data array. -const std::string& ColladaLoader::ReadString(const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex) const -{ +const std::string &ColladaLoader::ReadString(const Collada::Accessor &pAccessor, const Collada::Data &pData, size_t pIndex) const { size_t pos = pAccessor.mStride * pIndex + pAccessor.mOffset; ai_assert(pos < pData.mStrings.size()); return pData.mStrings[pos]; @@ -1848,8 +1763,7 @@ const std::string& ColladaLoader::ReadString(const Collada::Accessor& pAccessor, // ------------------------------------------------------------------------------------------------ // Collects all nodes into the given array -void ColladaLoader::CollectNodes(const aiNode* pNode, std::vector& poNodes) const -{ +void ColladaLoader::CollectNodes(const aiNode *pNode, std::vector &poNodes) const { poNodes.push_back(pNode); for (size_t a = 0; a < pNode->mNumChildren; ++a) { CollectNodes(pNode->mChildren[a], poNodes); @@ -1858,14 +1772,12 @@ void ColladaLoader::CollectNodes(const aiNode* pNode, std::vector // ------------------------------------------------------------------------------------------------ // Finds a node in the collada scene by the given name -const Collada::Node* ColladaLoader::FindNode(const Collada::Node* pNode, const std::string& pName) const -{ +const Collada::Node *ColladaLoader::FindNode(const Collada::Node *pNode, const std::string &pName) const { if (pNode->mName == pName || pNode->mID == pName) return pNode; - for (size_t a = 0; a < pNode->mChildren.size(); ++a) - { - const Collada::Node* node = FindNode(pNode->mChildren[a], pName); + for (size_t a = 0; a < pNode->mChildren.size(); ++a) { + const Collada::Node *node = FindNode(pNode->mChildren[a], pName); if (node) return node; } @@ -1875,7 +1787,7 @@ const Collada::Node* ColladaLoader::FindNode(const Collada::Node* pNode, const s // ------------------------------------------------------------------------------------------------ // Finds a node in the collada scene by the given SID -const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, const std::string& pSID) const { +const Collada::Node *ColladaLoader::FindNodeBySID(const Collada::Node *pNode, const std::string &pSID) const { if (nullptr == pNode) { return nullptr; } @@ -1884,8 +1796,8 @@ const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, c return pNode; } - for( size_t a = 0; a < pNode->mChildren.size(); ++a) { - const Collada::Node* node = FindNodeBySID( pNode->mChildren[a], pSID); + for (size_t a = 0; a < pNode->mChildren.size(); ++a) { + const Collada::Node *node = FindNodeBySID(pNode->mChildren[a], pSID); if (node) { return node; } @@ -1897,28 +1809,22 @@ const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, c // ------------------------------------------------------------------------------------------------ // Finds a proper unique name for a node derived from the collada-node's properties. // The name must be unique for proper node-bone association. -std::string ColladaLoader::FindNameForNode(const Collada::Node* pNode) -{ +std::string ColladaLoader::FindNameForNode(const Collada::Node *pNode) { // If explicitly requested, just use the collada name. - if (useColladaName) - { + if (useColladaName) { if (!pNode->mName.empty()) { return pNode->mName; - } - else { + } else { return format() << "$ColladaAutoName$_" << mNodeNameCounter++; } - } - else - { + } else { // Now setup the name of the assimp node. The collada name might not be // unique, so we use the collada ID. if (!pNode->mID.empty()) return pNode->mID; else if (!pNode->mSID.empty()) return pNode->mSID; - else - { + else { // No need to worry. Unnamed nodes are no problem at all, except // if cameras or lights need to be assigned to them. return format() << "$ColladaAutoName$_" << mNodeNameCounter++; diff --git a/code/Collada/ColladaParser.cpp b/code/Collada/ColladaParser.cpp index 25ee2bc3c..5080094c1 100644 --- a/code/Collada/ColladaParser.cpp +++ b/code/Collada/ColladaParser.cpp @@ -47,18 +47,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_COLLADA_IMPORTER -#include -#include #include "ColladaParser.h" -#include -#include #include #include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include #include @@ -68,24 +68,24 @@ using namespace Assimp::Formatter; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer -ColladaParser::ColladaParser(IOSystem* pIOHandler, const std::string& pFile) - : mFileName(pFile) - , mReader(nullptr) - , mDataLibrary() - , mAccessorLibrary() - , mMeshLibrary() - , mNodeLibrary() - , mImageLibrary() - , mEffectLibrary() - , mMaterialLibrary() - , mLightLibrary() - , mCameraLibrary() - , mControllerLibrary() - , mRootNode(nullptr) - , mAnims() - , mUnitSize(1.0f) - , mUpDirection(UP_Y) - , mFormat(FV_1_5_n) // We assume the newest file format by default +ColladaParser::ColladaParser(IOSystem *pIOHandler, const std::string &pFile) : + mFileName(pFile), + mReader(nullptr), + mDataLibrary(), + mAccessorLibrary(), + mMeshLibrary(), + mNodeLibrary(), + mImageLibrary(), + mEffectLibrary(), + mMaterialLibrary(), + mLightLibrary(), + mCameraLibrary(), + mControllerLibrary(), + mRootNode(nullptr), + mAnims(), + mUnitSize(1.0f), + mUpDirection(UP_Y), + mFormat(FV_1_5_n) // We assume the newest file format by default { // validate io-handler instance if (nullptr == pIOHandler) { @@ -112,8 +112,7 @@ ColladaParser::ColladaParser(IOSystem* pIOHandler, const std::string& pFile) if (daefile == nullptr) { ThrowException(std::string("Invalid ZAE manifest: '") + std::string(dae_filename) + std::string("' is missing")); } - } - else { + } else { // attempt to open the file directly daefile.reset(pIOHandler->Open(pFile)); if (daefile.get() == nullptr) { @@ -139,8 +138,7 @@ ColladaParser::ColladaParser(IOSystem* pIOHandler, const std::string& pFile) // ------------------------------------------------------------------------------------------------ // Destructor, private as well -ColladaParser::~ColladaParser() -{ +ColladaParser::~ColladaParser() { delete mReader; for (NodeLibrary::iterator it = mNodeLibrary.begin(); it != mNodeLibrary.end(); ++it) delete it->second; @@ -153,8 +151,7 @@ ColladaParser::~ColladaParser() std::string ColladaParser::ReadZaeManifest(ZipArchiveIOSystem &zip_archive) { // Open the manifest std::unique_ptr manifestfile(zip_archive.Open("manifest.xml")); - if (manifestfile == nullptr) - { + if (manifestfile == nullptr) { // No manifest, hope there is only one .DAE inside std::vector file_list; zip_archive.getFileListExtension(file_list, "dae"); @@ -168,19 +165,16 @@ std::string ColladaParser::ReadZaeManifest(ZipArchiveIOSystem &zip_archive) { std::unique_ptr mIOWrapper(new CIrrXML_IOStreamReader(manifestfile.get())); std::unique_ptr manifest_reader(irr::io::createIrrXMLReader(mIOWrapper.get())); - while (manifest_reader->read()) - { + while (manifest_reader->read()) { // find the manifest "dae_root" element - if (manifest_reader->getNodeType() == irr::io::EXN_ELEMENT) - { - if (::strcmp(manifest_reader->getNodeName(), "dae_root") == 0) - { + if (manifest_reader->getNodeType() == irr::io::EXN_ELEMENT) { + if (::strcmp(manifest_reader->getNodeName(), "dae_root") == 0) { if (!manifest_reader->read()) return std::string(); if (manifest_reader->getNodeType() != irr::io::EXN_TEXT && manifest_reader->getNodeType() != irr::io::EXN_CDATA) return std::string(); - const char* filepath = manifest_reader->getNodeData(); + const char *filepath = manifest_reader->getNodeData(); if (filepath == nullptr) return std::string(); @@ -196,14 +190,12 @@ std::string ColladaParser::ReadZaeManifest(ZipArchiveIOSystem &zip_archive) { // ------------------------------------------------------------------------------------------------ // Convert a path read from a collada file to the usual representation -void ColladaParser::UriDecodePath(aiString& ss) -{ +void ColladaParser::UriDecodePath(aiString &ss) { // TODO: collada spec, p 22. Handle URI correctly. // For the moment we're just stripping the file:// away to make it work. // Windows doesn't seem to be able to find stuff like // 'file://..\LWO\LWO2\MappingModes\earthSpherical.jpg' - if (0 == strncmp(ss.data, "file://", 7)) - { + if (0 == strncmp(ss.data, "file://", 7)) { ss.length -= 7; memmove(ss.data, ss.data + 7, ss.length); ss.data[ss.length] = '\0'; @@ -211,7 +203,7 @@ void ColladaParser::UriDecodePath(aiString& ss) // Maxon Cinema Collada Export writes "file:///C:\andsoon" with three slashes... // I need to filter it without destroying linux paths starting with "/somewhere" -#if defined( _MSC_VER ) +#if defined(_MSC_VER) if (ss.data[0] == '/' && isalpha((unsigned char)ss.data[1]) && ss.data[2] == ':') { #else if (ss.data[0] == '/' && isalpha(ss.data[1]) && ss.data[2] == ':') { @@ -222,19 +214,15 @@ void ColladaParser::UriDecodePath(aiString& ss) } // find and convert all %xy special chars - char* out = ss.data; - for (const char* it = ss.data; it != ss.data + ss.length; /**/) - { - if (*it == '%' && (it + 3) < ss.data + ss.length) - { + char *out = ss.data; + for (const char *it = ss.data; it != ss.data + ss.length; /**/) { + if (*it == '%' && (it + 3) < ss.data + ss.length) { // separate the number to avoid dragging in chars from behind into the parsing char mychar[3] = { it[1], it[2], 0 }; size_t nbr = strtoul16(mychar); it += 3; *out++ = (char)(nbr & 0xFF); - } - else - { + } else { *out++ = *it++; } } @@ -247,10 +235,9 @@ void ColladaParser::UriDecodePath(aiString& ss) // ------------------------------------------------------------------------------------------------ // Read bool from text contents of current element -bool ColladaParser::ReadBoolFromTextContent() -{ - const char* cur = GetTextContent(); - if ( nullptr == cur) { +bool ColladaParser::ReadBoolFromTextContent() { + const char *cur = GetTextContent(); + if (nullptr == cur) { return false; } return (!ASSIMP_strincmp(cur, "true", 4) || '0' != *cur); @@ -258,10 +245,9 @@ bool ColladaParser::ReadBoolFromTextContent() // ------------------------------------------------------------------------------------------------ // Read float from text contents of current element -ai_real ColladaParser::ReadFloatFromTextContent() -{ - const char* cur = GetTextContent(); - if ( nullptr == cur ) { +ai_real ColladaParser::ReadFloatFromTextContent() { + const char *cur = GetTextContent(); + if (nullptr == cur) { return 0.0; } return fast_atof(cur); @@ -269,49 +255,39 @@ ai_real ColladaParser::ReadFloatFromTextContent() // ------------------------------------------------------------------------------------------------ // Reads the contents of the file -void ColladaParser::ReadContents() -{ - while (mReader->read()) - { +void ColladaParser::ReadContents() { + while (mReader->read()) { // handle the root element "COLLADA" - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { - if (IsElement("COLLADA")) - { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("COLLADA")) { // check for 'version' attribute const int attrib = TestAttribute("version"); if (attrib != -1) { - const char* version = mReader->getAttributeValue(attrib); + const char *version = mReader->getAttributeValue(attrib); // Store declared format version string aiString v; v.Set(version); - mAssetMetaData.emplace(AI_METADATA_SOURCE_FORMAT_VERSION, v ); + mAssetMetaData.emplace(AI_METADATA_SOURCE_FORMAT_VERSION, v); if (!::strncmp(version, "1.5", 3)) { mFormat = FV_1_5_n; ASSIMP_LOG_DEBUG("Collada schema version is 1.5.n"); - } - else if (!::strncmp(version, "1.4", 3)) { + } else if (!::strncmp(version, "1.4", 3)) { mFormat = FV_1_4_n; ASSIMP_LOG_DEBUG("Collada schema version is 1.4.n"); - } - else if (!::strncmp(version, "1.3", 3)) { + } else if (!::strncmp(version, "1.3", 3)) { mFormat = FV_1_3_n; ASSIMP_LOG_DEBUG("Collada schema version is 1.3.n"); } } ReadStructure(); - } - else - { + } else { ASSIMP_LOG_DEBUG_F("Ignoring global element <", mReader->getNodeName(), ">."); SkipElement(); } - } - else - { + } else { // skip everything else silently } } @@ -319,13 +295,10 @@ void ColladaParser::ReadContents() // ------------------------------------------------------------------------------------------------ // Reads the structure of the file -void ColladaParser::ReadStructure() -{ - while (mReader->read()) - { +void ColladaParser::ReadStructure() { + while (mReader->read()) { // beginning of elements - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { if (IsElement("asset")) ReadAssetInfo(); else if (IsElement("library_animations")) @@ -354,9 +327,7 @@ void ColladaParser::ReadStructure() ReadScene(); else SkipElement(); - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { break; } } @@ -367,34 +338,27 @@ void ColladaParser::ReadStructure() // ------------------------------------------------------------------------------------------------ // Reads asset information such as coordinate system information and legal blah -void ColladaParser::ReadAssetInfo() -{ +void ColladaParser::ReadAssetInfo() { if (mReader->isEmptyElement()) return; - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { - if (IsElement("unit")) - { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("unit")) { // read unit data from the element's attributes const int attrIndex = TestAttribute("meter"); if (attrIndex == -1) { mUnitSize = 1.f; - } - else { + } else { mUnitSize = mReader->getAttributeValueAsFloat(attrIndex); } // consume the trailing stuff if (!mReader->isEmptyElement()) SkipElement(); - } - else if (IsElement("up_axis")) - { + } else if (IsElement("up_axis")) { // read content, strip whitespace, compare - const char* content = GetTextContent(); + const char *content = GetTextContent(); if (strncmp(content, "X_UP", 4) == 0) mUpDirection = UP_X; else if (strncmp(content, "Z_UP", 4) == 0) @@ -404,18 +368,12 @@ void ColladaParser::ReadAssetInfo() // check element end TestClosing("up_axis"); - } - else if (IsElement("contributor")) - { + } else if (IsElement("contributor")) { ReadContributorInfo(); - } - else - { + } else { ReadMetaDataItem(mAssetMetaData); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "asset") != 0) ThrowException("Expected end of element."); @@ -426,19 +384,14 @@ void ColladaParser::ReadAssetInfo() // ------------------------------------------------------------------------------------------------ // Reads the contributor info -void ColladaParser::ReadContributorInfo() -{ +void ColladaParser::ReadContributorInfo() { if (mReader->isEmptyElement()) return; - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { ReadMetaDataItem(mAssetMetaData); - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "contributor") != 0) ThrowException("Expected end of element."); break; @@ -448,11 +401,11 @@ void ColladaParser::ReadContributorInfo() static bool FindCommonKey(const std::string &collada_key, const MetaKeyPairVector &key_renaming, size_t &found_index) { for (size_t i = 0; i < key_renaming.size(); ++i) { - if (key_renaming[i].first == collada_key) { + if (key_renaming[i].first == collada_key) { found_index = i; return true; - } - } + } + } found_index = std::numeric_limits::max(); return false; } @@ -461,44 +414,39 @@ static bool FindCommonKey(const std::string &collada_key, const MetaKeyPairVecto // Reads a single string metadata item void ColladaParser::ReadMetaDataItem(StringMetaData &metadata) { const Collada::MetaKeyPairVector &key_renaming = GetColladaAssimpMetaKeysCamelCase(); - // Metadata such as created, keywords, subject etc - const char *key_char = mReader->getNodeName(); - if (key_char != nullptr) { + // Metadata such as created, keywords, subject etc + const char *key_char = mReader->getNodeName(); + if (key_char != nullptr) { const std::string key_str(key_char); - const char *value_char = TestTextContent(); - if (value_char != nullptr) { + const char *value_char = TestTextContent(); + if (value_char != nullptr) { aiString aistr; - aistr.Set(value_char); + aistr.Set(value_char); std::string camel_key_str(key_str); - ToCamelCase(camel_key_str); + ToCamelCase(camel_key_str); - size_t found_index; - if (FindCommonKey(camel_key_str, key_renaming, found_index)) { + size_t found_index; + if (FindCommonKey(camel_key_str, key_renaming, found_index)) { metadata.emplace(key_renaming[found_index].second, aistr); } else { - metadata.emplace(camel_key_str, aistr); - } + metadata.emplace(camel_key_str, aistr); + } } TestClosing(key_str.c_str()); - } - else + } else SkipElement(); } // ------------------------------------------------------------------------------------------------ // Reads the animation clips -void ColladaParser::ReadAnimationClipLibrary() -{ +void ColladaParser::ReadAnimationClipLibrary() { if (mReader->isEmptyElement()) return; - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { - if (IsElement("animation_clip")) - { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("animation_clip")) { // optional name given as an attribute std::string animName; int indexName = TestAttribute("name"); @@ -510,20 +458,16 @@ void ColladaParser::ReadAnimationClipLibrary() else animName = std::string("animation_") + to_string(mAnimationClipLibrary.size()); - std::pair > clip; + std::pair> clip; clip.first = animName; - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { - if (IsElement("instance_animation")) - { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("instance_animation")) { int indexUrl = TestAttribute("url"); - if (indexUrl >= 0) - { - const char* url = mReader->getAttributeValue(indexUrl); + if (indexUrl >= 0) { + const char *url = mReader->getAttributeValue(indexUrl); if (url[0] != '#') ThrowException("Unknown reference format"); @@ -531,15 +475,11 @@ void ColladaParser::ReadAnimationClipLibrary() clip.second.push_back(url); } - } - else - { + } else { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "animation_clip") != 0) ThrowException("Expected end of element."); @@ -547,19 +487,14 @@ void ColladaParser::ReadAnimationClipLibrary() } } - if (clip.second.size() > 0) - { + if (clip.second.size() > 0) { mAnimationClipLibrary.push_back(clip); } - } - else - { + } else { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "library_animation_clips") != 0) ThrowException("Expected end of element."); @@ -568,8 +503,7 @@ void ColladaParser::ReadAnimationClipLibrary() } } -void ColladaParser::PostProcessControllers() -{ +void ColladaParser::PostProcessControllers() { std::string meshId; for (ControllerLibrary::iterator it = mControllerLibrary.begin(); it != mControllerLibrary.end(); ++it) { meshId = it->second.mMeshId; @@ -585,14 +519,11 @@ void ColladaParser::PostProcessControllers() // ------------------------------------------------------------------------------------------------ // Re-build animations from animation clip library, if present, otherwise combine single-channel animations -void ColladaParser::PostProcessRootAnimations() -{ - if (mAnimationClipLibrary.size() > 0) - { +void ColladaParser::PostProcessRootAnimations() { + if (mAnimationClipLibrary.size() > 0) { Animation temp; - for (AnimationClipLibrary::iterator it = mAnimationClipLibrary.begin(); it != mAnimationClipLibrary.end(); ++it) - { + for (AnimationClipLibrary::iterator it = mAnimationClipLibrary.begin(); it != mAnimationClipLibrary.end(); ++it) { std::string clipName = it->first; Animation *clip = new Animation(); @@ -600,14 +531,12 @@ void ColladaParser::PostProcessRootAnimations() temp.mSubAnims.push_back(clip); - for (std::vector::iterator a = it->second.begin(); a != it->second.end(); ++a) - { + for (std::vector::iterator a = it->second.begin(); a != it->second.end(); ++a) { std::string animationID = *a; AnimationLibrary::iterator animation = mAnimationLibrary.find(animationID); - if (animation != mAnimationLibrary.end()) - { + if (animation != mAnimationLibrary.end()) { Animation *pSourceAnimation = animation->second; pSourceAnimation->CollectChannelsRecursively(clip->mChannels); @@ -619,37 +548,27 @@ void ColladaParser::PostProcessRootAnimations() // Ensure no double deletes. temp.mSubAnims.clear(); - } - else - { + } else { mAnims.CombineSingleChannelAnimations(); } } // ------------------------------------------------------------------------------------------------ // Reads the animation library -void ColladaParser::ReadAnimationLibrary() -{ +void ColladaParser::ReadAnimationLibrary() { if (mReader->isEmptyElement()) return; - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { - if (IsElement("animation")) - { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("animation")) { // delegate the reading. Depending on the inner elements it will be a container or a anim channel ReadAnimation(&mAnims); - } - else - { + } else { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "library_animations") != 0) ThrowException("Expected end of element."); @@ -660,8 +579,7 @@ void ColladaParser::ReadAnimationLibrary() // ------------------------------------------------------------------------------------------------ // Reads an animation into the given parent structure -void ColladaParser::ReadAnimation(Collada::Animation* pParent) -{ +void ColladaParser::ReadAnimation(Collada::Animation *pParent) { if (mReader->isEmptyElement()) return; @@ -670,7 +588,7 @@ void ColladaParser::ReadAnimation(Collada::Animation* pParent) typedef std::map ChannelMap; ChannelMap channels; // this is the anim container in case we're a container - Animation* anim = NULL; + Animation *anim = NULL; // optional name given as an attribute std::string animName; @@ -688,16 +606,12 @@ void ColladaParser::ReadAnimation(Collada::Animation* pParent) else animName = "animation"; - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { // we have subanimations - if (IsElement("animation")) - { + if (IsElement("animation")) { // create container from our element - if (!anim) - { + if (!anim) { anim = new Animation; anim->mName = animName; pParent->mSubAnims.push_back(anim); @@ -705,14 +619,10 @@ void ColladaParser::ReadAnimation(Collada::Animation* pParent) // recurse into the subelement ReadAnimation(anim); - } - else if (IsElement("source")) - { + } else if (IsElement("source")) { // possible animation data - we'll never know. Better store it ReadSource(); - } - else if (IsElement("sampler")) - { + } else if (IsElement("sampler")) { // read the ID to assign the corresponding collada channel afterwards. int indexId = GetAttribute("id"); std::string id = mReader->getAttributeValue(indexId); @@ -720,15 +630,13 @@ void ColladaParser::ReadAnimation(Collada::Animation* pParent) // have it read into a channel ReadAnimationSampler(newChannel->second); - } - else if (IsElement("channel")) - { + } else if (IsElement("channel")) { // the binding element whose whole purpose is to provide the target to animate // Thanks, Collada! A directly posted information would have been too simple, I guess. // Better add another indirection to that! Can't have enough of those. int indexTarget = GetAttribute("target"); int indexSource = GetAttribute("source"); - const char* sourceId = mReader->getAttributeValue(indexSource); + const char *sourceId = mReader->getAttributeValue(indexSource); if (sourceId[0] == '#') sourceId++; ChannelMap::iterator cit = channels.find(sourceId); @@ -737,15 +645,11 @@ void ColladaParser::ReadAnimation(Collada::Animation* pParent) if (!mReader->isEmptyElement()) SkipElement(); - } - else - { + } else { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "animation") != 0) ThrowException("Expected end of element."); @@ -754,15 +658,14 @@ void ColladaParser::ReadAnimation(Collada::Animation* pParent) } // it turned out to have channels - add them - if (!channels.empty()) - { + if (!channels.empty()) { // FIXME: Is this essentially doing the same as "single-anim-node" codepath in // ColladaLoader::StoreAnimations? For now, this has been deferred to after // all animations and all clips have been read. Due to handling of // this cannot be done here, as the channel owner // is lost, and some exporters make up animations by referring to multiple // single-channel animations from an . -/* + /* // special filtering for stupid exporters packing each channel into a separate animation if( channels.size() == 1) { @@ -771,8 +674,7 @@ void ColladaParser::ReadAnimation(Collada::Animation* pParent) */ { // else create the animation, if not done yet, and store the channels - if (!anim) - { + if (!anim) { anim = new Animation; anim->mName = animName; pParent->mSubAnims.push_back(anim); @@ -780,8 +682,7 @@ void ColladaParser::ReadAnimation(Collada::Animation* pParent) for (ChannelMap::const_iterator it = channels.begin(); it != channels.end(); ++it) anim->mChannels.push_back(it->second); - if (indexID >= 0) - { + if (indexID >= 0) { mAnimationLibrary[animID] = anim; } } @@ -790,18 +691,14 @@ void ColladaParser::ReadAnimation(Collada::Animation* pParent) // ------------------------------------------------------------------------------------------------ // Reads an animation sampler into the given anim channel -void ColladaParser::ReadAnimationSampler(Collada::AnimationChannel& pChannel) -{ - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { - if (IsElement("input")) - { +void ColladaParser::ReadAnimationSampler(Collada::AnimationChannel &pChannel) { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("input")) { int indexSemantic = GetAttribute("semantic"); - const char* semantic = mReader->getAttributeValue(indexSemantic); + const char *semantic = mReader->getAttributeValue(indexSemantic); int indexSource = GetAttribute("source"); - const char* source = mReader->getAttributeValue(indexSource); + const char *source = mReader->getAttributeValue(indexSource); if (source[0] != '#') ThrowException("Unsupported URL format"); source++; @@ -819,15 +716,11 @@ void ColladaParser::ReadAnimationSampler(Collada::AnimationChannel& pChannel) if (!mReader->isEmptyElement()) SkipElement(); - } - else - { + } else { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "sampler") != 0) ThrowException("Expected end of element."); @@ -838,17 +731,13 @@ void ColladaParser::ReadAnimationSampler(Collada::AnimationChannel& pChannel) // ------------------------------------------------------------------------------------------------ // Reads the skeleton controller library -void ColladaParser::ReadControllerLibrary() -{ +void ColladaParser::ReadControllerLibrary() { if (mReader->isEmptyElement()) return; - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { - if (IsElement("controller")) - { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("controller")) { // read ID. Ask the spec if it's necessary or optional... you might be surprised. int attrID = GetAttribute("id"); std::string id = mReader->getAttributeValue(attrID); @@ -858,15 +747,11 @@ void ColladaParser::ReadControllerLibrary() // read on from there ReadController(mControllerLibrary[id]); - } - else - { + } else { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "library_controllers") != 0) ThrowException("Expected end of element."); @@ -877,18 +762,14 @@ void ColladaParser::ReadControllerLibrary() // ------------------------------------------------------------------------------------------------ // Reads a controller into the given mesh structure -void ColladaParser::ReadController(Collada::Controller& pController) -{ +void ColladaParser::ReadController(Collada::Controller &pController) { // initial values pController.mType = Skin; pController.mMethod = Normalized; - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { // two types of controllers: "skin" and "morph". Only the first one is relevant, we skip the other - if (IsElement("morph")) - { + if (IsElement("morph")) { pController.mType = Morph; int baseIndex = GetAttribute("source"); pController.mMeshId = mReader->getAttributeValue(baseIndex) + 1; @@ -898,22 +779,17 @@ void ColladaParser::ReadController(Collada::Controller& pController) if (strcmp(method, "RELATIVE") == 0) pController.mMethod = Relative; } - } - else if (IsElement("skin")) - { + } else if (IsElement("skin")) { // read the mesh it refers to. According to the spec this could also be another // controller, but I refuse to implement every single idea they've come up with int sourceIndex = GetAttribute("source"); pController.mMeshId = mReader->getAttributeValue(sourceIndex) + 1; - } - else if (IsElement("bind_shape_matrix")) - { + } else if (IsElement("bind_shape_matrix")) { // content is 16 floats to define a matrix... it seems to be important for some models - const char* content = GetTextContent(); + const char *content = GetTextContent(); // read the 16 floats - for (unsigned int a = 0; a < 16; a++) - { + for (unsigned int a = 0; a < 16; a++) { // read a number content = fast_atoreal_move(content, pController.mBindShapeMatrix[a]); // skip whitespace after it @@ -921,22 +797,14 @@ void ColladaParser::ReadController(Collada::Controller& pController) } TestClosing("bind_shape_matrix"); - } - else if (IsElement("source")) - { + } else if (IsElement("source")) { // data array - we have specialists to handle this ReadSource(); - } - else if (IsElement("joints")) - { + } else if (IsElement("joints")) { ReadControllerJoints(pController); - } - else if (IsElement("vertex_weights")) - { + } else if (IsElement("vertex_weights")) { ReadControllerWeights(pController); - } - else if (IsElement("targets")) - { + } else if (IsElement("targets")) { while (mReader->read()) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { if (IsElement("input")) { @@ -947,29 +815,22 @@ void ColladaParser::ReadController(Collada::Controller& pController) const char *source = mReader->getAttributeValue(sourceIndex); if (strcmp(semantics, "MORPH_TARGET") == 0) { pController.mMorphTarget = source + 1; - } - else if (strcmp(semantics, "MORPH_WEIGHT") == 0) - { + } else if (strcmp(semantics, "MORPH_WEIGHT") == 0) { pController.mMorphWeight = source + 1; } } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "targets") == 0) break; else ThrowException("Expected end of element."); } } - } - else - { + } else { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "controller") == 0) break; else if (strcmp(mReader->getNodeName(), "skin") != 0 && strcmp(mReader->getNodeName(), "morph") != 0) @@ -980,19 +841,15 @@ void ColladaParser::ReadController(Collada::Controller& pController) // ------------------------------------------------------------------------------------------------ // Reads the joint definitions for the given controller -void ColladaParser::ReadControllerJoints(Collada::Controller& pController) -{ - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { +void ColladaParser::ReadControllerJoints(Collada::Controller &pController) { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { // Input channels for joint data. Two possible semantics: "JOINT" and "INV_BIND_MATRIX" - if (IsElement("input")) - { + if (IsElement("input")) { int indexSemantic = GetAttribute("semantic"); - const char* attrSemantic = mReader->getAttributeValue(indexSemantic); + const char *attrSemantic = mReader->getAttributeValue(indexSemantic); int indexSource = GetAttribute("source"); - const char* attrSource = mReader->getAttributeValue(indexSource); + const char *attrSource = mReader->getAttributeValue(indexSource); // local URLS always start with a '#'. We don't support global URLs if (attrSource[0] != '#') @@ -1010,15 +867,11 @@ void ColladaParser::ReadControllerJoints(Collada::Controller& pController) // skip inner data, if present if (!mReader->isEmptyElement()) SkipElement(); - } - else - { + } else { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "joints") != 0) ThrowException("Expected end of element."); @@ -1029,26 +882,22 @@ void ColladaParser::ReadControllerJoints(Collada::Controller& pController) // ------------------------------------------------------------------------------------------------ // Reads the joint weights for the given controller -void ColladaParser::ReadControllerWeights(Collada::Controller& pController) -{ +void ColladaParser::ReadControllerWeights(Collada::Controller &pController) { // read vertex count from attributes and resize the array accordingly int indexCount = GetAttribute("count"); size_t vertexCount = (size_t)mReader->getAttributeValueAsInt(indexCount); pController.mWeightCounts.resize(vertexCount); - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { // Input channels for weight data. Two possible semantics: "JOINT" and "WEIGHT" - if (IsElement("input") && vertexCount > 0) - { + if (IsElement("input") && vertexCount > 0) { InputChannel channel; int indexSemantic = GetAttribute("semantic"); - const char* attrSemantic = mReader->getAttributeValue(indexSemantic); + const char *attrSemantic = mReader->getAttributeValue(indexSemantic); int indexSource = GetAttribute("source"); - const char* attrSource = mReader->getAttributeValue(indexSource); + const char *attrSource = mReader->getAttributeValue(indexSource); int indexOffset = TestAttribute("offset"); if (indexOffset >= 0) channel.mOffset = mReader->getAttributeValueAsInt(indexOffset); @@ -1069,14 +918,11 @@ void ColladaParser::ReadControllerWeights(Collada::Controller& pController) // skip inner data, if present if (!mReader->isEmptyElement()) SkipElement(); - } - else if (IsElement("vcount") && vertexCount > 0) - { + } else if (IsElement("vcount") && vertexCount > 0) { // read weight count per vertex - const char* text = GetTextContent(); + const char *text = GetTextContent(); size_t numWeights = 0; - for (std::vector::iterator it = pController.mWeightCounts.begin(); it != pController.mWeightCounts.end(); ++it) - { + for (std::vector::iterator it = pController.mWeightCounts.begin(); it != pController.mWeightCounts.end(); ++it) { if (*text == 0) ThrowException("Out of data while reading "); @@ -1089,14 +935,11 @@ void ColladaParser::ReadControllerWeights(Collada::Controller& pController) // reserve weight count pController.mWeights.resize(numWeights); - } - else if (IsElement("v") && vertexCount > 0) - { + } else if (IsElement("v") && vertexCount > 0) { // read JointIndex - WeightIndex pairs - const char* text = GetTextContent(); + const char *text = GetTextContent(); - for (std::vector< std::pair >::iterator it = pController.mWeights.begin(); it != pController.mWeights.end(); ++it) - { + for (std::vector>::iterator it = pController.mWeights.begin(); it != pController.mWeights.end(); ++it) { if (*text == 0) ThrowException("Out of data while reading "); it->first = strtoul10(text, &text); @@ -1108,15 +951,11 @@ void ColladaParser::ReadControllerWeights(Collada::Controller& pController) } TestClosing("v"); - } - else - { + } else { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "vertex_weights") != 0) ThrowException("Expected end of element."); @@ -1127,16 +966,13 @@ void ColladaParser::ReadControllerWeights(Collada::Controller& pController) // ------------------------------------------------------------------------------------------------ // Reads the image library contents -void ColladaParser::ReadImageLibrary() -{ +void ColladaParser::ReadImageLibrary() { if (mReader->isEmptyElement()) return; - while (mReader->read()) - { + while (mReader->read()) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if (IsElement("image")) - { + if (IsElement("image")) { // read ID. Another entry which is "optional" by design but obligatory in reality int attrID = GetAttribute("id"); std::string id = mReader->getAttributeValue(attrID); @@ -1146,14 +982,11 @@ void ColladaParser::ReadImageLibrary() // read on from there ReadImage(mImageLibrary[id]); - } - else - { + } else { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "library_images") != 0) ThrowException("Expected end of element."); @@ -1164,25 +997,19 @@ void ColladaParser::ReadImageLibrary() // ------------------------------------------------------------------------------------------------ // Reads an image entry into the given image -void ColladaParser::ReadImage(Collada::Image& pImage) -{ - while (mReader->read()) - { +void ColladaParser::ReadImage(Collada::Image &pImage) { + while (mReader->read()) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { // Need to run different code paths here, depending on the Collada XSD version if (IsElement("image")) { SkipElement(); - } - else if (IsElement("init_from")) - { - if (mFormat == FV_1_4_n) - { + } else if (IsElement("init_from")) { + if (mFormat == FV_1_4_n) { // FIX: C4D exporter writes empty tags if (!mReader->isEmptyElement()) { // element content is filename - hopefully - const char* sz = TestTextContent(); - if (sz) - { + const char *sz = TestTextContent(); + if (sz) { aiString filepath(sz); UriDecodePath(filepath); pImage.mFileName = filepath.C_Str(); @@ -1192,9 +1019,7 @@ void ColladaParser::ReadImage(Collada::Image& pImage) if (!pImage.mFileName.length()) { pImage.mFileName = "unknown_texture"; } - } - else if (mFormat == FV_1_5_n) - { + } else if (mFormat == FV_1_5_n) { // make sure we skip over mip and array initializations, which // we don't support, but which could confuse the loader if // they're not skipped. @@ -1212,35 +1037,31 @@ void ColladaParser::ReadImage(Collada::Image& pImage) // TODO: correctly jump over cube and volume maps? } - } - else if (mFormat == FV_1_5_n) - { - if (IsElement("ref")) - { + } else if (mFormat == FV_1_5_n) { + if (IsElement("ref")) { // element content is filename - hopefully - const char* sz = TestTextContent(); - if (sz) - { + const char *sz = TestTextContent(); + if (sz) { aiString filepath(sz); UriDecodePath(filepath); pImage.mFileName = filepath.C_Str(); } TestClosing("ref"); - } - else if (IsElement("hex") && !pImage.mFileName.length()) - { + } else if (IsElement("hex") && !pImage.mFileName.length()) { // embedded image. get format const int attrib = TestAttribute("format"); if (-1 == attrib) ASSIMP_LOG_WARN("Collada: Unknown image file format"); - else pImage.mEmbeddedFormat = mReader->getAttributeValue(attrib); + else + pImage.mEmbeddedFormat = mReader->getAttributeValue(attrib); - const char* data = GetTextContent(); + const char *data = GetTextContent(); // hexadecimal-encoded binary octets. First of all, find the // required buffer size to reserve enough storage. - const char* cur = data; - while (!IsSpaceOrNewLine(*cur)) cur++; + const char *cur = data; + while (!IsSpaceOrNewLine(*cur)) + cur++; const unsigned int size = (unsigned int)(cur - data) * 2; pImage.mImageData.resize(size); @@ -1249,14 +1070,11 @@ void ColladaParser::ReadImage(Collada::Image& pImage) TestClosing("hex"); } - } - else - { + } else { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "image") == 0) break; } @@ -1265,18 +1083,14 @@ void ColladaParser::ReadImage(Collada::Image& pImage) // ------------------------------------------------------------------------------------------------ // Reads the material library -void ColladaParser::ReadMaterialLibrary() -{ +void ColladaParser::ReadMaterialLibrary() { if (mReader->isEmptyElement()) return; std::map names; - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { - if (IsElement("material")) - { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("material")) { // read ID. By now you probably know my opinion about this "specification" int attrID = GetAttribute("id"); std::string id = mReader->getAttributeValue(attrID); @@ -1289,17 +1103,13 @@ void ColladaParser::ReadMaterialLibrary() // create an entry and store it in the library under its ID mMaterialLibrary[id] = Material(); - if (!name.empty()) - { + if (!name.empty()) { std::map::iterator it = names.find(name); - if (it != names.end()) - { + if (it != names.end()) { std::ostringstream strStream; strStream << ++it->second; name.append(" " + strStream.str()); - } - else - { + } else { names[name] = 0; } @@ -1307,15 +1117,11 @@ void ColladaParser::ReadMaterialLibrary() } ReadMaterial(mMaterialLibrary[id]); - } - else - { + } else { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "library_materials") != 0) ThrowException("Expected end of element."); @@ -1326,16 +1132,13 @@ void ColladaParser::ReadMaterialLibrary() // ------------------------------------------------------------------------------------------------ // Reads the light library -void ColladaParser::ReadLightLibrary() -{ +void ColladaParser::ReadLightLibrary() { if (mReader->isEmptyElement()) return; - while (mReader->read()) - { + while (mReader->read()) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if (IsElement("light")) - { + if (IsElement("light")) { // read ID. By now you probably know my opinion about this "specification" int attrID = GetAttribute("id"); std::string id = mReader->getAttributeValue(attrID); @@ -1343,14 +1146,11 @@ void ColladaParser::ReadLightLibrary() // create an entry and store it in the library under its ID ReadLight(mLightLibrary[id] = Light()); - } - else - { + } else { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "library_lights") != 0) ThrowException("Expected end of element."); @@ -1361,36 +1161,30 @@ void ColladaParser::ReadLightLibrary() // ------------------------------------------------------------------------------------------------ // Reads the camera library -void ColladaParser::ReadCameraLibrary() -{ +void ColladaParser::ReadCameraLibrary() { if (mReader->isEmptyElement()) return; - while (mReader->read()) - { + while (mReader->read()) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if (IsElement("camera")) - { + if (IsElement("camera")) { // read ID. By now you probably know my opinion about this "specification" int attrID = GetAttribute("id"); std::string id = mReader->getAttributeValue(attrID); // create an entry and store it in the library under its ID - Camera& cam = mCameraLibrary[id]; + Camera &cam = mCameraLibrary[id]; attrID = TestAttribute("name"); if (attrID != -1) cam.mName = mReader->getAttributeValue(attrID); ReadCamera(cam); - } - else - { + } else { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "library_cameras") != 0) ThrowException("Expected end of element."); @@ -1401,33 +1195,26 @@ void ColladaParser::ReadCameraLibrary() // ------------------------------------------------------------------------------------------------ // Reads a material entry into the given material -void ColladaParser::ReadMaterial(Collada::Material& pMaterial) -{ - while (mReader->read()) - { +void ColladaParser::ReadMaterial(Collada::Material &pMaterial) { + while (mReader->read()) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { if (IsElement("material")) { SkipElement(); - } - else if (IsElement("instance_effect")) - { + } else if (IsElement("instance_effect")) { // referred effect by URL int attrUrl = GetAttribute("url"); - const char* url = mReader->getAttributeValue(attrUrl); + const char *url = mReader->getAttributeValue(attrUrl); if (url[0] != '#') ThrowException("Unknown reference format"); pMaterial.mEffect = url + 1; SkipElement(); - } - else - { + } else { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "material") != 0) ThrowException("Expected end of element."); @@ -1438,58 +1225,46 @@ void ColladaParser::ReadMaterial(Collada::Material& pMaterial) // ------------------------------------------------------------------------------------------------ // Reads a light entry into the given light -void ColladaParser::ReadLight(Collada::Light& pLight) -{ - while (mReader->read()) - { +void ColladaParser::ReadLight(Collada::Light &pLight) { + while (mReader->read()) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { if (IsElement("light")) { SkipElement(); - } - else if (IsElement("spot")) { + } else if (IsElement("spot")) { pLight.mType = aiLightSource_SPOT; - } - else if (IsElement("ambient")) { + } else if (IsElement("ambient")) { pLight.mType = aiLightSource_AMBIENT; - } - else if (IsElement("directional")) { + } else if (IsElement("directional")) { pLight.mType = aiLightSource_DIRECTIONAL; - } - else if (IsElement("point")) { + } else if (IsElement("point")) { pLight.mType = aiLightSource_POINT; - } - else if (IsElement("color")) { + } else if (IsElement("color")) { // text content contains 3 floats - const char* content = GetTextContent(); + const char *content = GetTextContent(); - content = fast_atoreal_move(content, (ai_real&)pLight.mColor.r); + content = fast_atoreal_move(content, (ai_real &)pLight.mColor.r); SkipSpacesAndLineEnd(&content); - content = fast_atoreal_move(content, (ai_real&)pLight.mColor.g); + content = fast_atoreal_move(content, (ai_real &)pLight.mColor.g); SkipSpacesAndLineEnd(&content); - content = fast_atoreal_move(content, (ai_real&)pLight.mColor.b); + content = fast_atoreal_move(content, (ai_real &)pLight.mColor.b); SkipSpacesAndLineEnd(&content); TestClosing("color"); - } - else if (IsElement("constant_attenuation")) { + } else if (IsElement("constant_attenuation")) { pLight.mAttConstant = ReadFloatFromTextContent(); TestClosing("constant_attenuation"); - } - else if (IsElement("linear_attenuation")) { + } else if (IsElement("linear_attenuation")) { pLight.mAttLinear = ReadFloatFromTextContent(); TestClosing("linear_attenuation"); - } - else if (IsElement("quadratic_attenuation")) { + } else if (IsElement("quadratic_attenuation")) { pLight.mAttQuadratic = ReadFloatFromTextContent(); TestClosing("quadratic_attenuation"); - } - else if (IsElement("falloff_angle")) { + } else if (IsElement("falloff_angle")) { pLight.mFalloffAngle = ReadFloatFromTextContent(); TestClosing("falloff_angle"); - } - else if (IsElement("falloff_exponent")) { + } else if (IsElement("falloff_exponent")) { pLight.mFalloffExponent = ReadFloatFromTextContent(); TestClosing("falloff_exponent"); } @@ -1503,16 +1278,13 @@ void ColladaParser::ReadLight(Collada::Light& pLight) else if (IsElement("penumbra_angle")) { pLight.mPenumbraAngle = ReadFloatFromTextContent(); TestClosing("penumbra_angle"); - } - else if (IsElement("intensity")) { + } else if (IsElement("intensity")) { pLight.mIntensity = ReadFloatFromTextContent(); TestClosing("intensity"); - } - else if (IsElement("falloff")) { + } else if (IsElement("falloff")) { pLight.mOuterAngle = ReadFloatFromTextContent(); TestClosing("falloff"); - } - else if (IsElement("hotspot_beam")) { + } else if (IsElement("hotspot_beam")) { pLight.mFalloffAngle = ReadFloatFromTextContent(); TestClosing("hotspot_beam"); } @@ -1522,8 +1294,7 @@ void ColladaParser::ReadLight(Collada::Light& pLight) pLight.mOuterAngle = ReadFloatFromTextContent(); TestClosing("decay_falloff"); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "light") == 0) break; } @@ -1532,39 +1303,30 @@ void ColladaParser::ReadLight(Collada::Light& pLight) // ------------------------------------------------------------------------------------------------ // Reads a camera entry into the given light -void ColladaParser::ReadCamera(Collada::Camera& pCamera) -{ - while (mReader->read()) - { +void ColladaParser::ReadCamera(Collada::Camera &pCamera) { + while (mReader->read()) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { if (IsElement("camera")) { SkipElement(); - } - else if (IsElement("orthographic")) { + } else if (IsElement("orthographic")) { pCamera.mOrtho = true; - } - else if (IsElement("xfov") || IsElement("xmag")) { + } else if (IsElement("xfov") || IsElement("xmag")) { pCamera.mHorFov = ReadFloatFromTextContent(); TestClosing((pCamera.mOrtho ? "xmag" : "xfov")); - } - else if (IsElement("yfov") || IsElement("ymag")) { + } else if (IsElement("yfov") || IsElement("ymag")) { pCamera.mVerFov = ReadFloatFromTextContent(); TestClosing((pCamera.mOrtho ? "ymag" : "yfov")); - } - else if (IsElement("aspect_ratio")) { + } else if (IsElement("aspect_ratio")) { pCamera.mAspect = ReadFloatFromTextContent(); TestClosing("aspect_ratio"); - } - else if (IsElement("znear")) { + } else if (IsElement("znear")) { pCamera.mZNear = ReadFloatFromTextContent(); TestClosing("znear"); - } - else if (IsElement("zfar")) { + } else if (IsElement("zfar")) { pCamera.mZFar = ReadFloatFromTextContent(); TestClosing("zfar"); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "camera") == 0) break; } @@ -1573,17 +1335,14 @@ void ColladaParser::ReadCamera(Collada::Camera& pCamera) // ------------------------------------------------------------------------------------------------ // Reads the effect library -void ColladaParser::ReadEffectLibrary() -{ +void ColladaParser::ReadEffectLibrary() { if (mReader->isEmptyElement()) { return; } - while (mReader->read()) - { + while (mReader->read()) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if (IsElement("effect")) - { + if (IsElement("effect")) { // read ID. Do I have to repeat my ranting about "optional" attributes? int attrID = GetAttribute("id"); std::string id = mReader->getAttributeValue(attrID); @@ -1592,14 +1351,11 @@ void ColladaParser::ReadEffectLibrary() mEffectLibrary[id] = Effect(); // read on from there ReadEffect(mEffectLibrary[id]); - } - else - { + } else { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "library_effects") != 0) ThrowException("Expected end of element."); @@ -1610,20 +1366,15 @@ void ColladaParser::ReadEffectLibrary() // ------------------------------------------------------------------------------------------------ // Reads an effect entry into the given effect -void ColladaParser::ReadEffect(Collada::Effect& pEffect) -{ +void ColladaParser::ReadEffect(Collada::Effect &pEffect) { // for the moment we don't support any other type of effect. - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { if (IsElement("profile_COMMON")) ReadEffectProfileCommon(pEffect); else SkipElement(); - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "effect") != 0) ThrowException("Expected end of element."); @@ -1634,26 +1385,20 @@ void ColladaParser::ReadEffect(Collada::Effect& pEffect) // ------------------------------------------------------------------------------------------------ // Reads an COMMON effect profile -void ColladaParser::ReadEffectProfileCommon(Collada::Effect& pEffect) -{ - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { +void ColladaParser::ReadEffectProfileCommon(Collada::Effect &pEffect) { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { if (IsElement("newparam")) { // save ID int attrSID = GetAttribute("sid"); std::string sid = mReader->getAttributeValue(attrSID); pEffect.mParams[sid] = EffectParam(); ReadEffectParam(pEffect.mParams[sid]); - } - else if (IsElement("technique") || IsElement("extra")) - { + } else if (IsElement("technique") || IsElement("extra")) { // just syntactic sugar } - else if (mFormat == FV_1_4_n && IsElement("image")) - { + else if (mFormat == FV_1_4_n && IsElement("image")) { // read ID. Another entry which is "optional" by design but obligatory in reality int attrID = GetAttribute("id"); std::string id = mReader->getAttributeValue(attrID); @@ -1686,11 +1431,10 @@ void ColladaParser::ReadEffectProfileCommon(Collada::Effect& pEffect) ReadEffectColor(pEffect.mSpecular, pEffect.mTexSpecular); else if (IsElement("reflective")) { ReadEffectColor(pEffect.mReflective, pEffect.mTexReflective); - } - else if (IsElement("transparent")) { + } else if (IsElement("transparent")) { pEffect.mHasTransparency = true; - const char* opaque = mReader->getAttributeValueSafe("opaque"); + const char *opaque = mReader->getAttributeValueSafe("opaque"); if (::strcmp(opaque, "RGB_ZERO") == 0 || ::strcmp(opaque, "RGB_ONE") == 0) { pEffect.mRGBTransparency = true; @@ -1702,8 +1446,7 @@ void ColladaParser::ReadEffectProfileCommon(Collada::Effect& pEffect) } ReadEffectColor(pEffect.mTransparent, pEffect.mTexTransparent); - } - else if (IsElement("shininess")) + } else if (IsElement("shininess")) ReadEffectFloat(pEffect.mShininess); else if (IsElement("reflectivity")) ReadEffectFloat(pEffect.mReflectivity); @@ -1731,20 +1474,15 @@ void ColladaParser::ReadEffectProfileCommon(Collada::Effect& pEffect) else if (IsElement("wireframe")) { pEffect.mWireframe = ReadBoolFromTextContent(); TestClosing("wireframe"); - } - else if (IsElement("faceted")) { + } else if (IsElement("faceted")) { pEffect.mFaceted = ReadBoolFromTextContent(); TestClosing("faceted"); - } - else - { + } else { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if (strcmp(mReader->getNodeName(), "profile_COMMON") == 0) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + if (strcmp(mReader->getNodeName(), "profile_COMMON") == 0) { break; } } @@ -1753,14 +1491,12 @@ void ColladaParser::ReadEffectProfileCommon(Collada::Effect& pEffect) // ------------------------------------------------------------------------------------------------ // Read texture wrapping + UV transform settings from a profile==Maya chunk -void ColladaParser::ReadSamplerProperties(Sampler& out) -{ +void ColladaParser::ReadSamplerProperties(Sampler &out) { if (mReader->isEmptyElement()) { return; } - while (mReader->read()) - { + while (mReader->read()) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { // MAYA extensions @@ -1768,42 +1504,33 @@ void ColladaParser::ReadSamplerProperties(Sampler& out) if (IsElement("wrapU")) { out.mWrapU = ReadBoolFromTextContent(); TestClosing("wrapU"); - } - else if (IsElement("wrapV")) { + } else if (IsElement("wrapV")) { out.mWrapV = ReadBoolFromTextContent(); TestClosing("wrapV"); - } - else if (IsElement("mirrorU")) { + } else if (IsElement("mirrorU")) { out.mMirrorU = ReadBoolFromTextContent(); TestClosing("mirrorU"); - } - else if (IsElement("mirrorV")) { + } else if (IsElement("mirrorV")) { out.mMirrorV = ReadBoolFromTextContent(); TestClosing("mirrorV"); - } - else if (IsElement("repeatU")) { + } else if (IsElement("repeatU")) { out.mTransform.mScaling.x = ReadFloatFromTextContent(); TestClosing("repeatU"); - } - else if (IsElement("repeatV")) { + } else if (IsElement("repeatV")) { out.mTransform.mScaling.y = ReadFloatFromTextContent(); TestClosing("repeatV"); - } - else if (IsElement("offsetU")) { + } else if (IsElement("offsetU")) { out.mTransform.mTranslation.x = ReadFloatFromTextContent(); TestClosing("offsetU"); - } - else if (IsElement("offsetV")) { + } else if (IsElement("offsetV")) { out.mTransform.mTranslation.y = ReadFloatFromTextContent(); TestClosing("offsetV"); - } - else if (IsElement("rotateUV")) { + } else if (IsElement("rotateUV")) { out.mTransform.mRotation = ReadFloatFromTextContent(); TestClosing("rotateUV"); - } - else if (IsElement("blend_mode")) { + } else if (IsElement("blend_mode")) { - const char* sz = GetTextContent(); + const char *sz = GetTextContent(); // http://www.feelingsoftware.com/content/view/55/72/lang,en/ // NONE, OVER, IN, OUT, ADD, SUBTRACT, MULTIPLY, DIFFERENCE, LIGHTEN, DARKEN, SATURATE, DESATURATE and ILLUMINATE if (0 == ASSIMP_strincmp(sz, "ADD", 3)) @@ -1825,8 +1552,7 @@ void ColladaParser::ReadSamplerProperties(Sampler& out) else if (IsElement("weighting")) { out.mWeighting = ReadFloatFromTextContent(); TestClosing("weighting"); - } - else if (IsElement("mix_with_previous_layer")) { + } else if (IsElement("mix_with_previous_layer")) { out.mMixWithPrevious = ReadFloatFromTextContent(); TestClosing("mix_with_previous_layer"); } @@ -1836,8 +1562,7 @@ void ColladaParser::ReadSamplerProperties(Sampler& out) out.mWeighting = ReadFloatFromTextContent(); TestClosing("amount"); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "technique") == 0) break; } @@ -1846,37 +1571,32 @@ void ColladaParser::ReadSamplerProperties(Sampler& out) // ------------------------------------------------------------------------------------------------ // Reads an effect entry containing a color or a texture defining that color -void ColladaParser::ReadEffectColor(aiColor4D& pColor, Sampler& pSampler) -{ +void ColladaParser::ReadEffectColor(aiColor4D &pColor, Sampler &pSampler) { if (mReader->isEmptyElement()) return; // Save current element name const std::string curElem = mReader->getNodeName(); - while (mReader->read()) - { + while (mReader->read()) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if (IsElement("color")) - { + if (IsElement("color")) { // text content contains 4 floats - const char* content = GetTextContent(); + const char *content = GetTextContent(); - content = fast_atoreal_move(content, (ai_real&)pColor.r); + content = fast_atoreal_move(content, (ai_real &)pColor.r); SkipSpacesAndLineEnd(&content); - content = fast_atoreal_move(content, (ai_real&)pColor.g); + content = fast_atoreal_move(content, (ai_real &)pColor.g); SkipSpacesAndLineEnd(&content); - content = fast_atoreal_move(content, (ai_real&)pColor.b); + content = fast_atoreal_move(content, (ai_real &)pColor.b); SkipSpacesAndLineEnd(&content); - content = fast_atoreal_move(content, (ai_real&)pColor.a); + content = fast_atoreal_move(content, (ai_real &)pColor.a); SkipSpacesAndLineEnd(&content); TestClosing("color"); - } - else if (IsElement("texture")) - { + } else if (IsElement("texture")) { // get name of source texture/sampler int attrTex = GetAttribute("texture"); pSampler.mName = mReader->getAttributeValue(attrTex); @@ -1890,28 +1610,22 @@ void ColladaParser::ReadEffectColor(aiColor4D& pColor, Sampler& pSampler) // as we've read texture, the color needs to be 1,1,1,1 pColor = aiColor4D(1.f, 1.f, 1.f, 1.f); - } - else if (IsElement("technique")) - { + } else if (IsElement("technique")) { const int _profile = GetAttribute("profile"); - const char* profile = mReader->getAttributeValue(_profile); + const char *profile = mReader->getAttributeValue(_profile); // Some extensions are quite useful ... ReadSamplerProperties processes // several extensions in MAYA, OKINO and MAX3D profiles. - if (!::strcmp(profile, "MAYA") || !::strcmp(profile, "MAX3D") || !::strcmp(profile, "OKINO")) - { + if (!::strcmp(profile, "MAYA") || !::strcmp(profile, "MAX3D") || !::strcmp(profile, "OKINO")) { // get more information on this sampler ReadSamplerProperties(pSampler); - } - else SkipElement(); - } - else if (!IsElement("extra")) - { + } else + SkipElement(); + } else if (!IsElement("extra")) { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (mReader->getNodeName() == curElem) break; } @@ -1920,27 +1634,21 @@ void ColladaParser::ReadEffectColor(aiColor4D& pColor, Sampler& pSampler) // ------------------------------------------------------------------------------------------------ // Reads an effect entry containing a float -void ColladaParser::ReadEffectFloat(ai_real& pFloat) -{ - while (mReader->read()) - { +void ColladaParser::ReadEffectFloat(ai_real &pFloat) { + while (mReader->read()) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if (IsElement("float")) - { + if (IsElement("float")) { // text content contains a single floats - const char* content = GetTextContent(); + const char *content = GetTextContent(); content = fast_atoreal_move(content, pFloat); SkipSpacesAndLineEnd(&content); TestClosing("float"); - } - else - { + } else { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { break; } } @@ -1948,55 +1656,45 @@ void ColladaParser::ReadEffectFloat(ai_real& pFloat) // ------------------------------------------------------------------------------------------------ // Reads an effect parameter specification of any kind -void ColladaParser::ReadEffectParam(Collada::EffectParam& pParam) -{ - while (mReader->read()) - { +void ColladaParser::ReadEffectParam(Collada::EffectParam &pParam) { + while (mReader->read()) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if (IsElement("surface")) - { + if (IsElement("surface")) { // image ID given inside tags TestOpening("init_from"); - const char* content = GetTextContent(); + const char *content = GetTextContent(); pParam.mType = Param_Surface; pParam.mReference = content; TestClosing("init_from"); // don't care for remaining stuff SkipElement("surface"); - } - else if (IsElement("sampler2D") && (FV_1_4_n == mFormat || FV_1_3_n == mFormat)) - { + } else if (IsElement("sampler2D") && (FV_1_4_n == mFormat || FV_1_3_n == mFormat)) { // surface ID is given inside tags TestOpening("source"); - const char* content = GetTextContent(); + const char *content = GetTextContent(); pParam.mType = Param_Sampler; pParam.mReference = content; TestClosing("source"); // don't care for remaining stuff SkipElement("sampler2D"); - } - else if (IsElement("sampler2D")) - { + } else if (IsElement("sampler2D")) { // surface ID is given inside tags TestOpening("instance_image"); int attrURL = GetAttribute("url"); - const char* url = mReader->getAttributeValue(attrURL); + const char *url = mReader->getAttributeValue(attrURL); if (url[0] != '#') ThrowException("Unsupported URL format in instance_image"); url++; pParam.mType = Param_Sampler; pParam.mReference = url; SkipElement("sampler2D"); - } - else - { + } else { // ignore unknown element SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { break; } } @@ -2004,17 +1702,13 @@ void ColladaParser::ReadEffectParam(Collada::EffectParam& pParam) // ------------------------------------------------------------------------------------------------ // Reads the geometry library contents -void ColladaParser::ReadGeometryLibrary() -{ +void ColladaParser::ReadGeometryLibrary() { if (mReader->isEmptyElement()) return; - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { - if (IsElement("geometry")) - { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("geometry")) { // read ID. Another entry which is "optional" by design but obligatory in reality int indexID = GetAttribute("id"); std::string id = mReader->getAttributeValue(indexID); @@ -2023,27 +1717,22 @@ void ColladaParser::ReadGeometryLibrary() // ai_assert( TestAttribute( "sid") == -1); // create a mesh and store it in the library under its ID - Mesh* mesh = new Mesh; + Mesh *mesh = new Mesh; mMeshLibrary[id] = mesh; // read the mesh name if it exists const int nameIndex = TestAttribute("name"); - if (nameIndex != -1) - { + if (nameIndex != -1) { mesh->mName = mReader->getAttributeValue(nameIndex); } // read on from there ReadGeometry(mesh); - } - else - { + } else { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "library_geometries") != 0) ThrowException("Expected end of element."); @@ -2054,28 +1743,20 @@ void ColladaParser::ReadGeometryLibrary() // ------------------------------------------------------------------------------------------------ // Reads a geometry from the geometry library. -void ColladaParser::ReadGeometry(Collada::Mesh* pMesh) -{ +void ColladaParser::ReadGeometry(Collada::Mesh *pMesh) { if (mReader->isEmptyElement()) return; - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { - if (IsElement("mesh")) - { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("mesh")) { // read on from there ReadMesh(pMesh); - } - else - { + } else { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "geometry") != 0) ThrowException("Expected end of element."); @@ -2086,50 +1767,32 @@ void ColladaParser::ReadGeometry(Collada::Mesh* pMesh) // ------------------------------------------------------------------------------------------------ // Reads a mesh from the geometry library -void ColladaParser::ReadMesh(Mesh* pMesh) -{ +void ColladaParser::ReadMesh(Mesh *pMesh) { if (mReader->isEmptyElement()) return; - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { - if (IsElement("source")) - { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("source")) { // we have professionals dealing with this ReadSource(); - } - else if (IsElement("vertices")) - { + } else if (IsElement("vertices")) { // read per-vertex mesh data ReadVertexData(pMesh); - } - else if (IsElement("triangles") || IsElement("lines") || IsElement("linestrips") - || IsElement("polygons") || IsElement("polylist") || IsElement("trifans") || IsElement("tristrips")) - { + } else if (IsElement("triangles") || IsElement("lines") || IsElement("linestrips") || IsElement("polygons") || IsElement("polylist") || IsElement("trifans") || IsElement("tristrips")) { // read per-index mesh data and faces setup ReadIndexData(pMesh); - } - else - { + } else { // ignore the restf SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { - if (strcmp(mReader->getNodeName(), "technique_common") == 0) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + if (strcmp(mReader->getNodeName(), "technique_common") == 0) { // end of another meaningless element - read over it - } - else if (strcmp(mReader->getNodeName(), "mesh") == 0) - { + } else if (strcmp(mReader->getNodeName(), "mesh") == 0) { // end of element - we're done here break; - } - else - { + } else { // everything else should be punished ThrowException("Expected end of element."); } @@ -2139,46 +1802,29 @@ void ColladaParser::ReadMesh(Mesh* pMesh) // ------------------------------------------------------------------------------------------------ // Reads a source element -void ColladaParser::ReadSource() -{ +void ColladaParser::ReadSource() { int indexID = GetAttribute("id"); std::string sourceID = mReader->getAttributeValue(indexID); - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { - if (IsElement("float_array") || IsElement("IDREF_array") || IsElement("Name_array")) - { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("float_array") || IsElement("IDREF_array") || IsElement("Name_array")) { ReadDataArray(); - } - else if (IsElement("technique_common")) - { + } else if (IsElement("technique_common")) { // I don't care for your profiles - } - else if (IsElement("accessor")) - { + } else if (IsElement("accessor")) { ReadAccessor(sourceID); - } - else - { + } else { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { - if (strcmp(mReader->getNodeName(), "source") == 0) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + if (strcmp(mReader->getNodeName(), "source") == 0) { // end of - we're done break; - } - else if (strcmp(mReader->getNodeName(), "technique_common") == 0) - { + } else if (strcmp(mReader->getNodeName(), "technique_common") == 0) { // end of another meaningless element - read over it - } - else - { + } else { // everything else should be punished ThrowException("Expected end of element."); } @@ -2188,8 +1834,7 @@ void ColladaParser::ReadSource() // ------------------------------------------------------------------------------------------------ // Reads a data array holding a number of floats, and stores it in the global library -void ColladaParser::ReadDataArray() -{ +void ColladaParser::ReadDataArray() { std::string elmName = mReader->getNodeName(); bool isStringArray = (elmName == "IDREF_array" || elmName == "Name_array"); bool isEmptyElement = mReader->isEmptyElement(); @@ -2199,23 +1844,20 @@ void ColladaParser::ReadDataArray() std::string id = mReader->getAttributeValue(indexID); int indexCount = GetAttribute("count"); unsigned int count = (unsigned int)mReader->getAttributeValueAsInt(indexCount); - const char* content = TestTextContent(); + const char *content = TestTextContent(); // read values and store inside an array in the data library mDataLibrary[id] = Data(); - Data& data = mDataLibrary[id]; + Data &data = mDataLibrary[id]; data.mIsStringArray = isStringArray; // some exporters write empty data arrays, but we need to conserve them anyways because others might reference them - if (content) - { - if (isStringArray) - { + if (content) { + if (isStringArray) { data.mStrings.reserve(count); std::string s; - for (unsigned int a = 0; a < count; a++) - { + for (unsigned int a = 0; a < count; a++) { if (*content == 0) ThrowException("Expected more values while reading IDREF_array contents."); @@ -2226,13 +1868,10 @@ void ColladaParser::ReadDataArray() SkipSpacesAndLineEnd(&content); } - } - else - { + } else { data.mValues.reserve(count); - for (unsigned int a = 0; a < count; a++) - { + for (unsigned int a = 0; a < count; a++) { if (*content == 0) ThrowException("Expected more values while reading float_array contents."); @@ -2253,11 +1892,10 @@ void ColladaParser::ReadDataArray() // ------------------------------------------------------------------------------------------------ // Reads an accessor and stores it in the global library -void ColladaParser::ReadAccessor(const std::string& pID) -{ +void ColladaParser::ReadAccessor(const std::string &pID) { // read accessor attributes int attrSource = GetAttribute("source"); - const char* source = mReader->getAttributeValue(attrSource); + const char *source = mReader->getAttributeValue(attrSource); if (source[0] != '#') ThrowException(format() << "Unknown reference format in url \"" << source << "\" in source attribute of element."); int attrCount = GetAttribute("count"); @@ -2273,7 +1911,7 @@ void ColladaParser::ReadAccessor(const std::string& pID) // store in the library under the given ID mAccessorLibrary[pID] = Accessor(); - Accessor& acc = mAccessorLibrary[pID]; + Accessor &acc = mAccessorLibrary[pID]; acc.mCount = count; acc.mOffset = offset; acc.mStride = stride; @@ -2281,50 +1919,57 @@ void ColladaParser::ReadAccessor(const std::string& pID) acc.mSize = 0; // gets incremented with every param // and read the components - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { - if (IsElement("param")) - { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("param")) { // read data param int attrName = TestAttribute("name"); std::string name; - if (attrName > -1) - { + if (attrName > -1) { name = mReader->getAttributeValue(attrName); // analyse for common type components and store it's sub-offset in the corresponding field /* Cartesian coordinates */ - if (name == "X") acc.mSubOffset[0] = acc.mParams.size(); - else if (name == "Y") acc.mSubOffset[1] = acc.mParams.size(); - else if (name == "Z") acc.mSubOffset[2] = acc.mParams.size(); + if (name == "X") + acc.mSubOffset[0] = acc.mParams.size(); + else if (name == "Y") + acc.mSubOffset[1] = acc.mParams.size(); + else if (name == "Z") + acc.mSubOffset[2] = acc.mParams.size(); /* RGBA colors */ - else if (name == "R") acc.mSubOffset[0] = acc.mParams.size(); - else if (name == "G") acc.mSubOffset[1] = acc.mParams.size(); - else if (name == "B") acc.mSubOffset[2] = acc.mParams.size(); - else if (name == "A") acc.mSubOffset[3] = acc.mParams.size(); + else if (name == "R") + acc.mSubOffset[0] = acc.mParams.size(); + else if (name == "G") + acc.mSubOffset[1] = acc.mParams.size(); + else if (name == "B") + acc.mSubOffset[2] = acc.mParams.size(); + else if (name == "A") + acc.mSubOffset[3] = acc.mParams.size(); /* UVWQ (STPQ) texture coordinates */ - else if (name == "S") acc.mSubOffset[0] = acc.mParams.size(); - else if (name == "T") acc.mSubOffset[1] = acc.mParams.size(); - else if (name == "P") acc.mSubOffset[2] = acc.mParams.size(); + else if (name == "S") + acc.mSubOffset[0] = acc.mParams.size(); + else if (name == "T") + acc.mSubOffset[1] = acc.mParams.size(); + else if (name == "P") + acc.mSubOffset[2] = acc.mParams.size(); // else if( name == "Q") acc.mSubOffset[3] = acc.mParams.size(); - /* 4D uv coordinates are not supported in Assimp */ + /* 4D uv coordinates are not supported in Assimp */ - /* Generic extra data, interpreted as UV data, too*/ - else if (name == "U") acc.mSubOffset[0] = acc.mParams.size(); - else if (name == "V") acc.mSubOffset[1] = acc.mParams.size(); + /* Generic extra data, interpreted as UV data, too*/ + else if (name == "U") + acc.mSubOffset[0] = acc.mParams.size(); + else if (name == "V") + acc.mSubOffset[1] = acc.mParams.size(); //else // DefaultLogger::get()->warn( format() << "Unknown accessor parameter \"" << name << "\". Ignoring data channel." ); } // read data type int attrType = TestAttribute("type"); - if (attrType > -1) - { + if (attrType > -1) { // for the moment we only distinguish between a 4x4 matrix and anything else. // TODO: (thom) I don't have a spec here at work. Check if there are other multi-value types // which should be tested for here. @@ -2339,14 +1984,10 @@ void ColladaParser::ReadAccessor(const std::string& pID) // skip remaining stuff of this element, if any SkipElement(); - } - else - { + } else { ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag "); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "accessor") != 0) ThrowException("Expected end of element."); break; @@ -2356,28 +1997,20 @@ void ColladaParser::ReadAccessor(const std::string& pID) // ------------------------------------------------------------------------------------------------ // Reads input declarations of per-vertex mesh data into the given mesh -void ColladaParser::ReadVertexData(Mesh* pMesh) -{ +void ColladaParser::ReadVertexData(Mesh *pMesh) { // extract the ID of the element. Not that we care, but to catch strange referencing schemes we should warn about int attrID = GetAttribute("id"); pMesh->mVertexID = mReader->getAttributeValue(attrID); // a number of elements - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { - if (IsElement("input")) - { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("input")) { ReadInputChannel(pMesh->mPerVertexData); - } - else - { + } else { ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag "); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "vertices") != 0) ThrowException("Expected end of element."); @@ -2388,8 +2021,7 @@ void ColladaParser::ReadVertexData(Mesh* pMesh) // ------------------------------------------------------------------------------------------------ // Reads input declarations of per-index mesh data into the given mesh -void ColladaParser::ReadIndexData(Mesh* pMesh) -{ +void ColladaParser::ReadIndexData(Mesh *pMesh) { std::vector vcount; std::vector perIndexData; @@ -2427,25 +2059,18 @@ void ColladaParser::ReadIndexData(Mesh* pMesh) ai_assert(primType != Prim_Invalid); // also a number of elements, but in addition a

primitive collection and probably index counts for all primitives - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { - if (IsElement("input")) - { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("input")) { ReadInputChannel(perIndexData); - } - else if (IsElement("vcount")) - { - if (!mReader->isEmptyElement()) - { - if (numPrimitives) // It is possible to define a mesh without any primitives + } else if (IsElement("vcount")) { + if (!mReader->isEmptyElement()) { + if (numPrimitives) // It is possible to define a mesh without any primitives { // case - specifies the number of indices for each polygon - const char* content = GetTextContent(); + const char *content = GetTextContent(); vcount.reserve(numPrimitives); - for (unsigned int a = 0; a < numPrimitives; a++) - { + for (unsigned int a = 0; a < numPrimitives; a++) { if (*content == 0) ThrowException("Expected more values while reading contents."); // read a number @@ -2457,28 +2082,19 @@ void ColladaParser::ReadIndexData(Mesh* pMesh) TestClosing("vcount"); } - } - else if (IsElement("p")) - { - if (!mReader->isEmptyElement()) - { + } else if (IsElement("p")) { + if (!mReader->isEmptyElement()) { // now here the actual fun starts - these are the indices to construct the mesh data from actualPrimitives += ReadPrimitives(pMesh, perIndexData, numPrimitives, vcount, primType); } - } - else if (IsElement("extra")) - { + } else if (IsElement("extra")) { SkipElement("extra"); - } - else if (IsElement("ph")) { + } else if (IsElement("ph")) { SkipElement("ph"); - } - else { + } else { ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <" << elementName << ">"); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (mReader->getNodeName() != elementName) ThrowException(format() << "Expected end of <" << elementName << "> element."); @@ -2488,7 +2104,7 @@ void ColladaParser::ReadIndexData(Mesh* pMesh) #ifdef ASSIMP_BUILD_DEBUG if (primType != Prim_TriFans && primType != Prim_TriStrips && primType != Prim_LineStrip && - primType != Prim_Lines) { // this is ONLY to workaround a bug in SketchUp 15.3.331 where it writes the wrong 'count' when it writes out the 'lines'. + primType != Prim_Lines) { // this is ONLY to workaround a bug in SketchUp 15.3.331 where it writes the wrong 'count' when it writes out the 'lines'. ai_assert(actualPrimitives == numPrimitives); } #endif @@ -2500,8 +2116,7 @@ void ColladaParser::ReadIndexData(Mesh* pMesh) // ------------------------------------------------------------------------------------------------ // Reads a single input channel element and stores it in the given array, if valid -void ColladaParser::ReadInputChannel(std::vector& poChannels) -{ +void ColladaParser::ReadInputChannel(std::vector &poChannels) { InputChannel channel; // read semantic @@ -2511,7 +2126,7 @@ void ColladaParser::ReadInputChannel(std::vector& poChannels) // read source int attrSource = GetAttribute("source"); - const char* source = mReader->getAttributeValue(attrSource); + const char *source = mReader->getAttributeValue(attrSource); if (source[0] != '#') ThrowException(format() << "Unknown reference format in url \"" << source << "\" in source attribute of element."); channel.mAccessor = source + 1; // skipping the leading #, hopefully the remaining text is the accessor ID only @@ -2543,15 +2158,13 @@ void ColladaParser::ReadInputChannel(std::vector& poChannels) // ------------------------------------------------------------------------------------------------ // Reads a

primitive index list and assembles the mesh data into the given mesh -size_t ColladaParser::ReadPrimitives(Mesh* pMesh, std::vector& pPerIndexChannels, - size_t pNumPrimitives, const std::vector& pVCount, PrimitiveType pPrimType) -{ +size_t ColladaParser::ReadPrimitives(Mesh *pMesh, std::vector &pPerIndexChannels, + size_t pNumPrimitives, const std::vector &pVCount, PrimitiveType pPrimType) { // determine number of indices coming per vertex // find the offset index for all per-vertex channels size_t numOffsets = 1; size_t perVertexOffset = SIZE_MAX; // invalid value - for (const InputChannel& channel : pPerIndexChannels) - { + for (const InputChannel &channel : pPerIndexChannels) { numOffsets = std::max(numOffsets, channel.mOffset + 1); if (channel.mType == IT_Vertex) perVertexOffset = channel.mOffset; @@ -2559,10 +2172,8 @@ size_t ColladaParser::ReadPrimitives(Mesh* pMesh, std::vector& pPe // determine the expected number of indices size_t expectedPointCount = 0; - switch (pPrimType) - { - case Prim_Polylist: - { + switch (pPrimType) { + case Prim_Polylist: { for (size_t i : pVCount) expectedPointCount += i; break; @@ -2585,9 +2196,8 @@ size_t ColladaParser::ReadPrimitives(Mesh* pMesh, std::vector& pPe if (pNumPrimitives > 0) // It is possible to not contain any indices { - const char* content = GetTextContent(); - while (*content != 0) - { + const char *content = GetTextContent(); + while (*content != 0) { // read a value. // Hack: (thom) Some exporters put negative indices sometimes. We just try to carry on anyways. int value = std::max(0, strtol10(content, &content)); @@ -2603,38 +2213,33 @@ size_t ColladaParser::ReadPrimitives(Mesh* pMesh, std::vector& pPe // HACK: We just fix this number since SketchUp 15.3.331 writes the wrong 'count' for 'lines' ReportWarning("Expected different index count in

element, %zu instead of %zu.", indices.size(), expectedPointCount * numOffsets); pNumPrimitives = (indices.size() / numOffsets) / 2; - } - else + } else ThrowException("Expected different index count in

element."); - } - else if (expectedPointCount == 0 && (indices.size() % numOffsets) != 0) + } else if (expectedPointCount == 0 && (indices.size() % numOffsets) != 0) ThrowException("Expected different index count in

element."); // find the data for all sources - for (std::vector::iterator it = pMesh->mPerVertexData.begin(); it != pMesh->mPerVertexData.end(); ++it) - { - InputChannel& input = *it; + for (std::vector::iterator it = pMesh->mPerVertexData.begin(); it != pMesh->mPerVertexData.end(); ++it) { + InputChannel &input = *it; if (input.mResolved) continue; // find accessor input.mResolved = &ResolveLibraryReference(mAccessorLibrary, input.mAccessor); // resolve accessor's data pointer as well, if necessary - const Accessor* acc = input.mResolved; + const Accessor *acc = input.mResolved; if (!acc->mData) acc->mData = &ResolveLibraryReference(mDataLibrary, acc->mSource); } // and the same for the per-index channels - for (std::vector::iterator it = pPerIndexChannels.begin(); it != pPerIndexChannels.end(); ++it) - { - InputChannel& input = *it; + for (std::vector::iterator it = pPerIndexChannels.begin(); it != pPerIndexChannels.end(); ++it) { + InputChannel &input = *it; if (input.mResolved) continue; // ignore vertex pointer, it doesn't refer to an accessor - if (input.mType == IT_Vertex) - { + if (input.mType == IT_Vertex) { // warn if the vertex channel does not refer to the element in the same mesh if (input.mAccessor != pMesh->mVertexID) ThrowException("Unsupported vertex referencing scheme."); @@ -2644,7 +2249,7 @@ size_t ColladaParser::ReadPrimitives(Mesh* pMesh, std::vector& pPe // find accessor input.mResolved = &ResolveLibraryReference(mAccessorLibrary, input.mAccessor); // resolve accessor's data pointer as well, if necessary - const Accessor* acc = input.mResolved; + const Accessor *acc = input.mResolved; if (!acc->mData) acc->mData = &ResolveLibraryReference(mDataLibrary, acc->mSource); } @@ -2667,12 +2272,10 @@ size_t ColladaParser::ReadPrimitives(Mesh* pMesh, std::vector& pPe pMesh->mFacePosIndices.reserve(indices.size() / numOffsets); size_t polylistStartVertex = 0; - for (size_t currentPrimitive = 0; currentPrimitive < numPrimitives; currentPrimitive++) - { + for (size_t currentPrimitive = 0; currentPrimitive < numPrimitives; currentPrimitive++) { // determine number of points for this primitive size_t numPoints = 0; - switch (pPrimType) - { + switch (pPrimType) { case Prim_Lines: numPoints = 2; for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++) @@ -2722,7 +2325,7 @@ size_t ColladaParser::ReadPrimitives(Mesh* pMesh, std::vector& pPe ///@note This function willn't work correctly if both PerIndex and PerVertex channels have same channels. ///For example if TEXCOORD present in both and tags this function will create wrong uv coordinates. ///It's not clear from COLLADA documentation is this allowed or not. For now only exporter fixed to avoid such behavior -void ColladaParser::CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset, Mesh* pMesh, std::vector& pPerIndexChannels, size_t currentPrimitive, const std::vector& indices) { +void ColladaParser::CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset, Mesh *pMesh, std::vector &pPerIndexChannels, size_t currentPrimitive, const std::vector &indices) { // calculate the base offset of the vertex whose attributes we ant to copy size_t baseOffset = currentPrimitive * numOffsets * numPoints + currentVertex * numOffsets; @@ -2740,14 +2343,13 @@ void ColladaParser::CopyVertex(size_t currentVertex, size_t numOffsets, size_t n pMesh->mFacePosIndices.push_back(indices[baseOffset + perVertexOffset]); } -void ColladaParser::ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Mesh* pMesh, std::vector& pPerIndexChannels, size_t currentPrimitive, const std::vector& indices) { +void ColladaParser::ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Mesh *pMesh, std::vector &pPerIndexChannels, size_t currentPrimitive, const std::vector &indices) { if (currentPrimitive % 2 != 0) { //odd tristrip triangles need their indices mangled, to preserve winding direction CopyVertex(1, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices); CopyVertex(0, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices); CopyVertex(2, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices); - } - else {//for non tristrips or even tristrip triangles + } else { //for non tristrips or even tristrip triangles CopyVertex(0, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices); CopyVertex(1, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices); CopyVertex(2, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices); @@ -2756,18 +2358,17 @@ void ColladaParser::ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, // ------------------------------------------------------------------------------------------------ // Extracts a single object from an input channel and stores it in the appropriate mesh data array -void ColladaParser::ExtractDataObjectFromChannel(const InputChannel& pInput, size_t pLocalIndex, Mesh* pMesh) -{ +void ColladaParser::ExtractDataObjectFromChannel(const InputChannel &pInput, size_t pLocalIndex, Mesh *pMesh) { // ignore vertex referrer - we handle them that separate if (pInput.mType == IT_Vertex) return; - const Accessor& acc = *pInput.mResolved; + const Accessor &acc = *pInput.mResolved; if (pLocalIndex >= acc.mCount) ThrowException(format() << "Invalid data index (" << pLocalIndex << "/" << acc.mCount << ") in primitive specification"); // get a pointer to the start of the data object referred to by the accessor and the local index - const ai_real* dataObject = &(acc.mData->mValues[0]) + acc.mOffset + pLocalIndex * acc.mStride; + const ai_real *dataObject = &(acc.mData->mValues[0]) + acc.mOffset + pLocalIndex * acc.mStride; // assemble according to the accessors component sub-offset list. We don't care, yet, // what kind of object exactly we're extracting here @@ -2776,8 +2377,7 @@ void ColladaParser::ExtractDataObjectFromChannel(const InputChannel& pInput, siz obj[c] = dataObject[acc.mSubOffset[c]]; // now we reinterpret it according to the type we're reading here - switch (pInput.mType) - { + switch (pInput.mType) { case IT_Position: // ignore all position streams except 0 - there can be only one position if (pInput.mIndex == 0) pMesh->mPositions.push_back(aiVector3D(obj[0], obj[1], obj[2])); @@ -2819,40 +2419,33 @@ void ColladaParser::ExtractDataObjectFromChannel(const InputChannel& pInput, siz break; case IT_Texcoord: // up to 4 texture coord sets are fine, ignore the others - if (pInput.mIndex < AI_MAX_NUMBER_OF_TEXTURECOORDS) - { + if (pInput.mIndex < AI_MAX_NUMBER_OF_TEXTURECOORDS) { // pad to current vertex count if necessary if (pMesh->mTexCoords[pInput.mIndex].size() < pMesh->mPositions.size() - 1) pMesh->mTexCoords[pInput.mIndex].insert(pMesh->mTexCoords[pInput.mIndex].end(), - pMesh->mPositions.size() - pMesh->mTexCoords[pInput.mIndex].size() - 1, aiVector3D(0, 0, 0)); + pMesh->mPositions.size() - pMesh->mTexCoords[pInput.mIndex].size() - 1, aiVector3D(0, 0, 0)); pMesh->mTexCoords[pInput.mIndex].push_back(aiVector3D(obj[0], obj[1], obj[2])); if (0 != acc.mSubOffset[2] || 0 != acc.mSubOffset[3]) /* hack ... consider cleaner solution */ pMesh->mNumUVComponents[pInput.mIndex] = 3; - } - else - { + } else { ASSIMP_LOG_ERROR("Collada: too many texture coordinate sets. Skipping."); } break; case IT_Color: // up to 4 color sets are fine, ignore the others - if (pInput.mIndex < AI_MAX_NUMBER_OF_COLOR_SETS) - { + if (pInput.mIndex < AI_MAX_NUMBER_OF_COLOR_SETS) { // pad to current vertex count if necessary if (pMesh->mColors[pInput.mIndex].size() < pMesh->mPositions.size() - 1) pMesh->mColors[pInput.mIndex].insert(pMesh->mColors[pInput.mIndex].end(), - pMesh->mPositions.size() - pMesh->mColors[pInput.mIndex].size() - 1, aiColor4D(0, 0, 0, 1)); + pMesh->mPositions.size() - pMesh->mColors[pInput.mIndex].size() - 1, aiColor4D(0, 0, 0, 1)); aiColor4D result(0, 0, 0, 1); - for (size_t i = 0; i < pInput.mResolved->mSize; ++i) - { + for (size_t i = 0; i < pInput.mResolved->mSize; ++i) { result[static_cast(i)] = obj[pInput.mResolved->mSubOffset[i]]; } pMesh->mColors[pInput.mIndex].push_back(result); - } - else - { + } else { ASSIMP_LOG_ERROR("Collada: too many vertex color sets. Skipping."); } @@ -2865,44 +2458,36 @@ void ColladaParser::ExtractDataObjectFromChannel(const InputChannel& pInput, siz // ------------------------------------------------------------------------------------------------ // Reads the library of node hierarchies and scene parts -void ColladaParser::ReadSceneLibrary() -{ +void ColladaParser::ReadSceneLibrary() { if (mReader->isEmptyElement()) return; - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { // a visual scene - generate root node under its ID and let ReadNode() do the recursive work - if (IsElement("visual_scene")) - { + if (IsElement("visual_scene")) { // read ID. Is optional according to the spec, but how on earth should a scene_instance refer to it then? int indexID = GetAttribute("id"); - const char* attrID = mReader->getAttributeValue(indexID); + const char *attrID = mReader->getAttributeValue(indexID); // read name if given. int indexName = TestAttribute("name"); - const char* attrName = "unnamed"; + const char *attrName = "unnamed"; if (indexName > -1) attrName = mReader->getAttributeValue(indexName); // create a node and store it in the library under its ID - Node* node = new Node; + Node *node = new Node; node->mID = attrID; node->mName = attrName; mNodeLibrary[node->mID] = node; ReadSceneNode(node); - } - else - { + } else { // ignore the rest SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "library_visual_scenes") == 0) //ThrowException( "Expected end of \"library_visual_scenes\" element."); @@ -2913,19 +2498,15 @@ void ColladaParser::ReadSceneLibrary() // ------------------------------------------------------------------------------------------------ // Reads a scene node's contents including children and stores it in the given node -void ColladaParser::ReadSceneNode(Node* pNode) -{ +void ColladaParser::ReadSceneNode(Node *pNode) { // quit immediately on elements if (mReader->isEmptyElement()) return; - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { - if (IsElement("node")) - { - Node* child = new Node; + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("node")) { + Node *child = new Node; int attrID = TestAttribute("id"); if (attrID > -1) child->mID = mReader->getAttributeValue(attrID); @@ -2940,13 +2521,10 @@ void ColladaParser::ReadSceneNode(Node* pNode) // TODO: (thom) support SIDs // ai_assert( TestAttribute( "sid") == -1); - if (pNode) - { + if (pNode) { pNode->mChildren.push_back(child); child->mParent = pNode; - } - else - { + } else { // no parent node given, probably called from element. // create new node in node library mNodeLibrary[child->mID] = child; @@ -2972,82 +2550,65 @@ void ColladaParser::ReadSceneNode(Node* pNode) ReadNodeTransformation(pNode, TF_SKEW); else if (IsElement("translate")) ReadNodeTransformation(pNode, TF_TRANSLATE); - else if (IsElement("render") && pNode->mParent == NULL && 0 == pNode->mPrimaryCamera.length()) - { + else if (IsElement("render") && pNode->mParent == NULL && 0 == pNode->mPrimaryCamera.length()) { // ... scene evaluation or, in other words, postprocessing pipeline, // or, again in other words, a turing-complete description how to // render a Collada scene. The only thing that is interesting for // us is the primary camera. int attrId = TestAttribute("camera_node"); - if (-1 != attrId) - { - const char* s = mReader->getAttributeValue(attrId); + if (-1 != attrId) { + const char *s = mReader->getAttributeValue(attrId); if (s[0] != '#') ASSIMP_LOG_ERROR("Collada: Unresolved reference format of camera"); else pNode->mPrimaryCamera = s + 1; } - } - else if (IsElement("instance_node")) - { + } else if (IsElement("instance_node")) { // find the node in the library int attrID = TestAttribute("url"); - if (attrID != -1) - { - const char* s = mReader->getAttributeValue(attrID); + if (attrID != -1) { + const char *s = mReader->getAttributeValue(attrID); if (s[0] != '#') ASSIMP_LOG_ERROR("Collada: Unresolved reference format of node"); - else - { + else { pNode->mNodeInstances.push_back(NodeInstance()); pNode->mNodeInstances.back().mNode = s + 1; } } - } - else if (IsElement("instance_geometry") || IsElement("instance_controller")) - { + } else if (IsElement("instance_geometry") || IsElement("instance_controller")) { // Reference to a mesh or controller, with possible material associations ReadNodeGeometry(pNode); - } - else if (IsElement("instance_light")) - { + } else if (IsElement("instance_light")) { // Reference to a light, name given in 'url' attribute int attrID = TestAttribute("url"); if (-1 == attrID) ASSIMP_LOG_WARN("Collada: Expected url attribute in element"); - else - { - const char* url = mReader->getAttributeValue(attrID); + else { + const char *url = mReader->getAttributeValue(attrID); if (url[0] != '#') ThrowException("Unknown reference format in element"); pNode->mLights.push_back(LightInstance()); pNode->mLights.back().mLight = url + 1; } - } - else if (IsElement("instance_camera")) - { + } else if (IsElement("instance_camera")) { // Reference to a camera, name given in 'url' attribute int attrID = TestAttribute("url"); if (-1 == attrID) ASSIMP_LOG_WARN("Collada: Expected url attribute in element"); - else - { - const char* url = mReader->getAttributeValue(attrID); + else { + const char *url = mReader->getAttributeValue(attrID); if (url[0] != '#') ThrowException("Unknown reference format in element"); pNode->mCameras.push_back(CameraInstance()); pNode->mCameras.back().mCamera = url + 1; } - } - else - { + } else { // skip everything else for the moment SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { break; } } @@ -3055,8 +2616,7 @@ void ColladaParser::ReadSceneNode(Node* pNode) // ------------------------------------------------------------------------------------------------ // Reads a node transformation entry of the given type and adds it to the given node's transformation list. -void ColladaParser::ReadNodeTransformation(Node* pNode, TransformType pType) -{ +void ColladaParser::ReadNodeTransformation(Node *pNode, TransformType pType) { if (mReader->isEmptyElement()) return; @@ -3072,11 +2632,10 @@ void ColladaParser::ReadNodeTransformation(Node* pNode, TransformType pType) // how many parameters to read per transformation type static const unsigned int sNumParameters[] = { 9, 4, 3, 3, 7, 16 }; - const char* content = GetTextContent(); + const char *content = GetTextContent(); // read as many parameters and store in the transformation - for (unsigned int a = 0; a < sNumParameters[pType]; a++) - { + for (unsigned int a = 0; a < sNumParameters[pType]; a++) { // read a number content = fast_atoreal_move(content, tf.f[a]); // skip whitespace after it @@ -3092,13 +2651,10 @@ void ColladaParser::ReadNodeTransformation(Node* pNode, TransformType pType) // ------------------------------------------------------------------------------------------------ // Processes bind_vertex_input and bind elements -void ColladaParser::ReadMaterialVertexInputBinding(Collada::SemanticMappingTable& tbl) -{ - while (mReader->read()) - { +void ColladaParser::ReadMaterialVertexInputBinding(Collada::SemanticMappingTable &tbl) { + while (mReader->read()) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if (IsElement("bind_vertex_input")) - { + if (IsElement("bind_vertex_input")) { Collada::InputSemanticMapEntry vn; // effect semantic @@ -3115,20 +2671,17 @@ void ColladaParser::ReadMaterialVertexInputBinding(Collada::SemanticMappingTable vn.mSet = mReader->getAttributeValueAsInt(n); tbl.mMap[s] = vn; - } - else if (IsElement("bind")) { + } else if (IsElement("bind")) { ASSIMP_LOG_WARN("Collada: Found unsupported element"); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "instance_material") == 0) break; } } } -void ColladaParser::ReadEmbeddedTextures(ZipArchiveIOSystem& zip_archive) -{ +void ColladaParser::ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive) { // Attempt to load any undefined Collada::Image in ImageLibrary for (ImageLibrary::iterator it = mImageLibrary.begin(); it != mImageLibrary.end(); ++it) { Collada::Image &image = (*it).second; @@ -3149,31 +2702,26 @@ void ColladaParser::ReadEmbeddedTextures(ZipArchiveIOSystem& zip_archive) // ------------------------------------------------------------------------------------------------ // Reads a mesh reference in a node and adds it to the node's mesh list -void ColladaParser::ReadNodeGeometry(Node* pNode) -{ +void ColladaParser::ReadNodeGeometry(Node *pNode) { // referred mesh is given as an attribute of the element int attrUrl = GetAttribute("url"); - const char* url = mReader->getAttributeValue(attrUrl); + const char *url = mReader->getAttributeValue(attrUrl); if (url[0] != '#') ThrowException("Unknown reference format"); Collada::MeshInstance instance; instance.mMeshOrController = url + 1; // skipping the leading # - if (!mReader->isEmptyElement()) - { + if (!mReader->isEmptyElement()) { // read material associations. Ignore additional elements in between - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { - if (IsElement("instance_material")) - { + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("instance_material")) { // read ID of the geometry subgroup and the target material int attrGroup = GetAttribute("symbol"); std::string group = mReader->getAttributeValue(attrGroup); int attrMaterial = GetAttribute("target"); - const char* urlMat = mReader->getAttributeValue(attrMaterial); + const char *urlMat = mReader->getAttributeValue(attrMaterial); Collada::SemanticMappingTable s; if (urlMat[0] == '#') urlMat++; @@ -3187,11 +2735,8 @@ void ColladaParser::ReadNodeGeometry(Node* pNode) // store the association instance.mMaterials[group] = s; } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { - if (strcmp(mReader->getNodeName(), "instance_geometry") == 0 - || strcmp(mReader->getNodeName(), "instance_controller") == 0) + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + if (strcmp(mReader->getNodeName(), "instance_geometry") == 0 || strcmp(mReader->getNodeName(), "instance_controller") == 0) break; } } @@ -3203,23 +2748,20 @@ void ColladaParser::ReadNodeGeometry(Node* pNode) // ------------------------------------------------------------------------------------------------ // Reads the collada scene -void ColladaParser::ReadScene() -{ +void ColladaParser::ReadScene() { if (mReader->isEmptyElement()) return; - while (mReader->read()) - { + while (mReader->read()) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if (IsElement("instance_visual_scene")) - { + if (IsElement("instance_visual_scene")) { // should be the first and only occurrence if (mRootNode) ThrowException("Invalid scene containing multiple root nodes in element"); // read the url of the scene to instance. Should be of format "#some_name" int urlIndex = GetAttribute("url"); - const char* url = mReader->getAttributeValue(urlIndex); + const char *url = mReader->getAttributeValue(urlIndex); if (url[0] != '#') ThrowException("Unknown reference format in element"); @@ -3228,12 +2770,10 @@ void ColladaParser::ReadScene() if (sit == mNodeLibrary.end()) ThrowException("Unable to resolve visual_scene reference \"" + std::string(url) + "\" in element."); mRootNode = sit->second; - } - else { + } else { SkipElement(); } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { break; } } @@ -3241,11 +2781,11 @@ void ColladaParser::ReadScene() // ------------------------------------------------------------------------------------------------ // Aborts the file reading with an exception -AI_WONT_RETURN void ColladaParser::ThrowException(const std::string& pError) const { +AI_WONT_RETURN void ColladaParser::ThrowException(const std::string &pError) const { throw DeadlyImportError(format() << "Collada: " << mFileName << " - " << pError); } -void ColladaParser::ReportWarning(const char* msg, ...) { +void ColladaParser::ReportWarning(const char *msg, ...) { ai_assert(nullptr != msg); va_list args; @@ -3273,7 +2813,7 @@ void ColladaParser::SkipElement() { // ------------------------------------------------------------------------------------------------ // Skips all data until the end node of the given element -void ColladaParser::SkipElement(const char* pElement) { +void ColladaParser::SkipElement(const char *pElement) { // copy the current node's name because it'a pointer to the reader's internal buffer, // which is going to change with the upcoming parsing std::string element = pElement; @@ -3288,7 +2828,7 @@ void ColladaParser::SkipElement(const char* pElement) { // ------------------------------------------------------------------------------------------------ // Tests for an opening element of the given name, throws an exception if not found -void ColladaParser::TestOpening(const char* pName) { +void ColladaParser::TestOpening(const char *pName) { // read element start if (!mReader->read()) { ThrowException(format() << "Unexpected end of file while beginning of <" << pName << "> element."); @@ -3307,7 +2847,7 @@ void ColladaParser::TestOpening(const char* pName) { // ------------------------------------------------------------------------------------------------ // Tests for the closing tag of the given element, throws an exception if not found -void ColladaParser::TestClosing(const char* pName) { +void ColladaParser::TestClosing(const char *pName) { // check if we have an empty (self-closing) element if (mReader->isEmptyElement()) { return; @@ -3337,7 +2877,7 @@ void ColladaParser::TestClosing(const char* pName) { // ------------------------------------------------------------------------------------------------ // Returns the index of the named attribute or -1 if not found. Does not throw, therefore useful for optional attributes -int ColladaParser::GetAttribute(const char* pAttr) const { +int ColladaParser::GetAttribute(const char *pAttr) const { int index = TestAttribute(pAttr); if (index == -1) { ThrowException(format() << "Expected attribute \"" << pAttr << "\" for element <" << mReader->getNodeName() << ">."); @@ -3349,8 +2889,7 @@ int ColladaParser::GetAttribute(const char* pAttr) const { // ------------------------------------------------------------------------------------------------ // Tests the present element for the presence of one attribute, returns its index or throws an exception if not found -int ColladaParser::TestAttribute(const char* pAttr) const -{ +int ColladaParser::TestAttribute(const char *pAttr) const { for (int a = 0; a < mReader->getAttributeCount(); a++) if (strcmp(mReader->getAttributeName(a), pAttr) == 0) return a; @@ -3360,9 +2899,8 @@ int ColladaParser::TestAttribute(const char* pAttr) const // ------------------------------------------------------------------------------------------------ // Reads the text contents of an element, throws an exception if not given. Skips leading whitespace. -const char* ColladaParser::GetTextContent() -{ - const char* sz = TestTextContent(); +const char *ColladaParser::GetTextContent() { + const char *sz = TestTextContent(); if (!sz) { ThrowException("Invalid contents in element \"n\"."); } @@ -3371,8 +2909,7 @@ const char* ColladaParser::GetTextContent() // ------------------------------------------------------------------------------------------------ // Reads the text contents of an element, returns NULL if not given. Skips leading whitespace. -const char* ColladaParser::TestTextContent() -{ +const char *ColladaParser::TestTextContent() { // present node should be the beginning of an element if (mReader->getNodeType() != irr::io::EXN_ELEMENT || mReader->isEmptyElement()) return NULL; @@ -3384,7 +2921,7 @@ const char* ColladaParser::TestTextContent() return NULL; // skip leading whitespace - const char* text = mReader->getNodeData(); + const char *text = mReader->getNodeData(); SkipSpacesAndLineEnd(&text); return text; @@ -3392,17 +2929,13 @@ const char* ColladaParser::TestTextContent() // ------------------------------------------------------------------------------------------------ // Calculates the resulting transformation fromm all the given transform steps -aiMatrix4x4 ColladaParser::CalculateResultTransform(const std::vector& pTransforms) const -{ +aiMatrix4x4 ColladaParser::CalculateResultTransform(const std::vector &pTransforms) const { aiMatrix4x4 res; - for (std::vector::const_iterator it = pTransforms.begin(); it != pTransforms.end(); ++it) - { - const Transform& tf = *it; - switch (tf.mType) - { - case TF_LOOKAT: - { + for (std::vector::const_iterator it = pTransforms.begin(); it != pTransforms.end(); ++it) { + const Transform &tf = *it; + switch (tf.mType) { + case TF_LOOKAT: { aiVector3D pos(tf.f[0], tf.f[1], tf.f[2]); aiVector3D dstPos(tf.f[3], tf.f[4], tf.f[5]); aiVector3D up = aiVector3D(tf.f[6], tf.f[7], tf.f[8]).Normalize(); @@ -3410,14 +2943,13 @@ aiMatrix4x4 ColladaParser::CalculateResultTransform(const std::vector aiVector3D right = (dir ^ up).Normalize(); res *= aiMatrix4x4( - right.x, up.x, -dir.x, pos.x, - right.y, up.y, -dir.y, pos.y, - right.z, up.z, -dir.z, pos.z, - 0, 0, 0, 1); + right.x, up.x, -dir.x, pos.x, + right.y, up.y, -dir.y, pos.y, + right.z, up.z, -dir.z, pos.z, + 0, 0, 0, 1); break; } - case TF_ROTATE: - { + case TF_ROTATE: { aiMatrix4x4 rot; ai_real angle = tf.f[3] * ai_real(AI_MATH_PI) / ai_real(180.0); aiVector3D axis(tf.f[0], tf.f[1], tf.f[2]); @@ -3425,17 +2957,15 @@ aiMatrix4x4 ColladaParser::CalculateResultTransform(const std::vector res *= rot; break; } - case TF_TRANSLATE: - { + case TF_TRANSLATE: { aiMatrix4x4 trans; aiMatrix4x4::Translation(aiVector3D(tf.f[0], tf.f[1], tf.f[2]), trans); res *= trans; break; } - case TF_SCALE: - { + case TF_SCALE: { aiMatrix4x4 scale(tf.f[0], 0.0f, 0.0f, 0.0f, 0.0f, tf.f[1], 0.0f, 0.0f, 0.0f, 0.0f, tf.f[2], 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f); + 0.0f, 0.0f, 0.0f, 1.0f); res *= scale; break; } @@ -3443,10 +2973,9 @@ aiMatrix4x4 ColladaParser::CalculateResultTransform(const std::vector // TODO: (thom) ai_assert(false); break; - case TF_MATRIX: - { + case TF_MATRIX: { aiMatrix4x4 mat(tf.f[0], tf.f[1], tf.f[2], tf.f[3], tf.f[4], tf.f[5], tf.f[6], tf.f[7], - tf.f[8], tf.f[9], tf.f[10], tf.f[11], tf.f[12], tf.f[13], tf.f[14], tf.f[15]); + tf.f[8], tf.f[9], tf.f[10], tf.f[11], tf.f[12], tf.f[13], tf.f[14], tf.f[15]); res *= mat; break; } @@ -3461,8 +2990,7 @@ aiMatrix4x4 ColladaParser::CalculateResultTransform(const std::vector // ------------------------------------------------------------------------------------------------ // Determines the input data type for the given semantic string -Collada::InputType ColladaParser::GetTypeForSemantic(const std::string& semantic) -{ +Collada::InputType ColladaParser::GetTypeForSemantic(const std::string &semantic) { if (semantic.empty()) { ASSIMP_LOG_WARN("Vertex input type is empty."); return IT_Invalid; diff --git a/code/Collada/ColladaParser.h b/code/Collada/ColladaParser.h index d1e812bd2..861a65256 100644 --- a/code/Collada/ColladaParser.h +++ b/code/Collada/ColladaParser.h @@ -47,346 +47,345 @@ #ifndef AI_COLLADAPARSER_H_INC #define AI_COLLADAPARSER_H_INC -#include #include "ColladaHelper.h" -#include #include +#include +#include -namespace Assimp -{ - class ZipArchiveIOSystem; +namespace Assimp { +class ZipArchiveIOSystem; - // ------------------------------------------------------------------------------------------ - /** Parser helper class for the Collada loader. +// ------------------------------------------------------------------------------------------ +/** Parser helper class for the Collada loader. * * Does all the XML reading and builds internal data structures from it, * but leaves the resolving of all the references to the loader. */ - class ColladaParser - { - friend class ColladaLoader; +class ColladaParser { + friend class ColladaLoader; - /** Converts a path read from a collada file to the usual representation */ - static void UriDecodePath(aiString& ss); + /** Converts a path read from a collada file to the usual representation */ + static void UriDecodePath(aiString &ss); - protected: - /** Map for generic metadata as aiString */ - typedef std::map StringMetaData; +protected: + /** Map for generic metadata as aiString */ + typedef std::map StringMetaData; - /** Constructor from XML file */ - ColladaParser(IOSystem* pIOHandler, const std::string& pFile); + /** Constructor from XML file */ + ColladaParser(IOSystem *pIOHandler, const std::string &pFile); - /** Destructor */ - ~ColladaParser(); + /** Destructor */ + ~ColladaParser(); - /** Attempts to read the ZAE manifest and returns the DAE to open */ - static std::string ReadZaeManifest(ZipArchiveIOSystem &zip_archive); + /** Attempts to read the ZAE manifest and returns the DAE to open */ + static std::string ReadZaeManifest(ZipArchiveIOSystem &zip_archive); - /** Reads the contents of the file */ - void ReadContents(); + /** Reads the contents of the file */ + void ReadContents(); - /** Reads the structure of the file */ - void ReadStructure(); + /** Reads the structure of the file */ + void ReadStructure(); - /** Reads asset information such as coordinate system information and legal blah */ - void ReadAssetInfo(); + /** Reads asset information such as coordinate system information and legal blah */ + void ReadAssetInfo(); - /** Reads contributor information such as author and legal blah */ - void ReadContributorInfo(); + /** Reads contributor information such as author and legal blah */ + void ReadContributorInfo(); - /** Reads generic metadata into provided map and renames keys for Assimp */ - void ReadMetaDataItem(StringMetaData &metadata); + /** Reads generic metadata into provided map and renames keys for Assimp */ + void ReadMetaDataItem(StringMetaData &metadata); - /** Reads the animation library */ - void ReadAnimationLibrary(); + /** Reads the animation library */ + void ReadAnimationLibrary(); - /** Reads the animation clip library */ - void ReadAnimationClipLibrary(); + /** Reads the animation clip library */ + void ReadAnimationClipLibrary(); - /** Unwrap controllers dependency hierarchy */ - void PostProcessControllers(); - - /** Re-build animations from animation clip library, if present, otherwise combine single-channel animations */ - void PostProcessRootAnimations(); + /** Unwrap controllers dependency hierarchy */ + void PostProcessControllers(); - /** Reads an animation into the given parent structure */ - void ReadAnimation( Collada::Animation* pParent); + /** Re-build animations from animation clip library, if present, otherwise combine single-channel animations */ + void PostProcessRootAnimations(); - /** Reads an animation sampler into the given anim channel */ - void ReadAnimationSampler( Collada::AnimationChannel& pChannel); + /** Reads an animation into the given parent structure */ + void ReadAnimation(Collada::Animation *pParent); - /** Reads the skeleton controller library */ - void ReadControllerLibrary(); + /** Reads an animation sampler into the given anim channel */ + void ReadAnimationSampler(Collada::AnimationChannel &pChannel); - /** Reads a controller into the given mesh structure */ - void ReadController( Collada::Controller& pController); + /** Reads the skeleton controller library */ + void ReadControllerLibrary(); - /** Reads the joint definitions for the given controller */ - void ReadControllerJoints( Collada::Controller& pController); + /** Reads a controller into the given mesh structure */ + void ReadController(Collada::Controller &pController); - /** Reads the joint weights for the given controller */ - void ReadControllerWeights( Collada::Controller& pController); + /** Reads the joint definitions for the given controller */ + void ReadControllerJoints(Collada::Controller &pController); - /** Reads the image library contents */ - void ReadImageLibrary(); + /** Reads the joint weights for the given controller */ + void ReadControllerWeights(Collada::Controller &pController); - /** Reads an image entry into the given image */ - void ReadImage( Collada::Image& pImage); + /** Reads the image library contents */ + void ReadImageLibrary(); - /** Reads the material library */ - void ReadMaterialLibrary(); + /** Reads an image entry into the given image */ + void ReadImage(Collada::Image &pImage); - /** Reads a material entry into the given material */ - void ReadMaterial( Collada::Material& pMaterial); + /** Reads the material library */ + void ReadMaterialLibrary(); - /** Reads the camera library */ - void ReadCameraLibrary(); + /** Reads a material entry into the given material */ + void ReadMaterial(Collada::Material &pMaterial); - /** Reads a camera entry into the given camera */ - void ReadCamera( Collada::Camera& pCamera); + /** Reads the camera library */ + void ReadCameraLibrary(); - /** Reads the light library */ - void ReadLightLibrary(); + /** Reads a camera entry into the given camera */ + void ReadCamera(Collada::Camera &pCamera); - /** Reads a light entry into the given light */ - void ReadLight( Collada::Light& pLight); + /** Reads the light library */ + void ReadLightLibrary(); - /** Reads the effect library */ - void ReadEffectLibrary(); + /** Reads a light entry into the given light */ + void ReadLight(Collada::Light &pLight); - /** Reads an effect entry into the given effect*/ - void ReadEffect( Collada::Effect& pEffect); + /** Reads the effect library */ + void ReadEffectLibrary(); - /** Reads an COMMON effect profile */ - void ReadEffectProfileCommon( Collada::Effect& pEffect); + /** Reads an effect entry into the given effect*/ + void ReadEffect(Collada::Effect &pEffect); - /** Read sampler properties */ - void ReadSamplerProperties( Collada::Sampler& pSampler); + /** Reads an COMMON effect profile */ + void ReadEffectProfileCommon(Collada::Effect &pEffect); - /** Reads an effect entry containing a color or a texture defining that color */ - void ReadEffectColor( aiColor4D& pColor, Collada::Sampler& pSampler); + /** Read sampler properties */ + void ReadSamplerProperties(Collada::Sampler &pSampler); - /** Reads an effect entry containing a float */ - void ReadEffectFloat( ai_real& pFloat); + /** Reads an effect entry containing a color or a texture defining that color */ + void ReadEffectColor(aiColor4D &pColor, Collada::Sampler &pSampler); - /** Reads an effect parameter specification of any kind */ - void ReadEffectParam( Collada::EffectParam& pParam); + /** Reads an effect entry containing a float */ + void ReadEffectFloat(ai_real &pFloat); - /** Reads the geometry library contents */ - void ReadGeometryLibrary(); + /** Reads an effect parameter specification of any kind */ + void ReadEffectParam(Collada::EffectParam &pParam); - /** Reads a geometry from the geometry library. */ - void ReadGeometry( Collada::Mesh* pMesh); + /** Reads the geometry library contents */ + void ReadGeometryLibrary(); - /** Reads a mesh from the geometry library */ - void ReadMesh( Collada::Mesh* pMesh); + /** Reads a geometry from the geometry library. */ + void ReadGeometry(Collada::Mesh *pMesh); - /** Reads a source element - a combination of raw data and an accessor defining + /** Reads a mesh from the geometry library */ + void ReadMesh(Collada::Mesh *pMesh); + + /** Reads a source element - a combination of raw data and an accessor defining * things that should not be redefinable. Yes, that's another rant. */ - void ReadSource(); + void ReadSource(); - /** Reads a data array holding a number of elements, and stores it in the global library. + /** Reads a data array holding a number of elements, and stores it in the global library. * Currently supported are array of floats and arrays of strings. */ - void ReadDataArray(); + void ReadDataArray(); - /** Reads an accessor and stores it in the global library under the given ID - + /** Reads an accessor and stores it in the global library under the given ID - * accessors use the ID of the parent element */ - void ReadAccessor( const std::string& pID); + void ReadAccessor(const std::string &pID); - /** Reads input declarations of per-vertex mesh data into the given mesh */ - void ReadVertexData( Collada::Mesh* pMesh); + /** Reads input declarations of per-vertex mesh data into the given mesh */ + void ReadVertexData(Collada::Mesh *pMesh); - /** Reads input declarations of per-index mesh data into the given mesh */ - void ReadIndexData( Collada::Mesh* pMesh); + /** Reads input declarations of per-index mesh data into the given mesh */ + void ReadIndexData(Collada::Mesh *pMesh); - /** Reads a single input channel element and stores it in the given array, if valid */ - void ReadInputChannel( std::vector& poChannels); + /** Reads a single input channel element and stores it in the given array, if valid */ + void ReadInputChannel(std::vector &poChannels); - /** Reads a

primitive index list and assembles the mesh data into the given mesh */ - size_t ReadPrimitives( Collada::Mesh* pMesh, std::vector& pPerIndexChannels, - size_t pNumPrimitives, const std::vector& pVCount, Collada::PrimitiveType pPrimType); + /** Reads a

primitive index list and assembles the mesh data into the given mesh */ + size_t ReadPrimitives(Collada::Mesh *pMesh, std::vector &pPerIndexChannels, + size_t pNumPrimitives, const std::vector &pVCount, Collada::PrimitiveType pPrimType); - /** Copies the data for a single primitive into the mesh, based on the InputChannels */ - void CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset, - Collada::Mesh* pMesh, std::vector& pPerIndexChannels, - size_t currentPrimitive, const std::vector& indices); + /** Copies the data for a single primitive into the mesh, based on the InputChannels */ + void CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset, + Collada::Mesh *pMesh, std::vector &pPerIndexChannels, + size_t currentPrimitive, const std::vector &indices); - /** Reads one triangle of a tristrip into the mesh */ - void ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Collada::Mesh* pMesh, - std::vector& pPerIndexChannels, size_t currentPrimitive, const std::vector& indices); + /** Reads one triangle of a tristrip into the mesh */ + void ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Collada::Mesh *pMesh, + std::vector &pPerIndexChannels, size_t currentPrimitive, const std::vector &indices); - /** Extracts a single object from an input channel and stores it in the appropriate mesh data array */ - void ExtractDataObjectFromChannel( const Collada::InputChannel& pInput, size_t pLocalIndex, Collada::Mesh* pMesh); + /** Extracts a single object from an input channel and stores it in the appropriate mesh data array */ + void ExtractDataObjectFromChannel(const Collada::InputChannel &pInput, size_t pLocalIndex, Collada::Mesh *pMesh); - /** Reads the library of node hierarchies and scene parts */ - void ReadSceneLibrary(); + /** Reads the library of node hierarchies and scene parts */ + void ReadSceneLibrary(); - /** Reads a scene node's contents including children and stores it in the given node */ - void ReadSceneNode( Collada::Node* pNode); + /** Reads a scene node's contents including children and stores it in the given node */ + void ReadSceneNode(Collada::Node *pNode); - /** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */ - void ReadNodeTransformation( Collada::Node* pNode, Collada::TransformType pType); + /** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */ + void ReadNodeTransformation(Collada::Node *pNode, Collada::TransformType pType); - /** Reads a mesh reference in a node and adds it to the node's mesh list */ - void ReadNodeGeometry( Collada::Node* pNode); + /** Reads a mesh reference in a node and adds it to the node's mesh list */ + void ReadNodeGeometry(Collada::Node *pNode); - /** Reads the collada scene */ - void ReadScene(); + /** Reads the collada scene */ + void ReadScene(); - // Processes bind_vertex_input and bind elements - void ReadMaterialVertexInputBinding( Collada::SemanticMappingTable& tbl); + // Processes bind_vertex_input and bind elements + void ReadMaterialVertexInputBinding(Collada::SemanticMappingTable &tbl); - /** Reads embedded textures from a ZAE archive*/ - void ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive); + /** Reads embedded textures from a ZAE archive*/ + void ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive); - protected: - /** Aborts the file reading with an exception */ - AI_WONT_RETURN void ThrowException( const std::string& pError) const AI_WONT_RETURN_SUFFIX; - void ReportWarning(const char* msg,...); +protected: + /** Aborts the file reading with an exception */ + AI_WONT_RETURN void ThrowException(const std::string &pError) const AI_WONT_RETURN_SUFFIX; + void ReportWarning(const char *msg, ...); - /** Skips all data until the end node of the current element */ - void SkipElement(); + /** Skips all data until the end node of the current element */ + void SkipElement(); - /** Skips all data until the end node of the given element */ - void SkipElement( const char* pElement); + /** Skips all data until the end node of the given element */ + void SkipElement(const char *pElement); - /** Compares the current xml element name to the given string and returns true if equal */ - bool IsElement( const char* pName) const; + /** Compares the current xml element name to the given string and returns true if equal */ + bool IsElement(const char *pName) const; - /** Tests for the opening tag of the given element, throws an exception if not found */ - void TestOpening( const char* pName); + /** Tests for the opening tag of the given element, throws an exception if not found */ + void TestOpening(const char *pName); - /** Tests for the closing tag of the given element, throws an exception if not found */ - void TestClosing( const char* pName); + /** Tests for the closing tag of the given element, throws an exception if not found */ + void TestClosing(const char *pName); - /** Checks the present element for the presence of the attribute, returns its index + /** Checks the present element for the presence of the attribute, returns its index or throws an exception if not found */ - int GetAttribute( const char* pAttr) const; + int GetAttribute(const char *pAttr) const; - /** Returns the index of the named attribute or -1 if not found. Does not throw, + /** Returns the index of the named attribute or -1 if not found. Does not throw, therefore useful for optional attributes */ - int TestAttribute( const char* pAttr) const; + int TestAttribute(const char *pAttr) const; - /** Reads the text contents of an element, throws an exception if not given. + /** Reads the text contents of an element, throws an exception if not given. Skips leading whitespace. */ - const char* GetTextContent(); + const char *GetTextContent(); - /** Reads the text contents of an element, returns NULL if not given. + /** Reads the text contents of an element, returns NULL if not given. Skips leading whitespace. */ - const char* TestTextContent(); + const char *TestTextContent(); - /** Reads a single bool from current text content */ - bool ReadBoolFromTextContent(); + /** Reads a single bool from current text content */ + bool ReadBoolFromTextContent(); - /** Reads a single float from current text content */ - ai_real ReadFloatFromTextContent(); + /** Reads a single float from current text content */ + ai_real ReadFloatFromTextContent(); - /** Calculates the resulting transformation from all the given transform steps */ - aiMatrix4x4 CalculateResultTransform( const std::vector& pTransforms) const; + /** Calculates the resulting transformation from all the given transform steps */ + aiMatrix4x4 CalculateResultTransform(const std::vector &pTransforms) const; - /** Determines the input data type for the given semantic string */ - Collada::InputType GetTypeForSemantic( const std::string& pSemantic); + /** Determines the input data type for the given semantic string */ + Collada::InputType GetTypeForSemantic(const std::string &pSemantic); - /** Finds the item in the given library by its reference, throws if not found */ - template const Type& ResolveLibraryReference( const std::map& pLibrary, const std::string& pURL) const; - - protected: - /** Filename, for a verbose error message */ - std::string mFileName; - - /** XML reader, member for everyday use */ - irr::io::IrrXMLReader* mReader; - - /** All data arrays found in the file by ID. Might be referred to by actually - everyone. Collada, you are a steaming pile of indirection. */ - typedef std::map DataLibrary; - DataLibrary mDataLibrary; - - /** Same for accessors which define how the data in a data array is accessed. */ - typedef std::map AccessorLibrary; - AccessorLibrary mAccessorLibrary; - - /** Mesh library: mesh by ID */ - typedef std::map MeshLibrary; - MeshLibrary mMeshLibrary; - - /** node library: root node of the hierarchy part by ID */ - typedef std::map NodeLibrary; - NodeLibrary mNodeLibrary; - - /** Image library: stores texture properties by ID */ - typedef std::map ImageLibrary; - ImageLibrary mImageLibrary; - - /** Effect library: surface attributes by ID */ - typedef std::map EffectLibrary; - EffectLibrary mEffectLibrary; - - /** Material library: surface material by ID */ - typedef std::map MaterialLibrary; - MaterialLibrary mMaterialLibrary; - - /** Light library: surface light by ID */ - typedef std::map LightLibrary; - LightLibrary mLightLibrary; - - /** Camera library: surface material by ID */ - typedef std::map CameraLibrary; - CameraLibrary mCameraLibrary; - - /** Controller library: joint controllers by ID */ - typedef std::map ControllerLibrary; - ControllerLibrary mControllerLibrary; - - /** Animation library: animation references by ID */ - typedef std::map AnimationLibrary; - AnimationLibrary mAnimationLibrary; - - /** Animation clip library: clip animation references by ID */ - typedef std::vector > > AnimationClipLibrary; - AnimationClipLibrary mAnimationClipLibrary; - - /** Pointer to the root node. Don't delete, it just points to one of - the nodes in the node library. */ - Collada::Node* mRootNode; - - /** Root animation container */ - Collada::Animation mAnims; - - /** Size unit: how large compared to a meter */ - ai_real mUnitSize; - - /** Which is the up vector */ - enum { UP_X, UP_Y, UP_Z } mUpDirection; - - /** Asset metadata (global for scene) */ - StringMetaData mAssetMetaData; - - /** Collada file format version */ - Collada::FormatVersion mFormat; - }; - - // ------------------------------------------------------------------------------------------------ - // Check for element match - inline bool ColladaParser::IsElement( const char* pName) const - { - ai_assert( mReader->getNodeType() == irr::io::EXN_ELEMENT); - return ::strcmp( mReader->getNodeName(), pName) == 0; - } - - // ------------------------------------------------------------------------------------------------ - // Finds the item in the given library by its reference, throws if not found + /** Finds the item in the given library by its reference, throws if not found */ template - const Type& ColladaParser::ResolveLibraryReference( const std::map& pLibrary, const std::string& pURL) const - { - typename std::map::const_iterator it = pLibrary.find( pURL); - if( it == pLibrary.end()) - ThrowException( Formatter::format() << "Unable to resolve library reference \"" << pURL << "\"." ); - return it->second; - } + const Type &ResolveLibraryReference(const std::map &pLibrary, const std::string &pURL) const; + +protected: + /** Filename, for a verbose error message */ + std::string mFileName; + + /** XML reader, member for everyday use */ + irr::io::IrrXMLReader *mReader; + + /** All data arrays found in the file by ID. Might be referred to by actually + everyone. Collada, you are a steaming pile of indirection. */ + typedef std::map DataLibrary; + DataLibrary mDataLibrary; + + /** Same for accessors which define how the data in a data array is accessed. */ + typedef std::map AccessorLibrary; + AccessorLibrary mAccessorLibrary; + + /** Mesh library: mesh by ID */ + typedef std::map MeshLibrary; + MeshLibrary mMeshLibrary; + + /** node library: root node of the hierarchy part by ID */ + typedef std::map NodeLibrary; + NodeLibrary mNodeLibrary; + + /** Image library: stores texture properties by ID */ + typedef std::map ImageLibrary; + ImageLibrary mImageLibrary; + + /** Effect library: surface attributes by ID */ + typedef std::map EffectLibrary; + EffectLibrary mEffectLibrary; + + /** Material library: surface material by ID */ + typedef std::map MaterialLibrary; + MaterialLibrary mMaterialLibrary; + + /** Light library: surface light by ID */ + typedef std::map LightLibrary; + LightLibrary mLightLibrary; + + /** Camera library: surface material by ID */ + typedef std::map CameraLibrary; + CameraLibrary mCameraLibrary; + + /** Controller library: joint controllers by ID */ + typedef std::map ControllerLibrary; + ControllerLibrary mControllerLibrary; + + /** Animation library: animation references by ID */ + typedef std::map AnimationLibrary; + AnimationLibrary mAnimationLibrary; + + /** Animation clip library: clip animation references by ID */ + typedef std::vector>> AnimationClipLibrary; + AnimationClipLibrary mAnimationClipLibrary; + + /** Pointer to the root node. Don't delete, it just points to one of + the nodes in the node library. */ + Collada::Node *mRootNode; + + /** Root animation container */ + Collada::Animation mAnims; + + /** Size unit: how large compared to a meter */ + ai_real mUnitSize; + + /** Which is the up vector */ + enum { UP_X, + UP_Y, + UP_Z } mUpDirection; + + /** Asset metadata (global for scene) */ + StringMetaData mAssetMetaData; + + /** Collada file format version */ + Collada::FormatVersion mFormat; +}; + +// ------------------------------------------------------------------------------------------------ +// Check for element match +inline bool ColladaParser::IsElement(const char *pName) const { + ai_assert(mReader->getNodeType() == irr::io::EXN_ELEMENT); + return ::strcmp(mReader->getNodeName(), pName) == 0; +} + +// ------------------------------------------------------------------------------------------------ +// Finds the item in the given library by its reference, throws if not found +template +const Type &ColladaParser::ResolveLibraryReference(const std::map &pLibrary, const std::string &pURL) const { + typename std::map::const_iterator it = pLibrary.find(pURL); + if (it == pLibrary.end()) + ThrowException(Formatter::format() << "Unable to resolve library reference \"" << pURL << "\"."); + return it->second; +} } // end of namespace Assimp From ff9f3b86084c3b502d9dd4fefe3d87275f4df57d Mon Sep 17 00:00:00 2001 From: RichardTea <31507749+RichardTea@users.noreply.github.com> Date: Wed, 29 Apr 2020 17:17:46 +0100 Subject: [PATCH 14/39] Collada: Ensure has unique id Use the "id" for mesh names by default. Set option AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES to use the mesh "name" instead --- code/CMakeLists.txt | 1 + code/Collada/ColladaExporter.cpp | 104 +++++++++++++++++++++------- code/Collada/ColladaExporter.h | 12 ++-- code/Collada/ColladaHelper.h | 4 +- code/Collada/ColladaLoader.cpp | 18 ++++- code/Collada/ColladaParser.cpp | 101 ++++++++++++++------------- code/Collada/ColladaParser.h | 16 ++--- include/assimp/ColladaMetaData.h | 53 ++++++++++++++ include/assimp/config.h.in | 6 +- test/unit/utColladaImportExport.cpp | 53 +++++++++++++- 10 files changed, 274 insertions(+), 94 deletions(-) create mode 100644 include/assimp/ColladaMetaData.h diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 6afed40f9..f626a51e3 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -66,6 +66,7 @@ SET( PUBLIC_HEADERS ${HEADER_PATH}/color4.h ${HEADER_PATH}/color4.inl ${CMAKE_CURRENT_BINARY_DIR}/../include/assimp/config.h + ${HEADER_PATH}/ColladaMetaData.h ${HEADER_PATH}/commonMetaData.h ${HEADER_PATH}/defs.h ${HEADER_PATH}/Defines.h diff --git a/code/Collada/ColladaExporter.cpp b/code/Collada/ColladaExporter.cpp index 0026fda26..a502e728c 100644 --- a/code/Collada/ColladaExporter.cpp +++ b/code/Collada/ColladaExporter.cpp @@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ColladaExporter.h" #include +#include #include #include #include @@ -115,7 +116,7 @@ static const std::string XMLIDEncode(const std::string &name) { if (strchr(XML_ID_CHARS, *it) != nullptr) { idEncoded << *it; } else { - // Select placeholder character based on invalid character to prevent name collisions + // Select placeholder character based on invalid character to reduce ID collisions idEncoded << XML_ID_CHARS[(*it) % XML_ID_CHARS_COUNT]; } } @@ -854,8 +855,8 @@ void ColladaExporter::WriteControllerLibrary() { // Writes a skin controller of the given mesh void ColladaExporter::WriteController(size_t pIndex) { const aiMesh *mesh = mScene->mMeshes[pIndex]; - const std::string idstr = mesh->mName.length == 0 ? GetMeshId(pIndex) : mesh->mName.C_Str(); - const std::string idstrEscaped = XMLIDEncode(idstr); + const std::string idstr = GetMeshUniqueId(pIndex); + const std::string namestr = GetMeshName(pIndex); if (mesh->mNumFaces == 0 || mesh->mNumVertices == 0) return; @@ -863,11 +864,11 @@ void ColladaExporter::WriteController(size_t pIndex) { if (mesh->mNumBones == 0) return; - mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); // bind pose matrix @@ -884,10 +885,10 @@ void ColladaExporter::WriteController(size_t pIndex) { PopTag(); mOutput << startstr << "" << endstr; - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "mNumBones << "\">"; + mOutput << startstr << "mNumBones << "\">"; for (size_t i = 0; i < mesh->mNumBones; ++i) mOutput << XMLIDEncode(mesh->mBones[i]->mName.C_Str()) << " "; @@ -897,7 +898,7 @@ void ColladaExporter::WriteController(size_t pIndex) { mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "mNumBones << "\" stride=\"" << 1 << "\">" << endstr; + mOutput << startstr << "mNumBones << "\" stride=\"" << 1 << "\">" << endstr; PushTag(); mOutput << startstr << "" << endstr; @@ -934,8 +935,8 @@ void ColladaExporter::WriteController(size_t pIndex) { mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "" << endstr; - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PopTag(); mOutput << startstr << "" << endstr; @@ -943,8 +944,8 @@ void ColladaExporter::WriteController(size_t pIndex) { mOutput << startstr << "mNumVertices << "\">" << endstr; PushTag(); - mOutput << startstr << "" << endstr; - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; mOutput << startstr << ""; @@ -1019,9 +1020,8 @@ void ColladaExporter::WriteGeometryLibrary() { // Writes the given mesh void ColladaExporter::WriteGeometry(size_t pIndex) { const aiMesh *mesh = mScene->mMeshes[pIndex]; - const std::string idstr = mesh->mName.length == 0 ? GetMeshId(pIndex) : mesh->mName.C_Str(); - const std::string geometryName = XMLEscape(idstr); - const std::string geometryId = XMLIDEncode(idstr); + const std::string geometryName = GetMeshName(pIndex); + const std::string geometryId = GetMeshUniqueId(pIndex); if (mesh->mNumFaces == 0 || mesh->mNumVertices == 0) return; @@ -1034,15 +1034,15 @@ void ColladaExporter::WriteGeometry(size_t pIndex) { PushTag(); // Positions - WriteFloatArray(idstr + "-positions", FloatType_Vector, (ai_real *)mesh->mVertices, mesh->mNumVertices); + WriteFloatArray(geometryId + "-positions", FloatType_Vector, (ai_real *)mesh->mVertices, mesh->mNumVertices); // Normals, if any if (mesh->HasNormals()) - WriteFloatArray(idstr + "-normals", FloatType_Vector, (ai_real *)mesh->mNormals, mesh->mNumVertices); + WriteFloatArray(geometryId + "-normals", FloatType_Vector, (ai_real *)mesh->mNormals, mesh->mNumVertices); // texture coords for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { if (mesh->HasTextureCoords(static_cast(a))) { - WriteFloatArray(idstr + "-tex" + to_string(a), mesh->mNumUVComponents[a] == 3 ? FloatType_TexCoord3 : FloatType_TexCoord2, + WriteFloatArray(geometryId + "-tex" + to_string(a), mesh->mNumUVComponents[a] == 3 ? FloatType_TexCoord3 : FloatType_TexCoord2, (ai_real *)mesh->mTextureCoords[a], mesh->mNumVertices); } } @@ -1050,7 +1050,7 @@ void ColladaExporter::WriteGeometry(size_t pIndex) { // vertex colors for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { if (mesh->HasVertexColors(static_cast(a))) - WriteFloatArray(idstr + "-color" + to_string(a), FloatType_Color, (ai_real *)mesh->mColors[a], mesh->mNumVertices); + WriteFloatArray(geometryId + "-color" + to_string(a), FloatType_Color, (ai_real *)mesh->mColors[a], mesh->mNumVertices); } // assemble vertex structure @@ -1530,13 +1530,13 @@ void ColladaExporter::WriteNode(const aiScene *pScene, aiNode *pNode) { const std::string node_name = XMLEscape(pNode->mName.data); mOutput << startstr << "" << endstr; PushTag(); @@ -1595,14 +1595,14 @@ void ColladaExporter::WriteNode(const aiScene *pScene, aiNode *pNode) { if (mesh->mNumFaces == 0 || mesh->mNumVertices == 0) continue; - const std::string meshName = mesh->mName.length == 0 ? GetMeshId(pNode->mMeshes[a]) : mesh->mName.C_Str(); + const std::string meshId = GetMeshUniqueId(pNode->mMeshes[a]); if (mesh->mNumBones == 0) { - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); } else { mOutput << startstr - << "" + << "" << endstr; PushTag(); @@ -1649,5 +1649,59 @@ void ColladaExporter::WriteNode(const aiScene *pScene, aiNode *pNode) { mOutput << startstr << "" << endstr; } +/// Get or Create a unique mesh ID string for the given mesh index +std::string Assimp::ColladaExporter::GetMeshUniqueId(size_t pIndex) { + auto meshId = mMeshIdMap.find(pIndex); + if (meshId != mMeshIdMap.cend()) + return meshId->second; + + // Not seen this mesh before, create and add + return AddMeshIndexToMaps(pIndex, true); +} + +std::string Assimp::ColladaExporter::GetMeshName(size_t pIndex) { + auto meshName = mMeshNameMap.find(pIndex); + if (meshName != mMeshNameMap.cend()) + return meshName->second; + + // Not seen this mesh before, create and add + return AddMeshIndexToMaps(pIndex, false); +} + +inline bool ValueIsUnique(const std::map &map, const std::string &value) { + for (const auto &map_val : map) { + if (value == map_val.second) + return false; + } + return true; +} + +// Add the mesh index to both Id and Name maps and return either Id or Name +std::string Assimp::ColladaExporter::AddMeshIndexToMaps(size_t pIndex, bool meshId) { + const aiMesh *mesh = mScene->mMeshes[pIndex]; + std::string idStr = mesh->mName.length == 0 ? std::string("meshId_") + to_string(pIndex) : XMLIDEncode(mesh->mName.C_Str()); + // Ensure is unique. Relatively slow but will only happen once per mesh + if (!ValueIsUnique(mMeshIdMap, idStr)) { + // Select a number to append + size_t postfix = 1; + idStr.append("_"); + while (!ValueIsUnique(mMeshIdMap, idStr + to_string(postfix))) { + ++postfix; + } + idStr = idStr + to_string(postfix); + } + // Add to map + mMeshIdMap.insert(std::make_pair(pIndex, idStr)); + + // Add name to map + const std::string nameStr = mesh->mName.length == 0 ? idStr : XMLEscape(mesh->mName.C_Str()); + mMeshNameMap.insert(std::make_pair(pIndex, nameStr)); + + if (meshId) + return idStr; + else + return nameStr; +} + #endif #endif diff --git a/code/Collada/ColladaExporter.h b/code/Collada/ColladaExporter.h index fa7e6ee80..d75d2d355 100644 --- a/code/Collada/ColladaExporter.h +++ b/code/Collada/ColladaExporter.h @@ -145,10 +145,14 @@ protected: startstr.erase(startstr.length() - 2); } - /// Creates a mesh ID for the given mesh - std::string GetMeshId(size_t pIndex) const { - return std::string("meshId") + to_string(pIndex); - } + /// Get or Create a unique mesh ID string for the given mesh index + std::string GetMeshUniqueId(size_t pIndex); + std::string GetMeshName(size_t pIndex); + +private: + std::string AddMeshIndexToMaps(size_t pIndex, bool meshId); + mutable std::map mMeshIdMap; // Cache of encoded unique IDs + mutable std::map mMeshNameMap; // Cache of encoded mesh names public: /// Stringstream to write all output into diff --git a/code/Collada/ColladaHelper.h b/code/Collada/ColladaHelper.h index 3eb073cd9..f41691606 100644 --- a/code/Collada/ColladaHelper.h +++ b/code/Collada/ColladaHelper.h @@ -339,11 +339,13 @@ struct SubMesh { /** Contains data for a single mesh */ struct Mesh { - Mesh() { + Mesh(const std::string &id) : + mId(id) { for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) mNumUVComponents[i] = 2; } + const std::string mId; std::string mName; // just to check if there's some sophisticated addressing involved... diff --git a/code/Collada/ColladaLoader.cpp b/code/Collada/ColladaLoader.cpp index 44d65e40d..c76954fdf 100644 --- a/code/Collada/ColladaLoader.cpp +++ b/code/Collada/ColladaLoader.cpp @@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ColladaLoader.h" #include "ColladaParser.h" +#include #include #include #include @@ -265,6 +266,13 @@ aiNode *ColladaLoader::BuildHierarchy(const ColladaParser &pParser, const Collad // find a name for the new node. It's more complicated than you might think node->mName.Set(FindNameForNode(pNode)); + // if we're not using the unique IDs, hold onto them for reference and export + if (useColladaName) { + if (!pNode->mID.empty()) + node->mMetaData->Add(AI_METADATA_COLLADA_ID, aiString(pNode->mID)); + if (!pNode->mSID.empty()) + node->mMetaData->Add(AI_METADATA_COLLADA_SID, aiString(pNode->mSID)); + } // calculate the transformation matrix for it node->mTransformation = pParser.CalculateResultTransform(pNode->mTransforms); @@ -603,7 +611,11 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::M const Collada::Controller *pSrcController, size_t pStartVertex, size_t pStartFace) { std::unique_ptr dstMesh(new aiMesh); - dstMesh->mName = pSrcMesh->mName; + if (useColladaName) { + dstMesh->mName = pSrcMesh->mName; + } else { + dstMesh->mName = pSrcMesh->mId; + } // count the vertices addressed by its faces const size_t numVertices = std::accumulate(pSrcMesh->mFaceSize.begin() + pStartFace, @@ -700,10 +712,10 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::M for (unsigned int i = 0; i < targetData.mStrings.size(); ++i) { const Collada::Mesh *targetMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, targetData.mStrings.at(i)); - aiMesh *aimesh = findMesh(targetMesh->mName); + aiMesh *aimesh = findMesh(useColladaName ? targetMesh->mName : targetMesh->mId); if (!aimesh) { if (targetMesh->mSubMeshes.size() > 1) { - throw DeadlyImportError("Morhing target mesh must be a single"); + throw DeadlyImportError("Morphing target mesh must be a single"); } aimesh = CreateMesh(pParser, targetMesh, targetMesh->mSubMeshes.at(0), NULL, 0, 0); mTargetMeshes.push_back(aimesh); diff --git a/code/Collada/ColladaParser.cpp b/code/Collada/ColladaParser.cpp index 5080094c1..d83980929 100644 --- a/code/Collada/ColladaParser.cpp +++ b/code/Collada/ColladaParser.cpp @@ -1716,18 +1716,25 @@ void ColladaParser::ReadGeometryLibrary() { // TODO: (thom) support SIDs // ai_assert( TestAttribute( "sid") == -1); - // create a mesh and store it in the library under its ID - Mesh *mesh = new Mesh; - mMeshLibrary[id] = mesh; + // create a mesh and store it in the library under its (resolved) ID + // Skip and warn if ID is not unique + if (mMeshLibrary.find(id) == mMeshLibrary.cend()) { + std::unique_ptr mesh(new Mesh(id)); - // read the mesh name if it exists - const int nameIndex = TestAttribute("name"); - if (nameIndex != -1) { - mesh->mName = mReader->getAttributeValue(nameIndex); + // read the mesh name if it exists + const int nameIndex = TestAttribute("name"); + if (nameIndex != -1) { + mesh->mName = mReader->getAttributeValue(nameIndex); + } + + // read on from there + ReadGeometry(*mesh); + // Read successfully, add to library + mMeshLibrary.insert({ id, mesh.release() }); + } else { + ASSIMP_LOG_ERROR_F("Collada: Skipped duplicate geometry id: \"", id, "\""); + SkipElement(); } - - // read on from there - ReadGeometry(mesh); } else { // ignore the rest SkipElement(); @@ -1743,7 +1750,7 @@ void ColladaParser::ReadGeometryLibrary() { // ------------------------------------------------------------------------------------------------ // Reads a geometry from the geometry library. -void ColladaParser::ReadGeometry(Collada::Mesh *pMesh) { +void ColladaParser::ReadGeometry(Collada::Mesh &pMesh) { if (mReader->isEmptyElement()) return; @@ -1767,7 +1774,7 @@ void ColladaParser::ReadGeometry(Collada::Mesh *pMesh) { // ------------------------------------------------------------------------------------------------ // Reads a mesh from the geometry library -void ColladaParser::ReadMesh(Mesh *pMesh) { +void ColladaParser::ReadMesh(Mesh &pMesh) { if (mReader->isEmptyElement()) return; @@ -1997,16 +2004,16 @@ void ColladaParser::ReadAccessor(const std::string &pID) { // ------------------------------------------------------------------------------------------------ // Reads input declarations of per-vertex mesh data into the given mesh -void ColladaParser::ReadVertexData(Mesh *pMesh) { +void ColladaParser::ReadVertexData(Mesh &pMesh) { // extract the ID of the element. Not that we care, but to catch strange referencing schemes we should warn about int attrID = GetAttribute("id"); - pMesh->mVertexID = mReader->getAttributeValue(attrID); + pMesh.mVertexID = mReader->getAttributeValue(attrID); // a number of elements while (mReader->read()) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { if (IsElement("input")) { - ReadInputChannel(pMesh->mPerVertexData); + ReadInputChannel(pMesh.mPerVertexData); } else { ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag "); } @@ -2021,7 +2028,7 @@ void ColladaParser::ReadVertexData(Mesh *pMesh) { // ------------------------------------------------------------------------------------------------ // Reads input declarations of per-index mesh data into the given mesh -void ColladaParser::ReadIndexData(Mesh *pMesh) { +void ColladaParser::ReadIndexData(Mesh &pMesh) { std::vector vcount; std::vector perIndexData; @@ -2111,7 +2118,7 @@ void ColladaParser::ReadIndexData(Mesh *pMesh) { // only when we're done reading all

tags (and thus know the final vertex count) can we commit the submesh subgroup.mNumFaces = actualPrimitives; - pMesh->mSubMeshes.push_back(subgroup); + pMesh.mSubMeshes.push_back(subgroup); } // ------------------------------------------------------------------------------------------------ @@ -2158,7 +2165,7 @@ void ColladaParser::ReadInputChannel(std::vector &poChannels) { // ------------------------------------------------------------------------------------------------ // Reads a

primitive index list and assembles the mesh data into the given mesh -size_t ColladaParser::ReadPrimitives(Mesh *pMesh, std::vector &pPerIndexChannels, +size_t ColladaParser::ReadPrimitives(Mesh &pMesh, std::vector &pPerIndexChannels, size_t pNumPrimitives, const std::vector &pVCount, PrimitiveType pPrimType) { // determine number of indices coming per vertex // find the offset index for all per-vertex channels @@ -2220,7 +2227,7 @@ size_t ColladaParser::ReadPrimitives(Mesh *pMesh, std::vector &pPe ThrowException("Expected different index count in

element."); // find the data for all sources - for (std::vector::iterator it = pMesh->mPerVertexData.begin(); it != pMesh->mPerVertexData.end(); ++it) { + for (std::vector::iterator it = pMesh.mPerVertexData.begin(); it != pMesh.mPerVertexData.end(); ++it) { InputChannel &input = *it; if (input.mResolved) continue; @@ -2241,7 +2248,7 @@ size_t ColladaParser::ReadPrimitives(Mesh *pMesh, std::vector &pPe // ignore vertex pointer, it doesn't refer to an accessor if (input.mType == IT_Vertex) { // warn if the vertex channel does not refer to the element in the same mesh - if (input.mAccessor != pMesh->mVertexID) + if (input.mAccessor != pMesh.mVertexID) ThrowException("Unsupported vertex referencing scheme."); continue; } @@ -2268,8 +2275,8 @@ size_t ColladaParser::ReadPrimitives(Mesh *pMesh, std::vector &pPe numPrimitives = numberOfVertices - 1; } - pMesh->mFaceSize.reserve(numPrimitives); - pMesh->mFacePosIndices.reserve(indices.size() / numOffsets); + pMesh.mFaceSize.reserve(numPrimitives); + pMesh.mFacePosIndices.reserve(indices.size() / numOffsets); size_t polylistStartVertex = 0; for (size_t currentPrimitive = 0; currentPrimitive < numPrimitives; currentPrimitive++) { @@ -2314,7 +2321,7 @@ size_t ColladaParser::ReadPrimitives(Mesh *pMesh, std::vector &pPe } // store the face size to later reconstruct the face from - pMesh->mFaceSize.push_back(numPoints); + pMesh.mFaceSize.push_back(numPoints); } // if I ever get my hands on that guy who invented this steaming pile of indirection... @@ -2325,7 +2332,7 @@ size_t ColladaParser::ReadPrimitives(Mesh *pMesh, std::vector &pPe ///@note This function willn't work correctly if both PerIndex and PerVertex channels have same channels. ///For example if TEXCOORD present in both and tags this function will create wrong uv coordinates. ///It's not clear from COLLADA documentation is this allowed or not. For now only exporter fixed to avoid such behavior -void ColladaParser::CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset, Mesh *pMesh, std::vector &pPerIndexChannels, size_t currentPrimitive, const std::vector &indices) { +void ColladaParser::CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset, Mesh &pMesh, std::vector &pPerIndexChannels, size_t currentPrimitive, const std::vector &indices) { // calculate the base offset of the vertex whose attributes we ant to copy size_t baseOffset = currentPrimitive * numOffsets * numPoints + currentVertex * numOffsets; @@ -2333,17 +2340,17 @@ void ColladaParser::CopyVertex(size_t currentVertex, size_t numOffsets, size_t n ai_assert((baseOffset + numOffsets - 1) < indices.size()); // extract per-vertex channels using the global per-vertex offset - for (std::vector::iterator it = pMesh->mPerVertexData.begin(); it != pMesh->mPerVertexData.end(); ++it) + for (std::vector::iterator it = pMesh.mPerVertexData.begin(); it != pMesh.mPerVertexData.end(); ++it) ExtractDataObjectFromChannel(*it, indices[baseOffset + perVertexOffset], pMesh); // and extract per-index channels using there specified offset for (std::vector::iterator it = pPerIndexChannels.begin(); it != pPerIndexChannels.end(); ++it) ExtractDataObjectFromChannel(*it, indices[baseOffset + it->mOffset], pMesh); // store the vertex-data index for later assignment of bone vertex weights - pMesh->mFacePosIndices.push_back(indices[baseOffset + perVertexOffset]); + pMesh.mFacePosIndices.push_back(indices[baseOffset + perVertexOffset]); } -void ColladaParser::ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Mesh *pMesh, std::vector &pPerIndexChannels, size_t currentPrimitive, const std::vector &indices) { +void ColladaParser::ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Mesh &pMesh, std::vector &pPerIndexChannels, size_t currentPrimitive, const std::vector &indices) { if (currentPrimitive % 2 != 0) { //odd tristrip triangles need their indices mangled, to preserve winding direction CopyVertex(1, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices); @@ -2358,7 +2365,7 @@ void ColladaParser::ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, // ------------------------------------------------------------------------------------------------ // Extracts a single object from an input channel and stores it in the appropriate mesh data array -void ColladaParser::ExtractDataObjectFromChannel(const InputChannel &pInput, size_t pLocalIndex, Mesh *pMesh) { +void ColladaParser::ExtractDataObjectFromChannel(const InputChannel &pInput, size_t pLocalIndex, Mesh &pMesh) { // ignore vertex referrer - we handle them that separate if (pInput.mType == IT_Vertex) return; @@ -2380,40 +2387,40 @@ void ColladaParser::ExtractDataObjectFromChannel(const InputChannel &pInput, siz switch (pInput.mType) { case IT_Position: // ignore all position streams except 0 - there can be only one position if (pInput.mIndex == 0) - pMesh->mPositions.push_back(aiVector3D(obj[0], obj[1], obj[2])); + pMesh.mPositions.push_back(aiVector3D(obj[0], obj[1], obj[2])); else ASSIMP_LOG_ERROR("Collada: just one vertex position stream supported"); break; case IT_Normal: // pad to current vertex count if necessary - if (pMesh->mNormals.size() < pMesh->mPositions.size() - 1) - pMesh->mNormals.insert(pMesh->mNormals.end(), pMesh->mPositions.size() - pMesh->mNormals.size() - 1, aiVector3D(0, 1, 0)); + if (pMesh.mNormals.size() < pMesh.mPositions.size() - 1) + pMesh.mNormals.insert(pMesh.mNormals.end(), pMesh.mPositions.size() - pMesh.mNormals.size() - 1, aiVector3D(0, 1, 0)); // ignore all normal streams except 0 - there can be only one normal if (pInput.mIndex == 0) - pMesh->mNormals.push_back(aiVector3D(obj[0], obj[1], obj[2])); + pMesh.mNormals.push_back(aiVector3D(obj[0], obj[1], obj[2])); else ASSIMP_LOG_ERROR("Collada: just one vertex normal stream supported"); break; case IT_Tangent: // pad to current vertex count if necessary - if (pMesh->mTangents.size() < pMesh->mPositions.size() - 1) - pMesh->mTangents.insert(pMesh->mTangents.end(), pMesh->mPositions.size() - pMesh->mTangents.size() - 1, aiVector3D(1, 0, 0)); + if (pMesh.mTangents.size() < pMesh.mPositions.size() - 1) + pMesh.mTangents.insert(pMesh.mTangents.end(), pMesh.mPositions.size() - pMesh.mTangents.size() - 1, aiVector3D(1, 0, 0)); // ignore all tangent streams except 0 - there can be only one tangent if (pInput.mIndex == 0) - pMesh->mTangents.push_back(aiVector3D(obj[0], obj[1], obj[2])); + pMesh.mTangents.push_back(aiVector3D(obj[0], obj[1], obj[2])); else ASSIMP_LOG_ERROR("Collada: just one vertex tangent stream supported"); break; case IT_Bitangent: // pad to current vertex count if necessary - if (pMesh->mBitangents.size() < pMesh->mPositions.size() - 1) - pMesh->mBitangents.insert(pMesh->mBitangents.end(), pMesh->mPositions.size() - pMesh->mBitangents.size() - 1, aiVector3D(0, 0, 1)); + if (pMesh.mBitangents.size() < pMesh.mPositions.size() - 1) + pMesh.mBitangents.insert(pMesh.mBitangents.end(), pMesh.mPositions.size() - pMesh.mBitangents.size() - 1, aiVector3D(0, 0, 1)); // ignore all bitangent streams except 0 - there can be only one bitangent if (pInput.mIndex == 0) - pMesh->mBitangents.push_back(aiVector3D(obj[0], obj[1], obj[2])); + pMesh.mBitangents.push_back(aiVector3D(obj[0], obj[1], obj[2])); else ASSIMP_LOG_ERROR("Collada: just one vertex bitangent stream supported"); break; @@ -2421,13 +2428,13 @@ void ColladaParser::ExtractDataObjectFromChannel(const InputChannel &pInput, siz // up to 4 texture coord sets are fine, ignore the others if (pInput.mIndex < AI_MAX_NUMBER_OF_TEXTURECOORDS) { // pad to current vertex count if necessary - if (pMesh->mTexCoords[pInput.mIndex].size() < pMesh->mPositions.size() - 1) - pMesh->mTexCoords[pInput.mIndex].insert(pMesh->mTexCoords[pInput.mIndex].end(), - pMesh->mPositions.size() - pMesh->mTexCoords[pInput.mIndex].size() - 1, aiVector3D(0, 0, 0)); + if (pMesh.mTexCoords[pInput.mIndex].size() < pMesh.mPositions.size() - 1) + pMesh.mTexCoords[pInput.mIndex].insert(pMesh.mTexCoords[pInput.mIndex].end(), + pMesh.mPositions.size() - pMesh.mTexCoords[pInput.mIndex].size() - 1, aiVector3D(0, 0, 0)); - pMesh->mTexCoords[pInput.mIndex].push_back(aiVector3D(obj[0], obj[1], obj[2])); + pMesh.mTexCoords[pInput.mIndex].push_back(aiVector3D(obj[0], obj[1], obj[2])); if (0 != acc.mSubOffset[2] || 0 != acc.mSubOffset[3]) /* hack ... consider cleaner solution */ - pMesh->mNumUVComponents[pInput.mIndex] = 3; + pMesh.mNumUVComponents[pInput.mIndex] = 3; } else { ASSIMP_LOG_ERROR("Collada: too many texture coordinate sets. Skipping."); } @@ -2436,15 +2443,15 @@ void ColladaParser::ExtractDataObjectFromChannel(const InputChannel &pInput, siz // up to 4 color sets are fine, ignore the others if (pInput.mIndex < AI_MAX_NUMBER_OF_COLOR_SETS) { // pad to current vertex count if necessary - if (pMesh->mColors[pInput.mIndex].size() < pMesh->mPositions.size() - 1) - pMesh->mColors[pInput.mIndex].insert(pMesh->mColors[pInput.mIndex].end(), - pMesh->mPositions.size() - pMesh->mColors[pInput.mIndex].size() - 1, aiColor4D(0, 0, 0, 1)); + if (pMesh.mColors[pInput.mIndex].size() < pMesh.mPositions.size() - 1) + pMesh.mColors[pInput.mIndex].insert(pMesh.mColors[pInput.mIndex].end(), + pMesh.mPositions.size() - pMesh.mColors[pInput.mIndex].size() - 1, aiColor4D(0, 0, 0, 1)); aiColor4D result(0, 0, 0, 1); for (size_t i = 0; i < pInput.mResolved->mSize; ++i) { result[static_cast(i)] = obj[pInput.mResolved->mSubOffset[i]]; } - pMesh->mColors[pInput.mIndex].push_back(result); + pMesh.mColors[pInput.mIndex].push_back(result); } else { ASSIMP_LOG_ERROR("Collada: too many vertex color sets. Skipping."); } diff --git a/code/Collada/ColladaParser.h b/code/Collada/ColladaParser.h index 861a65256..a84a59354 100644 --- a/code/Collada/ColladaParser.h +++ b/code/Collada/ColladaParser.h @@ -174,10 +174,10 @@ protected: void ReadGeometryLibrary(); /** Reads a geometry from the geometry library. */ - void ReadGeometry(Collada::Mesh *pMesh); + void ReadGeometry(Collada::Mesh &pMesh); /** Reads a mesh from the geometry library */ - void ReadMesh(Collada::Mesh *pMesh); + void ReadMesh(Collada::Mesh &pMesh); /** Reads a source element - a combination of raw data and an accessor defining * things that should not be redefinable. Yes, that's another rant. @@ -195,29 +195,29 @@ protected: void ReadAccessor(const std::string &pID); /** Reads input declarations of per-vertex mesh data into the given mesh */ - void ReadVertexData(Collada::Mesh *pMesh); + void ReadVertexData(Collada::Mesh &pMesh); /** Reads input declarations of per-index mesh data into the given mesh */ - void ReadIndexData(Collada::Mesh *pMesh); + void ReadIndexData(Collada::Mesh &pMesh); /** Reads a single input channel element and stores it in the given array, if valid */ void ReadInputChannel(std::vector &poChannels); /** Reads a

primitive index list and assembles the mesh data into the given mesh */ - size_t ReadPrimitives(Collada::Mesh *pMesh, std::vector &pPerIndexChannels, + size_t ReadPrimitives(Collada::Mesh &pMesh, std::vector &pPerIndexChannels, size_t pNumPrimitives, const std::vector &pVCount, Collada::PrimitiveType pPrimType); /** Copies the data for a single primitive into the mesh, based on the InputChannels */ void CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset, - Collada::Mesh *pMesh, std::vector &pPerIndexChannels, + Collada::Mesh &pMesh, std::vector &pPerIndexChannels, size_t currentPrimitive, const std::vector &indices); /** Reads one triangle of a tristrip into the mesh */ - void ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Collada::Mesh *pMesh, + void ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Collada::Mesh &pMesh, std::vector &pPerIndexChannels, size_t currentPrimitive, const std::vector &indices); /** Extracts a single object from an input channel and stores it in the appropriate mesh data array */ - void ExtractDataObjectFromChannel(const Collada::InputChannel &pInput, size_t pLocalIndex, Collada::Mesh *pMesh); + void ExtractDataObjectFromChannel(const Collada::InputChannel &pInput, size_t pLocalIndex, Collada::Mesh &pMesh); /** Reads the library of node hierarchies and scene parts */ void ReadSceneLibrary(); diff --git a/include/assimp/ColladaMetaData.h b/include/assimp/ColladaMetaData.h new file mode 100644 index 000000000..4288692c6 --- /dev/null +++ b/include/assimp/ColladaMetaData.h @@ -0,0 +1,53 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +/** @file ColladaMetaData.h + * Declares common metadata constants used by Collada files + */ +#pragma once +#ifndef AI_COLLADAMETADATA_H_INC +#define AI_COLLADAMETADATA_H_INC + +#define AI_METADATA_COLLADA_ID "COLLADA_ID" +#define AI_METADATA_COLLADA_SID "COLLADA_SID" + +#endif diff --git a/include/assimp/config.h.in b/include/assimp/config.h.in index e2f2a3888..c26dcc77f 100644 --- a/include/assimp/config.h.in +++ b/include/assimp/config.h.in @@ -1030,10 +1030,10 @@ enum aiComponent #define AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION "IMPORT_COLLADA_IGNORE_UP_DIRECTION" // --------------------------------------------------------------------------- -/** @brief Specifies whether the Collada loader should use Collada names as node names. +/** @brief Specifies whether the Collada loader should use Collada names. * - * If this property is set to true, the Collada names will be used as the - * node name. The default is to use the id tag (resp. sid tag, if no id tag is present) + * If this property is set to true, the Collada names will be used as the node and + * mesh names. The default is to use the id tag (resp. sid tag, if no id tag is present) * instead. * Property type: Bool. Default value: false. */ diff --git a/test/unit/utColladaImportExport.cpp b/test/unit/utColladaImportExport.cpp index 549ff68fb..5c2f801db 100644 --- a/test/unit/utColladaImportExport.cpp +++ b/test/unit/utColladaImportExport.cpp @@ -44,13 +44,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include using namespace Assimp; class utColladaImportExport : public AbstractImportExportBase { public: - virtual bool importerTest() { + virtual bool importerTest() final { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/duck.dae", aiProcess_ValidateDataStructure); if (scene == nullptr) @@ -80,15 +81,61 @@ public: return true; } + + void ImportAndCheckIds(const char *file, size_t meshCount) { + // Import the Collada using the 'default' where mesh names are the ids + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(file, aiProcess_ValidateDataStructure); + ASSERT_TRUE(scene != nullptr) << "Fatal: could not re-import " << file; + EXPECT_EQ(meshCount, scene->mNumMeshes) << "in " << file; + + // Check the mesh ids are unique + std::map meshNameMap; + for (size_t idx = 0; idx < scene->mNumMeshes; ++idx) { + std::string meshName(scene->mMeshes[idx]->mName.C_Str()); + const auto result = meshNameMap.insert(std::make_pair(meshName, idx)); + EXPECT_TRUE(result.second) << "Duplicate name: " << meshName << " index " << result.first->second; + } + } }; -TEST_F(utColladaImportExport, importBlenFromFileTest) { +TEST_F(utColladaImportExport, importDaeFromFileTest) { EXPECT_TRUE(importerTest()); } +TEST_F(utColladaImportExport, exporterUniqueIdsTest) { + Assimp::Importer importer; + Assimp::Exporter exporter; + const char *outFileEmpty = "exportMeshIdTest_empty_out.dae"; + const char *outFileNamed = "exportMeshIdTest_named_out.dae"; + + // Load a sample file containing multiple meshes + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/teapots.DAE", aiProcess_ValidateDataStructure); + + ASSERT_TRUE(scene != nullptr) << "Fatal: could not import teapots.DAE!"; + ASSERT_EQ(3u, scene->mNumMeshes) << "Fatal: teapots.DAE initial load failed"; + + // Clear the mesh names + for (size_t idx = 0; idx < scene->mNumMeshes; ++idx) { + scene->mMeshes[idx]->mName.Clear(); + } + ASSERT_EQ(AI_SUCCESS, exporter.Export(scene, "collada", outFileEmpty)) << "Fatal: Could not export un-named meshes file"; + + ImportAndCheckIds(outFileEmpty, 3); + + // Force the meshes to have the same non-empty name + aiString testName("test_mesh"); + for (size_t idx = 0; idx < scene->mNumMeshes; ++idx) { + scene->mMeshes[idx]->mName = testName; + } + ASSERT_EQ(AI_SUCCESS, exporter.Export(scene, "collada", outFileNamed)) << "Fatal: Could not export named meshes file"; + + ImportAndCheckIds(outFileNamed, 3); +} + class utColladaZaeImportExport : public AbstractImportExportBase { public: - virtual bool importerTest() { + virtual bool importerTest() final { { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/duck.zae", aiProcess_ValidateDataStructure); From 083ebdbc2ece2f4dd071e5439ab848ffade8a3c2 Mon Sep 17 00:00:00 2001 From: RichardTea <31507749+RichardTea@users.noreply.github.com> Date: Thu, 30 Apr 2020 18:28:06 +0100 Subject: [PATCH 15/39] Collada Export: More unique Ids Nodes, Materials, Animations, Lights, Cameras, Bones --- code/Collada/ColladaExporter.cpp | 405 ++++++++++++++++------------ code/Collada/ColladaExporter.h | 57 ++-- test/unit/utColladaImportExport.cpp | 107 +++++++- 3 files changed, 369 insertions(+), 200 deletions(-) diff --git a/code/Collada/ColladaExporter.cpp b/code/Collada/ColladaExporter.cpp index a502e728c..b91e118ec 100644 --- a/code/Collada/ColladaExporter.cpp +++ b/code/Collada/ColladaExporter.cpp @@ -164,6 +164,9 @@ void ColladaExporter::WriteFile() { WriteTextures(); WriteHeader(); + // Add node names to the unique id database first so they are most likely to use their names as unique ids + CreateNodeIds(mScene->mRootNode); + WriteCamerasLibrary(); WriteLightsLibrary(); WriteMaterials(); @@ -178,7 +181,7 @@ void ColladaExporter::WriteFile() { // useless Collada fu at the end, just in case we haven't had enough indirections, yet. mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "mRootNode->mName.C_Str()) + "\" />" << endstr; + mOutput << startstr << "mRootNode) + "\" />" << endstr; PopTag(); mOutput << startstr << "" << endstr; PopTag(); @@ -391,8 +394,8 @@ void ColladaExporter::WriteCamerasLibrary() { void ColladaExporter::WriteCamera(size_t pIndex) { const aiCamera *cam = mScene->mCameras[pIndex]; - const std::string cameraName = XMLEscape(cam->mName.C_Str()); - const std::string cameraId = XMLIDEncode(cam->mName.C_Str()); + const std::string cameraId = GetObjectUniqueId(AiObjectType::Camera, pIndex); + const std::string cameraName = GetObjectName(AiObjectType::Camera, pIndex); mOutput << startstr << "" << endstr; PushTag(); @@ -444,8 +447,8 @@ void ColladaExporter::WriteLightsLibrary() { void ColladaExporter::WriteLight(size_t pIndex) { const aiLight *light = mScene->mLights[pIndex]; - const std::string lightName = XMLEscape(light->mName.C_Str()); - const std::string lightId = XMLIDEncode(light->mName.C_Str()); + const std::string lightId = GetObjectUniqueId(AiObjectType::Light, pIndex); + const std::string lightName = GetObjectName(AiObjectType::Light, pIndex); mOutput << startstr << "" << endstr; @@ -564,12 +567,11 @@ void ColladaExporter::WriteAmbienttLight(const aiLight *const light) { // ------------------------------------------------------------------------------------------------ // Reads a single surface entry from the given material keys -void ColladaExporter::ReadMaterialSurface(Surface &poSurface, const aiMaterial *pSrcMat, - aiTextureType pTexture, const char *pKey, size_t pType, size_t pIndex) { - if (pSrcMat->GetTextureCount(pTexture) > 0) { +bool ColladaExporter::ReadMaterialSurface(Surface &poSurface, const aiMaterial &pSrcMat, aiTextureType pTexture, const char *pKey, size_t pType, size_t pIndex) { + if (pSrcMat.GetTextureCount(pTexture) > 0) { aiString texfile; unsigned int uvChannel = 0; - pSrcMat->GetTexture(pTexture, 0, &texfile, NULL, &uvChannel); + pSrcMat.GetTexture(pTexture, 0, &texfile, NULL, &uvChannel); std::string index_str(texfile.C_Str()); @@ -599,8 +601,9 @@ void ColladaExporter::ReadMaterialSurface(Surface &poSurface, const aiMaterial * poSurface.exist = true; } else { if (pKey) - poSurface.exist = pSrcMat->Get(pKey, static_cast(pType), static_cast(pIndex), poSurface.color) == aiReturn_SUCCESS; + poSurface.exist = pSrcMat.Get(pKey, static_cast(pType), static_cast(pIndex), poSurface.color) == aiReturn_SUCCESS; } + return poSurface.exist; } // ------------------------------------------------------------------------------------------------ @@ -611,9 +614,9 @@ static bool isalnum_C(char c) { // ------------------------------------------------------------------------------------------------ // Writes an image entry for the given surface -void ColladaExporter::WriteImageEntry(const Surface &pSurface, const std::string &pNameAdd) { +void ColladaExporter::WriteImageEntry(const Surface &pSurface, const std::string &imageId) { if (!pSurface.texture.empty()) { - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << ""; @@ -634,14 +637,14 @@ void ColladaExporter::WriteImageEntry(const Surface &pSurface, const std::string // ------------------------------------------------------------------------------------------------ // Writes a color-or-texture entry into an effect definition -void ColladaExporter::WriteTextureColorEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &pImageName) { +void ColladaExporter::WriteTextureColorEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &imageId) { if (pSurface.exist) { mOutput << startstr << "<" << pTypeName << ">" << endstr; PushTag(); if (pSurface.texture.empty()) { mOutput << startstr << "" << pSurface.color.r << " " << pSurface.color.g << " " << pSurface.color.b << " " << pSurface.color.a << "" << endstr; } else { - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; } PopTag(); mOutput << startstr << "" << endstr; @@ -650,24 +653,24 @@ void ColladaExporter::WriteTextureColorEntry(const Surface &pSurface, const std: // ------------------------------------------------------------------------------------------------ // Writes the two parameters necessary for referencing a texture in an effect entry -void ColladaExporter::WriteTextureParamEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &pMatName) { +void ColladaExporter::WriteTextureParamEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &materialId) { // if surface is a texture, write out the sampler and the surface parameters necessary to reference the texture if (!pSurface.texture.empty()) { - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "" << XMLIDEncode(pMatName) << "-" << pTypeName << "-image" << endstr; + mOutput << startstr << "" << materialId << "-" << pTypeName << "-image" << endstr; PopTag(); mOutput << startstr << "" << endstr; PopTag(); mOutput << startstr << "" << endstr; - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "" << XMLIDEncode(pMatName) << "-" << pTypeName << "-surface" << endstr; + mOutput << startstr << "" << materialId << "-" << pTypeName << "-surface" << endstr; PopTag(); mOutput << startstr << "" << endstr; PopTag(); @@ -690,80 +693,63 @@ void ColladaExporter::WriteFloatEntry(const Property &pProperty, const std::stri // ------------------------------------------------------------------------------------------------ // Writes the material setup void ColladaExporter::WriteMaterials() { + std::vector materials; materials.resize(mScene->mNumMaterials); /// collect all materials from the scene size_t numTextures = 0; for (size_t a = 0; a < mScene->mNumMaterials; ++a) { - const aiMaterial *mat = mScene->mMaterials[a]; - - aiString name; - if (mat->Get(AI_MATKEY_NAME, name) != aiReturn_SUCCESS) { - name = "mat"; - materials[a].name = std::string("m") + to_string(a) + name.C_Str(); - } else { - // try to use the material's name if no other material has already taken it, else append # - std::string testName = name.C_Str(); - size_t materialCountWithThisName = 0; - for (size_t i = 0; i < a; i++) { - if (materials[i].name == testName) { - materialCountWithThisName++; - } - } - if (materialCountWithThisName == 0) { - materials[a].name = name.C_Str(); - } else { - materials[a].name = std::string(name.C_Str()) + to_string(materialCountWithThisName); - } - } + Material &material = materials[a]; + material.id = GetObjectUniqueId(AiObjectType::Material, a); + material.name = GetObjectName(AiObjectType::Material, a); + const aiMaterial &mat = *(mScene->mMaterials[a]); aiShadingMode shading = aiShadingMode_Flat; - materials[a].shading_model = "phong"; - if (mat->Get(AI_MATKEY_SHADING_MODEL, shading) == aiReturn_SUCCESS) { + material.shading_model = "phong"; + if (mat.Get(AI_MATKEY_SHADING_MODEL, shading) == aiReturn_SUCCESS) { if (shading == aiShadingMode_Phong) { - materials[a].shading_model = "phong"; + material.shading_model = "phong"; } else if (shading == aiShadingMode_Blinn) { - materials[a].shading_model = "blinn"; + material.shading_model = "blinn"; } else if (shading == aiShadingMode_NoShading) { - materials[a].shading_model = "constant"; + material.shading_model = "constant"; } else if (shading == aiShadingMode_Gouraud) { - materials[a].shading_model = "lambert"; + material.shading_model = "lambert"; } } - ReadMaterialSurface(materials[a].ambient, mat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT); - if (!materials[a].ambient.texture.empty()) numTextures++; - ReadMaterialSurface(materials[a].diffuse, mat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE); - if (!materials[a].diffuse.texture.empty()) numTextures++; - ReadMaterialSurface(materials[a].specular, mat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR); - if (!materials[a].specular.texture.empty()) numTextures++; - ReadMaterialSurface(materials[a].emissive, mat, aiTextureType_EMISSIVE, AI_MATKEY_COLOR_EMISSIVE); - if (!materials[a].emissive.texture.empty()) numTextures++; - ReadMaterialSurface(materials[a].reflective, mat, aiTextureType_REFLECTION, AI_MATKEY_COLOR_REFLECTIVE); - if (!materials[a].reflective.texture.empty()) numTextures++; - ReadMaterialSurface(materials[a].transparent, mat, aiTextureType_OPACITY, AI_MATKEY_COLOR_TRANSPARENT); - if (!materials[a].transparent.texture.empty()) numTextures++; - ReadMaterialSurface(materials[a].normal, mat, aiTextureType_NORMALS, NULL, 0, 0); - if (!materials[a].normal.texture.empty()) numTextures++; + if (ReadMaterialSurface(material.ambient, mat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT)) + ++numTextures; + if (ReadMaterialSurface(material.diffuse, mat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE)) + ++numTextures; + if (ReadMaterialSurface(material.specular, mat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR)) + ++numTextures; + if (ReadMaterialSurface(material.emissive, mat, aiTextureType_EMISSIVE, AI_MATKEY_COLOR_EMISSIVE)) + ++numTextures; + if (ReadMaterialSurface(material.reflective, mat, aiTextureType_REFLECTION, AI_MATKEY_COLOR_REFLECTIVE)) + ++numTextures; + if (ReadMaterialSurface(material.transparent, mat, aiTextureType_OPACITY, AI_MATKEY_COLOR_TRANSPARENT)) + ++numTextures; + if (ReadMaterialSurface(material.normal, mat, aiTextureType_NORMALS, nullptr, 0, 0)) + ++numTextures; - materials[a].shininess.exist = mat->Get(AI_MATKEY_SHININESS, materials[a].shininess.value) == aiReturn_SUCCESS; - materials[a].transparency.exist = mat->Get(AI_MATKEY_OPACITY, materials[a].transparency.value) == aiReturn_SUCCESS; - materials[a].index_refraction.exist = mat->Get(AI_MATKEY_REFRACTI, materials[a].index_refraction.value) == aiReturn_SUCCESS; + material.shininess.exist = mat.Get(AI_MATKEY_SHININESS, material.shininess.value) == aiReturn_SUCCESS; + material.transparency.exist = mat.Get(AI_MATKEY_OPACITY, material.transparency.value) == aiReturn_SUCCESS; + material.index_refraction.exist = mat.Get(AI_MATKEY_REFRACTI, material.index_refraction.value) == aiReturn_SUCCESS; } // output textures if present if (numTextures > 0) { mOutput << startstr << "" << endstr; PushTag(); - for (std::vector::const_iterator it = materials.begin(); it != materials.end(); ++it) { - const Material &mat = *it; - WriteImageEntry(mat.ambient, mat.name + "-ambient-image"); - WriteImageEntry(mat.diffuse, mat.name + "-diffuse-image"); - WriteImageEntry(mat.specular, mat.name + "-specular-image"); - WriteImageEntry(mat.emissive, mat.name + "-emission-image"); - WriteImageEntry(mat.reflective, mat.name + "-reflective-image"); - WriteImageEntry(mat.transparent, mat.name + "-transparent-image"); - WriteImageEntry(mat.normal, mat.name + "-normal-image"); + for (const Material &mat : materials) { + WriteImageEntry(mat.ambient, mat.id + "-ambient-image"); + WriteImageEntry(mat.diffuse, mat.id + "-diffuse-image"); + WriteImageEntry(mat.specular, mat.id + "-specular-image"); + WriteImageEntry(mat.emissive, mat.id + "-emission-image"); + WriteImageEntry(mat.reflective, mat.id + "-reflective-image"); + WriteImageEntry(mat.transparent, mat.id + "-transparent-image"); + WriteImageEntry(mat.normal, mat.id + "-normal-image"); } PopTag(); mOutput << startstr << "" << endstr; @@ -773,40 +759,39 @@ void ColladaExporter::WriteMaterials() { if (!materials.empty()) { mOutput << startstr << "" << endstr; PushTag(); - for (std::vector::const_iterator it = materials.begin(); it != materials.end(); ++it) { - const Material &mat = *it; + for (const Material &mat : materials) { // this is so ridiculous it must be right - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" << endstr; PushTag(); // write sampler- and surface params for the texture entries - WriteTextureParamEntry(mat.emissive, "emission", mat.name); - WriteTextureParamEntry(mat.ambient, "ambient", mat.name); - WriteTextureParamEntry(mat.diffuse, "diffuse", mat.name); - WriteTextureParamEntry(mat.specular, "specular", mat.name); - WriteTextureParamEntry(mat.reflective, "reflective", mat.name); - WriteTextureParamEntry(mat.transparent, "transparent", mat.name); - WriteTextureParamEntry(mat.normal, "normal", mat.name); + WriteTextureParamEntry(mat.emissive, "emission", mat.id); + WriteTextureParamEntry(mat.ambient, "ambient", mat.id); + WriteTextureParamEntry(mat.diffuse, "diffuse", mat.id); + WriteTextureParamEntry(mat.specular, "specular", mat.id); + WriteTextureParamEntry(mat.reflective, "reflective", mat.id); + WriteTextureParamEntry(mat.transparent, "transparent", mat.id); + WriteTextureParamEntry(mat.normal, "normal", mat.id); mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "<" << mat.shading_model << ">" << endstr; PushTag(); - WriteTextureColorEntry(mat.emissive, "emission", mat.name + "-emission-sampler"); - WriteTextureColorEntry(mat.ambient, "ambient", mat.name + "-ambient-sampler"); - WriteTextureColorEntry(mat.diffuse, "diffuse", mat.name + "-diffuse-sampler"); - WriteTextureColorEntry(mat.specular, "specular", mat.name + "-specular-sampler"); + WriteTextureColorEntry(mat.emissive, "emission", mat.id + "-emission-sampler"); + WriteTextureColorEntry(mat.ambient, "ambient", mat.id + "-ambient-sampler"); + WriteTextureColorEntry(mat.diffuse, "diffuse", mat.id + "-diffuse-sampler"); + WriteTextureColorEntry(mat.specular, "specular", mat.id + "-specular-sampler"); WriteFloatEntry(mat.shininess, "shininess"); - WriteTextureColorEntry(mat.reflective, "reflective", mat.name + "-reflective-sampler"); - WriteTextureColorEntry(mat.transparent, "transparent", mat.name + "-transparent-sampler"); + WriteTextureColorEntry(mat.reflective, "reflective", mat.id + "-reflective-sampler"); + WriteTextureColorEntry(mat.transparent, "transparent", mat.id + "-transparent-sampler"); WriteFloatEntry(mat.transparency, "transparency"); WriteFloatEntry(mat.index_refraction, "index_of_refraction"); if (!mat.normal.texture.empty()) { - WriteTextureColorEntry(mat.normal, "bump", mat.name + "-normal-sampler"); + WriteTextureColorEntry(mat.normal, "bump", mat.id + "-normal-sampler"); } PopTag(); @@ -826,9 +811,9 @@ void ColladaExporter::WriteMaterials() { PushTag(); for (std::vector::const_iterator it = materials.begin(); it != materials.end(); ++it) { const Material &mat = *it; - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PopTag(); mOutput << startstr << "" << endstr; } @@ -855,14 +840,12 @@ void ColladaExporter::WriteControllerLibrary() { // Writes a skin controller of the given mesh void ColladaExporter::WriteController(size_t pIndex) { const aiMesh *mesh = mScene->mMeshes[pIndex]; - const std::string idstr = GetMeshUniqueId(pIndex); - const std::string namestr = GetMeshName(pIndex); - - if (mesh->mNumFaces == 0 || mesh->mNumVertices == 0) + // Is there a skin controller? + if (mesh->mNumBones == 0 || mesh->mNumFaces == 0 || mesh->mNumVertices == 0) return; - if (mesh->mNumBones == 0) - return; + const std::string idstr = GetObjectUniqueId(AiObjectType::Mesh, pIndex); + const std::string namestr = GetObjectName(AiObjectType::Mesh, pIndex); mOutput << startstr << "" << endstr; @@ -891,7 +874,7 @@ void ColladaExporter::WriteController(size_t pIndex) { mOutput << startstr << "mNumBones << "\">"; for (size_t i = 0; i < mesh->mNumBones; ++i) - mOutput << XMLIDEncode(mesh->mBones[i]->mName.C_Str()) << " "; + mOutput << GetBoneUniqueId(mesh->mBones[i]) << " "; mOutput << "" << endstr; @@ -1020,8 +1003,8 @@ void ColladaExporter::WriteGeometryLibrary() { // Writes the given mesh void ColladaExporter::WriteGeometry(size_t pIndex) { const aiMesh *mesh = mScene->mMeshes[pIndex]; - const std::string geometryName = GetMeshName(pIndex); - const std::string geometryId = GetMeshUniqueId(pIndex); + const std::string geometryId = GetObjectUniqueId(AiObjectType::Mesh, pIndex); + const std::string geometryName = GetObjectName(AiObjectType::Mesh, pIndex); if (mesh->mNumFaces == 0 || mesh->mNumVertices == 0) return; @@ -1250,8 +1233,8 @@ void ColladaExporter::WriteFloatArray(const std::string &pIdString, FloatDataTyp // ------------------------------------------------------------------------------------------------ // Writes the scene library void ColladaExporter::WriteSceneLibrary() { - const std::string sceneName = XMLEscape(mScene->mRootNode->mName.C_Str()); - const std::string sceneId = XMLIDEncode(mScene->mRootNode->mName.C_Str()); + const std::string sceneName = GetNodeUniqueId(mScene->mRootNode); + const std::string sceneId = GetNodeName(mScene->mRootNode); mOutput << startstr << "" << endstr; PushTag(); @@ -1260,7 +1243,7 @@ void ColladaExporter::WriteSceneLibrary() { // start recursive write at the root node for (size_t a = 0; a < mScene->mRootNode->mNumChildren; ++a) - WriteNode(mScene, mScene->mRootNode->mChildren[a]); + WriteNode(mScene->mRootNode->mChildren[a]); PopTag(); mOutput << startstr << "" << endstr; @@ -1274,20 +1257,10 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex) { if (anim->mNumChannels == 0 && anim->mNumMeshChannels == 0 && anim->mNumMorphMeshChannels == 0) return; - const std::string animation_name_escaped = XMLEscape(anim->mName.C_Str()); - std::string idstr = anim->mName.C_Str(); - std::string ending = std::string("AnimId") + to_string(pIndex); - if (idstr.length() >= ending.length()) { - if (0 != idstr.compare(idstr.length() - ending.length(), ending.length(), ending)) { - idstr = idstr + ending; - } - } else { - idstr = idstr + ending; - } + const std::string animationNameEscaped = GetObjectName(AiObjectType::Animation, pIndex); + const std::string idstrEscaped = GetObjectUniqueId(AiObjectType::Animation, pIndex); - const std::string idstrEscaped = XMLIDEncode(idstr); - - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); std::string cur_node_idstr; @@ -1503,31 +1476,25 @@ const aiNode *findSkeletonRootNode(const aiScene *scene, const aiMesh *mesh) { // ------------------------------------------------------------------------------------------------ // Recursively writes the given node -void ColladaExporter::WriteNode(const aiScene *pScene, aiNode *pNode) { - // the node must have a name - if (pNode->mName.length == 0) { - std::stringstream ss; - ss << "Node_" << pNode; - pNode->mName.Set(ss.str()); - } - +void ColladaExporter::WriteNode(const aiNode *pNode) { // If the node is associated with a bone, it is a joint node (JOINT) // otherwise it is a normal node (NODE) + // Assimp-specific: nodes with no name cannot be associated with bones const char *node_type; bool is_joint, is_skeleton_root = false; - if (nullptr == findBone(pScene, pNode->mName.C_Str())) { + if (pNode->mName.length == 0 && nullptr == findBone(mScene, pNode->mName.C_Str())) { node_type = "NODE"; is_joint = false; } else { node_type = "JOINT"; is_joint = true; - if (!pNode->mParent || nullptr == findBone(pScene, pNode->mParent->mName.C_Str())) { + if (!pNode->mParent || nullptr == findBone(mScene, pNode->mParent->mName.C_Str())) { is_skeleton_root = true; } } - const std::string node_id = XMLIDEncode(pNode->mName.data); - const std::string node_name = XMLEscape(pNode->mName.data); + const std::string node_id = GetNodeUniqueId(pNode); + const std::string node_name = GetNodeName(pNode); mOutput << startstr << "mNumFaces == 0 || mesh->mNumVertices == 0) continue; - const std::string meshId = GetMeshUniqueId(pNode->mMeshes[a]); + const std::string meshId = GetObjectUniqueId(AiObjectType::Mesh, pNode->mMeshes[a]); if (mesh->mNumBones == 0) { mOutput << startstr << "" << endstr; @@ -1608,9 +1575,9 @@ void ColladaExporter::WriteNode(const aiScene *pScene, aiNode *pNode) { // note! this mFoundSkeletonRootNodeID some how affects animation, it makes the mesh attaches to armature skeleton root node. // use the first bone to find skeleton root - const aiNode *skeletonRootBoneNode = findSkeletonRootNode(pScene, mesh); + const aiNode *skeletonRootBoneNode = findSkeletonRootNode(mScene, mesh); if (skeletonRootBoneNode) { - mFoundSkeletonRootNodeID = XMLIDEncode(skeletonRootBoneNode->mName.C_Str()); + mFoundSkeletonRootNodeID = GetNodeUniqueId(skeletonRootBoneNode); } mOutput << startstr << "#" << mFoundSkeletonRootNodeID << "" << endstr; } @@ -1618,7 +1585,7 @@ void ColladaExporter::WriteNode(const aiScene *pScene, aiNode *pNode) { PushTag(); mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "mMaterialIndex].name) << "\">" << endstr; + mOutput << startstr << "mMaterialIndex) << "\">" << endstr; PushTag(); for (size_t aa = 0; aa < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++aa) { if (mesh->HasTextureCoords(static_cast(aa))) @@ -1643,64 +1610,154 @@ void ColladaExporter::WriteNode(const aiScene *pScene, aiNode *pNode) { // recurse into subnodes for (size_t a = 0; a < pNode->mNumChildren; ++a) - WriteNode(pScene, pNode->mChildren[a]); + WriteNode(pNode->mChildren[a]); PopTag(); mOutput << startstr << "" << endstr; } -/// Get or Create a unique mesh ID string for the given mesh index -std::string Assimp::ColladaExporter::GetMeshUniqueId(size_t pIndex) { - auto meshId = mMeshIdMap.find(pIndex); - if (meshId != mMeshIdMap.cend()) - return meshId->second; - - // Not seen this mesh before, create and add - return AddMeshIndexToMaps(pIndex, true); +inline bool IsUniqueId(const std::unordered_set &idSet, const std::string &idStr) { + return (idSet.find(idStr) == idSet.end()); } -std::string Assimp::ColladaExporter::GetMeshName(size_t pIndex) { - auto meshName = mMeshNameMap.find(pIndex); - if (meshName != mMeshNameMap.cend()) - return meshName->second; - - // Not seen this mesh before, create and add - return AddMeshIndexToMaps(pIndex, false); -} - -inline bool ValueIsUnique(const std::map &map, const std::string &value) { - for (const auto &map_val : map) { - if (value == map_val.second) - return false; - } - return true; -} - -// Add the mesh index to both Id and Name maps and return either Id or Name -std::string Assimp::ColladaExporter::AddMeshIndexToMaps(size_t pIndex, bool meshId) { - const aiMesh *mesh = mScene->mMeshes[pIndex]; - std::string idStr = mesh->mName.length == 0 ? std::string("meshId_") + to_string(pIndex) : XMLIDEncode(mesh->mName.C_Str()); - // Ensure is unique. Relatively slow but will only happen once per mesh - if (!ValueIsUnique(mMeshIdMap, idStr)) { +inline void MakeUniqueId(const std::unordered_set &idSet, std::string &idStr) { + if (!IsUniqueId(idSet, idStr)) { // Select a number to append size_t postfix = 1; idStr.append("_"); - while (!ValueIsUnique(mMeshIdMap, idStr + to_string(postfix))) { + while (!IsUniqueId(idSet, idStr + to_string(postfix))) { ++postfix; } - idStr = idStr + to_string(postfix); + idStr.append(to_string(postfix)); } - // Add to map - mMeshIdMap.insert(std::make_pair(pIndex, idStr)); +} - // Add name to map - const std::string nameStr = mesh->mName.length == 0 ? idStr : XMLEscape(mesh->mName.C_Str()); - mMeshNameMap.insert(std::make_pair(pIndex, nameStr)); +void Assimp::ColladaExporter::CreateNodeIds(const aiNode *node) { + GetNodeUniqueId(node); + for (size_t a = 0; a < node->mNumChildren; ++a) + CreateNodeIds(node->mChildren[a]); +} - if (meshId) - return idStr; +std::string Assimp::ColladaExporter::GetNodeUniqueId(const aiNode *node) { + // Use the pointer as the key. This is safe because the scene is immutable. + auto idIt = mNodeIdMap.find(node); + if (idIt != mNodeIdMap.cend()) + return idIt->second; + + // Prefer the requested Collada Id if extant + std::string idStr; + aiString origId; + if (node->mMetaData && node->mMetaData->Get(AI_METADATA_COLLADA_ID, origId)) { + idStr = origId.C_Str(); + } else { + idStr = node->mName.C_Str(); + } + // Make sure the requested id is valid + if (idStr.empty()) + idStr = "node"; else - return nameStr; + idStr = XMLIDEncode(idStr); + + // Ensure it's unique + MakeUniqueId(mUniqueIds, idStr); + mUniqueIds.insert(idStr); + mNodeIdMap.insert(std::make_pair(node, idStr)); + return idStr; +} + +std::string Assimp::ColladaExporter::GetNodeName(const aiNode *node) { + + return XMLEscape(node->mName.C_Str()); +} + +std::string Assimp::ColladaExporter::GetBoneUniqueId(const aiBone *bone) { + // Use the pointer as the key. This is safe because the scene is immutable. + auto idIt = mNodeIdMap.find(bone); + if (idIt != mNodeIdMap.cend()) + return idIt->second; + + // New, create an id + std::string idStr(bone->mName.C_Str()); + + // Make sure the requested id is valid + if (idStr.empty()) + idStr = "bone"; + else + idStr = XMLIDEncode(idStr); + + // Ensure it's unique + MakeUniqueId(mUniqueIds, idStr); + mUniqueIds.insert(idStr); + mNodeIdMap.insert(std::make_pair(bone, idStr)); + return idStr; +} + +std::string Assimp::ColladaExporter::GetObjectUniqueId(AiObjectType type, size_t pIndex) { + auto idIt = GetObjectIdMap(type).find(pIndex); + if (idIt != GetObjectIdMap(type).cend()) + return idIt->second; + + // Not seen this object before, create and add + NameIdPair result = AddObjectIndexToMaps(type, pIndex); + return result.second; +} + +std::string Assimp::ColladaExporter::GetObjectName(AiObjectType type, size_t pIndex) { + auto meshName = GetObjectNameMap(type).find(pIndex); + if (meshName != GetObjectNameMap(type).cend()) + return meshName->second; + + // Not seen this object before, create and add + NameIdPair result = AddObjectIndexToMaps(type, pIndex); + return result.first; +} + +// Determine unique id and add the name and id to the maps +// @param type object type +// @param index object index +// @param name in/out. Caller to set the original name if known. +// @param idStr in/out. Caller to set the preferred id if known. +Assimp::ColladaExporter::NameIdPair Assimp::ColladaExporter::AddObjectIndexToMaps(AiObjectType type, size_t index) { + + std::string idStr; + std::string name; + + // Get the name + switch (type) { + case AiObjectType::Mesh: name = mScene->mMeshes[index]->mName.C_Str(); break; + case AiObjectType::Material: name = mScene->mMaterials[index]->GetName().C_Str(); break; + case AiObjectType::Animation: name = mScene->mAnimations[index]->mName.C_Str(); break; + case AiObjectType::Light: name = mScene->mLights[index]->mName.C_Str(); break; + case AiObjectType::Camera: name = mScene->mCameras[index]->mName.C_Str(); break; + case AiObjectType::Count: throw std::logic_error("ColladaExporter::AiObjectType::Count is not an object type"); + } + + if (name.empty()) { + // Default ids if empty name + switch (type) { + case AiObjectType::Mesh: idStr = std::string("meshId_"); break; + case AiObjectType::Material: idStr = std::string("materialId_"); break; // This one should never happen + case AiObjectType::Animation: idStr = std::string("animationId_"); break; + case AiObjectType::Light: idStr = std::string("lightId_"); break; + case AiObjectType::Camera: idStr = std::string("cameraId_"); break; + case AiObjectType::Count: throw std::logic_error("ColladaExporter::AiObjectType::Count is not an object type"); + } + idStr.append(to_string(index)); + } else { + idStr = XMLIDEncode(name); + } + + if (!name.empty()) + name = XMLEscape(name); + + MakeUniqueId(mUniqueIds, idStr); + + // Add to maps + mUniqueIds.insert(idStr); + GetObjectIdMap(type).insert(std::make_pair(index, idStr)); + GetObjectNameMap(type).insert(std::make_pair(index, idStr)); + + return std::make_pair(name, idStr); } #endif diff --git a/code/Collada/ColladaExporter.h b/code/Collada/ColladaExporter.h index d75d2d355..c6801395b 100644 --- a/code/Collada/ColladaExporter.h +++ b/code/Collada/ColladaExporter.h @@ -46,17 +46,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_COLLADAEXPORTER_H_INC #define AI_COLLADAEXPORTER_H_INC +#include #include #include #include #include #include + +#include #include #include +#include #include -#include - struct aiScene; struct aiNode; @@ -135,7 +137,7 @@ protected: std::string mFoundSkeletonRootNodeID = "skeleton_root"; // will be replaced by found node id in the WriteNode call. /// Recursively writes the given node - void WriteNode(const aiScene *scene, aiNode *pNode); + void WriteNode(const aiNode *pNode); /// Enters a new xml element, which increases the indentation void PushTag() { startstr.append(" "); } @@ -145,14 +147,40 @@ protected: startstr.erase(startstr.length() - 2); } - /// Get or Create a unique mesh ID string for the given mesh index - std::string GetMeshUniqueId(size_t pIndex); - std::string GetMeshName(size_t pIndex); + void CreateNodeIds(const aiNode *node); + + /// Get or Create a unique Node ID string for the given Node + std::string GetNodeUniqueId(const aiNode *node); + std::string GetNodeName(const aiNode *node); + + std::string GetBoneUniqueId(const aiBone *bone); + + enum class AiObjectType { + Mesh, + Material, + Animation, + Light, + Camera, + Count, + }; + /// Get or Create a unique ID string for the given scene object index + std::string GetObjectUniqueId(AiObjectType type, size_t pIndex); + /// Get or Create a name string for the given scene object index + std::string GetObjectName(AiObjectType type, size_t pIndex); + + typedef std::map IndexIdMap; + typedef std::pair NameIdPair; + NameIdPair AddObjectIndexToMaps(AiObjectType type, size_t pIndex); + + // Helpers + inline IndexIdMap &GetObjectIdMap(AiObjectType type) { return mObjectIdMap[static_cast(type)]; } + inline IndexIdMap &GetObjectNameMap(AiObjectType type) { return mObjectNameMap[static_cast(type)]; } private: - std::string AddMeshIndexToMaps(size_t pIndex, bool meshId); - mutable std::map mMeshIdMap; // Cache of encoded unique IDs - mutable std::map mMeshNameMap; // Cache of encoded mesh names + std::unordered_set mUniqueIds; // Cache of used unique ids + std::map mNodeIdMap; // Cache of encoded node and bone ids + std::array(AiObjectType::Count)> mObjectIdMap; // Cache of encoded unique IDs + std::array(AiObjectType::Count)> mObjectNameMap; // Cache of encoded names public: /// Stringstream to write all output into @@ -198,6 +226,7 @@ public: // summarize a material in an convenient way. struct Material { + std::string id; std::string name; std::string shading_model; Surface ambient, diffuse, specular, emissive, reflective, transparent, normal; @@ -206,20 +235,18 @@ public: Material() {} }; - std::vector materials; - std::map textures; public: /// Dammit C++ - y u no compile two-pass? No I have to add all methods below the struct definitions /// Reads a single surface entry from the given material keys - void ReadMaterialSurface(Surface &poSurface, const aiMaterial *pSrcMat, aiTextureType pTexture, const char *pKey, size_t pType, size_t pIndex); + bool ReadMaterialSurface(Surface &poSurface, const aiMaterial &pSrcMat, aiTextureType pTexture, const char *pKey, size_t pType, size_t pIndex); /// Writes an image entry for the given surface - void WriteImageEntry(const Surface &pSurface, const std::string &pNameAdd); + void WriteImageEntry(const Surface &pSurface, const std::string &imageId); /// Writes the two parameters necessary for referencing a texture in an effect entry - void WriteTextureParamEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &pMatName); + void WriteTextureParamEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &materialId); /// Writes a color-or-texture entry into an effect definition - void WriteTextureColorEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &pImageName); + void WriteTextureColorEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &imageId); /// Writes a scalar property void WriteFloatEntry(const Property &pProperty, const std::string &pTypeName); }; diff --git a/test/unit/utColladaImportExport.cpp b/test/unit/utColladaImportExport.cpp index 5c2f801db..5b0c9f880 100644 --- a/test/unit/utColladaImportExport.cpp +++ b/test/unit/utColladaImportExport.cpp @@ -82,20 +82,75 @@ public: return true; } + typedef std::pair IdNameString; + typedef std::map IdNameMap; + + template + static inline IdNameString GetItemIdName(const T *item, size_t index) { + std::ostringstream stream; + stream << typeid(T).name() << "@" << index; + return std::make_pair(std::string(item->mName.C_Str()), stream.str()); + } + + // Specialisations + static inline IdNameString GetItemIdName(aiMaterial *item, size_t index) { + std::ostringstream stream; + stream << typeid(aiMaterial).name() << "@" << index; + return std::make_pair(std::string(item->GetName().C_Str()), stream.str()); + } + + static inline IdNameString GetItemIdName(aiTexture *item, size_t index) { + std::ostringstream stream; + stream << typeid(aiTexture).name() << "@" << index; + return std::make_pair(std::string(item->mFilename.C_Str()), stream.str()); + } + + static inline void ReportDuplicate(IdNameMap &itemIdMap, const IdNameString &namePair, const char *typeNameStr) { + const auto result = itemIdMap.insert(namePair); + EXPECT_TRUE(result.second) << "Duplicate '" << typeNameStr << "' name: '" << namePair.first << "'. " << namePair.second << " == " << result.first->second; + } + + template + static inline void CheckUniqueIds(IdNameMap &itemIdMap, unsigned int itemCount, T **itemArray) { + for (size_t idx = 0; idx < itemCount; ++idx) { + IdNameString namePair = GetItemIdName(itemArray[idx], idx); + ReportDuplicate(itemIdMap, namePair, typeid(T).name()); + } + } + + static inline void CheckUniqueIds(IdNameMap &itemIdMap, const aiNode *parent, size_t index) { + IdNameString namePair = GetItemIdName(parent, index); + ReportDuplicate(itemIdMap, namePair, typeid(aiNode).name()); + for (size_t idx = 0; idx < parent->mNumChildren; ++idx) { + CheckUniqueIds(itemIdMap, parent->mChildren[idx], idx); + } + } + + static inline void SetAllNodeNames(const aiString &newName, aiNode *node) { + node->mName = newName; + for (size_t idx = 0; idx < node->mNumChildren; ++idx) { + SetAllNodeNames(newName, node->mChildren[idx]); + } + } + void ImportAndCheckIds(const char *file, size_t meshCount) { - // Import the Collada using the 'default' where mesh names are the ids + // Import the Collada using the 'default' where aiMesh names are the Collada ids Assimp::Importer importer; const aiScene *scene = importer.ReadFile(file, aiProcess_ValidateDataStructure); ASSERT_TRUE(scene != nullptr) << "Fatal: could not re-import " << file; EXPECT_EQ(meshCount, scene->mNumMeshes) << "in " << file; - // Check the mesh ids are unique - std::map meshNameMap; - for (size_t idx = 0; idx < scene->mNumMeshes; ++idx) { - std::string meshName(scene->mMeshes[idx]->mName.C_Str()); - const auto result = meshNameMap.insert(std::make_pair(meshName, idx)); - EXPECT_TRUE(result.second) << "Duplicate name: " << meshName << " index " << result.first->second; - } + // Check the ids are unique + IdNameMap itemIdMap; + // Recurse the Nodes + CheckUniqueIds(itemIdMap, scene->mRootNode, 0); + // Check the lists + CheckUniqueIds(itemIdMap, scene->mNumMeshes, scene->mMeshes); + CheckUniqueIds(itemIdMap, scene->mNumAnimations, scene->mAnimations); + CheckUniqueIds(itemIdMap, scene->mNumMaterials, scene->mMaterials); + CheckUniqueIds(itemIdMap, scene->mNumTextures, scene->mTextures); + CheckUniqueIds(itemIdMap, scene->mNumLights, scene->mLights); + CheckUniqueIds(itemIdMap, scene->mNumCameras, scene->mCameras); } }; @@ -115,19 +170,49 @@ TEST_F(utColladaImportExport, exporterUniqueIdsTest) { ASSERT_TRUE(scene != nullptr) << "Fatal: could not import teapots.DAE!"; ASSERT_EQ(3u, scene->mNumMeshes) << "Fatal: teapots.DAE initial load failed"; - // Clear the mesh names + // Clear all the names for (size_t idx = 0; idx < scene->mNumMeshes; ++idx) { scene->mMeshes[idx]->mName.Clear(); } + for (size_t idx = 0; idx < scene->mNumMaterials; ++idx) { + scene->mMaterials[idx]->RemoveProperty(AI_MATKEY_NAME); + } + for (size_t idx = 0; idx < scene->mNumAnimations; ++idx) { + scene->mAnimations[idx]->mName.Clear(); + } + // Can't clear texture names + for (size_t idx = 0; idx < scene->mNumLights; ++idx) { + scene->mLights[idx]->mName.Clear(); + } + for (size_t idx = 0; idx < scene->mNumCameras; ++idx) { + scene->mCameras[idx]->mName.Clear(); + } + + SetAllNodeNames(aiString(), scene->mRootNode); + ASSERT_EQ(AI_SUCCESS, exporter.Export(scene, "collada", outFileEmpty)) << "Fatal: Could not export un-named meshes file"; ImportAndCheckIds(outFileEmpty, 3); - // Force the meshes to have the same non-empty name - aiString testName("test_mesh"); + // Force everything to have the same non-empty name + aiString testName("test_name"); for (size_t idx = 0; idx < scene->mNumMeshes; ++idx) { scene->mMeshes[idx]->mName = testName; } + for (size_t idx = 0; idx < scene->mNumMaterials; ++idx) { + scene->mMaterials[idx]->AddProperty(&testName, AI_MATKEY_NAME); + } + for (size_t idx = 0; idx < scene->mNumAnimations; ++idx) { + scene->mAnimations[idx]->mName = testName; + } + // Can't clear texture names + for (size_t idx = 0; idx < scene->mNumLights; ++idx) { + scene->mLights[idx]->mName = testName; + } + for (size_t idx = 0; idx < scene->mNumCameras; ++idx) { + scene->mCameras[idx]->mName = testName; + } + ASSERT_EQ(AI_SUCCESS, exporter.Export(scene, "collada", outFileNamed)) << "Fatal: Could not export named meshes file"; ImportAndCheckIds(outFileNamed, 3); From ee16d2c4c95319a403f9c21ce10141b20e9df2a0 Mon Sep 17 00:00:00 2001 From: RichardTea <31507749+RichardTea@users.noreply.github.com> Date: Fri, 1 May 2020 11:13:38 +0100 Subject: [PATCH 16/39] Fix camera, light and bone unique ids Bones don't have a unit test yet --- code/Collada/ColladaExporter.cpp | 106 +++++++++++++++---------------- 1 file changed, 52 insertions(+), 54 deletions(-) diff --git a/code/Collada/ColladaExporter.cpp b/code/Collada/ColladaExporter.cpp index b91e118ec..a9137b50b 100644 --- a/code/Collada/ColladaExporter.cpp +++ b/code/Collada/ColladaExporter.cpp @@ -397,7 +397,7 @@ void ColladaExporter::WriteCamera(size_t pIndex) { const std::string cameraId = GetObjectUniqueId(AiObjectType::Camera, pIndex); const std::string cameraName = GetObjectName(AiObjectType::Camera, pIndex); - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" << endstr; PushTag(); @@ -450,7 +450,7 @@ void ColladaExporter::WriteLight(size_t pIndex) { const std::string lightId = GetObjectUniqueId(AiObjectType::Light, pIndex); const std::string lightName = GetObjectName(AiObjectType::Light, pIndex); - mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" << endstr; @@ -874,7 +874,7 @@ void ColladaExporter::WriteController(size_t pIndex) { mOutput << startstr << "mNumBones << "\">"; for (size_t i = 0; i < mesh->mNumBones; ++i) - mOutput << GetBoneUniqueId(mesh->mBones[i]) << " "; + mOutput << GetBoneUniqueId(mesh->mBones[i]) << ' '; mOutput << "" << endstr; @@ -1410,12 +1410,12 @@ void ColladaExporter::WriteAnimationsLibrary() { } // ------------------------------------------------------------------------------------------------ // Helper to find a bone by name in the scene -aiBone *findBone(const aiScene *scene, const char *name) { +aiBone *findBone(const aiScene *scene, const aiString &name) { for (size_t m = 0; m < scene->mNumMeshes; m++) { aiMesh *mesh = scene->mMeshes[m]; for (size_t b = 0; b < mesh->mNumBones; b++) { aiBone *bone = mesh->mBones[b]; - if (0 == strcmp(name, bone->mName.C_Str())) { + if (name == bone->mName) { return bone; } } @@ -1424,6 +1424,7 @@ aiBone *findBone(const aiScene *scene, const char *name) { } // ------------------------------------------------------------------------------------------------ +// Helper to find the node associated with a bone in the scene const aiNode *findBoneNode(const aiNode *aNode, const aiBone *bone) { if (aNode && bone && aNode->mName == bone->mName) { return aNode; @@ -1432,15 +1433,17 @@ const aiNode *findBoneNode(const aiNode *aNode, const aiBone *bone) { if (aNode && bone) { for (unsigned int i = 0; i < aNode->mNumChildren; ++i) { aiNode *aChild = aNode->mChildren[i]; - const aiNode *foundFromChild = 0; + const aiNode *foundFromChild = nullptr; if (aChild) { foundFromChild = findBoneNode(aChild, bone); - if (foundFromChild) return foundFromChild; + if (foundFromChild) { + return foundFromChild; + } } } } - return NULL; + return nullptr; } const aiNode *findSkeletonRootNode(const aiScene *scene, const aiMesh *mesh) { @@ -1451,7 +1454,7 @@ const aiNode *findSkeletonRootNode(const aiScene *scene, const aiMesh *mesh) { const aiNode *node = findBoneNode(scene->mRootNode, bone); if (node) { - while (node->mParent && findBone(scene, node->mParent->mName.C_Str()) != 0) { + while (node->mParent && findBone(scene, node->mParent->mName) != nullptr) { node = node->mParent; } topParentBoneNodes.insert(node); @@ -1482,13 +1485,13 @@ void ColladaExporter::WriteNode(const aiNode *pNode) { // Assimp-specific: nodes with no name cannot be associated with bones const char *node_type; bool is_joint, is_skeleton_root = false; - if (pNode->mName.length == 0 && nullptr == findBone(mScene, pNode->mName.C_Str())) { + if (pNode->mName.length == 0 || nullptr == findBone(mScene, pNode->mName)) { node_type = "NODE"; is_joint = false; } else { node_type = "JOINT"; is_joint = true; - if (!pNode->mParent || nullptr == findBone(mScene, pNode->mParent->mName.C_Str())) { + if (!pNode->mParent || nullptr == findBone(mScene, pNode->mParent->mName)) { is_skeleton_root = true; } } @@ -1542,14 +1545,14 @@ void ColladaExporter::WriteNode(const aiNode *pNode) { //check if it is a camera node for (size_t i = 0; i < mScene->mNumCameras; i++) { if (mScene->mCameras[i]->mName == pNode->mName) { - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; break; } } //check if it is a light node for (size_t i = 0; i < mScene->mNumLights; i++) { if (mScene->mLights[i]->mName == pNode->mName) { - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; break; } } @@ -1620,16 +1623,17 @@ inline bool IsUniqueId(const std::unordered_set &idSet, const std:: return (idSet.find(idStr) == idSet.end()); } -inline void MakeUniqueId(const std::unordered_set &idSet, std::string &idStr) { - if (!IsUniqueId(idSet, idStr)) { +inline std::string MakeUniqueId(const std::unordered_set &idSet, const std::string &idPrefix, const std::string &postfix) { + std::string result(idPrefix + postfix); + if (!IsUniqueId(idSet, result)) { // Select a number to append - size_t postfix = 1; - idStr.append("_"); - while (!IsUniqueId(idSet, idStr + to_string(postfix))) { - ++postfix; - } - idStr.append(to_string(postfix)); + size_t idnum = 1; + do { + result = idPrefix + '_' + to_string(idnum) + postfix; + ++idnum; + } while (!IsUniqueId(idSet, result)); } + return result; } void Assimp::ColladaExporter::CreateNodeIds(const aiNode *node) { @@ -1659,7 +1663,7 @@ std::string Assimp::ColladaExporter::GetNodeUniqueId(const aiNode *node) { idStr = XMLIDEncode(idStr); // Ensure it's unique - MakeUniqueId(mUniqueIds, idStr); + idStr = MakeUniqueId(mUniqueIds, idStr, std::string()); mUniqueIds.insert(idStr); mNodeIdMap.insert(std::make_pair(node, idStr)); return idStr; @@ -1671,25 +1675,12 @@ std::string Assimp::ColladaExporter::GetNodeName(const aiNode *node) { } std::string Assimp::ColladaExporter::GetBoneUniqueId(const aiBone *bone) { - // Use the pointer as the key. This is safe because the scene is immutable. - auto idIt = mNodeIdMap.find(bone); - if (idIt != mNodeIdMap.cend()) - return idIt->second; + // Find the Node that is this Bone + const aiNode *boneNode = findBoneNode(mScene->mRootNode, bone); + if (boneNode == nullptr) + return std::string(); - // New, create an id - std::string idStr(bone->mName.C_Str()); - - // Make sure the requested id is valid - if (idStr.empty()) - idStr = "bone"; - else - idStr = XMLIDEncode(idStr); - - // Ensure it's unique - MakeUniqueId(mUniqueIds, idStr); - mUniqueIds.insert(idStr); - mNodeIdMap.insert(std::make_pair(bone, idStr)); - return idStr; + return GetNodeUniqueId(boneNode); } std::string Assimp::ColladaExporter::GetObjectUniqueId(AiObjectType type, size_t pIndex) { @@ -1703,9 +1694,9 @@ std::string Assimp::ColladaExporter::GetObjectUniqueId(AiObjectType type, size_t } std::string Assimp::ColladaExporter::GetObjectName(AiObjectType type, size_t pIndex) { - auto meshName = GetObjectNameMap(type).find(pIndex); - if (meshName != GetObjectNameMap(type).cend()) - return meshName->second; + auto objectName = GetObjectNameMap(type).find(pIndex); + if (objectName != GetObjectNameMap(type).cend()) + return objectName->second; // Not seen this object before, create and add NameIdPair result = AddObjectIndexToMaps(type, pIndex); @@ -1719,27 +1710,34 @@ std::string Assimp::ColladaExporter::GetObjectName(AiObjectType type, size_t pIn // @param idStr in/out. Caller to set the preferred id if known. Assimp::ColladaExporter::NameIdPair Assimp::ColladaExporter::AddObjectIndexToMaps(AiObjectType type, size_t index) { - std::string idStr; std::string name; + std::string idStr; + std::string idPostfix; - // Get the name + // Get the name and id postfix switch (type) { case AiObjectType::Mesh: name = mScene->mMeshes[index]->mName.C_Str(); break; case AiObjectType::Material: name = mScene->mMaterials[index]->GetName().C_Str(); break; case AiObjectType::Animation: name = mScene->mAnimations[index]->mName.C_Str(); break; - case AiObjectType::Light: name = mScene->mLights[index]->mName.C_Str(); break; - case AiObjectType::Camera: name = mScene->mCameras[index]->mName.C_Str(); break; + case AiObjectType::Light: + name = mScene->mLights[index]->mName.C_Str(); + idPostfix = "-light"; + break; + case AiObjectType::Camera: + name = mScene->mCameras[index]->mName.C_Str(); + idPostfix = "-camera"; + break; case AiObjectType::Count: throw std::logic_error("ColladaExporter::AiObjectType::Count is not an object type"); } if (name.empty()) { // Default ids if empty name switch (type) { - case AiObjectType::Mesh: idStr = std::string("meshId_"); break; - case AiObjectType::Material: idStr = std::string("materialId_"); break; // This one should never happen - case AiObjectType::Animation: idStr = std::string("animationId_"); break; - case AiObjectType::Light: idStr = std::string("lightId_"); break; - case AiObjectType::Camera: idStr = std::string("cameraId_"); break; + case AiObjectType::Mesh: idStr = std::string("mesh_"); break; + case AiObjectType::Material: idStr = std::string("material_"); break; // This one should never happen + case AiObjectType::Animation: idStr = std::string("animation_"); break; + case AiObjectType::Light: idStr = std::string("light_"); break; + case AiObjectType::Camera: idStr = std::string("camera_"); break; case AiObjectType::Count: throw std::logic_error("ColladaExporter::AiObjectType::Count is not an object type"); } idStr.append(to_string(index)); @@ -1750,12 +1748,12 @@ Assimp::ColladaExporter::NameIdPair Assimp::ColladaExporter::AddObjectIndexToMap if (!name.empty()) name = XMLEscape(name); - MakeUniqueId(mUniqueIds, idStr); + idStr = MakeUniqueId(mUniqueIds, idStr, idPostfix); // Add to maps mUniqueIds.insert(idStr); GetObjectIdMap(type).insert(std::make_pair(index, idStr)); - GetObjectNameMap(type).insert(std::make_pair(index, idStr)); + GetObjectNameMap(type).insert(std::make_pair(index, name)); return std::make_pair(name, idStr); } From e6c4175d8dff75d0a2a62ce15c4b4299130b40f8 Mon Sep 17 00:00:00 2001 From: RichardTea <31507749+RichardTea@users.noreply.github.com> Date: Fri, 1 May 2020 11:49:15 +0100 Subject: [PATCH 17/39] Rename Collada export tests Use existing naming convention. Brings all Collada tests together in Test Explorers --- test/CMakeLists.txt | 3 +- ...adaExportLight.cpp => utColladaExport.cpp} | 51 +++++++- test/unit/utColladaExportCamera.cpp | 115 ------------------ 3 files changed, 50 insertions(+), 119 deletions(-) rename test/unit/{utColladaExportLight.cpp => utColladaExport.cpp} (78%) delete mode 100644 test/unit/utColladaExportCamera.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bf6694845..a5f8086e9 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -124,8 +124,7 @@ SET( IMPORTERS unit/utBlendImportMaterials.cpp unit/utBlenderWork.cpp unit/utBVHImportExport.cpp - unit/utColladaExportCamera.cpp - unit/utColladaExportLight.cpp + unit/utColladaExport.cpp unit/utColladaImportExport.cpp unit/utCSMImportExport.cpp unit/utB3DImportExport.cpp diff --git a/test/unit/utColladaExportLight.cpp b/test/unit/utColladaExport.cpp similarity index 78% rename from test/unit/utColladaExportLight.cpp rename to test/unit/utColladaExport.cpp index 0327b296e..efb2d7f17 100644 --- a/test/unit/utColladaExportLight.cpp +++ b/test/unit/utColladaExport.cpp @@ -49,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_EXPORT -class ColladaExportLight : public ::testing::Test { +class utColladaExport : public ::testing::Test { public: void SetUp() override { ex = new Assimp::Exporter(); @@ -58,7 +58,9 @@ public: void TearDown() override { delete ex; + ex = nullptr; delete im; + im = nullptr; } protected: @@ -66,8 +68,53 @@ protected: Assimp::Importer *im; }; +TEST_F(utColladaExport, testExportCamera) { + const char *file = "cameraExp.dae"; + + const aiScene *pTest = im->ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/cameras.dae", aiProcess_ValidateDataStructure); + ASSERT_NE(nullptr, pTest); + ASSERT_TRUE(pTest->HasCameras()); + + EXPECT_EQ(AI_SUCCESS, ex->Export(pTest, "collada", file)); + const unsigned int origNumCams(pTest->mNumCameras); + std::unique_ptr origFOV(new float[origNumCams]); + std::unique_ptr orifClipPlaneNear(new float[origNumCams]); + std::unique_ptr orifClipPlaneFar(new float[origNumCams]); + std::unique_ptr names(new aiString[origNumCams]); + std::unique_ptr pos(new aiVector3D[origNumCams]); + for (size_t i = 0; i < origNumCams; i++) { + const aiCamera *orig = pTest->mCameras[i]; + ASSERT_NE(nullptr, orig); + + origFOV[i] = orig->mHorizontalFOV; + orifClipPlaneNear[i] = orig->mClipPlaneNear; + orifClipPlaneFar[i] = orig->mClipPlaneFar; + names[i] = orig->mName; + pos[i] = orig->mPosition; + } + const aiScene *imported = im->ReadFile(file, aiProcess_ValidateDataStructure); + + ASSERT_NE(nullptr, imported); + + EXPECT_TRUE(imported->HasCameras()); + EXPECT_EQ(origNumCams, imported->mNumCameras); + + for (size_t i = 0; i < imported->mNumCameras; i++) { + const aiCamera *read = imported->mCameras[i]; + + EXPECT_TRUE(names[i] == read->mName); + EXPECT_NEAR(origFOV[i], read->mHorizontalFOV, 0.0001f); + EXPECT_FLOAT_EQ(orifClipPlaneNear[i], read->mClipPlaneNear); + EXPECT_FLOAT_EQ(orifClipPlaneFar[i], read->mClipPlaneFar); + + EXPECT_FLOAT_EQ(pos[i].x, read->mPosition.x); + EXPECT_FLOAT_EQ(pos[i].y, read->mPosition.y); + EXPECT_FLOAT_EQ(pos[i].z, read->mPosition.z); + } +} + // ------------------------------------------------------------------------------------------------ -TEST_F(ColladaExportLight, testExportLight) { +TEST_F(utColladaExport, testExportLight) { const char *file = "lightsExp.dae"; const aiScene *pTest = im->ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/lights.dae", aiProcess_ValidateDataStructure); diff --git a/test/unit/utColladaExportCamera.cpp b/test/unit/utColladaExportCamera.cpp deleted file mode 100644 index c2c704056..000000000 --- a/test/unit/utColladaExportCamera.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2020, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ -#include "UnitTestPCH.h" - -#include -#include -#include -#include -#include - -#ifndef ASSIMP_BUILD_NO_EXPORT - -class ColladaExportCamera : public ::testing::Test { -public: - void SetUp() override { - ex = new Assimp::Exporter(); - im = new Assimp::Importer(); - } - - void TearDown() override { - delete ex; - ex = nullptr; - delete im; - im = nullptr; - } - -protected: - Assimp::Exporter *ex; - Assimp::Importer *im; -}; - -TEST_F(ColladaExportCamera, testExportCamera) { - const char *file = "cameraExp.dae"; - - const aiScene *pTest = im->ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/cameras.dae", aiProcess_ValidateDataStructure); - ASSERT_NE(nullptr, pTest); - ASSERT_TRUE(pTest->HasCameras()); - - EXPECT_EQ(AI_SUCCESS, ex->Export(pTest, "collada", file)); - const unsigned int origNumCams(pTest->mNumCameras); - std::unique_ptr origFOV(new float[origNumCams]); - std::unique_ptr orifClipPlaneNear(new float[origNumCams]); - std::unique_ptr orifClipPlaneFar(new float[origNumCams]); - std::unique_ptr names(new aiString[origNumCams]); - std::unique_ptr pos(new aiVector3D[origNumCams]); - for (size_t i = 0; i < origNumCams; i++) { - const aiCamera *orig = pTest->mCameras[i]; - ASSERT_NE(nullptr, orig); - - origFOV[i] = orig->mHorizontalFOV; - orifClipPlaneNear[i] = orig->mClipPlaneNear; - orifClipPlaneFar[i] = orig->mClipPlaneFar; - names[i] = orig->mName; - pos[i] = orig->mPosition; - } - const aiScene *imported = im->ReadFile(file, aiProcess_ValidateDataStructure); - - ASSERT_NE(nullptr, imported); - - EXPECT_TRUE(imported->HasCameras()); - EXPECT_EQ(origNumCams, imported->mNumCameras); - - for (size_t i = 0; i < imported->mNumCameras; i++) { - const aiCamera *read = imported->mCameras[i]; - - EXPECT_TRUE(names[i] == read->mName); - EXPECT_NEAR(origFOV[i], read->mHorizontalFOV, 0.0001f); - EXPECT_FLOAT_EQ(orifClipPlaneNear[i], read->mClipPlaneNear); - EXPECT_FLOAT_EQ(orifClipPlaneFar[i], read->mClipPlaneFar); - - EXPECT_FLOAT_EQ(pos[i].x, read->mPosition.x); - EXPECT_FLOAT_EQ(pos[i].y, read->mPosition.y); - EXPECT_FLOAT_EQ(pos[i].z, read->mPosition.z); - } -} - -#endif // ASSIMP_BUILD_NO_EXPORT From 5b9f207f1fd6bda7add462c77a5ab458111cb6f0 Mon Sep 17 00:00:00 2001 From: RichardTea <31507749+RichardTea@users.noreply.github.com> Date: Fri, 1 May 2020 11:39:43 +0100 Subject: [PATCH 18/39] ColladaExporter cleanup Namespace, NULL and includes --- code/Collada/ColladaExporter.cpp | 39 ++++++++++++++------------------ code/Collada/ColladaExporter.h | 8 +++---- include/assimp/ColladaMetaData.h | 4 ++-- 3 files changed, 23 insertions(+), 28 deletions(-) diff --git a/code/Collada/ColladaExporter.cpp b/code/Collada/ColladaExporter.cpp index a9137b50b..5e4cdda2d 100644 --- a/code/Collada/ColladaExporter.cpp +++ b/code/Collada/ColladaExporter.cpp @@ -44,9 +44,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER #include "ColladaExporter.h" + #include #include #include +#include #include #include #include @@ -57,15 +59,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include - #include -#include #include -#include -#include - -using namespace Assimp; namespace Assimp { @@ -84,7 +79,7 @@ void ExportSceneCollada(const char *pFile, IOSystem *pIOSystem, const aiScene *p // we're still here - export successfully completed. Write result to the given IOSYstem std::unique_ptr outfile(pIOSystem->Open(pFile, "wt")); - if (outfile == NULL) { + if (outfile == nullptr) { throw DeadlyExportError("could not open output .dae file: " + std::string(pFile)); } @@ -92,8 +87,6 @@ void ExportSceneCollada(const char *pFile, IOSystem *pIOSystem, const aiScene *p outfile->Write(iDoTheExportThing.mOutput.str().c_str(), static_cast(iDoTheExportThing.mOutput.tellp()), 1); } -} // end of namespace Assimp - // ------------------------------------------------------------------------------------------------ // Encodes a string into a valid XML ID using the xsd:ID schema qualifications. static const std::string XMLIDEncode(const std::string &name) { @@ -207,7 +200,7 @@ void ColladaExporter::WriteHeader() { static const unsigned int date_nb_chars = 20; char date_str[date_nb_chars]; - std::time_t date = std::time(NULL); + std::time_t date = std::time(nullptr); std::strftime(date_str, date_nb_chars, "%Y-%m-%dT%H:%M:%S", std::localtime(&date)); aiVector3D scaling; @@ -358,7 +351,7 @@ void ColladaExporter::WriteTextures() { std::string name = mFile + "_texture_" + (i < 1000 ? "0" : "") + (i < 100 ? "0" : "") + (i < 10 ? "0" : "") + str + "." + ((const char *)texture->achFormatHint); std::unique_ptr outfile(mIOSystem->Open(mPath + mIOSystem->getOsSeparator() + name, "wb")); - if (outfile == NULL) { + if (outfile == nullptr) { throw DeadlyExportError("could not open output texture file: " + mPath + name); } @@ -571,7 +564,7 @@ bool ColladaExporter::ReadMaterialSurface(Surface &poSurface, const aiMaterial & if (pSrcMat.GetTextureCount(pTexture) > 0) { aiString texfile; unsigned int uvChannel = 0; - pSrcMat.GetTexture(pTexture, 0, &texfile, NULL, &uvChannel); + pSrcMat.GetTexture(pTexture, 0, &texfile, nullptr, &uvChannel); std::string index_str(texfile.C_Str()); @@ -1420,7 +1413,7 @@ aiBone *findBone(const aiScene *scene, const aiString &name) { } } } - return NULL; + return nullptr; } // ------------------------------------------------------------------------------------------------ @@ -1474,7 +1467,7 @@ const aiNode *findSkeletonRootNode(const aiScene *scene, const aiMesh *mesh) { } } - return NULL; + return nullptr; } // ------------------------------------------------------------------------------------------------ @@ -1636,13 +1629,13 @@ inline std::string MakeUniqueId(const std::unordered_set &idSet, co return result; } -void Assimp::ColladaExporter::CreateNodeIds(const aiNode *node) { +void ColladaExporter::CreateNodeIds(const aiNode *node) { GetNodeUniqueId(node); for (size_t a = 0; a < node->mNumChildren; ++a) CreateNodeIds(node->mChildren[a]); } -std::string Assimp::ColladaExporter::GetNodeUniqueId(const aiNode *node) { +std::string ColladaExporter::GetNodeUniqueId(const aiNode *node) { // Use the pointer as the key. This is safe because the scene is immutable. auto idIt = mNodeIdMap.find(node); if (idIt != mNodeIdMap.cend()) @@ -1669,12 +1662,12 @@ std::string Assimp::ColladaExporter::GetNodeUniqueId(const aiNode *node) { return idStr; } -std::string Assimp::ColladaExporter::GetNodeName(const aiNode *node) { +std::string ColladaExporter::GetNodeName(const aiNode *node) { return XMLEscape(node->mName.C_Str()); } -std::string Assimp::ColladaExporter::GetBoneUniqueId(const aiBone *bone) { +std::string ColladaExporter::GetBoneUniqueId(const aiBone *bone) { // Find the Node that is this Bone const aiNode *boneNode = findBoneNode(mScene->mRootNode, bone); if (boneNode == nullptr) @@ -1683,7 +1676,7 @@ std::string Assimp::ColladaExporter::GetBoneUniqueId(const aiBone *bone) { return GetNodeUniqueId(boneNode); } -std::string Assimp::ColladaExporter::GetObjectUniqueId(AiObjectType type, size_t pIndex) { +std::string ColladaExporter::GetObjectUniqueId(AiObjectType type, size_t pIndex) { auto idIt = GetObjectIdMap(type).find(pIndex); if (idIt != GetObjectIdMap(type).cend()) return idIt->second; @@ -1693,7 +1686,7 @@ std::string Assimp::ColladaExporter::GetObjectUniqueId(AiObjectType type, size_t return result.second; } -std::string Assimp::ColladaExporter::GetObjectName(AiObjectType type, size_t pIndex) { +std::string ColladaExporter::GetObjectName(AiObjectType type, size_t pIndex) { auto objectName = GetObjectNameMap(type).find(pIndex); if (objectName != GetObjectNameMap(type).cend()) return objectName->second; @@ -1708,7 +1701,7 @@ std::string Assimp::ColladaExporter::GetObjectName(AiObjectType type, size_t pIn // @param index object index // @param name in/out. Caller to set the original name if known. // @param idStr in/out. Caller to set the preferred id if known. -Assimp::ColladaExporter::NameIdPair Assimp::ColladaExporter::AddObjectIndexToMaps(AiObjectType type, size_t index) { +ColladaExporter::NameIdPair ColladaExporter::AddObjectIndexToMaps(AiObjectType type, size_t index) { std::string name; std::string idStr; @@ -1758,5 +1751,7 @@ Assimp::ColladaExporter::NameIdPair Assimp::ColladaExporter::AddObjectIndexToMap return std::make_pair(name, idStr); } +} // end of namespace Assimp + #endif #endif diff --git a/code/Collada/ColladaExporter.h b/code/Collada/ColladaExporter.h index c6801395b..bea65bafc 100644 --- a/code/Collada/ColladaExporter.h +++ b/code/Collada/ColladaExporter.h @@ -46,12 +46,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_COLLADAEXPORTER_H_INC #define AI_COLLADAEXPORTER_H_INC -#include #include -#include #include -#include -#include #include #include @@ -61,9 +57,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. struct aiScene; struct aiNode; +struct aiLight; +struct aiBone; namespace Assimp { +class IOSystem; + /// Helper class to export a given scene to a Collada file. Just for my personal /// comfort when implementing it. class ColladaExporter { diff --git a/include/assimp/ColladaMetaData.h b/include/assimp/ColladaMetaData.h index 4288692c6..82aee78d0 100644 --- a/include/assimp/ColladaMetaData.h +++ b/include/assimp/ColladaMetaData.h @@ -47,7 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_COLLADAMETADATA_H_INC #define AI_COLLADAMETADATA_H_INC -#define AI_METADATA_COLLADA_ID "COLLADA_ID" -#define AI_METADATA_COLLADA_SID "COLLADA_SID" +#define AI_METADATA_COLLADA_ID "Collada_id" +#define AI_METADATA_COLLADA_SID "Collada_sid" #endif From 1dabb1a0946168332f601bb46bfdfa7743c64d18 Mon Sep 17 00:00:00 2001 From: RichardTea <31507749+RichardTea@users.noreply.github.com> Date: Fri, 1 May 2020 14:59:09 +0100 Subject: [PATCH 19/39] Collada: Fix crash with AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES Add unit test for this --- code/Collada/ColladaLoader.cpp | 13 ++++- test/unit/utColladaImportExport.cpp | 76 +++++++++++++++++++++++++---- 2 files changed, 77 insertions(+), 12 deletions(-) diff --git a/code/Collada/ColladaLoader.cpp b/code/Collada/ColladaLoader.cpp index c76954fdf..8ca0b130e 100644 --- a/code/Collada/ColladaLoader.cpp +++ b/code/Collada/ColladaLoader.cpp @@ -258,6 +258,15 @@ void ColladaLoader::InternReadFile(const std::string &pFile, aiScene *pScene, IO } } +// Add an item of metadata to a node +// Assumes the key is not already in the list +template +inline void AddNodeMetaData(aiNode *node, const std::string &key, const T &value) { + if (nullptr == node->mMetaData) + node->mMetaData = new aiMetadata(); + node->mMetaData->Add(key, value); +} + // ------------------------------------------------------------------------------------------------ // Recursively constructs a scene node for the given parser node and returns it. aiNode *ColladaLoader::BuildHierarchy(const ColladaParser &pParser, const Collada::Node *pNode) { @@ -269,9 +278,9 @@ aiNode *ColladaLoader::BuildHierarchy(const ColladaParser &pParser, const Collad // if we're not using the unique IDs, hold onto them for reference and export if (useColladaName) { if (!pNode->mID.empty()) - node->mMetaData->Add(AI_METADATA_COLLADA_ID, aiString(pNode->mID)); + AddNodeMetaData(node, AI_METADATA_COLLADA_ID, aiString(pNode->mID)); if (!pNode->mSID.empty()) - node->mMetaData->Add(AI_METADATA_COLLADA_SID, aiString(pNode->mSID)); + AddNodeMetaData(node, AI_METADATA_COLLADA_SID, aiString(pNode->mSID)); } // calculate the transformation matrix for it diff --git a/test/unit/utColladaImportExport.cpp b/test/unit/utColladaImportExport.cpp index 5b0c9f880..876f60c54 100644 --- a/test/unit/utColladaImportExport.cpp +++ b/test/unit/utColladaImportExport.cpp @@ -41,6 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AbstractImportExportBase.h" #include "UnitTestPCH.h" +#include #include #include #include @@ -85,6 +86,18 @@ public: typedef std::pair IdNameString; typedef std::map IdNameMap; + template + static inline IdNameString GetColladaIdName(const T *item, size_t index) { + std::ostringstream stream; + stream << typeid(T).name() << "@" << index; + if (item->mMetaData) { + aiString aiStr; + if (item->mMetaData->Get(AI_METADATA_COLLADA_ID, aiStr)) + return std::make_pair(std::string(aiStr.C_Str()), stream.str()); + } + return std::make_pair(std::string(), stream.str()); + } + template static inline IdNameString GetItemIdName(const T *item, size_t index) { std::ostringstream stream; @@ -121,11 +134,23 @@ public: static inline void CheckUniqueIds(IdNameMap &itemIdMap, const aiNode *parent, size_t index) { IdNameString namePair = GetItemIdName(parent, index); ReportDuplicate(itemIdMap, namePair, typeid(aiNode).name()); + for (size_t idx = 0; idx < parent->mNumChildren; ++idx) { CheckUniqueIds(itemIdMap, parent->mChildren[idx], idx); } } + static inline void CheckNodeIdNames(IdNameMap &nodeIdMap, IdNameMap &nodeNameMap, const aiNode *parent, size_t index) { + IdNameString namePair = GetItemIdName(parent, index); + const auto result = nodeNameMap.insert(namePair); + IdNameString idPair = GetColladaIdName(parent, index); + ReportDuplicate(nodeIdMap, idPair, typeid(aiNode).name()); + + for (size_t idx = 0; idx < parent->mNumChildren; ++idx) { + CheckNodeIdNames(nodeIdMap, nodeNameMap, parent->mChildren[idx], idx); + } + } + static inline void SetAllNodeNames(const aiString &newName, aiNode *node) { node->mName = newName; for (size_t idx = 0; idx < node->mNumChildren; ++idx) { @@ -133,12 +158,12 @@ public: } } - void ImportAndCheckIds(const char *file, size_t meshCount) { - // Import the Collada using the 'default' where aiMesh names are the Collada ids + void ImportAndCheckIds(const char *file, const aiScene *origScene) { + // Import the Collada using the 'default' where aiNode and aiMesh names are the Collada ids Assimp::Importer importer; const aiScene *scene = importer.ReadFile(file, aiProcess_ValidateDataStructure); ASSERT_TRUE(scene != nullptr) << "Fatal: could not re-import " << file; - EXPECT_EQ(meshCount, scene->mNumMeshes) << "in " << file; + EXPECT_EQ(origScene->mNumMeshes, scene->mNumMeshes) << "in " << file; // Check the ids are unique IdNameMap itemIdMap; @@ -146,11 +171,39 @@ public: CheckUniqueIds(itemIdMap, scene->mRootNode, 0); // Check the lists CheckUniqueIds(itemIdMap, scene->mNumMeshes, scene->mMeshes); - CheckUniqueIds(itemIdMap, scene->mNumAnimations, scene->mAnimations); - CheckUniqueIds(itemIdMap, scene->mNumMaterials, scene->mMaterials); - CheckUniqueIds(itemIdMap, scene->mNumTextures, scene->mTextures); - CheckUniqueIds(itemIdMap, scene->mNumLights, scene->mLights); - CheckUniqueIds(itemIdMap, scene->mNumCameras, scene->mCameras); + // The remaining will come in using the name, which may not be unique + // Check we have the right number + EXPECT_EQ(origScene->mNumAnimations, scene->mNumAnimations); + EXPECT_EQ(origScene->mNumMaterials, scene->mNumMaterials); + EXPECT_EQ(origScene->mNumTextures, scene->mNumTextures); + EXPECT_EQ(origScene->mNumLights, scene->mNumLights); + EXPECT_EQ(origScene->mNumCameras, scene->mNumCameras); + } + + void ImportAsNames(const char *file, const aiScene *origScene) { + // Import the Collada but using the user-visible names for aiNode and aiMesh + // Note that this mode may not support bones or animations + Assimp::Importer importer; + importer.SetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES, 1); + + const aiScene *scene = importer.ReadFile(file, aiProcess_ValidateDataStructure); + ASSERT_TRUE(scene != nullptr) << "Fatal: could not re-import " << file; + EXPECT_EQ(origScene->mNumMeshes, scene->mNumMeshes) << "in " << file; + + // Check the node ids are unique but the node names are not + IdNameMap nodeIdMap; + IdNameMap nodeNameMap; + // Recurse the Nodes + CheckNodeIdNames(nodeIdMap, nodeNameMap, scene->mRootNode, 0); + + // nodeNameMap should have fewer than nodeIdMap + EXPECT_LT(nodeNameMap.size(), nodeIdMap.size()) << "Some nodes should have the same names"; + // Check the counts haven't changed + EXPECT_EQ(origScene->mNumAnimations, scene->mNumAnimations); + EXPECT_EQ(origScene->mNumMaterials, scene->mNumMaterials); + EXPECT_EQ(origScene->mNumTextures, scene->mNumTextures); + EXPECT_EQ(origScene->mNumLights, scene->mNumLights); + EXPECT_EQ(origScene->mNumCameras, scene->mNumCameras); } }; @@ -192,7 +245,7 @@ TEST_F(utColladaImportExport, exporterUniqueIdsTest) { ASSERT_EQ(AI_SUCCESS, exporter.Export(scene, "collada", outFileEmpty)) << "Fatal: Could not export un-named meshes file"; - ImportAndCheckIds(outFileEmpty, 3); + ImportAndCheckIds(outFileEmpty, scene); // Force everything to have the same non-empty name aiString testName("test_name"); @@ -213,9 +266,12 @@ TEST_F(utColladaImportExport, exporterUniqueIdsTest) { scene->mCameras[idx]->mName = testName; } + SetAllNodeNames(testName, scene->mRootNode); + ASSERT_EQ(AI_SUCCESS, exporter.Export(scene, "collada", outFileNamed)) << "Fatal: Could not export named meshes file"; - ImportAndCheckIds(outFileNamed, 3); + ImportAndCheckIds(outFileNamed, scene); + ImportAsNames(outFileNamed, scene); } class utColladaZaeImportExport : public AbstractImportExportBase { From c6f2196f60fb219c1de423c0e27e04eba05c6c90 Mon Sep 17 00:00:00 2001 From: David Golembiowski Date: Fri, 1 May 2020 16:32:25 -0400 Subject: [PATCH 20/39] vector definitions --- port/assimp_rs/src/structs/vec.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/port/assimp_rs/src/structs/vec.rs b/port/assimp_rs/src/structs/vec.rs index e69de29bb..37e1c5150 100644 --- a/port/assimp_rs/src/structs/vec.rs +++ b/port/assimp_rs/src/structs/vec.rs @@ -0,0 +1,29 @@ +struct Vector2d { + x: f32, + y: f32 +} + +struct Vector3d { + x: f32, + y: f32, + z: f32 +} + +impl Vector2d { + pub fn new(x_f32: f32, y_f32: f32) -> Vector2d { + Vector2d { + x: x_f32, + y: y_f32 + } + } +} + +impl Vector3d { + pub fn new(x_f32: f32, y_f32: f32, z_f32: f32) -> Vector3d { + Vector3d { + x: x_f32, + y: y_f32, + z: z_f32 + } + } +} From c338c5ca02e4b05d50275844f8aa89895c69a1a1 Mon Sep 17 00:00:00 2001 From: David Golembiowski Date: Fri, 1 May 2020 16:47:35 -0400 Subject: [PATCH 21/39] Populating 3d and 4d matrix struct definitions --- port/assimp_rs/src/structs/matrix.rs | 64 ++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/port/assimp_rs/src/structs/matrix.rs b/port/assimp_rs/src/structs/matrix.rs index e69de29bb..4673b2d69 100644 --- a/port/assimp_rs/src/structs/matrix.rs +++ b/port/assimp_rs/src/structs/matrix.rs @@ -0,0 +1,64 @@ +#[derive(Clone, Debug, Copy)] +struct Matrix3x3 { + a1: f32, + a2: f32, + a3: f32, + b1: f32, + b2: f32, + b3: f32, + c1: f32, + c2: f32, + c3: f32 +} + +#[derive(Clone, Debug, Copy)] +struct Matrix4x4 { + a1: f32, + a2: f32, + a3: f32, + a4: f32, + b1: f32, + b2: f32, + b3: f32, + b4: f32, + c1: f32, + c2: f32, + c3: f32, + c4: f32, + d1: f32, + d2: f32, + d3: f32, + d4: f32 +} + +impl Matrix3x3 { + pub fn new( + a1_f32: f32, a2_f32: f32, a3_f32: f32, + b1_f32: f32, b2_f32: f32, b3_f32: f32, + c1_f32: f32, c2_f32: f32, c3_f32: f32 + ) -> Matrix3x3 { + Matrix3x3 { + a1: a1_f32, a2: a2_f32, a3: a3_f32, + b1: b1_f32, b2: b2_f32, b3: b3_f32, + c1: c1_f32, c2: c2_f32, c3: c3_f32 + } + } +} + +impl Matrix4x4 { + pub fn new( + a1_f32: f32, a2_f32: f32, a3_f32: f32, a4_f32: f32, + b1_f32: f32, b2_f32: f32, b3_f32: f32, b4_f32: f32, + c1_f32: f32, c2_f32: f32, c3_f32: f32, c4_f32: f32, + d1_f32: f32, d2_f32: f32, d3_f32: f32, d4_f32: f32 + ) -> Matrix4x4 { + Matrix4x4 { + a1: a1_f32, a2: a2_f32, a3: a3_f32, a4: a4_f32, + b1: b1_f32, b2: b2_f32, b3: b3_f32, b4: b4_f32, + c1: c1_f32, c2: c2_f32, c3: c3_f32, c4: c4_f32, + d1: d1_f32, d2: d2_f32, d3: d3_f32, d4: d4_f32 + } + } +} + + From 4f8eb0f79ca0c1d88fab2bd357527e1d40137ee8 Mon Sep 17 00:00:00 2001 From: David Golembiowski Date: Fri, 1 May 2020 16:50:31 -0400 Subject: [PATCH 22/39] populating Texel struct definition for textures --- port/assimp_rs/src/structs/texel.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/port/assimp_rs/src/structs/texel.rs b/port/assimp_rs/src/structs/texel.rs index e69de29bb..b2c72f30e 100644 --- a/port/assimp_rs/src/structs/texel.rs +++ b/port/assimp_rs/src/structs/texel.rs @@ -0,0 +1,19 @@ +#[derive(Clone, Debug, Copy)] +struct Texel { + b: u32, + g: u32, + r: u32, + a: u32 +} + +impl Texel { + pub fn new(b_u32: u32, g_u32: u32, + r_u32: u32, a_u32: u32) -> Texel { + Texel { + b: b_u32, + g: g_u32, + r: r_u32, + a: a_u32 + } + } +} From ba633f95bb1af4bbca82738a95bf569cef035a35 Mon Sep 17 00:00:00 2001 From: David Golembiowski Date: Fri, 1 May 2020 16:54:56 -0400 Subject: [PATCH 23/39] populating colors --- port/assimp_rs/src/structs/color.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/port/assimp_rs/src/structs/color.rs b/port/assimp_rs/src/structs/color.rs index e69de29bb..0b5fc6413 100644 --- a/port/assimp_rs/src/structs/color.rs +++ b/port/assimp_rs/src/structs/color.rs @@ -0,0 +1,27 @@ +#[derive(Clone, Debug, Copy)] +struct Color3D { + r: f32, + g: f32, + b: f32 +} + +impl Color3D { + pub fn new(r_f32: f32, g_f32: f32, b_f32: f32) -> Color3D { + Color3D {r: r_f32, g: g_f32, b: b_f32 } + } +} + +#[derive(Clone, Debug, Copy)] +struct Color4D { + r: f32, + g: f32, + b: f32, + a: f32 +} + +impl Color4D { + pub fn new(r_f32: f32, g_f32: f32, b_f32: f32, a_f32: f32) -> Color4D { + Color4D {r: r_f32, g: g_f32, b: b_f32, a: a_f32 } + } +} + From 38b80f6c6b7dd60b0366af8eaaeca9a179128f33 Mon Sep 17 00:00:00 2001 From: David Golembiowski Date: Fri, 1 May 2020 16:58:32 -0400 Subject: [PATCH 24/39] populating plane struct --- port/assimp_rs/src/structs/plane.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/port/assimp_rs/src/structs/plane.rs b/port/assimp_rs/src/structs/plane.rs index e69de29bb..2b0b74499 100644 --- a/port/assimp_rs/src/structs/plane.rs +++ b/port/assimp_rs/src/structs/plane.rs @@ -0,0 +1,23 @@ +#[derive(Clone, Debug, Copy)] +struct Plane { + a: f32, + b: f32, + c: f32, + d: f32 +} + +impl Plane { + pub fn new( + a_f32: f32, + b_f32: f32, + c_f32: f32, + d_f32: f32 + ) -> Plane { + Plane { + a: a_f32, + b: b_f32, + c: b_f32, + d: d_f32 + } + } +} From e6837f73949d1d797f71531d0d6ba08dfee6a5fb Mon Sep 17 00:00:00 2001 From: David Golembiowski Date: Fri, 1 May 2020 17:25:02 -0400 Subject: [PATCH 25/39] Need to consider different implementations of String kinds in Rust, and additionally how we may want to `impl Copy for Str`, i.e. `std::mem::swap` with placeholders to keep performance up. --- port/assimp_rs/src/structs/string.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/port/assimp_rs/src/structs/string.rs b/port/assimp_rs/src/structs/string.rs index e69de29bb..c99fabffb 100644 --- a/port/assimp_rs/src/structs/string.rs +++ b/port/assimp_rs/src/structs/string.rs @@ -0,0 +1,17 @@ +pub const MAXLEN: u32 = 1024; + +#[derive(Clone, Debug)] +struct Str { + length: u32, + data: Vec +} + +impl Str { + pub fn new(len_u32: u32, data_string: String) -> Str { + Str { + length: len_u32, + data: data_string.chars().collect() + } + } +} + From a286506c234068bbab212eb7de4c8ea5e853a934 Mon Sep 17 00:00:00 2001 From: David Golembiowski Date: Fri, 1 May 2020 17:32:55 -0400 Subject: [PATCH 26/39] fixed a couple of things. Adding MaterialPropertyString --- port/assimp_rs/src/structs/string.rs | 30 +++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/port/assimp_rs/src/structs/string.rs b/port/assimp_rs/src/structs/string.rs index c99fabffb..b88457df4 100644 --- a/port/assimp_rs/src/structs/string.rs +++ b/port/assimp_rs/src/structs/string.rs @@ -1,13 +1,16 @@ -pub const MAXLEN: u32 = 1024; +pub const MAXLEN: usize = 1024; +/// Want to consider replacing `Vec` +/// with a comparable definition at +/// https://doc.rust-lang.org/src/alloc/string.rs.html#415-417 #[derive(Clone, Debug)] struct Str { - length: u32, + length: usize, data: Vec } impl Str { - pub fn new(len_u32: u32, data_string: String) -> Str { + pub fn new(len_u32: usize, data_string: String) -> Str { Str { length: len_u32, data: data_string.chars().collect() @@ -15,3 +18,24 @@ impl Str { } } +/// MaterialPropertyStr +/// The size of length is truncated to 4 bytes on a 64-bit platform when used as a +/// material property (see MaterialSystem.cpp, as aiMaterial::AddProperty() ). +#[derive(Clone, Debug)] +struct MaterialPropertyStr { + length: usize, + data: Vec +} + + +impl MaterialPropertyStr { + pub fn new(len_u32: usize, data_string: String) -> MaterialPropertyStr { + MaterialPropertyStr { + length: len_u32, + data: data_string.chars().collect() + } + } +} + + + From 2d43a2447530fe2abe30f9aaeae558212734c231 Mon Sep 17 00:00:00 2001 From: David Golembiowski Date: Fri, 1 May 2020 17:41:16 -0400 Subject: [PATCH 27/39] memory info struct --- port/assimp_rs/src/structs/mem.rs | 0 port/assimp_rs/src/structs/memory.rs | 35 ++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) delete mode 100644 port/assimp_rs/src/structs/mem.rs create mode 100644 port/assimp_rs/src/structs/memory.rs diff --git a/port/assimp_rs/src/structs/mem.rs b/port/assimp_rs/src/structs/mem.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/port/assimp_rs/src/structs/memory.rs b/port/assimp_rs/src/structs/memory.rs new file mode 100644 index 000000000..c076f172a --- /dev/null +++ b/port/assimp_rs/src/structs/memory.rs @@ -0,0 +1,35 @@ +#[derive(Clone, Debug, Copy)] +struct MemoryInfo { + textures: u32, + materials: u32, + meshes: u32, + nodes: u32, + animations: u32, + cameras: u32, + lights: u32, + total: u32 +} + +impl MemoryInfo { + pub fn new( + textures_uint: u32, + materials_uint: u32, + meshes_uint: u32, + nodes_uint: u32, + animations_uint: u32, + cameras_uint: u32, + lights_uint: u32, + total_uint: u32) -> MemoryInfo { + + MemoryInfo { + textures: textures_uint, + materials: materials_uint, + meshes: meshes_uint, + nodes: nodes_uint, + animations: animations_uint, + cameras: cameras_uint, + lights: lights_uint, + total: total_uint + } + } +} From 778c3afbbb052bea25d6eaaccba1d663432b0b27 Mon Sep 17 00:00:00 2001 From: David Golembiowski Date: Fri, 1 May 2020 18:11:44 -0400 Subject: [PATCH 28/39] Rust's import system dictates that we must make directories rather than use individual files to provide a clean public interface --- port/PyAssimp/pyassimp/.structs.py.swp | Bin 0 -> 16384 bytes port/assimp_rs/src/camera/mod.rs | 1 + port/assimp_rs/src/structs/.mod.rs.swp | Bin 0 -> 12288 bytes port/assimp_rs/src/structs/{ => anim}/anim.rs | 0 port/assimp_rs/src/structs/anim/mod.rs | 2 ++ port/assimp_rs/src/structs/{ => blob}/blob.rs | 0 port/assimp_rs/src/structs/blob/mod.rs | 2 ++ port/assimp_rs/src/structs/{ => bone}/bone.rs | 0 port/assimp_rs/src/structs/bone/mod.rs | 2 ++ .../src/structs/{ => camera}/camera.rs | 0 port/assimp_rs/src/structs/camera/mod.rs | 2 ++ .../src/structs/{ => color}/color.rs | 0 port/assimp_rs/src/structs/color/mod.rs | 2 ++ port/assimp_rs/src/structs/{ => face}/face.rs | 0 port/assimp_rs/src/structs/face/mod.rs | 2 ++ port/assimp_rs/src/structs/{ => key}/key.rs | 0 port/assimp_rs/src/structs/key/mod.rs | 2 ++ .../src/structs/{ => light}/light.rs | 0 port/assimp_rs/src/structs/light/mod.rs | 2 ++ .../src/structs/{ => material}/material.rs | 0 port/assimp_rs/src/structs/material/mod.rs | 2 ++ .../src/structs/{ => matrix}/matrix.rs | 0 port/assimp_rs/src/structs/matrix/mod.rs | 2 ++ .../src/structs/{ => memory}/memory.rs | 0 port/assimp_rs/src/structs/memory/mod.rs | 2 ++ port/assimp_rs/src/structs/{ => mesh}/mesh.rs | 0 port/assimp_rs/src/structs/mesh/mod.rs | 2 ++ port/assimp_rs/src/structs/{ => meta}/meta.rs | 0 port/assimp_rs/src/structs/meta/mod.rs | 2 ++ port/assimp_rs/src/structs/node/mod.rs | 2 ++ port/assimp_rs/src/structs/{ => node}/node.rs | 0 port/assimp_rs/src/structs/plane/mod.rs | 2 ++ .../src/structs/{ => plane}/plane.rs | 0 port/assimp_rs/src/structs/quaternion/mod.rs | 2 ++ .../src/structs/quaternion/quaternion.rs | 7 +++++++ port/assimp_rs/src/structs/ray/mod.rs | 2 ++ port/assimp_rs/src/structs/{ => ray}/ray.rs | 0 port/assimp_rs/src/structs/scene/mod.rs | 2 ++ .../src/structs/{ => scene}/scene.rs | 0 port/assimp_rs/src/structs/string/mod.rs | 2 ++ .../src/structs/{ => string}/string.rs | 0 port/assimp_rs/src/structs/texel/mod.rs | 2 ++ .../src/structs/{ => texel}/texel.rs | 0 port/assimp_rs/src/structs/texture/mod.rs | 2 ++ .../src/structs/{ => texture}/texture.rs | 0 port/assimp_rs/src/structs/transform/mod.rs | 2 ++ .../src/structs/{ => transform}/transform.rs | 0 port/assimp_rs/src/structs/vec/mod.rs | 2 ++ port/assimp_rs/src/structs/{ => vec}/vec.rs | 19 ++++++++++++++++++ port/assimp_rs/src/structs/vertex/mod.rs | 2 ++ .../{quaternion.rs => vertex/vertex.rs} | 0 port/assimp_rs/src/structs/vertex_weight.rs | 0 52 files changed, 75 insertions(+) create mode 100644 port/PyAssimp/pyassimp/.structs.py.swp create mode 100644 port/assimp_rs/src/structs/.mod.rs.swp rename port/assimp_rs/src/structs/{ => anim}/anim.rs (100%) create mode 100644 port/assimp_rs/src/structs/anim/mod.rs rename port/assimp_rs/src/structs/{ => blob}/blob.rs (100%) create mode 100644 port/assimp_rs/src/structs/blob/mod.rs rename port/assimp_rs/src/structs/{ => bone}/bone.rs (100%) create mode 100644 port/assimp_rs/src/structs/bone/mod.rs rename port/assimp_rs/src/structs/{ => camera}/camera.rs (100%) create mode 100644 port/assimp_rs/src/structs/camera/mod.rs rename port/assimp_rs/src/structs/{ => color}/color.rs (100%) create mode 100644 port/assimp_rs/src/structs/color/mod.rs rename port/assimp_rs/src/structs/{ => face}/face.rs (100%) create mode 100644 port/assimp_rs/src/structs/face/mod.rs rename port/assimp_rs/src/structs/{ => key}/key.rs (100%) create mode 100644 port/assimp_rs/src/structs/key/mod.rs rename port/assimp_rs/src/structs/{ => light}/light.rs (100%) create mode 100644 port/assimp_rs/src/structs/light/mod.rs rename port/assimp_rs/src/structs/{ => material}/material.rs (100%) create mode 100644 port/assimp_rs/src/structs/material/mod.rs rename port/assimp_rs/src/structs/{ => matrix}/matrix.rs (100%) create mode 100644 port/assimp_rs/src/structs/matrix/mod.rs rename port/assimp_rs/src/structs/{ => memory}/memory.rs (100%) create mode 100644 port/assimp_rs/src/structs/memory/mod.rs rename port/assimp_rs/src/structs/{ => mesh}/mesh.rs (100%) create mode 100644 port/assimp_rs/src/structs/mesh/mod.rs rename port/assimp_rs/src/structs/{ => meta}/meta.rs (100%) create mode 100644 port/assimp_rs/src/structs/meta/mod.rs create mode 100644 port/assimp_rs/src/structs/node/mod.rs rename port/assimp_rs/src/structs/{ => node}/node.rs (100%) create mode 100644 port/assimp_rs/src/structs/plane/mod.rs rename port/assimp_rs/src/structs/{ => plane}/plane.rs (100%) create mode 100644 port/assimp_rs/src/structs/quaternion/mod.rs create mode 100644 port/assimp_rs/src/structs/quaternion/quaternion.rs create mode 100644 port/assimp_rs/src/structs/ray/mod.rs rename port/assimp_rs/src/structs/{ => ray}/ray.rs (100%) create mode 100644 port/assimp_rs/src/structs/scene/mod.rs rename port/assimp_rs/src/structs/{ => scene}/scene.rs (100%) create mode 100644 port/assimp_rs/src/structs/string/mod.rs rename port/assimp_rs/src/structs/{ => string}/string.rs (100%) create mode 100644 port/assimp_rs/src/structs/texel/mod.rs rename port/assimp_rs/src/structs/{ => texel}/texel.rs (100%) create mode 100644 port/assimp_rs/src/structs/texture/mod.rs rename port/assimp_rs/src/structs/{ => texture}/texture.rs (100%) create mode 100644 port/assimp_rs/src/structs/transform/mod.rs rename port/assimp_rs/src/structs/{ => transform}/transform.rs (100%) create mode 100644 port/assimp_rs/src/structs/vec/mod.rs rename port/assimp_rs/src/structs/{ => vec}/vec.rs (60%) create mode 100644 port/assimp_rs/src/structs/vertex/mod.rs rename port/assimp_rs/src/structs/{quaternion.rs => vertex/vertex.rs} (100%) delete mode 100644 port/assimp_rs/src/structs/vertex_weight.rs diff --git a/port/PyAssimp/pyassimp/.structs.py.swp b/port/PyAssimp/pyassimp/.structs.py.swp new file mode 100644 index 0000000000000000000000000000000000000000..1de72f0f8f12a4e35de38089723ca2b124ce4459 GIT binary patch literal 16384 zcmeI3%a0sK9mgB6iHYMl1TIK{RK^0&Mzga|k;Me0C3d7GyX&=g6Cwzi)O6R(R9xLX z>8_rgK@kuRJYvMdjs(Kt0$BV3Mu?Xp3oPIO7X$(h9EcRK5lARPfjkI&tGap~J>#7j zBo3fz`Qx7MU)8UxzV(={U(HtMA6VNUE9C_T$1RStx&HNsfAQV}PW4{L@o0;C>i(ER z(54KVV-msqQSETf4Lvs3VnHjOqjAjr=3Fz3;2<0Si4ogDqt0`3RnfK0#*U5fK|XM@PDL$Y~JL24E1@f zsnh4o`8B!ozs&Ktx&Qf`{Z(Us$lO0@9Atj}Y3wJBy`HnbV(i@5zn!zcZ0wI3`|YN{ zng5rJ{kXAzCTD-q*td=S=Q;a7jQxzUlh>smGXH-!_PVj3&Dmct_J@uA`JCNcI>gww z_N5;(|K_$mSp}>DRspMkRlq7>6|f3e1*`&A0jq#j;J=~(#RmT@JU^kqfUkisgD-&q)WF@~-Qd~{s53YVo&;^M3u@q2@XYIx2dsnpz+1rI_Cp774g3sT z0T;nn!PDR@_#jvTcY*!jS;QHB4=#c8;2iM432+>|5&Q+gi9drMfD7O&;0(AAydN9} ze?|ZJ19%Sn6kG;RgQviGa1N+G^l>oNL2y)RoCz$u|E8BZB)}5+0K@Prkzn7Sv^zIheYVA>lG6Eb!9NuS8PE5kf>* z=PpKU`e>Ce%@Y$h3@~A6Z};!qJG(;sL`bflNMiO_!UC7YcaSxCG<`pTkX?>V`>gVSaHrl`m`UZf|Qw zVUtC&Ly9qG!VS|2w>z<9e%Wm{3FX<%W5-rKZ_A`F&h*cdGpSTNN=4OlP{wG4LSmu} z(s>QiE}Lcu1M<%0*(w^iDX7Gh>&Ilb!2*)Rm;h-^%mk(9=d1+1V(mFgXUVg&rk%_7 z*8kbwsyo3XbJH{}9qFl~CPIoY=3=2fcvSaiq$wEUlf^XE za(lVdi}L38Qv9umw-BGyD=M{csWgWozH5Qn$3cu#1)WR83rP@4M069k(Q~Y%Ef)L@ zZ1I@bv{@q+vs*Jmj$Im%DocZth+?WO8*I-YYDwj6++;4VahLeUqY7W{G9mKu<0Rm6 z7Lno>i(<7cQX>7I0xyhWf*4YWh;BrDY*>h%Z&lJX?(6h-4eTMQP_VLQG3c1oMOcLf z-Qw&vxZ6PSMHti(jt$djx62UZ5&R4rQs$oSR!}BPc1|rb!}{o`wepy+GmRpO;4-ff z*5TpH{u2p)E)hMFm#B3q8INK#yOol@h#MYShf_(mF;+x_jtqwLTRnQhZio330 z!2@!BR%p(!wdQ&MbiqD6=pQVP>s~n(()k6Z5)<|H0+gA z_t%lzf9gSMi?2h%rrIZ?qNFP2hq@*)HY=oRTq+TPs3zD-*yX4Ly5W4TYN|-ReU5G= nwF)HG%|eW7Lj_&W_7Sr-&d%B}qN)3((b5kzPU^1PHqO5R$L{t! literal 0 HcmV?d00001 diff --git a/port/assimp_rs/src/camera/mod.rs b/port/assimp_rs/src/camera/mod.rs index e69de29bb..26ca1185b 100644 --- a/port/assimp_rs/src/camera/mod.rs +++ b/port/assimp_rs/src/camera/mod.rs @@ -0,0 +1 @@ +pub use self::structs::{Camera}; diff --git a/port/assimp_rs/src/structs/.mod.rs.swp b/port/assimp_rs/src/structs/.mod.rs.swp new file mode 100644 index 0000000000000000000000000000000000000000..a6b06ed631bd7b51b0450777a8e7c266e3c9b7eb GIT binary patch literal 12288 zcmeI2J!lj`6vrnP+L&mxwOBtO5HOqMt_U0iV-iKei7{SEh|Ig3(heX@lGo;^SfLz&vlmXl7!`TThI@)NcbI*c9hSRY9+a!XHvU( zMJiv(&{tZvL#_NIi^indy*6c#0Wz?Ifwo>fJvG>dqiZe1P4;q4v3hO}qQRUw1d88yO%2WPl8i0Wv@a$N(8217v^< zkO4BV2Muuiz&~@4vBn@akKg~x|Np-oV(c^c2;PC$;3aql9)k^VAKV4&K!O-t1DC-Z zI0LF+1RMjyU_aOgz7H|>1#E-&U<)qicSu_%17v^&eA{E}K&+q}Wr_7*c!yq#e5*o`_Bu~|9CX+HvmlH**%$qO04|6^L7FO zbjxF2s>BvW+;6=sLY>J4(KFo^u}2ryg=*F_nK#YY9oK}W@O1&h&e&`gXR;cZ6dP6| zn-ZF7`@&{{f$b)%LKXO3(*H*$SciunYOxj9J6Eji9=Fh{%sA%q7 Vector2d { Vector2d { @@ -27,3 +34,15 @@ impl Vector3d { } } } + +impl Vector4d { + pub fn new(x_f32: f32, y_f32: f32, z_f32: f32, w_f32: f32) -> Vector4d { + Vector4d { + x: x_f32, + y: y_f32, + z: z_f32, + w: w_f32 + } + } +} + diff --git a/port/assimp_rs/src/structs/vertex/mod.rs b/port/assimp_rs/src/structs/vertex/mod.rs new file mode 100644 index 000000000..d169246ce --- /dev/null +++ b/port/assimp_rs/src/structs/vertex/mod.rs @@ -0,0 +1,2 @@ +mod vertex; + diff --git a/port/assimp_rs/src/structs/quaternion.rs b/port/assimp_rs/src/structs/vertex/vertex.rs similarity index 100% rename from port/assimp_rs/src/structs/quaternion.rs rename to port/assimp_rs/src/structs/vertex/vertex.rs diff --git a/port/assimp_rs/src/structs/vertex_weight.rs b/port/assimp_rs/src/structs/vertex_weight.rs deleted file mode 100644 index e69de29bb..000000000 From 57e837092e6aaedf69912729b45568af30a20ffc Mon Sep 17 00:00:00 2001 From: David Golembiowski Date: Fri, 1 May 2020 18:23:14 -0400 Subject: [PATCH 29/39] populated module level files --- port/PyAssimp/pyassimp/.structs.py.swp | Bin 16384 -> 0 bytes port/assimp_rs/src/structs/.mod.rs.swp | Bin 12288 -> 0 bytes port/assimp_rs/src/structs/anim/mod.rs | 6 +++++- port/assimp_rs/src/structs/color/mod.rs | 5 ++++- port/assimp_rs/src/structs/matrix/mod.rs | 4 +++- port/assimp_rs/src/structs/memory/mod.rs | 2 +- port/assimp_rs/src/structs/mesh/mod.rs | 1 + port/assimp_rs/src/structs/quaternion/mod.rs | 1 + port/assimp_rs/src/structs/string/mod.rs | 3 ++- port/assimp_rs/src/structs/texel/mod.rs | 2 -- port/assimp_rs/src/structs/texel/texel.rs | 19 ------------------ port/assimp_rs/src/structs/texture/mod.rs | 1 + port/assimp_rs/src/structs/texture/texture.rs | 19 ++++++++++++++++++ port/assimp_rs/src/structs/vertex/mod.rs | 2 +- 14 files changed, 38 insertions(+), 27 deletions(-) delete mode 100644 port/PyAssimp/pyassimp/.structs.py.swp delete mode 100644 port/assimp_rs/src/structs/.mod.rs.swp delete mode 100644 port/assimp_rs/src/structs/texel/mod.rs delete mode 100644 port/assimp_rs/src/structs/texel/texel.rs diff --git a/port/PyAssimp/pyassimp/.structs.py.swp b/port/PyAssimp/pyassimp/.structs.py.swp deleted file mode 100644 index 1de72f0f8f12a4e35de38089723ca2b124ce4459..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 zcmeI3%a0sK9mgB6iHYMl1TIK{RK^0&Mzga|k;Me0C3d7GyX&=g6Cwzi)O6R(R9xLX z>8_rgK@kuRJYvMdjs(Kt0$BV3Mu?Xp3oPIO7X$(h9EcRK5lARPfjkI&tGap~J>#7j zBo3fz`Qx7MU)8UxzV(={U(HtMA6VNUE9C_T$1RStx&HNsfAQV}PW4{L@o0;C>i(ER z(54KVV-msqQSETf4Lvs3VnHjOqjAjr=3Fz3;2<0Si4ogDqt0`3RnfK0#*U5fK|XM@PDL$Y~JL24E1@f zsnh4o`8B!ozs&Ktx&Qf`{Z(Us$lO0@9Atj}Y3wJBy`HnbV(i@5zn!zcZ0wI3`|YN{ zng5rJ{kXAzCTD-q*td=S=Q;a7jQxzUlh>smGXH-!_PVj3&Dmct_J@uA`JCNcI>gww z_N5;(|K_$mSp}>DRspMkRlq7>6|f3e1*`&A0jq#j;J=~(#RmT@JU^kqfUkisgD-&q)WF@~-Qd~{s53YVo&;^M3u@q2@XYIx2dsnpz+1rI_Cp774g3sT z0T;nn!PDR@_#jvTcY*!jS;QHB4=#c8;2iM432+>|5&Q+gi9drMfD7O&;0(AAydN9} ze?|ZJ19%Sn6kG;RgQviGa1N+G^l>oNL2y)RoCz$u|E8BZB)}5+0K@Prkzn7Sv^zIheYVA>lG6Eb!9NuS8PE5kf>* z=PpKU`e>Ce%@Y$h3@~A6Z};!qJG(;sL`bflNMiO_!UC7YcaSxCG<`pTkX?>V`>gVSaHrl`m`UZf|Qw zVUtC&Ly9qG!VS|2w>z<9e%Wm{3FX<%W5-rKZ_A`F&h*cdGpSTNN=4OlP{wG4LSmu} z(s>QiE}Lcu1M<%0*(w^iDX7Gh>&Ilb!2*)Rm;h-^%mk(9=d1+1V(mFgXUVg&rk%_7 z*8kbwsyo3XbJH{}9qFl~CPIoY=3=2fcvSaiq$wEUlf^XE za(lVdi}L38Qv9umw-BGyD=M{csWgWozH5Qn$3cu#1)WR83rP@4M069k(Q~Y%Ef)L@ zZ1I@bv{@q+vs*Jmj$Im%DocZth+?WO8*I-YYDwj6++;4VahLeUqY7W{G9mKu<0Rm6 z7Lno>i(<7cQX>7I0xyhWf*4YWh;BrDY*>h%Z&lJX?(6h-4eTMQP_VLQG3c1oMOcLf z-Qw&vxZ6PSMHti(jt$djx62UZ5&R4rQs$oSR!}BPc1|rb!}{o`wepy+GmRpO;4-ff z*5TpH{u2p)E)hMFm#B3q8INK#yOol@h#MYShf_(mF;+x_jtqwLTRnQhZio330 z!2@!BR%p(!wdQ&MbiqD6=pQVP>s~n(()k6Z5)<|H0+gA z_t%lzf9gSMi?2h%rrIZ?qNFP2hq@*)HY=oRTq+TPs3zD-*yX4Ly5W4TYN|-ReU5G= nwF)HG%|eW7Lj_&W_7Sr-&d%B}qN)3((b5kzPU^1PHqO5R$L{t! diff --git a/port/assimp_rs/src/structs/.mod.rs.swp b/port/assimp_rs/src/structs/.mod.rs.swp deleted file mode 100644 index a6b06ed631bd7b51b0450777a8e7c266e3c9b7eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2J!lj`6vrnP+L&mxwOBtO5HOqMt_U0iV-iKei7{SEh|Ig3(heX@lGo;^SfLz&vlmXl7!`TThI@)NcbI*c9hSRY9+a!XHvU( zMJiv(&{tZvL#_NIi^indy*6c#0Wz?Ifwo>fJvG>dqiZe1P4;q4v3hO}qQRUw1d88yO%2WPl8i0Wv@a$N(8217v^< zkO4BV2Muuiz&~@4vBn@akKg~x|Np-oV(c^c2;PC$;3aql9)k^VAKV4&K!O-t1DC-Z zI0LF+1RMjyU_aOgz7H|>1#E-&U<)qicSu_%17v^&eA{E}K&+q}Wr_7*c!yq#e5*o`_Bu~|9CX+HvmlH**%$qO04|6^L7FO zbjxF2s>BvW+;6=sLY>J4(KFo^u}2ryg=*F_nK#YY9oK}W@O1&h&e&`gXR;cZ6dP6| zn-ZF7`@&{{f$b)%LKXO3(*H*$SciunYOxj9J6Eji9=Fh{%sA%q7 Texel { - Texel { - b: b_u32, - g: g_u32, - r: r_u32, - a: a_u32 - } - } -} diff --git a/port/assimp_rs/src/structs/texture/mod.rs b/port/assimp_rs/src/structs/texture/mod.rs index a9d56e75b..1b5c9308d 100644 --- a/port/assimp_rs/src/structs/texture/mod.rs +++ b/port/assimp_rs/src/structs/texture/mod.rs @@ -1,2 +1,3 @@ mod texture; +pub use self::texture::Texel; diff --git a/port/assimp_rs/src/structs/texture/texture.rs b/port/assimp_rs/src/structs/texture/texture.rs index e69de29bb..b2c72f30e 100644 --- a/port/assimp_rs/src/structs/texture/texture.rs +++ b/port/assimp_rs/src/structs/texture/texture.rs @@ -0,0 +1,19 @@ +#[derive(Clone, Debug, Copy)] +struct Texel { + b: u32, + g: u32, + r: u32, + a: u32 +} + +impl Texel { + pub fn new(b_u32: u32, g_u32: u32, + r_u32: u32, a_u32: u32) -> Texel { + Texel { + b: b_u32, + g: g_u32, + r: r_u32, + a: a_u32 + } + } +} diff --git a/port/assimp_rs/src/structs/vertex/mod.rs b/port/assimp_rs/src/structs/vertex/mod.rs index d169246ce..97ae3eced 100644 --- a/port/assimp_rs/src/structs/vertex/mod.rs +++ b/port/assimp_rs/src/structs/vertex/mod.rs @@ -1,2 +1,2 @@ mod vertex; - +// pub use self::vertex:: From ea917bd4aeaae6c8e9249f3d3e6c74a8fae981aa Mon Sep 17 00:00:00 2001 From: RichardTea <31507749+RichardTea@users.noreply.github.com> Date: Mon, 4 May 2020 13:54:49 +0100 Subject: [PATCH 30/39] Move Collada into AssetLib folder Should make the merge easier --- code/{ => AssetLib}/Collada/ColladaExporter.cpp | 0 code/{ => AssetLib}/Collada/ColladaExporter.h | 0 code/{ => AssetLib}/Collada/ColladaHelper.cpp | 0 code/{ => AssetLib}/Collada/ColladaHelper.h | 0 code/{ => AssetLib}/Collada/ColladaLoader.cpp | 0 code/{ => AssetLib}/Collada/ColladaLoader.h | 0 code/{ => AssetLib}/Collada/ColladaParser.cpp | 0 code/{ => AssetLib}/Collada/ColladaParser.h | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename code/{ => AssetLib}/Collada/ColladaExporter.cpp (100%) rename code/{ => AssetLib}/Collada/ColladaExporter.h (100%) rename code/{ => AssetLib}/Collada/ColladaHelper.cpp (100%) rename code/{ => AssetLib}/Collada/ColladaHelper.h (100%) rename code/{ => AssetLib}/Collada/ColladaLoader.cpp (100%) rename code/{ => AssetLib}/Collada/ColladaLoader.h (100%) rename code/{ => AssetLib}/Collada/ColladaParser.cpp (100%) rename code/{ => AssetLib}/Collada/ColladaParser.h (100%) diff --git a/code/Collada/ColladaExporter.cpp b/code/AssetLib/Collada/ColladaExporter.cpp similarity index 100% rename from code/Collada/ColladaExporter.cpp rename to code/AssetLib/Collada/ColladaExporter.cpp diff --git a/code/Collada/ColladaExporter.h b/code/AssetLib/Collada/ColladaExporter.h similarity index 100% rename from code/Collada/ColladaExporter.h rename to code/AssetLib/Collada/ColladaExporter.h diff --git a/code/Collada/ColladaHelper.cpp b/code/AssetLib/Collada/ColladaHelper.cpp similarity index 100% rename from code/Collada/ColladaHelper.cpp rename to code/AssetLib/Collada/ColladaHelper.cpp diff --git a/code/Collada/ColladaHelper.h b/code/AssetLib/Collada/ColladaHelper.h similarity index 100% rename from code/Collada/ColladaHelper.h rename to code/AssetLib/Collada/ColladaHelper.h diff --git a/code/Collada/ColladaLoader.cpp b/code/AssetLib/Collada/ColladaLoader.cpp similarity index 100% rename from code/Collada/ColladaLoader.cpp rename to code/AssetLib/Collada/ColladaLoader.cpp diff --git a/code/Collada/ColladaLoader.h b/code/AssetLib/Collada/ColladaLoader.h similarity index 100% rename from code/Collada/ColladaLoader.h rename to code/AssetLib/Collada/ColladaLoader.h diff --git a/code/Collada/ColladaParser.cpp b/code/AssetLib/Collada/ColladaParser.cpp similarity index 100% rename from code/Collada/ColladaParser.cpp rename to code/AssetLib/Collada/ColladaParser.cpp diff --git a/code/Collada/ColladaParser.h b/code/AssetLib/Collada/ColladaParser.h similarity index 100% rename from code/Collada/ColladaParser.h rename to code/AssetLib/Collada/ColladaParser.h From 8e73984a1105f6b713942fd8125e5bf9cd3e2f6e Mon Sep 17 00:00:00 2001 From: RichardTea <31507749+RichardTea@users.noreply.github.com> Date: Mon, 4 May 2020 17:47:09 +0100 Subject: [PATCH 31/39] Collada Root Nodes aren't allowed to have meshes Create a null parent node instead --- code/AssetLib/Collada/ColladaExporter.cpp | 12 +++-- code/AssetLib/Collada/ColladaParser.cpp | 2 +- test/unit/utColladaImportExport.cpp | 55 +++++++++++++++++++++++ 3 files changed, 61 insertions(+), 8 deletions(-) diff --git a/code/AssetLib/Collada/ColladaExporter.cpp b/code/AssetLib/Collada/ColladaExporter.cpp index 5e4cdda2d..e15e81985 100644 --- a/code/AssetLib/Collada/ColladaExporter.cpp +++ b/code/AssetLib/Collada/ColladaExporter.cpp @@ -233,12 +233,13 @@ void ColladaExporter::WriteHeader() { add_root_node = true; } - if (mScene->mRootNode->mNumChildren == 0) { + // Assimp root nodes can have meshes, Collada Scenes cannot + if (mScene->mRootNode->mNumChildren == 0 || mScene->mRootNode->mMeshes != 0) { add_root_node = true; } if (add_root_node) { - aiScene *scene; + aiScene *scene = nullptr; SceneCombiner::CopyScene(&scene, mScene); aiNode *root = new aiNode("Scene"); @@ -1493,12 +1494,9 @@ void ColladaExporter::WriteNode(const aiNode *pNode) { const std::string node_name = GetNodeName(pNode); mOutput << startstr << "" << endstr; diff --git a/code/AssetLib/Collada/ColladaParser.cpp b/code/AssetLib/Collada/ColladaParser.cpp index d83980929..04e6eb7d4 100644 --- a/code/AssetLib/Collada/ColladaParser.cpp +++ b/code/AssetLib/Collada/ColladaParser.cpp @@ -2479,7 +2479,7 @@ void ColladaParser::ReadSceneLibrary() { // read name if given. int indexName = TestAttribute("name"); - const char *attrName = "unnamed"; + const char *attrName = "Scene"; if (indexName > -1) attrName = mReader->getAttributeValue(indexName); diff --git a/test/unit/utColladaImportExport.cpp b/test/unit/utColladaImportExport.cpp index 876f60c54..3d6e0db23 100644 --- a/test/unit/utColladaImportExport.cpp +++ b/test/unit/utColladaImportExport.cpp @@ -42,6 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "UnitTestPCH.h" #include +#include #include #include #include @@ -211,6 +212,60 @@ TEST_F(utColladaImportExport, importDaeFromFileTest) { EXPECT_TRUE(importerTest()); } +unsigned int GetMeshUseCount(const aiNode *rootNode) { + unsigned int result = rootNode->mNumMeshes; + for (unsigned int i = 0; i < rootNode->mNumChildren; ++i) { + result += GetMeshUseCount(rootNode->mChildren[i]); + } + return result; +} + +TEST_F(utColladaImportExport, exportRootNodeMeshTest) { + Assimp::Importer importer; + Assimp::Exporter exporter; + const char *outFile = "exportRootNodeMeshTest_out.dae"; + + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/duck.dae", aiProcess_ValidateDataStructure); + ASSERT_TRUE(scene != nullptr) << "Fatal: could not import duck.dae!"; + + ASSERT_EQ(0u, scene->mRootNode->mNumMeshes) << "Collada import should not give the root node a mesh"; + + { + // Clone the scene and give the root node a mesh and a transform + aiScene *rootMeshScene = nullptr; + SceneCombiner::CopyScene(&rootMeshScene, scene); + ASSERT_TRUE(rootMeshScene != nullptr) << "Fatal: could not copy scene!"; + // Do this by moving the meshes from the first child that has some + aiNode *rootNode = rootMeshScene->mRootNode; + ASSERT_TRUE(rootNode->mNumChildren > 0) << "Fatal: root has no children"; + aiNode *meshNode = rootNode->mChildren[0]; + ASSERT_EQ(1u, meshNode->mNumMeshes) << "Fatal: First child node has no duck mesh"; + + // Move the meshes to the parent + rootNode->mNumMeshes = meshNode->mNumMeshes; + rootNode->mMeshes = new unsigned int[rootNode->mNumMeshes]; + for (unsigned int i = 0; i < rootNode->mNumMeshes; ++i) { + rootNode->mMeshes[i] = meshNode->mMeshes[i]; + } + + meshNode->mNumMeshes = 0; + delete[] meshNode->mMeshes; + + ASSERT_EQ(AI_SUCCESS, exporter.Export(rootMeshScene, "collada", outFile)) << "Fatal: Could not export file"; + } + + // Reimport and look for meshes + scene = importer.ReadFile(outFile, aiProcess_ValidateDataStructure); + ASSERT_TRUE(scene != nullptr) << "Fatal: could not reimport!"; + + // A Collada root node is not allowed to have a mesh + ASSERT_EQ(0u, scene->mRootNode->mNumMeshes) << "Collada reimport should not give the root node a mesh"; + + // Walk nodes and counts used meshes + // Should be exactly one + EXPECT_EQ(1u, GetMeshUseCount(scene->mRootNode)) << "Nodes had unexpected number of meshes in use"; +} + TEST_F(utColladaImportExport, exporterUniqueIdsTest) { Assimp::Importer importer; Assimp::Exporter exporter; From d1ae6ac77a9380b3b915262d2f5682739c8e8ac1 Mon Sep 17 00:00:00 2001 From: RichardTea <31507749+RichardTea@users.noreply.github.com> Date: Tue, 5 May 2020 09:51:41 +0100 Subject: [PATCH 32/39] Fix typo in Swapped Id and Name --- code/AssetLib/Collada/ColladaExporter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/AssetLib/Collada/ColladaExporter.cpp b/code/AssetLib/Collada/ColladaExporter.cpp index 5e4cdda2d..3f4f53a3d 100644 --- a/code/AssetLib/Collada/ColladaExporter.cpp +++ b/code/AssetLib/Collada/ColladaExporter.cpp @@ -1226,8 +1226,8 @@ void ColladaExporter::WriteFloatArray(const std::string &pIdString, FloatDataTyp // ------------------------------------------------------------------------------------------------ // Writes the scene library void ColladaExporter::WriteSceneLibrary() { - const std::string sceneName = GetNodeUniqueId(mScene->mRootNode); - const std::string sceneId = GetNodeName(mScene->mRootNode); + const std::string sceneId = GetNodeUniqueId(mScene->mRootNode); + const std::string sceneName = GetNodeName(mScene->mRootNode); mOutput << startstr << "" << endstr; PushTag(); From 56a4e615336ea7410b25fe612b216340217adc0f Mon Sep 17 00:00:00 2001 From: RichardTea <31507749+RichardTea@users.noreply.github.com> Date: Tue, 5 May 2020 10:16:13 +0100 Subject: [PATCH 33/39] Collada: Don't copy the scene when exporting This was purely to add a virtual top-level node Use a flag instead. Also add more const --- code/AssetLib/Collada/ColladaExporter.cpp | 105 ++++++++++------------ code/AssetLib/Collada/ColladaExporter.h | 7 +- 2 files changed, 53 insertions(+), 59 deletions(-) diff --git a/code/AssetLib/Collada/ColladaExporter.cpp b/code/AssetLib/Collada/ColladaExporter.cpp index 480d6790b..567f7c8e7 100644 --- a/code/AssetLib/Collada/ColladaExporter.cpp +++ b/code/AssetLib/Collada/ColladaExporter.cpp @@ -117,22 +117,37 @@ static const std::string XMLIDEncode(const std::string &name) { return idEncoded.str(); } +// ------------------------------------------------------------------------------------------------ +// Helper functions to create unique ids +inline bool IsUniqueId(const std::unordered_set &idSet, const std::string &idStr) { + return (idSet.find(idStr) == idSet.end()); +} + +inline std::string MakeUniqueId(const std::unordered_set &idSet, const std::string &idPrefix, const std::string &postfix) { + std::string result(idPrefix + postfix); + if (!IsUniqueId(idSet, result)) { + // Select a number to append + size_t idnum = 1; + do { + result = idPrefix + '_' + to_string(idnum) + postfix; + ++idnum; + } while (!IsUniqueId(idSet, result)); + } + return result; +} + // ------------------------------------------------------------------------------------------------ // Constructor for a specific scene to export ColladaExporter::ColladaExporter(const aiScene *pScene, IOSystem *pIOSystem, const std::string &path, const std::string &file) : mIOSystem(pIOSystem), mPath(path), - mFile(file) { + mFile(file), + mScene(pScene), + endstr("\n") { // make sure that all formatting happens using the standard, C locale and not the user's current locale mOutput.imbue(std::locale("C")); mOutput.precision(ASSIMP_AI_REAL_TEXT_PRECISION); - mScene = pScene; - mSceneOwned = false; - - // set up strings - endstr = "\n"; - // start writing the file WriteFile(); } @@ -140,9 +155,6 @@ ColladaExporter::ColladaExporter(const aiScene *pScene, IOSystem *pIOSystem, con // ------------------------------------------------------------------------------------------------ // Destructor ColladaExporter::~ColladaExporter() { - if (mSceneOwned) { - delete mScene; - } } // ------------------------------------------------------------------------------------------------ @@ -171,10 +183,11 @@ void ColladaExporter::WriteFile() { // customized, Writes the animation library WriteAnimationsLibrary(); - // useless Collada fu at the end, just in case we haven't had enough indirections, yet. + // instantiate the scene(s) + // For Assimp there will only ever be one mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "mRootNode) + "\" />" << endstr; + mOutput << startstr << "" << endstr; PopTag(); mOutput << startstr << "" << endstr; PopTag(); @@ -209,13 +222,13 @@ void ColladaExporter::WriteHeader() { mScene->mRootNode->mTransformation.Decompose(scaling, rotation, position); rotation.Normalize(); - bool add_root_node = false; + mAdd_root_node = false; ai_real scale = 1.0; if (std::abs(scaling.x - scaling.y) <= epsilon && std::abs(scaling.x - scaling.z) <= epsilon && std::abs(scaling.y - scaling.z) <= epsilon) { scale = (ai_real)((((double)scaling.x) + ((double)scaling.y) + ((double)scaling.z)) / 3.0); } else { - add_root_node = true; + mAdd_root_node = true; } std::string up_axis = "Y_UP"; @@ -226,34 +239,19 @@ void ColladaExporter::WriteHeader() { } else if (rotation.Equal(z_rot, epsilon)) { up_axis = "Z_UP"; } else { - add_root_node = true; + mAdd_root_node = true; } if (!position.Equal(aiVector3D(0, 0, 0))) { - add_root_node = true; + mAdd_root_node = true; } // Assimp root nodes can have meshes, Collada Scenes cannot if (mScene->mRootNode->mNumChildren == 0 || mScene->mRootNode->mMeshes != 0) { - add_root_node = true; + mAdd_root_node = true; } - if (add_root_node) { - aiScene *scene = nullptr; - SceneCombiner::CopyScene(&scene, mScene); - - aiNode *root = new aiNode("Scene"); - - root->mNumChildren = 1; - root->mChildren = new aiNode *[root->mNumChildren]; - - root->mChildren[0] = scene->mRootNode; - scene->mRootNode->mParent = root; - scene->mRootNode = root; - - mScene = scene; - mSceneOwned = true; - + if (mAdd_root_node) { up_axis = "Y_UP"; scale = 1.0; } @@ -1227,17 +1225,29 @@ void ColladaExporter::WriteFloatArray(const std::string &pIdString, FloatDataTyp // ------------------------------------------------------------------------------------------------ // Writes the scene library void ColladaExporter::WriteSceneLibrary() { - const std::string sceneId = GetNodeUniqueId(mScene->mRootNode); - const std::string sceneName = GetNodeName(mScene->mRootNode); + // Determine if we are using the aiScene root or our own + std::string sceneName("Scene"); + if (mAdd_root_node) { + mSceneId = MakeUniqueId(mUniqueIds, sceneName, std::string()); + mUniqueIds.insert(mSceneId); + } else { + mSceneId = GetNodeUniqueId(mScene->mRootNode); + sceneName = GetNodeName(mScene->mRootNode); + } mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); - // start recursive write at the root node - for (size_t a = 0; a < mScene->mRootNode->mNumChildren; ++a) - WriteNode(mScene->mRootNode->mChildren[a]); + if (mAdd_root_node) { + // Export the root node + WriteNode(mScene->mRootNode); + } else { + // Have already exported the root node + for (size_t a = 0; a < mScene->mRootNode->mNumChildren; ++a) + WriteNode(mScene->mRootNode->mChildren[a]); + } PopTag(); mOutput << startstr << "" << endstr; @@ -1610,23 +1620,6 @@ void ColladaExporter::WriteNode(const aiNode *pNode) { mOutput << startstr << "" << endstr; } -inline bool IsUniqueId(const std::unordered_set &idSet, const std::string &idStr) { - return (idSet.find(idStr) == idSet.end()); -} - -inline std::string MakeUniqueId(const std::unordered_set &idSet, const std::string &idPrefix, const std::string &postfix) { - std::string result(idPrefix + postfix); - if (!IsUniqueId(idSet, result)) { - // Select a number to append - size_t idnum = 1; - do { - result = idPrefix + '_' + to_string(idnum) + postfix; - ++idnum; - } while (!IsUniqueId(idSet, result)); - } - return result; -} - void ColladaExporter::CreateNodeIds(const aiNode *node) { GetNodeUniqueId(node); for (size_t a = 0; a < node->mNumChildren; ++a) diff --git a/code/AssetLib/Collada/ColladaExporter.h b/code/AssetLib/Collada/ColladaExporter.h index bea65bafc..e9a3530ae 100644 --- a/code/AssetLib/Collada/ColladaExporter.h +++ b/code/AssetLib/Collada/ColladaExporter.h @@ -196,13 +196,14 @@ public: const std::string mFile; /// The scene to be written - const aiScene *mScene; - bool mSceneOwned; + const aiScene *const mScene; + std::string mSceneId; + bool mAdd_root_node = false; /// current line start string, contains the current indentation for simple stream insertion std::string startstr; /// current line end string for simple stream insertion - std::string endstr; + const std::string endstr; // pair of color and texture - texture precedences color struct Surface { From dc8550290ef2ce2b9d26e98c4172cbb289b56f83 Mon Sep 17 00:00:00 2001 From: RichardTea <31507749+RichardTea@users.noreply.github.com> Date: Tue, 5 May 2020 10:53:26 +0100 Subject: [PATCH 34/39] Ensure to delete the scene copy after the test --- test/unit/utColladaImportExport.cpp | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/test/unit/utColladaImportExport.cpp b/test/unit/utColladaImportExport.cpp index 3d6e0db23..451c8e235 100644 --- a/test/unit/utColladaImportExport.cpp +++ b/test/unit/utColladaImportExport.cpp @@ -53,6 +53,20 @@ using namespace Assimp; class utColladaImportExport : public AbstractImportExportBase { public: + // Clones the scene in an exception-safe way + struct SceneCloner { + SceneCloner(const aiScene *scene) { + sceneCopy = nullptr; + SceneCombiner::CopyScene(&sceneCopy, scene); + } + + ~SceneCloner() { + delete sceneCopy; + sceneCopy = nullptr; + } + aiScene *sceneCopy; + }; + virtual bool importerTest() final { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/duck.dae", aiProcess_ValidateDataStructure); @@ -231,12 +245,10 @@ TEST_F(utColladaImportExport, exportRootNodeMeshTest) { ASSERT_EQ(0u, scene->mRootNode->mNumMeshes) << "Collada import should not give the root node a mesh"; { - // Clone the scene and give the root node a mesh and a transform - aiScene *rootMeshScene = nullptr; - SceneCombiner::CopyScene(&rootMeshScene, scene); - ASSERT_TRUE(rootMeshScene != nullptr) << "Fatal: could not copy scene!"; + SceneCloner clone(scene); + ASSERT_TRUE(clone.sceneCopy != nullptr) << "Fatal: could not copy scene!"; // Do this by moving the meshes from the first child that has some - aiNode *rootNode = rootMeshScene->mRootNode; + aiNode *rootNode = clone.sceneCopy->mRootNode; ASSERT_TRUE(rootNode->mNumChildren > 0) << "Fatal: root has no children"; aiNode *meshNode = rootNode->mChildren[0]; ASSERT_EQ(1u, meshNode->mNumMeshes) << "Fatal: First child node has no duck mesh"; @@ -248,10 +260,12 @@ TEST_F(utColladaImportExport, exportRootNodeMeshTest) { rootNode->mMeshes[i] = meshNode->mMeshes[i]; } + // Remove the meshes from the original node meshNode->mNumMeshes = 0; delete[] meshNode->mMeshes; + meshNode->mMeshes = nullptr; - ASSERT_EQ(AI_SUCCESS, exporter.Export(rootMeshScene, "collada", outFile)) << "Fatal: Could not export file"; + ASSERT_EQ(AI_SUCCESS, exporter.Export(clone.sceneCopy, "collada", outFile)) << "Fatal: Could not export file"; } // Reimport and look for meshes From b990f703a0f7705fb51fdfa72f40911211a95553 Mon Sep 17 00:00:00 2001 From: Kalyan Kumar Date: Thu, 7 May 2020 15:00:21 -0700 Subject: [PATCH 35/39] Add IMPORTED_CONFIGURATIONS property to cmake target. --- assimpTargets-debug.cmake.in | 6 ++++++ assimpTargets-release.cmake.in | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/assimpTargets-debug.cmake.in b/assimpTargets-debug.cmake.in index de6459eaf..b7efe71f9 100644 --- a/assimpTargets-debug.cmake.in +++ b/assimpTargets-debug.cmake.in @@ -73,6 +73,9 @@ else() else() set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@") endif() + + # Import target "assimp::assimp" for configuration "Debug" + set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) set_target_properties(assimp::assimp PROPERTIES IMPORTED_SONAME_DEBUG "${sharedLibraryName}" IMPORTED_LOCATION_DEBUG "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}" @@ -81,6 +84,9 @@ else() list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}" ) else() set(staticLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@") + + # Import target "assimp::assimp" for configuration "Debug" + set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) set_target_properties(assimp::assimp PROPERTIES IMPORTED_LOCATION_DEBUG "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}" ) diff --git a/assimpTargets-release.cmake.in b/assimpTargets-release.cmake.in index 6a5bafcf7..c716006dd 100644 --- a/assimpTargets-release.cmake.in +++ b/assimpTargets-release.cmake.in @@ -73,6 +73,9 @@ else() else() set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@") endif() + + # Import target "assimp::assimp" for configuration "Release" + set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties(assimp::assimp PROPERTIES IMPORTED_SONAME_RELEASE "${sharedLibraryName}" IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}" @@ -81,6 +84,9 @@ else() list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}" ) else() set(staticLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_STATIC_LIBRARY_SUFFIX@") + + # Import target "assimp::assimp" for configuration "Release" + set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties(assimp::assimp PROPERTIES IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}" ) From aef4ecada533c40d41ae4e885eaa39bfe74601cb Mon Sep 17 00:00:00 2001 From: Jeremy Cytryn Date: Wed, 6 May 2020 23:41:05 -0700 Subject: [PATCH 36/39] Fail gltf/gltf2 export whenever invalid / incomplete JSON is generated This can happen currently for example if NaNs are introduced in accessor bounds as rapidjson cannot write NaN/inf floats (see subsequent commit for fix there) and will halt writing to buffer at this point. Fix here ensures that whenever anything like this happens we throw an exception so this ends up as a registered export failure case, rather than silently exporting the incomplete JSON --- code/AssetLib/glTF/glTFAssetWriter.inl | 12 ++++++++---- code/AssetLib/glTF2/glTF2AssetWriter.inl | 10 ++++++---- .../BoxWithInfinites.glb | Bin 0 -> 1900 bytes test/unit/utglTF2ImportExport.cpp | 10 ++++++++++ 4 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 test/models/glTF2/BoxWithInfinites-glTF-Binary/BoxWithInfinites.glb diff --git a/code/AssetLib/glTF/glTFAssetWriter.inl b/code/AssetLib/glTF/glTFAssetWriter.inl index 5e4416ee9..d8d2556fa 100644 --- a/code/AssetLib/glTF/glTFAssetWriter.inl +++ b/code/AssetLib/glTF/glTFAssetWriter.inl @@ -59,7 +59,7 @@ namespace glTF { namespace { template - inline + inline Value& MakeValue(Value& val, T(&r)[N], MemoryPoolAllocator<>& al) { val.SetArray(); val.Reserve(N, al); @@ -70,7 +70,7 @@ namespace glTF { } template - inline + inline Value& MakeValue(Value& val, const std::vector & r, MemoryPoolAllocator<>& al) { val.SetArray(); val.Reserve(static_cast(r.size()), al); @@ -530,7 +530,9 @@ namespace glTF { StringBuffer docBuffer; PrettyWriter writer(docBuffer); - mDoc.Accept(writer); + if (!mDoc.Accept(writer)) { + throw DeadlyExportError("Failed to write scene data!"); + } if (jsonOutFile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) { throw DeadlyExportError("Failed to write scene data!"); @@ -569,7 +571,9 @@ namespace glTF { StringBuffer docBuffer; Writer writer(docBuffer); - mDoc.Accept(writer); + if (!mDoc.Accept(writer)) { + throw DeadlyExportError("Failed to write scene data!"); + } if (outfile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) { throw DeadlyExportError("Failed to write scene data!"); diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.inl b/code/AssetLib/glTF2/glTF2AssetWriter.inl index 798f38c1c..361af40cd 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.inl +++ b/code/AssetLib/glTF2/glTF2AssetWriter.inl @@ -613,7 +613,9 @@ namespace glTF2 { StringBuffer docBuffer; PrettyWriter writer(docBuffer); - mDoc.Accept(writer); + if (!mDoc.Accept(writer)) { + throw DeadlyExportError("Failed to write scene data!"); + } if (jsonOutFile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) { throw DeadlyExportError("Failed to write scene data!"); @@ -664,7 +666,9 @@ namespace glTF2 { StringBuffer docBuffer; Writer writer(docBuffer); - mDoc.Accept(writer); + if (!mDoc.Accept(writer)) { + throw DeadlyExportError("Failed to write scene data!"); + } uint32_t jsonChunkLength = (docBuffer.GetSize() + 3) & ~3; // Round up to next multiple of 4 auto paddingLength = jsonChunkLength - docBuffer.GetSize(); @@ -816,5 +820,3 @@ namespace glTF2 { } } - - diff --git a/test/models/glTF2/BoxWithInfinites-glTF-Binary/BoxWithInfinites.glb b/test/models/glTF2/BoxWithInfinites-glTF-Binary/BoxWithInfinites.glb new file mode 100644 index 0000000000000000000000000000000000000000..ae83f1f06578eb6b6dc74988dc1c52b9dd6477ab GIT binary patch literal 1900 zcmb7ES#R1v5T^HiU$1DNTFFJWfdqI#BuXSIjug`N0Y#ND3#{Y=txcLJLgb(2FZ3U! z-z;lllC-3l@y?8Azi(#t79$)Z%!wi%v&soOarPtT3xAS5EauEy-YFF}HjC~jHZz#x zx;%+5g!QMxA(!6;|HUe%!TQHBZx4rx8m1cpHQ+(Ke>~x=Qnc(1a!vzeW)}<= zD>wVTvz%L z`vxR`uV@D3MSm8(3LGCzU|ZqQ4-t>+!B7Mu<`Gh%wl#P#ipQ+7X`2@lsj=xsU)SXH zWV=*Cp^hBU+UE=94P8MumSO;M%f9I26)ZJ5jb;^SjZ$d&f6OlAHCIx|4RWE@J298S z@m5;Y;RAGK(w9vhJDw-pPBU?o0lW-#sxZ1_W-_<96jB0tBQjGbmk&13Do+ShM8$ZQZ!`yTJ2r2|$O zB6&_r=JRNb<)mYwm%0fL6(WT%VxTWR`U(xLO=?#wA%cOx$-)|eG{$=Mr?fdx?_RrG z->JN@lC{eN<~$Qqn$@>Y4Mm|IZk{=TC}vT==P?m_NDaILG6?1zv?kjIcGdL;WP z?J1YEwqjF%$hd|9lav;z_TP F{RglTzqJ4W literal 0 HcmV?d00001 diff --git a/test/unit/utglTF2ImportExport.cpp b/test/unit/utglTF2ImportExport.cpp index 55cd2ef6a..99481101e 100644 --- a/test/unit/utglTF2ImportExport.cpp +++ b/test/unit/utglTF2ImportExport.cpp @@ -436,6 +436,16 @@ TEST_F(utglTF2ImportExport, error_string_preserved) { ASSERT_NE(error.find("BoxTextured0.bin"), std::string::npos) << "Error string should contain an error about missing .bin file"; } +TEST_F(utglTF2ImportExport, export_bad_accessor_bounds) { + Assimp::Importer importer; + Assimp::Exporter exporter; + const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxWithInfinites-glTF-Binary/BoxWithInfinites.glb", aiProcess_ValidateDataStructure); + ASSERT_NE(scene, nullptr); + + EXPECT_EQ(aiReturn_FAILURE, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxWithInfinites-glTF-Binary/BoxWithInfinites_out.glb")); + EXPECT_EQ(aiReturn_FAILURE, exporter.Export(scene, "gltf2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxWithInfinites-glTF-Binary/BoxWithInfinites_out.gltf")); +} + #endif // ASSIMP_BUILD_NO_EXPORT TEST_F(utglTF2ImportExport, sceneMetadata) { From c5a9fbd47f309cf33e2f8fdef03c952b3e212d63 Mon Sep 17 00:00:00 2001 From: Jeremy Cytryn Date: Wed, 6 May 2020 23:59:48 -0700 Subject: [PATCH 37/39] Gracefully handle NaNs and Infs in gltf2 accessor bound computation --- code/AssetLib/glTF2/glTF2Exporter.cpp | 13 ++++++++++--- test/unit/utglTF2ImportExport.cpp | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index da6d9ab2e..7ed4f2670 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -1,4 +1,4 @@ -/* +/* Open Asset Import Library (assimp) ---------------------------------------------------------------------- @@ -172,6 +172,13 @@ void SetAccessorRange(Ref acc, void* data, size_t count, for (unsigned int j = 0 ; j < numCompsOut ; j++) { double valueTmp = buffer_ptr[j]; + // Gracefully tolerate rogue NaN's in buffer data + // Any NaNs/Infs introduced in accessor bounds will end up in + // document and prevent rapidjson from writing out valid JSON + if (!std::isfinite(valueTmp)) { + continue; + } + if (valueTmp < acc->min[j]) { acc->min[j] = valueTmp; } @@ -348,7 +355,7 @@ void glTF2Exporter::GetMatTex(const aiMaterial* mat, Ref& texture, aiTe if (path[0] == '*') { // embedded aiTexture* curTex = mScene->mTextures[atoi(&path[1])]; - + texture->source->name = curTex->mFilename.C_Str(); // The asset has its own buffer, see Image::SetData @@ -762,7 +769,7 @@ void glTF2Exporter::ExportMeshes() for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { if (!aim->HasTextureCoords(i)) continue; - + // Flip UV y coords if (aim -> mNumUVComponents[i] > 1) { for (unsigned int j = 0; j < aim->mNumVertices; ++j) { diff --git a/test/unit/utglTF2ImportExport.cpp b/test/unit/utglTF2ImportExport.cpp index 99481101e..4ba7c69d4 100644 --- a/test/unit/utglTF2ImportExport.cpp +++ b/test/unit/utglTF2ImportExport.cpp @@ -442,8 +442,8 @@ TEST_F(utglTF2ImportExport, export_bad_accessor_bounds) { const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxWithInfinites-glTF-Binary/BoxWithInfinites.glb", aiProcess_ValidateDataStructure); ASSERT_NE(scene, nullptr); - EXPECT_EQ(aiReturn_FAILURE, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxWithInfinites-glTF-Binary/BoxWithInfinites_out.glb")); - EXPECT_EQ(aiReturn_FAILURE, exporter.Export(scene, "gltf2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxWithInfinites-glTF-Binary/BoxWithInfinites_out.gltf")); + EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxWithInfinites-glTF-Binary/BoxWithInfinites_out.glb")); + EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "gltf2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxWithInfinites-glTF-Binary/BoxWithInfinites_out.gltf")); } #endif // ASSIMP_BUILD_NO_EXPORT From c3a21666dadd01f7a2f532d3dc0ecaf2045aa81b Mon Sep 17 00:00:00 2001 From: Jeremy Cytryn Date: Thu, 7 May 2020 01:21:54 -0700 Subject: [PATCH 38/39] Make gltf2 export normal normalization safe This avoids introducing NaNs e.g. when the input mesh has 0-length normals --- code/AssetLib/glTF/glTFExporter.cpp | 2 +- code/AssetLib/glTF2/glTF2Exporter.cpp | 2 +- .../BoxBadNormals-glTF-Binary/BoxBadNormals.glb | Bin 0 -> 1924 bytes test/unit/utglTF2ImportExport.cpp | 15 +++++++++++++++ 4 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 test/models/glTF2/BoxBadNormals-glTF-Binary/BoxBadNormals.glb diff --git a/code/AssetLib/glTF/glTFExporter.cpp b/code/AssetLib/glTF/glTFExporter.cpp index e6c14e7dd..b85affc08 100644 --- a/code/AssetLib/glTF/glTFExporter.cpp +++ b/code/AssetLib/glTF/glTFExporter.cpp @@ -348,7 +348,7 @@ void glTFExporter::GetMatColorOrTex(const aiMaterial* mat, glTF::TexProperty& pr if (path[0] == '*') { // embedded aiTexture* curTex = mScene->mTextures[atoi(&path[1])]; - + prop.texture->source->name = curTex->mFilename.C_Str(); uint8_t *data = reinterpret_cast(curTex->pcData); diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index 7ed4f2670..566f95e80 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -758,7 +758,7 @@ void glTF2Exporter::ExportMeshes() // Normalize all normals as the validator can emit a warning otherwise if ( nullptr != aim->mNormals) { for ( auto i = 0u; i < aim->mNumVertices; ++i ) { - aim->mNormals[ i ].Normalize(); + aim->mNormals[ i ].NormalizeSafe(); } } diff --git a/test/models/glTF2/BoxBadNormals-glTF-Binary/BoxBadNormals.glb b/test/models/glTF2/BoxBadNormals-glTF-Binary/BoxBadNormals.glb new file mode 100644 index 0000000000000000000000000000000000000000..c36727d12ce675125a3f48e1ebeb68fd1a3992b2 GIT binary patch literal 1924 zcmb_d+iu!G5OweO`|TC&Q!6>hHX#XqsYsMaRDe@R`w~T!fdwr2g4QNYgpl&kkLb@- z{ee{KC-uy-OH2}}M2gK}E;~E3GdsH;gnK(T4a4|x&oF-8HjGbguQ_3Un(~af6L!c& z8YD4unNzfw$p$>;!p{-`jW^sks=~zLvnYiT5m|ZLZMoLNI5EVC8w1 zB_yn}Y;RTT)z&;ur!_?~<+f0reOrWaPc|6F5%w2b^Gh?cIejhH| zgZyM?V*|_a#ejOEv|3qH$+R;O^bpW?&Psd1mz;cU-pcE!Ox~NlN)3@)TZ!_F{EUmh z4;RYP;yqMl)DaDy`C%AzTgiAZjM0|V=^a1iTS=IR9ltC48!feA$;Y-Uj#Y6griEAT zwQ`_M(X&GP(mH!;G9Cpu2!~wj_Q`>T_4(mw=r8H z#dDboPltRVj|Mc9hzOz}gZJ5BB)y>+I(NAfLEH;)@NjMrG{b&%#uG?6OCwd;*R#O@$Udv#w_WU_L{iSF8pFg2E>RE;-(`D?m z%?ahBo@Mx}*v|ajz!duK-BOffeEy6(z+C{JLrF=#4?F-K0*@3W`7!VWcnUmIl;r2Y V3*aU2N>P$u18;!0z&k}r{s%56wT%D( literal 0 HcmV?d00001 diff --git a/test/unit/utglTF2ImportExport.cpp b/test/unit/utglTF2ImportExport.cpp index 4ba7c69d4..f0f18d503 100644 --- a/test/unit/utglTF2ImportExport.cpp +++ b/test/unit/utglTF2ImportExport.cpp @@ -446,6 +446,21 @@ TEST_F(utglTF2ImportExport, export_bad_accessor_bounds) { EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "gltf2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxWithInfinites-glTF-Binary/BoxWithInfinites_out.gltf")); } +TEST_F(utglTF2ImportExport, export_normalized_normals) { + Assimp::Importer importer; + Assimp::Exporter exporter; + const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxBadNormals-glTF-Binary/BoxBadNormals.glb", aiProcess_ValidateDataStructure); + ASSERT_NE(scene, nullptr); + EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxBadNormals-glTF-Binary/BoxBadNormals_out.glb")); + + // load in again and ensure normal-length normals but no Nan's or Inf's introduced + scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxBadNormals-glTF-Binary/BoxBadNormals_out.glb", aiProcess_ValidateDataStructure); + for ( auto i = 0u; i < scene->mMeshes[0]->mNumVertices; ++i ) { + const auto length = scene->mMeshes[0]->mNormals[i].Length(); + EXPECT_TRUE(abs(length) < 1e-6 || abs(length - 1) < 1e-6); + } +} + #endif // ASSIMP_BUILD_NO_EXPORT TEST_F(utglTF2ImportExport, sceneMetadata) { From 7a16a7a7e4b78be8d3887c1288831488edff83f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Kangasj=C3=A4rvel=C3=A4?= Date: Fri, 15 May 2020 16:48:41 +0300 Subject: [PATCH 39/39] Fix infinite recursion in gltf2 skin parsing Previously parsing a node caused the skin that was attached to it to be parsed, which caused the skins node joints to be parsed, which could cause the skin to be re-parsed leading to infinite or at the very least exponential recursion. The fix is to just get a reference to a temporarily uninitialized skin as they were being parsed after the scene graph just to be safe anyway. This way we avoid the recursion problem and all the references will be valid in the end. --- code/AssetLib/glTF2/glTF2Asset.inl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index 5e1cc42d6..e3fff61a7 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -1188,9 +1188,11 @@ inline void Node::Read(Value &obj, Asset &r) { } } + // Do not retrieve a skin here, just take a reference, to avoid infinite recursion + // Skins will be properly loaded later Value *curSkin = FindUInt(obj, "skin"); if (nullptr != curSkin) { - this->skin = r.skins.Retrieve(curSkin->GetUint()); + this->skin = r.skins.Get(curSkin->GetUint()); } Value *curCamera = FindUInt(obj, "camera"); @@ -1481,7 +1483,7 @@ inline void Asset::Load(const std::string &pFile, bool isBinary) { } } - // Force reading of skins since they're not always directly referenced + // Read skins after nodes have been loaded to avoid infinite recursion if (Value *skinsArray = FindArray(doc, "skins")) { for (unsigned int i = 0; i < skinsArray->Size(); ++i) { skins.Retrieve(i);