rev |
line source |
nuclear@0
|
1 /*
|
nuclear@0
|
2 ---------------------------------------------------------------------------
|
nuclear@0
|
3 Open Asset Import Library (assimp)
|
nuclear@0
|
4 ---------------------------------------------------------------------------
|
nuclear@0
|
5
|
nuclear@0
|
6 Copyright (c) 2006-2012, assimp team
|
nuclear@0
|
7
|
nuclear@0
|
8 All rights reserved.
|
nuclear@0
|
9
|
nuclear@0
|
10 Redistribution and use of this software in source and binary forms,
|
nuclear@0
|
11 with or without modification, are permitted provided that the following
|
nuclear@0
|
12 conditions are met:
|
nuclear@0
|
13
|
nuclear@0
|
14 * Redistributions of source code must retain the above
|
nuclear@0
|
15 copyright notice, this list of conditions and the
|
nuclear@0
|
16 following disclaimer.
|
nuclear@0
|
17
|
nuclear@0
|
18 * Redistributions in binary form must reproduce the above
|
nuclear@0
|
19 copyright notice, this list of conditions and the
|
nuclear@0
|
20 following disclaimer in the documentation and/or other
|
nuclear@0
|
21 materials provided with the distribution.
|
nuclear@0
|
22
|
nuclear@0
|
23 * Neither the name of the assimp team, nor the names of its
|
nuclear@0
|
24 contributors may be used to endorse or promote products
|
nuclear@0
|
25 derived from this software without specific prior
|
nuclear@0
|
26 written permission of the assimp team.
|
nuclear@0
|
27
|
nuclear@0
|
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
nuclear@0
|
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
nuclear@0
|
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
nuclear@0
|
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
nuclear@0
|
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
nuclear@0
|
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
nuclear@0
|
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
nuclear@0
|
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
nuclear@0
|
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
nuclear@0
|
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
nuclear@0
|
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
nuclear@0
|
39 ---------------------------------------------------------------------------
|
nuclear@0
|
40 */
|
nuclear@0
|
41
|
nuclear@0
|
42 /** @file ColladaParser.cpp
|
nuclear@0
|
43 * @brief Implementation of the Collada parser helper
|
nuclear@0
|
44 */
|
nuclear@0
|
45
|
nuclear@0
|
46 #include "AssimpPCH.h"
|
nuclear@0
|
47 #ifndef ASSIMP_BUILD_NO_COLLADA_IMPORTER
|
nuclear@0
|
48
|
nuclear@0
|
49 #include "ColladaParser.h"
|
nuclear@0
|
50 #include "fast_atof.h"
|
nuclear@0
|
51 #include "ParsingUtils.h"
|
nuclear@0
|
52
|
nuclear@0
|
53 using namespace Assimp;
|
nuclear@0
|
54 using namespace Assimp::Collada;
|
nuclear@0
|
55
|
nuclear@0
|
56 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
57 // Constructor to be privately used by Importer
|
nuclear@0
|
58 ColladaParser::ColladaParser( IOSystem* pIOHandler, const std::string& pFile)
|
nuclear@0
|
59 : mFileName( pFile)
|
nuclear@0
|
60 {
|
nuclear@0
|
61 mRootNode = NULL;
|
nuclear@0
|
62 mUnitSize = 1.0f;
|
nuclear@0
|
63 mUpDirection = UP_Z;
|
nuclear@0
|
64
|
nuclear@0
|
65 // We assume the newest file format by default
|
nuclear@0
|
66 mFormat = FV_1_5_n;
|
nuclear@0
|
67
|
nuclear@0
|
68 // open the file
|
nuclear@0
|
69 boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
|
nuclear@0
|
70 if( file.get() == NULL)
|
nuclear@0
|
71 throw DeadlyImportError( "Failed to open file " + pFile + ".");
|
nuclear@0
|
72
|
nuclear@0
|
73 // generate a XML reader for it
|
nuclear@0
|
74 boost::scoped_ptr<CIrrXML_IOStreamReader> mIOWrapper( new CIrrXML_IOStreamReader( file.get()));
|
nuclear@0
|
75 mReader = irr::io::createIrrXMLReader( mIOWrapper.get());
|
nuclear@0
|
76 if( !mReader)
|
nuclear@0
|
77 ThrowException( "Collada: Unable to open file.");
|
nuclear@0
|
78
|
nuclear@0
|
79 // start reading
|
nuclear@0
|
80 ReadContents();
|
nuclear@0
|
81 }
|
nuclear@0
|
82
|
nuclear@0
|
83 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
84 // Destructor, private as well
|
nuclear@0
|
85 ColladaParser::~ColladaParser()
|
nuclear@0
|
86 {
|
nuclear@0
|
87 delete mReader;
|
nuclear@0
|
88 for( NodeLibrary::iterator it = mNodeLibrary.begin(); it != mNodeLibrary.end(); ++it)
|
nuclear@0
|
89 delete it->second;
|
nuclear@0
|
90 for( MeshLibrary::iterator it = mMeshLibrary.begin(); it != mMeshLibrary.end(); ++it)
|
nuclear@0
|
91 delete it->second;
|
nuclear@0
|
92 }
|
nuclear@0
|
93
|
nuclear@0
|
94 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
95 // Read bool from text contents of current element
|
nuclear@0
|
96 bool ColladaParser::ReadBoolFromTextContent()
|
nuclear@0
|
97 {
|
nuclear@0
|
98 const char* cur = GetTextContent();
|
nuclear@0
|
99 return (!ASSIMP_strincmp(cur,"true",4) || '0' != *cur);
|
nuclear@0
|
100 }
|
nuclear@0
|
101
|
nuclear@0
|
102 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
103 // Read float from text contents of current element
|
nuclear@0
|
104 float ColladaParser::ReadFloatFromTextContent()
|
nuclear@0
|
105 {
|
nuclear@0
|
106 const char* cur = GetTextContent();
|
nuclear@0
|
107 return fast_atof(cur);
|
nuclear@0
|
108 }
|
nuclear@0
|
109
|
nuclear@0
|
110 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
111 // Reads the contents of the file
|
nuclear@0
|
112 void ColladaParser::ReadContents()
|
nuclear@0
|
113 {
|
nuclear@0
|
114 while( mReader->read())
|
nuclear@0
|
115 {
|
nuclear@0
|
116 // handle the root element "COLLADA"
|
nuclear@0
|
117 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
118 {
|
nuclear@0
|
119 if( IsElement( "COLLADA"))
|
nuclear@0
|
120 {
|
nuclear@0
|
121 // check for 'version' attribute
|
nuclear@0
|
122 const int attrib = TestAttribute("version");
|
nuclear@0
|
123 if (attrib != -1) {
|
nuclear@0
|
124 const char* version = mReader->getAttributeValue(attrib);
|
nuclear@0
|
125
|
nuclear@0
|
126 if (!::strncmp(version,"1.5",3)) {
|
nuclear@0
|
127 mFormat = FV_1_5_n;
|
nuclear@0
|
128 DefaultLogger::get()->debug("Collada schema version is 1.5.n");
|
nuclear@0
|
129 }
|
nuclear@0
|
130 else if (!::strncmp(version,"1.4",3)) {
|
nuclear@0
|
131 mFormat = FV_1_4_n;
|
nuclear@0
|
132 DefaultLogger::get()->debug("Collada schema version is 1.4.n");
|
nuclear@0
|
133 }
|
nuclear@0
|
134 else if (!::strncmp(version,"1.3",3)) {
|
nuclear@0
|
135 mFormat = FV_1_3_n;
|
nuclear@0
|
136 DefaultLogger::get()->debug("Collada schema version is 1.3.n");
|
nuclear@0
|
137 }
|
nuclear@0
|
138 }
|
nuclear@0
|
139
|
nuclear@0
|
140 ReadStructure();
|
nuclear@0
|
141 } else
|
nuclear@0
|
142 {
|
nuclear@0
|
143 DefaultLogger::get()->debug( boost::str( boost::format( "Ignoring global element <%s>.") % mReader->getNodeName()));
|
nuclear@0
|
144 SkipElement();
|
nuclear@0
|
145 }
|
nuclear@0
|
146 } else
|
nuclear@0
|
147 {
|
nuclear@0
|
148 // skip everything else silently
|
nuclear@0
|
149 }
|
nuclear@0
|
150 }
|
nuclear@0
|
151 }
|
nuclear@0
|
152
|
nuclear@0
|
153 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
154 // Reads the structure of the file
|
nuclear@0
|
155 void ColladaParser::ReadStructure()
|
nuclear@0
|
156 {
|
nuclear@0
|
157 while( mReader->read())
|
nuclear@0
|
158 {
|
nuclear@0
|
159 // beginning of elements
|
nuclear@0
|
160 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
161 {
|
nuclear@0
|
162 if( IsElement( "asset"))
|
nuclear@0
|
163 ReadAssetInfo();
|
nuclear@0
|
164 else if( IsElement( "library_animations"))
|
nuclear@0
|
165 ReadAnimationLibrary();
|
nuclear@0
|
166 else if( IsElement( "library_controllers"))
|
nuclear@0
|
167 ReadControllerLibrary();
|
nuclear@0
|
168 else if( IsElement( "library_images"))
|
nuclear@0
|
169 ReadImageLibrary();
|
nuclear@0
|
170 else if( IsElement( "library_materials"))
|
nuclear@0
|
171 ReadMaterialLibrary();
|
nuclear@0
|
172 else if( IsElement( "library_effects"))
|
nuclear@0
|
173 ReadEffectLibrary();
|
nuclear@0
|
174 else if( IsElement( "library_geometries"))
|
nuclear@0
|
175 ReadGeometryLibrary();
|
nuclear@0
|
176 else if( IsElement( "library_visual_scenes"))
|
nuclear@0
|
177 ReadSceneLibrary();
|
nuclear@0
|
178 else if( IsElement( "library_lights"))
|
nuclear@0
|
179 ReadLightLibrary();
|
nuclear@0
|
180 else if( IsElement( "library_cameras"))
|
nuclear@0
|
181 ReadCameraLibrary();
|
nuclear@0
|
182 else if( IsElement( "library_nodes"))
|
nuclear@0
|
183 ReadSceneNode(NULL); /* some hacking to reuse this piece of code */
|
nuclear@0
|
184 else if( IsElement( "scene"))
|
nuclear@0
|
185 ReadScene();
|
nuclear@0
|
186 else
|
nuclear@0
|
187 SkipElement();
|
nuclear@0
|
188 }
|
nuclear@0
|
189 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
nuclear@0
|
190 {
|
nuclear@0
|
191 break;
|
nuclear@0
|
192 }
|
nuclear@0
|
193 }
|
nuclear@0
|
194 }
|
nuclear@0
|
195
|
nuclear@0
|
196 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
197 // Reads asset informations such as coordinate system informations and legal blah
|
nuclear@0
|
198 void ColladaParser::ReadAssetInfo()
|
nuclear@0
|
199 {
|
nuclear@0
|
200 if( mReader->isEmptyElement())
|
nuclear@0
|
201 return;
|
nuclear@0
|
202
|
nuclear@0
|
203 while( mReader->read())
|
nuclear@0
|
204 {
|
nuclear@0
|
205 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
206 {
|
nuclear@0
|
207 if( IsElement( "unit"))
|
nuclear@0
|
208 {
|
nuclear@0
|
209 // read unit data from the element's attributes
|
nuclear@0
|
210 const int attrIndex = TestAttribute( "meter");
|
nuclear@0
|
211 if (attrIndex == -1) {
|
nuclear@0
|
212 mUnitSize = 1.f;
|
nuclear@0
|
213 }
|
nuclear@0
|
214 else {
|
nuclear@0
|
215 mUnitSize = mReader->getAttributeValueAsFloat( attrIndex);
|
nuclear@0
|
216 }
|
nuclear@0
|
217
|
nuclear@0
|
218 // consume the trailing stuff
|
nuclear@0
|
219 if( !mReader->isEmptyElement())
|
nuclear@0
|
220 SkipElement();
|
nuclear@0
|
221 }
|
nuclear@0
|
222 else if( IsElement( "up_axis"))
|
nuclear@0
|
223 {
|
nuclear@0
|
224 // read content, strip whitespace, compare
|
nuclear@0
|
225 const char* content = GetTextContent();
|
nuclear@0
|
226 if( strncmp( content, "X_UP", 4) == 0)
|
nuclear@0
|
227 mUpDirection = UP_X;
|
nuclear@0
|
228 else if( strncmp( content, "Y_UP", 4) == 0)
|
nuclear@0
|
229 mUpDirection = UP_Y;
|
nuclear@0
|
230 else
|
nuclear@0
|
231 mUpDirection = UP_Z;
|
nuclear@0
|
232
|
nuclear@0
|
233 // check element end
|
nuclear@0
|
234 TestClosing( "up_axis");
|
nuclear@0
|
235 } else
|
nuclear@0
|
236 {
|
nuclear@0
|
237 SkipElement();
|
nuclear@0
|
238 }
|
nuclear@0
|
239 }
|
nuclear@0
|
240 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
nuclear@0
|
241 {
|
nuclear@0
|
242 if( strcmp( mReader->getNodeName(), "asset") != 0)
|
nuclear@0
|
243 ThrowException( "Expected end of <asset> element.");
|
nuclear@0
|
244
|
nuclear@0
|
245 break;
|
nuclear@0
|
246 }
|
nuclear@0
|
247 }
|
nuclear@0
|
248 }
|
nuclear@0
|
249
|
nuclear@0
|
250 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
251 // Reads the animation library
|
nuclear@0
|
252 void ColladaParser::ReadAnimationLibrary()
|
nuclear@0
|
253 {
|
nuclear@0
|
254 if (mReader->isEmptyElement())
|
nuclear@0
|
255 return;
|
nuclear@0
|
256
|
nuclear@0
|
257 while( mReader->read())
|
nuclear@0
|
258 {
|
nuclear@0
|
259 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
260 {
|
nuclear@0
|
261 if( IsElement( "animation"))
|
nuclear@0
|
262 {
|
nuclear@0
|
263 // delegate the reading. Depending on the inner elements it will be a container or a anim channel
|
nuclear@0
|
264 ReadAnimation( &mAnims);
|
nuclear@0
|
265 } else
|
nuclear@0
|
266 {
|
nuclear@0
|
267 // ignore the rest
|
nuclear@0
|
268 SkipElement();
|
nuclear@0
|
269 }
|
nuclear@0
|
270 }
|
nuclear@0
|
271 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
nuclear@0
|
272 {
|
nuclear@0
|
273 if( strcmp( mReader->getNodeName(), "library_animations") != 0)
|
nuclear@0
|
274 ThrowException( "Expected end of <library_animations> element.");
|
nuclear@0
|
275
|
nuclear@0
|
276 break;
|
nuclear@0
|
277 }
|
nuclear@0
|
278 }
|
nuclear@0
|
279 }
|
nuclear@0
|
280
|
nuclear@0
|
281 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
282 // Reads an animation into the given parent structure
|
nuclear@0
|
283 void ColladaParser::ReadAnimation( Collada::Animation* pParent)
|
nuclear@0
|
284 {
|
nuclear@0
|
285 if( mReader->isEmptyElement())
|
nuclear@0
|
286 return;
|
nuclear@0
|
287
|
nuclear@0
|
288 // an <animation> element may be a container for grouping sub-elements or an animation channel
|
nuclear@0
|
289 // this is the channel collection by ID, in case it has channels
|
nuclear@0
|
290 typedef std::map<std::string, AnimationChannel> ChannelMap;
|
nuclear@0
|
291 ChannelMap channels;
|
nuclear@0
|
292 // this is the anim container in case we're a container
|
nuclear@0
|
293 Animation* anim = NULL;
|
nuclear@0
|
294
|
nuclear@0
|
295 // optional name given as an attribute
|
nuclear@0
|
296 std::string animName;
|
nuclear@0
|
297 int indexName = TestAttribute( "name");
|
nuclear@0
|
298 int indexID = TestAttribute( "id");
|
nuclear@0
|
299 if( indexName >= 0)
|
nuclear@0
|
300 animName = mReader->getAttributeValue( indexName);
|
nuclear@0
|
301 else if( indexID >= 0)
|
nuclear@0
|
302 animName = mReader->getAttributeValue( indexID);
|
nuclear@0
|
303 else
|
nuclear@0
|
304 animName = "animation";
|
nuclear@0
|
305
|
nuclear@0
|
306 while( mReader->read())
|
nuclear@0
|
307 {
|
nuclear@0
|
308 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
309 {
|
nuclear@0
|
310 // we have subanimations
|
nuclear@0
|
311 if( IsElement( "animation"))
|
nuclear@0
|
312 {
|
nuclear@0
|
313 // create container from our element
|
nuclear@0
|
314 if( !anim)
|
nuclear@0
|
315 {
|
nuclear@0
|
316 anim = new Animation;
|
nuclear@0
|
317 anim->mName = animName;
|
nuclear@0
|
318 pParent->mSubAnims.push_back( anim);
|
nuclear@0
|
319 }
|
nuclear@0
|
320
|
nuclear@0
|
321 // recurse into the subelement
|
nuclear@0
|
322 ReadAnimation( anim);
|
nuclear@0
|
323 }
|
nuclear@0
|
324 else if( IsElement( "source"))
|
nuclear@0
|
325 {
|
nuclear@0
|
326 // possible animation data - we'll never know. Better store it
|
nuclear@0
|
327 ReadSource();
|
nuclear@0
|
328 }
|
nuclear@0
|
329 else if( IsElement( "sampler"))
|
nuclear@0
|
330 {
|
nuclear@0
|
331 // read the ID to assign the corresponding collada channel afterwards.
|
nuclear@0
|
332 int indexID = GetAttribute( "id");
|
nuclear@0
|
333 std::string id = mReader->getAttributeValue( indexID);
|
nuclear@0
|
334 ChannelMap::iterator newChannel = channels.insert( std::make_pair( id, AnimationChannel())).first;
|
nuclear@0
|
335
|
nuclear@0
|
336 // have it read into a channel
|
nuclear@0
|
337 ReadAnimationSampler( newChannel->second);
|
nuclear@0
|
338 }
|
nuclear@0
|
339 else if( IsElement( "channel"))
|
nuclear@0
|
340 {
|
nuclear@0
|
341 // the binding element whose whole purpose is to provide the target to animate
|
nuclear@0
|
342 // Thanks, Collada! A directly posted information would have been too simple, I guess.
|
nuclear@0
|
343 // Better add another indirection to that! Can't have enough of those.
|
nuclear@0
|
344 int indexTarget = GetAttribute( "target");
|
nuclear@0
|
345 int indexSource = GetAttribute( "source");
|
nuclear@0
|
346 const char* sourceId = mReader->getAttributeValue( indexSource);
|
nuclear@0
|
347 if( sourceId[0] == '#')
|
nuclear@0
|
348 sourceId++;
|
nuclear@0
|
349 ChannelMap::iterator cit = channels.find( sourceId);
|
nuclear@0
|
350 if( cit != channels.end())
|
nuclear@0
|
351 cit->second.mTarget = mReader->getAttributeValue( indexTarget);
|
nuclear@0
|
352
|
nuclear@0
|
353 if( !mReader->isEmptyElement())
|
nuclear@0
|
354 SkipElement();
|
nuclear@0
|
355 }
|
nuclear@0
|
356 else
|
nuclear@0
|
357 {
|
nuclear@0
|
358 // ignore the rest
|
nuclear@0
|
359 SkipElement();
|
nuclear@0
|
360 }
|
nuclear@0
|
361 }
|
nuclear@0
|
362 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
nuclear@0
|
363 {
|
nuclear@0
|
364 if( strcmp( mReader->getNodeName(), "animation") != 0)
|
nuclear@0
|
365 ThrowException( "Expected end of <animation> element.");
|
nuclear@0
|
366
|
nuclear@0
|
367 break;
|
nuclear@0
|
368 }
|
nuclear@0
|
369 }
|
nuclear@0
|
370
|
nuclear@0
|
371 // it turned out to have channels - add them
|
nuclear@0
|
372 if( !channels.empty())
|
nuclear@0
|
373 {
|
nuclear@0
|
374 // special filtering for stupid exporters packing each channel into a separate animation
|
nuclear@0
|
375 if( channels.size() == 1)
|
nuclear@0
|
376 {
|
nuclear@0
|
377 pParent->mChannels.push_back( channels.begin()->second);
|
nuclear@0
|
378 } else
|
nuclear@0
|
379 {
|
nuclear@0
|
380 // else create the animation, if not done yet, and store the channels
|
nuclear@0
|
381 if( !anim)
|
nuclear@0
|
382 {
|
nuclear@0
|
383 anim = new Animation;
|
nuclear@0
|
384 anim->mName = animName;
|
nuclear@0
|
385 pParent->mSubAnims.push_back( anim);
|
nuclear@0
|
386 }
|
nuclear@0
|
387 for( ChannelMap::const_iterator it = channels.begin(); it != channels.end(); ++it)
|
nuclear@0
|
388 anim->mChannels.push_back( it->second);
|
nuclear@0
|
389 }
|
nuclear@0
|
390 }
|
nuclear@0
|
391 }
|
nuclear@0
|
392
|
nuclear@0
|
393 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
394 // Reads an animation sampler into the given anim channel
|
nuclear@0
|
395 void ColladaParser::ReadAnimationSampler( Collada::AnimationChannel& pChannel)
|
nuclear@0
|
396 {
|
nuclear@0
|
397 while( mReader->read())
|
nuclear@0
|
398 {
|
nuclear@0
|
399 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
400 {
|
nuclear@0
|
401 if( IsElement( "input"))
|
nuclear@0
|
402 {
|
nuclear@0
|
403 int indexSemantic = GetAttribute( "semantic");
|
nuclear@0
|
404 const char* semantic = mReader->getAttributeValue( indexSemantic);
|
nuclear@0
|
405 int indexSource = GetAttribute( "source");
|
nuclear@0
|
406 const char* source = mReader->getAttributeValue( indexSource);
|
nuclear@0
|
407 if( source[0] != '#')
|
nuclear@0
|
408 ThrowException( "Unsupported URL format");
|
nuclear@0
|
409 source++;
|
nuclear@0
|
410
|
nuclear@0
|
411 if( strcmp( semantic, "INPUT") == 0)
|
nuclear@0
|
412 pChannel.mSourceTimes = source;
|
nuclear@0
|
413 else if( strcmp( semantic, "OUTPUT") == 0)
|
nuclear@0
|
414 pChannel.mSourceValues = source;
|
nuclear@0
|
415
|
nuclear@0
|
416 if( !mReader->isEmptyElement())
|
nuclear@0
|
417 SkipElement();
|
nuclear@0
|
418 }
|
nuclear@0
|
419 else
|
nuclear@0
|
420 {
|
nuclear@0
|
421 // ignore the rest
|
nuclear@0
|
422 SkipElement();
|
nuclear@0
|
423 }
|
nuclear@0
|
424 }
|
nuclear@0
|
425 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
nuclear@0
|
426 {
|
nuclear@0
|
427 if( strcmp( mReader->getNodeName(), "sampler") != 0)
|
nuclear@0
|
428 ThrowException( "Expected end of <sampler> element.");
|
nuclear@0
|
429
|
nuclear@0
|
430 break;
|
nuclear@0
|
431 }
|
nuclear@0
|
432 }
|
nuclear@0
|
433 }
|
nuclear@0
|
434
|
nuclear@0
|
435 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
436 // Reads the skeleton controller library
|
nuclear@0
|
437 void ColladaParser::ReadControllerLibrary()
|
nuclear@0
|
438 {
|
nuclear@0
|
439 if (mReader->isEmptyElement())
|
nuclear@0
|
440 return;
|
nuclear@0
|
441
|
nuclear@0
|
442 while( mReader->read())
|
nuclear@0
|
443 {
|
nuclear@0
|
444 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
445 {
|
nuclear@0
|
446 if( IsElement( "controller"))
|
nuclear@0
|
447 {
|
nuclear@0
|
448 // read ID. Ask the spec if it's neccessary or optional... you might be surprised.
|
nuclear@0
|
449 int attrID = GetAttribute( "id");
|
nuclear@0
|
450 std::string id = mReader->getAttributeValue( attrID);
|
nuclear@0
|
451
|
nuclear@0
|
452 // create an entry and store it in the library under its ID
|
nuclear@0
|
453 mControllerLibrary[id] = Controller();
|
nuclear@0
|
454
|
nuclear@0
|
455 // read on from there
|
nuclear@0
|
456 ReadController( mControllerLibrary[id]);
|
nuclear@0
|
457 } else
|
nuclear@0
|
458 {
|
nuclear@0
|
459 // ignore the rest
|
nuclear@0
|
460 SkipElement();
|
nuclear@0
|
461 }
|
nuclear@0
|
462 }
|
nuclear@0
|
463 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
nuclear@0
|
464 {
|
nuclear@0
|
465 if( strcmp( mReader->getNodeName(), "library_controllers") != 0)
|
nuclear@0
|
466 ThrowException( "Expected end of <library_controllers> element.");
|
nuclear@0
|
467
|
nuclear@0
|
468 break;
|
nuclear@0
|
469 }
|
nuclear@0
|
470 }
|
nuclear@0
|
471 }
|
nuclear@0
|
472
|
nuclear@0
|
473 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
474 // Reads a controller into the given mesh structure
|
nuclear@0
|
475 void ColladaParser::ReadController( Collada::Controller& pController)
|
nuclear@0
|
476 {
|
nuclear@0
|
477 while( mReader->read())
|
nuclear@0
|
478 {
|
nuclear@0
|
479 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
480 {
|
nuclear@0
|
481 // two types of controllers: "skin" and "morph". Only the first one is relevant, we skip the other
|
nuclear@0
|
482 if( IsElement( "morph"))
|
nuclear@0
|
483 {
|
nuclear@0
|
484 // should skip everything inside, so there's no danger of catching elements inbetween
|
nuclear@0
|
485 SkipElement();
|
nuclear@0
|
486 }
|
nuclear@0
|
487 else if( IsElement( "skin"))
|
nuclear@0
|
488 {
|
nuclear@0
|
489 // read the mesh it refers to. According to the spec this could also be another
|
nuclear@0
|
490 // controller, but I refuse to implement every single idea they've come up with
|
nuclear@0
|
491 int sourceIndex = GetAttribute( "source");
|
nuclear@0
|
492 pController.mMeshId = mReader->getAttributeValue( sourceIndex) + 1;
|
nuclear@0
|
493 }
|
nuclear@0
|
494 else if( IsElement( "bind_shape_matrix"))
|
nuclear@0
|
495 {
|
nuclear@0
|
496 // content is 16 floats to define a matrix... it seems to be important for some models
|
nuclear@0
|
497 const char* content = GetTextContent();
|
nuclear@0
|
498
|
nuclear@0
|
499 // read the 16 floats
|
nuclear@0
|
500 for( unsigned int a = 0; a < 16; a++)
|
nuclear@0
|
501 {
|
nuclear@0
|
502 // read a number
|
nuclear@0
|
503 content = fast_atoreal_move<float>( content, pController.mBindShapeMatrix[a]);
|
nuclear@0
|
504 // skip whitespace after it
|
nuclear@0
|
505 SkipSpacesAndLineEnd( &content);
|
nuclear@0
|
506 }
|
nuclear@0
|
507
|
nuclear@0
|
508 TestClosing( "bind_shape_matrix");
|
nuclear@0
|
509 }
|
nuclear@0
|
510 else if( IsElement( "source"))
|
nuclear@0
|
511 {
|
nuclear@0
|
512 // data array - we have specialists to handle this
|
nuclear@0
|
513 ReadSource();
|
nuclear@0
|
514 }
|
nuclear@0
|
515 else if( IsElement( "joints"))
|
nuclear@0
|
516 {
|
nuclear@0
|
517 ReadControllerJoints( pController);
|
nuclear@0
|
518 }
|
nuclear@0
|
519 else if( IsElement( "vertex_weights"))
|
nuclear@0
|
520 {
|
nuclear@0
|
521 ReadControllerWeights( pController);
|
nuclear@0
|
522 }
|
nuclear@0
|
523 else
|
nuclear@0
|
524 {
|
nuclear@0
|
525 // ignore the rest
|
nuclear@0
|
526 SkipElement();
|
nuclear@0
|
527 }
|
nuclear@0
|
528 }
|
nuclear@0
|
529 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
nuclear@0
|
530 {
|
nuclear@0
|
531 if( strcmp( mReader->getNodeName(), "controller") == 0)
|
nuclear@0
|
532 break;
|
nuclear@0
|
533 else if( strcmp( mReader->getNodeName(), "skin") != 0)
|
nuclear@0
|
534 ThrowException( "Expected end of <controller> element.");
|
nuclear@0
|
535 }
|
nuclear@0
|
536 }
|
nuclear@0
|
537 }
|
nuclear@0
|
538
|
nuclear@0
|
539 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
540 // Reads the joint definitions for the given controller
|
nuclear@0
|
541 void ColladaParser::ReadControllerJoints( Collada::Controller& pController)
|
nuclear@0
|
542 {
|
nuclear@0
|
543 while( mReader->read())
|
nuclear@0
|
544 {
|
nuclear@0
|
545 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
546 {
|
nuclear@0
|
547 // Input channels for joint data. Two possible semantics: "JOINT" and "INV_BIND_MATRIX"
|
nuclear@0
|
548 if( IsElement( "input"))
|
nuclear@0
|
549 {
|
nuclear@0
|
550 int indexSemantic = GetAttribute( "semantic");
|
nuclear@0
|
551 const char* attrSemantic = mReader->getAttributeValue( indexSemantic);
|
nuclear@0
|
552 int indexSource = GetAttribute( "source");
|
nuclear@0
|
553 const char* attrSource = mReader->getAttributeValue( indexSource);
|
nuclear@0
|
554
|
nuclear@0
|
555 // local URLS always start with a '#'. We don't support global URLs
|
nuclear@0
|
556 if( attrSource[0] != '#')
|
nuclear@0
|
557 ThrowException( boost::str( boost::format( "Unsupported URL format in \"%s\" in source attribute of <joints> data <input> element") % attrSource));
|
nuclear@0
|
558 attrSource++;
|
nuclear@0
|
559
|
nuclear@0
|
560 // parse source URL to corresponding source
|
nuclear@0
|
561 if( strcmp( attrSemantic, "JOINT") == 0)
|
nuclear@0
|
562 pController.mJointNameSource = attrSource;
|
nuclear@0
|
563 else if( strcmp( attrSemantic, "INV_BIND_MATRIX") == 0)
|
nuclear@0
|
564 pController.mJointOffsetMatrixSource = attrSource;
|
nuclear@0
|
565 else
|
nuclear@0
|
566 ThrowException( boost::str( boost::format( "Unknown semantic \"%s\" in <joints> data <input> element") % attrSemantic));
|
nuclear@0
|
567
|
nuclear@0
|
568 // skip inner data, if present
|
nuclear@0
|
569 if( !mReader->isEmptyElement())
|
nuclear@0
|
570 SkipElement();
|
nuclear@0
|
571 }
|
nuclear@0
|
572 else
|
nuclear@0
|
573 {
|
nuclear@0
|
574 // ignore the rest
|
nuclear@0
|
575 SkipElement();
|
nuclear@0
|
576 }
|
nuclear@0
|
577 }
|
nuclear@0
|
578 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
nuclear@0
|
579 {
|
nuclear@0
|
580 if( strcmp( mReader->getNodeName(), "joints") != 0)
|
nuclear@0
|
581 ThrowException( "Expected end of <joints> element.");
|
nuclear@0
|
582
|
nuclear@0
|
583 break;
|
nuclear@0
|
584 }
|
nuclear@0
|
585 }
|
nuclear@0
|
586 }
|
nuclear@0
|
587
|
nuclear@0
|
588 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
589 // Reads the joint weights for the given controller
|
nuclear@0
|
590 void ColladaParser::ReadControllerWeights( Collada::Controller& pController)
|
nuclear@0
|
591 {
|
nuclear@0
|
592 // read vertex count from attributes and resize the array accordingly
|
nuclear@0
|
593 int indexCount = GetAttribute( "count");
|
nuclear@0
|
594 size_t vertexCount = (size_t) mReader->getAttributeValueAsInt( indexCount);
|
nuclear@0
|
595 pController.mWeightCounts.resize( vertexCount);
|
nuclear@0
|
596
|
nuclear@0
|
597 while( mReader->read())
|
nuclear@0
|
598 {
|
nuclear@0
|
599 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
600 {
|
nuclear@0
|
601 // Input channels for weight data. Two possible semantics: "JOINT" and "WEIGHT"
|
nuclear@0
|
602 if( IsElement( "input") && vertexCount > 0 )
|
nuclear@0
|
603 {
|
nuclear@0
|
604 InputChannel channel;
|
nuclear@0
|
605
|
nuclear@0
|
606 int indexSemantic = GetAttribute( "semantic");
|
nuclear@0
|
607 const char* attrSemantic = mReader->getAttributeValue( indexSemantic);
|
nuclear@0
|
608 int indexSource = GetAttribute( "source");
|
nuclear@0
|
609 const char* attrSource = mReader->getAttributeValue( indexSource);
|
nuclear@0
|
610 int indexOffset = TestAttribute( "offset");
|
nuclear@0
|
611 if( indexOffset >= 0)
|
nuclear@0
|
612 channel.mOffset = mReader->getAttributeValueAsInt( indexOffset);
|
nuclear@0
|
613
|
nuclear@0
|
614 // local URLS always start with a '#'. We don't support global URLs
|
nuclear@0
|
615 if( attrSource[0] != '#')
|
nuclear@0
|
616 ThrowException( boost::str( boost::format( "Unsupported URL format in \"%s\" in source attribute of <vertex_weights> data <input> element") % attrSource));
|
nuclear@0
|
617 channel.mAccessor = attrSource + 1;
|
nuclear@0
|
618
|
nuclear@0
|
619 // parse source URL to corresponding source
|
nuclear@0
|
620 if( strcmp( attrSemantic, "JOINT") == 0)
|
nuclear@0
|
621 pController.mWeightInputJoints = channel;
|
nuclear@0
|
622 else if( strcmp( attrSemantic, "WEIGHT") == 0)
|
nuclear@0
|
623 pController.mWeightInputWeights = channel;
|
nuclear@0
|
624 else
|
nuclear@0
|
625 ThrowException( boost::str( boost::format( "Unknown semantic \"%s\" in <vertex_weights> data <input> element") % attrSemantic));
|
nuclear@0
|
626
|
nuclear@0
|
627 // skip inner data, if present
|
nuclear@0
|
628 if( !mReader->isEmptyElement())
|
nuclear@0
|
629 SkipElement();
|
nuclear@0
|
630 }
|
nuclear@0
|
631 else if( IsElement( "vcount") && vertexCount > 0 )
|
nuclear@0
|
632 {
|
nuclear@0
|
633 // read weight count per vertex
|
nuclear@0
|
634 const char* text = GetTextContent();
|
nuclear@0
|
635 size_t numWeights = 0;
|
nuclear@0
|
636 for( std::vector<size_t>::iterator it = pController.mWeightCounts.begin(); it != pController.mWeightCounts.end(); ++it)
|
nuclear@0
|
637 {
|
nuclear@0
|
638 if( *text == 0)
|
nuclear@0
|
639 ThrowException( "Out of data while reading <vcount>");
|
nuclear@0
|
640
|
nuclear@0
|
641 *it = strtoul10( text, &text);
|
nuclear@0
|
642 numWeights += *it;
|
nuclear@0
|
643 SkipSpacesAndLineEnd( &text);
|
nuclear@0
|
644 }
|
nuclear@0
|
645
|
nuclear@0
|
646 TestClosing( "vcount");
|
nuclear@0
|
647
|
nuclear@0
|
648 // reserve weight count
|
nuclear@0
|
649 pController.mWeights.resize( numWeights);
|
nuclear@0
|
650 }
|
nuclear@0
|
651 else if( IsElement( "v") && vertexCount > 0 )
|
nuclear@0
|
652 {
|
nuclear@0
|
653 // read JointIndex - WeightIndex pairs
|
nuclear@0
|
654 const char* text = GetTextContent();
|
nuclear@0
|
655
|
nuclear@0
|
656 for( std::vector< std::pair<size_t, size_t> >::iterator it = pController.mWeights.begin(); it != pController.mWeights.end(); ++it)
|
nuclear@0
|
657 {
|
nuclear@0
|
658 if( *text == 0)
|
nuclear@0
|
659 ThrowException( "Out of data while reading <vertex_weights>");
|
nuclear@0
|
660 it->first = strtoul10( text, &text);
|
nuclear@0
|
661 SkipSpacesAndLineEnd( &text);
|
nuclear@0
|
662 if( *text == 0)
|
nuclear@0
|
663 ThrowException( "Out of data while reading <vertex_weights>");
|
nuclear@0
|
664 it->second = strtoul10( text, &text);
|
nuclear@0
|
665 SkipSpacesAndLineEnd( &text);
|
nuclear@0
|
666 }
|
nuclear@0
|
667
|
nuclear@0
|
668 TestClosing( "v");
|
nuclear@0
|
669 }
|
nuclear@0
|
670 else
|
nuclear@0
|
671 {
|
nuclear@0
|
672 // ignore the rest
|
nuclear@0
|
673 SkipElement();
|
nuclear@0
|
674 }
|
nuclear@0
|
675 }
|
nuclear@0
|
676 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
nuclear@0
|
677 {
|
nuclear@0
|
678 if( strcmp( mReader->getNodeName(), "vertex_weights") != 0)
|
nuclear@0
|
679 ThrowException( "Expected end of <vertex_weights> element.");
|
nuclear@0
|
680
|
nuclear@0
|
681 break;
|
nuclear@0
|
682 }
|
nuclear@0
|
683 }
|
nuclear@0
|
684 }
|
nuclear@0
|
685
|
nuclear@0
|
686 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
687 // Reads the image library contents
|
nuclear@0
|
688 void ColladaParser::ReadImageLibrary()
|
nuclear@0
|
689 {
|
nuclear@0
|
690 if( mReader->isEmptyElement())
|
nuclear@0
|
691 return;
|
nuclear@0
|
692
|
nuclear@0
|
693 while( mReader->read())
|
nuclear@0
|
694 {
|
nuclear@0
|
695 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
|
nuclear@0
|
696 if( IsElement( "image"))
|
nuclear@0
|
697 {
|
nuclear@0
|
698 // read ID. Another entry which is "optional" by design but obligatory in reality
|
nuclear@0
|
699 int attrID = GetAttribute( "id");
|
nuclear@0
|
700 std::string id = mReader->getAttributeValue( attrID);
|
nuclear@0
|
701
|
nuclear@0
|
702 // create an entry and store it in the library under its ID
|
nuclear@0
|
703 mImageLibrary[id] = Image();
|
nuclear@0
|
704
|
nuclear@0
|
705 // read on from there
|
nuclear@0
|
706 ReadImage( mImageLibrary[id]);
|
nuclear@0
|
707 } else
|
nuclear@0
|
708 {
|
nuclear@0
|
709 // ignore the rest
|
nuclear@0
|
710 SkipElement();
|
nuclear@0
|
711 }
|
nuclear@0
|
712 }
|
nuclear@0
|
713 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
|
nuclear@0
|
714 if( strcmp( mReader->getNodeName(), "library_images") != 0)
|
nuclear@0
|
715 ThrowException( "Expected end of <library_images> element.");
|
nuclear@0
|
716
|
nuclear@0
|
717 break;
|
nuclear@0
|
718 }
|
nuclear@0
|
719 }
|
nuclear@0
|
720 }
|
nuclear@0
|
721
|
nuclear@0
|
722 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
723 // Reads an image entry into the given image
|
nuclear@0
|
724 void ColladaParser::ReadImage( Collada::Image& pImage)
|
nuclear@0
|
725 {
|
nuclear@0
|
726 while( mReader->read())
|
nuclear@0
|
727 {
|
nuclear@0
|
728 if( mReader->getNodeType() == irr::io::EXN_ELEMENT){
|
nuclear@0
|
729 // Need to run different code paths here, depending on the Collada XSD version
|
nuclear@0
|
730 if (IsElement("image")) {
|
nuclear@0
|
731 SkipElement();
|
nuclear@0
|
732 }
|
nuclear@0
|
733 else if( IsElement( "init_from"))
|
nuclear@0
|
734 {
|
nuclear@0
|
735 if (mFormat == FV_1_4_n)
|
nuclear@0
|
736 {
|
nuclear@0
|
737 // FIX: C4D exporter writes empty <init_from/> tags
|
nuclear@0
|
738 if (!mReader->isEmptyElement()) {
|
nuclear@0
|
739 // element content is filename - hopefully
|
nuclear@0
|
740 const char* sz = TestTextContent();
|
nuclear@0
|
741 if (sz)pImage.mFileName = sz;
|
nuclear@0
|
742 TestClosing( "init_from");
|
nuclear@0
|
743 }
|
nuclear@0
|
744 if (!pImage.mFileName.length()) {
|
nuclear@0
|
745 pImage.mFileName = "unknown_texture";
|
nuclear@0
|
746 }
|
nuclear@0
|
747 }
|
nuclear@0
|
748 else if (mFormat == FV_1_5_n)
|
nuclear@0
|
749 {
|
nuclear@0
|
750 // make sure we skip over mip and array initializations, which
|
nuclear@0
|
751 // we don't support, but which could confuse the loader if
|
nuclear@0
|
752 // they're not skipped.
|
nuclear@0
|
753 int attrib = TestAttribute("array_index");
|
nuclear@0
|
754 if (attrib != -1 && mReader->getAttributeValueAsInt(attrib) > 0) {
|
nuclear@0
|
755 DefaultLogger::get()->warn("Collada: Ignoring texture array index");
|
nuclear@0
|
756 continue;
|
nuclear@0
|
757 }
|
nuclear@0
|
758
|
nuclear@0
|
759 attrib = TestAttribute("mip_index");
|
nuclear@0
|
760 if (attrib != -1 && mReader->getAttributeValueAsInt(attrib) > 0) {
|
nuclear@0
|
761 DefaultLogger::get()->warn("Collada: Ignoring MIP map layer");
|
nuclear@0
|
762 continue;
|
nuclear@0
|
763 }
|
nuclear@0
|
764
|
nuclear@0
|
765 // TODO: correctly jump over cube and volume maps?
|
nuclear@0
|
766 }
|
nuclear@0
|
767 }
|
nuclear@0
|
768 else if (mFormat == FV_1_5_n)
|
nuclear@0
|
769 {
|
nuclear@0
|
770 if( IsElement( "ref"))
|
nuclear@0
|
771 {
|
nuclear@0
|
772 // element content is filename - hopefully
|
nuclear@0
|
773 const char* sz = TestTextContent();
|
nuclear@0
|
774 if (sz)pImage.mFileName = sz;
|
nuclear@0
|
775 TestClosing( "ref");
|
nuclear@0
|
776 }
|
nuclear@0
|
777 else if( IsElement( "hex") && !pImage.mFileName.length())
|
nuclear@0
|
778 {
|
nuclear@0
|
779 // embedded image. get format
|
nuclear@0
|
780 const int attrib = TestAttribute("format");
|
nuclear@0
|
781 if (-1 == attrib)
|
nuclear@0
|
782 DefaultLogger::get()->warn("Collada: Unknown image file format");
|
nuclear@0
|
783 else pImage.mEmbeddedFormat = mReader->getAttributeValue(attrib);
|
nuclear@0
|
784
|
nuclear@0
|
785 const char* data = GetTextContent();
|
nuclear@0
|
786
|
nuclear@0
|
787 // hexadecimal-encoded binary octets. First of all, find the
|
nuclear@0
|
788 // required buffer size to reserve enough storage.
|
nuclear@0
|
789 const char* cur = data;
|
nuclear@0
|
790 while (!IsSpaceOrNewLine(*cur)) cur++;
|
nuclear@0
|
791
|
nuclear@0
|
792 const unsigned int size = (unsigned int)(cur-data) * 2;
|
nuclear@0
|
793 pImage.mImageData.resize(size);
|
nuclear@0
|
794 for (unsigned int i = 0; i < size;++i)
|
nuclear@0
|
795 pImage.mImageData[i] = HexOctetToDecimal(data+(i<<1));
|
nuclear@0
|
796
|
nuclear@0
|
797 TestClosing( "hex");
|
nuclear@0
|
798 }
|
nuclear@0
|
799 }
|
nuclear@0
|
800 else
|
nuclear@0
|
801 {
|
nuclear@0
|
802 // ignore the rest
|
nuclear@0
|
803 SkipElement();
|
nuclear@0
|
804 }
|
nuclear@0
|
805 }
|
nuclear@0
|
806 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
|
nuclear@0
|
807 if( strcmp( mReader->getNodeName(), "image") == 0)
|
nuclear@0
|
808 break;
|
nuclear@0
|
809 }
|
nuclear@0
|
810 }
|
nuclear@0
|
811 }
|
nuclear@0
|
812
|
nuclear@0
|
813 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
814 // Reads the material library
|
nuclear@0
|
815 void ColladaParser::ReadMaterialLibrary()
|
nuclear@0
|
816 {
|
nuclear@0
|
817 if( mReader->isEmptyElement())
|
nuclear@0
|
818 return;
|
nuclear@0
|
819
|
nuclear@0
|
820 while( mReader->read())
|
nuclear@0
|
821 {
|
nuclear@0
|
822 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
823 {
|
nuclear@0
|
824 if( IsElement( "material"))
|
nuclear@0
|
825 {
|
nuclear@0
|
826 // read ID. By now you propably know my opinion about this "specification"
|
nuclear@0
|
827 int attrID = GetAttribute( "id");
|
nuclear@0
|
828 std::string id = mReader->getAttributeValue( attrID);
|
nuclear@0
|
829
|
nuclear@0
|
830 // create an entry and store it in the library under its ID
|
nuclear@0
|
831 ReadMaterial(mMaterialLibrary[id] = Material());
|
nuclear@0
|
832 } else
|
nuclear@0
|
833 {
|
nuclear@0
|
834 // ignore the rest
|
nuclear@0
|
835 SkipElement();
|
nuclear@0
|
836 }
|
nuclear@0
|
837 }
|
nuclear@0
|
838 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
nuclear@0
|
839 {
|
nuclear@0
|
840 if( strcmp( mReader->getNodeName(), "library_materials") != 0)
|
nuclear@0
|
841 ThrowException( "Expected end of <library_materials> element.");
|
nuclear@0
|
842
|
nuclear@0
|
843 break;
|
nuclear@0
|
844 }
|
nuclear@0
|
845 }
|
nuclear@0
|
846 }
|
nuclear@0
|
847
|
nuclear@0
|
848 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
849 // Reads the light library
|
nuclear@0
|
850 void ColladaParser::ReadLightLibrary()
|
nuclear@0
|
851 {
|
nuclear@0
|
852 if( mReader->isEmptyElement())
|
nuclear@0
|
853 return;
|
nuclear@0
|
854
|
nuclear@0
|
855 while( mReader->read())
|
nuclear@0
|
856 {
|
nuclear@0
|
857 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
|
nuclear@0
|
858 if( IsElement( "light"))
|
nuclear@0
|
859 {
|
nuclear@0
|
860 // read ID. By now you propably know my opinion about this "specification"
|
nuclear@0
|
861 int attrID = GetAttribute( "id");
|
nuclear@0
|
862 std::string id = mReader->getAttributeValue( attrID);
|
nuclear@0
|
863
|
nuclear@0
|
864 // create an entry and store it in the library under its ID
|
nuclear@0
|
865 ReadLight(mLightLibrary[id] = Light());
|
nuclear@0
|
866
|
nuclear@0
|
867 } else
|
nuclear@0
|
868 {
|
nuclear@0
|
869 // ignore the rest
|
nuclear@0
|
870 SkipElement();
|
nuclear@0
|
871 }
|
nuclear@0
|
872 }
|
nuclear@0
|
873 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
|
nuclear@0
|
874 if( strcmp( mReader->getNodeName(), "library_lights") != 0)
|
nuclear@0
|
875 ThrowException( "Expected end of <library_lights> element.");
|
nuclear@0
|
876
|
nuclear@0
|
877 break;
|
nuclear@0
|
878 }
|
nuclear@0
|
879 }
|
nuclear@0
|
880 }
|
nuclear@0
|
881
|
nuclear@0
|
882 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
883 // Reads the camera library
|
nuclear@0
|
884 void ColladaParser::ReadCameraLibrary()
|
nuclear@0
|
885 {
|
nuclear@0
|
886 if( mReader->isEmptyElement())
|
nuclear@0
|
887 return;
|
nuclear@0
|
888
|
nuclear@0
|
889 while( mReader->read())
|
nuclear@0
|
890 {
|
nuclear@0
|
891 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
|
nuclear@0
|
892 if( IsElement( "camera"))
|
nuclear@0
|
893 {
|
nuclear@0
|
894 // read ID. By now you propably know my opinion about this "specification"
|
nuclear@0
|
895 int attrID = GetAttribute( "id");
|
nuclear@0
|
896 std::string id = mReader->getAttributeValue( attrID);
|
nuclear@0
|
897
|
nuclear@0
|
898 // create an entry and store it in the library under its ID
|
nuclear@0
|
899 Camera& cam = mCameraLibrary[id];
|
nuclear@0
|
900 attrID = TestAttribute( "name");
|
nuclear@0
|
901 if (attrID != -1)
|
nuclear@0
|
902 cam.mName = mReader->getAttributeValue( attrID);
|
nuclear@0
|
903
|
nuclear@0
|
904 ReadCamera(cam);
|
nuclear@0
|
905
|
nuclear@0
|
906 } else
|
nuclear@0
|
907 {
|
nuclear@0
|
908 // ignore the rest
|
nuclear@0
|
909 SkipElement();
|
nuclear@0
|
910 }
|
nuclear@0
|
911 }
|
nuclear@0
|
912 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
|
nuclear@0
|
913 if( strcmp( mReader->getNodeName(), "library_cameras") != 0)
|
nuclear@0
|
914 ThrowException( "Expected end of <library_cameras> element.");
|
nuclear@0
|
915
|
nuclear@0
|
916 break;
|
nuclear@0
|
917 }
|
nuclear@0
|
918 }
|
nuclear@0
|
919 }
|
nuclear@0
|
920
|
nuclear@0
|
921 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
922 // Reads a material entry into the given material
|
nuclear@0
|
923 void ColladaParser::ReadMaterial( Collada::Material& pMaterial)
|
nuclear@0
|
924 {
|
nuclear@0
|
925 while( mReader->read())
|
nuclear@0
|
926 {
|
nuclear@0
|
927 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
|
nuclear@0
|
928 if (IsElement("material")) {
|
nuclear@0
|
929 SkipElement();
|
nuclear@0
|
930 }
|
nuclear@0
|
931 else if( IsElement( "instance_effect"))
|
nuclear@0
|
932 {
|
nuclear@0
|
933 // referred effect by URL
|
nuclear@0
|
934 int attrUrl = GetAttribute( "url");
|
nuclear@0
|
935 const char* url = mReader->getAttributeValue( attrUrl);
|
nuclear@0
|
936 if( url[0] != '#')
|
nuclear@0
|
937 ThrowException( "Unknown reference format");
|
nuclear@0
|
938
|
nuclear@0
|
939 pMaterial.mEffect = url+1;
|
nuclear@0
|
940
|
nuclear@0
|
941 SkipElement();
|
nuclear@0
|
942 } else
|
nuclear@0
|
943 {
|
nuclear@0
|
944 // ignore the rest
|
nuclear@0
|
945 SkipElement();
|
nuclear@0
|
946 }
|
nuclear@0
|
947 }
|
nuclear@0
|
948 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
|
nuclear@0
|
949 if( strcmp( mReader->getNodeName(), "material") != 0)
|
nuclear@0
|
950 ThrowException( "Expected end of <material> element.");
|
nuclear@0
|
951
|
nuclear@0
|
952 break;
|
nuclear@0
|
953 }
|
nuclear@0
|
954 }
|
nuclear@0
|
955 }
|
nuclear@0
|
956
|
nuclear@0
|
957 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
958 // Reads a light entry into the given light
|
nuclear@0
|
959 void ColladaParser::ReadLight( Collada::Light& pLight)
|
nuclear@0
|
960 {
|
nuclear@0
|
961 while( mReader->read())
|
nuclear@0
|
962 {
|
nuclear@0
|
963 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
|
nuclear@0
|
964 if (IsElement("light")) {
|
nuclear@0
|
965 SkipElement();
|
nuclear@0
|
966 }
|
nuclear@0
|
967 else if (IsElement("spot")) {
|
nuclear@0
|
968 pLight.mType = aiLightSource_SPOT;
|
nuclear@0
|
969 }
|
nuclear@0
|
970 else if (IsElement("ambient")) {
|
nuclear@0
|
971 pLight.mType = aiLightSource_AMBIENT;
|
nuclear@0
|
972 }
|
nuclear@0
|
973 else if (IsElement("directional")) {
|
nuclear@0
|
974 pLight.mType = aiLightSource_DIRECTIONAL;
|
nuclear@0
|
975 }
|
nuclear@0
|
976 else if (IsElement("point")) {
|
nuclear@0
|
977 pLight.mType = aiLightSource_POINT;
|
nuclear@0
|
978 }
|
nuclear@0
|
979 else if (IsElement("color")) {
|
nuclear@0
|
980 // text content contains 3 floats
|
nuclear@0
|
981 const char* content = GetTextContent();
|
nuclear@0
|
982
|
nuclear@0
|
983 content = fast_atoreal_move<float>( content, (float&)pLight.mColor.r);
|
nuclear@0
|
984 SkipSpacesAndLineEnd( &content);
|
nuclear@0
|
985
|
nuclear@0
|
986 content = fast_atoreal_move<float>( content, (float&)pLight.mColor.g);
|
nuclear@0
|
987 SkipSpacesAndLineEnd( &content);
|
nuclear@0
|
988
|
nuclear@0
|
989 content = fast_atoreal_move<float>( content, (float&)pLight.mColor.b);
|
nuclear@0
|
990 SkipSpacesAndLineEnd( &content);
|
nuclear@0
|
991
|
nuclear@0
|
992 TestClosing( "color");
|
nuclear@0
|
993 }
|
nuclear@0
|
994 else if (IsElement("constant_attenuation")) {
|
nuclear@0
|
995 pLight.mAttConstant = ReadFloatFromTextContent();
|
nuclear@0
|
996 TestClosing("constant_attenuation");
|
nuclear@0
|
997 }
|
nuclear@0
|
998 else if (IsElement("linear_attenuation")) {
|
nuclear@0
|
999 pLight.mAttLinear = ReadFloatFromTextContent();
|
nuclear@0
|
1000 TestClosing("linear_attenuation");
|
nuclear@0
|
1001 }
|
nuclear@0
|
1002 else if (IsElement("quadratic_attenuation")) {
|
nuclear@0
|
1003 pLight.mAttQuadratic = ReadFloatFromTextContent();
|
nuclear@0
|
1004 TestClosing("quadratic_attenuation");
|
nuclear@0
|
1005 }
|
nuclear@0
|
1006 else if (IsElement("falloff_angle")) {
|
nuclear@0
|
1007 pLight.mFalloffAngle = ReadFloatFromTextContent();
|
nuclear@0
|
1008 TestClosing("falloff_angle");
|
nuclear@0
|
1009 }
|
nuclear@0
|
1010 else if (IsElement("falloff_exponent")) {
|
nuclear@0
|
1011 pLight.mFalloffExponent = ReadFloatFromTextContent();
|
nuclear@0
|
1012 TestClosing("falloff_exponent");
|
nuclear@0
|
1013 }
|
nuclear@0
|
1014 // FCOLLADA extensions
|
nuclear@0
|
1015 // -------------------------------------------------------
|
nuclear@0
|
1016 else if (IsElement("outer_cone")) {
|
nuclear@0
|
1017 pLight.mOuterAngle = ReadFloatFromTextContent();
|
nuclear@0
|
1018 TestClosing("outer_cone");
|
nuclear@0
|
1019 }
|
nuclear@0
|
1020 // ... and this one is even deprecated
|
nuclear@0
|
1021 else if (IsElement("penumbra_angle")) {
|
nuclear@0
|
1022 pLight.mPenumbraAngle = ReadFloatFromTextContent();
|
nuclear@0
|
1023 TestClosing("penumbra_angle");
|
nuclear@0
|
1024 }
|
nuclear@0
|
1025 else if (IsElement("intensity")) {
|
nuclear@0
|
1026 pLight.mIntensity = ReadFloatFromTextContent();
|
nuclear@0
|
1027 TestClosing("intensity");
|
nuclear@0
|
1028 }
|
nuclear@0
|
1029 else if (IsElement("falloff")) {
|
nuclear@0
|
1030 pLight.mOuterAngle = ReadFloatFromTextContent();
|
nuclear@0
|
1031 TestClosing("falloff");
|
nuclear@0
|
1032 }
|
nuclear@0
|
1033 else if (IsElement("hotspot_beam")) {
|
nuclear@0
|
1034 pLight.mFalloffAngle = ReadFloatFromTextContent();
|
nuclear@0
|
1035 TestClosing("hotspot_beam");
|
nuclear@0
|
1036 }
|
nuclear@0
|
1037 }
|
nuclear@0
|
1038 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
|
nuclear@0
|
1039 if( strcmp( mReader->getNodeName(), "light") == 0)
|
nuclear@0
|
1040 break;
|
nuclear@0
|
1041 }
|
nuclear@0
|
1042 }
|
nuclear@0
|
1043 }
|
nuclear@0
|
1044
|
nuclear@0
|
1045 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1046 // Reads a camera entry into the given light
|
nuclear@0
|
1047 void ColladaParser::ReadCamera( Collada::Camera& pCamera)
|
nuclear@0
|
1048 {
|
nuclear@0
|
1049 while( mReader->read())
|
nuclear@0
|
1050 {
|
nuclear@0
|
1051 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
|
nuclear@0
|
1052 if (IsElement("camera")) {
|
nuclear@0
|
1053 SkipElement();
|
nuclear@0
|
1054 }
|
nuclear@0
|
1055 else if (IsElement("orthographic")) {
|
nuclear@0
|
1056 pCamera.mOrtho = true;
|
nuclear@0
|
1057 }
|
nuclear@0
|
1058 else if (IsElement("xfov") || IsElement("xmag")) {
|
nuclear@0
|
1059 pCamera.mHorFov = ReadFloatFromTextContent();
|
nuclear@0
|
1060 TestClosing((pCamera.mOrtho ? "xmag" : "xfov"));
|
nuclear@0
|
1061 }
|
nuclear@0
|
1062 else if (IsElement("yfov") || IsElement("ymag")) {
|
nuclear@0
|
1063 pCamera.mVerFov = ReadFloatFromTextContent();
|
nuclear@0
|
1064 TestClosing((pCamera.mOrtho ? "ymag" : "yfov"));
|
nuclear@0
|
1065 }
|
nuclear@0
|
1066 else if (IsElement("aspect_ratio")) {
|
nuclear@0
|
1067 pCamera.mAspect = ReadFloatFromTextContent();
|
nuclear@0
|
1068 TestClosing("aspect_ratio");
|
nuclear@0
|
1069 }
|
nuclear@0
|
1070 else if (IsElement("znear")) {
|
nuclear@0
|
1071 pCamera.mZNear = ReadFloatFromTextContent();
|
nuclear@0
|
1072 TestClosing("znear");
|
nuclear@0
|
1073 }
|
nuclear@0
|
1074 else if (IsElement("zfar")) {
|
nuclear@0
|
1075 pCamera.mZFar = ReadFloatFromTextContent();
|
nuclear@0
|
1076 TestClosing("zfar");
|
nuclear@0
|
1077 }
|
nuclear@0
|
1078 }
|
nuclear@0
|
1079 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
|
nuclear@0
|
1080 if( strcmp( mReader->getNodeName(), "camera") == 0)
|
nuclear@0
|
1081 break;
|
nuclear@0
|
1082 }
|
nuclear@0
|
1083 }
|
nuclear@0
|
1084 }
|
nuclear@0
|
1085
|
nuclear@0
|
1086 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1087 // Reads the effect library
|
nuclear@0
|
1088 void ColladaParser::ReadEffectLibrary()
|
nuclear@0
|
1089 {
|
nuclear@0
|
1090 if (mReader->isEmptyElement()) {
|
nuclear@0
|
1091 return;
|
nuclear@0
|
1092 }
|
nuclear@0
|
1093
|
nuclear@0
|
1094 while( mReader->read())
|
nuclear@0
|
1095 {
|
nuclear@0
|
1096 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
|
nuclear@0
|
1097 if( IsElement( "effect"))
|
nuclear@0
|
1098 {
|
nuclear@0
|
1099 // read ID. Do I have to repeat my ranting about "optional" attributes?
|
nuclear@0
|
1100 int attrID = GetAttribute( "id");
|
nuclear@0
|
1101 std::string id = mReader->getAttributeValue( attrID);
|
nuclear@0
|
1102
|
nuclear@0
|
1103 // create an entry and store it in the library under its ID
|
nuclear@0
|
1104 mEffectLibrary[id] = Effect();
|
nuclear@0
|
1105 // read on from there
|
nuclear@0
|
1106 ReadEffect( mEffectLibrary[id]);
|
nuclear@0
|
1107 } else
|
nuclear@0
|
1108 {
|
nuclear@0
|
1109 // ignore the rest
|
nuclear@0
|
1110 SkipElement();
|
nuclear@0
|
1111 }
|
nuclear@0
|
1112 }
|
nuclear@0
|
1113 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
|
nuclear@0
|
1114 if( strcmp( mReader->getNodeName(), "library_effects") != 0)
|
nuclear@0
|
1115 ThrowException( "Expected end of <library_effects> element.");
|
nuclear@0
|
1116
|
nuclear@0
|
1117 break;
|
nuclear@0
|
1118 }
|
nuclear@0
|
1119 }
|
nuclear@0
|
1120 }
|
nuclear@0
|
1121
|
nuclear@0
|
1122 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1123 // Reads an effect entry into the given effect
|
nuclear@0
|
1124 void ColladaParser::ReadEffect( Collada::Effect& pEffect)
|
nuclear@0
|
1125 {
|
nuclear@0
|
1126 // for the moment we don't support any other type of effect.
|
nuclear@0
|
1127 while( mReader->read())
|
nuclear@0
|
1128 {
|
nuclear@0
|
1129 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
1130 {
|
nuclear@0
|
1131 if( IsElement( "profile_COMMON"))
|
nuclear@0
|
1132 ReadEffectProfileCommon( pEffect);
|
nuclear@0
|
1133 else
|
nuclear@0
|
1134 SkipElement();
|
nuclear@0
|
1135 }
|
nuclear@0
|
1136 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
nuclear@0
|
1137 {
|
nuclear@0
|
1138 if( strcmp( mReader->getNodeName(), "effect") != 0)
|
nuclear@0
|
1139 ThrowException( "Expected end of <effect> element.");
|
nuclear@0
|
1140
|
nuclear@0
|
1141 break;
|
nuclear@0
|
1142 }
|
nuclear@0
|
1143 }
|
nuclear@0
|
1144 }
|
nuclear@0
|
1145
|
nuclear@0
|
1146 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1147 // Reads an COMMON effect profile
|
nuclear@0
|
1148 void ColladaParser::ReadEffectProfileCommon( Collada::Effect& pEffect)
|
nuclear@0
|
1149 {
|
nuclear@0
|
1150 while( mReader->read())
|
nuclear@0
|
1151 {
|
nuclear@0
|
1152 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
1153 {
|
nuclear@0
|
1154 if( IsElement( "newparam")) {
|
nuclear@0
|
1155 // save ID
|
nuclear@0
|
1156 int attrSID = GetAttribute( "sid");
|
nuclear@0
|
1157 std::string sid = mReader->getAttributeValue( attrSID);
|
nuclear@0
|
1158 pEffect.mParams[sid] = EffectParam();
|
nuclear@0
|
1159 ReadEffectParam( pEffect.mParams[sid]);
|
nuclear@0
|
1160 }
|
nuclear@0
|
1161 else if( IsElement( "technique") || IsElement( "extra"))
|
nuclear@0
|
1162 {
|
nuclear@0
|
1163 // just syntactic sugar
|
nuclear@0
|
1164 }
|
nuclear@0
|
1165
|
nuclear@0
|
1166 /* Shading modes */
|
nuclear@0
|
1167 else if( IsElement( "phong"))
|
nuclear@0
|
1168 pEffect.mShadeType = Shade_Phong;
|
nuclear@0
|
1169 else if( IsElement( "constant"))
|
nuclear@0
|
1170 pEffect.mShadeType = Shade_Constant;
|
nuclear@0
|
1171 else if( IsElement( "lambert"))
|
nuclear@0
|
1172 pEffect.mShadeType = Shade_Lambert;
|
nuclear@0
|
1173 else if( IsElement( "blinn"))
|
nuclear@0
|
1174 pEffect.mShadeType = Shade_Blinn;
|
nuclear@0
|
1175
|
nuclear@0
|
1176 /* Color + texture properties */
|
nuclear@0
|
1177 else if( IsElement( "emission"))
|
nuclear@0
|
1178 ReadEffectColor( pEffect.mEmissive, pEffect.mTexEmissive);
|
nuclear@0
|
1179 else if( IsElement( "ambient"))
|
nuclear@0
|
1180 ReadEffectColor( pEffect.mAmbient, pEffect.mTexAmbient);
|
nuclear@0
|
1181 else if( IsElement( "diffuse"))
|
nuclear@0
|
1182 ReadEffectColor( pEffect.mDiffuse, pEffect.mTexDiffuse);
|
nuclear@0
|
1183 else if( IsElement( "specular"))
|
nuclear@0
|
1184 ReadEffectColor( pEffect.mSpecular, pEffect.mTexSpecular);
|
nuclear@0
|
1185 else if( IsElement( "reflective")) {
|
nuclear@0
|
1186 ReadEffectColor( pEffect.mReflective, pEffect.mTexReflective);
|
nuclear@0
|
1187 }
|
nuclear@0
|
1188 else if( IsElement( "transparent")) {
|
nuclear@0
|
1189 ReadEffectColor( pEffect.mTransparent,pEffect.mTexTransparent);
|
nuclear@0
|
1190 }
|
nuclear@0
|
1191 else if( IsElement( "shininess"))
|
nuclear@0
|
1192 ReadEffectFloat( pEffect.mShininess);
|
nuclear@0
|
1193 else if( IsElement( "reflectivity"))
|
nuclear@0
|
1194 ReadEffectFloat( pEffect.mReflectivity);
|
nuclear@0
|
1195
|
nuclear@0
|
1196 /* Single scalar properties */
|
nuclear@0
|
1197 else if( IsElement( "transparency"))
|
nuclear@0
|
1198 ReadEffectFloat( pEffect.mTransparency);
|
nuclear@0
|
1199 else if( IsElement( "index_of_refraction"))
|
nuclear@0
|
1200 ReadEffectFloat( pEffect.mRefractIndex);
|
nuclear@0
|
1201
|
nuclear@0
|
1202 // GOOGLEEARTH/OKINO extensions
|
nuclear@0
|
1203 // -------------------------------------------------------
|
nuclear@0
|
1204 else if( IsElement( "double_sided"))
|
nuclear@0
|
1205 pEffect.mDoubleSided = ReadBoolFromTextContent();
|
nuclear@0
|
1206
|
nuclear@0
|
1207 // FCOLLADA extensions
|
nuclear@0
|
1208 // -------------------------------------------------------
|
nuclear@0
|
1209 else if( IsElement( "bump")) {
|
nuclear@0
|
1210 aiColor4D dummy;
|
nuclear@0
|
1211 ReadEffectColor( dummy,pEffect.mTexBump);
|
nuclear@0
|
1212 }
|
nuclear@0
|
1213
|
nuclear@0
|
1214 // MAX3D extensions
|
nuclear@0
|
1215 // -------------------------------------------------------
|
nuclear@0
|
1216 else if( IsElement( "wireframe")) {
|
nuclear@0
|
1217 pEffect.mWireframe = ReadBoolFromTextContent();
|
nuclear@0
|
1218 TestClosing( "wireframe");
|
nuclear@0
|
1219 }
|
nuclear@0
|
1220 else if( IsElement( "faceted")) {
|
nuclear@0
|
1221 pEffect.mFaceted = ReadBoolFromTextContent();
|
nuclear@0
|
1222 TestClosing( "faceted");
|
nuclear@0
|
1223 }
|
nuclear@0
|
1224 else
|
nuclear@0
|
1225 {
|
nuclear@0
|
1226 // ignore the rest
|
nuclear@0
|
1227 SkipElement();
|
nuclear@0
|
1228 }
|
nuclear@0
|
1229 }
|
nuclear@0
|
1230 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
|
nuclear@0
|
1231 if( strcmp( mReader->getNodeName(), "profile_COMMON") == 0)
|
nuclear@0
|
1232 {
|
nuclear@0
|
1233 break;
|
nuclear@0
|
1234 }
|
nuclear@0
|
1235 }
|
nuclear@0
|
1236 }
|
nuclear@0
|
1237 }
|
nuclear@0
|
1238
|
nuclear@0
|
1239 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1240 // Read texture wrapping + UV transform settings from a profile==Maya chunk
|
nuclear@0
|
1241 void ColladaParser::ReadSamplerProperties( Sampler& out )
|
nuclear@0
|
1242 {
|
nuclear@0
|
1243 if (mReader->isEmptyElement()) {
|
nuclear@0
|
1244 return;
|
nuclear@0
|
1245 }
|
nuclear@0
|
1246
|
nuclear@0
|
1247 while( mReader->read())
|
nuclear@0
|
1248 {
|
nuclear@0
|
1249 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
|
nuclear@0
|
1250
|
nuclear@0
|
1251 // MAYA extensions
|
nuclear@0
|
1252 // -------------------------------------------------------
|
nuclear@0
|
1253 if( IsElement( "wrapU")) {
|
nuclear@0
|
1254 out.mWrapU = ReadBoolFromTextContent();
|
nuclear@0
|
1255 TestClosing( "wrapU");
|
nuclear@0
|
1256 }
|
nuclear@0
|
1257 else if( IsElement( "wrapV")) {
|
nuclear@0
|
1258 out.mWrapV = ReadBoolFromTextContent();
|
nuclear@0
|
1259 TestClosing( "wrapV");
|
nuclear@0
|
1260 }
|
nuclear@0
|
1261 else if( IsElement( "mirrorU")) {
|
nuclear@0
|
1262 out.mMirrorU = ReadBoolFromTextContent();
|
nuclear@0
|
1263 TestClosing( "mirrorU");
|
nuclear@0
|
1264 }
|
nuclear@0
|
1265 else if( IsElement( "mirrorV")) {
|
nuclear@0
|
1266 out.mMirrorV = ReadBoolFromTextContent();
|
nuclear@0
|
1267 TestClosing( "mirrorV");
|
nuclear@0
|
1268 }
|
nuclear@0
|
1269 else if( IsElement( "repeatU")) {
|
nuclear@0
|
1270 out.mTransform.mScaling.x = ReadFloatFromTextContent();
|
nuclear@0
|
1271 TestClosing( "repeatU");
|
nuclear@0
|
1272 }
|
nuclear@0
|
1273 else if( IsElement( "repeatV")) {
|
nuclear@0
|
1274 out.mTransform.mScaling.y = ReadFloatFromTextContent();
|
nuclear@0
|
1275 TestClosing( "repeatV");
|
nuclear@0
|
1276 }
|
nuclear@0
|
1277 else if( IsElement( "offsetU")) {
|
nuclear@0
|
1278 out.mTransform.mTranslation.x = ReadFloatFromTextContent();
|
nuclear@0
|
1279 TestClosing( "offsetU");
|
nuclear@0
|
1280 }
|
nuclear@0
|
1281 else if( IsElement( "offsetV")) {
|
nuclear@0
|
1282 out.mTransform.mTranslation.y = ReadFloatFromTextContent();
|
nuclear@0
|
1283 TestClosing( "offsetV");
|
nuclear@0
|
1284 }
|
nuclear@0
|
1285 else if( IsElement( "rotateUV")) {
|
nuclear@0
|
1286 out.mTransform.mRotation = ReadFloatFromTextContent();
|
nuclear@0
|
1287 TestClosing( "rotateUV");
|
nuclear@0
|
1288 }
|
nuclear@0
|
1289 else if( IsElement( "blend_mode")) {
|
nuclear@0
|
1290
|
nuclear@0
|
1291 const char* sz = GetTextContent();
|
nuclear@0
|
1292 // http://www.feelingsoftware.com/content/view/55/72/lang,en/
|
nuclear@0
|
1293 // NONE, OVER, IN, OUT, ADD, SUBTRACT, MULTIPLY, DIFFERENCE, LIGHTEN, DARKEN, SATURATE, DESATURATE and ILLUMINATE
|
nuclear@0
|
1294 if (0 == ASSIMP_strincmp(sz,"ADD",3))
|
nuclear@0
|
1295 out.mOp = aiTextureOp_Add;
|
nuclear@0
|
1296
|
nuclear@0
|
1297 else if (0 == ASSIMP_strincmp(sz,"SUBTRACT",8))
|
nuclear@0
|
1298 out.mOp = aiTextureOp_Subtract;
|
nuclear@0
|
1299
|
nuclear@0
|
1300 else if (0 == ASSIMP_strincmp(sz,"MULTIPLY",8))
|
nuclear@0
|
1301 out.mOp = aiTextureOp_Multiply;
|
nuclear@0
|
1302
|
nuclear@0
|
1303 else {
|
nuclear@0
|
1304 DefaultLogger::get()->warn("Collada: Unsupported MAYA texture blend mode");
|
nuclear@0
|
1305 }
|
nuclear@0
|
1306 TestClosing( "blend_mode");
|
nuclear@0
|
1307 }
|
nuclear@0
|
1308 // OKINO extensions
|
nuclear@0
|
1309 // -------------------------------------------------------
|
nuclear@0
|
1310 else if( IsElement( "weighting")) {
|
nuclear@0
|
1311 out.mWeighting = ReadFloatFromTextContent();
|
nuclear@0
|
1312 TestClosing( "weighting");
|
nuclear@0
|
1313 }
|
nuclear@0
|
1314 else if( IsElement( "mix_with_previous_layer")) {
|
nuclear@0
|
1315 out.mMixWithPrevious = ReadFloatFromTextContent();
|
nuclear@0
|
1316 TestClosing( "mix_with_previous_layer");
|
nuclear@0
|
1317 }
|
nuclear@0
|
1318 // MAX3D extensions
|
nuclear@0
|
1319 // -------------------------------------------------------
|
nuclear@0
|
1320 else if( IsElement( "amount")) {
|
nuclear@0
|
1321 out.mWeighting = ReadFloatFromTextContent();
|
nuclear@0
|
1322 TestClosing( "amount");
|
nuclear@0
|
1323 }
|
nuclear@0
|
1324 }
|
nuclear@0
|
1325 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
|
nuclear@0
|
1326 if( strcmp( mReader->getNodeName(), "technique") == 0)
|
nuclear@0
|
1327 break;
|
nuclear@0
|
1328 }
|
nuclear@0
|
1329 }
|
nuclear@0
|
1330 }
|
nuclear@0
|
1331
|
nuclear@0
|
1332 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1333 // Reads an effect entry containing a color or a texture defining that color
|
nuclear@0
|
1334 void ColladaParser::ReadEffectColor( aiColor4D& pColor, Sampler& pSampler)
|
nuclear@0
|
1335 {
|
nuclear@0
|
1336 if (mReader->isEmptyElement())
|
nuclear@0
|
1337 return;
|
nuclear@0
|
1338
|
nuclear@0
|
1339 // Save current element name
|
nuclear@0
|
1340 const std::string curElem = mReader->getNodeName();
|
nuclear@0
|
1341
|
nuclear@0
|
1342 while( mReader->read())
|
nuclear@0
|
1343 {
|
nuclear@0
|
1344 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
|
nuclear@0
|
1345 if( IsElement( "color"))
|
nuclear@0
|
1346 {
|
nuclear@0
|
1347 // text content contains 4 floats
|
nuclear@0
|
1348 const char* content = GetTextContent();
|
nuclear@0
|
1349
|
nuclear@0
|
1350 content = fast_atoreal_move<float>( content, (float&)pColor.r);
|
nuclear@0
|
1351 SkipSpacesAndLineEnd( &content);
|
nuclear@0
|
1352
|
nuclear@0
|
1353 content = fast_atoreal_move<float>( content, (float&)pColor.g);
|
nuclear@0
|
1354 SkipSpacesAndLineEnd( &content);
|
nuclear@0
|
1355
|
nuclear@0
|
1356 content = fast_atoreal_move<float>( content, (float&)pColor.b);
|
nuclear@0
|
1357 SkipSpacesAndLineEnd( &content);
|
nuclear@0
|
1358
|
nuclear@0
|
1359 content = fast_atoreal_move<float>( content, (float&)pColor.a);
|
nuclear@0
|
1360 SkipSpacesAndLineEnd( &content);
|
nuclear@0
|
1361 TestClosing( "color");
|
nuclear@0
|
1362 }
|
nuclear@0
|
1363 else if( IsElement( "texture"))
|
nuclear@0
|
1364 {
|
nuclear@0
|
1365 // get name of source textur/sampler
|
nuclear@0
|
1366 int attrTex = GetAttribute( "texture");
|
nuclear@0
|
1367 pSampler.mName = mReader->getAttributeValue( attrTex);
|
nuclear@0
|
1368
|
nuclear@0
|
1369 // get name of UV source channel. Specification demands it to be there, but some exporters
|
nuclear@0
|
1370 // don't write it. It will be the default UV channel in case it's missing.
|
nuclear@0
|
1371 attrTex = TestAttribute( "texcoord");
|
nuclear@0
|
1372 if( attrTex >= 0 )
|
nuclear@0
|
1373 pSampler.mUVChannel = mReader->getAttributeValue( attrTex);
|
nuclear@0
|
1374 //SkipElement();
|
nuclear@0
|
1375 }
|
nuclear@0
|
1376 else if( IsElement( "technique"))
|
nuclear@0
|
1377 {
|
nuclear@0
|
1378 const int _profile = GetAttribute( "profile");
|
nuclear@0
|
1379 const char* profile = mReader->getAttributeValue( _profile );
|
nuclear@0
|
1380
|
nuclear@0
|
1381 // Some extensions are quite useful ... ReadSamplerProperties processes
|
nuclear@0
|
1382 // several extensions in MAYA, OKINO and MAX3D profiles.
|
nuclear@0
|
1383 if (!::strcmp(profile,"MAYA") || !::strcmp(profile,"MAX3D") || !::strcmp(profile,"OKINO"))
|
nuclear@0
|
1384 {
|
nuclear@0
|
1385 // get more information on this sampler
|
nuclear@0
|
1386 ReadSamplerProperties(pSampler);
|
nuclear@0
|
1387 }
|
nuclear@0
|
1388 else SkipElement();
|
nuclear@0
|
1389 }
|
nuclear@0
|
1390 else if( !IsElement( "extra"))
|
nuclear@0
|
1391 {
|
nuclear@0
|
1392 // ignore the rest
|
nuclear@0
|
1393 SkipElement();
|
nuclear@0
|
1394 }
|
nuclear@0
|
1395 }
|
nuclear@0
|
1396 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END){
|
nuclear@0
|
1397 if (mReader->getNodeName() == curElem)
|
nuclear@0
|
1398 break;
|
nuclear@0
|
1399 }
|
nuclear@0
|
1400 }
|
nuclear@0
|
1401 }
|
nuclear@0
|
1402
|
nuclear@0
|
1403 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1404 // Reads an effect entry containing a float
|
nuclear@0
|
1405 void ColladaParser::ReadEffectFloat( float& pFloat)
|
nuclear@0
|
1406 {
|
nuclear@0
|
1407 while( mReader->read())
|
nuclear@0
|
1408 {
|
nuclear@0
|
1409 if( mReader->getNodeType() == irr::io::EXN_ELEMENT){
|
nuclear@0
|
1410 if( IsElement( "float"))
|
nuclear@0
|
1411 {
|
nuclear@0
|
1412 // text content contains a single floats
|
nuclear@0
|
1413 const char* content = GetTextContent();
|
nuclear@0
|
1414 content = fast_atoreal_move<float>( content, pFloat);
|
nuclear@0
|
1415 SkipSpacesAndLineEnd( &content);
|
nuclear@0
|
1416
|
nuclear@0
|
1417 TestClosing( "float");
|
nuclear@0
|
1418 } else
|
nuclear@0
|
1419 {
|
nuclear@0
|
1420 // ignore the rest
|
nuclear@0
|
1421 SkipElement();
|
nuclear@0
|
1422 }
|
nuclear@0
|
1423 }
|
nuclear@0
|
1424 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END){
|
nuclear@0
|
1425 break;
|
nuclear@0
|
1426 }
|
nuclear@0
|
1427 }
|
nuclear@0
|
1428 }
|
nuclear@0
|
1429
|
nuclear@0
|
1430 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1431 // Reads an effect parameter specification of any kind
|
nuclear@0
|
1432 void ColladaParser::ReadEffectParam( Collada::EffectParam& pParam)
|
nuclear@0
|
1433 {
|
nuclear@0
|
1434 while( mReader->read())
|
nuclear@0
|
1435 {
|
nuclear@0
|
1436 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
|
nuclear@0
|
1437 if( IsElement( "surface"))
|
nuclear@0
|
1438 {
|
nuclear@0
|
1439 // image ID given inside <init_from> tags
|
nuclear@0
|
1440 TestOpening( "init_from");
|
nuclear@0
|
1441 const char* content = GetTextContent();
|
nuclear@0
|
1442 pParam.mType = Param_Surface;
|
nuclear@0
|
1443 pParam.mReference = content;
|
nuclear@0
|
1444 TestClosing( "init_from");
|
nuclear@0
|
1445
|
nuclear@0
|
1446 // don't care for remaining stuff
|
nuclear@0
|
1447 SkipElement( "surface");
|
nuclear@0
|
1448 }
|
nuclear@0
|
1449 else if( IsElement( "sampler2D"))
|
nuclear@0
|
1450 {
|
nuclear@0
|
1451 // surface ID is given inside <source> tags
|
nuclear@0
|
1452 TestOpening( "source");
|
nuclear@0
|
1453 const char* content = GetTextContent();
|
nuclear@0
|
1454 pParam.mType = Param_Sampler;
|
nuclear@0
|
1455 pParam.mReference = content;
|
nuclear@0
|
1456 TestClosing( "source");
|
nuclear@0
|
1457
|
nuclear@0
|
1458 // don't care for remaining stuff
|
nuclear@0
|
1459 SkipElement( "sampler2D");
|
nuclear@0
|
1460 } else
|
nuclear@0
|
1461 {
|
nuclear@0
|
1462 // ignore unknown element
|
nuclear@0
|
1463 SkipElement();
|
nuclear@0
|
1464 }
|
nuclear@0
|
1465 }
|
nuclear@0
|
1466 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
|
nuclear@0
|
1467 break;
|
nuclear@0
|
1468 }
|
nuclear@0
|
1469 }
|
nuclear@0
|
1470 }
|
nuclear@0
|
1471
|
nuclear@0
|
1472 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1473 // Reads the geometry library contents
|
nuclear@0
|
1474 void ColladaParser::ReadGeometryLibrary()
|
nuclear@0
|
1475 {
|
nuclear@0
|
1476 if( mReader->isEmptyElement())
|
nuclear@0
|
1477 return;
|
nuclear@0
|
1478
|
nuclear@0
|
1479 while( mReader->read())
|
nuclear@0
|
1480 {
|
nuclear@0
|
1481 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
1482 {
|
nuclear@0
|
1483 if( IsElement( "geometry"))
|
nuclear@0
|
1484 {
|
nuclear@0
|
1485 // read ID. Another entry which is "optional" by design but obligatory in reality
|
nuclear@0
|
1486 int indexID = GetAttribute( "id");
|
nuclear@0
|
1487 std::string id = mReader->getAttributeValue( indexID);
|
nuclear@0
|
1488
|
nuclear@0
|
1489 // TODO: (thom) support SIDs
|
nuclear@0
|
1490 // ai_assert( TestAttribute( "sid") == -1);
|
nuclear@0
|
1491
|
nuclear@0
|
1492 // create a mesh and store it in the library under its ID
|
nuclear@0
|
1493 Mesh* mesh = new Mesh;
|
nuclear@0
|
1494 mMeshLibrary[id] = mesh;
|
nuclear@0
|
1495
|
nuclear@0
|
1496 // read on from there
|
nuclear@0
|
1497 ReadGeometry( mesh);
|
nuclear@0
|
1498 } else
|
nuclear@0
|
1499 {
|
nuclear@0
|
1500 // ignore the rest
|
nuclear@0
|
1501 SkipElement();
|
nuclear@0
|
1502 }
|
nuclear@0
|
1503 }
|
nuclear@0
|
1504 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
nuclear@0
|
1505 {
|
nuclear@0
|
1506 if( strcmp( mReader->getNodeName(), "library_geometries") != 0)
|
nuclear@0
|
1507 ThrowException( "Expected end of <library_geometries> element.");
|
nuclear@0
|
1508
|
nuclear@0
|
1509 break;
|
nuclear@0
|
1510 }
|
nuclear@0
|
1511 }
|
nuclear@0
|
1512 }
|
nuclear@0
|
1513
|
nuclear@0
|
1514 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1515 // Reads a geometry from the geometry library.
|
nuclear@0
|
1516 void ColladaParser::ReadGeometry( Collada::Mesh* pMesh)
|
nuclear@0
|
1517 {
|
nuclear@0
|
1518 if( mReader->isEmptyElement())
|
nuclear@0
|
1519 return;
|
nuclear@0
|
1520
|
nuclear@0
|
1521 while( mReader->read())
|
nuclear@0
|
1522 {
|
nuclear@0
|
1523 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
1524 {
|
nuclear@0
|
1525 if( IsElement( "mesh"))
|
nuclear@0
|
1526 {
|
nuclear@0
|
1527 // read on from there
|
nuclear@0
|
1528 ReadMesh( pMesh);
|
nuclear@0
|
1529 } else
|
nuclear@0
|
1530 {
|
nuclear@0
|
1531 // ignore the rest
|
nuclear@0
|
1532 SkipElement();
|
nuclear@0
|
1533 }
|
nuclear@0
|
1534 }
|
nuclear@0
|
1535 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
nuclear@0
|
1536 {
|
nuclear@0
|
1537 if( strcmp( mReader->getNodeName(), "geometry") != 0)
|
nuclear@0
|
1538 ThrowException( "Expected end of <geometry> element.");
|
nuclear@0
|
1539
|
nuclear@0
|
1540 break;
|
nuclear@0
|
1541 }
|
nuclear@0
|
1542 }
|
nuclear@0
|
1543 }
|
nuclear@0
|
1544
|
nuclear@0
|
1545 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1546 // Reads a mesh from the geometry library
|
nuclear@0
|
1547 void ColladaParser::ReadMesh( Mesh* pMesh)
|
nuclear@0
|
1548 {
|
nuclear@0
|
1549 if( mReader->isEmptyElement())
|
nuclear@0
|
1550 return;
|
nuclear@0
|
1551
|
nuclear@0
|
1552 while( mReader->read())
|
nuclear@0
|
1553 {
|
nuclear@0
|
1554 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
1555 {
|
nuclear@0
|
1556 if( IsElement( "source"))
|
nuclear@0
|
1557 {
|
nuclear@0
|
1558 // we have professionals dealing with this
|
nuclear@0
|
1559 ReadSource();
|
nuclear@0
|
1560 }
|
nuclear@0
|
1561 else if( IsElement( "vertices"))
|
nuclear@0
|
1562 {
|
nuclear@0
|
1563 // read per-vertex mesh data
|
nuclear@0
|
1564 ReadVertexData( pMesh);
|
nuclear@0
|
1565 }
|
nuclear@0
|
1566 else if( IsElement( "triangles") || IsElement( "lines") || IsElement( "linestrips")
|
nuclear@0
|
1567 || IsElement( "polygons") || IsElement( "polylist") || IsElement( "trifans") || IsElement( "tristrips"))
|
nuclear@0
|
1568 {
|
nuclear@0
|
1569 // read per-index mesh data and faces setup
|
nuclear@0
|
1570 ReadIndexData( pMesh);
|
nuclear@0
|
1571 } else
|
nuclear@0
|
1572 {
|
nuclear@0
|
1573 // ignore the rest
|
nuclear@0
|
1574 SkipElement();
|
nuclear@0
|
1575 }
|
nuclear@0
|
1576 }
|
nuclear@0
|
1577 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
nuclear@0
|
1578 {
|
nuclear@0
|
1579 if( strcmp( mReader->getNodeName(), "technique_common") == 0)
|
nuclear@0
|
1580 {
|
nuclear@0
|
1581 // end of another meaningless element - read over it
|
nuclear@0
|
1582 }
|
nuclear@0
|
1583 else if( strcmp( mReader->getNodeName(), "mesh") == 0)
|
nuclear@0
|
1584 {
|
nuclear@0
|
1585 // end of <mesh> element - we're done here
|
nuclear@0
|
1586 break;
|
nuclear@0
|
1587 } else
|
nuclear@0
|
1588 {
|
nuclear@0
|
1589 // everything else should be punished
|
nuclear@0
|
1590 ThrowException( "Expected end of <mesh> element.");
|
nuclear@0
|
1591 }
|
nuclear@0
|
1592 }
|
nuclear@0
|
1593 }
|
nuclear@0
|
1594 }
|
nuclear@0
|
1595
|
nuclear@0
|
1596 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1597 // Reads a source element
|
nuclear@0
|
1598 void ColladaParser::ReadSource()
|
nuclear@0
|
1599 {
|
nuclear@0
|
1600 int indexID = GetAttribute( "id");
|
nuclear@0
|
1601 std::string sourceID = mReader->getAttributeValue( indexID);
|
nuclear@0
|
1602
|
nuclear@0
|
1603 while( mReader->read())
|
nuclear@0
|
1604 {
|
nuclear@0
|
1605 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
1606 {
|
nuclear@0
|
1607 if( IsElement( "float_array") || IsElement( "IDREF_array") || IsElement( "Name_array"))
|
nuclear@0
|
1608 {
|
nuclear@0
|
1609 ReadDataArray();
|
nuclear@0
|
1610 }
|
nuclear@0
|
1611 else if( IsElement( "technique_common"))
|
nuclear@0
|
1612 {
|
nuclear@0
|
1613 // I don't care for your profiles
|
nuclear@0
|
1614 }
|
nuclear@0
|
1615 else if( IsElement( "accessor"))
|
nuclear@0
|
1616 {
|
nuclear@0
|
1617 ReadAccessor( sourceID);
|
nuclear@0
|
1618 } else
|
nuclear@0
|
1619 {
|
nuclear@0
|
1620 // ignore the rest
|
nuclear@0
|
1621 SkipElement();
|
nuclear@0
|
1622 }
|
nuclear@0
|
1623 }
|
nuclear@0
|
1624 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
nuclear@0
|
1625 {
|
nuclear@0
|
1626 if( strcmp( mReader->getNodeName(), "source") == 0)
|
nuclear@0
|
1627 {
|
nuclear@0
|
1628 // end of <source> - we're done
|
nuclear@0
|
1629 break;
|
nuclear@0
|
1630 }
|
nuclear@0
|
1631 else if( strcmp( mReader->getNodeName(), "technique_common") == 0)
|
nuclear@0
|
1632 {
|
nuclear@0
|
1633 // end of another meaningless element - read over it
|
nuclear@0
|
1634 } else
|
nuclear@0
|
1635 {
|
nuclear@0
|
1636 // everything else should be punished
|
nuclear@0
|
1637 ThrowException( "Expected end of <source> element.");
|
nuclear@0
|
1638 }
|
nuclear@0
|
1639 }
|
nuclear@0
|
1640 }
|
nuclear@0
|
1641 }
|
nuclear@0
|
1642
|
nuclear@0
|
1643 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1644 // Reads a data array holding a number of floats, and stores it in the global library
|
nuclear@0
|
1645 void ColladaParser::ReadDataArray()
|
nuclear@0
|
1646 {
|
nuclear@0
|
1647 std::string elmName = mReader->getNodeName();
|
nuclear@0
|
1648 bool isStringArray = (elmName == "IDREF_array" || elmName == "Name_array");
|
nuclear@0
|
1649 bool isEmptyElement = mReader->isEmptyElement();
|
nuclear@0
|
1650
|
nuclear@0
|
1651 // read attributes
|
nuclear@0
|
1652 int indexID = GetAttribute( "id");
|
nuclear@0
|
1653 std::string id = mReader->getAttributeValue( indexID);
|
nuclear@0
|
1654 int indexCount = GetAttribute( "count");
|
nuclear@0
|
1655 unsigned int count = (unsigned int) mReader->getAttributeValueAsInt( indexCount);
|
nuclear@0
|
1656 if (count == 0) { return; } // some exporters write empty data arrays with count="0"
|
nuclear@0
|
1657 const char* content = TestTextContent();
|
nuclear@0
|
1658
|
nuclear@0
|
1659 // read values and store inside an array in the data library
|
nuclear@0
|
1660 mDataLibrary[id] = Data();
|
nuclear@0
|
1661 Data& data = mDataLibrary[id];
|
nuclear@0
|
1662 data.mIsStringArray = isStringArray;
|
nuclear@0
|
1663
|
nuclear@0
|
1664 // some exporters write empty data arrays, but we need to conserve them anyways because others might reference them
|
nuclear@0
|
1665 if (content)
|
nuclear@0
|
1666 {
|
nuclear@0
|
1667 if( isStringArray)
|
nuclear@0
|
1668 {
|
nuclear@0
|
1669 data.mStrings.reserve( count);
|
nuclear@0
|
1670 std::string s;
|
nuclear@0
|
1671
|
nuclear@0
|
1672 for( unsigned int a = 0; a < count; a++)
|
nuclear@0
|
1673 {
|
nuclear@0
|
1674 if( *content == 0)
|
nuclear@0
|
1675 ThrowException( "Expected more values while reading IDREF_array contents.");
|
nuclear@0
|
1676
|
nuclear@0
|
1677 s.clear();
|
nuclear@0
|
1678 while( !IsSpaceOrNewLine( *content))
|
nuclear@0
|
1679 s += *content++;
|
nuclear@0
|
1680 data.mStrings.push_back( s);
|
nuclear@0
|
1681
|
nuclear@0
|
1682 SkipSpacesAndLineEnd( &content);
|
nuclear@0
|
1683 }
|
nuclear@0
|
1684 } else
|
nuclear@0
|
1685 {
|
nuclear@0
|
1686 data.mValues.reserve( count);
|
nuclear@0
|
1687
|
nuclear@0
|
1688 for( unsigned int a = 0; a < count; a++)
|
nuclear@0
|
1689 {
|
nuclear@0
|
1690 if( *content == 0)
|
nuclear@0
|
1691 ThrowException( "Expected more values while reading float_array contents.");
|
nuclear@0
|
1692
|
nuclear@0
|
1693 float value;
|
nuclear@0
|
1694 // read a number
|
nuclear@0
|
1695 content = fast_atoreal_move<float>( content, value);
|
nuclear@0
|
1696 data.mValues.push_back( value);
|
nuclear@0
|
1697 // skip whitespace after it
|
nuclear@0
|
1698 SkipSpacesAndLineEnd( &content);
|
nuclear@0
|
1699 }
|
nuclear@0
|
1700 }
|
nuclear@0
|
1701 }
|
nuclear@0
|
1702
|
nuclear@0
|
1703 // test for closing tag
|
nuclear@0
|
1704 if( !isEmptyElement )
|
nuclear@0
|
1705 TestClosing( elmName.c_str());
|
nuclear@0
|
1706 }
|
nuclear@0
|
1707
|
nuclear@0
|
1708 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1709 // Reads an accessor and stores it in the global library
|
nuclear@0
|
1710 void ColladaParser::ReadAccessor( const std::string& pID)
|
nuclear@0
|
1711 {
|
nuclear@0
|
1712 // read accessor attributes
|
nuclear@0
|
1713 int attrSource = GetAttribute( "source");
|
nuclear@0
|
1714 const char* source = mReader->getAttributeValue( attrSource);
|
nuclear@0
|
1715 if( source[0] != '#')
|
nuclear@0
|
1716 ThrowException( boost::str( boost::format( "Unknown reference format in url \"%s\" in source attribute of <accessor> element.") % source));
|
nuclear@0
|
1717 int attrCount = GetAttribute( "count");
|
nuclear@0
|
1718 unsigned int count = (unsigned int) mReader->getAttributeValueAsInt( attrCount);
|
nuclear@0
|
1719 int attrOffset = TestAttribute( "offset");
|
nuclear@0
|
1720 unsigned int offset = 0;
|
nuclear@0
|
1721 if( attrOffset > -1)
|
nuclear@0
|
1722 offset = (unsigned int) mReader->getAttributeValueAsInt( attrOffset);
|
nuclear@0
|
1723 int attrStride = TestAttribute( "stride");
|
nuclear@0
|
1724 unsigned int stride = 1;
|
nuclear@0
|
1725 if( attrStride > -1)
|
nuclear@0
|
1726 stride = (unsigned int) mReader->getAttributeValueAsInt( attrStride);
|
nuclear@0
|
1727
|
nuclear@0
|
1728 // store in the library under the given ID
|
nuclear@0
|
1729 mAccessorLibrary[pID] = Accessor();
|
nuclear@0
|
1730 Accessor& acc = mAccessorLibrary[pID];
|
nuclear@0
|
1731 acc.mCount = count;
|
nuclear@0
|
1732 acc.mOffset = offset;
|
nuclear@0
|
1733 acc.mStride = stride;
|
nuclear@0
|
1734 acc.mSource = source+1; // ignore the leading '#'
|
nuclear@0
|
1735 acc.mSize = 0; // gets incremented with every param
|
nuclear@0
|
1736
|
nuclear@0
|
1737 // and read the components
|
nuclear@0
|
1738 while( mReader->read())
|
nuclear@0
|
1739 {
|
nuclear@0
|
1740 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
1741 {
|
nuclear@0
|
1742 if( IsElement( "param"))
|
nuclear@0
|
1743 {
|
nuclear@0
|
1744 // read data param
|
nuclear@0
|
1745 int attrName = TestAttribute( "name");
|
nuclear@0
|
1746 std::string name;
|
nuclear@0
|
1747 if( attrName > -1)
|
nuclear@0
|
1748 {
|
nuclear@0
|
1749 name = mReader->getAttributeValue( attrName);
|
nuclear@0
|
1750
|
nuclear@0
|
1751 // analyse for common type components and store it's sub-offset in the corresponding field
|
nuclear@0
|
1752
|
nuclear@0
|
1753 /* Cartesian coordinates */
|
nuclear@0
|
1754 if( name == "X") acc.mSubOffset[0] = acc.mParams.size();
|
nuclear@0
|
1755 else if( name == "Y") acc.mSubOffset[1] = acc.mParams.size();
|
nuclear@0
|
1756 else if( name == "Z") acc.mSubOffset[2] = acc.mParams.size();
|
nuclear@0
|
1757
|
nuclear@0
|
1758 /* RGBA colors */
|
nuclear@0
|
1759 else if( name == "R") acc.mSubOffset[0] = acc.mParams.size();
|
nuclear@0
|
1760 else if( name == "G") acc.mSubOffset[1] = acc.mParams.size();
|
nuclear@0
|
1761 else if( name == "B") acc.mSubOffset[2] = acc.mParams.size();
|
nuclear@0
|
1762 else if( name == "A") acc.mSubOffset[3] = acc.mParams.size();
|
nuclear@0
|
1763
|
nuclear@0
|
1764 /* UVWQ (STPQ) texture coordinates */
|
nuclear@0
|
1765 else if( name == "S") acc.mSubOffset[0] = acc.mParams.size();
|
nuclear@0
|
1766 else if( name == "T") acc.mSubOffset[1] = acc.mParams.size();
|
nuclear@0
|
1767 else if( name == "P") acc.mSubOffset[2] = acc.mParams.size();
|
nuclear@0
|
1768 // else if( name == "Q") acc.mSubOffset[3] = acc.mParams.size();
|
nuclear@0
|
1769 /* 4D uv coordinates are not supported in Assimp */
|
nuclear@0
|
1770
|
nuclear@0
|
1771 /* Generic extra data, interpreted as UV data, too*/
|
nuclear@0
|
1772 else if( name == "U") acc.mSubOffset[0] = acc.mParams.size();
|
nuclear@0
|
1773 else if( name == "V") acc.mSubOffset[1] = acc.mParams.size();
|
nuclear@0
|
1774 //else
|
nuclear@0
|
1775 // DefaultLogger::get()->warn( boost::str( boost::format( "Unknown accessor parameter \"%s\". Ignoring data channel.") % name));
|
nuclear@0
|
1776 }
|
nuclear@0
|
1777
|
nuclear@0
|
1778 // read data type
|
nuclear@0
|
1779 int attrType = TestAttribute( "type");
|
nuclear@0
|
1780 if( attrType > -1)
|
nuclear@0
|
1781 {
|
nuclear@0
|
1782 // for the moment we only distinguish between a 4x4 matrix and anything else.
|
nuclear@0
|
1783 // TODO: (thom) I don't have a spec here at work. Check if there are other multi-value types
|
nuclear@0
|
1784 // which should be tested for here.
|
nuclear@0
|
1785 std::string type = mReader->getAttributeValue( attrType);
|
nuclear@0
|
1786 if( type == "float4x4")
|
nuclear@0
|
1787 acc.mSize += 16;
|
nuclear@0
|
1788 else
|
nuclear@0
|
1789 acc.mSize += 1;
|
nuclear@0
|
1790 }
|
nuclear@0
|
1791
|
nuclear@0
|
1792 acc.mParams.push_back( name);
|
nuclear@0
|
1793
|
nuclear@0
|
1794 // skip remaining stuff of this element, if any
|
nuclear@0
|
1795 SkipElement();
|
nuclear@0
|
1796 } else
|
nuclear@0
|
1797 {
|
nuclear@0
|
1798 ThrowException( boost::str( boost::format( "Unexpected sub element <%s> in tag <accessor>") % mReader->getNodeName()));
|
nuclear@0
|
1799 }
|
nuclear@0
|
1800 }
|
nuclear@0
|
1801 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
nuclear@0
|
1802 {
|
nuclear@0
|
1803 if( strcmp( mReader->getNodeName(), "accessor") != 0)
|
nuclear@0
|
1804 ThrowException( "Expected end of <accessor> element.");
|
nuclear@0
|
1805 break;
|
nuclear@0
|
1806 }
|
nuclear@0
|
1807 }
|
nuclear@0
|
1808 }
|
nuclear@0
|
1809
|
nuclear@0
|
1810 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1811 // Reads input declarations of per-vertex mesh data into the given mesh
|
nuclear@0
|
1812 void ColladaParser::ReadVertexData( Mesh* pMesh)
|
nuclear@0
|
1813 {
|
nuclear@0
|
1814 // extract the ID of the <vertices> element. Not that we care, but to catch strange referencing schemes we should warn about
|
nuclear@0
|
1815 int attrID= GetAttribute( "id");
|
nuclear@0
|
1816 pMesh->mVertexID = mReader->getAttributeValue( attrID);
|
nuclear@0
|
1817
|
nuclear@0
|
1818 // a number of <input> elements
|
nuclear@0
|
1819 while( mReader->read())
|
nuclear@0
|
1820 {
|
nuclear@0
|
1821 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
1822 {
|
nuclear@0
|
1823 if( IsElement( "input"))
|
nuclear@0
|
1824 {
|
nuclear@0
|
1825 ReadInputChannel( pMesh->mPerVertexData);
|
nuclear@0
|
1826 } else
|
nuclear@0
|
1827 {
|
nuclear@0
|
1828 ThrowException( boost::str( boost::format( "Unexpected sub element <%s> in tag <vertices>") % mReader->getNodeName()));
|
nuclear@0
|
1829 }
|
nuclear@0
|
1830 }
|
nuclear@0
|
1831 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
nuclear@0
|
1832 {
|
nuclear@0
|
1833 if( strcmp( mReader->getNodeName(), "vertices") != 0)
|
nuclear@0
|
1834 ThrowException( "Expected end of <vertices> element.");
|
nuclear@0
|
1835
|
nuclear@0
|
1836 break;
|
nuclear@0
|
1837 }
|
nuclear@0
|
1838 }
|
nuclear@0
|
1839 }
|
nuclear@0
|
1840
|
nuclear@0
|
1841 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1842 // Reads input declarations of per-index mesh data into the given mesh
|
nuclear@0
|
1843 void ColladaParser::ReadIndexData( Mesh* pMesh)
|
nuclear@0
|
1844 {
|
nuclear@0
|
1845 std::vector<size_t> vcount;
|
nuclear@0
|
1846 std::vector<InputChannel> perIndexData;
|
nuclear@0
|
1847
|
nuclear@0
|
1848 // read primitive count from the attribute
|
nuclear@0
|
1849 int attrCount = GetAttribute( "count");
|
nuclear@0
|
1850 size_t numPrimitives = (size_t) mReader->getAttributeValueAsInt( attrCount);
|
nuclear@0
|
1851
|
nuclear@0
|
1852 // material subgroup
|
nuclear@0
|
1853 int attrMaterial = TestAttribute( "material");
|
nuclear@0
|
1854 SubMesh subgroup;
|
nuclear@0
|
1855 if( attrMaterial > -1)
|
nuclear@0
|
1856 subgroup.mMaterial = mReader->getAttributeValue( attrMaterial);
|
nuclear@0
|
1857 subgroup.mNumFaces = numPrimitives;
|
nuclear@0
|
1858 pMesh->mSubMeshes.push_back( subgroup);
|
nuclear@0
|
1859
|
nuclear@0
|
1860 // distinguish between polys and triangles
|
nuclear@0
|
1861 std::string elementName = mReader->getNodeName();
|
nuclear@0
|
1862 PrimitiveType primType = Prim_Invalid;
|
nuclear@0
|
1863 if( IsElement( "lines"))
|
nuclear@0
|
1864 primType = Prim_Lines;
|
nuclear@0
|
1865 else if( IsElement( "linestrips"))
|
nuclear@0
|
1866 primType = Prim_LineStrip;
|
nuclear@0
|
1867 else if( IsElement( "polygons"))
|
nuclear@0
|
1868 primType = Prim_Polygon;
|
nuclear@0
|
1869 else if( IsElement( "polylist"))
|
nuclear@0
|
1870 primType = Prim_Polylist;
|
nuclear@0
|
1871 else if( IsElement( "triangles"))
|
nuclear@0
|
1872 primType = Prim_Triangles;
|
nuclear@0
|
1873 else if( IsElement( "trifans"))
|
nuclear@0
|
1874 primType = Prim_TriFans;
|
nuclear@0
|
1875 else if( IsElement( "tristrips"))
|
nuclear@0
|
1876 primType = Prim_TriStrips;
|
nuclear@0
|
1877
|
nuclear@0
|
1878 ai_assert( primType != Prim_Invalid);
|
nuclear@0
|
1879
|
nuclear@0
|
1880 // also a number of <input> elements, but in addition a <p> primitive collection and propably index counts for all primitives
|
nuclear@0
|
1881 while( mReader->read())
|
nuclear@0
|
1882 {
|
nuclear@0
|
1883 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
1884 {
|
nuclear@0
|
1885 if( IsElement( "input"))
|
nuclear@0
|
1886 {
|
nuclear@0
|
1887 ReadInputChannel( perIndexData);
|
nuclear@0
|
1888 }
|
nuclear@0
|
1889 else if( IsElement( "vcount"))
|
nuclear@0
|
1890 {
|
nuclear@0
|
1891 if( !mReader->isEmptyElement())
|
nuclear@0
|
1892 {
|
nuclear@0
|
1893 if (numPrimitives) // It is possible to define a mesh without any primitives
|
nuclear@0
|
1894 {
|
nuclear@0
|
1895 // case <polylist> - specifies the number of indices for each polygon
|
nuclear@0
|
1896 const char* content = GetTextContent();
|
nuclear@0
|
1897 vcount.reserve( numPrimitives);
|
nuclear@0
|
1898 for( unsigned int a = 0; a < numPrimitives; a++)
|
nuclear@0
|
1899 {
|
nuclear@0
|
1900 if( *content == 0)
|
nuclear@0
|
1901 ThrowException( "Expected more values while reading <vcount> contents.");
|
nuclear@0
|
1902 // read a number
|
nuclear@0
|
1903 vcount.push_back( (size_t) strtoul10( content, &content));
|
nuclear@0
|
1904 // skip whitespace after it
|
nuclear@0
|
1905 SkipSpacesAndLineEnd( &content);
|
nuclear@0
|
1906 }
|
nuclear@0
|
1907 }
|
nuclear@0
|
1908
|
nuclear@0
|
1909 TestClosing( "vcount");
|
nuclear@0
|
1910 }
|
nuclear@0
|
1911 }
|
nuclear@0
|
1912 else if( IsElement( "p"))
|
nuclear@0
|
1913 {
|
nuclear@0
|
1914 if( !mReader->isEmptyElement())
|
nuclear@0
|
1915 {
|
nuclear@0
|
1916 // now here the actual fun starts - these are the indices to construct the mesh data from
|
nuclear@0
|
1917 ReadPrimitives( pMesh, perIndexData, numPrimitives, vcount, primType);
|
nuclear@0
|
1918 }
|
nuclear@0
|
1919 } else
|
nuclear@0
|
1920 {
|
nuclear@0
|
1921 ThrowException( boost::str( boost::format( "Unexpected sub element <%s> in tag <%s>") % mReader->getNodeName() % elementName));
|
nuclear@0
|
1922 }
|
nuclear@0
|
1923 }
|
nuclear@0
|
1924 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
nuclear@0
|
1925 {
|
nuclear@0
|
1926 if( mReader->getNodeName() != elementName)
|
nuclear@0
|
1927 ThrowException( boost::str( boost::format( "Expected end of <%s> element.") % elementName));
|
nuclear@0
|
1928
|
nuclear@0
|
1929 break;
|
nuclear@0
|
1930 }
|
nuclear@0
|
1931 }
|
nuclear@0
|
1932 }
|
nuclear@0
|
1933
|
nuclear@0
|
1934 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1935 // Reads a single input channel element and stores it in the given array, if valid
|
nuclear@0
|
1936 void ColladaParser::ReadInputChannel( std::vector<InputChannel>& poChannels)
|
nuclear@0
|
1937 {
|
nuclear@0
|
1938 InputChannel channel;
|
nuclear@0
|
1939
|
nuclear@0
|
1940 // read semantic
|
nuclear@0
|
1941 int attrSemantic = GetAttribute( "semantic");
|
nuclear@0
|
1942 std::string semantic = mReader->getAttributeValue( attrSemantic);
|
nuclear@0
|
1943 channel.mType = GetTypeForSemantic( semantic);
|
nuclear@0
|
1944
|
nuclear@0
|
1945 // read source
|
nuclear@0
|
1946 int attrSource = GetAttribute( "source");
|
nuclear@0
|
1947 const char* source = mReader->getAttributeValue( attrSource);
|
nuclear@0
|
1948 if( source[0] != '#')
|
nuclear@0
|
1949 ThrowException( boost::str( boost::format( "Unknown reference format in url \"%s\" in source attribute of <input> element.") % source));
|
nuclear@0
|
1950 channel.mAccessor = source+1; // skipping the leading #, hopefully the remaining text is the accessor ID only
|
nuclear@0
|
1951
|
nuclear@0
|
1952 // read index offset, if per-index <input>
|
nuclear@0
|
1953 int attrOffset = TestAttribute( "offset");
|
nuclear@0
|
1954 if( attrOffset > -1)
|
nuclear@0
|
1955 channel.mOffset = mReader->getAttributeValueAsInt( attrOffset);
|
nuclear@0
|
1956
|
nuclear@0
|
1957 // read set if texture coordinates
|
nuclear@0
|
1958 if(channel.mType == IT_Texcoord || channel.mType == IT_Color){
|
nuclear@0
|
1959 int attrSet = TestAttribute("set");
|
nuclear@0
|
1960 if(attrSet > -1){
|
nuclear@0
|
1961 attrSet = mReader->getAttributeValueAsInt( attrSet);
|
nuclear@0
|
1962 if(attrSet < 0)
|
nuclear@0
|
1963 ThrowException( boost::str( boost::format( "Invalid index \"%i\" in set attribute of <input> element") % (attrSet)));
|
nuclear@0
|
1964
|
nuclear@0
|
1965 channel.mIndex = attrSet;
|
nuclear@0
|
1966 }
|
nuclear@0
|
1967 }
|
nuclear@0
|
1968
|
nuclear@0
|
1969 // store, if valid type
|
nuclear@0
|
1970 if( channel.mType != IT_Invalid)
|
nuclear@0
|
1971 poChannels.push_back( channel);
|
nuclear@0
|
1972
|
nuclear@0
|
1973 // skip remaining stuff of this element, if any
|
nuclear@0
|
1974 SkipElement();
|
nuclear@0
|
1975 }
|
nuclear@0
|
1976
|
nuclear@0
|
1977 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1978 // Reads a <p> primitive index list and assembles the mesh data into the given mesh
|
nuclear@0
|
1979 void ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pPerIndexChannels,
|
nuclear@0
|
1980 size_t pNumPrimitives, const std::vector<size_t>& pVCount, PrimitiveType pPrimType)
|
nuclear@0
|
1981 {
|
nuclear@0
|
1982 // determine number of indices coming per vertex
|
nuclear@0
|
1983 // find the offset index for all per-vertex channels
|
nuclear@0
|
1984 size_t numOffsets = 1;
|
nuclear@0
|
1985 size_t perVertexOffset = SIZE_MAX; // invalid value
|
nuclear@0
|
1986 BOOST_FOREACH( const InputChannel& channel, pPerIndexChannels)
|
nuclear@0
|
1987 {
|
nuclear@0
|
1988 numOffsets = std::max( numOffsets, channel.mOffset+1);
|
nuclear@0
|
1989 if( channel.mType == IT_Vertex)
|
nuclear@0
|
1990 perVertexOffset = channel.mOffset;
|
nuclear@0
|
1991 }
|
nuclear@0
|
1992
|
nuclear@0
|
1993 // determine the expected number of indices
|
nuclear@0
|
1994 size_t expectedPointCount = 0;
|
nuclear@0
|
1995 switch( pPrimType)
|
nuclear@0
|
1996 {
|
nuclear@0
|
1997 case Prim_Polylist:
|
nuclear@0
|
1998 {
|
nuclear@0
|
1999 BOOST_FOREACH( size_t i, pVCount)
|
nuclear@0
|
2000 expectedPointCount += i;
|
nuclear@0
|
2001 break;
|
nuclear@0
|
2002 }
|
nuclear@0
|
2003 case Prim_Lines:
|
nuclear@0
|
2004 expectedPointCount = 2 * pNumPrimitives;
|
nuclear@0
|
2005 break;
|
nuclear@0
|
2006 case Prim_Triangles:
|
nuclear@0
|
2007 expectedPointCount = 3 * pNumPrimitives;
|
nuclear@0
|
2008 break;
|
nuclear@0
|
2009 default:
|
nuclear@0
|
2010 // other primitive types don't state the index count upfront... we need to guess
|
nuclear@0
|
2011 break;
|
nuclear@0
|
2012 }
|
nuclear@0
|
2013
|
nuclear@0
|
2014 // and read all indices into a temporary array
|
nuclear@0
|
2015 std::vector<size_t> indices;
|
nuclear@0
|
2016 if( expectedPointCount > 0)
|
nuclear@0
|
2017 indices.reserve( expectedPointCount * numOffsets);
|
nuclear@0
|
2018
|
nuclear@0
|
2019 if (pNumPrimitives > 0) // It is possible to not contain any indicies
|
nuclear@0
|
2020 {
|
nuclear@0
|
2021 const char* content = GetTextContent();
|
nuclear@0
|
2022 while( *content != 0)
|
nuclear@0
|
2023 {
|
nuclear@0
|
2024 // read a value.
|
nuclear@0
|
2025 // Hack: (thom) Some exporters put negative indices sometimes. We just try to carry on anyways.
|
nuclear@0
|
2026 int value = std::max( 0, strtol10( content, &content));
|
nuclear@0
|
2027 indices.push_back( size_t( value));
|
nuclear@0
|
2028 // skip whitespace after it
|
nuclear@0
|
2029 SkipSpacesAndLineEnd( &content);
|
nuclear@0
|
2030 }
|
nuclear@0
|
2031 }
|
nuclear@0
|
2032
|
nuclear@0
|
2033 // complain if the index count doesn't fit
|
nuclear@0
|
2034 if( expectedPointCount > 0 && indices.size() != expectedPointCount * numOffsets)
|
nuclear@0
|
2035 ThrowException( "Expected different index count in <p> element.");
|
nuclear@0
|
2036 else if( expectedPointCount == 0 && (indices.size() % numOffsets) != 0)
|
nuclear@0
|
2037 ThrowException( "Expected different index count in <p> element.");
|
nuclear@0
|
2038
|
nuclear@0
|
2039 // find the data for all sources
|
nuclear@0
|
2040 for( std::vector<InputChannel>::iterator it = pMesh->mPerVertexData.begin(); it != pMesh->mPerVertexData.end(); ++it)
|
nuclear@0
|
2041 {
|
nuclear@0
|
2042 InputChannel& input = *it;
|
nuclear@0
|
2043 if( input.mResolved)
|
nuclear@0
|
2044 continue;
|
nuclear@0
|
2045
|
nuclear@0
|
2046 // find accessor
|
nuclear@0
|
2047 input.mResolved = &ResolveLibraryReference( mAccessorLibrary, input.mAccessor);
|
nuclear@0
|
2048 // resolve accessor's data pointer as well, if neccessary
|
nuclear@0
|
2049 const Accessor* acc = input.mResolved;
|
nuclear@0
|
2050 if( !acc->mData)
|
nuclear@0
|
2051 acc->mData = &ResolveLibraryReference( mDataLibrary, acc->mSource);
|
nuclear@0
|
2052 }
|
nuclear@0
|
2053 // and the same for the per-index channels
|
nuclear@0
|
2054 for( std::vector<InputChannel>::iterator it = pPerIndexChannels.begin(); it != pPerIndexChannels.end(); ++it)
|
nuclear@0
|
2055 {
|
nuclear@0
|
2056 InputChannel& input = *it;
|
nuclear@0
|
2057 if( input.mResolved)
|
nuclear@0
|
2058 continue;
|
nuclear@0
|
2059
|
nuclear@0
|
2060 // ignore vertex pointer, it doesn't refer to an accessor
|
nuclear@0
|
2061 if( input.mType == IT_Vertex)
|
nuclear@0
|
2062 {
|
nuclear@0
|
2063 // warn if the vertex channel does not refer to the <vertices> element in the same mesh
|
nuclear@0
|
2064 if( input.mAccessor != pMesh->mVertexID)
|
nuclear@0
|
2065 ThrowException( "Unsupported vertex referencing scheme.");
|
nuclear@0
|
2066 continue;
|
nuclear@0
|
2067 }
|
nuclear@0
|
2068
|
nuclear@0
|
2069 // find accessor
|
nuclear@0
|
2070 input.mResolved = &ResolveLibraryReference( mAccessorLibrary, input.mAccessor);
|
nuclear@0
|
2071 // resolve accessor's data pointer as well, if neccessary
|
nuclear@0
|
2072 const Accessor* acc = input.mResolved;
|
nuclear@0
|
2073 if( !acc->mData)
|
nuclear@0
|
2074 acc->mData = &ResolveLibraryReference( mDataLibrary, acc->mSource);
|
nuclear@0
|
2075 }
|
nuclear@0
|
2076
|
nuclear@0
|
2077
|
nuclear@0
|
2078 // now assemble vertex data according to those indices
|
nuclear@0
|
2079 std::vector<size_t>::const_iterator idx = indices.begin();
|
nuclear@0
|
2080
|
nuclear@0
|
2081 // For continued primitives, the given count does not come all in one <p>, but only one primitive per <p>
|
nuclear@0
|
2082 size_t numPrimitives = pNumPrimitives;
|
nuclear@0
|
2083 if( pPrimType == Prim_TriFans || pPrimType == Prim_Polygon)
|
nuclear@0
|
2084 numPrimitives = 1;
|
nuclear@0
|
2085
|
nuclear@0
|
2086 pMesh->mFaceSize.reserve( numPrimitives);
|
nuclear@0
|
2087 pMesh->mFacePosIndices.reserve( indices.size() / numOffsets);
|
nuclear@0
|
2088
|
nuclear@0
|
2089 for( size_t a = 0; a < numPrimitives; a++)
|
nuclear@0
|
2090 {
|
nuclear@0
|
2091 // determine number of points for this primitive
|
nuclear@0
|
2092 size_t numPoints = 0;
|
nuclear@0
|
2093 switch( pPrimType)
|
nuclear@0
|
2094 {
|
nuclear@0
|
2095 case Prim_Lines:
|
nuclear@0
|
2096 numPoints = 2;
|
nuclear@0
|
2097 break;
|
nuclear@0
|
2098 case Prim_Triangles:
|
nuclear@0
|
2099 numPoints = 3;
|
nuclear@0
|
2100 break;
|
nuclear@0
|
2101 case Prim_Polylist:
|
nuclear@0
|
2102 numPoints = pVCount[a];
|
nuclear@0
|
2103 break;
|
nuclear@0
|
2104 case Prim_TriFans:
|
nuclear@0
|
2105 case Prim_Polygon:
|
nuclear@0
|
2106 numPoints = indices.size() / numOffsets;
|
nuclear@0
|
2107 break;
|
nuclear@0
|
2108 default:
|
nuclear@0
|
2109 // LineStrip and TriStrip not supported due to expected index unmangling
|
nuclear@0
|
2110 ThrowException( "Unsupported primitive type.");
|
nuclear@0
|
2111 break;
|
nuclear@0
|
2112 }
|
nuclear@0
|
2113
|
nuclear@0
|
2114 // store the face size to later reconstruct the face from
|
nuclear@0
|
2115 pMesh->mFaceSize.push_back( numPoints);
|
nuclear@0
|
2116
|
nuclear@0
|
2117 // gather that number of vertices
|
nuclear@0
|
2118 for( size_t b = 0; b < numPoints; b++)
|
nuclear@0
|
2119 {
|
nuclear@0
|
2120 // read all indices for this vertex. Yes, in a hacky local array
|
nuclear@0
|
2121 ai_assert( numOffsets < 20 && perVertexOffset < 20);
|
nuclear@0
|
2122 size_t vindex[20];
|
nuclear@0
|
2123 for( size_t offsets = 0; offsets < numOffsets; ++offsets)
|
nuclear@0
|
2124 vindex[offsets] = *idx++;
|
nuclear@0
|
2125
|
nuclear@0
|
2126 // extract per-vertex channels using the global per-vertex offset
|
nuclear@0
|
2127 for( std::vector<InputChannel>::iterator it = pMesh->mPerVertexData.begin(); it != pMesh->mPerVertexData.end(); ++it)
|
nuclear@0
|
2128 ExtractDataObjectFromChannel( *it, vindex[perVertexOffset], pMesh);
|
nuclear@0
|
2129 // and extract per-index channels using there specified offset
|
nuclear@0
|
2130 for( std::vector<InputChannel>::iterator it = pPerIndexChannels.begin(); it != pPerIndexChannels.end(); ++it)
|
nuclear@0
|
2131 ExtractDataObjectFromChannel( *it, vindex[it->mOffset], pMesh);
|
nuclear@0
|
2132
|
nuclear@0
|
2133 // store the vertex-data index for later assignment of bone vertex weights
|
nuclear@0
|
2134 pMesh->mFacePosIndices.push_back( vindex[perVertexOffset]);
|
nuclear@0
|
2135 }
|
nuclear@0
|
2136 }
|
nuclear@0
|
2137
|
nuclear@0
|
2138
|
nuclear@0
|
2139 // if I ever get my hands on that guy who invented this steaming pile of indirection...
|
nuclear@0
|
2140 TestClosing( "p");
|
nuclear@0
|
2141 }
|
nuclear@0
|
2142
|
nuclear@0
|
2143 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
2144 // Extracts a single object from an input channel and stores it in the appropriate mesh data array
|
nuclear@0
|
2145 void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, size_t pLocalIndex, Mesh* pMesh)
|
nuclear@0
|
2146 {
|
nuclear@0
|
2147 // ignore vertex referrer - we handle them that separate
|
nuclear@0
|
2148 if( pInput.mType == IT_Vertex)
|
nuclear@0
|
2149 return;
|
nuclear@0
|
2150
|
nuclear@0
|
2151 const Accessor& acc = *pInput.mResolved;
|
nuclear@0
|
2152 if( pLocalIndex >= acc.mCount)
|
nuclear@0
|
2153 ThrowException( boost::str( boost::format( "Invalid data index (%d/%d) in primitive specification") % pLocalIndex % acc.mCount));
|
nuclear@0
|
2154
|
nuclear@0
|
2155 // get a pointer to the start of the data object referred to by the accessor and the local index
|
nuclear@0
|
2156 const float* dataObject = &(acc.mData->mValues[0]) + acc.mOffset + pLocalIndex* acc.mStride;
|
nuclear@0
|
2157
|
nuclear@0
|
2158 // assemble according to the accessors component sub-offset list. We don't care, yet,
|
nuclear@0
|
2159 // what kind of object exactly we're extracting here
|
nuclear@0
|
2160 float obj[4];
|
nuclear@0
|
2161 for( size_t c = 0; c < 4; ++c)
|
nuclear@0
|
2162 obj[c] = dataObject[acc.mSubOffset[c]];
|
nuclear@0
|
2163
|
nuclear@0
|
2164 // now we reinterpret it according to the type we're reading here
|
nuclear@0
|
2165 switch( pInput.mType)
|
nuclear@0
|
2166 {
|
nuclear@0
|
2167 case IT_Position: // ignore all position streams except 0 - there can be only one position
|
nuclear@0
|
2168 if( pInput.mIndex == 0)
|
nuclear@0
|
2169 pMesh->mPositions.push_back( aiVector3D( obj[0], obj[1], obj[2]));
|
nuclear@0
|
2170 else
|
nuclear@0
|
2171 DefaultLogger::get()->error("Collada: just one vertex position stream supported");
|
nuclear@0
|
2172 break;
|
nuclear@0
|
2173 case IT_Normal:
|
nuclear@0
|
2174 // pad to current vertex count if necessary
|
nuclear@0
|
2175 if( pMesh->mNormals.size() < pMesh->mPositions.size()-1)
|
nuclear@0
|
2176 pMesh->mNormals.insert( pMesh->mNormals.end(), pMesh->mPositions.size() - pMesh->mNormals.size() - 1, aiVector3D( 0, 1, 0));
|
nuclear@0
|
2177
|
nuclear@0
|
2178 // ignore all normal streams except 0 - there can be only one normal
|
nuclear@0
|
2179 if( pInput.mIndex == 0)
|
nuclear@0
|
2180 pMesh->mNormals.push_back( aiVector3D( obj[0], obj[1], obj[2]));
|
nuclear@0
|
2181 else
|
nuclear@0
|
2182 DefaultLogger::get()->error("Collada: just one vertex normal stream supported");
|
nuclear@0
|
2183 break;
|
nuclear@0
|
2184 case IT_Tangent:
|
nuclear@0
|
2185 // pad to current vertex count if necessary
|
nuclear@0
|
2186 if( pMesh->mTangents.size() < pMesh->mPositions.size()-1)
|
nuclear@0
|
2187 pMesh->mTangents.insert( pMesh->mTangents.end(), pMesh->mPositions.size() - pMesh->mTangents.size() - 1, aiVector3D( 1, 0, 0));
|
nuclear@0
|
2188
|
nuclear@0
|
2189 // ignore all tangent streams except 0 - there can be only one tangent
|
nuclear@0
|
2190 if( pInput.mIndex == 0)
|
nuclear@0
|
2191 pMesh->mTangents.push_back( aiVector3D( obj[0], obj[1], obj[2]));
|
nuclear@0
|
2192 else
|
nuclear@0
|
2193 DefaultLogger::get()->error("Collada: just one vertex tangent stream supported");
|
nuclear@0
|
2194 break;
|
nuclear@0
|
2195 case IT_Bitangent:
|
nuclear@0
|
2196 // pad to current vertex count if necessary
|
nuclear@0
|
2197 if( pMesh->mBitangents.size() < pMesh->mPositions.size()-1)
|
nuclear@0
|
2198 pMesh->mBitangents.insert( pMesh->mBitangents.end(), pMesh->mPositions.size() - pMesh->mBitangents.size() - 1, aiVector3D( 0, 0, 1));
|
nuclear@0
|
2199
|
nuclear@0
|
2200 // ignore all bitangent streams except 0 - there can be only one bitangent
|
nuclear@0
|
2201 if( pInput.mIndex == 0)
|
nuclear@0
|
2202 pMesh->mBitangents.push_back( aiVector3D( obj[0], obj[1], obj[2]));
|
nuclear@0
|
2203 else
|
nuclear@0
|
2204 DefaultLogger::get()->error("Collada: just one vertex bitangent stream supported");
|
nuclear@0
|
2205 break;
|
nuclear@0
|
2206 case IT_Texcoord:
|
nuclear@0
|
2207 // up to 4 texture coord sets are fine, ignore the others
|
nuclear@0
|
2208 if( pInput.mIndex < AI_MAX_NUMBER_OF_TEXTURECOORDS)
|
nuclear@0
|
2209 {
|
nuclear@0
|
2210 // pad to current vertex count if necessary
|
nuclear@0
|
2211 if( pMesh->mTexCoords[pInput.mIndex].size() < pMesh->mPositions.size()-1)
|
nuclear@0
|
2212 pMesh->mTexCoords[pInput.mIndex].insert( pMesh->mTexCoords[pInput.mIndex].end(),
|
nuclear@0
|
2213 pMesh->mPositions.size() - pMesh->mTexCoords[pInput.mIndex].size() - 1, aiVector3D( 0, 0, 0));
|
nuclear@0
|
2214
|
nuclear@0
|
2215 pMesh->mTexCoords[pInput.mIndex].push_back( aiVector3D( obj[0], obj[1], obj[2]));
|
nuclear@0
|
2216 if (0 != acc.mSubOffset[2] || 0 != acc.mSubOffset[3]) /* hack ... consider cleaner solution */
|
nuclear@0
|
2217 pMesh->mNumUVComponents[pInput.mIndex]=3;
|
nuclear@0
|
2218 } else
|
nuclear@0
|
2219 {
|
nuclear@0
|
2220 DefaultLogger::get()->error("Collada: too many texture coordinate sets. Skipping.");
|
nuclear@0
|
2221 }
|
nuclear@0
|
2222 break;
|
nuclear@0
|
2223 case IT_Color:
|
nuclear@0
|
2224 // up to 4 color sets are fine, ignore the others
|
nuclear@0
|
2225 if( pInput.mIndex < AI_MAX_NUMBER_OF_COLOR_SETS)
|
nuclear@0
|
2226 {
|
nuclear@0
|
2227 // pad to current vertex count if necessary
|
nuclear@0
|
2228 if( pMesh->mColors[pInput.mIndex].size() < pMesh->mPositions.size()-1)
|
nuclear@0
|
2229 pMesh->mColors[pInput.mIndex].insert( pMesh->mColors[pInput.mIndex].end(),
|
nuclear@0
|
2230 pMesh->mPositions.size() - pMesh->mColors[pInput.mIndex].size() - 1, aiColor4D( 0, 0, 0, 1));
|
nuclear@0
|
2231
|
nuclear@0
|
2232 aiColor4D result(0, 0, 0, 1);
|
nuclear@0
|
2233 for (size_t i = 0; i < pInput.mResolved->mSize; ++i)
|
nuclear@0
|
2234 {
|
nuclear@0
|
2235 result[i] = obj[pInput.mResolved->mSubOffset[i]];
|
nuclear@0
|
2236 }
|
nuclear@0
|
2237 pMesh->mColors[pInput.mIndex].push_back(result);
|
nuclear@0
|
2238 } else
|
nuclear@0
|
2239 {
|
nuclear@0
|
2240 DefaultLogger::get()->error("Collada: too many vertex color sets. Skipping.");
|
nuclear@0
|
2241 }
|
nuclear@0
|
2242
|
nuclear@0
|
2243 break;
|
nuclear@0
|
2244 default:
|
nuclear@0
|
2245 // IT_Invalid and IT_Vertex
|
nuclear@0
|
2246 ai_assert(false && "shouldn't ever get here");
|
nuclear@0
|
2247 }
|
nuclear@0
|
2248 }
|
nuclear@0
|
2249
|
nuclear@0
|
2250 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
2251 // Reads the library of node hierarchies and scene parts
|
nuclear@0
|
2252 void ColladaParser::ReadSceneLibrary()
|
nuclear@0
|
2253 {
|
nuclear@0
|
2254 if( mReader->isEmptyElement())
|
nuclear@0
|
2255 return;
|
nuclear@0
|
2256
|
nuclear@0
|
2257 while( mReader->read())
|
nuclear@0
|
2258 {
|
nuclear@0
|
2259 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
2260 {
|
nuclear@0
|
2261 // a visual scene - generate root node under its ID and let ReadNode() do the recursive work
|
nuclear@0
|
2262 if( IsElement( "visual_scene"))
|
nuclear@0
|
2263 {
|
nuclear@0
|
2264 // read ID. Is optional according to the spec, but how on earth should a scene_instance refer to it then?
|
nuclear@0
|
2265 int indexID = GetAttribute( "id");
|
nuclear@0
|
2266 const char* attrID = mReader->getAttributeValue( indexID);
|
nuclear@0
|
2267
|
nuclear@0
|
2268 // read name if given.
|
nuclear@0
|
2269 int indexName = TestAttribute( "name");
|
nuclear@0
|
2270 const char* attrName = "unnamed";
|
nuclear@0
|
2271 if( indexName > -1)
|
nuclear@0
|
2272 attrName = mReader->getAttributeValue( indexName);
|
nuclear@0
|
2273
|
nuclear@0
|
2274 // create a node and store it in the library under its ID
|
nuclear@0
|
2275 Node* node = new Node;
|
nuclear@0
|
2276 node->mID = attrID;
|
nuclear@0
|
2277 node->mName = attrName;
|
nuclear@0
|
2278 mNodeLibrary[node->mID] = node;
|
nuclear@0
|
2279
|
nuclear@0
|
2280 ReadSceneNode( node);
|
nuclear@0
|
2281 } else
|
nuclear@0
|
2282 {
|
nuclear@0
|
2283 // ignore the rest
|
nuclear@0
|
2284 SkipElement();
|
nuclear@0
|
2285 }
|
nuclear@0
|
2286 }
|
nuclear@0
|
2287 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
nuclear@0
|
2288 {
|
nuclear@0
|
2289 if( strcmp( mReader->getNodeName(), "library_visual_scenes") == 0)
|
nuclear@0
|
2290 //ThrowException( "Expected end of \"library_visual_scenes\" element.");
|
nuclear@0
|
2291
|
nuclear@0
|
2292 break;
|
nuclear@0
|
2293 }
|
nuclear@0
|
2294 }
|
nuclear@0
|
2295 }
|
nuclear@0
|
2296
|
nuclear@0
|
2297 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
2298 // Reads a scene node's contents including children and stores it in the given node
|
nuclear@0
|
2299 void ColladaParser::ReadSceneNode( Node* pNode)
|
nuclear@0
|
2300 {
|
nuclear@0
|
2301 // quit immediately on <bla/> elements
|
nuclear@0
|
2302 if( mReader->isEmptyElement())
|
nuclear@0
|
2303 return;
|
nuclear@0
|
2304
|
nuclear@0
|
2305 while( mReader->read())
|
nuclear@0
|
2306 {
|
nuclear@0
|
2307 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
2308 {
|
nuclear@0
|
2309 if( IsElement( "node"))
|
nuclear@0
|
2310 {
|
nuclear@0
|
2311 Node* child = new Node;
|
nuclear@0
|
2312 int attrID = TestAttribute( "id");
|
nuclear@0
|
2313 if( attrID > -1)
|
nuclear@0
|
2314 child->mID = mReader->getAttributeValue( attrID);
|
nuclear@0
|
2315 int attrSID = TestAttribute( "sid");
|
nuclear@0
|
2316 if( attrSID > -1)
|
nuclear@0
|
2317 child->mSID = mReader->getAttributeValue( attrSID);
|
nuclear@0
|
2318
|
nuclear@0
|
2319 int attrName = TestAttribute( "name");
|
nuclear@0
|
2320 if( attrName > -1)
|
nuclear@0
|
2321 child->mName = mReader->getAttributeValue( attrName);
|
nuclear@0
|
2322
|
nuclear@0
|
2323 // TODO: (thom) support SIDs
|
nuclear@0
|
2324 // ai_assert( TestAttribute( "sid") == -1);
|
nuclear@0
|
2325
|
nuclear@0
|
2326 if (pNode)
|
nuclear@0
|
2327 {
|
nuclear@0
|
2328 pNode->mChildren.push_back( child);
|
nuclear@0
|
2329 child->mParent = pNode;
|
nuclear@0
|
2330 }
|
nuclear@0
|
2331 else
|
nuclear@0
|
2332 {
|
nuclear@0
|
2333 // no parent node given, probably called from <library_nodes> element.
|
nuclear@0
|
2334 // create new node in node library
|
nuclear@0
|
2335 mNodeLibrary[child->mID] = child;
|
nuclear@0
|
2336 }
|
nuclear@0
|
2337
|
nuclear@0
|
2338 // read on recursively from there
|
nuclear@0
|
2339 ReadSceneNode( child);
|
nuclear@0
|
2340 continue;
|
nuclear@0
|
2341 }
|
nuclear@0
|
2342 // For any further stuff we need a valid node to work on
|
nuclear@0
|
2343 else if (!pNode)
|
nuclear@0
|
2344 continue;
|
nuclear@0
|
2345
|
nuclear@0
|
2346 if( IsElement( "lookat"))
|
nuclear@0
|
2347 ReadNodeTransformation( pNode, TF_LOOKAT);
|
nuclear@0
|
2348 else if( IsElement( "matrix"))
|
nuclear@0
|
2349 ReadNodeTransformation( pNode, TF_MATRIX);
|
nuclear@0
|
2350 else if( IsElement( "rotate"))
|
nuclear@0
|
2351 ReadNodeTransformation( pNode, TF_ROTATE);
|
nuclear@0
|
2352 else if( IsElement( "scale"))
|
nuclear@0
|
2353 ReadNodeTransformation( pNode, TF_SCALE);
|
nuclear@0
|
2354 else if( IsElement( "skew"))
|
nuclear@0
|
2355 ReadNodeTransformation( pNode, TF_SKEW);
|
nuclear@0
|
2356 else if( IsElement( "translate"))
|
nuclear@0
|
2357 ReadNodeTransformation( pNode, TF_TRANSLATE);
|
nuclear@0
|
2358 else if( IsElement( "render") && pNode->mParent == NULL && 0 == pNode->mPrimaryCamera.length())
|
nuclear@0
|
2359 {
|
nuclear@0
|
2360 // ... scene evaluation or, in other words, postprocessing pipeline,
|
nuclear@0
|
2361 // or, again in other words, a turing-complete description how to
|
nuclear@0
|
2362 // render a Collada scene. The only thing that is interesting for
|
nuclear@0
|
2363 // us is the primary camera.
|
nuclear@0
|
2364 int attrId = TestAttribute("camera_node");
|
nuclear@0
|
2365 if (-1 != attrId)
|
nuclear@0
|
2366 {
|
nuclear@0
|
2367 const char* s = mReader->getAttributeValue(attrId);
|
nuclear@0
|
2368 if (s[0] != '#')
|
nuclear@0
|
2369 DefaultLogger::get()->error("Collada: Unresolved reference format of camera");
|
nuclear@0
|
2370 else
|
nuclear@0
|
2371 pNode->mPrimaryCamera = s+1;
|
nuclear@0
|
2372 }
|
nuclear@0
|
2373 }
|
nuclear@0
|
2374 else if( IsElement( "instance_node"))
|
nuclear@0
|
2375 {
|
nuclear@0
|
2376 // find the node in the library
|
nuclear@0
|
2377 int attrID = TestAttribute( "url");
|
nuclear@0
|
2378 if( attrID != -1)
|
nuclear@0
|
2379 {
|
nuclear@0
|
2380 const char* s = mReader->getAttributeValue(attrID);
|
nuclear@0
|
2381 if (s[0] != '#')
|
nuclear@0
|
2382 DefaultLogger::get()->error("Collada: Unresolved reference format of node");
|
nuclear@0
|
2383 else
|
nuclear@0
|
2384 {
|
nuclear@0
|
2385 pNode->mNodeInstances.push_back(NodeInstance());
|
nuclear@0
|
2386 pNode->mNodeInstances.back().mNode = s+1;
|
nuclear@0
|
2387 }
|
nuclear@0
|
2388 }
|
nuclear@0
|
2389 }
|
nuclear@0
|
2390 else if( IsElement( "instance_geometry") || IsElement( "instance_controller"))
|
nuclear@0
|
2391 {
|
nuclear@0
|
2392 // Reference to a mesh or controller, with possible material associations
|
nuclear@0
|
2393 ReadNodeGeometry( pNode);
|
nuclear@0
|
2394 }
|
nuclear@0
|
2395 else if( IsElement( "instance_light"))
|
nuclear@0
|
2396 {
|
nuclear@0
|
2397 // Reference to a light, name given in 'url' attribute
|
nuclear@0
|
2398 int attrID = TestAttribute("url");
|
nuclear@0
|
2399 if (-1 == attrID)
|
nuclear@0
|
2400 DefaultLogger::get()->warn("Collada: Expected url attribute in <instance_light> element");
|
nuclear@0
|
2401 else
|
nuclear@0
|
2402 {
|
nuclear@0
|
2403 const char* url = mReader->getAttributeValue( attrID);
|
nuclear@0
|
2404 if( url[0] != '#')
|
nuclear@0
|
2405 ThrowException( "Unknown reference format in <instance_light> element");
|
nuclear@0
|
2406
|
nuclear@0
|
2407 pNode->mLights.push_back(LightInstance());
|
nuclear@0
|
2408 pNode->mLights.back().mLight = url+1;
|
nuclear@0
|
2409 }
|
nuclear@0
|
2410 }
|
nuclear@0
|
2411 else if( IsElement( "instance_camera"))
|
nuclear@0
|
2412 {
|
nuclear@0
|
2413 // Reference to a camera, name given in 'url' attribute
|
nuclear@0
|
2414 int attrID = TestAttribute("url");
|
nuclear@0
|
2415 if (-1 == attrID)
|
nuclear@0
|
2416 DefaultLogger::get()->warn("Collada: Expected url attribute in <instance_camera> element");
|
nuclear@0
|
2417 else
|
nuclear@0
|
2418 {
|
nuclear@0
|
2419 const char* url = mReader->getAttributeValue( attrID);
|
nuclear@0
|
2420 if( url[0] != '#')
|
nuclear@0
|
2421 ThrowException( "Unknown reference format in <instance_camera> element");
|
nuclear@0
|
2422
|
nuclear@0
|
2423 pNode->mCameras.push_back(CameraInstance());
|
nuclear@0
|
2424 pNode->mCameras.back().mCamera = url+1;
|
nuclear@0
|
2425 }
|
nuclear@0
|
2426 }
|
nuclear@0
|
2427 else
|
nuclear@0
|
2428 {
|
nuclear@0
|
2429 // skip everything else for the moment
|
nuclear@0
|
2430 SkipElement();
|
nuclear@0
|
2431 }
|
nuclear@0
|
2432 }
|
nuclear@0
|
2433 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
|
nuclear@0
|
2434 break;
|
nuclear@0
|
2435 }
|
nuclear@0
|
2436 }
|
nuclear@0
|
2437 }
|
nuclear@0
|
2438
|
nuclear@0
|
2439 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
2440 // Reads a node transformation entry of the given type and adds it to the given node's transformation list.
|
nuclear@0
|
2441 void ColladaParser::ReadNodeTransformation( Node* pNode, TransformType pType)
|
nuclear@0
|
2442 {
|
nuclear@0
|
2443 if( mReader->isEmptyElement())
|
nuclear@0
|
2444 return;
|
nuclear@0
|
2445
|
nuclear@0
|
2446 std::string tagName = mReader->getNodeName();
|
nuclear@0
|
2447
|
nuclear@0
|
2448 Transform tf;
|
nuclear@0
|
2449 tf.mType = pType;
|
nuclear@0
|
2450
|
nuclear@0
|
2451 // read SID
|
nuclear@0
|
2452 int indexSID = TestAttribute( "sid");
|
nuclear@0
|
2453 if( indexSID >= 0)
|
nuclear@0
|
2454 tf.mID = mReader->getAttributeValue( indexSID);
|
nuclear@0
|
2455
|
nuclear@0
|
2456 // how many parameters to read per transformation type
|
nuclear@0
|
2457 static const unsigned int sNumParameters[] = { 9, 4, 3, 3, 7, 16 };
|
nuclear@0
|
2458 const char* content = GetTextContent();
|
nuclear@0
|
2459
|
nuclear@0
|
2460 // read as many parameters and store in the transformation
|
nuclear@0
|
2461 for( unsigned int a = 0; a < sNumParameters[pType]; a++)
|
nuclear@0
|
2462 {
|
nuclear@0
|
2463 // read a number
|
nuclear@0
|
2464 content = fast_atoreal_move<float>( content, tf.f[a]);
|
nuclear@0
|
2465 // skip whitespace after it
|
nuclear@0
|
2466 SkipSpacesAndLineEnd( &content);
|
nuclear@0
|
2467 }
|
nuclear@0
|
2468
|
nuclear@0
|
2469 // place the transformation at the queue of the node
|
nuclear@0
|
2470 pNode->mTransforms.push_back( tf);
|
nuclear@0
|
2471
|
nuclear@0
|
2472 // and consume the closing tag
|
nuclear@0
|
2473 TestClosing( tagName.c_str());
|
nuclear@0
|
2474 }
|
nuclear@0
|
2475
|
nuclear@0
|
2476 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
2477 // Processes bind_vertex_input and bind elements
|
nuclear@0
|
2478 void ColladaParser::ReadMaterialVertexInputBinding( Collada::SemanticMappingTable& tbl)
|
nuclear@0
|
2479 {
|
nuclear@0
|
2480 while( mReader->read())
|
nuclear@0
|
2481 {
|
nuclear@0
|
2482 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
|
nuclear@0
|
2483 if( IsElement( "bind_vertex_input"))
|
nuclear@0
|
2484 {
|
nuclear@0
|
2485 Collada::InputSemanticMapEntry vn;
|
nuclear@0
|
2486
|
nuclear@0
|
2487 // effect semantic
|
nuclear@0
|
2488 int n = GetAttribute("semantic");
|
nuclear@0
|
2489 std::string s = mReader->getAttributeValue(n);
|
nuclear@0
|
2490
|
nuclear@0
|
2491 // input semantic
|
nuclear@0
|
2492 n = GetAttribute("input_semantic");
|
nuclear@0
|
2493 vn.mType = GetTypeForSemantic( mReader->getAttributeValue(n) );
|
nuclear@0
|
2494
|
nuclear@0
|
2495 // index of input set
|
nuclear@0
|
2496 n = TestAttribute("input_set");
|
nuclear@0
|
2497 if (-1 != n)
|
nuclear@0
|
2498 vn.mSet = mReader->getAttributeValueAsInt(n);
|
nuclear@0
|
2499
|
nuclear@0
|
2500 tbl.mMap[s] = vn;
|
nuclear@0
|
2501 }
|
nuclear@0
|
2502 else if( IsElement( "bind")) {
|
nuclear@0
|
2503 DefaultLogger::get()->warn("Collada: Found unsupported <bind> element");
|
nuclear@0
|
2504 }
|
nuclear@0
|
2505 }
|
nuclear@0
|
2506 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
|
nuclear@0
|
2507 if( strcmp( mReader->getNodeName(), "instance_material") == 0)
|
nuclear@0
|
2508 break;
|
nuclear@0
|
2509 }
|
nuclear@0
|
2510 }
|
nuclear@0
|
2511 }
|
nuclear@0
|
2512
|
nuclear@0
|
2513 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
2514 // Reads a mesh reference in a node and adds it to the node's mesh list
|
nuclear@0
|
2515 void ColladaParser::ReadNodeGeometry( Node* pNode)
|
nuclear@0
|
2516 {
|
nuclear@0
|
2517 // referred mesh is given as an attribute of the <instance_geometry> element
|
nuclear@0
|
2518 int attrUrl = GetAttribute( "url");
|
nuclear@0
|
2519 const char* url = mReader->getAttributeValue( attrUrl);
|
nuclear@0
|
2520 if( url[0] != '#')
|
nuclear@0
|
2521 ThrowException( "Unknown reference format");
|
nuclear@0
|
2522
|
nuclear@0
|
2523 Collada::MeshInstance instance;
|
nuclear@0
|
2524 instance.mMeshOrController = url+1; // skipping the leading #
|
nuclear@0
|
2525
|
nuclear@0
|
2526 if( !mReader->isEmptyElement())
|
nuclear@0
|
2527 {
|
nuclear@0
|
2528 // read material associations. Ignore additional elements inbetween
|
nuclear@0
|
2529 while( mReader->read())
|
nuclear@0
|
2530 {
|
nuclear@0
|
2531 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
nuclear@0
|
2532 {
|
nuclear@0
|
2533 if( IsElement( "instance_material"))
|
nuclear@0
|
2534 {
|
nuclear@0
|
2535 // read ID of the geometry subgroup and the target material
|
nuclear@0
|
2536 int attrGroup = GetAttribute( "symbol");
|
nuclear@0
|
2537 std::string group = mReader->getAttributeValue( attrGroup);
|
nuclear@0
|
2538 int attrMaterial = GetAttribute( "target");
|
nuclear@0
|
2539 const char* urlMat = mReader->getAttributeValue( attrMaterial);
|
nuclear@0
|
2540 Collada::SemanticMappingTable s;
|
nuclear@0
|
2541 if( urlMat[0] == '#')
|
nuclear@0
|
2542 urlMat++;
|
nuclear@0
|
2543
|
nuclear@0
|
2544 s.mMatName = urlMat;
|
nuclear@0
|
2545
|
nuclear@0
|
2546 // resolve further material details + THIS UGLY AND NASTY semantic mapping stuff
|
nuclear@0
|
2547 if( !mReader->isEmptyElement())
|
nuclear@0
|
2548 ReadMaterialVertexInputBinding(s);
|
nuclear@0
|
2549
|
nuclear@0
|
2550 // store the association
|
nuclear@0
|
2551 instance.mMaterials[group] = s;
|
nuclear@0
|
2552 }
|
nuclear@0
|
2553 }
|
nuclear@0
|
2554 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
nuclear@0
|
2555 {
|
nuclear@0
|
2556 if( strcmp( mReader->getNodeName(), "instance_geometry") == 0
|
nuclear@0
|
2557 || strcmp( mReader->getNodeName(), "instance_controller") == 0)
|
nuclear@0
|
2558 break;
|
nuclear@0
|
2559 }
|
nuclear@0
|
2560 }
|
nuclear@0
|
2561 }
|
nuclear@0
|
2562
|
nuclear@0
|
2563 // store it
|
nuclear@0
|
2564 pNode->mMeshes.push_back( instance);
|
nuclear@0
|
2565 }
|
nuclear@0
|
2566
|
nuclear@0
|
2567 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
2568 // Reads the collada scene
|
nuclear@0
|
2569 void ColladaParser::ReadScene()
|
nuclear@0
|
2570 {
|
nuclear@0
|
2571 if( mReader->isEmptyElement())
|
nuclear@0
|
2572 return;
|
nuclear@0
|
2573
|
nuclear@0
|
2574 while( mReader->read())
|
nuclear@0
|
2575 {
|
nuclear@0
|
2576 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
|
nuclear@0
|
2577 if( IsElement( "instance_visual_scene"))
|
nuclear@0
|
2578 {
|
nuclear@0
|
2579 // should be the first and only occurence
|
nuclear@0
|
2580 if( mRootNode)
|
nuclear@0
|
2581 ThrowException( "Invalid scene containing multiple root nodes in <instance_visual_scene> element");
|
nuclear@0
|
2582
|
nuclear@0
|
2583 // read the url of the scene to instance. Should be of format "#some_name"
|
nuclear@0
|
2584 int urlIndex = GetAttribute( "url");
|
nuclear@0
|
2585 const char* url = mReader->getAttributeValue( urlIndex);
|
nuclear@0
|
2586 if( url[0] != '#')
|
nuclear@0
|
2587 ThrowException( "Unknown reference format in <instance_visual_scene> element");
|
nuclear@0
|
2588
|
nuclear@0
|
2589 // find the referred scene, skip the leading #
|
nuclear@0
|
2590 NodeLibrary::const_iterator sit = mNodeLibrary.find( url+1);
|
nuclear@0
|
2591 if( sit == mNodeLibrary.end())
|
nuclear@0
|
2592 ThrowException( "Unable to resolve visual_scene reference \"" + std::string(url) + "\" in <instance_visual_scene> element.");
|
nuclear@0
|
2593 mRootNode = sit->second;
|
nuclear@0
|
2594 } else {
|
nuclear@0
|
2595 SkipElement();
|
nuclear@0
|
2596 }
|
nuclear@0
|
2597 }
|
nuclear@0
|
2598 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END){
|
nuclear@0
|
2599 break;
|
nuclear@0
|
2600 }
|
nuclear@0
|
2601 }
|
nuclear@0
|
2602 }
|
nuclear@0
|
2603
|
nuclear@0
|
2604 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
2605 // Aborts the file reading with an exception
|
nuclear@0
|
2606 void ColladaParser::ThrowException( const std::string& pError) const
|
nuclear@0
|
2607 {
|
nuclear@0
|
2608 throw DeadlyImportError( boost::str( boost::format( "Collada: %s - %s") % mFileName % pError));
|
nuclear@0
|
2609 }
|
nuclear@0
|
2610
|
nuclear@0
|
2611 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
2612 // Skips all data until the end node of the current element
|
nuclear@0
|
2613 void ColladaParser::SkipElement()
|
nuclear@0
|
2614 {
|
nuclear@0
|
2615 // nothing to skip if it's an <element />
|
nuclear@0
|
2616 if( mReader->isEmptyElement())
|
nuclear@0
|
2617 return;
|
nuclear@0
|
2618
|
nuclear@0
|
2619 // reroute
|
nuclear@0
|
2620 SkipElement( mReader->getNodeName());
|
nuclear@0
|
2621 }
|
nuclear@0
|
2622
|
nuclear@0
|
2623 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
2624 // Skips all data until the end node of the given element
|
nuclear@0
|
2625 void ColladaParser::SkipElement( const char* pElement)
|
nuclear@0
|
2626 {
|
nuclear@0
|
2627 // copy the current node's name because it'a pointer to the reader's internal buffer,
|
nuclear@0
|
2628 // which is going to change with the upcoming parsing
|
nuclear@0
|
2629 std::string element = pElement;
|
nuclear@0
|
2630 while( mReader->read())
|
nuclear@0
|
2631 {
|
nuclear@0
|
2632 if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
nuclear@0
|
2633 if( mReader->getNodeName() == element)
|
nuclear@0
|
2634 break;
|
nuclear@0
|
2635 }
|
nuclear@0
|
2636 }
|
nuclear@0
|
2637
|
nuclear@0
|
2638 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
2639 // Tests for an opening element of the given name, throws an exception if not found
|
nuclear@0
|
2640 void ColladaParser::TestOpening( const char* pName)
|
nuclear@0
|
2641 {
|
nuclear@0
|
2642 // read element start
|
nuclear@0
|
2643 if( !mReader->read())
|
nuclear@0
|
2644 ThrowException( boost::str( boost::format( "Unexpected end of file while beginning of <%s> element.") % pName));
|
nuclear@0
|
2645 // whitespace in front is ok, just read again if found
|
nuclear@0
|
2646 if( mReader->getNodeType() == irr::io::EXN_TEXT)
|
nuclear@0
|
2647 if( !mReader->read())
|
nuclear@0
|
2648 ThrowException( boost::str( boost::format( "Unexpected end of file while reading beginning of <%s> element.") % pName));
|
nuclear@0
|
2649
|
nuclear@0
|
2650 if( mReader->getNodeType() != irr::io::EXN_ELEMENT || strcmp( mReader->getNodeName(), pName) != 0)
|
nuclear@0
|
2651 ThrowException( boost::str( boost::format( "Expected start of <%s> element.") % pName));
|
nuclear@0
|
2652 }
|
nuclear@0
|
2653
|
nuclear@0
|
2654 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
2655 // Tests for the closing tag of the given element, throws an exception if not found
|
nuclear@0
|
2656 void ColladaParser::TestClosing( const char* pName)
|
nuclear@0
|
2657 {
|
nuclear@0
|
2658 // check if we're already on the closing tag and return right away
|
nuclear@0
|
2659 if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END && strcmp( mReader->getNodeName(), pName) == 0)
|
nuclear@0
|
2660 return;
|
nuclear@0
|
2661
|
nuclear@0
|
2662 // if not, read some more
|
nuclear@0
|
2663 if( !mReader->read())
|
nuclear@0
|
2664 ThrowException( boost::str( boost::format( "Unexpected end of file while reading end of <%s> element.") % pName));
|
nuclear@0
|
2665 // whitespace in front is ok, just read again if found
|
nuclear@0
|
2666 if( mReader->getNodeType() == irr::io::EXN_TEXT)
|
nuclear@0
|
2667 if( !mReader->read())
|
nuclear@0
|
2668 ThrowException( boost::str( boost::format( "Unexpected end of file while reading end of <%s> element.") % pName));
|
nuclear@0
|
2669
|
nuclear@0
|
2670 // but this has the be the closing tag, or we're lost
|
nuclear@0
|
2671 if( mReader->getNodeType() != irr::io::EXN_ELEMENT_END || strcmp( mReader->getNodeName(), pName) != 0)
|
nuclear@0
|
2672 ThrowException( boost::str( boost::format( "Expected end of <%s> element.") % pName));
|
nuclear@0
|
2673 }
|
nuclear@0
|
2674
|
nuclear@0
|
2675 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
2676 // Returns the index of the named attribute or -1 if not found. Does not throw, therefore useful for optional attributes
|
nuclear@0
|
2677 int ColladaParser::GetAttribute( const char* pAttr) const
|
nuclear@0
|
2678 {
|
nuclear@0
|
2679 int index = TestAttribute( pAttr);
|
nuclear@0
|
2680 if( index != -1)
|
nuclear@0
|
2681 return index;
|
nuclear@0
|
2682
|
nuclear@0
|
2683 // attribute not found -> throw an exception
|
nuclear@0
|
2684 ThrowException( boost::str( boost::format( "Expected attribute \"%s\" for element <%s>.") % pAttr % mReader->getNodeName()));
|
nuclear@0
|
2685 return -1;
|
nuclear@0
|
2686 }
|
nuclear@0
|
2687
|
nuclear@0
|
2688 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
2689 // Tests the present element for the presence of one attribute, returns its index or throws an exception if not found
|
nuclear@0
|
2690 int ColladaParser::TestAttribute( const char* pAttr) const
|
nuclear@0
|
2691 {
|
nuclear@0
|
2692 for( int a = 0; a < mReader->getAttributeCount(); a++)
|
nuclear@0
|
2693 if( strcmp( mReader->getAttributeName( a), pAttr) == 0)
|
nuclear@0
|
2694 return a;
|
nuclear@0
|
2695
|
nuclear@0
|
2696 return -1;
|
nuclear@0
|
2697 }
|
nuclear@0
|
2698
|
nuclear@0
|
2699 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
2700 // Reads the text contents of an element, throws an exception if not given. Skips leading whitespace.
|
nuclear@0
|
2701 const char* ColladaParser::GetTextContent()
|
nuclear@0
|
2702 {
|
nuclear@0
|
2703 const char* sz = TestTextContent();
|
nuclear@0
|
2704 if(!sz) {
|
nuclear@0
|
2705 ThrowException( "Invalid contents in element \"n\".");
|
nuclear@0
|
2706 }
|
nuclear@0
|
2707 return sz;
|
nuclear@0
|
2708 }
|
nuclear@0
|
2709
|
nuclear@0
|
2710 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
2711 // Reads the text contents of an element, returns NULL if not given. Skips leading whitespace.
|
nuclear@0
|
2712 const char* ColladaParser::TestTextContent()
|
nuclear@0
|
2713 {
|
nuclear@0
|
2714 // present node should be the beginning of an element
|
nuclear@0
|
2715 if( mReader->getNodeType() != irr::io::EXN_ELEMENT || mReader->isEmptyElement())
|
nuclear@0
|
2716 return NULL;
|
nuclear@0
|
2717
|
nuclear@0
|
2718 // read contents of the element
|
nuclear@0
|
2719 if( !mReader->read() )
|
nuclear@0
|
2720 return NULL;
|
nuclear@0
|
2721 if( mReader->getNodeType() != irr::io::EXN_TEXT)
|
nuclear@0
|
2722 return NULL;
|
nuclear@0
|
2723
|
nuclear@0
|
2724 // skip leading whitespace
|
nuclear@0
|
2725 const char* text = mReader->getNodeData();
|
nuclear@0
|
2726 SkipSpacesAndLineEnd( &text);
|
nuclear@0
|
2727
|
nuclear@0
|
2728 return text;
|
nuclear@0
|
2729 }
|
nuclear@0
|
2730
|
nuclear@0
|
2731 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
2732 // Calculates the resulting transformation fromm all the given transform steps
|
nuclear@0
|
2733 aiMatrix4x4 ColladaParser::CalculateResultTransform( const std::vector<Transform>& pTransforms) const
|
nuclear@0
|
2734 {
|
nuclear@0
|
2735 aiMatrix4x4 res;
|
nuclear@0
|
2736
|
nuclear@0
|
2737 for( std::vector<Transform>::const_iterator it = pTransforms.begin(); it != pTransforms.end(); ++it)
|
nuclear@0
|
2738 {
|
nuclear@0
|
2739 const Transform& tf = *it;
|
nuclear@0
|
2740 switch( tf.mType)
|
nuclear@0
|
2741 {
|
nuclear@0
|
2742 case TF_LOOKAT:
|
nuclear@0
|
2743 {
|
nuclear@0
|
2744 aiVector3D pos( tf.f[0], tf.f[1], tf.f[2]);
|
nuclear@0
|
2745 aiVector3D dstPos( tf.f[3], tf.f[4], tf.f[5]);
|
nuclear@0
|
2746 aiVector3D up = aiVector3D( tf.f[6], tf.f[7], tf.f[8]).Normalize();
|
nuclear@0
|
2747 aiVector3D dir = aiVector3D( dstPos - pos).Normalize();
|
nuclear@0
|
2748 aiVector3D right = (dir ^ up).Normalize();
|
nuclear@0
|
2749
|
nuclear@0
|
2750 res *= aiMatrix4x4(
|
nuclear@0
|
2751 right.x, up.x, -dir.x, pos.x,
|
nuclear@0
|
2752 right.y, up.y, -dir.y, pos.y,
|
nuclear@0
|
2753 right.z, up.z, -dir.z, pos.z,
|
nuclear@0
|
2754 0, 0, 0, 1);
|
nuclear@0
|
2755 break;
|
nuclear@0
|
2756 }
|
nuclear@0
|
2757 case TF_ROTATE:
|
nuclear@0
|
2758 {
|
nuclear@0
|
2759 aiMatrix4x4 rot;
|
nuclear@0
|
2760 float angle = tf.f[3] * float( AI_MATH_PI) / 180.0f;
|
nuclear@0
|
2761 aiVector3D axis( tf.f[0], tf.f[1], tf.f[2]);
|
nuclear@0
|
2762 aiMatrix4x4::Rotation( angle, axis, rot);
|
nuclear@0
|
2763 res *= rot;
|
nuclear@0
|
2764 break;
|
nuclear@0
|
2765 }
|
nuclear@0
|
2766 case TF_TRANSLATE:
|
nuclear@0
|
2767 {
|
nuclear@0
|
2768 aiMatrix4x4 trans;
|
nuclear@0
|
2769 aiMatrix4x4::Translation( aiVector3D( tf.f[0], tf.f[1], tf.f[2]), trans);
|
nuclear@0
|
2770 res *= trans;
|
nuclear@0
|
2771 break;
|
nuclear@0
|
2772 }
|
nuclear@0
|
2773 case TF_SCALE:
|
nuclear@0
|
2774 {
|
nuclear@0
|
2775 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,
|
nuclear@0
|
2776 0.0f, 0.0f, 0.0f, 1.0f);
|
nuclear@0
|
2777 res *= scale;
|
nuclear@0
|
2778 break;
|
nuclear@0
|
2779 }
|
nuclear@0
|
2780 case TF_SKEW:
|
nuclear@0
|
2781 // TODO: (thom)
|
nuclear@0
|
2782 ai_assert( false);
|
nuclear@0
|
2783 break;
|
nuclear@0
|
2784 case TF_MATRIX:
|
nuclear@0
|
2785 {
|
nuclear@0
|
2786 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],
|
nuclear@0
|
2787 tf.f[8], tf.f[9], tf.f[10], tf.f[11], tf.f[12], tf.f[13], tf.f[14], tf.f[15]);
|
nuclear@0
|
2788 res *= mat;
|
nuclear@0
|
2789 break;
|
nuclear@0
|
2790 }
|
nuclear@0
|
2791 default:
|
nuclear@0
|
2792 ai_assert( false);
|
nuclear@0
|
2793 break;
|
nuclear@0
|
2794 }
|
nuclear@0
|
2795 }
|
nuclear@0
|
2796
|
nuclear@0
|
2797 return res;
|
nuclear@0
|
2798 }
|
nuclear@0
|
2799
|
nuclear@0
|
2800 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
2801 // Determines the input data type for the given semantic string
|
nuclear@0
|
2802 Collada::InputType ColladaParser::GetTypeForSemantic( const std::string& pSemantic)
|
nuclear@0
|
2803 {
|
nuclear@0
|
2804 if( pSemantic == "POSITION")
|
nuclear@0
|
2805 return IT_Position;
|
nuclear@0
|
2806 else if( pSemantic == "TEXCOORD")
|
nuclear@0
|
2807 return IT_Texcoord;
|
nuclear@0
|
2808 else if( pSemantic == "NORMAL")
|
nuclear@0
|
2809 return IT_Normal;
|
nuclear@0
|
2810 else if( pSemantic == "COLOR")
|
nuclear@0
|
2811 return IT_Color;
|
nuclear@0
|
2812 else if( pSemantic == "VERTEX")
|
nuclear@0
|
2813 return IT_Vertex;
|
nuclear@0
|
2814 else if( pSemantic == "BINORMAL" || pSemantic == "TEXBINORMAL")
|
nuclear@0
|
2815 return IT_Bitangent;
|
nuclear@0
|
2816 else if( pSemantic == "TANGENT" || pSemantic == "TEXTANGENT")
|
nuclear@0
|
2817 return IT_Tangent;
|
nuclear@0
|
2818
|
nuclear@0
|
2819 DefaultLogger::get()->warn( boost::str( boost::format( "Unknown vertex input type \"%s\". Ignoring.") % pSemantic));
|
nuclear@0
|
2820 return IT_Invalid;
|
nuclear@0
|
2821 }
|
nuclear@0
|
2822
|
nuclear@0
|
2823 #endif // !! ASSIMP_BUILD_NO_DAE_IMPORTER
|