From 0064205b157be07f7b80d41d1ee9fd6bca29f54b Mon Sep 17 00:00:00 2001 From: Jakub Melka Date: Fri, 23 Sep 2022 16:16:43 +0200 Subject: [PATCH] 3D PDF: Mesh continuation block --- Pdf4QtLib/sources/pdf3d_u3d.cpp | 112 ++++++++++++++++++++++++++++++++ Pdf4QtLib/sources/pdf3d_u3d.h | 78 ++++++++++++++++++++++ 2 files changed, 190 insertions(+) diff --git a/Pdf4QtLib/sources/pdf3d_u3d.cpp b/Pdf4QtLib/sources/pdf3d_u3d.cpp index a9c0b35..31c2d5b 100644 --- a/Pdf4QtLib/sources/pdf3d_u3d.cpp +++ b/Pdf4QtLib/sources/pdf3d_u3d.cpp @@ -554,6 +554,7 @@ PDF3D_U3D_AbstractBlockPtr PDF3D_U3D::parseBlockWithDeclaration(PDF3D_U3D_DataRe auto block = parseBlock(blockType, blockData, metaData); LoadBlockInfo info; + info.typeName = QByteArray::fromRawData(reinterpret_cast(&blockType), sizeof(decltype(blockType))).toHex(); info.success = block != nullptr; info.blockType = blockType; info.dataSize = dataSize; @@ -579,6 +580,36 @@ PDF3D_U3D PDF3D_U3D::parse(QByteArray data) return object; } +const PDF3D_U3D_CLODMeshDeclarationBlock* PDF3D_U3D::getCLODMeshDeclarationBlock(const QString& meshName) const +{ + for (const auto& block : m_blocks) + { + if (auto typedBlock = dynamic_cast(block.data())) + { + if (typedBlock->getMeshName() == meshName) + { + return typedBlock; + } + } + + if (auto typedBlock = dynamic_cast(block.data())) + { + for (const auto& modifierChainChildBlock : typedBlock->getModifierDeclarationBlocks()) + { + if (auto modifierChainChildTypedBlock = dynamic_cast(modifierChainChildBlock.data())) + { + if (modifierChainChildTypedBlock->getMeshName() == meshName) + { + return modifierChainChildTypedBlock; + } + } + } + } + } + + return nullptr; +} + PDF3D_U3D_AbstractBlockPtr PDF3D_U3D::parseBlock(uint32_t blockType, const QByteArray& data, const QByteArray& metaData) @@ -632,6 +663,9 @@ PDF3D_U3D_AbstractBlockPtr PDF3D_U3D::parseBlock(uint32_t blockType, case PDF3D_U3D_CLODMeshDeclarationBlock::ID: return PDF3D_U3D_CLODMeshDeclarationBlock::parse(data, metaData, this); + case PDF3D_U3D_CLODBaseMeshContinuationBlock::ID: + return PDF3D_U3D_CLODBaseMeshContinuationBlock::parse(data, metaData, this); + default: break; } @@ -1536,6 +1570,84 @@ const std::vector& PDF3D_U3 return m_boneDescription; } +PDF3D_U3D_AbstractBlockPtr PDF3D_U3D_CLODBaseMeshContinuationBlock::parse(QByteArray data, QByteArray metaData, PDF3D_U3D* object) +{ + PDF3D_U3D_CLODBaseMeshContinuationBlock* block = new PDF3D_U3D_CLODBaseMeshContinuationBlock(); + PDF3D_U3D_AbstractBlockPtr pointer(block); + + PDF3D_U3D_DataReader reader(data, object->isCompressed()); + + // Read the data + block->m_meshName = reader.readString(object->getTextCodec()); + block->m_chainIndex = reader.readU32(); + + /* max mesh description */ + block->m_faceCount = reader.readU32(); + block->m_positionCount = reader.readU32(); + block->m_normalCount = reader.readU32(); + block->m_diffuseColorCount = reader.readU32(); + block->m_specularColorCount = reader.readU32(); + block->m_textureColorCount = reader.readU32(); + + block->m_basePositions = reader.readVectorFloats32(block->m_positionCount); + block->m_baseNormals = reader.readVectorFloats32(block->m_normalCount); + block->m_baseDiffuseColors = reader.readVectorFloats32(block->m_diffuseColorCount); + block->m_baseSpecularColors = reader.readVectorFloats32(block->m_specularColorCount); + block->m_baseTextureCoords = reader.readVectorFloats32(block->m_textureColorCount); + + // We must read attributes of the mesh to read faces + if (auto declarationBlock = object->getCLODMeshDeclarationBlock(block->m_meshName)) + { + const bool hasNormals = !declarationBlock->isNormalsExcluded(); + + for (size_t i = 0; i < block->m_faceCount; ++i) + { + BaseFace face; + face.m_shadingId = reader.readCompressedU32(reader.getStaticContext(cShading)); + + const PDF3D_U3D_CLODMeshDeclarationBlock::ShadingDescription* shadingDescription = declarationBlock->getShadingDescriptionItem(face.m_shadingId); + if (!shadingDescription) + { + return nullptr; + } + + for (size_t ci = 0; ci < face.m_corners.size(); ++ci) + { + BaseCornerInfo cornerInfo; + + cornerInfo.basePositionIndex = reader.readCompressedU32(reader.getRangeContext(block->m_positionCount)); + + if (hasNormals) + { + cornerInfo.baseNormalIndex = reader.readCompressedU32(reader.getRangeContext(block->m_normalCount)); + } + + if (shadingDescription->hasDiffuseColors()) + { + cornerInfo.baseDiffuseColorIndex = reader.readCompressedU32(reader.getRangeContext(block->m_diffuseColorCount)); + } + + if (shadingDescription->hasSpecularColors()) + { + cornerInfo.baseSpecularColorIndex = reader.readCompressedU32(reader.getRangeContext(block->m_specularColorCount)); + } + + for (uint32_t ti = 0; ti < shadingDescription->textureLayerCount; ++ti) + { + cornerInfo.baseTextureCoordIndex.push_back(reader.readCompressedU32(reader.getRangeContext(block->m_textureColorCount))); + } + + face.m_corners[ci] = std::move(cornerInfo); + } + + block->m_baseFaces.emplace_back(std::move(face)); + } + } + + block->parseMetadata(metaData, object); + return pointer; +} + } // namespace u3d } // namespace pdf diff --git a/Pdf4QtLib/sources/pdf3d_u3d.h b/Pdf4QtLib/sources/pdf3d_u3d.h index 63ede45..df2cc1f 100644 --- a/Pdf4QtLib/sources/pdf3d_u3d.h +++ b/Pdf4QtLib/sources/pdf3d_u3d.h @@ -395,6 +395,9 @@ public: uint32_t textureLayerCount = 0; std::vector textureCoordDimensions; uint32_t originalShading = 0; + + bool hasDiffuseColors() const { return shadingAttributes & 0x00000001; } + bool hasSpecularColors() const { return shadingAttributes & 0x00000002; } }; struct BoneJoint @@ -427,6 +430,8 @@ public: const QString& getMeshName() const; uint32_t getChainIndex() const; + bool isNormalsExcluded() const { return getMeshAttributes() & 0x00000001; } + /* max mesh description */ uint32_t getMeshAttributes() const; uint32_t getFaceCount() const; @@ -437,6 +442,7 @@ public: uint32_t getTextureColorCount() const; uint32_t getShadingCount() const; const std::vector& getShadingDescription() const; + const ShadingDescription* getShadingDescriptionItem(uint32_t index) const { return index < m_shadingDescription.size() ? &m_shadingDescription[index] : nullptr; } /* clod description */ uint32_t getMinimumResolution() const; @@ -496,6 +502,56 @@ private: std::vector m_boneDescription; }; +class PDF3D_U3D_CLODBaseMeshContinuationBlock : public PDF3D_U3D_AbstractBlock +{ +public: + static constexpr uint32_t ID = 0xFFFFFF3B; + + static PDF3D_U3D_AbstractBlockPtr parse(QByteArray data, QByteArray metaData, PDF3D_U3D* object); + + struct BaseCornerInfo + { + uint32_t basePositionIndex = 0; // rBasePositionCount + uint32_t baseNormalIndex = 0; // rBaseNormalCount + uint32_t baseDiffuseColorIndex = 0; // rBaseDiffColorCnt + uint32_t baseSpecularColorIndex = 0; // rBaseSpecColorCnt + std::vector baseTextureCoordIndex; // rBaseTexCoordCnt + }; + + struct BaseFace + { + uint32_t m_shadingId = 0; // cShading + std::array m_corners = { }; + }; + + const QString& getMeshName() const; + uint32_t getChainIndex() const; + +private: + enum Context + { + cShading = 1 + }; + + QString m_meshName; + uint32_t m_chainIndex = 0; + + /* base mesh description */ + uint32_t m_faceCount = 0; + uint32_t m_positionCount = 0; + uint32_t m_normalCount = 0; + uint32_t m_diffuseColorCount = 0; + uint32_t m_specularColorCount = 0; + uint32_t m_textureColorCount = 0; + + std::vector m_basePositions; + std::vector m_baseNormals; + std::vector m_baseDiffuseColors; + std::vector m_baseSpecularColors; + std::vector m_baseTextureCoords; + std::vector m_baseFaces; +}; + // ------------------------------------------------------------------------------- // PDF3D_U3D // ------------------------------------------------------------------------------- @@ -510,6 +566,8 @@ public: static PDF3D_U3D parse(QByteArray data); + const PDF3D_U3D_CLODMeshDeclarationBlock* getCLODMeshDeclarationBlock(const QString& meshName) const; + PDF3D_U3D_AbstractBlockPtr parseBlockWithDeclaration(PDF3D_U3D_DataReader& reader); private: @@ -518,6 +576,7 @@ private: struct LoadBlockInfo { + QString typeName; bool success = false; uint32_t blockType = 0; uint32_t dataSize = 0; @@ -593,6 +652,9 @@ public: void setData(QByteArray data); + static constexpr uint32_t getRangeContext(uint32_t value) { return value + PDF3D_U3D_Constants::S_STATIC_FULL; } + static constexpr uint32_t getStaticContext(uint32_t value) { return value; } + uint8_t readU8(); uint16_t readU16(); uint32_t readU32(); @@ -626,6 +688,22 @@ public: } } + template + std::vector readVectorFloats32(uint32_t count) + { + std::vector result; + result.reserve(count); + + for (uint32_t i = 0; i < count; ++i) + { + T value = T(); + readFloats32(value); + result.emplace_back(std::move(value)); + } + + return result; + } + private: uint32_t readSymbol(uint32_t context); uint8_t swapBits8(uint8_t source);