Browse Source

lots of improvements to the COLLADA loader

rdb 14 years ago
parent
commit
b33ffd9636

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

@@ -6,8 +6,12 @@
 #define COMBINED_SOURCES collada_composite1.cxx
 #define COMBINED_SOURCES collada_composite1.cxx
 
 
 #define SOURCES \
 #define SOURCES \
+  colladaInput.cxx \
+  colladaInput.h colladaInput.I \
   colladaLoader.cxx \
   colladaLoader.cxx \
   colladaLoader.h colladaLoader.I \
   colladaLoader.h colladaLoader.I \
+  colladaPrimitive.cxx \
+  colladaPrimitive.h colladaPrimitive.I \
   config_collada.h \
   config_collada.h \
   load_collada_file.h \
   load_collada_file.h \
   loaderFileTypeDae.h
   loaderFileTypeDae.h

+ 33 - 0
panda/src/collada/colladaInput.I

@@ -0,0 +1,33 @@
+// Filename: colladaInput.I
+// Created by:  rdb (23May11)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaInput::is_vertex_source
+//  Description: Returns true if this has a <vertices> element as
+//               source.
+////////////////////////////////////////////////////////////////////
+bool ColladaInput::
+is_vertex_source() const {
+  return (_semantic == "VERTEX");
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaInput::get_offset
+//  Description: Returns the offset associated with this input.
+////////////////////////////////////////////////////////////////////
+unsigned int ColladaInput::
+get_offset() const {
+  return _offset;
+}

+ 277 - 0
panda/src/collada/colladaInput.cxx

@@ -0,0 +1,277 @@
+// Filename: colladaInput.cxx
+// Created by:  rdb (23May11)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "colladaInput.h"
+#include "string_utils.h"
+#include "geomVertexArrayFormat.h"
+#include "geomVertexWriter.h"
+
+// Collada DOM includes.  No other includes beyond this point.
+#include "pre_collada_include.h"
+#include <dom/domAccessor.h>
+#include <dom/domP.h>
+#include <dom/domSource.h>
+#include <dom/domVertices.h>
+
+#if PANDA_COLLADA_VERSION >= 15
+#include <dom/domInput_local_offset.h>
+#include <dom/domInput_local.h>
+#else
+#include <dom/domInputLocalOffset.h>
+#include <dom/domInputLocal.h>
+#define domList_of_floats domListOfFloats
+#define domList_of_uints domListOfUInts
+#endif
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaInput::Constructor
+//  Description: Pretty obvious what this does.
+////////////////////////////////////////////////////////////////////
+ColladaInput::
+ColladaInput(const string &semantic) :
+  _column_name (NULL),
+  _semantic (semantic),
+  _offset (0),
+  _have_set (false),
+  _set (0) {
+
+  if (semantic == "POSITION") {
+    _column_name = InternalName::get_vertex();
+    _column_contents = GeomEnums::C_point;
+  } else if (semantic == "COLOR") {
+    _column_name = InternalName::get_color();
+    _column_contents = GeomEnums::C_color;
+  } else if (semantic == "NORMAL") {
+    _column_name = InternalName::get_normal();
+    _column_contents = GeomEnums::C_vector;
+  } else if (semantic == "TEXCOORD") {
+    _column_name = InternalName::get_texcoord();
+    _column_contents = GeomEnums::C_texcoord;
+  } else if (semantic == "TEXBINORMAL") {
+    _column_name = InternalName::get_binormal();
+    _column_contents = GeomEnums::C_vector;
+  } else if (semantic == "TEXTANGENT") {
+    _column_name = InternalName::get_tangent();
+    _column_contents = GeomEnums::C_vector;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaInput::Constructor
+//  Description: Pretty obvious what this does.
+////////////////////////////////////////////////////////////////////
+ColladaInput::
+ColladaInput(const string &semantic, unsigned int set) :
+  _column_name (NULL),
+  _semantic (semantic),
+  _offset (0),
+  _have_set (true),
+  _set (set) {
+
+  ostringstream setstr;
+  setstr << _set;
+
+  if (semantic == "POSITION") {
+    _column_name = InternalName::get_vertex();
+    _column_contents = GeomEnums::C_point;
+  } else if (semantic == "COLOR") {
+    _column_name = InternalName::get_color();
+    _column_contents = GeomEnums::C_color;
+  } else if (semantic == "NORMAL") {
+    _column_name = InternalName::get_normal();
+    _column_contents = GeomEnums::C_vector;
+  } else if (semantic == "TEXCOORD") {
+    _column_name = InternalName::get_texcoord_name(setstr.str());
+    _column_contents = GeomEnums::C_texcoord;
+  } else if (semantic == "TEXBINORMAL") {
+    _column_name = InternalName::get_binormal_name(setstr.str());
+    _column_contents = GeomEnums::C_vector;
+  } else if (semantic == "TEXTANGENT") {
+    _column_name = InternalName::get_tangent_name(setstr.str());
+    _column_contents = GeomEnums::C_vector;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaInput::from_dom
+//  Description: Returns the ColladaInput object that represents
+//               the provided DOM input element.
+////////////////////////////////////////////////////////////////////
+ColladaInput *ColladaInput::
+from_dom(domInput_local_offset &input) {
+  // If we already loaded it before, use that.
+  if (input.getUserData() != NULL) {
+    return (ColladaInput *) input.getUserData();
+  }
+
+  ColladaInput *new_input = new ColladaInput(input.getSemantic(), input.getSet());
+  new_input->_offset = input.getOffset();
+
+  // If this has the VERTEX semantic, it points to a <vertices> element.
+  if (new_input->is_vertex_source()) {
+    domVertices *verts = daeSafeCast<domVertices> (input.getSource().getElement());
+    nassertr(verts != NULL, NULL);
+    daeTArray<domInput_localRef> &inputs = verts->getInput_array();
+
+    // Iterate over the <input> elements in <vertices>.
+    for (size_t i = 0; i < inputs.getCount(); ++i) {
+      PT(ColladaInput) vtx_input = ColladaInput::from_dom(*inputs[i]);
+      new_input->_vertex_inputs.push_back(vtx_input);
+    }
+  } else {
+    domSource *source = daeSafeCast<domSource> (input.getSource().getElement());
+    nassertr(source != NULL, NULL);
+    new_input->read_data(*source);
+  }
+
+  return new_input;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaInput::from_dom
+//  Description: Returns the ColladaInput object that represents
+//               the provided DOM input element.
+////////////////////////////////////////////////////////////////////
+ColladaInput *ColladaInput::
+from_dom(domInput_local &input) {
+  // If we already loaded it before, use that.
+  if (input.getUserData() != NULL) {
+    return (ColladaInput *) input.getUserData();
+  }
+
+  ColladaInput *new_input = new ColladaInput(input.getSemantic());
+  new_input->_offset = 0;
+
+  nassertr (!new_input->is_vertex_source(), NULL);
+
+  domSource *source = daeSafeCast<domSource> (input.getSource().getElement());
+  nassertr(source != NULL, NULL);
+  new_input->read_data(*source);
+
+  return new_input;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaInput::make_vertex_columns
+//  Description: Takes a semantic and source URI, and adds a new
+//               column to the format.  If this is a vertex source,
+//               adds all of the inputs from the corresponding
+//               <vertices> element.  Returns the number of
+//               columns added to the format.
+////////////////////////////////////////////////////////////////////
+int ColladaInput::
+make_vertex_columns(GeomVertexArrayFormat *format) const {
+
+  if (is_vertex_source()) {
+    int counter = 0;
+    Inputs::const_iterator it;
+    for (it = _vertex_inputs.begin(); it != _vertex_inputs.end(); ++it) {
+      counter += (*it)->make_vertex_columns(format);
+    }
+    return counter;
+  }
+
+  nassertr(_column_name != NULL, 0);
+
+  format->add_column(_column_name, _num_bound_params, GeomEnums::NT_float32, _column_contents);
+  return 1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaInput::read_data
+//  Description: Reads the data from the source and fills in _data.
+////////////////////////////////////////////////////////////////////
+bool ColladaInput::
+read_data(domSource &source) {
+  _data.clear();
+
+  // Get this, get that
+  domFloat_array* float_array = source.getFloat_array();
+  if (float_array == NULL) {
+    return false;
+  }
+
+  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.
+  _num_bound_params = 0;
+  for (size_t p = 0; p < params.getCount(); ++p) {
+    if (params[p]->getName()) {
+      ++_num_bound_params;
+    }
+  }
+
+  _data.reserve(accessor.getCount());
+
+  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];
+      }
+    }
+    _data.push_back(v);
+    pos += accessor.getStride();
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaInput::write_data
+//  Description: Writes data to the indicated GeomVertexData using
+//               the given indices.
+////////////////////////////////////////////////////////////////////
+void ColladaInput::
+write_data(GeomVertexData *vdata, int start_row, domP &p, unsigned int stride) const {
+  if (is_vertex_source()) {
+    Inputs::const_iterator it;
+    for (it = _vertex_inputs.begin(); it != _vertex_inputs.end(); ++it) {
+      (*it)->write_data(vdata, start_row, p, stride, _offset);
+    }
+
+  } else {
+    write_data(vdata, start_row, p, stride, _offset);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaInput::write_data
+//  Description: Called internally by the other write_data.
+////////////////////////////////////////////////////////////////////
+void ColladaInput::
+write_data(GeomVertexData *vdata, int start_row, domP &p, unsigned int stride, unsigned int offset) const {
+  nassertv(_column_name != NULL);
+  GeomVertexWriter writer (vdata, _column_name);
+  writer.set_row(start_row);
+
+  domList_of_uints &indices = p.getValue();
+
+  // Allocate space for all the rows we're going to write.
+  int min_length = start_row + indices.getCount() / stride;
+  if (vdata->get_num_rows() < min_length) {
+    vdata->unclean_set_num_rows(start_row);
+  }
+
+  for (size_t i = 0; i < indices.getCount(); i += stride) {
+    size_t index = indices[i + offset];
+    writer.add_data4f(_data[index]);
+  }
+}

+ 79 - 0
panda/src/collada/colladaInput.h

@@ -0,0 +1,79 @@
+// Filename: colladaInput.h
+// Created by:  rdb (23May11)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 COLLADAINPUT_H
+#define COLLADAINPUT_H
+
+#include "config_collada.h"
+#include "referenceCount.h"
+#include "pvector.h"
+#include "pta_LVecBase4f.h"
+#include "internalName.h"
+#include "geomEnums.h"
+
+class GeomPrimitive;
+class GeomVertexArrayFormat;
+class GeomVertexData;
+
+#if PANDA_COLLADA_VERSION < 15
+#define domInput_local domInputLocal
+#define domInput_localRef domInputLocalRef
+#define domInput_local_offset domInputLocalOffset
+#define domInput_local_offsetRef domInputLocalOffsetRef
+#endif
+
+class domInput_local;
+class domInput_local_offset;
+class domP;
+class domSource;
+
+////////////////////////////////////////////////////////////////////
+//       Class : ColladaInput
+// Description : Class that deals with COLLADA data sources.
+////////////////////////////////////////////////////////////////////
+class ColladaInput : public ReferenceCount {
+public:
+  static ColladaInput *from_dom(domInput_local_offset &input);
+  static ColladaInput *from_dom(domInput_local &input);
+
+  int make_vertex_columns(GeomVertexArrayFormat *fmt) const;
+  void write_data(GeomVertexData *vdata, int start_row, domP &p, unsigned int stride) const;
+
+  INLINE bool is_vertex_source() const;
+  INLINE unsigned int get_offset() const;
+
+private:
+  ColladaInput(const string &semantic);
+  ColladaInput(const string &semantic, unsigned int set);
+  bool read_data(domSource &source);
+  void write_data(GeomVertexData *vdata, int start_row, domP &p, unsigned int stride, unsigned int offset) const;
+
+  typedef pvector<PT(ColladaInput)> Inputs;
+  Inputs _vertex_inputs;
+  PTA_LVecBase4f _data;
+
+  // Only filled in when appropriate.
+  PT(InternalName) _column_name;
+  GeomEnums::Contents _column_contents;
+
+  unsigned int _num_bound_params;
+  unsigned int _offset;
+  string _semantic;
+  bool _have_set;
+  unsigned int _set;
+};
+
+#include "colladaInput.I"
+
+#endif

+ 153 - 188
panda/src/collada/colladaLoader.cxx

@@ -26,11 +26,10 @@
 #include "pointLight.h"
 #include "pointLight.h"
 #include "spotlight.h"
 #include "spotlight.h"
 
 
-// Ugh, undef some macros that conflict with COLLADA.
-#undef INLINE
-#undef tolower
+#include "colladaPrimitive.h"
 
 
-#include <dae.h>
+// Collada DOM includes.  No other includes beyond this point.
+#include "pre_collada_include.h"
 #include <dom/domCOLLADA.h>
 #include <dom/domCOLLADA.h>
 #include <dom/domNode.h>
 #include <dom/domNode.h>
 #include <dom/domVisual_scene.h>
 #include <dom/domVisual_scene.h>
@@ -43,12 +42,11 @@
 #else
 #else
 #include <dom/domInstanceWithExtra.h>
 #include <dom/domInstanceWithExtra.h>
 #define domInstance_with_extra domInstanceWithExtra
 #define domInstance_with_extra domInstanceWithExtra
-#define domInput_localRef domInputLocalRef
-#define domInput_local_offsetRef domInputLocalOffsetRef
-#define domList_of_uints domListOfUInts
-#define domList_of_floats domListOfFloats
+#define domTargetable_floatRef domTargetableFloatRef
 #endif
 #endif
 
 
+#define TOSTRING(x) (x == NULL ? "" : x)
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: ColladaLoader::Constructor
 //     Function: ColladaLoader::Constructor
 //  Description:
 //  Description:
@@ -128,7 +126,7 @@ load_visual_scene(domVisual_scene& scene, PandaNode *parent) {
     return;
     return;
   }
   }
 
 
-  PT(PandaNode) pnode = new PandaNode(scene.getName());
+  PT(PandaNode) pnode = new PandaNode(TOSTRING(scene.getName()));
   scene.setUserData((void *) pnode);
   scene.setUserData((void *) pnode);
   parent->add_child(pnode);
   parent->add_child(pnode);
 
 
@@ -149,7 +147,7 @@ load_visual_scene(domVisual_scene& scene, PandaNode *parent) {
     CPT(LightAttrib) lattr = DCAST(LightAttrib, LightAttrib::make());
     CPT(LightAttrib) lattr = DCAST(LightAttrib, LightAttrib::make());
     pvector<LightNode*>::iterator it;
     pvector<LightNode*>::iterator it;
     for (it = _lights.begin(); it != _lights.end(); ++it) {
     for (it = _lights.begin(); it != _lights.end(); ++it) {
-      lattr = DCAST(LightAttrib, lattr->add_light(*it));
+      lattr = DCAST(LightAttrib, lattr->add_on_light(*it));
     }
     }
     pnode->set_state(RenderState::make(lattr));
     pnode->set_state(RenderState::make(lattr));
 
 
@@ -171,7 +169,7 @@ load_node(domNode& node, PandaNode *parent) {
 
 
   // Create the node.
   // Create the node.
   PT(PandaNode) pnode;
   PT(PandaNode) pnode;
-  pnode = new PandaNode(node.getName());
+  pnode = new PandaNode(TOSTRING(node.getName()));
   node.setUserData((void *) pnode);
   node.setUserData((void *) pnode);
   parent->add_child(pnode);
   parent->add_child(pnode);
 
 
@@ -179,8 +177,8 @@ load_node(domNode& node, PandaNode *parent) {
   LMatrix4f transform (LMatrix4f::ident_mat());
   LMatrix4f transform (LMatrix4f::ident_mat());
 
 
   daeElementRefArray &elements = node.getContents();
   daeElementRefArray &elements = node.getContents();
-  for (size_t i = elements.getCount() - 1; i > 0; --i) {
-    daeElementRef &elem = elements[i];
+  for (size_t i = elements.getCount(); i > 0; --i) {
+    daeElementRef &elem = elements[i - 1];
 
 
     switch (elem->getElementType()) {
     switch (elem->getElementType()) {
       case COLLADA_TYPE::LOOKAT: {
       case COLLADA_TYPE::LOOKAT: {
@@ -221,7 +219,7 @@ load_node(domNode& node, PandaNode *parent) {
         break;
         break;
       }
       }
       case COLLADA_TYPE::SKEW:
       case COLLADA_TYPE::SKEW:
-        // FIXME: implement skew
+        //FIXME: implement skew
         collada_cat.error() << "<skew> not supported yet\n";
         collada_cat.error() << "<skew> not supported yet\n";
         break;
         break;
       case COLLADA_TYPE::TRANSLATE: {
       case COLLADA_TYPE::TRANSLATE: {
@@ -246,11 +244,22 @@ load_node(domNode& node, PandaNode *parent) {
     load_camera(*target, pnode);
     load_camera(*target, pnode);
   }
   }
 
 
+  // See if this node instantiates any controllers.
+  domInstance_controller_Array &ctrlinst = node.getInstance_controller_array();
+  for (size_t i = 0; i < ctrlinst.getCount(); ++i) {
+    domController* target = daeSafeCast<domController> (ctrlinst[i]->getUrl().getElement());
+    //TODO: implement controllers.  For now, let's just read the geometry
+    if (target->getSkin() != NULL) {
+      domGeometry* geom = daeSafeCast<domGeometry> (target->getSkin()->getSource().getElement());
+      //TODO: bind_material stuff
+      load_geometry(*geom, pnode);
+    }
+  }
+
   // See if this node instantiates any geoms.
   // See if this node instantiates any geoms.
   domInstance_geometry_Array &ginst = node.getInstance_geometry_array();
   domInstance_geometry_Array &ginst = node.getInstance_geometry_array();
   for (size_t i = 0; i < ginst.getCount(); ++i) {
   for (size_t i = 0; i < ginst.getCount(); ++i) {
-    domGeometry* target = daeSafeCast<domGeometry> (ginst[i]->getUrl().getElement());
-    load_geometry(*target, pnode);
+    load_instance_geometry(*ginst[i], pnode);
   }
   }
 
 
   // See if this node instantiates any lights.
   // See if this node instantiates any lights.
@@ -327,6 +336,26 @@ load_camera(domCamera &cam, PandaNode *parent) {
   //TODO
   //TODO
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaLoader::load_instance_geometry
+//  Description: Loads a COLLADA <instance_geometry> as a PandaNode
+//               object.
+////////////////////////////////////////////////////////////////////
+void ColladaLoader::
+load_instance_geometry(domInstance_geometry &inst, PandaNode *parent) {
+  domGeometry* geom = daeSafeCast<domGeometry> (inst.getUrl().getElement());
+  nassertv(geom != NULL);
+
+  domBind_materialRef bind_mat = inst.getBind_material();
+  if (bind_mat == NULL) {
+    load_geometry(*geom, parent);
+    return;
+  }
+
+  domInstance_material_Array &mat_instances = bind_mat->getTechnique_common()->getInstance_material_array();
+  load_geometry(*geom, parent);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: ColladaLoader::load_geometry
 //     Function: ColladaLoader::load_geometry
 //  Description: Loads a COLLADA <geometry> as a GeomNode object.
 //  Description: Loads a COLLADA <geometry> as a GeomNode object.
@@ -346,105 +375,67 @@ load_geometry(domGeometry &geom, PandaNode *parent) {
   }
   }
 
 
   // Create the node.
   // Create the node.
-  PT(GeomNode) gnode = new GeomNode(geom.getName());
+  PT(GeomNode) gnode = new GeomNode(TOSTRING(geom.getName()));
   geom.setUserData((void *) gnode);
   geom.setUserData((void *) gnode);
   parent->add_child(gnode);
   parent->add_child(gnode);
 
 
-  // First handle the <vertices> element.
-  domVertices &vertices = *mesh->getVertices();
-  daeTArray<domInput_localRef> &vtx_inputs = vertices.getInput_array();
+  //TODO: support other than just triangles.
+  domLines_Array &lines_array = mesh->getLines_array();
+  for (size_t i = 0; i < lines_array.getCount(); ++i) {
+    PT(ColladaPrimitive) prim = ColladaPrimitive::from_dom(*lines_array[i]);
+    if (prim != NULL) {
+      gnode->add_geom(prim->get_geom());
+    }
+  }
 
 
-  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()];
+  domLinestrips_Array &linestrips_array = mesh->getLinestrips_array();
+  for (size_t i = 0; i < linestrips_array.getCount(); ++i) {
+    PT(ColladaPrimitive) prim = ColladaPrimitive::from_dom(*linestrips_array[i]);
+    if (prim != NULL) {
+      gnode->add_geom(prim->get_geom());
+    }
+  }
 
 
-  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;
+  domPolygons_Array &polygons_array = mesh->getPolygons_array();
+  for (size_t i = 0; i < polygons_array.getCount(); ++i) {
+    PT(ColladaPrimitive) prim = ColladaPrimitive::from_dom(*polygons_array[i]);
+    if (prim != NULL) {
+      gnode->add_geom(prim->get_geom());
+    }
+  }
 
 
-    vtx_names[i] = load_input(vtx_aformat, vtx_values[i], semantic, *source);
+  domPolylist_Array &polylist_array = mesh->getPolylist_array();
+  for (size_t i = 0; i < polylist_array.getCount(); ++i) {
+    PT(ColladaPrimitive) prim = ColladaPrimitive::from_dom(*polylist_array[i]);
+    if (prim != NULL) {
+      gnode->add_geom(prim->get_geom());
+    }
   }
   }
 
 
-  //TODO: support other than just triangles.
   domTriangles_Array &triangles_array = mesh->getTriangles_array();
   domTriangles_Array &triangles_array = mesh->getTriangles_array();
   for (size_t i = 0; i < triangles_array.getCount(); ++i) {
   for (size_t i = 0; i < triangles_array.getCount(); ++i) {
-    domTriangles &tris = *triangles_array[i];
-
-    if (tris.getP() == NULL) {
-      continue;
+    PT(ColladaPrimitive) prim = ColladaPrimitive::from_dom(*triangles_array[i]);
+    if (prim != NULL) {
+      gnode->add_geom(prim->get_geom());
     }
     }
-    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, inputs[i]->getSet());
+  }
 
 
-      if (inputs[in]->getOffset() >= stride) {
-        stride = inputs[in]->getOffset() + 1;
-      }
+  domTrifans_Array &trifans_array = mesh->getTrifans_array();
+  for (size_t i = 0; i < trifans_array.getCount(); ++i) {
+    PT(ColladaPrimitive) prim = ColladaPrimitive::from_dom(*trifans_array[i]);
+    if (prim != NULL) {
+      gnode->add_geom(prim->get_geom());
     }
     }
+  }
 
 
-    // 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]);
-          }
-        }
-      }
+  domTristrips_Array &tristrips_array = mesh->getTristrips_array();
+  for (size_t i = 0; i < tristrips_array.getCount(); ++i) {
+    PT(ColladaPrimitive) prim = ColladaPrimitive::from_dom(*tristrips_array[i]);
+    if (prim != NULL) {
+      gnode->add_geom(prim->get_geom());
     }
     }
-
-    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.
   // Load in any tags.
   domExtra_Array &extras = geom.getExtra_array();
   domExtra_Array &extras = geom.getExtra_array();
   for (size_t i = 0; i < extras.getCount(); ++i) {
   for (size_t i = 0; i < extras.getCount(); ++i) {
@@ -452,80 +443,6 @@ load_geometry(domGeometry &geom, PandaNode *parent) {
   }
   }
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     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, unsigned int set) {
-
-  PT(InternalName) cname;
-  GeomEnums::Contents contents = GeomEnums::C_other;
-
-  ostringstream setstr;
-  setstr << set;
-
-  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 if (semantic == "TEXCOORD") {
-    cname = InternalName::get_texcoord_name(setstr.str());
-    contents = GeomEnums::C_texcoord;
-  } else if (semantic == "TEXBINORMAL") {
-    cname = InternalName::get_binormal_name(setstr.str());
-    contents = GeomEnums::C_vector;
-  } else if (semantic == "TEXTANGENT") {
-    cname = InternalName::get_tangent_name(setstr.str());
-    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
 //     Function: ColladaLoader::load_light
 //  Description: Loads a COLLADA <light> as a LightNode object.
 //  Description: Loads a COLLADA <light> as a LightNode object.
@@ -541,18 +458,20 @@ load_light(domLight &light, PandaNode *parent) {
   PT(LightNode) lnode;
   PT(LightNode) lnode;
   domLight::domTechnique_common &tc = *light.getTechnique_common();
   domLight::domTechnique_common &tc = *light.getTechnique_common();
 
 
+  // Check for an ambient light.
   domLight::domTechnique_common::domAmbientRef ambient = tc.getAmbient();
   domLight::domTechnique_common::domAmbientRef ambient = tc.getAmbient();
   if (ambient != NULL) {
   if (ambient != NULL) {
-    PT(AmbientLight) alight = new AmbientLight(light.getName());
+    PT(AmbientLight) alight = new AmbientLight(TOSTRING(light.getName()));
     lnode = DCAST(LightNode, alight);
     lnode = DCAST(LightNode, alight);
 
 
     domFloat3 &color = ambient->getColor()->getValue();
     domFloat3 &color = ambient->getColor()->getValue();
     alight->set_color(Colorf(color[0], color[1], color[2], 1.0));
     alight->set_color(Colorf(color[0], color[1], color[2], 1.0));
   }
   }
 
 
+  // Check for a directional light.
   domLight::domTechnique_common::domDirectionalRef directional = tc.getDirectional();
   domLight::domTechnique_common::domDirectionalRef directional = tc.getDirectional();
   if (directional != NULL) {
   if (directional != NULL) {
-    PT(DirectionalLight) dlight = new DirectionalLight(light.getName());
+    PT(DirectionalLight) dlight = new DirectionalLight(TOSTRING(light.getName()));
     lnode = DCAST(LightNode, dlight);
     lnode = DCAST(LightNode, dlight);
 
 
     domFloat3 &color = directional->getColor()->getValue();
     domFloat3 &color = directional->getColor()->getValue();
@@ -560,34 +479,70 @@ load_light(domLight &light, PandaNode *parent) {
     dlight->set_direction(LVector3f(0, 0, -1));
     dlight->set_direction(LVector3f(0, 0, -1));
   }
   }
 
 
+  // Check for a point light.
   domLight::domTechnique_common::domPointRef point = tc.getPoint();
   domLight::domTechnique_common::domPointRef point = tc.getPoint();
   if (point != NULL) {
   if (point != NULL) {
-    PT(PointLight) plight = new PointLight(light.getName());
+    PT(PointLight) plight = new PointLight(TOSTRING(light.getName()));
     lnode = DCAST(LightNode, plight);
     lnode = DCAST(LightNode, plight);
 
 
     domFloat3 &color = point->getColor()->getValue();
     domFloat3 &color = point->getColor()->getValue();
     plight->set_color(Colorf(color[0], color[1], color[2], 1.0));
     plight->set_color(Colorf(color[0], color[1], color[2], 1.0));
-    plight->set_attenuation(LVecBase3f(
-      point->getConstant_attenuation()->getValue(),
-      point->getLinear_attenuation()->getValue(),
-      point->getQuadratic_attenuation()->getValue()
-    ));
+
+    LVecBase3f atten (1.0f, 0.0f, 0.0f);
+    domTargetable_floatRef fval = point->getConstant_attenuation();
+    if (fval != NULL) {
+      atten[0] = fval->getValue();
+    }
+    fval = point->getLinear_attenuation();
+    if (fval != NULL) {
+      atten[1] = fval->getValue();
+    }
+    fval = point->getQuadratic_attenuation();
+    if (fval != NULL) {
+      atten[2] = fval->getValue();
+    }
+
+    plight->set_attenuation(atten);
   }
   }
 
 
+  // Check for a spot light.
   domLight::domTechnique_common::domSpotRef spot = tc.getSpot();
   domLight::domTechnique_common::domSpotRef spot = tc.getSpot();
   if (spot != NULL) {
   if (spot != NULL) {
-    PT(Spotlight) slight = new Spotlight(light.getName());
+    PT(Spotlight) slight = new Spotlight(TOSTRING(light.getName()));
     lnode = DCAST(LightNode, slight);
     lnode = DCAST(LightNode, slight);
 
 
     domFloat3 &color = spot->getColor()->getValue();
     domFloat3 &color = spot->getColor()->getValue();
     slight->set_color(Colorf(color[0], color[1], color[2], 1.0));
     slight->set_color(Colorf(color[0], color[1], color[2], 1.0));
-    slight->set_attenuation(LVecBase3f(
-      spot->getConstant_attenuation()->getValue(),
-      spot->getLinear_attenuation()->getValue(),
-      spot->getQuadratic_attenuation()->getValue()
-    ));
-    slight->get_lens()->set_fov(spot->getFalloff_angle()->getValue());
-    slight->set_exponent(spot->getFalloff_exponent()->getValue());
+
+    LVecBase3f atten (1.0f, 0.0f, 0.0f);
+    domTargetable_floatRef fval = spot->getConstant_attenuation();
+    if (fval != NULL) {
+      atten[0] = fval->getValue();
+    }
+    fval = spot->getLinear_attenuation();
+    if (fval != NULL) {
+      atten[1] = fval->getValue();
+    }
+    fval = spot->getQuadratic_attenuation();
+    if (fval != NULL) {
+      atten[2] = fval->getValue();
+    }
+
+    slight->set_attenuation(atten);
+
+    fval = spot->getFalloff_angle();
+    if (fval != NULL) {
+      slight->get_lens()->set_fov(fval->getValue());
+    } else {
+      slight->get_lens()->set_fov(180.0f);
+    }
+
+    fval = spot->getFalloff_exponent();
+    if (fval != NULL) {
+      slight->set_exponent(fval->getValue());
+    } else {
+      slight->set_exponent(0.0f);
+    }
   }
   }
 
 
   if (lnode == NULL) {
   if (lnode == NULL) {
@@ -603,3 +558,13 @@ load_light(domLight &light, PandaNode *parent) {
     load_tags(*extras[i], lnode);
     load_tags(*extras[i], lnode);
   }
   }
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaLoader::load_material
+//  Description: Loads a COLLADA <bind_material> as a RenderState
+//               object.
+////////////////////////////////////////////////////////////////////
+void ColladaLoader::
+load_material(domBind_material &bind_mat, PandaNode *node) {
+
+}

+ 4 - 1
panda/src/collada/colladaLoader.h

@@ -26,11 +26,13 @@
 class BamCacheRecord;
 class BamCacheRecord;
 class LightNode;
 class LightNode;
 
 
+class domBind_material;
 class domCOLLADA;
 class domCOLLADA;
 class domNode;
 class domNode;
 class domVisual_scene;
 class domVisual_scene;
 class domExtra;
 class domExtra;
 class domGeometry;
 class domGeometry;
+class domInstance_geometry;
 class domLight;
 class domLight;
 class domCamera;
 class domCamera;
 class domSource;
 class domSource;
@@ -64,9 +66,10 @@ private:
   void load_node(domNode &node, PandaNode *parent);
   void load_node(domNode &node, PandaNode *parent);
   void load_tags(domExtra &extra, PandaNode *node);
   void load_tags(domExtra &extra, PandaNode *node);
   void load_camera(domCamera &cam, PandaNode *parent);
   void load_camera(domCamera &cam, PandaNode *parent);
+  void load_instance_geometry(domInstance_geometry &inst, PandaNode *parent);
   void load_geometry(domGeometry &geom, PandaNode *parent);
   void load_geometry(domGeometry &geom, PandaNode *parent);
-  CPT(InternalName) load_input(GeomVertexArrayFormat *fmt, PTA_LVecBase4f &values, const string &semantic, domSource &src, unsigned int set=0);
   void load_light(domLight &light, PandaNode *parent);
   void load_light(domLight &light, PandaNode *parent);
+  void load_material(domBind_material &bind_mat, PandaNode *node);
 };
 };
 
 
 #include "colladaLoader.I"
 #include "colladaLoader.I"

+ 35 - 0
panda/src/collada/colladaPrimitive.I

@@ -0,0 +1,35 @@
+// Filename: colladaPrimitive.I
+// Created by:  rdb (23May11)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaPrimitive::add_input
+//  Description: Adds a new ColladaInput to this primitive.
+////////////////////////////////////////////////////////////////////
+INLINE void ColladaPrimitive::
+add_input(ColladaInput *input) {
+  if (input->get_offset() >= _stride) {
+    _stride = input->get_offset() + 1;
+  }
+  _inputs.push_back(input);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaPrimitive::get_geom
+//  Description: Returns the Goem associated with this primitive.
+////////////////////////////////////////////////////////////////////
+INLINE PT(Geom) ColladaPrimitive::
+get_geom() const {
+  return _geom;
+}

+ 298 - 0
panda/src/collada/colladaPrimitive.cxx

@@ -0,0 +1,298 @@
+// Filename: colladaPrimitive.cxx
+// Created by:  rdb (23May11)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "colladaPrimitive.h"
+#include "geomLines.h"
+#include "geomLinestrips.h"
+#include "geomTriangles.h"
+#include "geomTrifans.h"
+#include "geomTristrips.h"
+
+// Collada DOM includes.  No other includes beyond this point.
+#include "pre_collada_include.h"
+#include <dom/domLines.h>
+#include <dom/domLinestrips.h>
+#include <dom/domPolygons.h>
+#include <dom/domPolylist.h>
+#include <dom/domTriangles.h>
+#include <dom/domTrifans.h>
+#include <dom/domTristrips.h>
+
+#if PANDA_COLLADA_VERSION < 15
+#define domInput_local_offsetRef domInputLocalOffsetRef
+#endif
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaPrimitive::Constructor
+//  Description: Why do I even bother documenting the simplest of
+//               constructors?  A private one at that.
+////////////////////////////////////////////////////////////////////
+ColladaPrimitive::
+ColladaPrimitive(GeomPrimitive *prim, daeTArray<domInput_local_offsetRef> &inputs)
+  : _stride (1), _gprim (prim) {
+
+  PT(GeomVertexArrayFormat) aformat = new GeomVertexArrayFormat;
+
+  // Add the inputs one by one.
+  for (size_t in = 0; in < inputs.getCount(); ++in) {
+    PT(ColladaInput) input = ColladaInput::from_dom(*inputs[in]);
+    add_input(input);
+
+    input->make_vertex_columns(aformat);
+  }
+
+  // Create the vertex data.
+  PT(GeomVertexFormat) format = new GeomVertexFormat();
+  format->add_array(aformat);
+  _vdata = new GeomVertexData("", GeomVertexFormat::register_format(format), GeomEnums::UH_static);
+  _geom = new Geom(_vdata);
+  _geom->add_primitive(_gprim);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaPrimitive::from_dom
+//  Description: Returns the ColladaPrimitive object that represents
+//               the provided DOM input element.
+////////////////////////////////////////////////////////////////////
+ColladaPrimitive *ColladaPrimitive::
+from_dom(domLines &prim) {
+  // If we already loaded it before, use that.
+  if (prim.getUserData() != NULL) {
+    return (ColladaPrimitive *) prim.getUserData();
+  }
+
+  ColladaPrimitive *new_prim =
+    new ColladaPrimitive(new GeomLines(GeomEnums::UH_static),
+                         prim.getInput_array());
+
+  prim.setUserData(new_prim);
+
+  domPRef p = prim.getP();
+  if (p != NULL) {
+    new_prim->load_primitive(*p);
+  }
+
+  return new_prim;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaPrimitive::from_dom
+//  Description: Returns the ColladaPrimitive object that represents
+//               the provided DOM input element.
+////////////////////////////////////////////////////////////////////
+ColladaPrimitive *ColladaPrimitive::
+from_dom(domLinestrips &prim) {
+  // If we already loaded it before, use that.
+  if (prim.getUserData() != NULL) {
+    return (ColladaPrimitive *) prim.getUserData();
+  }
+
+  ColladaPrimitive *new_prim =
+    new ColladaPrimitive(new GeomLinestrips(GeomEnums::UH_static),
+                         prim.getInput_array());
+
+  prim.setUserData(new_prim);
+
+  new_prim->load_primitives(prim.getP_array());
+
+  return new_prim;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaPrimitive::from_dom
+//  Description: Returns the ColladaPrimitive object that represents
+//               the provided DOM input element.
+////////////////////////////////////////////////////////////////////
+ColladaPrimitive *ColladaPrimitive::
+from_dom(domPolygons &prim) {
+  // If we already loaded it before, use that.
+  if (prim.getUserData() != NULL) {
+    return (ColladaPrimitive *) prim.getUserData();
+  }
+
+  // We use trifans to represent polygons, seems to be easiest.
+  // I tried using tristrips instead, but for some reason,
+  // this resulted in a few flipped polygons.  Weird.
+  ColladaPrimitive *new_prim =
+    new ColladaPrimitive(new GeomTrifans(GeomEnums::UH_static),
+                         prim.getInput_array());
+
+  prim.setUserData(new_prim);
+
+  new_prim->load_primitives(prim.getP_array());
+
+  if (prim.getPh_array().getCount() > 0) {
+    collada_cat.error()
+      << "Polygons with holes are not supported!\n";
+  }
+
+  return new_prim;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaPrimitive::from_dom
+//  Description: Returns the ColladaPrimitive object that represents
+//               the provided DOM input element.
+////////////////////////////////////////////////////////////////////
+ColladaPrimitive *ColladaPrimitive::
+from_dom(domPolylist &prim) {
+  // If we already loaded it before, use that.
+  if (prim.getUserData() != NULL) {
+    return (ColladaPrimitive *) prim.getUserData();
+  }
+
+  // We use trifans to represent polygons, seems to be easiest.
+  // I tried using tristrips instead, but for some reason,
+  // this resulted in a few flipped polygons.  Weird.
+  PT(GeomPrimitive) gprim = new GeomTrifans(GeomEnums::UH_static);
+
+  ColladaPrimitive *new_prim =
+    new ColladaPrimitive(gprim, prim.getInput_array());
+
+  prim.setUserData(new_prim);
+
+  domPRef p = prim.getP();
+  domPolylist::domVcountRef vcounts = prim.getVcount();
+  if (p == NULL || vcounts == NULL) {
+    return new_prim;
+  }
+
+  new_prim->write_data(new_prim->_vdata, 0, *p);
+
+  daeTArray<domUint> &values = vcounts->getValue();
+  for (size_t i = 0; i < values.getCount(); ++i) {
+    unsigned int vcount = values[i];
+    gprim->add_next_vertices(vcount);
+    gprim->close_primitive();
+  }
+
+  return new_prim;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaPrimitive::from_dom
+//  Description: Returns the ColladaPrimitive object that represents
+//               the provided DOM input element.
+////////////////////////////////////////////////////////////////////
+ColladaPrimitive *ColladaPrimitive::
+from_dom(domTriangles &prim) {
+  // If we already loaded it before, use that.
+  if (prim.getUserData() != NULL) {
+    return (ColladaPrimitive *) prim.getUserData();
+  }
+
+  ColladaPrimitive *new_prim =
+    new ColladaPrimitive(new GeomTriangles(GeomEnums::UH_static),
+                         prim.getInput_array());
+
+  prim.setUserData(new_prim);
+
+  domPRef p = prim.getP();
+  if (p != NULL) {
+    new_prim->load_primitive(*p);
+  }
+
+  return new_prim;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaPrimitive::from_dom
+//  Description: Returns the ColladaPrimitive object that represents
+//               the provided DOM input element.
+////////////////////////////////////////////////////////////////////
+ColladaPrimitive *ColladaPrimitive::
+from_dom(domTrifans &prim) {
+  // If we already loaded it before, use that.
+  if (prim.getUserData() != NULL) {
+    return (ColladaPrimitive *) prim.getUserData();
+  }
+
+  ColladaPrimitive *new_prim =
+    new ColladaPrimitive(new GeomTrifans(GeomEnums::UH_static),
+                         prim.getInput_array());
+
+  prim.setUserData(new_prim);
+
+  new_prim->load_primitives(prim.getP_array());
+
+  return new_prim;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaPrimitive::from_dom
+//  Description: Returns the ColladaPrimitive object that represents
+//               the provided DOM input element.
+////////////////////////////////////////////////////////////////////
+ColladaPrimitive *ColladaPrimitive::
+from_dom(domTristrips &prim) {
+  // If we already loaded it before, use that.
+  if (prim.getUserData() != NULL) {
+    return (ColladaPrimitive *) prim.getUserData();
+  }
+
+  ColladaPrimitive *new_prim =
+    new ColladaPrimitive(new GeomTristrips(GeomEnums::UH_static),
+                         prim.getInput_array());
+
+  prim.setUserData(new_prim);
+
+  new_prim->load_primitives(prim.getP_array());
+
+  return new_prim;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaPrimitive::write_data
+//  Description: Writes the vertex data to the GeomVertexData.
+//               Returns the number of rows written.
+////////////////////////////////////////////////////////////////////
+unsigned int ColladaPrimitive::
+write_data(GeomVertexData *vdata, int start_row, domP &p) {
+  unsigned int num_vertices = p.getValue().getCount() / _stride;
+
+  Inputs::iterator it;
+  for (it = _inputs.begin(); it != _inputs.end(); ++it) {
+    (*it)->write_data(vdata, start_row, p, _stride);
+  }
+
+  return num_vertices;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaPrimitive::load_primitive
+//  Description: Adds the given indices to the primitive, and
+//               writes the relevant data to the geom.
+////////////////////////////////////////////////////////////////////
+void ColladaPrimitive::
+load_primitive(domP &p) {
+  _gprim->add_next_vertices(write_data(_vdata, 0, p));
+  _gprim->close_primitive();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColladaPrimitive::load_primitives
+//  Description: Adds the given indices to the primitive, and
+//               writes the relevant data to the geom.
+////////////////////////////////////////////////////////////////////
+void ColladaPrimitive::
+load_primitives(domP_Array &p_array) {
+  int start_row = 0;
+
+  for (size_t i = 0; i < p_array.getCount(); ++i) {
+    unsigned int num_vertices = write_data(_vdata, start_row, *p_array[i]);
+    _gprim->add_next_vertices(num_vertices);
+    _gprim->close_primitive();
+    start_row += num_vertices;
+  }
+}

+ 71 - 0
panda/src/collada/colladaPrimitive.h

@@ -0,0 +1,71 @@
+// Filename: colladaPrimitive.h
+// Created by:  rdb (23May11)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 COLLADAPRIMITIVE_H
+#define COLLADAPRIMITIVE_H
+
+#include "config_collada.h"
+#include "referenceCount.h"
+#include "geomVertexData.h"
+#include "geom.h"
+#include "geomPrimitive.h"
+
+#include "colladaInput.h"
+
+class domP;
+class domLines;
+class domLinestrips;
+class domPolygons;
+class domPolylist;
+class domTriangles;
+class domTrifans;
+class domTristrips;
+
+////////////////////////////////////////////////////////////////////
+//       Class : ColladaPrimitive
+// Description : Class that deals with COLLADA primitive structures,
+//               such as <triangles> and <polylist>.
+////////////////////////////////////////////////////////////////////
+class ColladaPrimitive : public ReferenceCount {
+public:
+  static ColladaPrimitive *from_dom(domLines &lines);
+  static ColladaPrimitive *from_dom(domLinestrips &linestrips);
+  static ColladaPrimitive *from_dom(domPolygons &polygons);
+  static ColladaPrimitive *from_dom(domPolylist &polylist);
+  static ColladaPrimitive *from_dom(domTriangles &triangles);
+  static ColladaPrimitive *from_dom(domTrifans &trifans);
+  static ColladaPrimitive *from_dom(domTristrips &tristrips);
+
+  unsigned int write_data(GeomVertexData *vdata, int start_row, domP &p);
+
+  INLINE PT(Geom) get_geom() const;
+
+private:
+  ColladaPrimitive(GeomPrimitive *prim, daeTArray<daeSmartRef<domInput_local_offset> > &inputs);
+  void load_primitive(domP &p);
+  void load_primitives(daeTArray<daeSmartRef<domP> > &p_array);
+  INLINE void add_input(ColladaInput *input);
+
+  typedef pvector<PT(ColladaInput)> Inputs;
+  Inputs _inputs;
+
+  unsigned int _stride;
+  PT(Geom) _geom;
+  PT(GeomVertexData) _vdata;
+  PT(GeomPrimitive) _gprim;
+};
+
+#include "colladaPrimitive.I"
+
+#endif

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

@@ -20,6 +20,8 @@
 #include "notifyCategoryProxy.h"
 #include "notifyCategoryProxy.h"
 #include "dconfig.h"
 #include "dconfig.h"
 
 
+template<class T> class daeTArray;
+template<class T> class daeSmartRef;
 
 
 ConfigureDecl(config_collada, EXPCL_COLLADA, EXPTP_COLLADA);
 ConfigureDecl(config_collada, EXPCL_COLLADA, EXPTP_COLLADA);
 NotifyCategoryDecl(collada, EXPCL_COLLADA, EXPTP_COLLADA);
 NotifyCategoryDecl(collada, EXPCL_COLLADA, EXPTP_COLLADA);

+ 7 - 1
panda/src/collada/loaderFileTypeDae.cxx

@@ -33,7 +33,13 @@ LoaderFileTypeDae() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 string LoaderFileTypeDae::
 string LoaderFileTypeDae::
 get_name() const {
 get_name() const {
-  return "COLLADA Digital Asset Exchange";
+#if PANDA_COLLADA_VERSION == 14
+  return "COLLADA 1.4";
+#elif PANDA_COLLADA_VERSION == 15
+  return "COLLADA 1.5";
+#else
+  return "COLLADA";
+#endif
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 29 - 0
panda/src/collada/pre_collada_include.h

@@ -0,0 +1,29 @@
+// Filename: pre_collada_include.h
+// Created by:  rdb (23May11)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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."
+//
+////////////////////////////////////////////////////////////////////
+
+// This header file should be included before including any of the
+// COLLADA DOM headers.  It should only be included in a .cxx file
+// (not in a header file) and no Panda3D headers should be included
+// after the pre_collada_include.h include.
+
+#ifdef PRE_COLLADA_INCLUDE_H
+#error Don't include any Panda headers after including pre_collada_include.h!
+#endif
+#define PRE_COLLADA_INCLUDE_H
+
+// Undef some macros that conflict with COLLADA.
+#undef INLINE
+#undef tolower
+
+#include <dae.h>