| 1 | /* |
| 2 | Open Asset Import Library (assimp) |
| 3 | ---------------------------------------------------------------------- |
| 4 | |
| 5 | Copyright (c) 2006-2025, assimp team |
| 6 | |
| 7 | All rights reserved. |
| 8 | |
| 9 | Redistribution and use of this software in source and binary forms, |
| 10 | with or without modification, are permitted provided that the |
| 11 | following conditions are met: |
| 12 | |
| 13 | * Redistributions of source code must retain the above |
| 14 | copyright notice, this list of conditions and the |
| 15 | following disclaimer. |
| 16 | |
| 17 | * Redistributions in binary form must reproduce the above |
| 18 | copyright notice, this list of conditions and the |
| 19 | following disclaimer in the documentation and/or other |
| 20 | materials provided with the distribution. |
| 21 | |
| 22 | * Neither the name of the assimp team, nor the names of its |
| 23 | contributors may be used to endorse or promote products |
| 24 | derived from this software without specific prior |
| 25 | written permission of the assimp team. |
| 26 | |
| 27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 28 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 29 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 30 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 31 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 32 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 33 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 34 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 35 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 36 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 37 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 38 | |
| 39 | ---------------------------------------------------------------------- |
| 40 | */ |
| 41 | |
| 42 | /** @file ColladaParser.h |
| 43 | * @brief Defines the parser helper class for the collada loader |
| 44 | */ |
| 45 | |
| 46 | #pragma once |
| 47 | #ifndef AI_COLLADAPARSER_H_INC |
| 48 | #define AI_COLLADAPARSER_H_INC |
| 49 | |
| 50 | #include "ColladaHelper.h" |
| 51 | #include <assimp/ai_assert.h> |
| 52 | #include <assimp/XmlParser.h> |
| 53 | |
| 54 | #include <map> |
| 55 | |
| 56 | namespace Assimp { |
| 57 | |
| 58 | class ZipArchiveIOSystem; |
| 59 | |
| 60 | // ------------------------------------------------------------------------------------------ |
| 61 | /** Parser helper class for the Collada loader. |
| 62 | * |
| 63 | * Does all the XML reading and builds internal data structures from it, |
| 64 | * but leaves the resolving of all the references to the loader. |
| 65 | */ |
| 66 | class ColladaParser { |
| 67 | friend class ColladaLoader; |
| 68 | |
| 69 | public: |
| 70 | /// Map for generic metadata as aiString. |
| 71 | using StringMetaData = std::map<std::string, aiString>; |
| 72 | |
| 73 | /// Constructor from XML file. |
| 74 | ColladaParser(IOSystem *pIOHandler, const std::string &pFile); |
| 75 | |
| 76 | /// Destructor |
| 77 | ~ColladaParser(); |
| 78 | |
| 79 | /// Attempts to read the ZAE manifest and returns the DAE to open |
| 80 | static std::string ReadZaeManifest(ZipArchiveIOSystem &zip_archive); |
| 81 | |
| 82 | /// Reads the contents of the file |
| 83 | void ReadContents(XmlNode &node); |
| 84 | |
| 85 | /// Reads the structure of the file |
| 86 | void ReadStructure(XmlNode &node); |
| 87 | |
| 88 | /// Reads asset information such as coordinate system information and legal blah |
| 89 | void ReadAssetInfo(XmlNode &node); |
| 90 | |
| 91 | /// Reads contributor information such as author and legal blah |
| 92 | void ReadContributorInfo(XmlNode &node); |
| 93 | |
| 94 | /// Reads the animation library |
| 95 | void ReadAnimationLibrary(XmlNode &node); |
| 96 | |
| 97 | /// Reads the animation clip library |
| 98 | void ReadAnimationClipLibrary(XmlNode &node); |
| 99 | |
| 100 | /// Unwrap controllers dependency hierarchy |
| 101 | void PostProcessControllers(); |
| 102 | |
| 103 | /// Re-build animations from animation clip library, if present, otherwise combine single-channel animations |
| 104 | void PostProcessRootAnimations(); |
| 105 | |
| 106 | /// Reads an animation into the given parent structure |
| 107 | void ReadAnimation(XmlNode &node, Collada::Animation *pParent); |
| 108 | |
| 109 | /// Reads the skeleton controller library |
| 110 | void ReadControllerLibrary(XmlNode &node); |
| 111 | |
| 112 | /// Reads a controller into the given mesh structure |
| 113 | void ReadController(XmlNode &node, Collada::Controller &pController); |
| 114 | |
| 115 | /// Reads the image library contents |
| 116 | void ReadImageLibrary(const XmlNode &node); |
| 117 | |
| 118 | /// Reads an image entry into the given image |
| 119 | void ReadImage(const XmlNode &node, Collada::Image &pImage) const; |
| 120 | |
| 121 | /// Reads the material library |
| 122 | void ReadMaterialLibrary(XmlNode &node); |
| 123 | |
| 124 | /// Reads the camera library |
| 125 | void ReadCameraLibrary(XmlNode &node); |
| 126 | |
| 127 | /// Reads the light library |
| 128 | void ReadLightLibrary(XmlNode &node); |
| 129 | |
| 130 | /// Reads the effect library |
| 131 | void ReadEffectLibrary(XmlNode &node); |
| 132 | |
| 133 | /// Reads an effect entry into the given effect |
| 134 | void ReadEffect(XmlNode &node, Collada::Effect &pEffect); |
| 135 | |
| 136 | /// Reads an COMMON effect profile |
| 137 | void ReadEffectProfileCommon(XmlNode &node, Collada::Effect &pEffect); |
| 138 | |
| 139 | /// Read sampler properties |
| 140 | void ReadSamplerProperties(XmlNode &node, Collada::Sampler &pSampler); |
| 141 | |
| 142 | /// Reads an effect entry containing a color or a texture defining that color |
| 143 | void ReadEffectColor(XmlNode &node, aiColor4D &pColor, Collada::Sampler &pSampler); |
| 144 | |
| 145 | /// Reads an effect entry containing a float |
| 146 | void ReadEffectFloat(XmlNode &node, ai_real &pFloat); |
| 147 | |
| 148 | /// Reads an effect parameter specification of any kind |
| 149 | void ReadEffectParam(XmlNode &node, Collada::EffectParam &pParam); |
| 150 | |
| 151 | /// Reads the geometry library contents |
| 152 | void ReadGeometryLibrary(XmlNode &node); |
| 153 | |
| 154 | /// Reads a geometry from the geometry library. |
| 155 | void ReadGeometry(XmlNode &node, Collada::Mesh &pMesh); |
| 156 | |
| 157 | /// Reads a mesh from the geometry library |
| 158 | void ReadMesh(XmlNode &node, Collada::Mesh &pMesh); |
| 159 | |
| 160 | /// Reads a source element - a combination of raw data and an accessor defining |
| 161 | ///things that should not be definable. Yes, that's another rant. |
| 162 | void ReadSource(XmlNode &node); |
| 163 | |
| 164 | /// Reads a data array holding a number of elements, and stores it in the global library. |
| 165 | /// Currently supported are array of floats and arrays of strings. |
| 166 | void ReadDataArray(XmlNode &node); |
| 167 | |
| 168 | /// Reads an accessor and stores it in the global library under the given ID - |
| 169 | /// accessors use the ID of the parent <source> element |
| 170 | void ReadAccessor(XmlNode &node, const std::string &pID); |
| 171 | |
| 172 | /// Reads input declarations of per-vertex mesh data into the given mesh |
| 173 | void ReadVertexData(XmlNode &node, Collada::Mesh &pMesh); |
| 174 | |
| 175 | /// Reads input declarations of per-index mesh data into the given mesh |
| 176 | void ReadIndexData(XmlNode &node, Collada::Mesh &pMesh); |
| 177 | |
| 178 | /// Reads a single input channel element and stores it in the given array, if valid |
| 179 | void ReadInputChannel(XmlNode &node, std::vector<Collada::InputChannel> &poChannels); |
| 180 | |
| 181 | /// Reads a <p> primitive index list and assembles the mesh data into the given mesh |
| 182 | size_t ReadPrimitives(XmlNode &node, Collada::Mesh &pMesh, std::vector<Collada::InputChannel> &pPerIndexChannels, |
| 183 | size_t pNumPrimitives, const std::vector<size_t> &pVCount, Collada::PrimitiveType pPrimType); |
| 184 | |
| 185 | /// Copies the data for a single primitive into the mesh, based on the InputChannels |
| 186 | void CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset, |
| 187 | Collada::Mesh &pMesh, std::vector<Collada::InputChannel> &pPerIndexChannels, |
| 188 | size_t currentPrimitive, const std::vector<size_t> &indices); |
| 189 | |
| 190 | /// Reads one triangle of a tristrip into the mesh |
| 191 | void ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Collada::Mesh &pMesh, |
| 192 | std::vector<Collada::InputChannel> &pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t> &indices); |
| 193 | |
| 194 | /// Extracts a single object from an input channel and stores it in the appropriate mesh data array |
| 195 | void (const Collada::InputChannel &pInput, size_t pLocalIndex, Collada::Mesh &pMesh); |
| 196 | |
| 197 | /// Reads the library of node hierarchies and scene parts |
| 198 | void ReadSceneLibrary(XmlNode &node); |
| 199 | |
| 200 | /// Reads a scene node's contents including children and stores it in the given node |
| 201 | void ReadSceneNode(XmlNode &node, Collada::Node *pNode); |
| 202 | |
| 203 | /// Reads a mesh reference in a node and adds it to the node's mesh list |
| 204 | void ReadNodeGeometry(XmlNode &node, Collada::Node *pNode); |
| 205 | |
| 206 | /// Reads the collada scene |
| 207 | void ReadScene(XmlNode &node); |
| 208 | |
| 209 | /// Processes bind_vertex_input and bind elements |
| 210 | void ReadMaterialVertexInputBinding(XmlNode &node, Collada::SemanticMappingTable &tbl); |
| 211 | |
| 212 | /// Reads embedded textures from a ZAE archive |
| 213 | void ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive); |
| 214 | |
| 215 | protected: |
| 216 | /// Converts a path read from a collada file to the usual representation |
| 217 | static void UriDecodePath(aiString &ss); |
| 218 | |
| 219 | /// Calculates the resulting transformation from all the given transform steps |
| 220 | aiMatrix4x4 CalculateResultTransform(const std::vector<Collada::Transform> &pTransforms) const; |
| 221 | |
| 222 | /// Determines the input data type for the given semantic string |
| 223 | Collada::InputType GetTypeForSemantic(const std::string &pSemantic); |
| 224 | |
| 225 | /// Finds the item in the given library by its reference, throws if not found |
| 226 | template <typename Type> |
| 227 | const Type &ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const; |
| 228 | |
| 229 | private: |
| 230 | /// Filename, for a verbose error message |
| 231 | std::string mFileName; |
| 232 | |
| 233 | /// XML reader, member for everyday use |
| 234 | XmlParser mXmlParser; |
| 235 | |
| 236 | /// All data arrays found in the file by ID. Might be referred to by actually |
| 237 | /// everyone. Collada, you are a steaming pile of indirection. |
| 238 | using DataLibrary = std::map<std::string, Collada::Data> ; |
| 239 | DataLibrary mDataLibrary; |
| 240 | |
| 241 | /// Same for accessors which define how the data in a data array is accessed. |
| 242 | using AccessorLibrary = std::map<std::string, Collada::Accessor> ; |
| 243 | AccessorLibrary mAccessorLibrary; |
| 244 | |
| 245 | /// Mesh library: mesh by ID |
| 246 | using MeshLibrary = std::map<std::string, Collada::Mesh *>; |
| 247 | MeshLibrary mMeshLibrary; |
| 248 | |
| 249 | /// node library: root node of the hierarchy part by ID |
| 250 | using NodeLibrary = std::map<std::string, Collada::Node *>; |
| 251 | NodeLibrary mNodeLibrary; |
| 252 | |
| 253 | /// Image library: stores texture properties by ID |
| 254 | using ImageLibrary = std::map<std::string, Collada::Image> ; |
| 255 | ImageLibrary mImageLibrary; |
| 256 | |
| 257 | /// Effect library: surface attributes by ID |
| 258 | using EffectLibrary = std::map<std::string, Collada::Effect> ; |
| 259 | EffectLibrary mEffectLibrary; |
| 260 | |
| 261 | /// Material library: surface material by ID |
| 262 | using MaterialLibrary = std::map<std::string, Collada::Material> ; |
| 263 | MaterialLibrary mMaterialLibrary; |
| 264 | |
| 265 | /// Light library: surface light by ID |
| 266 | using LightLibrary = std::map<std::string, Collada::Light> ; |
| 267 | LightLibrary mLightLibrary; |
| 268 | |
| 269 | /// Camera library: surface material by ID |
| 270 | using CameraLibrary = std::map<std::string, Collada::Camera> ; |
| 271 | CameraLibrary mCameraLibrary; |
| 272 | |
| 273 | /// Controller library: joint controllers by ID |
| 274 | using ControllerLibrary = std::map<std::string, Collada::Controller> ; |
| 275 | ControllerLibrary mControllerLibrary; |
| 276 | |
| 277 | /// Animation library: animation references by ID |
| 278 | using AnimationLibrary = std::map<std::string, Collada::Animation *> ; |
| 279 | AnimationLibrary mAnimationLibrary; |
| 280 | |
| 281 | /// Animation clip library: clip animation references by ID |
| 282 | using AnimationClipLibrary = std::vector<std::pair<std::string, std::vector<std::string>>> ; |
| 283 | AnimationClipLibrary mAnimationClipLibrary; |
| 284 | |
| 285 | /// Pointer to the root node. Don't delete, it just points to one of the nodes in the node library. |
| 286 | Collada::Node *mRootNode; |
| 287 | |
| 288 | /// Root animation container |
| 289 | Collada::Animation mAnims; |
| 290 | |
| 291 | /// Size unit: how large compared to a meter |
| 292 | ai_real mUnitSize; |
| 293 | |
| 294 | /// Which is the up vector |
| 295 | enum { UP_X, |
| 296 | UP_Y, |
| 297 | UP_Z } mUpDirection; |
| 298 | |
| 299 | /// Asset metadata (global for scene) |
| 300 | StringMetaData mAssetMetaData; |
| 301 | |
| 302 | /// Collada file format version |
| 303 | Collada::FormatVersion mFormat; |
| 304 | }; |
| 305 | |
| 306 | // ------------------------------------------------------------------------------------------------ |
| 307 | // Finds the item in the given library by its reference, throws if not found |
| 308 | template <typename Type> |
| 309 | const Type &ColladaParser::ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const { |
| 310 | typename std::map<std::string, Type>::const_iterator it = pLibrary.find(pURL); |
| 311 | if (it == pLibrary.end()) { |
| 312 | throw DeadlyImportError("Unable to resolve library reference \"" , pURL, "\"." ); |
| 313 | } |
| 314 | return it->second; |
| 315 | } |
| 316 | |
| 317 | } // end of namespace Assimp |
| 318 | |
| 319 | #endif // AI_COLLADAPARSER_H_INC |
| 320 | |