Panda3D
 All Classes Functions Variables Enumerations
colladaInput.cxx
1 // Filename: colladaInput.cxx
2 // Created by: rdb (23May11)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "colladaInput.h"
16 #include "string_utils.h"
17 #include "geomVertexArrayFormat.h"
18 #include "geomVertexWriter.h"
19 
20 // Collada DOM includes. No other includes beyond this point.
21 #include "pre_collada_include.h"
22 #include <dom/domAccessor.h>
23 #include <dom/domP.h>
24 #include <dom/domSource.h>
25 #include <dom/domVertices.h>
26 
27 #if PANDA_COLLADA_VERSION >= 15
28 #include <dom/domInput_local_offset.h>
29 #include <dom/domInput_local.h>
30 #else
31 #include <dom/domInputLocalOffset.h>
32 #include <dom/domInputLocal.h>
33 #define domList_of_floats domListOfFloats
34 #define domList_of_uints domListOfUInts
35 #endif
36 
37 ////////////////////////////////////////////////////////////////////
38 // Function: ColladaInput::Constructor
39 // Description: Pretty obvious what this does.
40 ////////////////////////////////////////////////////////////////////
41 ColladaInput::
42 ColladaInput(const string &semantic) :
43  _column_name (NULL),
44  _semantic (semantic),
45  _offset (0),
46  _have_set (false),
47  _set (0) {
48 
49  if (semantic == "POSITION") {
50  _column_name = InternalName::get_vertex();
51  _column_contents = GeomEnums::C_point;
52  } else if (semantic == "COLOR") {
53  _column_name = InternalName::get_color();
54  _column_contents = GeomEnums::C_color;
55  } else if (semantic == "NORMAL") {
56  _column_name = InternalName::get_normal();
57  _column_contents = GeomEnums::C_vector;
58  } else if (semantic == "TEXCOORD") {
59  _column_name = InternalName::get_texcoord();
60  _column_contents = GeomEnums::C_texcoord;
61  } else if (semantic == "TEXBINORMAL") {
62  _column_name = InternalName::get_binormal();
63  _column_contents = GeomEnums::C_vector;
64  } else if (semantic == "TEXTANGENT") {
65  _column_name = InternalName::get_tangent();
66  _column_contents = GeomEnums::C_vector;
67  }
68 }
69 
70 ////////////////////////////////////////////////////////////////////
71 // Function: ColladaInput::Constructor
72 // Description: Pretty obvious what this does.
73 ////////////////////////////////////////////////////////////////////
74 ColladaInput::
75 ColladaInput(const string &semantic, unsigned int set) :
76  _column_name (NULL),
77  _semantic (semantic),
78  _offset (0),
79  _have_set (true),
80  _set (set) {
81 
82  ostringstream setstr;
83  setstr << _set;
84 
85  if (semantic == "POSITION") {
86  _column_name = InternalName::get_vertex();
87  _column_contents = GeomEnums::C_point;
88  } else if (semantic == "COLOR") {
89  _column_name = InternalName::get_color();
90  _column_contents = GeomEnums::C_color;
91  } else if (semantic == "NORMAL") {
92  _column_name = InternalName::get_normal();
93  _column_contents = GeomEnums::C_vector;
94  } else if (semantic == "TEXCOORD") {
95  _column_name = InternalName::get_texcoord_name(setstr.str());
96  _column_contents = GeomEnums::C_texcoord;
97  } else if (semantic == "TEXBINORMAL") {
98  _column_name = InternalName::get_binormal_name(setstr.str());
99  _column_contents = GeomEnums::C_vector;
100  } else if (semantic == "TEXTANGENT") {
101  _column_name = InternalName::get_tangent_name(setstr.str());
102  _column_contents = GeomEnums::C_vector;
103  }
104 }
105 
106 ////////////////////////////////////////////////////////////////////
107 // Function: ColladaInput::from_dom
108 // Description: Returns the ColladaInput object that represents
109 // the provided DOM input element.
110 ////////////////////////////////////////////////////////////////////
112 from_dom(domInput_local_offset &input) {
113  // If we already loaded it before, use that.
114  if (input.getUserData() != NULL) {
115  return (ColladaInput *) input.getUserData();
116  }
117 
118  ColladaInput *new_input = new ColladaInput(input.getSemantic(), input.getSet());
119  new_input->_offset = input.getOffset();
120 
121  // If this has the VERTEX semantic, it points to a <vertices> element.
122  if (new_input->is_vertex_source()) {
123  domVertices *verts = daeSafeCast<domVertices> (input.getSource().getElement());
124  nassertr(verts != NULL, NULL);
125  daeTArray<domInput_localRef> &inputs = verts->getInput_array();
126 
127  // Iterate over the <input> elements in <vertices>.
128  for (size_t i = 0; i < inputs.getCount(); ++i) {
129  PT(ColladaInput) vtx_input = ColladaInput::from_dom(*inputs[i]);
130  new_input->_vertex_inputs.push_back(vtx_input);
131  }
132  } else {
133  domSource *source = daeSafeCast<domSource> (input.getSource().getElement());
134  nassertr(source != NULL, NULL);
135  new_input->read_data(*source);
136  }
137 
138  return new_input;
139 }
140 
141 ////////////////////////////////////////////////////////////////////
142 // Function: ColladaInput::from_dom
143 // Description: Returns the ColladaInput object that represents
144 // the provided DOM input element.
145 ////////////////////////////////////////////////////////////////////
147 from_dom(domInput_local &input) {
148  // If we already loaded it before, use that.
149  if (input.getUserData() != NULL) {
150  return (ColladaInput *) input.getUserData();
151  }
152 
153  ColladaInput *new_input = new ColladaInput(input.getSemantic());
154  new_input->_offset = 0;
155 
156  nassertr (!new_input->is_vertex_source(), NULL);
157 
158  domSource *source = daeSafeCast<domSource> (input.getSource().getElement());
159  nassertr(source != NULL, NULL);
160  new_input->read_data(*source);
161 
162  return new_input;
163 }
164 
165 ////////////////////////////////////////////////////////////////////
166 // Function: ColladaInput::make_vertex_columns
167 // Description: Takes a semantic and source URI, and adds a new
168 // column to the format. If this is a vertex source,
169 // adds all of the inputs from the corresponding
170 // <vertices> element. Returns the number of
171 // columns added to the format.
172 ////////////////////////////////////////////////////////////////////
173 int ColladaInput::
174 make_vertex_columns(GeomVertexArrayFormat *format) const {
175 
176  if (is_vertex_source()) {
177  int counter = 0;
178  Inputs::const_iterator it;
179  for (it = _vertex_inputs.begin(); it != _vertex_inputs.end(); ++it) {
180  counter += (*it)->make_vertex_columns(format);
181  }
182  return counter;
183  }
184 
185  nassertr(_column_name != NULL, 0);
186 
187  format->add_column(_column_name, _num_bound_params, GeomEnums::NT_stdfloat, _column_contents);
188  return 1;
189 }
190 
191 ////////////////////////////////////////////////////////////////////
192 // Function: ColladaInput::read_data
193 // Description: Reads the data from the source and fills in _data.
194 ////////////////////////////////////////////////////////////////////
195 bool ColladaInput::
196 read_data(domSource &source) {
197  _data.clear();
198 
199  // Get this, get that
200  domFloat_array* float_array = source.getFloat_array();
201  if (float_array == NULL) {
202  return false;
203  }
204 
205  domList_of_floats &floats = float_array->getValue();
206  domAccessor &accessor = *source.getTechnique_common()->getAccessor();
207  domParam_Array &params = accessor.getParam_array();
208 
209  // Count the number of params that have a name attribute.
210  _num_bound_params = 0;
211  for (size_t p = 0; p < params.getCount(); ++p) {
212  if (params[p]->getName()) {
213  ++_num_bound_params;
214  }
215  }
216 
217  _data.reserve(accessor.getCount());
218 
219  domUint pos = accessor.getOffset();
220  for (domUint a = 0; a < accessor.getCount(); ++a) {
221  domUint c = 0;
222  // Yes, the last component defaults to 1 to work around a
223  // perspective divide that Panda3D does internally for points.
224  LVecBase4f v (0, 0, 0, 1);
225  for (domUint p = 0; p < params.getCount(); ++p) {
226  if (params[c]->getName()) {
227  v[c++] = floats[pos + p];
228  }
229  }
230  _data.push_back(v);
231  pos += accessor.getStride();
232  }
233 
234  return true;
235 }
236 
237 ////////////////////////////////////////////////////////////////////
238 // Function: ColladaInput::write_data
239 // Description: Writes data to the indicated GeomVertexData using
240 // the given indices.
241 ////////////////////////////////////////////////////////////////////
242 void ColladaInput::
243 write_data(GeomVertexData *vdata, int start_row, domP &p, unsigned int stride) const {
244  if (is_vertex_source()) {
245  Inputs::const_iterator it;
246  for (it = _vertex_inputs.begin(); it != _vertex_inputs.end(); ++it) {
247  (*it)->write_data(vdata, start_row, p, stride, _offset);
248  }
249 
250  } else {
251  write_data(vdata, start_row, p, stride, _offset);
252  }
253 }
254 
255 ////////////////////////////////////////////////////////////////////
256 // Function: ColladaInput::write_data
257 // Description: Called internally by the other write_data.
258 ////////////////////////////////////////////////////////////////////
259 void ColladaInput::
260 write_data(GeomVertexData *vdata, int start_row, domP &p, unsigned int stride, unsigned int offset) const {
261  nassertv(_column_name != NULL);
262  GeomVertexWriter writer (vdata, _column_name);
263  writer.set_row_unsafe(start_row);
264 
265  domList_of_uints &indices = p.getValue();
266 
267  // Allocate space for all the rows we're going to write.
268  int min_length = start_row + indices.getCount() / stride;
269  if (vdata->get_num_rows() < min_length) {
270  vdata->unclean_set_num_rows(start_row);
271  }
272 
273  for (size_t i = 0; i < indices.getCount(); i += stride) {
274  size_t index = indices[i + offset];
275  writer.add_data4f(_data[index]);
276  }
277 }
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
bool unclean_set_num_rows(int n)
This method behaves like set_num_rows(), except the new data is not initialized.
Class that deals with COLLADA data sources.
Definition: colladaInput.h:45
int make_vertex_columns(GeomVertexArrayFormat *fmt) const
Takes a semantic and source URI, and adds a new column to the format.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
void write_data(GeomVertexData *vdata, int start_row, domP &p, unsigned int stride) const
Writes data to the indicated GeomVertexData using the given indices.
bool is_vertex_source() const
Returns true if this has a &lt;vertices&gt; element as source.
Definition: colladaInput.I:22
static ColladaInput * from_dom(domInputLocalOffset &input)
Returns the ColladaInput object that represents the provided DOM input element.
int get_num_rows() const
Returns the number of rows stored within all the arrays.