Torque3D Documentation / _generateds / colladaAppNode.cpp

colladaAppNode.cpp

Engine/source/ts/collada/colladaAppNode.cpp

More...

Public Functions

char *
TrimFirstWord(char * str)

Detailed Description

Public Functions

TrimFirstWord(char * str)

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25
 26#ifdef _MSC_VER
 27#pragma warning(disable : 4706)  // disable warning about assignment within conditional
 28#endif
 29
 30#include "ts/loader/appSequence.h"
 31#include "ts/collada/colladaExtensions.h"
 32#include "ts/collada/colladaAppNode.h"
 33#include "ts/collada/colladaAppMesh.h"
 34#include "ts/collada/colladaAppMesh.h"
 35
 36#include "core/stringTable.h"
 37
 38// Trim leading and trailing whitespace from the first word in the string
 39// Note that the string is modified.
 40static char* TrimFirstWord(char* str)
 41{
 42   char* value = str;
 43
 44   // Trim leading whitespace
 45   while ( value && *value && dIsspace( *value ) )
 46      value++;
 47
 48   // Trim trailing whitespace
 49   if ( value && *value )
 50   {
 51      char* end = value + 1;
 52      while ( *end && !dIsspace( *end ) )
 53         end++;
 54      *end = '\0';
 55   }
 56
 57   return value;
 58}
 59
 60ColladaAppNode::ColladaAppNode(const domNode* node, ColladaAppNode* parent)
 61      : p_domNode(node), appParent(parent),
 62        nodeExt(new ColladaExtension_node(node)),
 63        invertMeshes(false),
 64        lastTransformTime(TSShapeLoader::DefaultTime-1),
 65        defaultTransformValid(false)
 66      
 67{
 68   mName = dStrdup(_GetNameOrId(node));
 69   mParentName = dStrdup(parent ? parent->getName() : "ROOT");
 70
 71   // Extract user properties from the <node> extension as whitespace separated
 72   // "name=value" pairs
 73   char* properties = dStrdup(nodeExt->user_properties);
 74   char* pos = properties;
 75   char* end = properties + dStrlen( properties );
 76   while ( pos < end )
 77   {
 78      // Find the '=' character to separate the name and value pair
 79      char* split = dStrchr( pos, '=' );
 80      if ( !split )
 81         break;
 82
 83      // Get the name (whitespace trimmed string up to the '=')
 84      // and value (whitespace trimmed string after the '=')
 85      *split = '\0';
 86      char* name = TrimFirstWord( pos );
 87      char* value = TrimFirstWord( split + 1 );
 88
 89      mProps.insert(StringTable->insert(name), dAtof(value));
 90
 91      pos = value + dStrlen( value ) + 1;
 92   }
 93
 94   dFree( properties );
 95
 96   // Create vector of transform elements
 97   for (S32 iChild = 0; iChild < node->getContents().getCount(); iChild++) {
 98      switch (node->getContents()[iChild]->getElementType()) {
 99         case COLLADA_TYPE::TRANSLATE:
100         case COLLADA_TYPE::ROTATE:
101         case COLLADA_TYPE::SCALE:
102         case COLLADA_TYPE::SKEW:
103         case COLLADA_TYPE::MATRIX:
104         case COLLADA_TYPE::LOOKAT:
105            nodeTransforms.increment();
106            nodeTransforms.last().element = node->getContents()[iChild];
107            break;
108      }
109   }
110}
111
112// Get all child nodes
113void ColladaAppNode::buildChildList()
114{
115   // Process children: collect <node> and <instance_node> elements
116   for (S32 iChild = 0; iChild < p_domNode->getContents().getCount(); iChild++) {
117
118      daeElement* child = p_domNode->getContents()[iChild];
119      switch (child->getElementType()) {
120
121         case COLLADA_TYPE::NODE:
122         {
123            domNode* node = daeSafeCast<domNode>(child);
124            mChildNodes.push_back(new ColladaAppNode(node, this));
125            break;
126         }
127
128         case COLLADA_TYPE::INSTANCE_NODE:
129         {
130            domInstance_node* instanceNode = daeSafeCast<domInstance_node>(child);
131            domNode* node = daeSafeCast<domNode>(instanceNode->getUrl().getElement());
132            if (node)
133               mChildNodes.push_back(new ColladaAppNode(node, this));
134            else
135               Con::warnf("Failed to resolve instance_node with url=%s", instanceNode->getUrl().originalStr().c_str());
136            break;
137         }
138      }
139   }
140}
141
142// Get all geometry attached to this node
143void ColladaAppNode::buildMeshList()
144{
145   // Process children: collect <instance_geometry> and <instance_controller> elements
146   for (S32 iChild = 0; iChild < p_domNode->getContents().getCount(); iChild++) {
147
148      daeElement* child = p_domNode->getContents()[iChild];
149      switch (child->getElementType()) {
150
151         case COLLADA_TYPE::INSTANCE_GEOMETRY:
152         {
153            // Only <geometry>.<mesh> instances are supported
154            domInstance_geometry* instanceGeom = daeSafeCast<domInstance_geometry>(child);
155            if (instanceGeom) {
156               domGeometry* geometry = daeSafeCast<domGeometry>(instanceGeom->getUrl().getElement());
157               if (geometry && geometry->getMesh())
158                  mMeshes.push_back(new ColladaAppMesh(instanceGeom, this));
159            }
160            break;
161         }
162
163         case COLLADA_TYPE::INSTANCE_CONTROLLER:
164            mMeshes.push_back(new ColladaAppMesh(daeSafeCast<domInstance_controller>(child), this));
165            break;
166      }
167   }
168}
169
170bool ColladaAppNode::animatesTransform(const AppSequence* appSeq)
171{
172   // Check if any of this node's transform elements are animated during the
173   // sequence interval
174   for (S32 iTxfm = 0; iTxfm < nodeTransforms.size(); iTxfm++) {
175      if (nodeTransforms[iTxfm].isAnimated(appSeq->getStart(), appSeq->getEnd()))
176         return true;
177   }
178   return false;
179}
180
181/// Get the world transform of the node at the specified time
182MatrixF ColladaAppNode::getNodeTransform(F32 time)
183{
184   // Avoid re-computing the default transform if possible
185   if (defaultTransformValid && time == TSShapeLoader::DefaultTime)
186   {
187      return defaultNodeTransform;
188   }
189   else
190   {
191      MatrixF nodeTransform = getTransform(time);
192
193      // Check for inverted node coordinate spaces => can happen when modelers
194      // use the 'mirror' tool in their 3d app. Shows up as negative <scale>
195      // transforms in the collada model.
196      if (m_matF_determinant(nodeTransform) < 0.0f)
197      {
198         // Mark this node as inverted so we can mirror mesh geometry, then
199         // de-invert the transform matrix
200         invertMeshes = true;
201         nodeTransform.scale(Point3F(1, 1, -1));
202      }
203
204      // Cache the default transform
205      if (time == TSShapeLoader::DefaultTime)
206      {
207         defaultTransformValid = true;
208         defaultNodeTransform = nodeTransform;
209      }
210
211      return nodeTransform;
212   }
213}
214
215MatrixF ColladaAppNode::getTransform(F32 time)
216{
217   // Check if we can use the last computed transform
218   if (time == lastTransformTime)
219      return lastTransform;
220
221   if (appParent) {
222      // Get parent node's transform
223      lastTransform = appParent->getTransform(time);
224   }
225   else {
226      // no parent (ie. root level) => scale by global shape <unit>
227      lastTransform.identity();
228      lastTransform.scale(ColladaUtils::getOptions().unit);
229      if (!isBounds())
230         ColladaUtils::convertTransform(lastTransform);     // don't convert bounds node transform (or upAxis won't work!)
231   }
232
233   // Multiply by local node transform elements
234   for (S32 iTxfm = 0; iTxfm < nodeTransforms.size(); iTxfm++) {
235
236      MatrixF mat(true);
237
238      // Convert the transform element to a MatrixF
239      switch (nodeTransforms[iTxfm].element->getElementType()) {
240         case COLLADA_TYPE::TRANSLATE: mat = vecToMatrixF<domTranslate>(nodeTransforms[iTxfm].getValue(time));  break;
241         case COLLADA_TYPE::SCALE:     mat = vecToMatrixF<domScale>(nodeTransforms[iTxfm].getValue(time));      break;
242         case COLLADA_TYPE::ROTATE:    mat = vecToMatrixF<domRotate>(nodeTransforms[iTxfm].getValue(time));     break;
243         case COLLADA_TYPE::MATRIX:    mat = vecToMatrixF<domMatrix>(nodeTransforms[iTxfm].getValue(time));     break;
244         case COLLADA_TYPE::SKEW:      mat = vecToMatrixF<domSkew>(nodeTransforms[iTxfm].getValue(time));       break;
245         case COLLADA_TYPE::LOOKAT:    mat = vecToMatrixF<domLookat>(nodeTransforms[iTxfm].getValue(time));     break;
246      }
247
248      // Remove node scaling (but keep reflections) if desired
249      if (ColladaUtils::getOptions().ignoreNodeScale)
250      {
251         Point3F invScale = mat.getScale();
252         invScale.x = invScale.x ? (1.0f / invScale.x) : 0;
253         invScale.y = invScale.y ? (1.0f / invScale.y) : 0;
254         invScale.z = invScale.z ? (1.0f / invScale.z) : 0;
255         mat.scale(invScale);
256      }
257
258      // Post multiply the animated transform
259      lastTransform.mul(mat);
260   }
261
262   lastTransformTime = time;
263   return lastTransform;
264}
265