Browse Source

Basically functional collada loader that uses the COLLADA DOM. Can load scene graph and geometry.

rdb 14 years ago
parent
commit
776baf7c15

+ 10 - 4
dtool/Config.pp

@@ -1054,10 +1054,16 @@
 #defer HAVE_FCOLLADA $[libtest $[FCOLLADA_LPATH],$[FCOLLADA_LIBS]]
 
 // Is the COLLADA DOM installed? This is for the native COLLADA loader.
-#define COLLADADOM_IPATH /usr/local/include/collada-dom /usr/local/include/collada-dom/1.5
-#define COLLADADOM_LPATH /usr/local/lib
-#define COLLADADOM_LIBS collada15dom xml2 boost_filesystem
-#defer HAVE_COLLADADOM $[libtest $[COLLADADOM_LPATH],$[COLLADADOM_LIBS]]
+// This defines the versions that your copy of COLLADA DOM supports.
+#define COLLADA14DOM_IPATH /usr/local/include/collada-dom /usr/local/include/collada-dom/1.4
+#define COLLADA14DOM_LPATH /usr/local/lib
+#define COLLADA14DOM_LIBS collada14dom xml2 boost_filesystem
+#defer HAVE_COLLADA14DOM $[libtest $[COLLADA14DOM_LPATH],$[COLLADA14DOM_LIBS]]
+
+#define COLLADA15DOM_IPATH /usr/local/include/collada-dom /usr/local/include/collada-dom/1.5
+#define COLLADA15DOM_LPATH /usr/local/lib
+#define COLLADA15DOM_LIBS collada15dom xml2 boost_filesystem
+#defer HAVE_COLLADA15DOM $[libtest $[COLLADA15DOM_LPATH],$[COLLADA15DOM_LIBS]]
 
 // Also for the ARToolKit library, for augmented reality
 #define ARTOOLKIT_IPATH

+ 1 - 1
dtool/LocalSetup.pp

@@ -205,7 +205,7 @@
 #else
 #print - Did not find FCollada
 #endif
-#if $[HAVE_COLLADADOM]
+#if $[or $[HAVE_COLLADA14DOM],$[HAVE_COLLADA15DOM]]
 #print + COLLADA DOM
 #else
 #print - Did not find COLLADA DOM

+ 9 - 4
dtool/Package.pp

@@ -359,10 +359,15 @@
 #set FCOLLADA_LIBS $[FCOLLADA_LIBS]
 #set HAVE_FCOLLADA $[HAVE_FCOLLADA]
 
-#set COLLADADOM_IPATH $[unixfilename $[COLLADADOM_IPATH]]
-#set COLLADADOM_LPATH $[unixfilename $[COLLADADOM_LPATH]]
-#set COLLADADOM_LIBS $[COLLADADOM_LIBS]
-#set HAVE_COLLADADOM $[HAVE_COLLADADOM]
+#set COLLADA14DOM_IPATH $[unixfilename $[COLLADA14DOM_IPATH]]
+#set COLLADA14DOM_LPATH $[unixfilename $[COLLADA14DOM_LPATH]]
+#set COLLADA14DOM_LIBS $[COLLADA14DOM_LIBS]
+#set HAVE_COLLADA14DOM $[HAVE_COLLADA14DOM]
+
+#set COLLADA15DOM_IPATH $[unixfilename $[COLLADA15DOM_IPATH]]
+#set COLLADA15DOM_LPATH $[unixfilename $[COLLADA15DOM_LPATH]]
+#set COLLADA15DOM_LIBS $[COLLADA15DOM_LIBS]
+#set HAVE_COLLADA15DOM $[HAVE_COLLADA15DOM]
 
 #set ARTOOLKIT_IPATH $[unixfilename $[ARTOOLKIT_IPATH]]
 #set ARTOOLKIT_LPATH $[unixfilename $[ARTOOLKIT_LPATH]]

+ 10 - 4
dtool/pptempl/Global.pp

@@ -479,10 +479,16 @@
   #define fcollada_libs $[FCOLLADA_LIBS]
 #endif
 
-#if $[HAVE_COLLADADOM]
-  #define colladadom_ipath $[wildcard $[COLLADADOM_IPATH]]
-  #define colladadom_lpath $[wildcard $[COLLADADOM_LPATH]]
-  #define colladadom_libs $[COLLADADOM_LIBS]
+#if $[HAVE_COLLADA14DOM]
+  #define collada14dom_ipath $[wildcard $[COLLADA14DOM_IPATH]]
+  #define collada14dom_lpath $[wildcard $[COLLADA14DOM_LPATH]]
+  #define collada14dom_libs $[COLLADA14DOM_LIBS]
+#endif
+
+#if $[HAVE_COLLADA15DOM]
+  #define collada15dom_ipath $[wildcard $[COLLADA15DOM_IPATH]]
+  #define collada15dom_lpath $[wildcard $[COLLADA15DOM_LPATH]]
+  #define collada15dom_libs $[COLLADA15DOM_LIBS]
 #endif
 
 #if $[HAVE_ARTOOLKIT]

+ 37 - 0
panda/src/collada/Sources.pp

@@ -0,0 +1,37 @@
+#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
+                   dtoolutil:c dtoolbase:c dtool:m prc:c
+
+#define LOCAL_LIBS display pgraph express putil pandabase
+
+#define COMBINED_SOURCES collada_composite1.cxx
+
+#define SOURCES \
+  colladaLoader.cxx \
+  colladaLoader.h colladaLoader.I \
+  config_collada.h \
+  load_collada_file.h \
+  loaderFileTypeDae.h
+
+#define INCLUDED_SOURCES \
+  config_collada.cxx \
+  load_collada_file.cxx \
+  loaderFileTypeDae.cxx
+
+#define INSTALL_HEADERS \
+  config_collada.h \
+  load_collada_file.h \
+  loaderFileTypeDae.h
+
+#begin lib_target
+  #define BUILD_TARGET $[HAVE_COLLADA14DOM]
+  #define USE_PACKAGES collada14dom
+  #define EXTRA_CDEFS PANDA_COLLADA_VERSION=14
+  #define TARGET p3collada14
+#end lib_target
+
+#begin lib_target
+  #define BUILD_TARGET $[HAVE_COLLADA15DOM]
+  #define USE_PACKAGES collada15dom
+  #define EXTRA_CDEFS PANDA_COLLADA_VERSION=15
+  #define TARGET p3collada15
+#end lib_target

+ 14 - 0
panda/src/collada/colladaLoader.I

@@ -0,0 +1,14 @@
+// Filename: colladaLoader.I
+// Created by:  rdb (16Mar11)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+

+ 511 - 0
panda/src/collada/colladaLoader.cxx

@@ -0,0 +1,511 @@
+// Filename: colladaLoader.cxx
+// Created by: Xidram (21Dec10)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "colladaLoader.h"
+#include "virtualFileSystem.h"
+#include "luse.h"
+#include "string_utils.h"
+#include "geomNode.h"
+#include "geomVertexWriter.h"
+#include "geomTriangles.h"
+
+// Ugh, undef some macros that conflict with COLLADA.
+#undef INLINE
+#undef tolower
+
+#include <dae.h>
+#include <dom/domCOLLADA.h>
+#include <dom/domNode.h>
+#include <dom/domVisual_scene.h>
+#include <dom/domTranslate.h>
+#include <dom/domRotate.h>
+#include <dom/domMatrix.h>
+
+#if PANDA_COLLADA_VERSION >= 15
+#include <dom/domInstance_with_extra.h>
+#else
+#include <dom/domInstanceWithExtra.h>
+#define domInstance_with_extra domInstanceWithExtra
+#define domInput_localRef domInputLocalRef
+#define domInput_local_offsetRef domInputLocalOffsetRef
+#define domList_of_uints domListOfUInts
+#define domList_of_floats domListOfFloats
+#endif
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaLoader::Constructor
+//  Description:
+////////////////////////////////////////////////////////////////////
+ColladaLoader::
+ColladaLoader() :
+  _record (NULL),
+  _cs (CS_default),
+  _error (false),
+  _root (NULL),
+  _collada (NULL) {
+
+  _dae = new DAE;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaLoader::Destructor
+//  Description:
+////////////////////////////////////////////////////////////////////
+ColladaLoader::
+~ColladaLoader() {
+  delete _dae;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaLoader::read
+//  Description: Reads from the indicated file.
+////////////////////////////////////////////////////////////////////
+bool ColladaLoader::
+read(const Filename &filename) {
+  _filename = filename;
+
+  string data;
+  VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+
+  if (!vfs->read_file(_filename, data, true)) {
+    collada_cat.error()
+      << "Error reading " << _filename << "\n";
+    _error = true;
+    return false;
+  }
+
+  _collada = _dae->openFromMemory(_filename.to_os_specific(), data.c_str());
+  _error = (_collada == NULL);
+  return !_error;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaLoader::build_graph
+//  Description: Converts scene graph structures into a Panda3D
+//               scene graph, with _root being the root node.
+////////////////////////////////////////////////////////////////////
+void ColladaLoader::
+build_graph() {
+  nassertv(_collada); // read() must be called first
+  nassertv(!_error);  // and have succeeded
+
+  _root = new ModelRoot(_filename.get_basename());
+
+  domCOLLADA::domScene* scene = _collada->getScene();
+  domInstance_with_extra* inst = scene->getInstance_visual_scene();
+  domVisual_scene* vscene = daeSafeCast<domVisual_scene> (inst->getUrl().getElement());
+  if (vscene) {
+    load_visual_scene(*vscene, _root);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaLoader::load_visual_scene
+//  Description: Loads a visual scene structure.
+////////////////////////////////////////////////////////////////////
+void ColladaLoader::
+load_visual_scene(domVisual_scene& scene, PandaNode *parent) {
+  // If we already loaded it before, instantiate the stored node.
+  if (scene.getUserData() != NULL) {
+    parent->add_child((PandaNode *) scene.getUserData());
+    return;
+  }
+
+  PT(PandaNode) pnode = new PandaNode(scene.getName());
+  scene.setUserData((void *) pnode);
+  parent->add_child(pnode);
+
+  // Load in any tags.
+  domExtra_Array &extras = scene.getExtra_array();
+  for (size_t i = 0; i < extras.getCount(); ++i) {
+    load_tags(*extras[i], pnode);
+  }
+
+  // Now load in the child nodes.
+  domNode_Array &nodes = scene.getNode_array();
+  for (size_t i = 0; i < nodes.getCount(); ++i) {
+    load_node(*nodes[i], pnode);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaLoader::load_node
+//  Description: Loads a COLLADA <node>.
+////////////////////////////////////////////////////////////////////
+void ColladaLoader::
+load_node(domNode& node, PandaNode *parent) {
+  // If we already loaded it before, instantiate the stored node.
+  if (node.getUserData() != NULL) {
+    parent->add_child((PandaNode *) node.getUserData());
+    return;
+  }
+
+  // Create the node.
+  PT(PandaNode) pnode;
+  pnode = new PandaNode(node.getName());
+  node.setUserData((void *) pnode);
+  parent->add_child(pnode);
+
+  // Apply the transformation elements in reverse order.
+  LMatrix4f transform (LMatrix4f::ident_mat());
+
+  daeElementRefArray &elements = node.getContents();
+  for (size_t i = elements.getCount() - 1; i > 0; --i) {
+    daeElementRef &elem = elements[i];
+
+    switch (elem->getElementType()) {
+      case COLLADA_TYPE::LOOKAT: {
+        // Didn't test this, but *should* be right.
+        domFloat3x3 &l = (daeSafeCast<domLookat>(elem))->getValue();
+        LPoint3f eye (l[0], l[1], l[2]);
+        LVector3f up (l[6], l[7], l[8]);
+        LVector3f forward = LPoint3f(l[3], l[4], l[5]) - eye;
+        forward.normalize();
+        LVector3f side = forward.cross(up);
+        side.normalize();
+        up = side.cross(forward);
+        LMatrix4f mat (LMatrix4f::ident_mat());
+        mat.set_col(0, side);
+        mat.set_col(1, up);
+        mat.set_col(2, -forward);
+        transform *= mat;
+        transform *= LMatrix4f::translate_mat(-eye);
+        break;
+      }
+      case COLLADA_TYPE::MATRIX: {
+        domFloat4x4 &m = (daeSafeCast<domMatrix>(elem))->getValue();
+        transform *= LMatrix4f(
+          m[0], m[4], m[ 8], m[12],
+          m[1], m[5], m[ 9], m[13],
+          m[2], m[6], m[10], m[14],
+          m[3], m[7], m[11], m[15]);
+        break;
+      }
+      case COLLADA_TYPE::ROTATE: {
+        domFloat4 &r = (daeSafeCast<domRotate>(elem))->getValue();
+        transform *= LMatrix4f::rotate_mat(r[3], LVecBase3f(r[0], r[1], r[2]));
+        break;
+      }
+      case COLLADA_TYPE::SCALE: {
+        domFloat3 &s = (daeSafeCast<domScale>(elem))->getValue();
+        transform *= LMatrix4f::scale_mat(s[0], s[1], s[2]);
+        break;
+      }
+      case COLLADA_TYPE::SKEW:
+        // FIXME: implement skew
+        collada_cat.error() << "<skew> not supported yet\n";
+        break;
+      case COLLADA_TYPE::TRANSLATE: {
+        domFloat3 &t = (daeSafeCast<domTranslate>(elem))->getValue();
+        transform *= LMatrix4f::translate_mat(t[0], t[1], t[2]);
+        break;
+      }
+    }
+  }
+  //TODO: convert coordinate systems
+  //transform *= LMatrix4f::convert_mat(XXX, _cs);
+
+  // If there's a transform, set it.
+  if (transform != LMatrix4f::ident_mat()) {
+    pnode->set_transform(TransformState::make_mat(transform));
+  }
+
+  // See if this node instantiates any cameras.
+  domInstance_camera_Array &caminst = node.getInstance_camera_array();
+  for (size_t i = 0; i < caminst.getCount(); ++i) {
+    domCamera* target = daeSafeCast<domCamera> (caminst[i]->getUrl().getElement());
+    load_camera(*target, pnode);
+  }
+
+  // See if this node instantiates any geoms.
+  domInstance_geometry_Array &ginst = node.getInstance_geometry_array();
+  for (size_t i = 0; i < ginst.getCount(); ++i) {
+    domGeometry* target = daeSafeCast<domGeometry> (ginst[i]->getUrl().getElement());
+    load_geometry(*target, pnode);
+  }
+
+  // See if this node instantiates any lights.
+  domInstance_light_Array &linst = node.getInstance_light_array();
+  for (size_t i = 0; i < linst.getCount(); ++i) {
+    domLight* target = daeSafeCast<domLight> (linst[i]->getUrl().getElement());
+    load_light(*target, pnode);
+  }
+
+  // And instantiate any <instance_nodes> elements.
+  domInstance_node_Array &ninst = node.getInstance_node_array();
+  for (size_t i = 0; i < ninst.getCount(); ++i) {
+    domNode* target = daeSafeCast<domNode> (ninst[i]->getUrl().getElement());
+    load_node(*target, pnode);
+  }
+
+  // Now load in the child nodes.
+  domNode_Array &nodes = node.getNode_array();
+  for (size_t i = 0; i < nodes.getCount(); ++i) {
+    load_node(*nodes[i], pnode);
+  }
+
+  // Load in any tags.
+  domExtra_Array &extras = node.getExtra_array();
+  for (size_t i = 0; i < extras.getCount(); ++i) {
+    load_tags(*extras[i], pnode);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaLoader::load_tags
+//  Description: Loads tags specified in an <extra> element.
+////////////////////////////////////////////////////////////////////
+void ColladaLoader::
+load_tags(domExtra &extra, PandaNode *node) {
+  domTechnique_Array &techniques = extra.getTechnique_array();
+
+  for (size_t t = 0; t < techniques.getCount(); ++t) {
+    if (cmp_nocase(techniques[t]->getProfile(), "PANDA3D") == 0) {
+      const daeElementRefArray &children = techniques[t]->getChildren();
+
+      for (size_t c = 0; c < children.getCount(); ++c) {
+        daeElement &child = *children[c];
+
+        if (cmp_nocase(child.getElementName(), "tag") == 0) {
+          const string &name = child.getAttribute("name");
+          if (name.size() > 0) {
+            node->set_tag(name, child.getCharData());
+          } else {
+            collada_cat.warning() << "Ignoring <tag> without name attribute\n";
+          }
+        } else if (cmp_nocase(child.getElementName(), "param") == 0) {
+          collada_cat.error() <<
+            "Unknown <param> attribute in PANDA3D technique. "
+            "Did you mean to use <tag> instead?\n";
+        }
+      }
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaLoader::load_camera
+//  Description: Loads a COLLADA <camera> as a Camera object.
+////////////////////////////////////////////////////////////////////
+void ColladaLoader::
+load_camera(domCamera &cam, PandaNode *parent) {
+  // If we already loaded it before, instantiate the stored node.
+  if (cam.getUserData() != NULL) {
+    parent->add_child((PandaNode *) cam.getUserData());
+    return;
+  }
+
+  //TODO
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaLoader::load_geometry
+//  Description: Loads a COLLADA <geometry> as a GeomNode object.
+////////////////////////////////////////////////////////////////////
+void ColladaLoader::
+load_geometry(domGeometry &geom, PandaNode *parent) {
+  // If we already loaded it before, instantiate the stored node.
+  if (geom.getUserData() != NULL) {
+    parent->add_child((PandaNode *) geom.getUserData());
+    return;
+  }
+
+  domMesh* mesh = geom.getMesh();
+  if (mesh == NULL) {
+    //TODO: support non-mesh geometry.
+    return;
+  }
+
+  // Create the node.
+  PT(GeomNode) gnode = new GeomNode(geom.getName());
+  geom.setUserData((void *) gnode);
+  parent->add_child(gnode);
+
+  // First handle the <vertices> element.
+  domVertices &vertices = *mesh->getVertices();
+  daeTArray<domInput_localRef> &vtx_inputs = vertices.getInput_array();
+
+  PT(GeomVertexArrayFormat) vtx_aformat = new GeomVertexArrayFormat;
+  PTA_LVecBase4f *vtx_values = new PTA_LVecBase4f[vtx_inputs.getCount()];
+  CPT(InternalName) *vtx_names = new CPT(InternalName)[vtx_inputs.getCount()];
+
+  for (size_t i = 0; i < vtx_inputs.getCount(); ++i) {
+    const string semantic = vtx_inputs[i]->getSemantic();
+    domSource *source = daeSafeCast<domSource>(vtx_inputs[i]->getSource().getElement());
+    nassertd(source != NULL) continue;
+
+    vtx_names[i] = load_input(vtx_aformat, vtx_values[i], semantic, *source);
+  }
+
+  domTriangles_Array &triangles_array = mesh->getTriangles_array();
+  for (size_t i = 0; i < triangles_array.getCount(); ++i) {
+    domTriangles &tris = *triangles_array[i];
+
+    if (tris.getP() == NULL) {
+      continue;
+    }
+    domList_of_uints &p = tris.getP()->getValue();
+
+    // Read out the inputs.
+    daeTArray<domInput_local_offsetRef> &inputs = tris.getInput_array();
+
+    PT(GeomVertexArrayFormat) aformat = new GeomVertexArrayFormat;
+    PTA_LVecBase4f *values = new PTA_LVecBase4f[inputs.getCount()];
+    CPT(InternalName) *names = new CPT(InternalName)[inputs.getCount()];
+
+    domUint stride = 1;
+    for (size_t in = 0; in < inputs.getCount(); ++in) {
+      const string semantic = inputs[in]->getSemantic();
+      if (semantic == "VERTEX") {
+        names[in] = NULL;
+        continue;
+      }
+      domSource *source = daeSafeCast<domSource>(inputs[in]->getSource().getElement());
+      nassertd(source != NULL) continue;
+
+      names[in] = load_input(aformat, values[in], semantic, *source);
+
+      if (inputs[in]->getOffset() >= stride) {
+        stride = inputs[in]->getOffset() + 1;
+      }
+    }
+
+    // Create the vertex data.
+    PT(GeomVertexFormat) format = new GeomVertexFormat();
+    format->add_array(vtx_aformat);
+    format->add_array(aformat);
+    PT(GeomVertexData) vdata = new GeomVertexData(geom.getName(), GeomVertexFormat::register_format(format), GeomEnums::UH_static);
+
+    // Time to go and write the data.
+    PT(GeomTriangles) gtris = new GeomTriangles(GeomEnums::UH_static);
+    for (size_t in = 0; in < inputs.getCount(); ++in) {
+      if (names[in] == NULL) {
+        // Refers to a <vertices> tag, so write the vertex inputs.
+        int counter = 0;
+        for (size_t in = 0; in < vtx_inputs.getCount(); ++in) {
+          GeomVertexWriter writer(vdata, vtx_names[in]);
+          for (size_t j = 0; j < p.getCount(); j += stride * 3) {
+            for (char v = 0; v < 3; ++v) {
+              int idx = p[j + v * stride];
+              writer.add_data4f(vtx_values[in][idx]);
+              gtris->add_vertex(counter++);
+            }
+            gtris->close_primitive();
+          }
+        }
+      } else {
+        GeomVertexWriter writer(vdata, names[in]);
+        for (size_t j = 0; j < p.getCount(); j += stride * 3) {
+          for (char v = 0; v < 3; ++v) {
+            int idx = p[j + v * stride + inputs[in]->getOffset()];
+            writer.add_data4f(values[in][idx]);
+          }
+        }
+      }
+    }
+
+    PT(Geom) geom = new Geom(vdata);
+    geom->add_primitive(gtris);
+    gnode->add_geom(geom);
+
+    delete[] values;
+    delete[] names;
+  }
+
+  delete[] vtx_values;
+  delete[] vtx_names;
+
+  // Load in any tags.
+  domExtra_Array &extras = geom.getExtra_array();
+  for (size_t i = 0; i < extras.getCount(); ++i) {
+    load_tags(*extras[i], gnode);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaLoader::load_input
+//  Description: Takes a semantic and source URI, and adds a new
+//               column to the format.  Also fills up the values
+//               into the indicated PTA_LVecBase4f.
+//               Returns the InternalName of the input.
+////////////////////////////////////////////////////////////////////
+CPT(InternalName) ColladaLoader::
+load_input(GeomVertexArrayFormat *fmt, PTA_LVecBase4f &values,
+           const string &semantic, domSource &source) {
+
+  PT(InternalName) cname;
+  GeomEnums::Contents contents = GeomEnums::C_other;
+
+  if (semantic == "POSITION") {
+    cname = InternalName::get_vertex();
+    contents = GeomEnums::C_point;
+  } else if (semantic == "COLOR") {
+    cname = InternalName::get_color();
+    contents = GeomEnums::C_color;
+  } else if (semantic == "NORMAL") {
+    cname = InternalName::get_normal();
+    contents = GeomEnums::C_vector;
+  } else {
+    collada_cat.warning() << "Unrecognized semantic " << semantic << "\n";
+    cname = InternalName::make(downcase(semantic));
+  }
+
+  // Get this, get that
+  domFloat_array* float_array = source.getFloat_array();
+  nassertr(float_array != NULL, cname);
+  domList_of_floats &floats = float_array->getValue();
+  domAccessor &accessor = *source.getTechnique_common()->getAccessor();
+  domParam_Array &params = accessor.getParam_array();
+
+  // Count the number of params that have a name attribute.
+  domUint num_bound_params = 0;
+  for (size_t p = 0; p < params.getCount(); ++p) {
+    if (params[p]->getName()) {
+      ++num_bound_params;
+    }
+  }
+
+  domUint pos = accessor.getOffset();
+  for (domUint a = 0; a < accessor.getCount(); ++a) {
+    domUint c = 0;
+    // Yes, the last component defaults to 1 to work around a
+    // perspective divide that Panda3D does internally for points.
+    LVecBase4f v (0, 0, 0, 1);
+    for (domUint p = 0; p < params.getCount(); ++p) {
+      if (params[c]->getName()) {
+        v._v.data[c++] = floats[pos + p];
+      }
+    }
+    values.push_back(v);
+    pos += accessor.getStride();
+  }
+
+  fmt->add_column(cname, num_bound_params, GeomEnums::NT_float32, contents);
+  return cname;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaLoader::load_light
+//  Description: Loads a COLLADA <light> as a LightNode object.
+////////////////////////////////////////////////////////////////////
+void ColladaLoader::
+load_light(domLight &light, PandaNode *parent) {
+  // If we already loaded it before, instantiate the stored node.
+  if (light.getUserData() != NULL) {
+    parent->add_child((PandaNode *) light.getUserData());
+    return;
+  }
+
+  //TODO
+}

+ 72 - 0
panda/src/collada/colladaLoader.h

@@ -0,0 +1,72 @@
+// Filename: colladaLoader.h
+// Created by: Xidram (21Dec10)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef COLLADALOADER_H
+#define COLLADALOADER_H
+
+#include "pandabase.h"
+#include "config_collada.h"
+#include "typedReferenceCount.h"
+#include "pandaNode.h"
+#include "modelRoot.h"
+#include "pvector.h"
+#include "pta_LVecBase4f.h"
+
+class BamCacheRecord;
+
+class domCOLLADA;
+class domNode;
+class domVisual_scene;
+class domExtra;
+class domGeometry;
+class domLight;
+class domCamera;
+class domSource;
+class DAE;
+
+////////////////////////////////////////////////////////////////////
+//       Class : ColladaLoader
+// Description : Object that interfaces with the COLLADA DOM library
+//               and loads the COLLADA structures into Panda nodes.
+////////////////////////////////////////////////////////////////////
+class ColladaLoader {
+public:
+  ColladaLoader();
+  virtual ~ColladaLoader();
+
+  bool _error;
+  PT(ModelRoot) _root;
+  BamCacheRecord *_record;
+  CoordinateSystem _cs;
+  Filename _filename;
+
+  bool read(const Filename &filename);
+  void build_graph();
+
+private:
+  const domCOLLADA* _collada;
+  DAE* _dae;
+
+  void load_visual_scene(domVisual_scene &scene, PandaNode *parent);
+  void load_node(domNode &node, PandaNode *parent);
+  void load_tags(domExtra &extra, PandaNode *node);
+  void load_camera(domCamera &cam, PandaNode *parent);
+  void load_geometry(domGeometry &geom, PandaNode *parent);
+  CPT(InternalName) load_input(GeomVertexArrayFormat *fmt, PTA_LVecBase4f &values, const string &semantic, domSource &src);
+  void load_light(domLight &light, PandaNode *parent);
+};
+
+#include "colladaLoader.I"
+
+#endif

+ 3 - 0
panda/src/collada/collada_composite1.cxx

@@ -0,0 +1,3 @@
+#include "config_collada.cxx"
+#include "load_collada_file.cxx"
+#include "loaderFileTypeDae.cxx"

+ 87 - 0
panda/src/collada/config_collada.cxx

@@ -0,0 +1,87 @@
+// Filename: config_collada.cxx
+// Created by: Xidram (21Dec10)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "config_collada.h"
+
+#include "dconfig.h"
+#include "loaderFileTypeDae.h"
+#include "loaderFileTypeRegistry.h"
+
+ConfigureDef(config_collada);
+NotifyCategoryDef(collada, "");
+
+ConfigVariableBool collada_flatten
+("collada-flatten", false,
+ PRC_DESC("This is normally true to flatten out useless nodes after loading "
+          "a collada file.  Set it false if you want to see the complete "
+          "and true hierarchy as specified in the file (although the "
+          "extra nodes may have a small impact on render performance)."));
+
+ConfigVariableDouble collada_flatten_radius
+("collada-flatten-radius", 0.0,
+ PRC_DESC("This specifies the minimum cull radius in the egg file.  Nodes "
+          "whose bounding volume is smaller than this radius will be "
+          "flattened tighter than nodes larger than this radius, to "
+          "reduce the node count even further.  The idea is that small "
+          "objects will not need to have their individual components "
+          "culled separately, but large environments should.  This allows "
+          "the user to specify what should be considered \"small\".  Set "
+          "it to 0.0 to disable this feature."));
+
+ConfigVariableBool collada_unify
+("collada-unify", true,
+ PRC_DESC("When this is true, then in addition to flattening the scene graph "
+          "nodes, the collada loader will also combine as many Geoms as "
+          "possible within "
+          "a given node into a single Geom.  This has theoretical performance "
+          "benefits, especially on higher-end graphics cards, but it also "
+          "slightly slows down collada loading."));
+
+ConfigVariableBool collada_combine_geoms
+("collada-combine-geoms", false,
+ PRC_DESC("Set this true to combine sibling GeomNodes into a single GeomNode, "
+          "when possible."));
+
+ConfigVariableBool collada_accept_errors
+("collada-accept-errors", true,
+ PRC_DESC("When this is true, certain kinds of recoverable errors (not syntax "
+          "errors) in a collada file will be allowed and ignored when a "
+          "collada file is loaded.  When it is false, only perfectly pristine "
+          "collada files may be loaded."));
+
+ConfigureFn(config_collada) {
+  init_libcollada();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: init_libcollada
+//  Description: Initializes the library. This must be called at
+//               least once before any of the functions or classes in
+//               this library can be used.  Normally it will be
+//               called by the static initializers and need not be
+//               called explicitly, but special cases exist.
+////////////////////////////////////////////////////////////////////
+void
+init_libcollada() {
+  static bool initialized = false;
+  if (initialized) {
+    return;
+  }
+  initialized = true;
+
+  LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_global_ptr();
+
+  reg->register_type(new LoaderFileTypeDae);
+}
+

+ 35 - 0
panda/src/collada/config_collada.h

@@ -0,0 +1,35 @@
+// Filename: config_collada.h
+// Created by: Xidram (21Dec10)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CONFIG_COLLADA_H
+#define CONFIG_COLLADA_H
+
+#include "pandabase.h"
+
+#include "notifyCategoryProxy.h"
+#include "dconfig.h"
+
+
+ConfigureDecl(config_collada, EXPCL_COLLADA, EXPTP_COLLADA);
+NotifyCategoryDecl(collada, EXPCL_COLLADA, EXPTP_COLLADA);
+
+extern EXPCL_COLLADA ConfigVariableBool collada_flatten;
+extern EXPCL_COLLADA ConfigVariableBool collada_unify;
+extern EXPCL_COLLADA ConfigVariableDouble collada_flatten_radius;
+extern EXPCL_COLLADA ConfigVariableBool collada_combine_geoms;
+extern EXPCL_COLLADA ConfigVariableBool collada_accept_errors;
+
+extern EXPCL_COLLADA void init_libcollada();
+
+#endif

+ 96 - 0
panda/src/collada/load_collada_file.cxx

@@ -0,0 +1,96 @@
+// Filename: load_dae_file.cxx
+// Created by:  rdb (16Mar11)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "load_collada_file.h"
+#include "colladaLoader.h"
+#include "config_collada.h"
+#include "sceneGraphReducer.h"
+#include "virtualFileSystem.h"
+#include "config_util.h"
+#include "bamCacheRecord.h"
+
+static PT(PandaNode)
+load_from_loader(ColladaLoader &loader) {
+  loader.build_graph();
+
+  if (loader._error && !collada_accept_errors) {
+    collada_cat.error()
+      << "Errors in collada file.\n";
+    return NULL;
+  }
+
+  if (loader._root != NULL && collada_flatten) {
+    SceneGraphReducer gr;
+
+    int combine_siblings_bits = 0;
+    if (collada_combine_geoms) {
+      combine_siblings_bits |= SceneGraphReducer::CS_geom_node;
+    }
+    if (collada_flatten_radius > 0.0) {
+      combine_siblings_bits |= SceneGraphReducer::CS_within_radius;
+      gr.set_combine_radius(collada_flatten_radius);
+    }
+
+    int num_reduced = gr.flatten(loader._root, combine_siblings_bits);
+    collada_cat.info() << "Flattened " << num_reduced << " nodes.\n";
+
+    if (collada_unify) {
+      // We want to premunge before unifying, since otherwise we risk
+      // needlessly duplicating vertices.
+      if (premunge_data) {
+        gr.premunge(loader._root, RenderState::make_empty());
+      }
+      gr.collect_vertex_data(loader._root);
+      gr.unify(loader._root, true);
+      if (collada_cat.is_debug()) {
+        collada_cat.debug() << "Unified.\n";
+      }
+    }
+  }
+
+  return DCAST(ModelRoot, loader._root);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: load_collada_file
+//  Description: A convenience function.  Loads up the indicated
+//               dae file, and returns the root of a scene graph.
+//               Returns NULL if the file cannot be read for some
+//               reason.  Does not search along the model path for
+//               the filename first.
+////////////////////////////////////////////////////////////////////
+PT(PandaNode)
+load_collada_file(const Filename &filename, CoordinateSystem cs,
+                  BamCacheRecord *record) {
+
+  VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+
+  if (record != (BamCacheRecord *)NULL) {
+    record->add_dependent_file(filename);
+  }
+
+  ColladaLoader loader;
+  loader._filename = filename;
+  loader._cs = cs;
+  loader._record = record;
+
+  collada_cat.info()
+    << "Reading " << filename << "\n";
+
+  if (!loader.read(filename)) {
+    return NULL;
+  }
+
+  return load_from_loader(loader);
+}

+ 39 - 0
panda/src/collada/load_collada_file.h

@@ -0,0 +1,39 @@
+// Filename: load_collada_file.h
+// Created by:  rdb (16Mar11)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef LOAD_COLLADA_FILE_H
+#define LOAD_COLLADA_FILE_H
+
+#include "pandabase.h"
+
+#include "pandaNode.h"
+#include "filename.h"
+#include "coordinateSystem.h"
+
+class BamCacheRecord;
+
+BEGIN_PUBLISH
+////////////////////////////////////////////////////////////////////
+//     Function: load_collada_file
+//  Description: A convenience function; the primary interface to this
+//               package.  Loads up the indicated DAE file, and
+//               returns the root of a scene graph.  Returns NULL if
+//               the file cannot be read for some reason.
+////////////////////////////////////////////////////////////////////
+EXPCL_COLLADA PT(PandaNode)
+load_collada_file(const Filename &filename, CoordinateSystem cs = CS_default,
+                  BamCacheRecord *record = NULL);
+END_PUBLISH
+
+#endif

+ 84 - 0
panda/src/collada/loaderFileTypeDae.cxx

@@ -0,0 +1,84 @@
+// Filename: loaderFileTypeDae.cxx
+// Created by:  rdb (23Aug09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "loaderFileTypeDae.h"
+#include "load_collada_file.h"
+
+TypeHandle LoaderFileTypeDae::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: LoaderFileTypeDae::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+LoaderFileTypeDae::
+LoaderFileTypeDae() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LoaderFileTypeDae::get_name
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+string LoaderFileTypeDae::
+get_name() const {
+  return "COLLADA Digital Asset Exchange";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LoaderFileTypeDae::get_extension
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+string LoaderFileTypeDae::
+get_extension() const {
+  return "dae";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LoaderFileType::get_additional_extensions
+//       Access: Published, Virtual
+//  Description: Returns a space-separated list of extension, in
+//               addition to the one returned by get_extension(), that
+//               are recognized by this loader.
+////////////////////////////////////////////////////////////////////
+string LoaderFileTypeDae::
+get_additional_extensions() const {
+  return "zae";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LoaderFileTypeDae::supports_compressed
+//       Access: Published, Virtual
+//  Description: Returns true if this file type can transparently load
+//               compressed files (with a .pz extension), false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+bool LoaderFileTypeDae::
+supports_compressed() const {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LoaderFileTypeDae::load_file
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+PT(PandaNode) LoaderFileTypeDae::
+load_file(const Filename &path, const LoaderOptions &,
+          BamCacheRecord *record) const {
+  PT(PandaNode) result = load_collada_file(path, CS_default, record);
+  return result;
+}
+

+ 57 - 0
panda/src/collada/loaderFileTypeDae.h

@@ -0,0 +1,57 @@
+// Filename: loaderFileTypeDae.h
+// Created by:  rdb (23Aug09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef LOADERFILETYPEDAE_H
+#define LOADERFILETYPEDAE_H
+
+#include "pandabase.h"
+
+#include "loaderFileType.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : LoaderFileTypeDae
+// Description : This defines the Loader interface to read Dae files.
+////////////////////////////////////////////////////////////////////
+class EXPCL_COLLADA LoaderFileTypeDae : public LoaderFileType {
+public:
+  LoaderFileTypeDae();
+
+  virtual string get_name() const;
+  virtual string get_extension() const;
+  virtual string get_additional_extensions() const;
+  virtual bool supports_compressed() const;
+
+  virtual PT(PandaNode) load_file(const Filename &path, const LoaderOptions &options,
+                                  BamCacheRecord *record) const;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    LoaderFileType::init_type();
+    register_type(_type_handle, "LoaderFileTypeDae",
+                  LoaderFileType::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#endif
+