Results 1 to 9 of 9

Thread: 3ds max importer - problems importing skeletal data

  1. #1
    bentllama
    Guest

    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

  2. #2
    Junior Member
    Join Date
    Aug 2005
    Posts
    2

    Same errors with sample data

    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.
    Greg Snook
    Bungie Studios

  3. #3
    Junior Member
    Join Date
    Aug 2004
    Location
    Autodesk, San Francisco
    Posts
    19
    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:

  4. #4
    Junior Member
    Join Date
    Aug 2005
    Posts
    4
    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

  5. #5
    Quote Originally Posted by Jol
    Hi,

    We are having some issues with Collada and max too.
    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?

  6. #6
    Junior Member
    Join Date
    Aug 2005
    Posts
    2
    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!
    Greg Snook
    Bungie Studios

  7. #7
    Junior Member
    Join Date
    Aug 2005
    Posts
    4
    Hi Kevt,

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

    Cheers

    Jolyon

  8. #8

    my updates to collada C++ export from Max.

    Quote Originally Posted by Jol
    Hi Kevt,

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

    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<TSTR*> params;
    - IGameNode *n;
    + Tab<TSTR*> params;
    + IGameNode *n;

    AnimParam(IGameNode* node) {
    - n = node;
    + n = node;
    nodeName = node->GetName(); cleanID(nodeName);
    makeNodeID(node, objectID);
    mapper = identity;
    @@ -103,7 +103,7 @@

    TSTR& getTarget(int i) { return i < 0 ? paramID : *targets[i]; }
    TSTR& getSubanimID(int i) { return i < 0 ? animID : *subanims[i]; }
    - TSTR& getParam(int i) { return i<0 ? paramID : *params[i]; }
    + TSTR& getParam(int i) { return i<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 ColladaExporterClassDescublic ClassDesc2
    @@ -669,7 +670,9 @@
    // create COLLADA node and its attribs
    CreateXMLNode(pXMLDoc, pRoot, _T("COLLADA"), &colladaNode);
    AddXMLAttribute(colladaNode, _T("xmlns"), _T("http://www.collada.org/2005/COLLADASchema"));
    - 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); // <instance>
    + {
    + // kevt:
    + // put mesh under pivot node, or parent node if pivot is ident
    + CreateXMLNode(pXMLDoc, pivotNode, _T("instance"), &instNode); // <instance>
    if (obj->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); // <instance>
    + CreateXMLNode(pXMLDoc, pivotNode, _T("instance"), &instNode); // <instance>
    AddXMLAttribute(instNode, _T("url"), TSTR(_T("#")) + objID);
    break;

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

    case IGameObject::IGAME_CAMERA:
    - CreateXMLNode(pXMLDoc, nodeNode, _T("instance"), &instNode); // <instance>
    + CreateXMLNode(pXMLDoc, pivotNode, _T("instance"), &instNode); // <instance>
    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->GetMaxNode()->GetNodeTM(0);
    - Matrix3 iParentTM(1);
    -
    - // world space transformation of the node's parent at the current time
    - IGameNode *parent = node->GetNodeParent();
    - if (parent != NULL) iParentTM = parent->GetMaxNode()->GetNodeTM(0);
    - iParentTM.Invert();
    -
    - // local matrix relative to parent
    - tm = tm * iParentTM;
    -
    - CComPtr<IXMLDOMNode> matrixNode;
    - CreateXMLNode(pXMLDoc, nodeNode, _T("matrix"), &matrixNode); // <scale>
    -
    - // if any channel is animated then matrix is animated
    - IGameControl* c = node->GetIGameControl();
    -
    - if (
    - // biped controlls can say they are not animated yet they have keys
    - (c->GetIGameKeyCount(IGAME_POS)!=0) ||
    - (c->GetIGameKeyCount(IGAME_ROT)!=0) ||
    - (c->GetIGameKeyCount(IGAME_SCALE)!=0) ||
    - c->IsAnimated(IGAME_POS) ||
    - c->IsAnimated(IGAME_ROT) ||
    - c->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->GetMaxNode()->GetNodeTM(0);
    + Matrix3 iParentTM(1);
    +
    + // world space transformation of the node's parent at the current time
    + IGameNode *parent = node->GetNodeParent();
    + if (parent != NULL) iParentTM = parent->GetMaxNode()->GetNodeTM(0);
    + iParentTM.Invert();
    +
    + // local matrix relative to parent
    + tm = tm * iParentTM;
    +
    + CComPtr<IXMLDOMNode> matrixNode;
    + CreateXMLNode(pXMLDoc, nodeNode, _T("matrix"), &matrixNode); // <scale>
    +
    + // if any channel is animated then matrix is animated
    + IGameControl* c = node->GetIGameControl();
    +
    + if (
    + // biped controlls can say they are not animated yet they have keys
    + (c->GetIGameKeyCount(IGAME_POS)!=0) ||
    + (c->GetIGameKeyCount(IGAME_ROT)!=0) ||
    + (c->GetIGameKeyCount(IGAME_SCALE)!=0) ||
    + c->IsAnimated(IGAME_POS) ||
    + c->IsAnimated(IGAME_ROT) ||
    + c->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<IXMLDOMNode> transNode;
    CreateXMLNode(pXMLDoc, nodeNode, _T("translate"), &transNode); // <translate>
    // check for animation, add sid attrib if so
    IGameControl* c = node->GetIGameControl();
    - if (c->IsAnimated(IGAME_POS))
    + if (c->IsAnimated(IGAME_POS) || (c->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<IXMLDOMNode> rotNode;
    // check for animation, add sid attrib if so
    - bool hasAnim = c->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->IsAnimated(IGAME_ROT) || (c->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); // <rotate> 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<IXMLDOMNode> scaleNode;
    CreateXMLNode(pXMLDoc, nodeNode, _T("scale"), &scaleNode); // <scale>
    buf.printf("%g %g %g ", scale.x, scale.y, scale.z);
    AddXMLText(pXMLDoc, scaleNode, buf);
    - if (c->IsAnimated(IGAME_SCALE))
    + if (c->IsAnimated(IGAME_SCALE) || (c->GetIGameKeyCount(IGAME_SCALE)!=0))
    AddXMLAttribute(scaleNode, _T("sid"), _T("Scale"));
    -
    -#endif
    +
    +#endif
    }

    node->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<IXMLDOMNode> 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->GetObjOffsetScale();
    - ApplyScaling(tm, scaleValue);
    -
    - CComPtr<IXMLDOMNode> matrixNode;
    - CreateXMLNode(pXMLDoc, nodeNode, _T("matrix"), &matrixNode); // <matrix>
    -
    - // 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->GetObjOffsetScale();
    + ApplyScaling(tm, scaleValue);
    +
    + CComPtr<IXMLDOMNode> matrixNode;
    + CreateXMLNode(pXMLDoc, nodeNode, _T("matrix"), &matrixNode); // <matrix>
    +
    + // 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<IXMLDOMNod e>& libNode, IGameNode* node)
    {
    - // add <camera> library node for nodes that are cameras
    - IGameObject* obj = node->GetIGameObject();
    + if (!node->IsNodeHidden())
    + {
    + // add <camera> library node for nodes that are cameras
    + IGameObject* obj = node->GetIGameObject();

    - if (obj->GetIGameType() == IGameObject::IGAME_CAMERA) {
    - TSTR objID; makeObjectID(obj, objID, node);
    - IGameCamera* cam = (IGameCamera*)obj;
    - CameraObject* camObj = (CameraObject*)cam->GetMaxObject();
    + if (obj->GetIGameType() == IGameObject::IGAME_CAMERA) {
    + TSTR objID; makeObjectID(obj, objID, node);
    + IGameCamera* cam = (IGameCamera*)obj;
    + CameraObject* camObj = (CameraObject*)cam->GetMaxObject();

    - CComPtr<IXMLDOMNode> camNode, techNode, optNode, progNode, paramNode;
    - CreateXMLNode(pXMLDoc, libNode, _T("camera"), &camNode); // <camera>
    - AddXMLAttribute(camNode, _T("id"), objID);
    - AddXMLAttribute(camNode, _T("name"), objID);
    - CreateXMLNode(pXMLDoc, camNode, _T("technique"), &techNode); // <technique>
    - AddXMLAttribute(techNode, _T("profile"), _T("COMMON"));
    - CreateXMLNode(pXMLDoc, techNode, _T("optics"), &optNode); // <optics>
    - CreateXMLNode(pXMLDoc, optNode, _T("program"), &progNode); // <program>
    - // add perspective or ortho attribs & props
    - if (camObj->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->GetCameraFOV()->GetPropertyValue(fov);
    - AddParamValNode(progNode, _T("YFOV"), pt_float, _T("IN"), RadToDeg(fov), (cam->GetCameraFOV()->IsPropAnimated() ? _T("FOV") : NULL));
    - }
    - // add common props
    - float n; cam->GetCameraNearClip()->GetPropertyValue(n);
    - 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));
    - // if target, add 3DSMAX technique
    - INode* target = node->GetMaxNode()->GetTarget();
    - if (target != NULL) {
    - techNode = NULL; optNode = NULL; progNode = NULL;
    + CComPtr<IXMLDOMNode> camNode, techNode, optNode, progNode, paramNode;
    + CreateXMLNode(pXMLDoc, libNode, _T("camera"), &camNode); // <camera>
    + AddXMLAttribute(camNode, _T("id"), objID);
    + AddXMLAttribute(camNode, _T("name"), objID);
    CreateXMLNode(pXMLDoc, camNode, _T("technique"), &techNode); // <technique>
    - AddXMLAttribute(techNode, _T("profile"), _T("MAX3D"));
    + AddXMLAttribute(techNode, _T("profile"), _T("COMMON"));
    CreateXMLNode(pXMLDoc, techNode, _T("optics"), &optNode); // <optics>
    CreateXMLNode(pXMLDoc, optNode, _T("program"), &progNode); // <program>
    // 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->GetIGameNode(target);
    - TSTR targID; makeNodeID(targNode, targID);
    - AddXMLText(pXMLDoc, paramNode, targID);
    - }
    + // if target, add 3DSMAX technique
    + INode* target = node->GetMaxNode()->GetTarget();
    + if (target != NULL) {
    + techNode = NULL; optNode = NULL; progNode = NULL;
    + CreateXMLNode(pXMLDoc, camNode, _T("technique"), &techNode); // <technique>
    + AddXMLAttribute(techNode, _T("profile"), _T("MAX3D"));
    + CreateXMLNode(pXMLDoc, techNode, _T("optics"), &optNode); // <optics>
    + CreateXMLNode(pXMLDoc, optNode, _T("program"), &progNode); // <program>
    + // add perspective or ortho attribs & props
    + if (camObj->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->GetCameraFOV()->GetPropertyValue(fov);
    + AddParamValNode(progNode, _T("YFOV"), pt_float, _T("IN"), RadToDeg(fov), (cam->GetCameraFOV()->IsPropAnimated() ? _T("FOV") : NULL));
    + }
    + // add common props
    + float n; cam->GetCameraNearClip()->GetPropertyValue(n);
    + 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->GetIGameNode(target);
    + TSTR targID; makeNodeID(targNode, targID);
    + AddXMLText(pXMLDoc, paramNode, targID);
    + }

    - }
    - node->ReleaseIGameObject();
    + }
    + node->ReleaseIGameObject();
    }
    - node->ReleaseIGameObject();

    // recurse through children nodes
    for (int i = 0; i < node->GetChildCount(); i++)
    @@ -1361,64 +1356,68 @@
    void
    ColladaExporter::AddAnimationNodes(CComPtr<IXMLDOM Node>& libNode, IGameNode* node)
    {
    - // add <animation> library elements for scene nodes
    - AnimParam ap(node);
    - IGameObject* obj = node->GetIGameObject();
    + if (!node->IsNodeHidden())
    + {
    + // add <animation> library elements for scene nodes
    + IGameObject* obj = node->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->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->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->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->GetMaxObject();
    - TSTR camID; makeObjectID(obj, camID, node); ap.setObjectID(camID);
    - if (!camObj->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->GetMaxObject();
    + TSTR camID; makeObjectID(obj, camID, node); ap.setObjectID(camID);
    + if (!camObj->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->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->GetIGameKeyCount(IGAME_POS)!=0) ||
    - (c->GetIGameKeyCount(IGAME_ROT)!=0) ||
    - (c->GetIGameKeyCount(IGAME_SCALE)!=0) ||
    - c->IsAnimated(IGAME_POS) ||
    - c->IsAnimated(IGAME_ROT) ||
    - c->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->GetIGameKeyCount(IGAME_POS)!=0) ||
    + (c->GetIGameKeyCount(IGAME_ROT)!=0) ||
    + (c->GetIGameKeyCount(IGAME_SCALE)!=0) ||
    + c->IsAnimated(IGAME_POS) ||
    + c->IsAnimated(IGAME_ROT) ||
    + c->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->IsAnimated()) {
    + if ((pc != NULL && pc->IsAnimated()) || (c->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->GetMaxControl(IGAME_ROT);
    - if (pc != NULL && pc->IsAnimated()) {
    + if ((pc != NULL && pc->IsAnimated()) || (c->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->IsAnimated()) {
    + if ((pc != NULL && pc->IsAnimated()) || (c->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); // <accessor>
    - 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<IXMLDOMNode> tsourceNode, vsourceNode, isourceNode;
    - CreateXMLNode(pXMLDoc, animNode, _T("source"), &tsourceNode); // <source> for time
    - CreateXMLNode(pXMLDoc, animNode, _T("source"), &vsourceNode); // <source> for values
    - AddXMLAttribute(vsourceNode, _T("id"), ap.getSubanimID(subanim) + TSTR(_T("-values")));
    - AddXMLAttribute(tsourceNode, _T("id"), ap.getSubanimID(subanim) + TSTR(_T("-time")));
    - CComPtr<IXMLDOMNode> tarrayNode, varrayNode;
    - CreateXMLNode(pXMLDoc, tsourceNode, _T("array"), &tarrayNode); // <array> for time
    - CreateXMLNode(pXMLDoc, vsourceNode, _T("array"), &varrayNode); // <array> 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 <technique> nodes
    - CComPtr<IXMLDOMNode> techNode, accessNode, paramNode;
    - CreateXMLNode(pXMLDoc, tsourceNode, _T("technique"), &techNode); // <technique> for time
    - AddXMLAttribute(techNode, _T("profile"), _T("COMMON"));
    -
    - CreateXMLNode(pXMLDoc, techNode, _T("accessor"), &accessNode); // <accessor>
    - 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); // <param>
    - 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); // <technique> for values
    - AddXMLAttribute(techNode, _T("profile"), _T("COMMON"));
    -
    - CreateXMLNode(pXMLDoc, techNode, _T("accessor"), &accessNode); // <accessor>
    - 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); // <param>
    - AddXMLAttribute(paramNode, _T("type"), _T("float"));
    - AddXMLAttribute(paramNode, _T("flow"), _T("OUT"));
    - techNode = NULL; accessNode = NULL; paramNode = NULL;
    -
    -
    - TimeValue current = animStart * pIgame->GetSceneTicks();
    -
    - INode *node = ap.n->GetMaxNode();
    - INode *parent = node->GetParentNode();
    -
    - TSTR timeBuf;
    - TSTR valuesBuf;
    -
    - while (current<=(animEnd*pIgame->GetSceneTicks()))
    - {
    - buf.printf(" %g", current / (float)(pIgame->GetSceneTicks() * GetFrameRate())); // time in secs
    -
    - timeBuf += buf;
    -
    - // AddXMLText(pXMLDoc, tarrayNode, buf);
    -
    - Matrix3 tm = node->GetNodeTM(current);
    - if (parent)
    - {
    - Matrix3 parentNodeTM = parent->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->GetSceneTicks();
    - }
    -
    - AddXMLText(pXMLDoc, tarrayNode, timeBuf);
    - AddXMLText(pXMLDoc, varrayNode, valuesBuf);
    -
    -
    - return;
    - }
    -
    + if (ap.type == IGAME_TM)
    + {
    + TSTR buf;
    +
    + CComPtr<IXMLDOMNode> tsourceNode, vsourceNode, isourceNode;
    + CreateXMLNode(pXMLDoc, animNode, _T("source"), &tsourceNode); // <source> for time
    + CreateXMLNode(pXMLDoc, animNode, _T("source"), &vsourceNode); // <source> for values
    + AddXMLAttribute(vsourceNode, _T("id"), ap.getSubanimID(subanim) + TSTR(_T("-values")));
    + AddXMLAttribute(tsourceNode, _T("id"), ap.getSubanimID(subanim) + TSTR(_T("-time")));
    + CComPtr<IXMLDOMNode> tarrayNode, varrayNode;
    + CreateXMLNode(pXMLDoc, tsourceNode, _T("array"), &tarrayNode); // <array> for time
    + CreateXMLNode(pXMLDoc, vsourceNode, _T("array"), &varrayNode); // <array> 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 <technique> nodes
    + CComPtr<IXMLDOMNode> techNode, accessNode, paramNode;
    + CreateXMLNode(pXMLDoc, tsourceNode, _T("technique"), &techNode); // <technique> for time
    + AddXMLAttribute(techNode, _T("profile"), _T("COMMON"));
    +
    + CreateXMLNode(pXMLDoc, techNode, _T("accessor"), &accessNode); // <accessor>
    + 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); // <param>
    + 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); // <technique> for values
    + AddXMLAttribute(techNode, _T("profile"), _T("COMMON"));
    +
    + CreateXMLNode(pXMLDoc, techNode, _T("accessor"), &accessNode); // <accessor>
    + 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); // <param>
    + AddXMLAttribute(paramNode, _T("type"), _T("float"));
    + AddXMLAttribute(paramNode, _T("flow"), _T("OUT"));
    + techNode = NULL; accessNode = NULL; paramNode = NULL;
    +
    +
    + TimeValue current = animStart * pIgame->GetSceneTicks();
    +
    + INode *node = ap.n->GetMaxNode();
    + INode *parent = node->GetParentNode();
    +
    + TSTR timeBuf;
    + TSTR valuesBuf;
    +
    + while (current<=(animEnd*pIgame->GetSceneTicks()))
    + {
    + buf.printf(" %g", current / (float)(pIgame->GetSceneTicks() * GetFrameRate())); // time in secs
    +
    + timeBuf += buf;
    +
    + // AddXMLText(pXMLDoc, tarrayNode, buf);
    +
    + Matrix3 tm = node->GetNodeTM(current);
    + if (parent)
    + {
    + Matrix3 parentNodeTM = parent->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->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<IXMLDOMNode> 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->GetFullSampledKeys(keys, 1, ap.type, false)) {
    +
    + if (ap.c->GetFullSampledKeys(keys, 1, IGAME_TM, false)) {
    TimeValue start = animStart * pIgame->GetSceneTicks(),
    end = animEnd * pIgame->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 < keys.Count(); i++)
    {
    if (keys[i].t >= start && keys[i].t <= end)
    {
    buf.printf(" %g", double(keys[i].t) / (pIgame->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 < keys.Count(); i++)
    {
    if (keys[i].t >= start && keys[i].t <= end)
    {
    buf.printf(" %g", double(keys[i].t) / (pIgame->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); // <accessor>
    - 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<IXMLDOMNode> lightNode, paramNode;
    - CreateXMLNode(pXMLDoc, libNode, _T("light"), &lightNode); // <camera>
    - AddXMLAttribute(lightNode, _T("id"), objID);
    - AddXMLAttribute(lightNode, _T("name"), objID);
    - int type = light->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->GetLightColor() != NULL)
    - {
    - // common params
    - Point3 rgb; light->GetLightColor()->GetPropertyValue(rgb);
    - Point4 rgba (rgb, 1);
    - AddParamValNode(lightNode, _T("COLOR"), pt_float4, _T("IN"), rgba, (light->GetLightColor()->IsPropAnimated() ? _T("Color") : NULL));
    - float mult; light->GetLightMultiplier()->GetPropertyValue(mult);
    - AddParamValNode(lightNode, _T("INTENSITY"), pt_float, _T("IN"), mult, (light->GetLightMultiplier()->IsPropAnimated() ? _T("Multiplier") : NULL));
    - // non-point params
    - if (type != IGameLight::IGAME_OMNI) {
    - float aspect; light->GetLightAspectRatio()->GetPropertyValue(aspect);
    - AddParamValNode(lightNode, _T("ASPECTRATIO"), pt_float, _T("IN"), aspect, (light->GetLightAspectRatio()->IsPropAnimated() ? _T("AspectRatio") : NULL));
    - float falloff; light->GetLightFallOff()->GetPropertyValue(falloff);
    - AddParamValNode(lightNode, _T("OUTERCONE"), pt_float, _T("IN"), falloff, (light->GetLightFallOff()->IsPropAnimated() ? _T("Falloff") : NULL));
    - float hotspot; light->GetLightHotSpot()->GetPropertyValue(hotspot);
    - AddParamValNode(lightNode, _T("INNERCONE"), pt_float, _T("IN"), hotspot, (light->GetLightHotSpot()->IsPropAnimated() ? _T("Hotspot") : NULL));
    - }
    - }
    - // target param
    - IGameNode* target = light->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->GetIGameType() == IGameObject::IGAME_LIGHT) {
    + TSTR objID; makeObjectID(obj, objID, node);
    + IGameLight* light = (IGameLight*)obj;
    + CComPtr<IXMLDOMNode> lightNode, paramNode;
    + CreateXMLNode(pXMLDoc, libNode, _T("light"), &lightNode); // <camera>
    + AddXMLAttribute(lightNode, _T("id"), objID);
    + AddXMLAttribute(lightNode, _T("name"), objID);
    + int type = light->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->GetLightColor() != NULL)
    + {
    + // common params
    + Point3 rgb; light->GetLightColor()->GetPropertyValue(rgb);
    + Point4 rgba (rgb, 1);
    + AddParamValNode(lightNode, _T("COLOR"), pt_float4, _T("IN"), rgba, (light->GetLightColor()->IsPropAnimated() ? _T("Color") : NULL));
    + float mult; light->GetLightMultiplier()->GetPropertyValue(mult);
    + AddParamValNode(lightNode, _T("INTENSITY"), pt_float, _T("IN"), mult, (light->GetLightMultiplier()->IsPropAnimated() ? _T("Multiplier") : NULL));
    + // non-point params
    + if (type != IGameLight::IGAME_OMNI) {
    + float aspect; light->GetLightAspectRatio()->GetPropertyValue(aspect);
    + AddParamValNode(lightNode, _T("ASPECTRATIO"), pt_float, _T("IN"), aspect, (light->GetLightAspectRatio()->IsPropAnimated() ? _T("AspectRatio") : NULL));
    + float falloff; light->GetLightFallOff()->GetPropertyValue(falloff);
    + AddParamValNode(lightNode, _T("OUTERCONE"), pt_float, _T("IN"), falloff, (light->GetLightFallOff()->IsPropAnimated() ? _T("Falloff") : NULL));
    + float hotspot; light->GetLightHotSpot()->GetPropertyValue(hotspot);
    + AddParamValNode(lightNode, _T("INNERCONE"), pt_float, _T("IN"), hotspot, (light->GetLightHotSpot()->IsPropAnimated() ? _T("Hotspot") : NULL));
    + }
    + }
    + // target param
    + IGameNode* target = light->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<IXMLDOMN ode>& 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->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->GetMaxObject();
    - for (int i = 0; i < objects.Count(); i++)
    - if (objects[i] == maxobj) break;
    - if (i == objects.Count()) { // not found, so 1st inst, add <geometry> node for it
    - objects.Append(1, &maxobj);
    - AddGeometryNode(libNode, (IGameMesh*)obj, node);
    + // add <geometry> nodes for this node and its children
    + IGameObject* obj = node->GetIGameObject();
    + if (obj->GetIGameType() == IGameObject::IGAME_MESH)
    + {
    + if (!obj->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->GetMaxObject();
    + for (int i = 0; i < objects.Count(); i++)
    + if (objects[i] == maxobj) break;
    + if (i == objects.Count()) { // not found, so 1st inst, add <geometry> node for it
    + objects.Append(1, &maxobj);
    + AddGeometryNode(libNode, (IGameMesh*)obj, node);
    + }
    }
    }
    - node->ReleaseIGameObject();
    + node->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 < numVerts; i++) {
    Point3 vert;
    mesh->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

  9. #9
    Junior Member
    Join Date
    Aug 2005
    Posts
    4
    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

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •