colladaUtils.h 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #ifndef _COLLADA_UTILS_H_
  23. #define _COLLADA_UTILS_H_
  24. #ifdef _MSC_VER
  25. #pragma warning(disable : 4786) // disable warning about long debug symbol names
  26. #pragma warning(disable : 4355) // disable "'this' : used in base member initializer list" warnings
  27. #endif
  28. #ifndef _MMATRIX_H_
  29. #include "math/mMatrix.h"
  30. #endif
  31. #ifndef _MQUAT_H_
  32. #include "math/mQuat.h"
  33. #endif
  34. #ifndef _TVECTOR_H_
  35. #include "core/util/tVector.h"
  36. #endif
  37. #ifndef _TSSHAPE_LOADER_H_
  38. #include "ts/loader/tsShapeLoader.h"
  39. #endif
  40. #ifndef _OPTIMIZEDPOLYLIST_H_
  41. #include "collision/optimizedPolyList.h"
  42. #endif
  43. #ifndef TINYXML_INCLUDED
  44. #include "tinyxml.h"
  45. #endif
  46. #ifndef _CONSOLE_H_
  47. #include "console/console.h"
  48. #endif
  49. #include "platform/tmm_off.h"
  50. #include "dae.h"
  51. #include "dae/daeErrorHandler.h"
  52. #include "dae/domAny.h"
  53. #include "dom/domProfile_COMMON.h"
  54. #include "dom/domMaterial.h"
  55. #include "dom/domGeometry.h"
  56. #include "dom/domMorph.h"
  57. #include "dom/domNode.h"
  58. #include "dom/domCOLLADA.h"
  59. #include "platform/tmm_on.h"
  60. namespace ColladaUtils
  61. {
  62. struct ImportOptions
  63. {
  64. enum eLodType
  65. {
  66. DetectDTS = 0,
  67. SingleSize,
  68. TrailingNumber,
  69. NumLodTypes
  70. };
  71. domUpAxisType upAxis; // Override for the collada <up_axis> element
  72. F32 unit; // Override for the collada <unit> element
  73. eLodType lodType; // LOD type option
  74. S32 singleDetailSize; // Detail size for all meshes in the model
  75. String matNamePrefix; // Prefix to apply to collada material names
  76. String alwaysImport; // List of node names (with wildcards) to import, even if in the neverImport list
  77. String neverImport; // List of node names (with wildcards) to ignore on loading
  78. String alwaysImportMesh; // List of mesh names (with wildcards) to import, even if in the neverImportMesh list
  79. String neverImportMesh; // List of mesh names (with wildcards) to ignore on loading
  80. bool ignoreNodeScale; // Ignore <scale> elements in <node>s
  81. bool adjustCenter; // Translate model so origin is at the center
  82. bool adjustFloor; // Translate model so origin is at the bottom
  83. bool forceUpdateMaterials; // Force update of materials.cs
  84. bool useDiffuseNames; // Use diffuse texture as the material name
  85. ImportOptions()
  86. {
  87. reset();
  88. }
  89. void reset()
  90. {
  91. upAxis = UPAXISTYPE_COUNT;
  92. unit = -1.0f;
  93. lodType = DetectDTS;
  94. singleDetailSize = 2;
  95. matNamePrefix = "";
  96. alwaysImport = "";
  97. neverImport = "";
  98. alwaysImportMesh = "";
  99. neverImportMesh = "";
  100. ignoreNodeScale = false;
  101. adjustCenter = false;
  102. adjustFloor = false;
  103. forceUpdateMaterials = false;
  104. useDiffuseNames = false;
  105. }
  106. };
  107. ImportOptions& getOptions();
  108. void convertTransform(MatrixF& m);
  109. void collapsePath(std::string& path);
  110. // Apply the set of Collada conditioners (suited for loading Collada models into Torque)
  111. void applyConditioners(domCOLLADA* root);
  112. const domProfile_COMMON* findEffectCommonProfile(const domEffect* effect);
  113. const domCommon_color_or_texture_type_complexType* findEffectDiffuse(const domEffect* effect);
  114. const domCommon_color_or_texture_type_complexType* findEffectSpecular(const domEffect* effect);
  115. const domFx_sampler2D_common_complexType* getTextureSampler(const domEffect* effect, const domCommon_color_or_texture_type_complexType* texture);
  116. String getSamplerImagePath(const domEffect* effect, const domFx_sampler2D_common_complexType* sampler2D);
  117. String resolveImagePath(const domImage* image);
  118. // Collada export helper functions
  119. Torque::Path findTexture(const Torque::Path& diffuseMap);
  120. void exportColladaHeader(TiXmlElement* rootNode);
  121. void exportColladaMaterials(TiXmlElement* rootNode, const OptimizedPolyList& mesh, Vector<String>& matNames, const Torque::Path& colladaFile);
  122. void exportColladaTriangles(TiXmlElement* meshNode, const OptimizedPolyList& mesh, const String& meshName, const Vector<String>& matNames);
  123. void exportColladaMesh(TiXmlElement* rootNode, const OptimizedPolyList& mesh, const String& meshName, const Vector<String>& matNames);
  124. void exportColladaScene(TiXmlElement* rootNode, const String& meshName, const Vector<String>& matNames);
  125. // Export an OptimizedPolyList to a simple Collada file
  126. void exportToCollada(const Torque::Path& colladaFile, const OptimizedPolyList& mesh, const String& meshName = String::EmptyString);
  127. };
  128. //-----------------------------------------------------------------------------
  129. // Helper Classes
  130. //
  131. // The Collada DOM uses a different class for each XML element, and there is very
  132. // little class inheritance, even though many elements have the same attributes
  133. // and children. This makes the DOM a bit ugly to work with, and the following
  134. // templates attempt to make this situation a bit nicer by providing a common way
  135. // to access common elements, while retaining the strong typing of the DOM classes.
  136. //-----------------------------------------------------------------------------
  137. /// Convert from the Collada transform types to a Torque MatrixF
  138. template<class T> inline MatrixF vecToMatrixF(const domListOfFloats& vec) { return MatrixF(true); }
  139. /// Collada <translate>: [x_translate, y_translate, z_translate]
  140. template<> inline MatrixF vecToMatrixF<domTranslate>(const domListOfFloats& vec)
  141. {
  142. MatrixF mat(true);
  143. mat.setPosition(Point3F(vec[0], vec[1], vec[2]));
  144. return mat;
  145. }
  146. /// Collada <scale>: [x_scale, y_scale, z_scale]
  147. template<> inline MatrixF vecToMatrixF<domScale>(const domListOfFloats& vec)
  148. {
  149. MatrixF mat(true);
  150. mat.scale(Point3F(vec[0], vec[1], vec[2]));
  151. return mat;
  152. }
  153. /// Collada <rotate>: [rotation_axis, angle_in_degrees]
  154. template<> inline MatrixF vecToMatrixF<domRotate>(const domListOfFloats& vec)
  155. {
  156. AngAxisF aaxis(Point3F(vec[0], vec[1], vec[2]), -(vec[3] * M_PI) / 180.0f);
  157. MatrixF mat(true);
  158. aaxis.setMatrix(&mat);
  159. return mat;
  160. }
  161. /// Collada <matrix>: same form as TGE (woohoo!)
  162. template<> inline MatrixF vecToMatrixF<domMatrix>(const domListOfFloats& vec)
  163. {
  164. MatrixF mat;
  165. for (S32 i = 0; i < 16; i++)
  166. mat[i] = vec[i];
  167. return mat;
  168. }
  169. /// Collada <skew>: [angle_in_degrees, rotation_axis, translation_axis]
  170. /// skew transform code adapted from GMANMatrix4 implementation
  171. template<> inline MatrixF vecToMatrixF<domSkew>(const domListOfFloats& vec)
  172. {
  173. F32 angle = -(vec[0] * M_PI) / 180.0f;
  174. Point3F rotAxis(vec[1], vec[2], vec[3]);
  175. Point3F transAxis(vec[4], vec[5], vec[6]);
  176. transAxis.normalize();
  177. Point3F a1 = transAxis * mDot(rotAxis, transAxis);
  178. Point3F a2 = rotAxis - a1;
  179. a2.normalize();
  180. F32 an1 = mDot(rotAxis, a2);
  181. F32 an2 = mDot(rotAxis, transAxis);
  182. F32 rx = an1 * mCos(angle) - an2 * mSin(angle);
  183. F32 ry = an1 * mSin(angle) + an2 * mCos(angle);
  184. // Check for rotation parallel to translation
  185. F32 alpha = (an1 == 0) ? 0 : (ry/rx - an2/an1);
  186. MatrixF mat(true);
  187. mat(0,0) = a2.x * transAxis.x * alpha + 1.0;
  188. mat(1,0) = a2.y * transAxis.x * alpha;
  189. mat(2,0) = a2.z * transAxis.x * alpha;
  190. mat(0,1) = a2.x * transAxis.y * alpha;
  191. mat(1,1) = a2.y * transAxis.y * alpha + 1.0;
  192. mat(2,1) = a2.z * transAxis.y * alpha;
  193. mat(0,2) = a2.x * transAxis.z * alpha;
  194. mat(1,2) = a2.y * transAxis.z * alpha;
  195. mat(2,2) = a2.z * transAxis.z * alpha + 1.0;
  196. return mat;
  197. }
  198. /// Collada <lookat>: [eye, target, up]
  199. template<> inline MatrixF vecToMatrixF<domLookat>(const domListOfFloats& vec)
  200. {
  201. Point3F eye(vec[0], vec[1], vec[2]);
  202. Point3F target(vec[3], vec[4], vec[5]);
  203. Point3F up(vec[6], vec[7], vec[8]);
  204. Point3F fwd = target - eye;
  205. fwd.normalizeSafe();
  206. Point3F right = mCross(fwd, up);
  207. right.normalizeSafe();
  208. up = mCross(right, fwd);
  209. up.normalizeSafe();
  210. MatrixF mat(true);
  211. mat.setColumn(0, right);
  212. mat.setColumn(1, fwd);
  213. mat.setColumn(2, up);
  214. mat.setColumn(3, eye);
  215. return mat;
  216. }
  217. //-----------------------------------------------------------------------------
  218. /// Try to get a name for the element using the following attributes (in order):
  219. /// name, sid, id, "null"
  220. template<class T> inline const char* _GetNameOrId(const T* element)
  221. {
  222. return element ? (element->getName() ? element->getName() : (element->getId() ? element->getId() : "null")) : "null";
  223. }
  224. template<> inline const char* _GetNameOrId(const domInstance_geometry* element)
  225. {
  226. return element ? (element->getName() ? element->getName() : (element->getSid() ? element->getSid() : "null")) : "null";
  227. }
  228. template<> inline const char* _GetNameOrId(const domInstance_controller* element)
  229. {
  230. return element ? (element->getName() ? element->getName() : (element->getSid() ? element->getSid() : "null")) : "null";
  231. }
  232. //-----------------------------------------------------------------------------
  233. // Collada <source>s are extremely flexible, and thus difficult to access in a nice
  234. // way. This class attempts to provide a clean interface to convert Collada source
  235. // data to the appropriate Torque data structure without losing any of the flexibility
  236. // of the underlying Collada DOM.
  237. //
  238. // Some of the conversions we need to handle are:
  239. // - daeString to const char*
  240. // - daeIDRef to const char*
  241. // - double to F32
  242. // - double to Point2F
  243. // - double to Point3F
  244. // - double to MatrixF
  245. //
  246. // The _SourceReader object is initialized with a list of parameter names that it
  247. // tries to match to <param> elements in the source accessor to figure out how to
  248. // pull values out of the 1D source array. Note that no type checking of any kind
  249. // is done until we actually try to extract values from the source.
  250. class _SourceReader
  251. {
  252. const domSource* source; // the wrapped Collada source
  253. const domAccessor* accessor; // shortcut to the source accessor
  254. Vector<U32> offsets; // offset of each of the desired values to pull from the source array
  255. public:
  256. _SourceReader() : source(0), accessor(0) {}
  257. void reset()
  258. {
  259. source = 0;
  260. accessor = 0;
  261. offsets.clear();
  262. }
  263. //------------------------------------------------------
  264. // Initialize the _SourceReader object
  265. bool initFromSource(const domSource* src, const char* paramNames[] = 0)
  266. {
  267. source = src;
  268. accessor = source->getTechnique_common()->getAccessor();
  269. offsets.clear();
  270. // The source array has groups of values in a 1D stream => need to map the
  271. // input param names to source params to determine the offset within the
  272. // group for each desired value
  273. U32 paramCount = 0;
  274. while (paramNames && paramNames[paramCount][0]) {
  275. // lookup the index of the source param that matches the input param
  276. offsets.push_back(paramCount);
  277. for (U32 iParam = 0; iParam < accessor->getParam_array().getCount(); iParam++) {
  278. if (accessor->getParam_array()[iParam]->getName() &&
  279. dStrEqual(accessor->getParam_array()[iParam]->getName(), paramNames[paramCount])) {
  280. offsets.last() = iParam;
  281. break;
  282. }
  283. }
  284. paramCount++;
  285. }
  286. // If no input params were specified, just map the source params directly
  287. if (!offsets.size()) {
  288. for (S32 iParam = 0; iParam < accessor->getParam_array().getCount(); iParam++)
  289. offsets.push_back(iParam);
  290. }
  291. return true;
  292. }
  293. //------------------------------------------------------
  294. // Shortcut to the size of the array (should be the number of destination objects)
  295. S32 size() const { return accessor ? accessor->getCount() : 0; }
  296. // Get the number of elements per group in the source
  297. S32 stride() const { return accessor ? accessor->getStride() : 0; }
  298. //------------------------------------------------------
  299. // Get a pointer to the start of a group of values (index advances by stride)
  300. //template<class T> T getArrayData(S32 index) const { return 0; }
  301. const double* getStringArrayData(S32 index) const
  302. {
  303. if ((index >= 0) && (index < size())) {
  304. if (source->getFloat_array())
  305. return &source->getFloat_array()->getValue()[index*stride()];
  306. }
  307. return 0;
  308. }
  309. //------------------------------------------------------
  310. // Read a single value from the source array
  311. //template<class T> T getValue(S32 index) const { return T; }
  312. const char* getStringValue(S32 index) const
  313. {
  314. if ((index >= 0) && (index < size())) {
  315. // could be plain strings or IDREFs
  316. if (source->getName_array())
  317. return source->getName_array()->getValue()[index*stride()];
  318. else if (source->getIDREF_array())
  319. return source->getIDREF_array()->getValue()[index*stride()].getID();
  320. }
  321. return "";
  322. }
  323. F32 getFloatValue(S32 index) const
  324. {
  325. F32 value(0);
  326. if (const double* data = getStringArrayData(index))
  327. return data[offsets[0]];
  328. return value;
  329. }
  330. Point2F getPoint2FValue(S32 index) const
  331. {
  332. Point2F value(0, 0);
  333. if (const double* data = getStringArrayData(index))
  334. value.set(data[offsets[0]], data[offsets[1]]);
  335. return value;
  336. }
  337. Point3F getPoint3FValue(S32 index) const
  338. {
  339. Point3F value(1, 0, 0);
  340. if (const double* data = getStringArrayData(index))
  341. value.set(data[offsets[0]], data[offsets[1]], data[offsets[2]]);
  342. return value;
  343. }
  344. ColorI getColorIValue(S32 index) const
  345. {
  346. ColorI value(255, 255, 255, 255);
  347. if (const double* data = getStringArrayData(index))
  348. {
  349. value.red = data[offsets[0]] * 255.0;
  350. value.green = data[offsets[1]] * 255.0;
  351. value.blue = data[offsets[2]] * 255.0;
  352. if ( stride() == 4 )
  353. value.alpha = data[offsets[3]] * 255.0;
  354. }
  355. return value;
  356. }
  357. MatrixF getMatrixFValue(S32 index) const
  358. {
  359. MatrixF value(true);
  360. if (const double* data = getStringArrayData(index)) {
  361. for (S32 i = 0; i < 16; i++)
  362. value[i] = data[i];
  363. }
  364. return value;
  365. }
  366. };
  367. //-----------------------------------------------------------------------------
  368. // Collada geometric primitives: Use the BasePrimitive class to access the
  369. // different primitive types in a nice way.
  370. class BasePrimitive
  371. {
  372. public:
  373. virtual ~BasePrimitive() { }
  374. /// Return true if the element is a geometric primitive type
  375. static bool isPrimitive(const daeElement* element)
  376. {
  377. switch (element->getElementType()) {
  378. case COLLADA_TYPE::TRIANGLES: case COLLADA_TYPE::POLYLIST:
  379. case COLLADA_TYPE::POLYGONS: case COLLADA_TYPE::TRIFANS:
  380. case COLLADA_TYPE::TRISTRIPS: case COLLADA_TYPE::CAPSULE:
  381. case COLLADA_TYPE::CYLINDER: case COLLADA_TYPE::LINES:
  382. case COLLADA_TYPE::LINESTRIPS: case COLLADA_TYPE::PLANE:
  383. case COLLADA_TYPE::SPLINE: case COLLADA_TYPE::SPHERE:
  384. case COLLADA_TYPE::TAPERED_CAPSULE: case COLLADA_TYPE::TAPERED_CYLINDER:
  385. return true;
  386. }
  387. return false;
  388. }
  389. /// Return true if the element is a supported primitive type
  390. static bool isSupportedPrimitive(const daeElement* element)
  391. {
  392. switch (element->getElementType()) {
  393. case COLLADA_TYPE::TRIANGLES:
  394. case COLLADA_TYPE::TRISTRIPS:
  395. case COLLADA_TYPE::TRIFANS:
  396. case COLLADA_TYPE::POLYLIST:
  397. case COLLADA_TYPE::POLYGONS:
  398. return true;
  399. }
  400. return false;
  401. }
  402. /// Construct a child class based on the type of Collada element
  403. static BasePrimitive* get(const daeElement* element);
  404. /// Methods to be implemented for each supported Collada geometric element
  405. virtual const char* getElementName() = 0;
  406. virtual const char* getMaterial() = 0;
  407. virtual const domInputLocalOffset_Array& getInputs() = 0;
  408. virtual S32 getStride() const = 0;
  409. virtual const domListOfUInts *getTriangleData() = 0;
  410. };
  411. /// Template child class for supported Collada primitive elements
  412. template<class T> class ColladaPrimitive : public BasePrimitive
  413. {
  414. T* primitive;
  415. domListOfUInts *pTriangleData;
  416. S32 stride;
  417. public:
  418. ColladaPrimitive(const daeElement* e) : pTriangleData(0)
  419. {
  420. // Cast to geometric primitive element
  421. primitive = daeSafeCast<T>(const_cast<daeElement*>(e));
  422. // Determine stride
  423. stride = 0;
  424. for (S32 iInput = 0; iInput < getInputs().getCount(); iInput++) {
  425. if (getInputs()[iInput]->getOffset() >= stride)
  426. stride = getInputs()[iInput]->getOffset() + 1;
  427. }
  428. }
  429. ~ColladaPrimitive()
  430. {
  431. delete pTriangleData;
  432. }
  433. /// Most primitives can use these common implementations
  434. const char* getElementName() { return primitive->getElementName(); }
  435. const char* getMaterial() { return primitive->getMaterial(); }
  436. const domInputLocalOffset_Array& getInputs() { return primitive->getInput_array(); }
  437. S32 getStride() const { return stride; }
  438. /// Each supported primitive needs to implement this method (and convert
  439. /// to triangles if required)
  440. const domListOfUInts *getTriangleData() { return NULL; }
  441. };
  442. //-----------------------------------------------------------------------------
  443. // <triangles>
  444. template<> inline const domListOfUInts *ColladaPrimitive<domTriangles>::getTriangleData()
  445. {
  446. // Return the <p> integer list directly
  447. return (primitive->getP() ? &(primitive->getP()->getValue()) : NULL);
  448. }
  449. //-----------------------------------------------------------------------------
  450. // <tristrips>
  451. template<> inline const domListOfUInts *ColladaPrimitive<domTristrips>::getTriangleData()
  452. {
  453. if (!pTriangleData)
  454. {
  455. // Convert strips to triangles
  456. pTriangleData = new domListOfUInts();
  457. for (S32 iStrip = 0; iStrip < primitive->getCount(); iStrip++) {
  458. domP* P = primitive->getP_array()[iStrip];
  459. // Ignore invalid P arrays
  460. if (!P || !P->getValue().getCount())
  461. continue;
  462. domUint* pSrcData = &(P->getValue()[0]);
  463. S32 numTriangles = (P->getValue().getCount() / stride) - 2;
  464. // Convert the strip back to a triangle list
  465. domUint* v0 = pSrcData;
  466. for (S32 iTri = 0; iTri < numTriangles; iTri++, v0 += stride) {
  467. if (iTri & 0x1)
  468. {
  469. // CW triangle
  470. pTriangleData->appendArray(stride, v0);
  471. pTriangleData->appendArray(stride, v0 + 2*stride);
  472. pTriangleData->appendArray(stride, v0 + stride);
  473. }
  474. else
  475. {
  476. // CCW triangle
  477. pTriangleData->appendArray(stride*3, v0);
  478. }
  479. }
  480. }
  481. }
  482. return pTriangleData;
  483. }
  484. //-----------------------------------------------------------------------------
  485. // <trifans>
  486. template<> inline const domListOfUInts *ColladaPrimitive<domTrifans>::getTriangleData()
  487. {
  488. if (!pTriangleData)
  489. {
  490. // Convert strips to triangles
  491. pTriangleData = new domListOfUInts();
  492. for (S32 iStrip = 0; iStrip < primitive->getCount(); iStrip++) {
  493. domP* P = primitive->getP_array()[iStrip];
  494. // Ignore invalid P arrays
  495. if (!P || !P->getValue().getCount())
  496. continue;
  497. domUint* pSrcData = &(P->getValue()[0]);
  498. S32 numTriangles = (P->getValue().getCount() / stride) - 2;
  499. // Convert the fan back to a triangle list
  500. domUint* v0 = pSrcData + stride;
  501. for (S32 iTri = 0; iTri < numTriangles; iTri++, v0 += stride) {
  502. pTriangleData->appendArray(stride, pSrcData); // shared vertex
  503. pTriangleData->appendArray(stride, v0); // previous vertex
  504. pTriangleData->appendArray(stride, v0+stride); // current vertex
  505. }
  506. }
  507. }
  508. return pTriangleData;
  509. }
  510. //-----------------------------------------------------------------------------
  511. // <polygons>
  512. template<> inline const domListOfUInts *ColladaPrimitive<domPolygons>::getTriangleData()
  513. {
  514. if (!pTriangleData)
  515. {
  516. // Convert polygons to triangles
  517. pTriangleData = new domListOfUInts();
  518. for (S32 iPoly = 0; iPoly < primitive->getCount(); iPoly++) {
  519. domP* P = primitive->getP_array()[iPoly];
  520. // Ignore invalid P arrays
  521. if (!P || !P->getValue().getCount())
  522. continue;
  523. domUint* pSrcData = &(P->getValue()[0]);
  524. S32 numPoints = P->getValue().getCount() / stride;
  525. // Use a simple tri-fan (centered at the first point) method of
  526. // converting the polygon to triangles.
  527. domUint* v0 = pSrcData;
  528. pSrcData += stride;
  529. for (S32 iTri = 0; iTri < numPoints-2; iTri++) {
  530. pTriangleData->appendArray(stride, v0);
  531. pTriangleData->appendArray(stride*2, pSrcData);
  532. pSrcData += stride;
  533. }
  534. }
  535. }
  536. return pTriangleData;
  537. }
  538. //-----------------------------------------------------------------------------
  539. // <polylist>
  540. template<> inline const domListOfUInts *ColladaPrimitive<domPolylist>::getTriangleData()
  541. {
  542. if (!pTriangleData)
  543. {
  544. // Convert polygons to triangles
  545. pTriangleData = new domListOfUInts();
  546. // Check that the P element has the right number of values (this
  547. // has been seen with certain models exported using COLLADAMax)
  548. const domListOfUInts& vcount = primitive->getVcount()->getValue();
  549. U32 expectedCount = 0;
  550. for (S32 iPoly = 0; iPoly < vcount.getCount(); iPoly++)
  551. expectedCount += vcount[iPoly];
  552. expectedCount *= stride;
  553. if (!primitive->getP() || !primitive->getP()->getValue().getCount() ||
  554. (primitive->getP()->getValue().getCount() != expectedCount) )
  555. {
  556. Con::warnf("<polylist> element found with invalid <p> array. This primitive will be ignored.");
  557. return pTriangleData;
  558. }
  559. domUint* pSrcData = &(primitive->getP()->getValue()[0]);
  560. for (S32 iPoly = 0; iPoly < vcount.getCount(); iPoly++) {
  561. // Use a simple tri-fan (centered at the first point) method of
  562. // converting the polygon to triangles.
  563. domUint* v0 = pSrcData;
  564. pSrcData += stride;
  565. for (S32 iTri = 0; iTri < vcount[iPoly]-2; iTri++) {
  566. pTriangleData->appendArray(stride, v0);
  567. pTriangleData->appendArray(stride*2, pSrcData);
  568. pSrcData += stride;
  569. }
  570. pSrcData += stride;
  571. }
  572. }
  573. return pTriangleData;
  574. }
  575. //-----------------------------------------------------------------------------
  576. /// Convert a custom parameter string to a particular type
  577. template<typename T> inline T convert(const char* value) { return value; }
  578. template<> inline bool convert(const char* value) { return dAtob(value); }
  579. template<> inline S32 convert(const char* value) { return dAtoi(value); }
  580. template<> inline F64 convert(const char* value) { return dAtof(value); }
  581. template<> inline F32 convert(const char* value) { return convert<double>(value); }
  582. //-----------------------------------------------------------------------------
  583. /// Collada animation data
  584. struct AnimChannels : public Vector<struct AnimData*>
  585. {
  586. daeElement *element;
  587. AnimChannels(daeElement* el) : element(el)
  588. {
  589. element->setUserData(this);
  590. }
  591. ~AnimChannels()
  592. {
  593. if (element)
  594. element->setUserData(0);
  595. }
  596. };
  597. struct AnimData
  598. {
  599. bool enabled; ///!< Used to select animation channels for the current clip
  600. _SourceReader input;
  601. _SourceReader output;
  602. _SourceReader inTangent;
  603. _SourceReader outTangent;
  604. _SourceReader interpolation;
  605. U32 targetValueOffset; ///< Offset into the target element (for arrays of values)
  606. U32 targetValueCount; ///< Number of values animated (from OUTPUT source array)
  607. /// Get the animation channels for the Collada element (if any)
  608. static AnimChannels* getAnimChannels(const daeElement* element)
  609. {
  610. return element ? (AnimChannels*)const_cast<daeElement*>(element)->getUserData() : 0;
  611. }
  612. AnimData() : enabled(false) { }
  613. void parseTargetString(const char* target, S32 fullCount, const char* elements[]);
  614. F32 invertParamCubic(F32 param, F32 x0, F32 x1, F32 x2, F32 x3) const;
  615. void interpValue(F32 t, U32 offset, double* value) const;
  616. void interpValue(F32 t, U32 offset, const char** value) const;
  617. };
  618. //-----------------------------------------------------------------------------
  619. // Collada allows any element with an SID or ID attribute to be the target of
  620. // an animation channel, which is very flexible, but awkward to work with. Some
  621. // examples of animated values are:
  622. // - single float
  623. // - single int
  624. // - single bool
  625. // - single string
  626. // - list of floats (transform elements or morph weights)
  627. //
  628. // This class provides a generic way to check if an element is animated, and
  629. // to get the value of the element at a given time.
  630. template<class T>
  631. struct AnimatedElement
  632. {
  633. const daeElement* element; ///< The Collada element (can be NULL)
  634. T defaultVal; ///< Default value (used when element is NULL)
  635. AnimatedElement(const daeElement* e=0) : element(e) { }
  636. /// Check if the element has any animations channels
  637. bool isAnimated() { return (AnimData::getAnimChannels(element) != 0); }
  638. bool isAnimated(F32 start, F32 end) { return isAnimated(); }
  639. /// Get the value of the element at the specified time
  640. T getValue(F32 time)
  641. {
  642. // If the element is NULL, just use the default (handy for <extra> profiles which
  643. // may or may not be present in the document)
  644. T value(defaultVal);
  645. if (const domAny* param = daeSafeCast<domAny>(const_cast<daeElement*>(element))) {
  646. // If the element is not animated, just use its current value
  647. value = convert<T>(param->getValue());
  648. // Animate the value
  649. const AnimChannels* channels = AnimData::getAnimChannels(element);
  650. if (channels && (time >= 0)) {
  651. for (S32 iChannel = 0; iChannel < channels->size(); iChannel++) {
  652. const AnimData* animData = (*channels)[iChannel];
  653. if (animData->enabled)
  654. animData->interpValue(time, 0, &value);
  655. }
  656. }
  657. }
  658. return value;
  659. }
  660. };
  661. template<class T> struct AnimatedElementList : public AnimatedElement<T>
  662. {
  663. AnimatedElementList(const daeElement* e=0) : AnimatedElement<T>(e) { }
  664. // @todo: Disable morph animations for now since they are not supported by T3D
  665. bool isAnimated() { return false; }
  666. bool isAnimated(F32 start, F32 end) { return false; }
  667. // Get the value of the element list at the specified time
  668. T getValue(F32 time)
  669. {
  670. T vec(this->defaultVal);
  671. if (this->element) {
  672. // Get a copy of the vector
  673. vec = *(T*)const_cast<daeElement*>(this->element)->getValuePointer();
  674. // Animate the vector
  675. const AnimChannels* channels = AnimData::getAnimChannels(this->element);
  676. if (channels && (time >= 0)) {
  677. for (S32 iChannel = 0; iChannel < channels->size(); iChannel++) {
  678. const AnimData* animData = (*channels)[iChannel];
  679. if (animData->enabled) {
  680. for (S32 iValue = 0; iValue < animData->targetValueCount; iValue++)
  681. animData->interpValue(time, iValue, &vec[animData->targetValueOffset + iValue]);
  682. }
  683. }
  684. }
  685. }
  686. return vec;
  687. }
  688. };
  689. // Strongly typed animated values
  690. typedef AnimatedElement<double> AnimatedFloat;
  691. typedef AnimatedElement<bool> AnimatedBool;
  692. typedef AnimatedElement<S32> AnimatedInt;
  693. typedef AnimatedElement<const char*> AnimatedString;
  694. typedef AnimatedElementList<domListOfFloats> AnimatedFloatList;
  695. #endif // _COLLADA_UTILS_H_