diff --git a/panda/src/collada/Sources.pp b/panda/src/collada/Sources.pp index 7668a21a7f..34c3e1a42e 100644 --- a/panda/src/collada/Sources.pp +++ b/panda/src/collada/Sources.pp @@ -6,8 +6,12 @@ #define COMBINED_SOURCES collada_composite1.cxx #define SOURCES \ + colladaInput.cxx \ + colladaInput.h colladaInput.I \ colladaLoader.cxx \ colladaLoader.h colladaLoader.I \ + colladaPrimitive.cxx \ + colladaPrimitive.h colladaPrimitive.I \ config_collada.h \ load_collada_file.h \ loaderFileTypeDae.h diff --git a/panda/src/collada/colladaInput.I b/panda/src/collada/colladaInput.I new file mode 100644 index 0000000000..1b0873844f --- /dev/null +++ b/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 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; +} diff --git a/panda/src/collada/colladaInput.cxx b/panda/src/collada/colladaInput.cxx new file mode 100644 index 0000000000..a52a1b1255 --- /dev/null +++ b/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 +#include +#include +#include + +#if PANDA_COLLADA_VERSION >= 15 +#include +#include +#else +#include +#include +#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 element. + if (new_input->is_vertex_source()) { + domVertices *verts = daeSafeCast (input.getSource().getElement()); + nassertr(verts != NULL, NULL); + daeTArray &inputs = verts->getInput_array(); + + // Iterate over the elements in . + 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 (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 (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 +// 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 ¶ms = 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]); + } +} diff --git a/panda/src/collada/colladaInput.h b/panda/src/collada/colladaInput.h new file mode 100644 index 0000000000..fa0813909d --- /dev/null +++ b/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 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 diff --git a/panda/src/collada/colladaLoader.cxx b/panda/src/collada/colladaLoader.cxx index 37b69abb21..90ee9d7de6 100644 --- a/panda/src/collada/colladaLoader.cxx +++ b/panda/src/collada/colladaLoader.cxx @@ -26,11 +26,10 @@ #include "pointLight.h" #include "spotlight.h" -// Ugh, undef some macros that conflict with COLLADA. -#undef INLINE -#undef tolower +#include "colladaPrimitive.h" -#include +// Collada DOM includes. No other includes beyond this point. +#include "pre_collada_include.h" #include #include #include @@ -43,12 +42,11 @@ #else #include #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 +#define TOSTRING(x) (x == NULL ? "" : x) + //////////////////////////////////////////////////////////////////// // Function: ColladaLoader::Constructor // Description: @@ -128,7 +126,7 @@ load_visual_scene(domVisual_scene& scene, PandaNode *parent) { return; } - PT(PandaNode) pnode = new PandaNode(scene.getName()); + PT(PandaNode) pnode = new PandaNode(TOSTRING(scene.getName())); scene.setUserData((void *) pnode); parent->add_child(pnode); @@ -149,7 +147,7 @@ load_visual_scene(domVisual_scene& scene, PandaNode *parent) { CPT(LightAttrib) lattr = DCAST(LightAttrib, LightAttrib::make()); pvector::iterator 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)); @@ -171,7 +169,7 @@ load_node(domNode& node, PandaNode *parent) { // Create the node. PT(PandaNode) pnode; - pnode = new PandaNode(node.getName()); + pnode = new PandaNode(TOSTRING(node.getName())); node.setUserData((void *) pnode); parent->add_child(pnode); @@ -179,8 +177,8 @@ load_node(domNode& node, PandaNode *parent) { LMatrix4f transform (LMatrix4f::ident_mat()); 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()) { case COLLADA_TYPE::LOOKAT: { @@ -221,7 +219,7 @@ load_node(domNode& node, PandaNode *parent) { break; } case COLLADA_TYPE::SKEW: - // FIXME: implement skew + //FIXME: implement skew collada_cat.error() << " not supported yet\n"; break; case COLLADA_TYPE::TRANSLATE: { @@ -246,11 +244,22 @@ load_node(domNode& node, PandaNode *parent) { 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 (ctrlinst[i]->getUrl().getElement()); + //TODO: implement controllers. For now, let's just read the geometry + if (target->getSkin() != NULL) { + domGeometry* geom = daeSafeCast (target->getSkin()->getSource().getElement()); + //TODO: bind_material stuff + load_geometry(*geom, 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 (ginst[i]->getUrl().getElement()); - load_geometry(*target, pnode); + load_instance_geometry(*ginst[i], pnode); } // See if this node instantiates any lights. @@ -327,6 +336,26 @@ load_camera(domCamera &cam, PandaNode *parent) { //TODO } +//////////////////////////////////////////////////////////////////// +// Function: ColladaLoader::load_instance_geometry +// Description: Loads a COLLADA as a PandaNode +// object. +//////////////////////////////////////////////////////////////////// +void ColladaLoader:: +load_instance_geometry(domInstance_geometry &inst, PandaNode *parent) { + domGeometry* geom = daeSafeCast (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 // Description: Loads a COLLADA as a GeomNode object. @@ -346,104 +375,66 @@ load_geometry(domGeometry &geom, PandaNode *parent) { } // Create the node. - PT(GeomNode) gnode = new GeomNode(geom.getName()); + PT(GeomNode) gnode = new GeomNode(TOSTRING(geom.getName())); geom.setUserData((void *) gnode); parent->add_child(gnode); - // First handle the element. - domVertices &vertices = *mesh->getVertices(); - daeTArray &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(vtx_inputs[i]->getSource().getElement()); - nassertd(source != NULL) continue; - - vtx_names[i] = load_input(vtx_aformat, vtx_values[i], semantic, *source); + //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()); + } + } + + 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()); + } + } + + 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()); + } + } + + 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(); 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 &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(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; - } - } - - // 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 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; + 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()); + } + } + + 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()); + } + } // Load in any tags. domExtra_Array &extras = geom.getExtra_array(); @@ -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 ¶ms = 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 as a LightNode object. @@ -541,18 +458,20 @@ load_light(domLight &light, PandaNode *parent) { PT(LightNode) lnode; domLight::domTechnique_common &tc = *light.getTechnique_common(); + // Check for an ambient light. domLight::domTechnique_common::domAmbientRef ambient = tc.getAmbient(); if (ambient != NULL) { - PT(AmbientLight) alight = new AmbientLight(light.getName()); + PT(AmbientLight) alight = new AmbientLight(TOSTRING(light.getName())); lnode = DCAST(LightNode, alight); domFloat3 &color = ambient->getColor()->getValue(); alight->set_color(Colorf(color[0], color[1], color[2], 1.0)); } + // Check for a directional light. domLight::domTechnique_common::domDirectionalRef directional = tc.getDirectional(); if (directional != NULL) { - PT(DirectionalLight) dlight = new DirectionalLight(light.getName()); + PT(DirectionalLight) dlight = new DirectionalLight(TOSTRING(light.getName())); lnode = DCAST(LightNode, dlight); domFloat3 &color = directional->getColor()->getValue(); @@ -560,34 +479,70 @@ load_light(domLight &light, PandaNode *parent) { dlight->set_direction(LVector3f(0, 0, -1)); } + // Check for a point light. domLight::domTechnique_common::domPointRef point = tc.getPoint(); if (point != NULL) { - PT(PointLight) plight = new PointLight(light.getName()); + PT(PointLight) plight = new PointLight(TOSTRING(light.getName())); lnode = DCAST(LightNode, plight); domFloat3 &color = point->getColor()->getValue(); 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(); if (spot != NULL) { - PT(Spotlight) slight = new Spotlight(light.getName()); + PT(Spotlight) slight = new Spotlight(TOSTRING(light.getName())); lnode = DCAST(LightNode, slight); domFloat3 &color = spot->getColor()->getValue(); 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) { @@ -603,3 +558,13 @@ load_light(domLight &light, PandaNode *parent) { load_tags(*extras[i], lnode); } } + +//////////////////////////////////////////////////////////////////// +// Function: ColladaLoader::load_material +// Description: Loads a COLLADA as a RenderState +// object. +//////////////////////////////////////////////////////////////////// +void ColladaLoader:: +load_material(domBind_material &bind_mat, PandaNode *node) { + +} diff --git a/panda/src/collada/colladaLoader.h b/panda/src/collada/colladaLoader.h index 13faa0bd68..219494f965 100644 --- a/panda/src/collada/colladaLoader.h +++ b/panda/src/collada/colladaLoader.h @@ -26,11 +26,13 @@ class BamCacheRecord; class LightNode; +class domBind_material; class domCOLLADA; class domNode; class domVisual_scene; class domExtra; class domGeometry; +class domInstance_geometry; class domLight; class domCamera; class domSource; @@ -64,9 +66,10 @@ private: void load_node(domNode &node, PandaNode *parent); void load_tags(domExtra &extra, PandaNode *node); void load_camera(domCamera &cam, PandaNode *parent); + void load_instance_geometry(domInstance_geometry &inst, 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_material(domBind_material &bind_mat, PandaNode *node); }; #include "colladaLoader.I" diff --git a/panda/src/collada/colladaPrimitive.I b/panda/src/collada/colladaPrimitive.I new file mode 100644 index 0000000000..db5be67efa --- /dev/null +++ b/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; +} diff --git a/panda/src/collada/colladaPrimitive.cxx b/panda/src/collada/colladaPrimitive.cxx new file mode 100644 index 0000000000..93295ecbd2 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include + +#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 &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 &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; + } +} diff --git a/panda/src/collada/colladaPrimitive.h b/panda/src/collada/colladaPrimitive.h new file mode 100644 index 0000000000..53a40f12d0 --- /dev/null +++ b/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 and . +//////////////////////////////////////////////////////////////////// +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 > &inputs); + void load_primitive(domP &p); + void load_primitives(daeTArray > &p_array); + INLINE void add_input(ColladaInput *input); + + typedef pvector Inputs; + Inputs _inputs; + + unsigned int _stride; + PT(Geom) _geom; + PT(GeomVertexData) _vdata; + PT(GeomPrimitive) _gprim; +}; + +#include "colladaPrimitive.I" + +#endif diff --git a/panda/src/collada/config_collada.h b/panda/src/collada/config_collada.h index effc38e2a1..5f019eca61 100644 --- a/panda/src/collada/config_collada.h +++ b/panda/src/collada/config_collada.h @@ -20,6 +20,8 @@ #include "notifyCategoryProxy.h" #include "dconfig.h" +template class daeTArray; +template class daeSmartRef; ConfigureDecl(config_collada, EXPCL_COLLADA, EXPTP_COLLADA); NotifyCategoryDecl(collada, EXPCL_COLLADA, EXPTP_COLLADA); diff --git a/panda/src/collada/loaderFileTypeDae.cxx b/panda/src/collada/loaderFileTypeDae.cxx index 20911eafd4..89cf3e4c6b 100644 --- a/panda/src/collada/loaderFileTypeDae.cxx +++ b/panda/src/collada/loaderFileTypeDae.cxx @@ -33,7 +33,13 @@ LoaderFileTypeDae() { //////////////////////////////////////////////////////////////////// string LoaderFileTypeDae:: 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 } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/collada/pre_collada_include.h b/panda/src/collada/pre_collada_include.h new file mode 100644 index 0000000000..6d07cecff0 --- /dev/null +++ b/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