1 /*
2     Copyright (c) 2008-2009 NetAllied Systems GmbH
3 
4     This file is part of COLLADASaxFrameworkLoader.
5 
6     Licensed under the MIT Open Source License,
7     for details please see LICENSE file or the website
8     http://www.opensource.org/licenses/mit-license.php
9 */
10 
11 #include "COLLADASaxFWLStableHeaders.h"
12 #include "COLLADASaxFWLSplineLoader.h"
13 #include "COLLADASaxFWLGeometryMaterialIdInfo.h"
14 #include "COLLADASaxFWLLoader.h"
15 #include "COLLADASaxFWLFileLoader.h"
16 
17 #include "COLLADAFWTriangles.h"
18 #include "COLLADAFWLines.h"
19 #include "COLLADAFWTristrips.h"
20 #include "COLLADAFWTrifans.h"
21 #include "COLLADAFWPolygons.h"
22 #include "COLLADAFWLinestrips.h"
23 #include "COLLADAFWIWriter.h"
24 
25 #include <fstream>
26 
27 
28 namespace COLLADASaxFWL
29 {
30 
SplineLoader(IFilePartLoader * callingFilePartLoader,const String & geometryId,const String & geometryName)31 	SplineLoader::SplineLoader( IFilePartLoader* callingFilePartLoader, const String& geometryId, const String& geometryName )
32 		: SourceArrayLoader (callingFilePartLoader )
33 		, mSplineUniqueId(createUniqueIdFromId((ParserChar*)geometryId.c_str(), COLLADAFW::Geometry::ID()))
34 		, mSpline ( new COLLADAFW::Spline(mSplineUniqueId) )
35         , mInterpolations()
36         , mVerticesInputs()
37         , mCurrentVertexInput( 0 )
38         , mInVertices ( false )
39         , mInSpline (true)
40 	{
41         if ( !geometryName.empty() )
42             mSpline->setName ( geometryName );
43         else if ( !geometryId.empty() )
44             mSpline->setName ( geometryId );
45 
46         if ( !geometryId.empty() )
47             mSpline->setOriginalId ( geometryId );
48 	}
49 
50     //------------------------------
getUniqueId()51     const COLLADAFW::UniqueId& SplineLoader::getUniqueId ()
52     {
53 
54         if ( mSpline ) return mSpline->getUniqueId ();
55         return COLLADAFW::UniqueId::INVALID;
56     }
57 
58 	//------------------------------
begin__source(const source__AttributeData & attributes)59 	bool SplineLoader::begin__source( const source__AttributeData& attributes )
60 	{
61 		return beginSource(attributes);
62 	}
63 
64 	//------------------------------
end__source()65 	bool SplineLoader::end__source(  )
66 	{
67 		return endSource();
68 	}
69 
70 	//------------------------------
begin__input____InputLocal(const input____InputLocal__AttributeData & attributeData)71 	bool SplineLoader::begin__input____InputLocal( const input____InputLocal__AttributeData& attributeData )
72 	{
73 		mCurrentVertexInput = new InputUnshared(attributeData.semantic, attributeData.source);
74 		return true;
75 	}
76 
77 	//------------------------------
end__input____InputLocal()78 	bool SplineLoader::end__input____InputLocal()
79 	{
80 		mVerticesInputs.getInputArray().append(mCurrentVertexInput);
81 		mCurrentVertexInput = 0;
82 		return true;
83 	}
84 
85     //------------------------------
86 
begin__control_vertices()87     bool SplineLoader::begin__control_vertices()
88     {
89         mInVertices = true;
90 
91         return true;
92     }
93 
end__control_vertices()94     bool SplineLoader::end__control_vertices()
95     {
96         mInVertices = false;
97 
98         return true;
99     }
100 
101     //------------------------------
begin__Name_array(const Name_array__AttributeData & attributeData)102     bool SplineLoader::begin__Name_array( const Name_array__AttributeData& attributeData )
103     {
104         return beginInterpolationArray( false );
105     }
106 
107     //------------------------------
end__Name_array()108     bool SplineLoader::end__Name_array()
109     {
110         return true;
111     }
112 
113     //------------------------------
data__Name_array(const ParserString * data,size_t length)114     bool SplineLoader::data__Name_array( const ParserString* data, size_t length )
115     {
116         return dataInterpolationArray( data, length);
117     }
118 
119     //------------------------------
beginInterpolationArray(bool isIdArray)120     bool SplineLoader::beginInterpolationArray( bool isIdArray )
121     {
122         const String& sourceId = getCurrentSourceId();
123 
124         // Without id we will never be able to us this array again. Don't store it.
125         if ( sourceId.empty() )
126             return true;
127 
128         return true;
129     }
130 
131     //------------------------------
dataInterpolationArray(const ParserString * data,size_t length)132     bool SplineLoader::dataInterpolationArray( const ParserString* data, size_t length )
133     {
134         for ( size_t i = 0; i < length;  ++i)
135         {
136             const ParserString& parserString = data[i];
137             mInterpolations.push_back( String( parserString.str, parserString.length ) );
138         }
139         return true;
140     }
141 
end__spline()142     bool SplineLoader::end__spline()
143     {
144         mInSpline = false;
145 
146         loadPositions();
147         loadOutTangents();
148         loadInTangents();
149         loadInterpolations();
150 
151         // The mesh will be written by the GeometyLoader. Therefore nothing to with the mesh here
152         finish();
153         return true;
154     }
155 
loadPositions()156     bool SplineLoader::loadPositions()
157     {
158         const InputUnshared * input = mVerticesInputs.getInputBySemantic( InputSemantic::POSITION );
159 
160         if( input )
161         {
162             // Get the source element with the uri of the input element.
163             COLLADABU::URI inputUrl = input->getSource ();
164             String sourceId = inputUrl.getFragment ();
165             SourceBase* sourceBase = getSourceById ( sourceId );
166             if ( sourceBase == 0 ) return false;
167 
168             // Get the source input array
169             const SourceBase::DataType& dataType = sourceBase->getDataType ();
170             switch ( dataType )
171             {
172             case SourceBase::DATA_TYPE_FLOAT:
173                 {
174                     // Get the values array from the source
175                     FloatSource* source = ( FloatSource* ) sourceBase;
176                     FloatArrayElement& arrayElement = source->getArrayElement ();
177                     COLLADAFW::ArrayPrimitiveType<float>& valuesArray = arrayElement.getValues ();
178 
179                     // TODO
180                     unsigned long long stride = source->getStride ();
181 
182                     // Check if there are already some values in the positions list.
183                     // If so, we have to store the last index to increment the following indexes.
184                     COLLADAFW::MeshVertexData& positions = mSpline->getPositions ();
185                     const size_t initialIndex = positions.getValuesCount ();
186                     sourceBase->setInitialIndex ( initialIndex );
187 
188                     // Push the new positions into the list of positions.
189                     positions.setType ( COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT );
190                     if ( initialIndex != 0 )
191                     {
192                         positions.appendValues ( valuesArray );
193                     }
194                     else
195                     {
196                         positions.setData ( valuesArray.getData (), valuesArray.getCount () );
197                         valuesArray.yieldOwnerShip();
198                     }
199 
200                     // Set the source base as loaded element.
201                     sourceBase->addLoadedInputElement ( InputSemantic::POSITION  );
202 
203                     break;
204                 }
205             case SourceBase::DATA_TYPE_DOUBLE:
206                 {
207                     // Get the values array from the source
208                     DoubleSource* source = ( DoubleSource* ) sourceBase;
209                     DoubleArrayElement& arrayElement = source->getArrayElement ();
210                     COLLADAFW::ArrayPrimitiveType<double>& valuesArray = arrayElement.getValues ();
211 
212                     // Check if there are already some values in the positions list.
213                     // If so, we have to store the last index to increment the following indexes.
214                     COLLADAFW::MeshVertexData& positions = mSpline->getPositions ();
215                     const size_t initialIndex = positions.getValuesCount ();
216                     sourceBase->setInitialIndex ( initialIndex );
217 
218                     // Push the new positions into the list of positions.
219                     positions.setType ( COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE );
220                     if ( initialIndex != 0 )
221                     {
222                         positions.appendValues ( valuesArray );
223                     }
224                     else
225                     {
226                         positions.setData ( valuesArray.getData (), valuesArray.getCount () );
227                         valuesArray.yieldOwnerShip();
228                     }
229 
230                     // Set the source base as loaded element.
231                     sourceBase->addLoadedInputElement ( InputSemantic::POSITION  );
232 
233                     break;
234                 }
235             default:
236                 std::cerr << "Position source has an other datatype as float or double! " << dataType << std::endl;
237                 return false;
238             }
239 
240             return true;
241         }
242         else
243         {
244             return false;
245         }
246     }
247 
loadOutTangents()248     bool SplineLoader::loadOutTangents()
249     {
250         const InputUnshared * input = mVerticesInputs.getInputBySemantic( InputSemantic::OUT_TANGENT );
251 
252         if( input )
253         {
254             // Get the source element with the uri of the input element.
255             COLLADABU::URI inputUrl = input->getSource ();
256             String sourceId = inputUrl.getFragment ();
257             SourceBase* sourceBase = getSourceById ( sourceId );
258             if ( sourceBase == 0 ) return false;
259 
260             // Get the source input array
261             const SourceBase::DataType& dataType = sourceBase->getDataType ();
262             switch ( dataType )
263             {
264             case SourceBase::DATA_TYPE_FLOAT:
265                 {
266                     // Get the values array from the source
267                     FloatSource* source = ( FloatSource* ) sourceBase;
268                     FloatArrayElement& arrayElement = source->getArrayElement ();
269                     COLLADAFW::ArrayPrimitiveType<float>& valuesArray = arrayElement.getValues ();
270 
271                     // TODO
272                     unsigned long long stride = source->getStride ();
273 
274                     // Check if there are already some values in the positions list.
275                     // If so, we have to store the last index to increment the following indexes.
276                     COLLADAFW::MeshVertexData& positions = mSpline->getOutTangents();
277                     const size_t initialIndex = positions.getValuesCount ();
278                     sourceBase->setInitialIndex ( initialIndex );
279 
280                     // Push the new positions into the list of positions.
281                     positions.setType ( COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT );
282                     if ( initialIndex != 0 )
283                     {
284                         positions.appendValues ( valuesArray );
285                     }
286                     else
287                     {
288                         positions.setData ( valuesArray.getData (), valuesArray.getCount () );
289                         valuesArray.yieldOwnerShip();
290                     }
291 
292                     // Set the source base as loaded element.
293                     sourceBase->addLoadedInputElement ( InputSemantic::OUT_TANGENT  );
294 
295                     break;
296                 }
297             case SourceBase::DATA_TYPE_DOUBLE:
298                 {
299                     // Get the values array from the source
300                     DoubleSource* source = ( DoubleSource* ) sourceBase;
301                     DoubleArrayElement& arrayElement = source->getArrayElement ();
302                     COLLADAFW::ArrayPrimitiveType<double>& valuesArray = arrayElement.getValues ();
303 
304                     // Check if there are already some values in the positions list.
305                     // If so, we have to store the last index to increment the following indexes.
306                     COLLADAFW::MeshVertexData& positions = mSpline->getOutTangents ();
307                     const size_t initialIndex = positions.getValuesCount ();
308                     sourceBase->setInitialIndex ( initialIndex );
309 
310                     // Push the new positions into the list of positions.
311                     positions.setType ( COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE );
312                     if ( initialIndex != 0 )
313                     {
314                         positions.appendValues ( valuesArray );
315                     }
316                     else
317                     {
318                         positions.setData ( valuesArray.getData (), valuesArray.getCount () );
319                         valuesArray.yieldOwnerShip();
320                     }
321 
322                     // Set the source base as loaded element.
323                     sourceBase->addLoadedInputElement ( InputSemantic::OUT_TANGENT  );
324 
325                     break;
326                 }
327             default:
328                 std::cerr << "Position source has an other datatype as float or double! " << dataType << std::endl;
329                 return false;
330             }
331 
332             return true;
333         }
334         else
335         {
336             return false;
337         }
338     }
339 
loadInTangents()340     bool SplineLoader::loadInTangents()
341     {
342         const InputUnshared * input = mVerticesInputs.getInputBySemantic( InputSemantic::IN_TANGENT );
343 
344         if( input )
345         {
346             // Get the source element with the uri of the input element.
347             COLLADABU::URI inputUrl = input->getSource ();
348             String sourceId = inputUrl.getFragment ();
349             SourceBase* sourceBase = getSourceById ( sourceId );
350             if ( sourceBase == 0 ) return false;
351 
352             // Get the source input array
353             const SourceBase::DataType& dataType = sourceBase->getDataType ();
354             switch ( dataType )
355             {
356             case SourceBase::DATA_TYPE_FLOAT:
357                 {
358                     // Get the values array from the source
359                     FloatSource* source = ( FloatSource* ) sourceBase;
360                     FloatArrayElement& arrayElement = source->getArrayElement ();
361                     COLLADAFW::ArrayPrimitiveType<float>& valuesArray = arrayElement.getValues ();
362 
363                     // TODO
364                     unsigned long long stride = source->getStride ();
365 
366                     // Check if there are already some values in the positions list.
367                     // If so, we have to store the last index to increment the following indexes.
368                     COLLADAFW::MeshVertexData& positions = mSpline->getInTangents ();
369                     const size_t initialIndex = positions.getValuesCount ();
370                     sourceBase->setInitialIndex ( initialIndex );
371 
372                     // Push the new positions into the list of positions.
373                     positions.setType ( COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT );
374                     if ( initialIndex != 0 )
375                     {
376                         positions.appendValues ( valuesArray );
377                     }
378                     else
379                     {
380                         positions.setData ( valuesArray.getData (), valuesArray.getCount () );
381                         valuesArray.yieldOwnerShip();
382                     }
383 
384                     // Set the source base as loaded element.
385                     sourceBase->addLoadedInputElement ( InputSemantic::POSITION  );
386 
387                     break;
388                 }
389             case SourceBase::DATA_TYPE_DOUBLE:
390                 {
391                     // Get the values array from the source
392                     DoubleSource* source = ( DoubleSource* ) sourceBase;
393                     DoubleArrayElement& arrayElement = source->getArrayElement ();
394                     COLLADAFW::ArrayPrimitiveType<double>& valuesArray = arrayElement.getValues ();
395 
396                     // Check if there are already some values in the positions list.
397                     // If so, we have to store the last index to increment the following indexes.
398                     COLLADAFW::MeshVertexData& positions = mSpline->getInTangents ();
399                     const size_t initialIndex = positions.getValuesCount ();
400                     sourceBase->setInitialIndex ( initialIndex );
401 
402                     // Push the new positions into the list of positions.
403                     positions.setType ( COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE );
404                     if ( initialIndex != 0 )
405                     {
406                         positions.appendValues ( valuesArray );
407                     }
408                     else
409                     {
410                         positions.setData ( valuesArray.getData (), valuesArray.getCount () );
411                         valuesArray.yieldOwnerShip();
412                     }
413 
414                     // Set the source base as loaded element.
415                     sourceBase->addLoadedInputElement ( InputSemantic::IN_TANGENT  );
416 
417                     break;
418                 }
419             default:
420                 std::cerr << "Position source has an other datatype as float or double! " << dataType << std::endl;
421                 return false;
422             }
423 
424             return true;
425         }
426         else
427         {
428             return false;
429         }
430     }
431 
loadInterpolations()432     bool SplineLoader::loadInterpolations()
433     {
434         if( mInterpolations.size() )
435         {
436             COLLADAFW::Spline::InterpolationArray & interpolations = mSpline->getInterpolations();
437 
438             interpolations.reallocMemory( mInterpolations.size() );
439 
440             StringList::const_iterator it = mInterpolations.begin(), end = mInterpolations.end();
441             for( ; it != end ; ++it)
442             {
443                 if( *it == "LINEAR" )
444                 {
445                     interpolations.append( COLLADAFW::Spline::LINEAR );
446                 }
447                 else if( *it == "BEZIER" )
448                 {
449                     interpolations.append( COLLADAFW::Spline::BEZIER );
450                 }
451                 else
452                 {
453                     std::cerr << "Interpolation source has an unknown type : " << *it << std::endl;
454                     return false;
455                 }
456             }
457             return true;
458         }
459         else
460         {
461             return false;
462         }
463     }
464 
465 } // namespace COLLADASaxFWL
466