1 /*
2  Open Asset Import Library (assimp)
3  ----------------------------------------------------------------------
4 
5  Copyright (c) 2006-2015, assimp team
6  All rights reserved.
7 
8  Redistribution and use of this software in source and binary forms,
9  with or without modification, are permitted provided that the
10  following conditions are met:
11 
12  * Redistributions of source code must retain the above
13  copyright notice, this list of conditions and the
14  following disclaimer.
15 
16  * Redistributions in binary form must reproduce the above
17  copyright notice, this list of conditions and the
18  following disclaimer in the documentation and/or other
19  materials provided with the distribution.
20 
21  * Neither the name of the assimp team, nor the names of its
22  contributors may be used to endorse or promote products
23  derived from this software without specific prior
24  written permission of the assimp team.
25 
26  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 
38  ----------------------------------------------------------------------
39  */
40 
41 /** @file ColladaParser.h
42  *  @brief Defines the parser helper class for the collada loader
43  */
44 
45 #ifndef AI_COLLADAPARSER_H_INC
46 #define AI_COLLADAPARSER_H_INC
47 
48 #include "irrXMLWrapper.h"
49 #include "ColladaHelper.h"
50 #include "../include/assimp/ai_assert.h"
51 #include <boost/format.hpp>
52 
53 namespace Assimp
54 {
55 
56     // ------------------------------------------------------------------------------------------
57     /** Parser helper class for the Collada loader.
58      *
59      *  Does all the XML reading and builds internal data structures from it,
60      *  but leaves the resolving of all the references to the loader.
61      */
62     class ColladaParser
63     {
64         friend class ColladaLoader;
65 
66     protected:
67         /** Constructor from XML file */
68         ColladaParser( IOSystem* pIOHandler, const std::string& pFile);
69 
70         /** Destructor */
71         ~ColladaParser();
72 
73         /** Reads the contents of the file */
74         void ReadContents();
75 
76         /** Reads the structure of the file */
77         void ReadStructure();
78 
79         /** Reads asset informations such as coordinate system informations and legal blah */
80         void ReadAssetInfo();
81 
82         /** Reads the animation library */
83         void ReadAnimationLibrary();
84 
85         /** Reads an animation into the given parent structure */
86         void ReadAnimation( Collada::Animation* pParent);
87 
88         /** Reads an animation sampler into the given anim channel */
89         void ReadAnimationSampler( Collada::AnimationChannel& pChannel);
90 
91         /** Reads the skeleton controller library */
92         void ReadControllerLibrary();
93 
94         /** Reads a controller into the given mesh structure */
95         void ReadController( Collada::Controller& pController);
96 
97         /** Reads the joint definitions for the given controller */
98         void ReadControllerJoints( Collada::Controller& pController);
99 
100         /** Reads the joint weights for the given controller */
101         void ReadControllerWeights( Collada::Controller& pController);
102 
103         /** Reads the image library contents */
104         void ReadImageLibrary();
105 
106         /** Reads an image entry into the given image */
107         void ReadImage( Collada::Image& pImage);
108 
109         /** Reads the material library */
110         void ReadMaterialLibrary();
111 
112         /** Reads a material entry into the given material */
113         void ReadMaterial( Collada::Material& pMaterial);
114 
115         /** Reads the camera library */
116         void ReadCameraLibrary();
117 
118         /** Reads a camera entry into the given camera */
119         void ReadCamera( Collada::Camera& pCamera);
120 
121         /** Reads the light library */
122         void ReadLightLibrary();
123 
124         /** Reads a light entry into the given light */
125         void ReadLight( Collada::Light& pLight);
126 
127         /** Reads the effect library */
128         void ReadEffectLibrary();
129 
130         /** Reads an effect entry into the given effect*/
131         void ReadEffect( Collada::Effect& pEffect);
132 
133         /** Reads an COMMON effect profile */
134         void ReadEffectProfileCommon( Collada::Effect& pEffect);
135 
136         /** Read sampler properties */
137         void ReadSamplerProperties( Collada::Sampler& pSampler);
138 
139         /** Reads an effect entry containing a color or a texture defining that color */
140         void ReadEffectColor( aiColor4D& pColor, Collada::Sampler& pSampler);
141 
142         /** Reads an effect entry containing a float */
143         void ReadEffectFloat( float& pFloat);
144 
145         /** Reads an effect parameter specification of any kind */
146         void ReadEffectParam( Collada::EffectParam& pParam);
147 
148         /** Reads the geometry library contents */
149         void ReadGeometryLibrary();
150 
151         /** Reads a geometry from the geometry library. */
152         void ReadGeometry( Collada::Mesh* pMesh);
153 
154         /** Reads a mesh from the geometry library */
155         void ReadMesh( Collada::Mesh* pMesh);
156 
157         /** Reads a source element - a combination of raw data and an accessor defining
158          * things that should not be redefinable. Yes, that's another rant.
159          */
160         void ReadSource();
161 
162         /** Reads a data array holding a number of elements, and stores it in the global library.
163          * Currently supported are array of floats and arrays of strings.
164          */
165         void ReadDataArray();
166 
167         /** Reads an accessor and stores it in the global library under the given ID -
168          * accessors use the ID of the parent <source> element
169          */
170         void ReadAccessor( const std::string& pID);
171 
172         /** Reads input declarations of per-vertex mesh data into the given mesh */
173         void ReadVertexData( Collada::Mesh* pMesh);
174 
175         /** Reads input declarations of per-index mesh data into the given mesh */
176         void ReadIndexData( Collada::Mesh* pMesh);
177 
178         /** Reads a single input channel element and stores it in the given array, if valid */
179         void ReadInputChannel( 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( 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 ExtractDataObjectFromChannel( const Collada::InputChannel& pInput, size_t pLocalIndex, Collada::Mesh* pMesh);
196 
197         /** Reads the library of node hierarchies and scene parts */
198         void ReadSceneLibrary();
199 
200         /** Reads a scene node's contents including children and stores it in the given node */
201         void ReadSceneNode( Collada::Node* pNode);
202 
203         /** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */
204         void ReadNodeTransformation( Collada::Node* pNode, Collada::TransformType pType);
205 
206         /** Reads a mesh reference in a node and adds it to the node's mesh list */
207         void ReadNodeGeometry( Collada::Node* pNode);
208 
209         /** Reads the collada scene */
210         void ReadScene();
211 
212         // Processes bind_vertex_input and bind elements
213         void ReadMaterialVertexInputBinding( Collada::SemanticMappingTable& tbl);
214 
215     protected:
216         /** Aborts the file reading with an exception */
217         AI_WONT_RETURN void ThrowException( const std::string& pError) const AI_WONT_RETURN_SUFFIX;
218         void ReportWarning(const char* msg,...);
219 
220         /** Skips all data until the end node of the current element */
221         void SkipElement();
222 
223         /** Skips all data until the end node of the given element */
224         void SkipElement( const char* pElement);
225 
226         /** Compares the current xml element name to the given string and returns true if equal */
227         bool IsElement( const char* pName) const;
228 
229         /** Tests for the opening tag of the given element, throws an exception if not found */
230         void TestOpening( const char* pName);
231 
232         /** Tests for the closing tag of the given element, throws an exception if not found */
233         void TestClosing( const char* pName);
234 
235         /** Checks the present element for the presence of the attribute, returns its index
236          or throws an exception if not found */
237         int GetAttribute( const char* pAttr) const;
238 
239         /** Returns the index of the named attribute or -1 if not found. Does not throw,
240          therefore useful for optional attributes */
241         int TestAttribute( const char* pAttr) const;
242 
243         /** Reads the text contents of an element, throws an exception if not given.
244          Skips leading whitespace. */
245         const char* GetTextContent();
246 
247         /** Reads the text contents of an element, returns NULL if not given.
248          Skips leading whitespace. */
249         const char* TestTextContent();
250 
251         /** Reads a single bool from current text content */
252         bool ReadBoolFromTextContent();
253 
254         /** Reads a single float from current text content */
255         float ReadFloatFromTextContent();
256 
257         /** Calculates the resulting transformation from all the given transform steps */
258         aiMatrix4x4 CalculateResultTransform( const std::vector<Collada::Transform>& pTransforms) const;
259 
260         /** Determines the input data type for the given semantic string */
261         Collada::InputType GetTypeForSemantic( const std::string& pSemantic);
262 
263         /** Finds the item in the given library by its reference, throws if not found */
264         template <typename Type> const Type& ResolveLibraryReference(
265                                                                      const std::map<std::string, Type>& pLibrary, const std::string& pURL) const;
266 
267     protected:
268         /** Filename, for a verbose error message */
269         std::string mFileName;
270 
271         /** XML reader, member for everyday use */
272         irr::io::IrrXMLReader* mReader;
273 
274         /** All data arrays found in the file by ID. Might be referred to by actually
275          everyone. Collada, you are a steaming pile of indirection. */
276         typedef std::map<std::string, Collada::Data> DataLibrary;
277         DataLibrary mDataLibrary;
278 
279         /** Same for accessors which define how the data in a data array is accessed. */
280         typedef std::map<std::string, Collada::Accessor> AccessorLibrary;
281         AccessorLibrary mAccessorLibrary;
282 
283         /** Mesh library: mesh by ID */
284         typedef std::map<std::string, Collada::Mesh*> MeshLibrary;
285         MeshLibrary mMeshLibrary;
286 
287         /** node library: root node of the hierarchy part by ID */
288         typedef std::map<std::string, Collada::Node*> NodeLibrary;
289         NodeLibrary mNodeLibrary;
290 
291         /** Image library: stores texture properties by ID */
292         typedef std::map<std::string, Collada::Image> ImageLibrary;
293         ImageLibrary mImageLibrary;
294 
295         /** Effect library: surface attributes by ID */
296         typedef std::map<std::string, Collada::Effect> EffectLibrary;
297         EffectLibrary mEffectLibrary;
298 
299         /** Material library: surface material by ID */
300         typedef std::map<std::string, Collada::Material> MaterialLibrary;
301         MaterialLibrary mMaterialLibrary;
302 
303         /** Light library: surface light by ID */
304         typedef std::map<std::string, Collada::Light> LightLibrary;
305         LightLibrary mLightLibrary;
306 
307         /** Camera library: surface material by ID */
308         typedef std::map<std::string, Collada::Camera> CameraLibrary;
309         CameraLibrary mCameraLibrary;
310 
311         /** Controller library: joint controllers by ID */
312         typedef std::map<std::string, Collada::Controller> ControllerLibrary;
313         ControllerLibrary mControllerLibrary;
314 
315         /** Pointer to the root node. Don't delete, it just points to one of
316          the nodes in the node library. */
317         Collada::Node* mRootNode;
318 
319         /** Root animation container */
320         Collada::Animation mAnims;
321 
322         /** Size unit: how large compared to a meter */
323         float mUnitSize;
324 
325         /** Which is the up vector */
326         enum { UP_X, UP_Y, UP_Z } mUpDirection;
327 
328         /** Collada file format version */
329         Collada::FormatVersion mFormat;
330     };
331 
332     // ------------------------------------------------------------------------------------------------
333     // Check for element match
IsElement(const char * pName)334     inline bool ColladaParser::IsElement( const char* pName) const
335     {
336         ai_assert( mReader->getNodeType() == irr::io::EXN_ELEMENT);
337         return ::strcmp( mReader->getNodeName(), pName) == 0;
338     }
339 
340     // ------------------------------------------------------------------------------------------------
341     // Finds the item in the given library by its reference, throws if not found
342     template <typename Type>
ResolveLibraryReference(const std::map<std::string,Type> & pLibrary,const std::string & pURL)343     const Type& ColladaParser::ResolveLibraryReference( const std::map<std::string, Type>& pLibrary, const std::string& pURL) const
344     {
345         typename std::map<std::string, Type>::const_iterator it = pLibrary.find( pURL);
346         if( it == pLibrary.end())
347             ThrowException( boost::str( boost::format( "Unable to resolve library reference \"%s\".") % pURL));
348         return it->second;
349     }
350 
351 } // end of namespace Assimp
352 
353 #endif // AI_COLLADAPARSER_H_INC
354