1/*
2 Open Asset Import Library (assimp)
3 ----------------------------------------------------------------------
4
5 Copyright (c) 2006-2017, 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#ifndef AI_COLLADAPARSER_H_INC
47#define AI_COLLADAPARSER_H_INC
48
49#include "irrXMLWrapper.h"
50#include "ColladaHelper.h"
51#include <assimp/ai_assert.h>
52#include "TinyFormatter.h"
53
54namespace Assimp
55{
56
57 // ------------------------------------------------------------------------------------------
58 /** Parser helper class for the Collada loader.
59 *
60 * Does all the XML reading and builds internal data structures from it,
61 * but leaves the resolving of all the references to the loader.
62 */
63 class ColladaParser
64 {
65 friend class ColladaLoader;
66
67 protected:
68 /** Constructor from XML file */
69 ColladaParser( IOSystem* pIOHandler, const std::string& pFile);
70
71 /** Destructor */
72 ~ColladaParser();
73
74 /** Reads the contents of the file */
75 void ReadContents();
76
77 /** Reads the structure of the file */
78 void ReadStructure();
79
80 /** Reads asset information such as coordinate system information and legal blah */
81 void ReadAssetInfo();
82
83 /** Reads the animation library */
84 void ReadAnimationLibrary();
85
86 /** Reads the animation clip library */
87 void ReadAnimationClipLibrary();
88
89 /** Re-build animations from animation clip library, if present, otherwise combine single-channel animations */
90 void PostProcessRootAnimations();
91
92 /** Reads an animation into the given parent structure */
93 void ReadAnimation( Collada::Animation* pParent);
94
95 /** Reads an animation sampler into the given anim channel */
96 void ReadAnimationSampler( Collada::AnimationChannel& pChannel);
97
98 /** Reads the skeleton controller library */
99 void ReadControllerLibrary();
100
101 /** Reads a controller into the given mesh structure */
102 void ReadController( Collada::Controller& pController);
103
104 /** Reads the joint definitions for the given controller */
105 void ReadControllerJoints( Collada::Controller& pController);
106
107 /** Reads the joint weights for the given controller */
108 void ReadControllerWeights( Collada::Controller& pController);
109
110 /** Reads the image library contents */
111 void ReadImageLibrary();
112
113 /** Reads an image entry into the given image */
114 void ReadImage( Collada::Image& pImage);
115
116 /** Reads the material library */
117 void ReadMaterialLibrary();
118
119 /** Reads a material entry into the given material */
120 void ReadMaterial( Collada::Material& pMaterial);
121
122 /** Reads the camera library */
123 void ReadCameraLibrary();
124
125 /** Reads a camera entry into the given camera */
126 void ReadCamera( Collada::Camera& pCamera);
127
128 /** Reads the light library */
129 void ReadLightLibrary();
130
131 /** Reads a light entry into the given light */
132 void ReadLight( Collada::Light& pLight);
133
134 /** Reads the effect library */
135 void ReadEffectLibrary();
136
137 /** Reads an effect entry into the given effect*/
138 void ReadEffect( Collada::Effect& pEffect);
139
140 /** Reads an COMMON effect profile */
141 void ReadEffectProfileCommon( Collada::Effect& pEffect);
142
143 /** Read sampler properties */
144 void ReadSamplerProperties( Collada::Sampler& pSampler);
145
146 /** Reads an effect entry containing a color or a texture defining that color */
147 void ReadEffectColor( aiColor4D& pColor, Collada::Sampler& pSampler);
148
149 /** Reads an effect entry containing a float */
150 void ReadEffectFloat( ai_real& pFloat);
151
152 /** Reads an effect parameter specification of any kind */
153 void ReadEffectParam( Collada::EffectParam& pParam);
154
155 /** Reads the geometry library contents */
156 void ReadGeometryLibrary();
157
158 /** Reads a geometry from the geometry library. */
159 void ReadGeometry( Collada::Mesh* pMesh);
160
161 /** Reads a mesh from the geometry library */
162 void ReadMesh( Collada::Mesh* pMesh);
163
164 /** Reads a source element - a combination of raw data and an accessor defining
165 * things that should not be redefinable. Yes, that's another rant.
166 */
167 void ReadSource();
168
169 /** Reads a data array holding a number of elements, and stores it in the global library.
170 * Currently supported are array of floats and arrays of strings.
171 */
172 void ReadDataArray();
173
174 /** Reads an accessor and stores it in the global library under the given ID -
175 * accessors use the ID of the parent <source> element
176 */
177 void ReadAccessor( const std::string& pID);
178
179 /** Reads input declarations of per-vertex mesh data into the given mesh */
180 void ReadVertexData( Collada::Mesh* pMesh);
181
182 /** Reads input declarations of per-index mesh data into the given mesh */
183 void ReadIndexData( Collada::Mesh* pMesh);
184
185 /** Reads a single input channel element and stores it in the given array, if valid */
186 void ReadInputChannel( std::vector<Collada::InputChannel>& poChannels);
187
188 /** Reads a <p> primitive index list and assembles the mesh data into the given mesh */
189 size_t ReadPrimitives( Collada::Mesh* pMesh, std::vector<Collada::InputChannel>& pPerIndexChannels,
190 size_t pNumPrimitives, const std::vector<size_t>& pVCount, Collada::PrimitiveType pPrimType);
191
192 /** Copies the data for a single primitive into the mesh, based on the InputChannels */
193 void CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset,
194 Collada::Mesh* pMesh, std::vector<Collada::InputChannel>& pPerIndexChannels,
195 size_t currentPrimitive, const std::vector<size_t>& indices);
196
197 /** Reads one triangle of a tristrip into the mesh */
198 void ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Collada::Mesh* pMesh,
199 std::vector<Collada::InputChannel>& pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t>& indices);
200
201 /** Extracts a single object from an input channel and stores it in the appropriate mesh data array */
202 void ExtractDataObjectFromChannel( const Collada::InputChannel& pInput, size_t pLocalIndex, Collada::Mesh* pMesh);
203
204 /** Reads the library of node hierarchies and scene parts */
205 void ReadSceneLibrary();
206
207 /** Reads a scene node's contents including children and stores it in the given node */
208 void ReadSceneNode( Collada::Node* pNode);
209
210 /** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */
211 void ReadNodeTransformation( Collada::Node* pNode, Collada::TransformType pType);
212
213 /** Reads a mesh reference in a node and adds it to the node's mesh list */
214 void ReadNodeGeometry( Collada::Node* pNode);
215
216 /** Reads the collada scene */
217 void ReadScene();
218
219 // Processes bind_vertex_input and bind elements
220 void ReadMaterialVertexInputBinding( Collada::SemanticMappingTable& tbl);
221
222 protected:
223 /** Aborts the file reading with an exception */
224 AI_WONT_RETURN void ThrowException( const std::string& pError) const AI_WONT_RETURN_SUFFIX;
225 void ReportWarning(const char* msg,...);
226
227 /** Skips all data until the end node of the current element */
228 void SkipElement();
229
230 /** Skips all data until the end node of the given element */
231 void SkipElement( const char* pElement);
232
233 /** Compares the current xml element name to the given string and returns true if equal */
234 bool IsElement( const char* pName) const;
235
236 /** Tests for the opening tag of the given element, throws an exception if not found */
237 void TestOpening( const char* pName);
238
239 /** Tests for the closing tag of the given element, throws an exception if not found */
240 void TestClosing( const char* pName);
241
242 /** Checks the present element for the presence of the attribute, returns its index
243 or throws an exception if not found */
244 int GetAttribute( const char* pAttr) const;
245
246 /** Returns the index of the named attribute or -1 if not found. Does not throw,
247 therefore useful for optional attributes */
248 int TestAttribute( const char* pAttr) const;
249
250 /** Reads the text contents of an element, throws an exception if not given.
251 Skips leading whitespace. */
252 const char* GetTextContent();
253
254 /** Reads the text contents of an element, returns NULL if not given.
255 Skips leading whitespace. */
256 const char* TestTextContent();
257
258 /** Reads a single bool from current text content */
259 bool ReadBoolFromTextContent();
260
261 /** Reads a single float from current text content */
262 ai_real ReadFloatFromTextContent();
263
264 /** Calculates the resulting transformation from all the given transform steps */
265 aiMatrix4x4 CalculateResultTransform( const std::vector<Collada::Transform>& pTransforms) const;
266
267 /** Determines the input data type for the given semantic string */
268 Collada::InputType GetTypeForSemantic( const std::string& pSemantic);
269
270 /** Finds the item in the given library by its reference, throws if not found */
271 template <typename Type> const Type& ResolveLibraryReference( const std::map<std::string, Type>& pLibrary, const std::string& pURL) const;
272
273 protected:
274 /** Filename, for a verbose error message */
275 std::string mFileName;
276
277 /** XML reader, member for everyday use */
278 irr::io::IrrXMLReader* mReader;
279
280 /** All data arrays found in the file by ID. Might be referred to by actually
281 everyone. Collada, you are a steaming pile of indirection. */
282 typedef std::map<std::string, Collada::Data> DataLibrary;
283 DataLibrary mDataLibrary;
284
285 /** Same for accessors which define how the data in a data array is accessed. */
286 typedef std::map<std::string, Collada::Accessor> AccessorLibrary;
287 AccessorLibrary mAccessorLibrary;
288
289 /** Mesh library: mesh by ID */
290 typedef std::map<std::string, Collada::Mesh*> MeshLibrary;
291 MeshLibrary mMeshLibrary;
292
293 /** node library: root node of the hierarchy part by ID */
294 typedef std::map<std::string, Collada::Node*> NodeLibrary;
295 NodeLibrary mNodeLibrary;
296
297 /** Image library: stores texture properties by ID */
298 typedef std::map<std::string, Collada::Image> ImageLibrary;
299 ImageLibrary mImageLibrary;
300
301 /** Effect library: surface attributes by ID */
302 typedef std::map<std::string, Collada::Effect> EffectLibrary;
303 EffectLibrary mEffectLibrary;
304
305 /** Material library: surface material by ID */
306 typedef std::map<std::string, Collada::Material> MaterialLibrary;
307 MaterialLibrary mMaterialLibrary;
308
309 /** Light library: surface light by ID */
310 typedef std::map<std::string, Collada::Light> LightLibrary;
311 LightLibrary mLightLibrary;
312
313 /** Camera library: surface material by ID */
314 typedef std::map<std::string, Collada::Camera> CameraLibrary;
315 CameraLibrary mCameraLibrary;
316
317 /** Controller library: joint controllers by ID */
318 typedef std::map<std::string, Collada::Controller> ControllerLibrary;
319 ControllerLibrary mControllerLibrary;
320
321 /** Animation library: animation references by ID */
322 typedef std::map<std::string, Collada::Animation*> AnimationLibrary;
323 AnimationLibrary mAnimationLibrary;
324
325 /** Animation clip library: clip animation references by ID */
326 typedef std::vector<std::pair<std::string, std::vector<std::string> > > AnimationClipLibrary;
327 AnimationClipLibrary mAnimationClipLibrary;
328
329 /** Pointer to the root node. Don't delete, it just points to one of
330 the nodes in the node library. */
331 Collada::Node* mRootNode;
332
333 /** Root animation container */
334 Collada::Animation mAnims;
335
336 /** Size unit: how large compared to a meter */
337 ai_real mUnitSize;
338
339 /** Which is the up vector */
340 enum { UP_X, UP_Y, UP_Z } mUpDirection;
341
342 /** Collada file format version */
343 Collada::FormatVersion mFormat;
344 };
345
346 // ------------------------------------------------------------------------------------------------
347 // Check for element match
348 inline bool ColladaParser::IsElement( const char* pName) const
349 {
350 ai_assert( mReader->getNodeType() == irr::io::EXN_ELEMENT);
351 return ::strcmp( mReader->getNodeName(), pName) == 0;
352 }
353
354 // ------------------------------------------------------------------------------------------------
355 // Finds the item in the given library by its reference, throws if not found
356 template <typename Type>
357 const Type& ColladaParser::ResolveLibraryReference( const std::map<std::string, Type>& pLibrary, const std::string& pURL) const
358 {
359 typename std::map<std::string, Type>::const_iterator it = pLibrary.find( pURL);
360 if( it == pLibrary.end())
361 ThrowException( Formatter::format() << "Unable to resolve library reference \"" << pURL << "\"." );
362 return it->second;
363 }
364
365} // end of namespace Assimp
366
367#endif // AI_COLLADAPARSER_H_INC
368