3ds max importer - problems importing skeletal data

I am exporting skeletal data without animation from Maya to MAX and am encountering weird data when importing into Max using the 08/05/05 Collada tools…

When the skeelton imports through Collada to MAX, it gets the joint lengths correct but fails to lock in the transforms and pivot/rotation of the joints - instead it becomes a jumbled unusable mess.

Does anyone have any idea what I may be doing wrong? The .dae file imports back into maya correnctly, but wiht MAX, no dice.

maya collada exporter v 0.61
max collada version built 08/05/05

Collada looks very promising, I just wish I could get past this hump.

Nathan Walpole
Lead Animator
Bungie Studios - Halo 2

We also see the same errors when trying to load the example Collada files into Max using the 8-5-2005 version of the importer. For example, loading cylinder_man.xml from the COLLADA_120_viewer_and_samples.zip file creates a set of cylinders bunched around the origin.

Any help would be appreciated.

There was some changes between COLLADA 1.2 and 1.3 which would explain some of the problems you are encountering. We are still working on some issues with imports of skeletal animations. Pivots are tricky to import in 3ds Max.
This is a hard problem and I will keep you updated on our progress.

Thanks,
Jean-Luc:

Hi,

We are having some issues with Collada and max too.

Early days at the moment but the sample files are not importing correctly. The ‘cylinder man’ file does not import all at world origin as described above but does import with a random looking placement.

The animation is there but I can’t make any sense of it at the moment either.

On a simpler test exporting a teapot mesh with a diffuse texture from Max I can import and export this correctly using the latest scripted ‘In Out’ files. However if I use the standard type of export when I import the file again I get missing faces and some flipped normals in the mesh.

I understand you guys will be under a lot of pressure with Siggraph just gone and Max 8 arriving but it would be very helpful to get an estimate of when you think the Collada import and exports from Max are likely to be solid and production ready.

Cheers

Jolyon

Central Tech Group
Codemasters

We were too. I’ve fixed some of the problems and we can import skeletal animation now as seperate translate, rotate, scale or matrices.

I can post my changes here if anyone is interested. A message with the contents of the ‘patch’ file ok?

Weve been considering doing the same work just to get basic animation rigs transferring from Maya to Max. I’d love to try out your solution. please post or PM me with the file.

Thanks!

Hi Kevt,

Any informnation would be appreciated, if you can post stuff please do :slight_smile:

Cheers

Jolyon

ok. my changes follow.

I’ve just realised that the original problem was to import into Max. My changes are for export from Max, so I haven’t helped your problem here.
However, I have fixed the export from Max plugin which did have issues for us and previously we couldn’t export animation from max at all but now we can.

We don’t have any problems importing animation into Max, because the animators will probably use fbx which comes with Maya and Max.

Please enable ‘KEVT_MATRICES’ by activating the #define. Exporting as matrices works fine and is not really slow. You will get both skeleton and skeletal animation exporting ok, and you’ll get <matrix> under <node> and matrix data in the animation arrays - same as maya collada exporter generates.

Exporting as seperate translate,rotate,scale is very slow , by disabling ‘KEVT_MATRICES’ and needs a lot of optimisation to make it useable; for example if a transform is driving the position, rotation and scale, it will actually sample this 3 times. I haven’t changed this yet.

But, it works much better than it used to and actually generates more reasonable data.

I have tested the export with matrices with some of our animations.
Following is a unified diff.

— orig.cpp 2005-08-22 14:36:00.312244600 +0100
+++ shared/ColladaExporter.cpp 2005-08-19 14:58:46.000000000 +0100
@@ -18,8 +18,8 @@
#include “IGameModifier.h”
#include “IConversionManager.h”
#include “IGameError.h”

-//#define KEVT_MATRICES
+
+//#define KEVT_MATRICES

// exporter’s class ID
#define COALLADAEXPORTER_CLASS_ID Class_ID(0x18466e01, 0x17b5275b)
@@ -86,11 +86,11 @@
PropMapper mapper; // value mapper if not NULL
Tab<TSTR*> targets; // channel targets
Tab<TSTR*> subanims; // subanim IDs

  •   Tab&lt;TSTR*&gt; params;	
    
  •   IGameNode *n;
    
  •   Tab&lt;TSTR*&gt; params;	
    
  •   IGameNode *n;
    
      AnimParam(IGameNode* node) {
    
  •   	n = node;
    
  •   	n = node;
      	nodeName = node-&gt;GetName(); cleanID(nodeName);
      	makeNodeID(node, objectID);
      	mapper = identity;
    

@@ -103,7 +103,7 @@

	TSTR& getTarget(int i) { return  i &lt; 0 ? paramID : *targets[i]; }
	TSTR& getSubanimID(int i) { return i &lt; 0 ? animID : *subanims[i]; }
  •   TSTR& getParam(int i) { return i&lt;0 ? paramID : *params[i]; }
    
  •   TSTR& getParam(int i) { return i&lt;0 ? paramID : *params[i]; }
    
      AnimParam& setAnim(TCHAR* param, IGameControl* gc, IGameControlType gtype) {
      	paramID = param; cleanID(paramID);
    

@@ -150,9 +150,9 @@
}

	void setSubanims(TCHAR* sx, TCHAR* sy, TCHAR* sz) {
  •   	TSTR * ps[3] = { new TSTR(sx), new TSTR(sy), new TSTR(sz) };
    
  •        params.Append(3, (TSTR**)&ps);
    
  •   	TSTR * ps[3] = { new TSTR(sx), new TSTR(sy), new TSTR(sz) };
    
  •        params.Append(3, (TSTR**)&ps);
    
  •   	clearSubanims(); 
      	TSTR prefix = objectID + TSTR(_T("-")) + paramID + TSTR(_T("-"));
      	TSTR* ns[3] = { new TSTR(prefix), new TSTR(prefix), new TSTR(prefix) };
    

@@ -258,7 +258,7 @@
pt_string,
pt_name,
pt_bool,

  •   pt_matrix,
    
  •   pt_matrix,
    
    };
    static TCHAR* typeNames;

@@ -274,7 +274,8 @@
_T(“int”),
_T(“string”),
_T(“Name”),

  • _T(“bool”)
  • _T(“bool”),
  • _T(“matrix”),
    };

class ColladaExporterClassDesc:public ClassDesc2
@@ -669,7 +670,9 @@
// create COLLADA node and its attribs
CreateXMLNode(pXMLDoc, pRoot, _T(“COLLADA”), &colladaNode);
AddXMLAttribute(colladaNode, _T(“xmlns”), _T(“COLLADA 1.3 Schema”));

  • AddXMLAttribute(colladaNode, _T(“version”), _T(“1.2.3”));
    +// kevt
  • AddXMLAttribute(colladaNode, _T(“version”), _T(“1.3.2”));
  • // add <asset> node
    CComPtr<IXMLDOMNode> assetNode;
    CComPtr<IXMLDOMNode> tempNode;
    @@ -694,14 +697,14 @@
    tempNode = NULL;
    CreateXMLNode(pXMLDoc, assetNode, _T(“up_axis”), &tempNode);
    AddXMLText(pXMLDoc, tempNode, _T(“Z_UP”));
  • // kevt
  • CComPtr<IXMLDOMNode> unitNode;
  • CreateXMLNode(pXMLDoc, assetNode, _T(“unit”), &unitNode);
  • AddXMLAttribute(unitNode, _T(“name”), _T(“generic”));
  • // get internal units in terms of meters
  • buf.printf(“%g”,GetMasterScale(UNITS_METERS));
  • AddXMLAttribute(unitNode, _T(“meter”), buf);
  • // kevt
  • CComPtr<IXMLDOMNode> unitNode;
  • CreateXMLNode(pXMLDoc, assetNode, _T(“unit”), &unitNode);
  • AddXMLAttribute(unitNode, _T(“name”), _T(“generic”));
  • // get internal units in terms of meters
  • buf.printf(“%g”,GetMasterScale(UNITS_METERS));
  • AddXMLAttribute(unitNode, _T(“meter”), buf);
    }

void
@@ -856,36 +859,37 @@
void
ColladaExporter::AddSceneNodes(CComPtr<IXMLDOMNode>& rootNode, IGameNode* node)
{

  • // kevt: if hidden then don’t export!
  • if (node->IsNodeHidden())
  •   return;
    
  • // kevt: if hidden then don’t export!
  • if (node->IsNodeHidden())
  •   return;
    
  • // add <node> nodes for this node and its children
    TSTR buf, nodeID, nodeName = node->GetName(); cleanID(nodeName);
    makeNodeID(node, nodeID);
  • // optional insert node for pivot if objectOffsetTM is non-ident

  • CComPtr<IXMLDOMNode> parentNode = AddPivotNode(rootNode, node, nodeName);

    // add <node>
    CComPtr<IXMLDOMNode> nodeNode, instNode, transNode, rotNode, scaleNode;

  • CreateXMLNode(pXMLDoc, parentNode, _T(“node”), &nodeNode); // <node>

  • CreateXMLNode(pXMLDoc, rootNode, _T(“node”), &nodeNode); // <node>
    AddXMLAttribute(nodeNode, _T(“id”), nodeID);
    AddXMLAttribute(nodeNode, _T(“name”), nodeName);
  • // kevt:
  • // optional insert node for pivot if objectOffsetTM is non-ident
  • // this is not inherited!
  • CComPtr<IXMLDOMNode> pivotNode = AddPivotNode(nodeNode, node, nodeName);
  • // kevt:

  • // optional insert node for pivot if objectOffsetTM is non-ident

  • // this is not inherited!

  • CComPtr<IXMLDOMNode> pivotNode = AddPivotNode(nodeNode, node, nodeName);

  • // add <instance> based on class
    IGameObject* obj = node->GetIGameObject();
    TSTR objID; makeObjectID(obj, objID, node);
    switch (obj->GetIGameType()) {

      case IGameObject::IGAME_MESH:
    
  •   	CreateXMLNode(pXMLDoc, nodeNode, _T("instance"), &instNode);		// &lt;instance&gt;
    
  •   {
    
  •   	// kevt:
    
  •   	// put mesh under pivot node, or parent node if pivot is ident
    
  •   	CreateXMLNode(pXMLDoc, pivotNode, _T("instance"), &instNode);		// &lt;instance&gt;
      	if (obj-&gt;IsObjectXRef()) {
      		// xref, url is external file
      		//	 construct valid xref file URI with .dae suffix
    

@@ -899,10 +903,11 @@
else
// url is baseObj id
AddXMLAttribute(instNode, _T(“url”), TSTR(_T(“#”)) + (IsSkinned(obj, node) ? TSTR(_T(“skin-”)) : TSTR()) + objID);

  •   	break;
    
  •   }
    
  •   break;
    
      case IGameObject::IGAME_LIGHT:
    
  •   	CreateXMLNode(pXMLDoc, nodeNode, _T("instance"), &instNode);		// &lt;instance&gt;
    
  •   	CreateXMLNode(pXMLDoc, pivotNode, _T("instance"), &instNode);		// &lt;instance&gt;
      	AddXMLAttribute(instNode, _T("url"), TSTR(_T("#")) + objID);
      	break;
    

@@ -910,19 +915,23 @@
break;

	case IGameObject::IGAME_CAMERA:
  •   	CreateXMLNode(pXMLDoc, nodeNode, _T("instance"), &instNode);		// &lt;instance&gt;
    
  •   	CreateXMLNode(pXMLDoc, pivotNode, _T("instance"), &instNode);		// &lt;instance&gt;
      	AddXMLAttribute(instNode, _T("url"), TSTR(_T("#")) + objID);
      	break;
    
      case IGameObject::IGAME_HELPER:
    
  •   	break;
    
  •   {
    
  •   }
    
  •   break;
    
      case IGameObject::IGAME_BONE:
      	AddXMLAttribute(nodeNode, _T("type"), _T("JOINT"));
      	break;
    
      case IGameObject::IGAME_IKCHAIN:
    
  •   	break;
    
  •   {
    
  •   }
    
  •   break;
    

    }

    // add transform nodes
    @@ -959,172 +968,166 @@
    else {
    // PRS nodes for others

-// kevt; both of these work now
-#ifdef KEVT_MATRICES

  •   // world space transformation of the node at the current time
    
  •   Matrix3 tm = node-&gt;GetMaxNode()-&gt;GetNodeTM(0);
    
  •   Matrix3 iParentTM(1);
    
  •   // world space transformation of the node's parent at the current time
    
  •   IGameNode *parent = node-&gt;GetNodeParent();
    
  •   if (parent != NULL) iParentTM = parent-&gt;GetMaxNode()-&gt;GetNodeTM(0);
    
  •   iParentTM.Invert();
    
  •   // local matrix relative to parent
    
  •   tm = tm * iParentTM;
    
  •    CComPtr&lt;IXMLDOMNode&gt; matrixNode;
    
  •   CreateXMLNode(pXMLDoc, nodeNode, _T("matrix"), &matrixNode);		// &lt;scale&gt;
    
  •   // if any channel is animated then matrix is animated
    
  •   IGameControl* c = node-&gt;GetIGameControl();
    
  •   if (
    
  •   	// biped controlls can say they are not animated yet they have keys
    
  •   	(c-&gt;GetIGameKeyCount(IGAME_POS)!=0) || 
    
  •   	(c-&gt;GetIGameKeyCount(IGAME_ROT)!=0) || 
    
  •   	(c-&gt;GetIGameKeyCount(IGAME_SCALE)!=0) ||
    
  •   	c-&gt;IsAnimated(IGAME_POS) || 
    
  •   	c-&gt;IsAnimated(IGAME_ROT) || 
    
  •   	c-&gt;IsAnimated(IGAME_SCALE) 
    
  •   	)
    
  •   {
    
  •   	AddXMLAttribute(matrixNode, _T("sid"), _T("transform"));
    
  •   }
    
  •   // this code converts from max matrix to collada matrix and outputs it in the collada form
    
  •   float matrix[4][4];
    
  •   Point3 row = tm.GetRow(0);
    
  •   matrix[0][0] = row.x;
    
  •   matrix[1][0] = row.y;
    
  •   matrix[2][0] = row.z;
    
  •   row = tm.GetRow(1);
    
  •   matrix[0][1] = row.x;
    
  •   matrix[1][1] = row.y;
    
  •   matrix[2][1] = row.z;
    
  •   row = tm.GetRow(2);
    
  •   matrix[0][2] = row.x;
    
  •   matrix[1][2] = row.y;
    
  •   matrix[2][2] = row.z;
    
  •   Point3 t = tm.GetRow(3);
    
  •   matrix[0][3] = t.x;
    
  •   matrix[1][3] = t.y;
    
  •   matrix[2][3] = t.z;
    
  •   matrix[3][3] = 1.0f;
    
  •   // fill unused elements
    
  •   matrix[3][0] = 0.0f;
    
  •   matrix[3][1] = 0.0f;
    
  •   matrix[3][2] = 0.0f;
    
  •   buf.printf("%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g", 
    
  •   	matrix[0][0],
    
  •   	matrix[0][1],
    
  •   	matrix[0][2],
    
  •   	matrix[0][3],
    
  •   	matrix[1][0],
    
  •   	matrix[1][1],
    
  •   	matrix[1][2],
    
  •   	matrix[1][3],
    
  •   	matrix[2][0],
    
  •   	matrix[2][1],
    
  •   	matrix[2][2],
    
  •   	matrix[2][3],
    
  •   	matrix[3][0],
    
  •   	matrix[3][1],
    
  •   	matrix[3][2],
    
  •   	matrix[3][3]);
    
  •   AddXMLText(pXMLDoc, matrixNode, buf);
    

-#else
+// kevt; both of these work now
+#ifdef KEVT_MATRICES

  •   // world space transformation of the node at the current time
    
  •   Matrix3 tm = node-&gt;GetMaxNode()-&gt;GetNodeTM(0);
    
  •   Matrix3 iParentTM(1);
    
  •   // world space transformation of the node's parent at the current time
    
  •   IGameNode *parent = node-&gt;GetNodeParent();
    
  •   if (parent != NULL) iParentTM = parent-&gt;GetMaxNode()-&gt;GetNodeTM(0);
    
  •   iParentTM.Invert();
    
  •   // local matrix relative to parent
    
  •   tm = tm * iParentTM;
    
  •    CComPtr&lt;IXMLDOMNode&gt; matrixNode;
    
  •   CreateXMLNode(pXMLDoc, nodeNode, _T("matrix"), &matrixNode);		// &lt;scale&gt;
    
  •   // if any channel is animated then matrix is animated
    
  •   IGameControl* c = node-&gt;GetIGameControl();
    
  •   if (
    
  •   	// biped controlls can say they are not animated yet they have keys
    
  •   	(c-&gt;GetIGameKeyCount(IGAME_POS)!=0) || 
    
  •   	(c-&gt;GetIGameKeyCount(IGAME_ROT)!=0) || 
    
  •   	(c-&gt;GetIGameKeyCount(IGAME_SCALE)!=0) ||
    
  •   	c-&gt;IsAnimated(IGAME_POS) || 
    
  •   	c-&gt;IsAnimated(IGAME_ROT) || 
    
  •   	c-&gt;IsAnimated(IGAME_SCALE) 
    
  •   	)
    
  •   {
    
  •   	AddXMLAttribute(matrixNode, _T("sid"), _T("transform"));
    
  •   }
    
  •   // this code converts from max matrix to collada matrix and outputs it in the collada form
    
  •   float matrix[4][4];
    
  •   Point3 row = tm.GetRow(0);
    
  •   matrix[0][0] = row.x;
    
  •   matrix[1][0] = row.y;
    
  •   matrix[2][0] = row.z;
    
  •   row = tm.GetRow(1);
    
  •   matrix[0][1] = row.x;
    
  •   matrix[1][1] = row.y;
    
  •   matrix[2][1] = row.z;
    
  •   row = tm.GetRow(2);
    
  •   matrix[0][2] = row.x;
    
  •   matrix[1][2] = row.y;
    
  •   matrix[2][2] = row.z;
    
  •   Point3 t = tm.GetRow(3);
    
  •   matrix[0][3] = t.x;
    
  •   matrix[1][3] = t.y;
    
  •   matrix[2][3] = t.z;
    
  •   matrix[3][3] = 1.0f;
    
  •   // fill unused elements
    
  •   matrix[3][0] = 0.0f;
    
  •   matrix[3][1] = 0.0f;
    
  •   matrix[3][2] = 0.0f;
    
  •   buf.printf("%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g", 
    
  •   	matrix[0][0],
    
  •   	matrix[0][1],
    
  •   	matrix[0][2],
    
  •   	matrix[0][3],
    
  •   	matrix[1][0],
    
  •   	matrix[1][1],
    
  •   	matrix[1][2],
    
  •   	matrix[1][3],
    
  •   	matrix[2][0],
    
  •   	matrix[2][1],
    
  •   	matrix[2][2],
    
  •   	matrix[2][3],
    
  •   	matrix[3][0],
    
  •   	matrix[3][1],
    
  •   	matrix[3][2],
    
  •   	matrix[3][3]);
    
  •   AddXMLText(pXMLDoc, matrixNode, buf);
    

+#else
// set up various transforms and decompose node TM into affine parts
Matrix3 tm = node->GetMaxNode()->GetNodeTM(0);
Matrix3 iparentTM(1);
IGameNode* parent = node->GetNodeParent();
if (parent != NULL) iparentTM = parent->GetMaxNode()->GetNodeTM(0);
iparentTM.Invert();

  •   tm = tm * iparentTM;
    
  •   Point3 row1 = tm.GetRow(0);
    
  •   Point3 row2 = tm.GetRow(1);
    
  •   Point3 row3 = tm.GetRow(2);
    
  •   Point3 row4 = tm.GetRow(3);
    
  •   Matrix3 TransposedTM;
    
  •   Point4 column1;
    
  •   Point4 column2;
    
  •   Point4 column3;
    
  •   column1.x = row1.x;
    
  •   column1.y = row1.y;
    
  •   column1.z = row1.z;
    
  •   column1.w = row4.x;
    
  •   column2.x = row2.x;
    
  •   column2.y = row2.y;
    
  •   column2.z = row2.z;
    
  •   column2.w = row4.y;
    
  •   column3.x = row3.x;
    
  •   column3.y = row3.y;
    
  •   column3.z = row3.z;
    
  •   column3.w = row4.z;
    
  •   TransposedTM.SetColumn(0, column1);
    
  •   TransposedTM.SetColumn(1, column2);
    
  •   TransposedTM.SetColumn(2, column3);
    
  •   tm = tm * iparentTM;
    
  •   Point3 row1 = tm.GetRow(0);
    
  •   Point3 row2 = tm.GetRow(1);
    
  •   Point3 row3 = tm.GetRow(2);
    
  •   Point3 row4 = tm.GetRow(3);
    
  •   Matrix3 TransposedTM;
    
  •   Point4 column1;
    
  •   Point4 column2;
    
  •   Point4 column3;
    
  •   column1.x = row1.x;
    
  •   column1.y = row1.y;
    
  •   column1.z = row1.z;
    
  •   column1.w = row4.x;
    
  •   column2.x = row2.x;
    
  •   column2.y = row2.y;
    
  •   column2.z = row2.z;
    
  •   column2.w = row4.y;
    
  •   column3.x = row3.x;
    
  •   column3.y = row3.y;
    
  •   column3.z = row3.z;
    
  •   column3.w = row4.z;
    
  •   TransposedTM.SetColumn(0, column1);
    
  •   TransposedTM.SetColumn(1, column2);
    
  •   TransposedTM.SetColumn(2, column3);
    
  •   AffineParts ap;
    
  •   decomp_affine(tm, &ap);
    
  •   decomp_affine(TransposedTM, &ap);
    
	// translation
	CComPtr&lt;IXMLDOMNode&gt; transNode;
	CreateXMLNode(pXMLDoc, nodeNode, _T("translate"), &transNode);		// &lt;translate&gt;
	// check for animation, add sid attrib if so
	IGameControl* c = node-&gt;GetIGameControl();
  •   if (c-&gt;IsAnimated(IGAME_POS))
    
  •   if (c-&gt;IsAnimated(IGAME_POS) || (c-&gt;GetIGameKeyCount(IGAME_POS)!=0) )
      	AddXMLAttribute(transNode, _T("sid"), _T("Trans"));
    
  •   // pos in parent coordsys
    
  •   Point3 p = tm.GetTrans() * iparentTM;
    
  •   Point3 p = ap.t;
      buf.printf("%g %g %g ", p.x, p.y, p.z);
      AddXMLText(pXMLDoc, transNode, buf);
    
      // rotation
      CComPtr&lt;IXMLDOMNode&gt; rotNode;
      // check for animation, add sid attrib if so
    
  •   bool hasAnim = c-&gt;IsAnimated(IGAME_ROT);
    
  •   Point3 mp; Quat mq; Point3 ms;
    
  •   DecomposeMatrix(iparentTM, mp, mq, ms);
    
  •   ap.q = ap.q + mq;
    
  •   // as eulerangles for output
    
  •   float angles[3];
    
  •   Matrix3 qtm;
    
  •   ap.q.MakeMatrix(qtm);
    
  •   MatrixToEuler(qtm, angles, EULERTYPE_XYZ);
    
  •   bool hasAnim = c-&gt;IsAnimated(IGAME_ROT) || (c-&gt;GetIGameKeyCount(IGAME_ROT)!=0);
    
  •   float angles[3];
    
  •   QuatToEuler(ap.q, angles);
    
  •   angles[0] = -angles[0];
    
  •   angles[1] = -angles[1];
    
  •   angles[2] = -angles[2];
    
  •   float angles[3];
    
  •   QuatToEuler(ap.q, angles);
    
  •   angles[0] = -angles[0];
    
  •   angles[1] = -angles[1];
    
  •   angles[2] = -angles[2];
    
  •   CreateXMLNode(pXMLDoc, nodeNode, _T("rotate"), &rotNode);		// &lt;rotate&gt; x
      if (hasAnim) AddXMLAttribute(rotNode, _T("sid"), _T("RotX"));
      buf.printf("1 0 0 %g", RadToDeg(angles[0]));
    

@@ -1140,25 +1143,16 @@
buf.printf(“0 0 1 %g”, RadToDeg(angles[2]));
AddXMLText(pXMLDoc, rotNode, buf);

  •   // scale
    
  •   // get scale in parent coordsys
    
  •   ScaleValue s(ap.k, ap.u);
    
  •   Matrix3 m (1);
    
  •   Matrix3 sm (1);
    
  •   ApplyScaling(sm, s);
    
  •   AffineParts sap;
    
  •   sm = sm * iparentTM;
    
  •   decomp_affine(sm, &sap);
    
  •   Point3 scale = sap.k * sap.f;
    
  •   Point3 scale = ap.k * ap.f;
    
      CComPtr&lt;IXMLDOMNode&gt; scaleNode;
      CreateXMLNode(pXMLDoc, nodeNode, _T("scale"), &scaleNode);		// &lt;scale&gt;
      buf.printf("%g %g %g ", scale.x, scale.y, scale.z);
      AddXMLText(pXMLDoc, scaleNode, buf);
    
  •   if (c-&gt;IsAnimated(IGAME_SCALE)) 
    
  •   if (c-&gt;IsAnimated(IGAME_SCALE)  || (c-&gt;GetIGameKeyCount(IGAME_SCALE)!=0)) 
      	AddXMLAttribute(scaleNode, _T("sid"), _T("Scale"));
    

-#endif
+
+#endif
}

node-&gt;ReleaseIGameObject();

@@ -1179,83 +1173,83 @@
if (opos == Point3::Origin && orot == Quat() && oscale == Point3(1,1,1))
return parentNode; // no need for pivot

  • // insert pivot node for objectOffsetTM
  • CComPtr<IXMLDOMNode> nodeNode, transNode, rotNode, scaleNode;
  • TSTR buf;
  •   CComPtr&lt;IXMLDOMNode&gt; nodeNode, transNode, rotNode, scaleNode;
    
    CreateXMLNode(pXMLDoc, parentNode, _T(“node”), &nodeNode); // <node>
    AddXMLAttribute(nodeNode, _T(“id”), nodeName + TSTR(_T(“_PIVOT”)));
    AddXMLAttribute(nodeNode, _T(“name”), nodeName + TSTR(_T(“_PIVOT”)));

-// kevt
-#ifdef KEVT_MATRICES

  •   // world space transformation of the node at the current time
    
  •   Matrix3 tm(1);
    
  •   tm.PreTranslate(opos);
    
  •   PreRotateMatrix(tm, orot);
    
  •   ScaleValue scaleValue = maxNode-&gt;GetObjOffsetScale();
    
  •   ApplyScaling(tm, scaleValue);
    
  •    CComPtr&lt;IXMLDOMNode&gt; matrixNode;
    
  •   CreateXMLNode(pXMLDoc, nodeNode, _T("matrix"), &matrixNode);		// &lt;matrix&gt;
    
  •   // this code converts from max matrix to collada matrix and outputs it in the collada form
    
  •   float matrix[4][4];
    
  •   Point3 row = tm.GetRow(0);
    
  •   matrix[0][0] = row.x;
    
  •   matrix[1][0] = row.y;
    
  •   matrix[2][0] = row.z;
    
  •   row = tm.GetRow(1);
    
  •   matrix[0][1] = row.x;
    
  •   matrix[1][1] = row.y;
    
  •   matrix[2][1] = row.z;
    
  •   row = tm.GetRow(2);
    
  •   matrix[0][2] = row.x;
    
  •   matrix[1][2] = row.y;
    
  •   matrix[2][2] = row.z;
    
  •   Point3 t = tm.GetRow(3);
    
  •   matrix[0][3] = t.x;
    
  •   matrix[1][3] = t.y;
    
  •   matrix[2][3] = t.z;
    
  •   matrix[3][3] = 1.0f;
    
  •   // fill unused elements
    
  •   matrix[3][0] = 0.0f;
    
  •   matrix[3][1] = 0.0f;
    
  •   matrix[3][2] = 0.0f;
    
  •   buf.printf("%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g", 
    
  •   	matrix[0][0],
    
  •   	matrix[0][1],
    
  •   	matrix[0][2],
    
  •   	matrix[0][3],
    
  •   	matrix[1][0],
    
  •   	matrix[1][1],
    
  •   	matrix[1][2],
    
  •   	matrix[1][3],
    
  •   	matrix[2][0],
    
  •   	matrix[2][1],
    
  •   	matrix[2][2],
    
  •   	matrix[2][3],
    
  •   	matrix[3][0],
    
  •   	matrix[3][1],
    
  •   	matrix[3][2],
    
  •   	matrix[3][3]);
    
  •   AddXMLText(pXMLDoc, matrixNode, buf);
    

-#else

  • // insert pivot node for objectOffsetTM

+// kevt
+#ifdef KEVT_MATRICES

  •   // world space transformation of the node at the current time
    
  •   Matrix3 tm(1);
    
  •   tm.PreTranslate(opos);
    
  •   PreRotateMatrix(tm, orot);
    
  •   ScaleValue scaleValue = maxNode-&gt;GetObjOffsetScale();
    
  •   ApplyScaling(tm, scaleValue);
    
  •    CComPtr&lt;IXMLDOMNode&gt; matrixNode;
    
  •   CreateXMLNode(pXMLDoc, nodeNode, _T("matrix"), &matrixNode);		// &lt;matrix&gt;
    
  •   // this code converts from max matrix to collada matrix and outputs it in the collada form
    
  •   float matrix[4][4];
    
  •   Point3 row = tm.GetRow(0);
    
  •   matrix[0][0] = row.x;
    
  •   matrix[1][0] = row.y;
    
  •   matrix[2][0] = row.z;
    
  •   row = tm.GetRow(1);
    
  •   matrix[0][1] = row.x;
    
  •   matrix[1][1] = row.y;
    
  •   matrix[2][1] = row.z;
    
  •   row = tm.GetRow(2);
    
  •   matrix[0][2] = row.x;
    
  •   matrix[1][2] = row.y;
    
  •   matrix[2][2] = row.z;
    
  •   Point3 t = tm.GetRow(3);
    
  •   matrix[0][3] = t.x;
    
  •   matrix[1][3] = t.y;
    
  •   matrix[2][3] = t.z;
    
  •   matrix[3][3] = 1.0f;
    
  •   // fill unused elements
    
  •   matrix[3][0] = 0.0f;
    
  •   matrix[3][1] = 0.0f;
    
  •   matrix[3][2] = 0.0f;
    
  •   buf.printf("%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g", 
    
  •   	matrix[0][0],
    
  •   	matrix[0][1],
    
  •   	matrix[0][2],
    
  •   	matrix[0][3],
    
  •   	matrix[1][0],
    
  •   	matrix[1][1],
    
  •   	matrix[1][2],
    
  •   	matrix[1][3],
    
  •   	matrix[2][0],
    
  •   	matrix[2][1],
    
  •   	matrix[2][2],
    
  •   	matrix[2][3],
    
  •   	matrix[3][0],
    
  •   	matrix[3][1],
    
  •   	matrix[3][2],
    
  •   	matrix[3][3]);
    
  •   AddXMLText(pXMLDoc, matrixNode, buf);
    

+#else

  • // insert pivot node for objectOffsetTM
    CreateXMLNode(pXMLDoc, nodeNode, _T(“translate”), &transNode); // <translate>
  • TSTR buf; buf.printf(“%g %g %g”, opos.x, opos.y, opos.z);
  • buf.printf(“%g %g %g”, opos.x, opos.y, opos.z);
    AddXMLText(pXMLDoc, transNode, buf);
    float rx, ry, rz;
    orot.GetEuler(&rx, &ry, &rz) ;
    @@ -1273,7 +1267,7 @@
    CreateXMLNode(pXMLDoc, nodeNode, _T(“scale”), &scaleNode); // <scale>
    buf.printf(“%g %g %g”, oscale.x, oscale.y, oscale.z);
    AddXMLText(pXMLDoc, scaleNode, buf);
    -#endif
    +#endif

    return nodeNode;
    }
    @@ -1283,44 +1277,22 @@
    void
    ColladaExporter::AddCameraNodes(CComPtr<IXMLDOMNode>& libNode, IGameNode* node)
    {

  • // add <camera> library node for nodes that are cameras
  • IGameObject* obj = node->GetIGameObject();
  • if (!node->IsNodeHidden())
  • {
  •   //  add &lt;camera&gt; library node for nodes that are cameras
    
  •   IGameObject* obj = node-&gt;GetIGameObject();
    
  • if (obj->GetIGameType() == IGameObject::IGAME_CAMERA) {
  •   TSTR objID; makeObjectID(obj, objID, node);
    
  •   IGameCamera* cam = (IGameCamera*)obj;
    
  •   CameraObject* camObj = (CameraObject*)cam-&gt;GetMaxObject();
    
  •   if (obj-&gt;GetIGameType() == IGameObject::IGAME_CAMERA) {
    
  •   	TSTR objID; makeObjectID(obj, objID, node);
    
  •   	IGameCamera* cam = (IGameCamera*)obj;
    
  •   	CameraObject* camObj = (CameraObject*)cam-&gt;GetMaxObject();
    
  •   CComPtr&lt;IXMLDOMNode&gt; camNode, techNode, optNode, progNode, paramNode;
    
  •   CreateXMLNode(pXMLDoc, libNode, _T("camera"), &camNode);		// &lt;camera&gt;
    
  •   AddXMLAttribute(camNode, _T("id"), objID);
    
  •   AddXMLAttribute(camNode, _T("name"), objID);
    
  •   	CreateXMLNode(pXMLDoc, camNode, _T("technique"), &techNode);		// &lt;technique&gt;
    
  •   	AddXMLAttribute(techNode, _T("profile"), _T("COMMON"));
    
  •   		CreateXMLNode(pXMLDoc, techNode, _T("optics"), &optNode);		//   &lt;optics&gt;
    
  •   			CreateXMLNode(pXMLDoc, optNode, _T("program"), &progNode);		//   &lt;program&gt;
    
  •   			// add perspective or ortho attribs & props
    
  •   			if (camObj-&gt;IsOrtho()) {
    
  •   				AddXMLAttribute(progNode, _T("url"), _T("ORTHOGRAPHIC"));
    
  •   				AddXMLAttribute(progNode, _T("name"), _T("ORTHOGRAPHIC"));
    
  •   			} 
    
  •   			else {
    
  •   				AddXMLAttribute(progNode, _T("url"), _T("PERSPECTIVE"));
    
  •   				AddXMLAttribute(progNode, _T("name"), _T("PERSPECTIVE"));
    
  •   				float fov; cam-&gt;GetCameraFOV()-&gt;GetPropertyValue(fov);
    
  •   				AddParamValNode(progNode, _T("YFOV"), pt_float, _T("IN"), RadToDeg(fov), (cam-&gt;GetCameraFOV()-&gt;IsPropAnimated() ? _T("FOV") : NULL));
    
  •   			}
    
  •   			// add common props
    
  •   			float n; cam-&gt;GetCameraNearClip()-&gt;GetPropertyValue(n);
    
  •   			AddParamValNode(progNode, _T("ZNEAR"), pt_float, _T("IN"), n, (cam-&gt;GetCameraNearClip()-&gt;IsPropAnimated() ? _T("NearClip") : NULL));
    
  •   			float f; cam-&gt;GetCameraFarClip()-&gt;GetPropertyValue(f);
    
  •   			AddParamValNode(progNode, _T("ZFAR"), pt_float, _T("IN"), f, (cam-&gt;GetCameraFarClip()-&gt;IsPropAnimated() ? _T("FarClip") : NULL));
    
  •   	// if target, add 3DSMAX technique
    
  •   	INode* target = node-&gt;GetMaxNode()-&gt;GetTarget();
    
  •   	if (target != NULL) {
    
  •   		techNode = NULL; optNode = NULL; progNode = NULL;
    
  •   	CComPtr&lt;IXMLDOMNode&gt; camNode, techNode, optNode, progNode, paramNode;
    
  •   	CreateXMLNode(pXMLDoc, libNode, _T("camera"), &camNode);		// &lt;camera&gt;
    
  •   	AddXMLAttribute(camNode, _T("id"), objID);
    
  •   	AddXMLAttribute(camNode, _T("name"), objID);
      		CreateXMLNode(pXMLDoc, camNode, _T("technique"), &techNode);		// &lt;technique&gt;
    
  •   		AddXMLAttribute(techNode, _T("profile"), _T("MAX3D"));
    
  •   		AddXMLAttribute(techNode, _T("profile"), _T("COMMON"));
      			CreateXMLNode(pXMLDoc, techNode, _T("optics"), &optNode);		//   &lt;optics&gt;
      				CreateXMLNode(pXMLDoc, optNode, _T("program"), &progNode);		//   &lt;program&gt;
      				// add perspective or ortho attribs & props
    

@@ -1339,17 +1311,40 @@
AddParamValNode(progNode, _T(“ZNEAR”), pt_float, _T(“IN”), n, (cam->GetCameraNearClip()->IsPropAnimated() ? _T(“NearClip”) : NULL));
float f; cam->GetCameraFarClip()->GetPropertyValue(f);
AddParamValNode(progNode, _T(“ZFAR”), pt_float, _T(“IN”), f, (cam->GetCameraFarClip()->IsPropAnimated() ? _T(“FarClip”) : NULL));

  •   				// add target ref
    
  •   				AddParamNode(progNode, _T("TARGET"), pt_name, _T("IN"), paramNode);
    
  •   				IGameNode* targNode = pIgame-&gt;GetIGameNode(target);
    
  •   				TSTR targID; makeNodeID(targNode, targID);
    
  •   				AddXMLText(pXMLDoc, paramNode, targID);
    
  •   	}
    
  •   		// if target, add 3DSMAX technique
    
  •   		INode* target = node-&gt;GetMaxNode()-&gt;GetTarget();
    
  •   		if (target != NULL) {
    
  •   			techNode = NULL; optNode = NULL; progNode = NULL;
    
  •   			CreateXMLNode(pXMLDoc, camNode, _T("technique"), &techNode);		// &lt;technique&gt;
    
  •   			AddXMLAttribute(techNode, _T("profile"), _T("MAX3D"));
    
  •   				CreateXMLNode(pXMLDoc, techNode, _T("optics"), &optNode);		//   &lt;optics&gt;
    
  •   					CreateXMLNode(pXMLDoc, optNode, _T("program"), &progNode);		//   &lt;program&gt;
    
  •   					// add perspective or ortho attribs & props
    
  •   					if (camObj-&gt;IsOrtho()) {
    
  •   						AddXMLAttribute(progNode, _T("url"), _T("ORTHOGRAPHIC"));
    
  •   						AddXMLAttribute(progNode, _T("name"), _T("ORTHOGRAPHIC"));
    
  •   					} 
    
  •   					else {
    
  •   						AddXMLAttribute(progNode, _T("url"), _T("PERSPECTIVE"));
    
  •   						AddXMLAttribute(progNode, _T("name"), _T("PERSPECTIVE"));
    
  •   						float fov; cam-&gt;GetCameraFOV()-&gt;GetPropertyValue(fov);
    
  •   						AddParamValNode(progNode, _T("YFOV"), pt_float, _T("IN"), RadToDeg(fov), (cam-&gt;GetCameraFOV()-&gt;IsPropAnimated() ? _T("FOV") : NULL));
    
  •   					}
    
  •   					// add common props
    
  •   					float n; cam-&gt;GetCameraNearClip()-&gt;GetPropertyValue(n);
    
  •   					AddParamValNode(progNode, _T("ZNEAR"), pt_float, _T("IN"), n, (cam-&gt;GetCameraNearClip()-&gt;IsPropAnimated() ? _T("NearClip") : NULL));
    
  •   					float f; cam-&gt;GetCameraFarClip()-&gt;GetPropertyValue(f);
    
  •   					AddParamValNode(progNode, _T("ZFAR"), pt_float, _T("IN"), f, (cam-&gt;GetCameraFarClip()-&gt;IsPropAnimated() ? _T("FarClip") : NULL));
    
  •   					// add target ref
    
  •   					AddParamNode(progNode, _T("TARGET"), pt_name, _T("IN"), paramNode);
    
  •   					IGameNode* targNode = pIgame-&gt;GetIGameNode(target);
    
  •   					TSTR targID; makeNodeID(targNode, targID);
    
  •   					AddXMLText(pXMLDoc, paramNode, targID);
    
  •   		}
    
  •   }
    
  •   node-&gt;ReleaseIGameObject();
    
  •   }
    
  •   node-&gt;ReleaseIGameObject();
    
    }
  • node->ReleaseIGameObject();

    // recurse through children nodes
    for (int i = 0; i < node->GetChildCount(); i++)
    @@ -1361,64 +1356,68 @@
    void
    ColladaExporter::AddAnimationNodes(CComPtr<IXMLDOMNode>& libNode, IGameNode* node)
    {

  • // add <animation> library elements for scene nodes

  • AnimParam ap(node);

  • IGameObject* obj = node->GetIGameObject();

  • if (!node->IsNodeHidden())
  • {
  •   //  add &lt;animation&gt; library elements for scene nodes
    
  •   IGameObject* obj = node-&gt;GetIGameObject();
    
  • // export selected animation based on object type
  • switch (obj->GetIGameType()) {
  •   AnimParam ap(node);
    
  •   case IGameObject::IGAME_MESH:
    
  •   	AddPRSAnimationNodes(libNode, node, ap);
    
  •   	AddMtlAnimationNodes(libNode, node, ap);
    
  •   	break;
    
  •   // export selected animation based on object type
    
  •   switch (obj-&gt;GetIGameType()) {
    
  •   case IGameObject::IGAME_LIGHT: {
    
  •   	AddPRSAnimationNodes(libNode, node, ap);
    
  •   	// light props
    
  •   	IGameLight* lt = (IGameLight*)obj;
    
  •   	TSTR ltID; makeObjectID(obj, ltID, node); ap.setObjectID(ltID);
    
  •   	ap.setSubanims(_T("R"), _T("G"), _T("B"));
    
  •   	ap.setTargets(_T("R"), _T("G"), _T("B"));
    
  •   	AddPropAnimationNodes2(libNode, ap, lt, _T("Color"), _T("COLOR"), IGAME_POINT3);
    
  •   	AddPropAnimationNodes2(libNode, ap, lt, _T("Multiplier"), _T("INTENSITY"), IGAME_FLOAT);
    
  •   	if (lt-&gt;GetLightType() != IGameLight::IGAME_OMNI) {
    
  •   		AddPropAnimationNodes2(libNode, ap, lt, _T("AspectRatio"), _T("ASPECTRATIO"), IGAME_FLOAT);
    
  •   		AddPropAnimationNodes2(libNode, ap, lt, _T("Hotspot"), _T("INNERCONE"), IGAME_FLOAT);
    
  •   		AddPropAnimationNodes2(libNode, ap, lt, _T("Falloff"), _T("OUTERCONE"), IGAME_FLOAT);
    
  •   	case IGameObject::IGAME_MESH:
    
  •   		AddPRSAnimationNodes(libNode, node, ap);
    
  •   		AddMtlAnimationNodes(libNode, node, ap);
    
  •   		break;
    
  •   	case IGameObject::IGAME_LIGHT: {
    
  •   		AddPRSAnimationNodes(libNode, node, ap);
    
  •   		// light props
    
  •   		IGameLight* lt = (IGameLight*)obj;
    
  •   		TSTR ltID; makeObjectID(obj, ltID, node); ap.setObjectID(ltID);
    
  •   		ap.setSubanims(_T("R"), _T("G"), _T("B"));
    
  •   		ap.setTargets(_T("R"), _T("G"), _T("B"));
    
  •   		AddPropAnimationNodes2(libNode, ap, lt, _T("Color"), _T("COLOR"), IGAME_POINT3);
    
  •   		AddPropAnimationNodes2(libNode, ap, lt, _T("Multiplier"), _T("INTENSITY"), IGAME_FLOAT);
    
  •   		if (lt-&gt;GetLightType() != IGameLight::IGAME_OMNI) {
    
  •   			AddPropAnimationNodes2(libNode, ap, lt, _T("AspectRatio"), _T("ASPECTRATIO"), IGAME_FLOAT);
    
  •   			AddPropAnimationNodes2(libNode, ap, lt, _T("Hotspot"), _T("INNERCONE"), IGAME_FLOAT);
    
  •   			AddPropAnimationNodes2(libNode, ap, lt, _T("Falloff"), _T("OUTERCONE"), IGAME_FLOAT);
    
  •   		}
    
  •   		break;
      	}
    
  •   	break;
    
  •   }
    
  •   case IGameObject::IGAME_SPLINE:
    
  •   	break;
    
  •   	case IGameObject::IGAME_SPLINE:
    
  •   		break;
    
  •   case IGameObject::IGAME_CAMERA: {
    
  •   	AddPRSAnimationNodes(libNode, node, ap);
    
  •   	// camera props
    
  •   	IGameCamera* cam = (IGameCamera*)obj;
    
  •   	CameraObject* camObj = (CameraObject*)cam-&gt;GetMaxObject();
    
  •   	TSTR camID; makeObjectID(obj, camID, node); ap.setObjectID(camID);
    
  •   	if (!camObj-&gt;IsOrtho())
    
  •   		AddPropAnimationNodes(libNode, ap, cam, _T("FOV"), _T("YFOV"), IGAME_FLOAT, toDegrees);
    
  •   	AddPropAnimationNodes(libNode, ap, cam, _T("NearClip"), _T("ZNEAR"), IGAME_FLOAT, toDegrees);
    
  •   	AddPropAnimationNodes(libNode, ap, cam, _T("FarClip"), _T("ZFAR"), IGAME_FLOAT, toDegrees);
    
  •   	break;
    
  •   }
    
  •   	case IGameObject::IGAME_CAMERA: {
    
  •   		AddPRSAnimationNodes(libNode, node, ap);
    
  •   		// camera props
    
  •   		IGameCamera* cam = (IGameCamera*)obj;
    
  •   		CameraObject* camObj = (CameraObject*)cam-&gt;GetMaxObject();
    
  •   		TSTR camID; makeObjectID(obj, camID, node); ap.setObjectID(camID);
    
  •   		if (!camObj-&gt;IsOrtho())
    
  •   			AddPropAnimationNodes(libNode, ap, cam, _T("FOV"), _T("YFOV"), IGAME_FLOAT, toDegrees);
    
  •   		AddPropAnimationNodes(libNode, ap, cam, _T("NearClip"), _T("ZNEAR"), IGAME_FLOAT, toDegrees);
    
  •   		AddPropAnimationNodes(libNode, ap, cam, _T("FarClip"), _T("ZFAR"), IGAME_FLOAT, toDegrees);
    
  •   		break;
    
  •   	}
    
  •   case IGameObject::IGAME_HELPER:
    
  •   	break;
    
  •   	case IGameObject::IGAME_HELPER:
    
  •   		break;
    
  •   case IGameObject::IGAME_BONE:
    
  •   	AddPRSAnimationNodes(libNode, node, ap);
    
  •   	break;
    
  •   	case IGameObject::IGAME_BONE:
    
  •   		AddPRSAnimationNodes(libNode, node, ap);
    
  •   		break;
    
  •   case IGameObject::IGAME_IKCHAIN:
    
  •   	break;
    
  • }
  •   	case IGameObject::IGAME_IKCHAIN:
    
  •   		break;
    
  •   }
    
  • node->ReleaseIGameObject();
  •   node-&gt;ReleaseIGameObject();
    
  • }

    // recurse through children nodes
    for (int i = 0; i < node->GetChildCount(); i++)
    @@ -1432,31 +1431,31 @@
    IGameControl* c = node->GetIGameControl();
    if (c != NULL)
    {
    -#ifdef KEVT_MATRICES

  •   // if any of these are animated then matrix will be animated
    
  •   if (
    
  •   	// biped controlls can say they are not animated yet they have keys
    
  •   	(c-&gt;GetIGameKeyCount(IGAME_POS)!=0) || 
    
  •   	(c-&gt;GetIGameKeyCount(IGAME_ROT)!=0) || 
    
  •   	(c-&gt;GetIGameKeyCount(IGAME_SCALE)!=0) ||
    
  •   	c-&gt;IsAnimated(IGAME_POS) || 
    
  •   	c-&gt;IsAnimated(IGAME_ROT) || 
    
  •   	c-&gt;IsAnimated(IGAME_SCALE) 
    
  •   	)
    
  •   {
    
  •   	ap.setAnim(_T("transform"), c, IGAME_TM);
    
  •   	AddAnimationNode(libNode, ap);
    
  •   }
    

-#else
+#ifdef KEVT_MATRICES

  •   // if any of these are animated then matrix will be animated
    
  •   if (
    
  •   	// biped controlls can say they are not animated yet they have keys
    
  •   	(c-&gt;GetIGameKeyCount(IGAME_POS)!=0) || 
    
  •   	(c-&gt;GetIGameKeyCount(IGAME_ROT)!=0) || 
    
  •   	(c-&gt;GetIGameKeyCount(IGAME_SCALE)!=0) ||
    
  •   	c-&gt;IsAnimated(IGAME_POS) || 
    
  •   	c-&gt;IsAnimated(IGAME_ROT) || 
    
  •   	c-&gt;IsAnimated(IGAME_SCALE) 
    
  •   	)
    
  •   {
    
  •   	ap.setAnim(_T("transform"), c, IGAME_TM);
    
  •   	AddAnimationNode(libNode, ap);
    
  •   }
    

+#else
// pos
Control* pc = c->GetMaxControl(IGAME_POS);

  •   if (pc != NULL && pc-&gt;IsAnimated()) {
    
  •   if ((pc != NULL && pc-&gt;IsAnimated()) || (c-&gt;GetIGameKeyCount(IGAME_POS)!=0))  {
      	ap.setAnim(_T("Translate"), c, IGAME_POS, _T("X"), _T("Y"), _T("Z"), _T("Trans.X"), _T("Trans.Y"), _T("Trans.Z"));
      	AddAnimationNode(libNode, ap);
      }
      // rotation
      pc = c-&gt;GetMaxControl(IGAME_ROT);
    
  •   if (pc != NULL && pc-&gt;IsAnimated()) {
    
  •   if ((pc != NULL && pc-&gt;IsAnimated()) || (c-&gt;GetIGameKeyCount(IGAME_ROT)!=0))  {
      	ap.setAnim(_T("Rotate"), c, IGAME_ROT, _T("X"), _T("Y"), _T("Z"), _T("RotX.ANGLE"), _T("RotY.ANGLE"), _T("RotZ.ANGLE"));
      	ap.setMapper(toRotDegrees);
      	AddAnimationNode(libNode, ap);
    

@@ -1464,12 +1463,12 @@
}
// scale
pc = c->GetMaxControl(IGAME_SCALE);

  •   if (pc != NULL && pc-&gt;IsAnimated()) {
    
  •   if ((pc != NULL && pc-&gt;IsAnimated())  || (c-&gt;GetIGameKeyCount(IGAME_ROT)!=0)) {
      	ap.setAnim(_T("Scale"), c, IGAME_SCALE, _T("X"), _T("Y"), _T("Z"), _T("Scale.X"), _T("Scale.Y"), _T("Scale.Z"));
      	AddAnimationNode(libNode, ap);
      }
    

-#endif

+#endif
+
}
}

@@ -1549,7 +1548,7 @@
AddSamplerNode(animNode, ap);
AddChannelNode(animNode, ap);
}

  •   }
    
    }
    }
    @@ -1564,14 +1563,14 @@
    // add <source> nodes based on controller type
    try {
    switch (ap.type) {
  •   	case IGAME_TM:
    
  •   	{
    
  •   		AddAnimationSourceNodes(animNode, ap);
    
  •   		AddSamplerNode(animNode, ap);
    
  •   		AddChannelNode(animNode, ap);
    
  •   	}
    
  •   	break;
    
  •   	case IGAME_TM:
    
  •   	{
    
  •   		AddAnimationSourceNodes(animNode, ap);
    
  •   		AddSamplerNode(animNode, ap);
    
  •   		AddChannelNode(animNode, ap);
    
  •   	}
    
  •   	break;
    
  •   	case IGAME_FLOAT:
      		AddAnimationSourceNodes(animNode, ap);
      		AddSamplerNode(animNode, ap);
    

@@ -1664,7 +1663,7 @@
CreateXMLNode(pXMLDoc, animNode, _T(“source”), &tsourceNode); // <source> for time
CreateXMLNode(pXMLDoc, animNode, _T(“source”), &vsourceNode); // <source> for values
CreateXMLNode(pXMLDoc, animNode, _T(“source”), &isourceNode); // <source> for interps

  • AddXMLAttribute(vsourceNode, _T(“id”), ap.animID);
  • AddXMLAttribute(vsourceNode, _T(“id”), ap.animID + TSTR(_T(“-values”)));
    AddXMLAttribute(tsourceNode, _T(“id”), ap.animID + TSTR(_T(“-time”)));
    AddXMLAttribute(isourceNode, _T(“id”), ap.animID + TSTR(_T(“-interp”)));
    CComPtr<IXMLDOMNode> tarrayNode, varrayNode, iarrayNode, itarrayNode, otarrayNode;
    @@ -1675,7 +1674,7 @@
    AddXMLAttribute(tarrayNode, _T(“type”), _T(“float”));

    CreateXMLNode(pXMLDoc, vsourceNode, _T(“array”), &varrayNode); // <array> for values

  • AddXMLAttribute(varrayNode, _T(“id”), ap.animID + TSTR(_T(“-array”)));
  • AddXMLAttribute(varrayNode, _T(“id”), ap.animID + TSTR(_T(“-values-array”)));
    AddXMLAttribute(varrayNode, _T(“type”), _T(“float”));

    CreateXMLNode(pXMLDoc, isourceNode, _T(“array”), &iarrayNode); // <array> for interps
    @@ -1692,7 +1691,7 @@
    end = animEnd * pIgame->GetSceneTicks();

    	numKeys = animEnd - animStart + 1;
    
  •   	buf.printf("%d", numKeys);
    
  •   	buf.printf("%d", keys.Count());
      	AddXMLAttribute(tarrayNode, _T("count"), buf);
      	AddXMLAttribute(varrayNode, _T("count"), buf);
      	AddXMLAttribute(iarrayNode, _T("count"), buf);
    

@@ -1809,7 +1808,7 @@
AddXMLAttribute(techNode, _T(“profile”), _T(“COMMON”));

CreateXMLNode(pXMLDoc, techNode, _T("accessor"), &accessNode);  // &lt;accessor&gt;
  • AddXMLAttribute(accessNode, _T(“source”), TSTR(_T(“#”)) + ap.animID + TSTR(_T(“-array”)));
  • AddXMLAttribute(accessNode, _T(“source”), TSTR(_T(“#”)) + ap.animID + TSTR(_T(“-values-array”)));
    buf.printf(“%d”, numKeys);
    AddXMLAttribute(accessNode, _T(“count”), buf);
    AddXMLAttribute(accessNode, _T(“stride”), _T(“1”));
    @@ -1930,162 +1929,162 @@
    return;
    }
  • if (ap.type == IGAME_TM)
  • {
  •   TSTR buf;
    
  •   CComPtr&lt;IXMLDOMNode&gt; tsourceNode, vsourceNode, isourceNode;
    
  •   CreateXMLNode(pXMLDoc, animNode, _T("source"), &tsourceNode);		// &lt;source&gt; for time
    
  •   CreateXMLNode(pXMLDoc, animNode, _T("source"), &vsourceNode);		// &lt;source&gt; for values
    
  •   AddXMLAttribute(vsourceNode, _T("id"), ap.getSubanimID(subanim) + TSTR(_T("-values")));
    
  •   AddXMLAttribute(tsourceNode, _T("id"), ap.getSubanimID(subanim) + TSTR(_T("-time")));
    
  •   CComPtr&lt;IXMLDOMNode&gt; tarrayNode, varrayNode;
    
  •   CreateXMLNode(pXMLDoc, tsourceNode, _T("array"), &tarrayNode);		// &lt;array&gt; for time
    
  •   CreateXMLNode(pXMLDoc, vsourceNode, _T("array"), &varrayNode);		// &lt;array&gt; for values
    
  •   AddXMLAttribute(tarrayNode, _T("id"), ap.getSubanimID(subanim) + TSTR(_T("-time-array")));
    
  •   AddXMLAttribute(tarrayNode, _T("type"), _T("float"));
    
  •   AddXMLAttribute(varrayNode, _T("id"), ap.getSubanimID(subanim) + TSTR(_T("-values-array")));
    
  •   AddXMLAttribute(varrayNode, _T("type"), _T("float"));
    
  •   int numKeys;
    
  •   numKeys = animEnd - animStart + 1;
    
  •   buf.printf("%d", numKeys);
    
  •   AddXMLAttribute(tarrayNode, _T("count"), buf);
    
  •   buf.printf("%d", numKeys*16);
    
  •   AddXMLAttribute(varrayNode, _T("count"), buf);
    
  •   // add &lt;technique&gt; nodes
    
  •   CComPtr&lt;IXMLDOMNode&gt; techNode, accessNode, paramNode;
    
  •   CreateXMLNode(pXMLDoc, tsourceNode, _T("technique"), &techNode);  // &lt;technique&gt; for time
    
  •   AddXMLAttribute(techNode, _T("profile"), _T("COMMON"));
    
  •   CreateXMLNode(pXMLDoc, techNode, _T("accessor"), &accessNode);  // &lt;accessor&gt;
    
  •   AddXMLAttribute(accessNode, _T("source"), TSTR(_T("#")) + ap.getSubanimID(subanim) + TSTR(_T("-time-array")));
    
  •   buf.printf("%d", numKeys);
    
  •   AddXMLAttribute(accessNode, _T("count"), buf);
    
  •   AddXMLAttribute(accessNode, _T("stride"), _T("1"));
    
  •   CreateXMLNode(pXMLDoc, accessNode, _T("param"), &paramNode);  // &lt;param&gt;
    
  •   AddXMLAttribute(paramNode, _T("name"), _T("time"));
    
  •   AddXMLAttribute(paramNode, _T("type"), _T("float"));
    
  •   AddXMLAttribute(paramNode, _T("flow"), _T("OUT"));
    
  •   techNode = NULL; accessNode = NULL; paramNode = NULL;
    
  •   CreateXMLNode(pXMLDoc, vsourceNode, _T("technique"), &techNode);  // &lt;technique&gt; for values
    
  •   AddXMLAttribute(techNode, _T("profile"), _T("COMMON"));
    
  •   CreateXMLNode(pXMLDoc, techNode, _T("accessor"), &accessNode);  // &lt;accessor&gt;
    
  •   AddXMLAttribute(accessNode, _T("source"), TSTR(_T("#")) + ap.getSubanimID(subanim) + TSTR(_T("-values-array")));
    
  •   buf.printf("%d", numKeys*16);
    
  •   AddXMLAttribute(accessNode, _T("count"), buf);
    
  •   CreateXMLNode(pXMLDoc, accessNode, _T("param"), &paramNode);  // &lt;param&gt;
    
  •   AddXMLAttribute(paramNode, _T("type"), _T("float"));
    
  •   AddXMLAttribute(paramNode, _T("flow"), _T("OUT"));
    
  •   techNode = NULL; accessNode = NULL; paramNode = NULL;
    
  •   TimeValue current = animStart * pIgame-&gt;GetSceneTicks();
    
  •   INode *node = ap.n-&gt;GetMaxNode();
    
  •   INode *parent = node-&gt;GetParentNode();
    
  •   TSTR timeBuf;
    
  •   TSTR valuesBuf;
    
  •   while (current&lt;=(animEnd*pIgame-&gt;GetSceneTicks()))
    
  •   {
    
  •   	buf.printf(" %g", current / (float)(pIgame-&gt;GetSceneTicks() * GetFrameRate()));  // time in secs
    
  •   	timeBuf += buf;
    
  •   	//			AddXMLText(pXMLDoc, tarrayNode, buf);
    
  •   	Matrix3 tm = node-&gt;GetNodeTM(current);
    
  •   	if (parent)
    
  •   	{
    
  •   		Matrix3 parentNodeTM = parent-&gt;GetNodeTM(current);
    
  •   		parentNodeTM.Invert();
    
  •   		tm = tm * parentNodeTM;
    
  •   	}
    
  •   	// this code converts from max matrix to collada matrix and outputs it in the collada form
    
  •   	float matrix[4][4];
    
  •   	Point3 row = tm.GetRow(0);
    
  •   	matrix[0][0] = row.x;
    
  •   	matrix[1][0] = row.y;
    
  •   	matrix[2][0] = row.z;
    
  •   	row = tm.GetRow(1);
    
  •   	matrix[0][1] = row.x;
    
  •   	matrix[1][1] = row.y;
    
  •   	matrix[2][1] = row.z;
    
  •   	row = tm.GetRow(2);
    
  •   	matrix[0][2] = row.x;
    
  •   	matrix[1][2] = row.y;
    
  •   	matrix[2][2] = row.z;
    
  •   	Point3 t = tm.GetRow(3);
    
  •   	matrix[0][3] = t.x;
    
  •   	matrix[1][3] = t.y;
    
  •   	matrix[2][3] = t.z;
    
  •   	matrix[3][3] = 1.0f;
    
  •   	// fill unused elements
    
  •   	matrix[3][0] = 0.0f;
    
  •   	matrix[3][1] = 0.0f;
    
  •   	matrix[3][2] = 0.0f;
    
  •   	buf.printf(" %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g", 
    
  •   		matrix[0][0],
    
  •   		matrix[0][1],
    
  •   		matrix[0][2],
    
  •   		matrix[0][3],
    
  •   		matrix[1][0],
    
  •   		matrix[1][1],
    
  •   		matrix[1][2],
    
  •   		matrix[1][3],
    
  •   		matrix[2][0],
    
  •   		matrix[2][1],
    
  •   		matrix[2][2],
    
  •   		matrix[2][3],
    
  •   		matrix[3][0],
    
  •   		matrix[3][1],
    
  •   		matrix[3][2],
    
  •   		matrix[3][3]);
    
  •   	valuesBuf+=buf;
    
  • // AddXMLText(pXMLDoc, varrayNode, buf);
  •   	current+=pIgame-&gt;GetSceneTicks();
    
  •   }
    
  •   AddXMLText(pXMLDoc, tarrayNode, timeBuf);
    
  •   AddXMLText(pXMLDoc, varrayNode, valuesBuf);
    
  •   return;
    
  • }
  • if (ap.type == IGAME_TM)
  • {
  •   TSTR buf;
    
  •   CComPtr&lt;IXMLDOMNode&gt; tsourceNode, vsourceNode, isourceNode;
    
  •   CreateXMLNode(pXMLDoc, animNode, _T("source"), &tsourceNode);		// &lt;source&gt; for time
    
  •   CreateXMLNode(pXMLDoc, animNode, _T("source"), &vsourceNode);		// &lt;source&gt; for values
    
  •   AddXMLAttribute(vsourceNode, _T("id"), ap.getSubanimID(subanim) + TSTR(_T("-values")));
    
  •   AddXMLAttribute(tsourceNode, _T("id"), ap.getSubanimID(subanim) + TSTR(_T("-time")));
    
  •   CComPtr&lt;IXMLDOMNode&gt; tarrayNode, varrayNode;
    
  •   CreateXMLNode(pXMLDoc, tsourceNode, _T("array"), &tarrayNode);		// &lt;array&gt; for time
    
  •   CreateXMLNode(pXMLDoc, vsourceNode, _T("array"), &varrayNode);		// &lt;array&gt; for values
    
  •   AddXMLAttribute(tarrayNode, _T("id"), ap.getSubanimID(subanim) + TSTR(_T("-time-array")));
    
  •   AddXMLAttribute(tarrayNode, _T("type"), _T("float"));
    
  •   AddXMLAttribute(varrayNode, _T("id"), ap.getSubanimID(subanim) + TSTR(_T("-values-array")));
    
  •   AddXMLAttribute(varrayNode, _T("type"), _T("float"));
    
  •   int numKeys;
    
  •   numKeys = animEnd - animStart + 1;
    
  •   buf.printf("%d", numKeys);
    
  •   AddXMLAttribute(tarrayNode, _T("count"), buf);
    
  •   buf.printf("%d", numKeys*16);
    
  •   AddXMLAttribute(varrayNode, _T("count"), buf);
    
  •   // add &lt;technique&gt; nodes
    
  •   CComPtr&lt;IXMLDOMNode&gt; techNode, accessNode, paramNode;
    
  •   CreateXMLNode(pXMLDoc, tsourceNode, _T("technique"), &techNode);  // &lt;technique&gt; for time
    
  •   AddXMLAttribute(techNode, _T("profile"), _T("COMMON"));
    
  •   CreateXMLNode(pXMLDoc, techNode, _T("accessor"), &accessNode);  // &lt;accessor&gt;
    
  •   AddXMLAttribute(accessNode, _T("source"), TSTR(_T("#")) + ap.getSubanimID(subanim) + TSTR(_T("-time-array")));
    
  •   buf.printf("%d", numKeys);
    
  •   AddXMLAttribute(accessNode, _T("count"), buf);
    
  •   AddXMLAttribute(accessNode, _T("stride"), _T("1"));
    
  •   CreateXMLNode(pXMLDoc, accessNode, _T("param"), &paramNode);  // &lt;param&gt;
    
  •   AddXMLAttribute(paramNode, _T("name"), _T("time"));
    
  •   AddXMLAttribute(paramNode, _T("type"), _T("float"));
    
  •   AddXMLAttribute(paramNode, _T("flow"), _T("OUT"));
    
  •   techNode = NULL; accessNode = NULL; paramNode = NULL;
    
  •   CreateXMLNode(pXMLDoc, vsourceNode, _T("technique"), &techNode);  // &lt;technique&gt; for values
    
  •   AddXMLAttribute(techNode, _T("profile"), _T("COMMON"));
    
  •   CreateXMLNode(pXMLDoc, techNode, _T("accessor"), &accessNode);  // &lt;accessor&gt;
    
  •   AddXMLAttribute(accessNode, _T("source"), TSTR(_T("#")) + ap.getSubanimID(subanim) + TSTR(_T("-values-array")));
    
  •   buf.printf("%d", numKeys*16);
    
  •   AddXMLAttribute(accessNode, _T("count"), buf);
    
  •   CreateXMLNode(pXMLDoc, accessNode, _T("param"), &paramNode);  // &lt;param&gt;
    
  •   AddXMLAttribute(paramNode, _T("type"), _T("float"));
    
  •   AddXMLAttribute(paramNode, _T("flow"), _T("OUT"));
    
  •   techNode = NULL; accessNode = NULL; paramNode = NULL;
    
  •   TimeValue current = animStart * pIgame-&gt;GetSceneTicks();
    
  •   INode *node = ap.n-&gt;GetMaxNode();
    
  •   INode *parent = node-&gt;GetParentNode();
    
  •   TSTR timeBuf;
    
  •   TSTR valuesBuf;
    
  •   while (current&lt;=(animEnd*pIgame-&gt;GetSceneTicks()))
    
  •   {
    
  •   	buf.printf(" %g", current / (float)(pIgame-&gt;GetSceneTicks() * GetFrameRate()));  // time in secs
    
  •   	timeBuf += buf;
    
  •   	//			AddXMLText(pXMLDoc, tarrayNode, buf);
    
  •   	Matrix3 tm = node-&gt;GetNodeTM(current);
    
  •   	if (parent)
    
  •   	{
    
  •   		Matrix3 parentNodeTM = parent-&gt;GetNodeTM(current);
    
  •   		parentNodeTM.Invert();
    
  •   		tm = tm * parentNodeTM;
    
  •   	}
    
  •   	// this code converts from max matrix to collada matrix and outputs it in the collada form
    
  •   	float matrix[4][4];
    
  •   	Point3 row = tm.GetRow(0);
    
  •   	matrix[0][0] = row.x;
    
  •   	matrix[1][0] = row.y;
    
  •   	matrix[2][0] = row.z;
    
  •   	row = tm.GetRow(1);
    
  •   	matrix[0][1] = row.x;
    
  •   	matrix[1][1] = row.y;
    
  •   	matrix[2][1] = row.z;
    
  •   	row = tm.GetRow(2);
    
  •   	matrix[0][2] = row.x;
    
  •   	matrix[1][2] = row.y;
    
  •   	matrix[2][2] = row.z;
    
  •   	Point3 t = tm.GetRow(3);
    
  •   	matrix[0][3] = t.x;
    
  •   	matrix[1][3] = t.y;
    
  •   	matrix[2][3] = t.z;
    
  •   	matrix[3][3] = 1.0f;
    
  •   	// fill unused elements
    
  •   	matrix[3][0] = 0.0f;
    
  •   	matrix[3][1] = 0.0f;
    
  •   	matrix[3][2] = 0.0f;
    
  •   	buf.printf(" %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g", 
    
  •   		matrix[0][0],
    
  •   		matrix[0][1],
    
  •   		matrix[0][2],
    
  •   		matrix[0][3],
    
  •   		matrix[1][0],
    
  •   		matrix[1][1],
    
  •   		matrix[1][2],
    
  •   		matrix[1][3],
    
  •   		matrix[2][0],
    
  •   		matrix[2][1],
    
  •   		matrix[2][2],
    
  •   		matrix[2][3],
    
  •   		matrix[3][0],
    
  •   		matrix[3][1],
    
  •   		matrix[3][2],
    
  •   		matrix[3][3]);
    
  •   	valuesBuf+=buf;
    
  • // AddXMLText(pXMLDoc, varrayNode, buf);
  •   	current+=pIgame-&gt;GetSceneTicks();
    
  •   }
    
  •   AddXMLText(pXMLDoc, tarrayNode, timeBuf);
    
  •   AddXMLText(pXMLDoc, varrayNode, valuesBuf);
    
  •   return;
    
  • }
  • // add time & value <source> elements for this controller
    Control* maxc = ap.c->GetMaxControl(ap.type);
  • if (maxc != NULL && maxc->IsAnimated())
  • if (maxc != NULL && (maxc->IsAnimated() || (ap.c->GetIGameKeyCount(ap.type)!=0)))
    {
    TSTR buf;
    bool hasTangents = false, sampleController = sampleAnim != 0;
    @@ -2094,7 +2093,7 @@
    CreateXMLNode(pXMLDoc, animNode, _T(“source”), &tsourceNode); // <source> for time
    CreateXMLNode(pXMLDoc, animNode, _T(“source”), &vsourceNode); // <source> for values
    CreateXMLNode(pXMLDoc, animNode, _T(“source”), &isourceNode); // <source> for interps
  •   AddXMLAttribute(vsourceNode, _T("id"), ap.getSubanimID(subanim));
    
  •   AddXMLAttribute(vsourceNode, _T("id"), ap.getSubanimID(subanim) + TSTR(_T("-values")));
      AddXMLAttribute(tsourceNode, _T("id"), ap.getSubanimID(subanim) + TSTR(_T("-time")));
      AddXMLAttribute(isourceNode, _T("id"), ap.getSubanimID(subanim) + TSTR(_T("-interp")));
      CComPtr&lt;IXMLDOMNode&gt; tarrayNode, varrayNode, iarrayNode, itarrayNode, otarrayNode;
    

@@ -2106,7 +2105,7 @@
AddXMLAttribute(tarrayNode, _T(“id”), ap.getSubanimID(subanim) + TSTR(_T(“-time-array”)));
AddXMLAttribute(tarrayNode, _T(“type”), _T(“float”));

  •   AddXMLAttribute(varrayNode, _T("id"), ap.getSubanimID(subanim) + TSTR(_T("-array")));
    
  •   AddXMLAttribute(varrayNode, _T("id"), ap.getSubanimID(subanim) + TSTR(_T("-values-array")));
      AddXMLAttribute(varrayNode, _T("type"), _T("float"));
    
      AddXMLAttribute(iarrayNode, _T("id"), ap.getSubanimID(subanim) + TSTR(_T("-interp-array")));
    

@@ -2117,31 +2116,37 @@
{
// sample controller value at each frame in the selected range
IGameKeyTab keys;

  •   	if (ap.c-&gt;GetFullSampledKeys(keys, 1, ap.type, false)) {
    
  •   	if (ap.c-&gt;GetFullSampledKeys(keys, 1, IGAME_TM, false)) {
      		TimeValue start = animStart * pIgame-&gt;GetSceneTicks(),
      					end = animEnd * pIgame-&gt;GetSceneTicks();
      		numKeys = animEnd - animStart + 1;
    
  •   		buf.printf("%d", numKeys);
    
  •   		buf.printf("%d", keys.Count());
      		AddXMLAttribute(tarrayNode, _T("count"), buf);
      		AddXMLAttribute(iarrayNode, _T("count"), buf);
    
  •   		if (subanim == SUBANIM_NONE) buf.printf("%d", numKeys*3);
    
  •   		if (subanim == SUBANIM_NONE) buf.printf("%d", keys.Count()*3);
      		AddXMLAttribute(varrayNode, _T("count"), buf);
      		
      		// loop over sampled keys
      		if (subanim == SUBANIM_NONE)
      		{
    
  •   			TSTR timeBuf;
    
  •   			TSTR valuesBuf;
    
  •   			TSTR interpBuf;
    
  •   			TSTR timeBuf;
    
  •   			TSTR valuesBuf;
    
  •   			TSTR interpBuf;
    
  •   			for (int i = 0; i &lt; keys.Count(); i++)
      			{
      				if (keys[i].t &gt;= start && keys[i].t &lt;= end)
      				{
      					buf.printf(" %g", double(keys[i].t) / (pIgame-&gt;GetSceneTicks() * GetFrameRate()));  // frame time in secs
    
  •   					AddXMLText(pXMLDoc, tarrayNode, buf);
    
  •   					AddXMLText(pXMLDoc, iarrayNode, _T(" LINEAR"));
    
  •   					timeBuf += buf;
    
  •   					interpBuf += _T(" LINEAR");
    

+// AddXMLText(pXMLDoc, tarrayNode, buf);
+// AddXMLText(pXMLDoc, iarrayNode, _T(" LINEAR"));
+
+
// export key value based on controller ap.type and value component specifier
if (ap.type==IGAME_POS || ap.type==IGAME_POINT3) {
Point3 k = keys[i].sampleKey.pval;
@@ -2156,28 +2161,34 @@
Point3 s = keys[i].sampleKey.sval.s;
buf.printf(" %g %g %g", ap.mapper(s.x), ap.mapper(s.y), ap.mapper(s.z));
}

  •   					AddXMLText(pXMLDoc, varrayNode, buf);
    
  •   					valuesBuf+=buf;
    
  •   				//	AddXMLText(pXMLDoc, varrayNode, buf);
      				}
    
  •   			}
    
  •   			AddXMLText(pXMLDoc, iarrayNode, interpBuf);
    
  •   			AddXMLText(pXMLDoc, tarrayNode, timeBuf);
    
  •   			AddXMLText(pXMLDoc, varrayNode, valuesBuf);
    
  •   			AddXMLText(pXMLDoc, iarrayNode, interpBuf);
    
  •   			AddXMLText(pXMLDoc, tarrayNode, timeBuf);
    
  •   			AddXMLText(pXMLDoc, varrayNode, valuesBuf);
      		}
      		else
      		{
    
  •   			TSTR timeBuf;
    
  •   			TSTR valuesBuf;
    
  •   			TSTR interpBuf;
    
  •   			TSTR timeBuf;
    
  •   			TSTR valuesBuf;
    
  •   			TSTR interpBuf;
    
  •   			for (int i = 0; i &lt; keys.Count(); i++)
      			{
      				if (keys[i].t &gt;= start && keys[i].t &lt;= end)
      				{
      					buf.printf(" %g", double(keys[i].t) / (pIgame-&gt;GetSceneTicks() * GetFrameRate()));  // frame time in secs
    
  •   					AddXMLText(pXMLDoc, tarrayNode, buf);
    
  •   					AddXMLText(pXMLDoc, iarrayNode, _T(" LINEAR"));
    
  •   					timeBuf += buf;
    
  •   					interpBuf += _T(" LINEAR");
    

+// AddXMLText(pXMLDoc, tarrayNode, buf);
+// AddXMLText(pXMLDoc, iarrayNode, _T(" LINEAR"));
+
+
// export key value based on controller ap.type and value component specifier
if (ap.type==IGAME_POS || ap.type==IGAME_POINT3) {
Point3 k = keys[i].sampleKey.pval;
@@ -2196,14 +2207,15 @@
Point3 s = keys[i].sampleKey.sval.s;
buf.printf(" %g", ap.mapper(getSubanimVal(subanim,s)));
}

  •   					AddXMLText(pXMLDoc, varrayNode, buf);
    
  •   					valuesBuf+=buf;
    
  •   				//	AddXMLText(pXMLDoc, varrayNode, buf);
      				}
      			}
    
  •   			AddXMLText(pXMLDoc, iarrayNode, interpBuf);
    
  •   			AddXMLText(pXMLDoc, tarrayNode, timeBuf);
    
  •   			AddXMLText(pXMLDoc, varrayNode, valuesBuf);
    
  •   			AddXMLText(pXMLDoc, iarrayNode, interpBuf);
    
  •   			AddXMLText(pXMLDoc, tarrayNode, timeBuf);
    
  •   			AddXMLText(pXMLDoc, varrayNode, valuesBuf);
    
  •   		}
      	}
      }
    

@@ -2340,7 +2352,7 @@
AddXMLAttribute(techNode, _T(“profile”), _T(“COMMON”));

	CreateXMLNode(pXMLDoc, techNode, _T("accessor"), &accessNode);  // &lt;accessor&gt;
  •   AddXMLAttribute(accessNode, _T("source"), TSTR(_T("#")) + ap.getSubanimID(subanim) + TSTR(_T("-array")));
    
  •   AddXMLAttribute(accessNode, _T("source"), TSTR(_T("#")) + ap.getSubanimID(subanim) + TSTR(_T("-values-array")));
      buf.printf("%d", numKeys);
      AddXMLAttribute(accessNode, _T("count"), buf);
    

@@ -2348,7 +2360,9 @@
{
AddXMLAttribute(accessNode, _T(“stride”), _T(“1”));
CreateXMLNode(pXMLDoc, accessNode, _T(“param”), &paramNode); // <param>

  •   	AddXMLAttribute(paramNode, _T("name"), ap.getTarget(subanim));
    
  •   	// kevt
    
  •   	AddXMLAttribute(paramNode, _T("name"), ap.getParam(subanim));
    
  •   	AddXMLAttribute(paramNode, _T("type"), _T("float"));
      	AddXMLAttribute(paramNode, _T("flow"), _T("OUT"));
      }
    

@@ -2453,7 +2467,8 @@
inputNode = NULL;
CreateXMLNode(pXMLDoc, samplerNode, _T(“input”), &inputNode); // <input> for OUTPUT
AddXMLAttribute(inputNode, _T(“semantic”), _T(“OUTPUT”));

  •   AddXMLAttribute(inputNode, _T("source"), TSTR(_T("#")) + ap.getSubanimID(subanim));
    
  •   // kevt
    
  •   AddXMLAttribute(inputNode, _T("source"), TSTR(_T("#")) + ap.getSubanimID(subanim) + TSTR(_T("-values")));
    

}

void
@@ -2475,45 +2490,48 @@
// add <light> library node for nodes that are lights
IGameObject* obj = node->GetIGameObject();

  • if (obj->GetIGameType() == IGameObject::IGAME_LIGHT) {
  •   TSTR objID; makeObjectID(obj, objID, node);
    
  •   IGameLight* light = (IGameLight*)obj;
    
  •   CComPtr&lt;IXMLDOMNode&gt; lightNode, paramNode;
    
  •   CreateXMLNode(pXMLDoc, libNode, _T("light"), &lightNode);		// &lt;camera&gt;
    
  •   AddXMLAttribute(lightNode, _T("id"), objID);
    
  •   AddXMLAttribute(lightNode, _T("name"), objID);
    
  •   int type = light-&gt;GetLightType();
    
  •   TCHAR* typeStr = type == IGameLight::IGAME_OMNI ? _T("POINT") :
    
  •   				 type == IGameLight::IGAME_TSPOT ? _T("SPOT") :
    
  •   				 type == IGameLight::IGAME_DIR ? _T("DIRECTIONAL") :
    
  •   				 type == IGameLight::IGAME_FSPOT ? _T("SPOT") :
    
  •   				 type == IGameLight::IGAME_TDIR ? _T("DIRECTIONAL") : _T("POINT");
    
  •   AddXMLAttribute(lightNode, _T("type"), typeStr);
    
  •   if (light-&gt;GetLightColor() != NULL)
    
  •   {
    
  •   	// common params
    
  •   	Point3 rgb; light-&gt;GetLightColor()-&gt;GetPropertyValue(rgb);
    
  •   	Point4 rgba (rgb, 1);
    
  •   	AddParamValNode(lightNode, _T("COLOR"), pt_float4, _T("IN"), rgba, (light-&gt;GetLightColor()-&gt;IsPropAnimated() ? _T("Color") : NULL));
    
  •   	float mult; light-&gt;GetLightMultiplier()-&gt;GetPropertyValue(mult);
    
  •   	AddParamValNode(lightNode, _T("INTENSITY"), pt_float, _T("IN"), mult, (light-&gt;GetLightMultiplier()-&gt;IsPropAnimated() ? _T("Multiplier") : NULL));
    
  •   	// non-point params
    
  •   	if (type != IGameLight::IGAME_OMNI) {
    
  •   		float aspect; light-&gt;GetLightAspectRatio()-&gt;GetPropertyValue(aspect);
    
  •   		AddParamValNode(lightNode, _T("ASPECTRATIO"), pt_float, _T("IN"), aspect, (light-&gt;GetLightAspectRatio()-&gt;IsPropAnimated() ? _T("AspectRatio") : NULL));
    
  •   		float falloff; light-&gt;GetLightFallOff()-&gt;GetPropertyValue(falloff);
    
  •   		AddParamValNode(lightNode, _T("OUTERCONE"), pt_float, _T("IN"), falloff, (light-&gt;GetLightFallOff()-&gt;IsPropAnimated() ? _T("Falloff") : NULL));
    
  •   		float hotspot; light-&gt;GetLightHotSpot()-&gt;GetPropertyValue(hotspot);
    
  •   		AddParamValNode(lightNode, _T("INNERCONE"), pt_float, _T("IN"), hotspot, (light-&gt;GetLightHotSpot()-&gt;IsPropAnimated() ? _T("Hotspot") : NULL));
    
  •   	}
    
  •   }
    
  •   // target param
    
  •   IGameNode* target = light-&gt;GetLightTarget();
    
  •   if (target != NULL) {
    
  •   	// add target ref
    
  •   	AddParamNode(lightNode, _T("TARGET"), pt_name, _T("IN"), paramNode);
    
  •   	TSTR targID; makeNodeID(target, targID);
    
  •   	AddXMLText(pXMLDoc, paramNode, targID);
    
  • if (!node->IsNodeHidden())
  • {
  •   if (obj-&gt;GetIGameType() == IGameObject::IGAME_LIGHT) {
    
  •   	TSTR objID; makeObjectID(obj, objID, node);
    
  •   	IGameLight* light = (IGameLight*)obj;
    
  •   	CComPtr&lt;IXMLDOMNode&gt; lightNode, paramNode;
    
  •   	CreateXMLNode(pXMLDoc, libNode, _T("light"), &lightNode);		// &lt;camera&gt;
    
  •   	AddXMLAttribute(lightNode, _T("id"), objID);
    
  •   	AddXMLAttribute(lightNode, _T("name"), objID);
    
  •   	int type = light-&gt;GetLightType();
    
  •   	TCHAR* typeStr = type == IGameLight::IGAME_OMNI ? _T("POINT") :
    
  •   					type == IGameLight::IGAME_TSPOT ? _T("SPOT") :
    
  •   					type == IGameLight::IGAME_DIR ? _T("DIRECTIONAL") :
    
  •   					type == IGameLight::IGAME_FSPOT ? _T("SPOT") :
    
  •   					type == IGameLight::IGAME_TDIR ? _T("DIRECTIONAL") : _T("POINT");
    
  •   	AddXMLAttribute(lightNode, _T("type"), typeStr);
    
  •   	if (light-&gt;GetLightColor() != NULL)
    
  •   	{
    
  •   		// common params
    
  •   		Point3 rgb; light-&gt;GetLightColor()-&gt;GetPropertyValue(rgb);
    
  •   		Point4 rgba (rgb, 1);
    
  •   		AddParamValNode(lightNode, _T("COLOR"), pt_float4, _T("IN"), rgba, (light-&gt;GetLightColor()-&gt;IsPropAnimated() ? _T("Color") : NULL));
    
  •   		float mult; light-&gt;GetLightMultiplier()-&gt;GetPropertyValue(mult);
    
  •   		AddParamValNode(lightNode, _T("INTENSITY"), pt_float, _T("IN"), mult, (light-&gt;GetLightMultiplier()-&gt;IsPropAnimated() ? _T("Multiplier") : NULL));
    
  •   		// non-point params
    
  •   		if (type != IGameLight::IGAME_OMNI) {
    
  •   			float aspect; light-&gt;GetLightAspectRatio()-&gt;GetPropertyValue(aspect);
    
  •   			AddParamValNode(lightNode, _T("ASPECTRATIO"), pt_float, _T("IN"), aspect, (light-&gt;GetLightAspectRatio()-&gt;IsPropAnimated() ? _T("AspectRatio") : NULL));
    
  •   			float falloff; light-&gt;GetLightFallOff()-&gt;GetPropertyValue(falloff);
    
  •   			AddParamValNode(lightNode, _T("OUTERCONE"), pt_float, _T("IN"), falloff, (light-&gt;GetLightFallOff()-&gt;IsPropAnimated() ? _T("Falloff") : NULL));
    
  •   			float hotspot; light-&gt;GetLightHotSpot()-&gt;GetPropertyValue(hotspot);
    
  •   			AddParamValNode(lightNode, _T("INNERCONE"), pt_float, _T("IN"), hotspot, (light-&gt;GetLightHotSpot()-&gt;IsPropAnimated() ? _T("Hotspot") : NULL));
    
  •   		}
    
  •   	}
    
  •   	// target param
    
  •   	IGameNode* target = light-&gt;GetLightTarget();
    
  •   	if (target != NULL) {
    
  •   		// add target ref
    
  •   		AddParamNode(lightNode, _T("TARGET"), pt_name, _T("IN"), paramNode);
    
  •   		TSTR targID; makeNodeID(target, targID);
    
  •   		AddXMLText(pXMLDoc, paramNode, targID);
    
  •   	}
      }
    
    }
    node->ReleaseIGameObject();
    @@ -2691,7 +2709,11 @@
    AddXMLAttribute(imgNode, _T(“id”), id);
    AddXMLAttribute(imgNode, _T(“name”), id);
    // make valid sourcefile URI
  •   			TSTR src = c; makeValidURIFilename(src, false);
    
  •   			TSTR src = c;
    
  •   			// kevt
    
  •   			makeValidURIFilename(src, false);
    
  •   			src = TSTR(_T("file://")) + src; 
      			AddXMLAttribute(imgNode, _T("source"), src);
      		}
      	}
    

@@ -2750,23 +2772,25 @@
void
ColladaExporter::AddGeometryNodes(CComPtr<IXMLDOMNode>& libNode, IGameNode* node, Tab<Object*>& objects)
{

  • // add <geometry> nodes for this node and its children
  • IGameObject* obj = node->GetIGameObject();
  • if (obj->GetIGameType() == IGameObject::IGAME_MESH)
  • if (!node->IsNodeHidden())
    {
  •   if (!obj-&gt;IsObjectXRef()) { // but not xrefs, they just have scene nodes, no geom
    
  •   	// only first instance of object, so search in accumulating Object* table
    
  •   	Object* maxobj = obj-&gt;GetMaxObject();
    
  •   	for (int i = 0; i &lt; objects.Count(); i++)
    
  •   		if (objects[i] == maxobj) break;
    
  •   	if (i == objects.Count()) {		// not found, so 1st inst, add &lt;geometry&gt; node for it
    
  •   		objects.Append(1, &maxobj);
    
  •   		AddGeometryNode(libNode, (IGameMesh*)obj, node);
    
  •   // add &lt;geometry&gt; nodes for this node and its children
    
  •   IGameObject* obj = node-&gt;GetIGameObject();
    
  •   if (obj-&gt;GetIGameType() == IGameObject::IGAME_MESH)
    
  •   {
    
  •   	if (!obj-&gt;IsObjectXRef()) { // but not xrefs, they just have scene nodes, no geom
    
  •   		// only first instance of object, so search in accumulating Object* table
    
  •   		Object* maxobj = obj-&gt;GetMaxObject();
    
  •   		for (int i = 0; i &lt; objects.Count(); i++)
    
  •   			if (objects[i] == maxobj) break;
    
  •   		if (i == objects.Count()) {		// not found, so 1st inst, add &lt;geometry&gt; node for it
    
  •   			objects.Append(1, &maxobj);
    
  •   			AddGeometryNode(libNode, (IGameMesh*)obj, node);
    
  •   		}
      	}
      }
    
  •   node-&gt;ReleaseIGameObject();
    
  •   node-&gt;ReleaseIGameObject();
    
    }
  • node->ReleaseIGameObject();

    // recurse through any children
    for (int j = 0; j < node->GetChildCount(); j++) {
    @@ -3067,16 +3091,16 @@
    AddXMLAttribute(arrayNode, _T(“type”), _T(“float”));
    TSTR buf; buf.printf(“%d”, numVerts * 3);
    AddXMLAttribute(arrayNode, _T(“count”), buf);

  •   TSTR vertsBuf;
    
  •   TSTR vertsBuf;
      // mesh vertex positions
      for (int i = 0; i &lt; numVerts; i++) {
      		Point3 vert;
      		mesh-&gt;GetVertex(i, vert, true);
      		buf.printf("%g %g %g ", vert.x, vert.y, vert.z);
    
  •   		AddXMLText(pXMLDoc, arrayNode, buf);
    
  •   		vertsBuf+=buf;
      }
    
  •   AddXMLText(pXMLDoc, arrayNode, vertsBuf);
    
  •   AddXMLText(pXMLDoc, arrayNode, vertsBuf);
      // accessor technique node
      TCHAR* pnames[3] = { "X", "Y", "Z" };
      AddNTupleTechniqueNode(sourceNode, arrayID, numVerts, 3, pnames);
    

@@ -3103,20 +3127,24 @@
AddXMLAttribute(arrayNode, _T(“count”), buf);
// mesh normals
Point3 n(0,0,0);

  • TSTR normalsBuf;
  • TSTR normalsBuf;
  • for (int i = 0; i < numNormals; i++) {
    if(mesh->GetNormal(i,n))
    {
    buf.printf("%g %g %g ",n.x,n.y,n.z);
  •   	AddXMLText(pXMLDoc,arrayNode,buf.data());
    
  •   	normalsBuf+=buf;
    
  • // AddXMLText(pXMLDoc,arrayNode,buf.data());
    }
    else
  •   	AddXMLText(pXMLDoc,arrayNode,_T("0 0 1"));
    
  •   {
    
  •   	normalsBuf+=_T("0 0 1");
    
  • // AddXMLText(pXMLDoc,arrayNode,_T(“0 0 1”));
  •   }
    
    }
  • AddXMLText(pXMLDoc,arrayNode,normalsBuf);
  • AddXMLText(pXMLDoc,arrayNode,normalsBuf);

  • // accessor technique node
    TCHAR* pnames[3] = { “X”, “Y”, “Z” };
    AddNTupleTechniqueNode(sourceNode, arrayID, numNormals, 3, pnames);
    @@ -3437,7 +3465,7 @@

    // map funny chars
    for (int i = 0; i < fn.length(); i++) {

  •   if (fn[i] == _T(':')) fn[i] = _T('$');
    
  •   if (fn[i] == _T(':')) fn[i] = _T('|');
      else if (fn[i] == _T(' ')) fn[i] = _T('_');
      else if (fn[i] == _T('\\')) fn[i] = _T('/');
    
    }

end

Hi Kevt,

Thanks for that. I’m not following the code as I’m evaluating Collada from the art side but I’m going to pass this on to our tools pragrammers who are getting to grips with Collada at the moment.

I think they will find it very interesting. Thanks for posting this up and sharing! If I get any comments or furhter questions I’ll post those up too.

Cheers

Jolyon