lots of improvements to the COLLADA loader

This commit is contained in:
rdb 2011-05-24 13:14:11 +00:00
parent 70f6605442
commit b33ffd9636
12 changed files with 998 additions and 196 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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]);
}
}

View File

@ -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

View File

@ -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 <dae.h>
// Collada DOM includes. No other includes beyond this point.
#include "pre_collada_include.h"
#include <dom/domCOLLADA.h>
#include <dom/domNode.h>
#include <dom/domVisual_scene.h>
@ -43,12 +42,11 @@
#else
#include <dom/domInstanceWithExtra.h>
#define domInstance_with_extra domInstanceWithExtra
#define domInput_localRef domInputLocalRef
#define domInput_local_offsetRef domInputLocalOffsetRef
#define domList_of_uints domListOfUInts
#define domList_of_floats domListOfFloats
#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<LightNode*>::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: {
@ -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<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.
domInstance_geometry_Array &ginst = node.getInstance_geometry_array();
for (size_t i = 0; i < ginst.getCount(); ++i) {
domGeometry* target = daeSafeCast<domGeometry> (ginst[i]->getUrl().getElement());
load_geometry(*target, pnode);
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 <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
// Description: Loads a COLLADA <geometry> 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 <vertices> element.
domVertices &vertices = *mesh->getVertices();
daeTArray<domInput_localRef> &vtx_inputs = vertices.getInput_array();
PT(GeomVertexArrayFormat) vtx_aformat = new GeomVertexArrayFormat;
PTA_LVecBase4f *vtx_values = new PTA_LVecBase4f[vtx_inputs.getCount()];
CPT(InternalName) *vtx_names = new CPT(InternalName)[vtx_inputs.getCount()];
for (size_t i = 0; i < vtx_inputs.getCount(); ++i) {
const string semantic = vtx_inputs[i]->getSemantic();
domSource *source = daeSafeCast<domSource>(vtx_inputs[i]->getSource().getElement());
nassertd(source != NULL) continue;
vtx_names[i] = load_input(vtx_aformat, vtx_values[i], semantic, *source);
//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;
}
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;
PT(ColladaPrimitive) prim = ColladaPrimitive::from_dom(*triangles_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]);
}
}
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());
}
}
PT(Geom) geom = new Geom(vdata);
geom->add_primitive(gtris);
gnode->add_geom(geom);
delete[] values;
delete[] names;
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());
}
}
delete[] vtx_values;
delete[] vtx_names;
// 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 &params = accessor.getParam_array();
// Count the number of params that have a name attribute.
domUint num_bound_params = 0;
for (size_t p = 0; p < params.getCount(); ++p) {
if (params[p]->getName()) {
++num_bound_params;
}
}
domUint pos = accessor.getOffset();
for (domUint a = 0; a < accessor.getCount(); ++a) {
domUint c = 0;
// Yes, the last component defaults to 1 to work around a
// perspective divide that Panda3D does internally for points.
LVecBase4f v (0, 0, 0, 1);
for (domUint p = 0; p < params.getCount(); ++p) {
if (params[c]->getName()) {
v._v.data[c++] = floats[pos + p];
}
}
values.push_back(v);
pos += accessor.getStride();
}
fmt->add_column(cname, num_bound_params, GeomEnums::NT_float32, contents);
return cname;
}
////////////////////////////////////////////////////////////////////
// Function: ColladaLoader::load_light
// Description: Loads a COLLADA <light> as a LightNode object.
@ -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 <bind_material> as a RenderState
// object.
////////////////////////////////////////////////////////////////////
void ColladaLoader::
load_material(domBind_material &bind_mat, PandaNode *node) {
}

View File

@ -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"

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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

View File

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

View File

@ -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
}
////////////////////////////////////////////////////////////////////

View File

@ -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>