Some C# code to help get started loading a Collada document

C# kickstart for loading the xmlNodes of a collada document.

This code does not render the mesh, or scene or whatever, but it provides a pretty good starting point for loading the data contained in a collada file.

This basically consists of a function that walks over the xml and loads the various libraries into a dictionary based on their id.

There is a todo statement to help you find where you can load the mesh data. TODO: Save off the mesh data for rendering.

There is an additional class at that provides the string constants that are the elements that we are iterating over.


using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.XPath;

namespace Game.Model
{
  public class Collada
  {
    public void Load(string fileName)
    {
      fileName = Environment.ExpandEnvironmentVariables(fileName);
      
      if (! System.IO.File.Exists(fileName) )
        return;

      //XPathDocument means we are doing a readonly traversal
      XPathDocument doc = new XPathDocument(fileName);   
      XPathNavigator navigator = doc.CreateNavigator();

      //Move to the first child element of the document.  
      //This will be the root element.
      navigator.MoveToChild(XPathNodeType.Element);  
      string uri = string.Empty;
      if (navigator.HasAttributes == true)
      {
        uri = navigator.NamespaceURI;
      }

      //temp variable -- to get key for data dictionary
      string id;  

      //Since everything is pretty much organized by id semantics 
      //I've chosen to just add the nodes to a dictionary 
      //This should  make processing the doucment easier.

      Dictionary<string, XPathNavigator> data;
      data = new Dictionary<string, XPathNavigator>();

      //Handle Asset data
      structAssetData assetData;
      assetData = Collada.GetAssetData(navigator, uri);

      ////Handle Library data
      XPathNodeIterator libraryNodesIterator;
      libraryNodesIterator = navigator.SelectChildren(XmlCollada.Library.root, uri);

      while (libraryNodesIterator.MoveNext())
      {
        XPathNodeIterator typeAttributeIterator = libraryNodesIterator.Current.Select("@" + XmlCollada.Library.type);
        while (typeAttributeIterator.MoveNext())
        {
          string typeAttributeValue = typeAttributeIterator.Current.Value;

          //Parse the material node
          switch (typeAttributeValue)
          {
            case XmlCollada.Library.VMATERIAL:
              XPathNodeIterator materialNodeIterator = libraryNodesIterator.Current.SelectChildren(XmlCollada.Material.root, uri);
              while (materialNodeIterator.MoveNext())
              {
                XPathNodeIterator attributeIterator = materialNodeIterator.Current.Select("@" + XmlCollada.Material.id);
                attributeIterator.MoveNext();
                id = attributeIterator.Current.Value;
                data[id] = libraryNodesIterator.Current;
              }
              break;

            case XmlCollada.Library.VGEOMETRY:
              XPathNodeIterator geometryNodeIterator = libraryNodesIterator.Current.SelectChildren(XmlCollada.Geometry.root, uri);
              while (geometryNodeIterator.MoveNext())
              {
                XPathNodeIterator meshNodeIterator = geometryNodeIterator.Current.SelectChildren(XmlCollada.Mesh.root, uri);
                while (meshNodeIterator.MoveNext())
                {
                  //Here is the data
                  XPathNodeIterator sourceNodeIterator = meshNodeIterator.Current.SelectChildren(XmlCollada.Mesh.source, uri);
                  while (sourceNodeIterator.MoveNext())
                  {
                    XPathNodeIterator attributeIterator = sourceNodeIterator.Current.Select("@" + XmlCollada.Source.id);
                    attributeIterator.MoveNext();
                    id = attributeIterator.Current.Value;
                    data[id] = sourceNodeIterator.Current;
                  }

                  XPathNodeIterator verticesNodeIterator = meshNodeIterator.Current.SelectChildren(XmlCollada.Mesh.vertices, uri);
                  while (verticesNodeIterator.MoveNext())
                  {
                    XPathNodeIterator attributeIterator = verticesNodeIterator.Current.Select("@" + XmlCollada.Vertices.id);
                    attributeIterator.MoveNext();
                    id = attributeIterator.Current.Value;
                    data[id] = verticesNodeIterator.Current;
                  }

                  XPathNodeIterator polygonNodeIterator = meshNodeIterator.Current.SelectChildren(XmlCollada.Mesh.polygons, uri);
                  XPathNodeIterator linesNodeIterator = meshNodeIterator.Current.SelectChildren(XmlCollada.Mesh.lines, uri);
                  XPathNodeIterator lineStripsNodeIterator = meshNodeIterator.Current.SelectChildren(XmlCollada.Mesh.linestrips, uri);
                  XPathNodeIterator trianglesNodeIterator = meshNodeIterator.Current.SelectChildren(XmlCollada.Mesh.triangles, uri);
                  XPathNodeIterator trifansNodeIterator = meshNodeIterator.Current.SelectChildren(XmlCollada.Mesh.trifans, uri);
                  XPathNodeIterator tristripsNodeIterator = meshNodeIterator.Current.SelectChildren(XmlCollada.Mesh.tristrips, uri);

                  //TODO: Save off the mesh data for rendering.

                }
              }
              break;

            case XmlCollada.Library.VLIGHT:
              XPathNodeIterator lightNodeIterator = libraryNodesIterator.Current.SelectChildren(XmlCollada.Light.root, uri);
              while (lightNodeIterator.MoveNext())
              {
                XPathNodeIterator attributeIterator = lightNodeIterator.Current.Select("@" + XmlCollada.Light.id);
                attributeIterator.MoveNext();
                id = attributeIterator.Current.Value;
                data[id] = lightNodeIterator.Current;
              }
              break;
            case XmlCollada.Library.VCAMERA:
              XPathNodeIterator cameraNodeIterator = libraryNodesIterator.Current.SelectChildren(XmlCollada.Camera.root, uri);
              while (cameraNodeIterator.MoveNext())
              {
                XPathNodeIterator attributeIterator = cameraNodeIterator.Current.Select("@" + XmlCollada.Camera.id);
                attributeIterator.MoveNext();
                id = attributeIterator.Current.Value;
                data[id] = cameraNodeIterator.Current;
              }
              break;
          }  //end switch library typeAttribte value
        }
      }

      ////Handle Scene data

      //Keep in mind that according to the specification there will only be one scene element per document.
      XPathNodeIterator sceneNodeIterator = navigator.SelectChildren(XmlCollada.Scene.root, uri);
      while (sceneNodeIterator.MoveNext())
      {
        XPathNodeIterator sceneExtraNodeIterator = sceneNodeIterator.Current.SelectChildren(XmlCollada.Extra.root, uri);

        XPathNodeIterator sceneNodesNodeIterator = sceneNodeIterator.Current.SelectChildren(XmlCollada.Node.root, uri);
        while (sceneNodesNodeIterator.MoveNext())
        {
          XPathNodeIterator attributeIterator = sceneNodesNodeIterator.Current.Select("@" + XmlCollada.Node.id);
          attributeIterator.MoveNext();
          id = attributeIterator.Current.Value;
          data[id] = sceneNodeIterator.Current;
        }
      }
    }

    private struct structAssetData
    {
      public string copyRight;
      public string authoringTool;
      public string sourceData;
      public string upAxis;
      public string unitName;
      public string unitMeter;
      public string author;
      public string dateModified;
    }

    private static structAssetData GetAssetData(XPathNavigator navigator, string uri)
    {
      structAssetData result;
      result.copyRight = string.Empty;
      result.authoringTool = string.Empty;
      result.sourceData = string.Empty;
      result.upAxis = string.Empty;
      result.unitName = string.Empty;
      result.unitMeter = string.Empty;
      result.author = string.Empty;
      result.dateModified = string.Empty;

      XPathNodeIterator assetNodeIterator = navigator.SelectDescendants(XmlCollada.Asset.root, uri, false);
      while (assetNodeIterator.MoveNext())
      {
        XPathNodeIterator assetChildrenNodeIterator = assetNodeIterator.Current.SelectChildren(XPathNodeType.Element);
        while (assetChildrenNodeIterator.MoveNext())
        {
          switch (assetChildrenNodeIterator.Current.Name)
          {
            case XmlCollada.Asset.copyright:
              result.copyRight = assetChildrenNodeIterator.Current.Value;
              break;
            case XmlCollada.Asset.authoringTool:
              result.authoringTool = assetChildrenNodeIterator.Current.Value;
              break;
            case XmlCollada.Asset.sourceData:
              result.sourceData = assetChildrenNodeIterator.Current.Value;
              break;
            case XmlCollada.Asset.upaxis:
              result.upAxis = assetChildrenNodeIterator.Current.Value;
              break;
            case XmlCollada.Asset.unit:
              XPathNodeIterator attributeIterator = assetChildrenNodeIterator.Current.Select("@" + XmlCollada.Asset.name);
              attributeIterator.MoveNext();
              result.unitName = attributeIterator.Current.Value;

              attributeIterator = assetChildrenNodeIterator.Current.Select("@" + XmlCollada.Asset.meter);
              attributeIterator.MoveNext();
              result.unitMeter = attributeIterator.Current.Value;
              break;
            case XmlCollada.Asset.author:
              result.author = assetChildrenNodeIterator.Current.Value;
              break;
            case XmlCollada.Asset.modified:
              result.dateModified = assetChildrenNodeIterator.Current.Value;
              break;
          }
        }
      }
      return result;
    }
  }  //class

//Here are the constants


  public class XmlCollada
  {
    public class Collada
    {
      public const string root = "COLLADA";
      public const string xmlns = "xmlns";
      public const string version = "version";
      public const string V130 = "1.3.0";
    }

    public class Instance
    {
      public const string root = "instance";
      public const string url = "url";
    }

    public class Camera
    {
      public const string root = "camera";
      public const string id = "id";
      public const string name = "name";
    }

    public class Skew
    {
      public const string root = "skew";
      public const string sid = "sid";
      public const string VshearYZ = "shearYZ";
    }

    public class Vertices
    {
      public const string root = "vertices";
      public const string id = "id";
    }

    public class Rotate
    {
      public const string root = "rotate";
      public const string sid = "sid";
      public const string VrotateY = "rotateY";
      public const string VrotateX = "rotateX";
    }

    public class Program
    {
      public const string root = "program";
      public const string url = "url";
      public const string VPHONG = "PHONG";
      public const string VPERSPECTIVE = "PERSPECTIVE";
    }


    public class Float_array
    {
      public const string root = "float_array";
      public const string id = "id";
      public const string count = "count";
    }

    public class Param
    {
      public const string root = "param";
      public const string name = "name";
      public const string type = "type";
      public const string flow = "flow";
      public const string sid = "sid";
      public const string VDIFFUSE = "DIFFUSE";
      public const string Vfloat3 = "float3";
      public const string VIN = "IN";
      public const string Vdiffuse = "diffuse";
      public const string VAMBIENT = "AMBIENT";
      public const string Vparam1 = "param1";
      public const string VTRANSPARENT = "TRANSPARENT";
      public const string Vtransparent = "transparent";
      public const string VTRANSPARENCY = "TRANSPARENCY";
      public const string Vfloat = "float";
      public const string VEMISSION = "EMISSION";
      public const string Vparam4 = "param4";
      public const string VSPECULAR = "SPECULAR";
      public const string Vparam5 = "param5";
      public const string VREFLECTIVE = "REFLECTIVE";
      public const string Vparam6 = "param6";
      public const string VREFLECTIVITY = "REFLECTIVITY";
      public const string Vparam7 = "param7";
      public const string VSHININESS = "SHININESS";
      public const string Vparam8 = "param8";
      public const string VX = "X";
      public const string VOUT = "OUT";
      public const string VY = "Y";
      public const string VZ = "Z";
      public const string VDOUBLESIDED = "DOUBLE_SIDED";
      public const string Vbool = "bool";
      public const string VCOLOR = "COLOR";
      public const string Vparam0 = "param0";
      public const string VATTENUATION = "ATTENUATION";
      public const string Vfunction = "function";
      public const string VATTENUATIONSCALE = "ATTENUATION_SCALE";
      public const string VVERTICALAPERTURE = "VERTICAL_APERTURE";
      public const string VHORIZONTALAPERTURE = "HORIZONTAL_APERTURE";
      public const string VLENSSQUEEZE = "LENS_SQUEEZE";
      public const string Vparam2 = "param2";
      public const string VYFOV = "YFOV";
      public const string VZNEAR = "ZNEAR";
      public const string VZFAR = "ZFAR";
      public const string VSTARTTIME = "START_TIME";
      public const string VENDTIME = "END_TIME";
    }

    public class Geometry
    {
      public const string root = "geometry";
      public const string id = "id";
      public const string name = "name";
      public const string Vfloor = "floor";
      public const string Vcollada = "collada";
    }

    public class Boundingbox
    {
      public const string root = "boundingbox";
      public const string min = "min";
      public const string max = "max";
    }

    public class Translate
    {
      public const string root = "translate";
      public const string sid = "sid";
      public const string Vtranslate = "translate";
    }

    public class Input
    {
      public const string root = "input";
      public const string semantic = "semantic";
      public const string source = "source";
      public const string idx = "idx";
      public const string VPOSITION = "POSITION";
      public const string VNORMAL = "NORMAL";
      public const string VVERTEX = "VERTEX";
      public const string V0 = "0";
      public const string V1 = "1";
    }


    public class Source
    {
      public const string root = "source";
      public const string id = "id";
    }

    public class Polygons
    {
      public const string root = "polygons";
      public const string material = "material";
      public const string count = "count";
    }

    public class Node
    {
      public const string root = "node";
      public const string id = "id";
      public const string name = "name";
      public const string VCamera = "Camera";
      public const string VLight = "Light";
      public const string VFloor = "Floor";
      public const string VCollada = "Collada";
    }

    public class Extra
    {
      public const string root = "extra";
    }

    public class Pass
    {
      public const string root = "pass";
    }

    public class Asset
    {
      public const string root = "asset";
      public const string author = "author";
      public const string upaxis = "up_axis";
      public const string modified = "modified";
      public const string unit = "unit";
      public const string name = "name";
      public const string meter = "meter";
      public const string Vcentimeter = "centimeter";
      public const string V1e002 = "1.e-002";
      public const string sourceData = "source_data";
      public const string authoringTool = "authoring_tool";
      public const string copyright = "copyright";
    }

    public class Library
    {
      public const string root = "library";
      public const string type = "type";
      public const string VMATERIAL = "MATERIAL";
      public const string VGEOMETRY = "GEOMETRY";
      public const string VLIGHT = "LIGHT";
      public const string VCAMERA = "CAMERA";
    }

    public class Scene
    {
      public const string root = "scene";
      public const string name = "name";
      public const string VcolladaIMaya = "collada_I-Maya";
    }

    public class Material
    {
      public const string root = "material";
      public const string id = "id";
      public const string name = "name";
      public const string asset = "asset";
      public const string param = "param";
      public const string shader = "shader";
      public const string VStone = "Stone";
      public const string VRedPlastic = "RedPlastic";
    }

    public class Accessor
    {
      public const string root = "accessor";
      public const string source = "source";
      public const string count = "count";
      public const string stride = "stride";
      public const string V4 = "4";
      public const string V3 = "3";
    }

    public class Mesh
    {
      public const string root = "mesh";

      public const string source = "source";
      public const string vertices = "vertices";
      public const string lines = "lines";
      public const string linestrips = "linestrips";
      public const string polygons = "polygons";
      public const string triangles = "triangles";
      public const string trifans = "trifans";
      public const string tristrips = "tristrips";
    }

    public class Optics
    {
      public const string root = "optics";
    }

    public class Shader
    {
      public const string root = "shader";
    }

    public class Light
    {
      public const string root = "light";
      public const string id = "id";
      public const string name = "name";
      public const string type = "type";
      public const string Vlight = "light";
      public const string VPOINT = "POINT";

    }

    public class Technique
    {
      public const string root = "technique";
      public const string profile = "profile";
      public const string VCOMMON = "COMMON";
      public const string VMAYA = "MAYA";
    }

    /// <summary>
    /// Primitive
    /// </summary>
    public class P
    {
      public const string root = "p";
    }
  }  //class

}  //namespace


Hopefully, by the end of the week, I’ll post a better, more usable example too. An example that parses through the rest of the geometry data, and stores it off. I might even have an opengl renderer done by then too, so that you will be able to view the file in an application.

Has there been any progress with the C# loader?

Yes, I have a working loader for models in C#. Though it is for collada version 1.3 … meaning that 1.4 models do not load due to the breaking changes in the way that the xml is formatted.

Mostly, easy changes, but I just haven’t gotten around to fixing it yet.