Panda3D
geomVertexFormat.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file geomVertexFormat.cxx
10  * @author drose
11  * @date 2005-03-07
12  */
13 
14 #include "geomVertexFormat.h"
15 #include "geomVertexData.h"
16 #include "geomMunger.h"
17 #include "lightReMutexHolder.h"
18 #include "indent.h"
19 #include "bamReader.h"
20 #include "bamWriter.h"
21 
22 GeomVertexFormat::Registry *GeomVertexFormat::_registry = nullptr;
23 TypeHandle GeomVertexFormat::_type_handle;
24 
25 /**
26  *
27  */
28 GeomVertexFormat::
29 GeomVertexFormat() :
30  _is_registered(false),
31  _post_animated_format(nullptr)
32 {
33 }
34 
35 /**
36  *
37  */
38 GeomVertexFormat::
39 GeomVertexFormat(const GeomVertexArrayFormat *array_format) :
40  _is_registered(false),
41  _post_animated_format(nullptr)
42 {
43  add_array(array_format);
44 }
45 
46 /**
47  *
48  */
49 GeomVertexFormat::
50 GeomVertexFormat(const GeomVertexFormat &copy) :
51  _is_registered(false),
52  _animation(copy._animation),
53  _arrays(copy._arrays),
54  _post_animated_format(nullptr)
55 {
56 }
57 
58 /**
59  *
60  */
61 void GeomVertexFormat::
62 operator = (const GeomVertexFormat &copy) {
63  nassertv(!is_registered());
64 
65  _animation = copy._animation;
66  _arrays = copy._arrays;
67 }
68 
69 /**
70  *
71  */
72 GeomVertexFormat::
73 ~GeomVertexFormat() {
74  // unref() should have unregistered us.
75  nassertv(!is_registered());
76 }
77 
78 /**
79  * This method overrides ReferenceCount::unref() to unregister the object when
80  * its reference count goes to zero.
81  */
83 unref() const {
84  Registry *registry = get_registry();
85  LightReMutexHolder holder(registry->_lock);
86 
87  if (ReferenceCount::unref()) {
88  return true;
89  }
90 
91  if (is_registered()) {
92  registry->unregister_format((GeomVertexFormat *)this);
93  }
94 
95  return false;
96 }
97 
98 /**
99  * Returns a suitable vertex format for sending the animated vertices to the
100  * graphics backend. This is the same format as the source format, with the
101  * CPU-animation data elements removed.
102  *
103  * This may only be called after the format has been registered. The return
104  * value will have been already registered.
105  */
106 CPT(GeomVertexFormat) GeomVertexFormat::
107 get_post_animated_format() const {
108  nassertr(is_registered(), nullptr);
109 
110  if (_post_animated_format == nullptr) {
111  PT(GeomVertexFormat) new_format = new GeomVertexFormat(*this);
112  new_format->remove_column(InternalName::get_transform_blend());
113 
114  int num_morphs = get_num_morphs();
115  for (int mi = 0; mi < num_morphs; mi++) {
116  CPT(InternalName) delta_name = get_morph_delta(mi);
117  new_format->remove_column(delta_name);
118  }
119 
120  new_format->_animation.set_none();
121 
122  CPT(GeomVertexFormat) registered =
123  GeomVertexFormat::register_format(new_format);
124  ((GeomVertexFormat *)this)->_post_animated_format = registered;
125  if (_post_animated_format != this) {
126  // We only keep the reference count if the new pointer is not the same
127  // as this, to avoid a circular dependency.
128  _post_animated_format->ref();
129  }
130  }
131 
132  _post_animated_format->test_ref_count_integrity();
133 
134  return _post_animated_format;
135 }
136 
137 /**
138  * Returns a new GeomVertexFormat that includes all of the columns defined in
139  * either this GeomVertexFormat or the other one. If any column is defined in
140  * both formats with different sizes (for instance, texcoord2 vs. texcoord3),
141  * the new format will include the larger of the two definitions.
142  *
143  * This may only be called after both source formats have been registered.
144  * The return value will also have been already registered.
145  */
146 CPT(GeomVertexFormat) GeomVertexFormat::
147 get_union_format(const GeomVertexFormat *other) const {
148  nassertr(is_registered() && other->is_registered(), nullptr);
149 
150  PT(GeomVertexFormat) new_format = new GeomVertexFormat;
151 
152  // Preserve whichever animation type is not AT_None. (If both animation
153  // types are not AT_None, but they are different, this whole operation is
154  // questionable.)
155  if (_animation.get_animation_type() != AT_none) {
156  new_format->set_animation(_animation);
157  } else {
158  new_format->set_animation(other->get_animation());
159  }
160 
161  // Keep track of the columns we have already added.
162  typedef pset< CPT(InternalName) > ColumnNames;
163  ColumnNames column_names;
164 
165  // We go through all the (0)-level arrays first, then all the (1)-level
166  // arrays, and so on. We do this to ensure that the new format gets written
167  // out with all the (0)-level columns appearing before all the (1)-level
168  // columns, which might lead to a small optimization at render time.
169 
170  // We also try to keep the structure as similar as possible. If both source
171  // formats have columns (A, B) in array 0, and columns (C, D, E) in array 1,
172  // then the resulting union format will also have (A, B) in array 0 and (C,
173  // D, E) in array 1. In general, a column will appear in the result in the
174  // first array it appears in either of the inputs.
175 
176  size_t num_arrays = std::max(_arrays.size(), other->_arrays.size());
177  for (size_t ai = 0; ai < num_arrays; ++ai) {
178  PT(GeomVertexArrayFormat) new_array = new GeomVertexArrayFormat;
179 
180  // Add the columns from the first format.
181  if (ai < _arrays.size()) {
182  GeomVertexArrayFormat *array_format = _arrays[ai];
183  size_t num_columns = array_format->get_num_columns();
184  for (size_t i = 0; i < num_columns; ++i) {
185  const GeomVertexColumn *column_a = array_format->get_column(i);
186  bool inserted = column_names.insert(column_a->get_name()).second;
187  if (inserted) {
188  const GeomVertexColumn *column_b = other->get_column(column_a->get_name());
189  if (column_b != nullptr &&
190  column_b->get_total_bytes() > column_a->get_total_bytes()) {
191  // Column b is larger. Keep it.
192  new_array->add_column(column_b->get_name(),
193  column_b->get_num_components(),
194  column_b->get_numeric_type(),
195  column_b->get_contents());
196  } else {
197  // Column a is larger. Keep it.
198  new_array->add_column(column_a->get_name(),
199  column_a->get_num_components(),
200  column_a->get_numeric_type(),
201  column_a->get_contents());
202  }
203  }
204  }
205  }
206 
207  // Add the columns from the second format.
208  if (ai < other->_arrays.size()) {
209  GeomVertexArrayFormat *array_format = other->_arrays[ai];
210  size_t num_columns = array_format->get_num_columns();
211  for (size_t i = 0; i < num_columns; ++i) {
212  const GeomVertexColumn *column_a = array_format->get_column(i);
213  bool inserted = column_names.insert(column_a->get_name()).second;
214  if (inserted) {
215  const GeomVertexColumn *column_b = get_column(column_a->get_name());
216  if (column_b != nullptr &&
217  column_b->get_total_bytes() > column_a->get_total_bytes()) {
218  // Column b is larger. Keep it.
219  new_array->add_column(column_b->get_name(),
220  column_b->get_num_components(),
221  column_b->get_numeric_type(),
222  column_b->get_contents());
223  } else {
224  // Column a is larger. Keep it.
225  new_array->add_column(column_a->get_name(),
226  column_a->get_num_components(),
227  column_a->get_numeric_type(),
228  column_a->get_contents());
229  }
230  }
231  }
232  }
233 
234  if (new_array->get_num_columns() != 0) {
235  new_format->add_array(new_array);
236  }
237  }
238 
239  // Finally, register the format for the thing.
240  return GeomVertexFormat::register_format(new_format);
241 }
242 
243 /**
244  * Returns a modifiable pointer to the indicated array. This means
245  * duplicating it if it is shared or registered.
246  *
247  * This may not be called once the format has been registered.
248  */
249 GeomVertexArrayFormat *GeomVertexFormat::
250 modify_array(size_t array) {
251  nassertr(!is_registered(), nullptr);
252  nassertr(array < _arrays.size(), nullptr);
253 
254  if (_arrays[array]->is_registered() ||
255  _arrays[array]->get_ref_count() > 1) {
256  _arrays[array] = new GeomVertexArrayFormat(*_arrays[array]);
257  }
258 
259  return _arrays[array];
260 }
261 
262 /**
263  * Replaces the definition of the indicated array.
264  *
265  * This may not be called once the format has been registered.
266  */
268 set_array(size_t array, const GeomVertexArrayFormat *format) {
269  nassertv(!is_registered());
270  nassertv(array < _arrays.size());
271  _arrays[array] = (GeomVertexArrayFormat *)format;
272 }
273 
274 /**
275  * Removes the nth array from the format.
276  *
277  * This may not be called once the format has been registered.
278  */
280 remove_array(size_t array) {
281  nassertv(!is_registered());
282 
283  nassertv(array < _arrays.size());
284  _arrays.erase(_arrays.begin() + array);
285 }
286 
287 /**
288  * Adds the indicated array definition to the list of arrays included within
289  * this vertex format definition. The return value is the index number of the
290  * new array.
291  *
292  * This may not be called once the format has been registered.
293  */
294 size_t GeomVertexFormat::
295 add_array(const GeomVertexArrayFormat *array_format) {
296  nassertr(!is_registered(), 0);
297 
298  size_t new_array = _arrays.size();
299  _arrays.push_back((GeomVertexArrayFormat *)array_format);
300  return new_array;
301 }
302 
303 /**
304  * Adds the indicated array definition to the list of arrays at the indicated
305  * position. This works just like add_array(), except that you can specify
306  * which array index the new array should have.
307  *
308  * This may not be called once the format has been registered.
309  */
311 insert_array(size_t array, const GeomVertexArrayFormat *array_format) {
312  nassertv(!is_registered());
313  if (array > _arrays.size()) {
314  array = _arrays.size();
315  }
316 
317  _arrays.insert(_arrays.begin() + array, (GeomVertexArrayFormat *)array_format);
318 }
319 
320 /**
321  * Removes all of the array definitions from the format and starts over.
322  *
323  * This may not be called once the format has been registered.
324  */
327  nassertv(!is_registered());
328 
329  _arrays.clear();
330 }
331 
332 /**
333  * Removes the arrays that define no columns.
334  *
335  * This may not be called once the format has been registered.
336  */
339  nassertv(!is_registered());
340 
341  Arrays orig_arrays;
342  orig_arrays.swap(_arrays);
343  Arrays::const_iterator ai;
344  for (ai = orig_arrays.begin(); ai != orig_arrays.end(); ++ai) {
345  GeomVertexArrayFormat *array_format = (*ai);
346  if (array_format->get_num_columns() != 0) {
347  _arrays.push_back(array_format);
348  }
349  }
350 }
351 
352 /**
353  * Returns the total number of different columns in the specification, across
354  * all arrays.
355  */
356 size_t GeomVertexFormat::
357 get_num_columns() const {
358  size_t num_columns = 0;
359  Arrays::const_iterator ai;
360  for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
361  num_columns += (*ai)->get_num_columns();
362  }
363  return num_columns;
364 }
365 
366 /**
367  * Returns the ith column of the specification, across all arrays.
368  */
370 get_column(size_t i) const {
371  Arrays::const_iterator ai;
372  for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
373  if (i < (size_t)(*ai)->get_num_columns()) {
374  return (*ai)->get_column(i);
375  }
376  i -= (*ai)->get_num_columns();
377  }
378 
379  return nullptr;
380 }
381 
382 /**
383  * Returns the name of the ith column, across all arrays.
384  */
386 get_column_name(size_t i) const {
387  Arrays::const_iterator ai;
388  for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
389  if (i < (size_t)(*ai)->get_num_columns()) {
390  return (*ai)->get_column(i)->get_name();
391  }
392  i -= (*ai)->get_num_columns();
393  }
394 
395  return nullptr;
396 }
397 
398 /**
399  * Returns the index number of the array with the ith column.
400  *
401  * The return value can be passed to get_array_format() to get the format of
402  * the array. It may also be passed to GeomVertexData::get_array_data() or
403  * get_data() or set_data() to manipulate the actual array data.
404  */
406 get_array_with(size_t i) const {
407  int array_index = 0;
408  for (array_index = 0; array_index < (int)_arrays.size(); array_index++) {
409  if (i < (size_t)_arrays[array_index]->get_num_columns()) {
410  return array_index;
411  }
412  i -= _arrays[array_index]->get_num_columns();
413  }
414 
415  return -1;
416 }
417 
418 /**
419  * Returns the index number of the array with the indicated column, or -1 if
420  * no arrays contained that name.
421  *
422  * The return value can be passed to get_array_format() to get the format of
423  * the array. It may also be passed to GeomVertexData::get_array_data() or
424  * get_data() or set_data() to manipulate the actual array data.
425  *
426  * This may only be called after the format has been registered.
427  */
429 get_array_with(const InternalName *name) const {
430  nassertr(_is_registered, -1);
431 
432  DataTypesByName::const_iterator ai;
433  ai = _columns_by_name.find(name);
434  if (ai != _columns_by_name.end()) {
435  return (*ai).second._array_index;
436  }
437  return -1;
438 }
439 
440 /**
441  * Returns the specification with the indicated name, or NULL if the name is
442  * not used. Use get_array_with() to determine which array this column is
443  * associated with.
444  */
446 get_column(const InternalName *name) const {
447  if (!_is_registered) {
448  // If the format hasn't yet been registered, we have to search for the
449  // column the hard way.
450  Arrays::const_iterator ai;
451  for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
452  const GeomVertexColumn *column = (*ai)->get_column(name);
453  if (column != nullptr) {
454  return column;
455  }
456  }
457  return nullptr;
458 
459  } else {
460  // If the format has been registered, we can just check the toplevel
461  // index.
462 
463  DataTypesByName::const_iterator ai;
464  ai = _columns_by_name.find(name);
465  if (ai != _columns_by_name.end()) {
466  int array_index = (*ai).second._array_index;
467  int column_index = (*ai).second._column_index;
468 
469  nassertr(array_index >= 0 && array_index < (int)_arrays.size(), nullptr);
470  return _arrays[array_index]->get_column(column_index);
471  }
472  return nullptr;
473  }
474 }
475 
476 /**
477  * Removes the named column from the format, from whichever array it exists
478  * in. If there are other columns remaining in the array, the array is left
479  * with a gap where the column used to be; if this was the only column in the
480  * array, the array is removed (unless keep_empty_array is true).
481  *
482  * This may not be called once the format has been registered.
483  */
485 remove_column(const InternalName *name, bool keep_empty_array) {
486  nassertv(!_is_registered);
487 
488  // Since the format's not registered, it doesn't yet have an index of
489  // columns--so we have to search all of the arrays, one at a time, until we
490  // find it.
491  for (int array = 0; array < (int)_arrays.size(); ++array) {
492  GeomVertexArrayFormat *array_format = _arrays[array];
493 
494  if (array_format->get_column(name) != nullptr) {
495  // Here's the array with the named column!
496  if (array_format->is_registered() ||
497  array_format->get_ref_count() > 1) {
498  // Get a safe-to-modify copy of the array format.
499  _arrays[array] = new GeomVertexArrayFormat(*array_format);
500  array_format = _arrays[array];
501  }
502 
503  array_format->remove_column(name);
504 
505  // Are there any columns remaining in the array?
506  if (!keep_empty_array && array_format->get_num_columns() == 0) {
507  // Remove the whole array.
508  remove_array(array);
509  }
510  return;
511  }
512  }
513 
514  // It appears that column wasn't part of the format anyway. No problem;
515  // quietly return.
516 }
517 
518 /**
519  * Removes wasted space between columns.
520  */
523  nassertv(!_is_registered);
524  Arrays::iterator ai;
525  for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
526  if ((*ai)->is_registered()) {
527  (*ai) = new GeomVertexArrayFormat(*(*ai));
528  }
529  (*ai)->pack_columns();
530  }
531 }
532 
533 /**
534  * Reprocesses the columns in the format to align the C_point and C_vector
535  * columns to 16-byte boundaries to allow for the more efficient SSE2
536  * operations (assuming SSE2 is enabled in the build).
537  *
538  * Also see maybe_align_columns_for_animation().
539  */
542  nassertv(!_is_registered);
543  Arrays::iterator ai;
544  for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
545  if ((*ai)->is_registered()) {
546  (*ai) = new GeomVertexArrayFormat(*(*ai));
547  }
548  (*ai)->align_columns_for_animation();
549  }
550 }
551 
552 /**
553  * Calls align_columns_for_animation() if this format's AnimationSpec
554  * indicates that it contains animated vertices, and if vertex-animation-
555  * align-16 is true.
556  */
559  if (_animation.get_animation_type() == AT_panda && vertex_animation_align_16) {
560  align_columns_for_animation();
561  }
562 }
563 
564 /**
565  *
566  */
567 void GeomVertexFormat::
568 output(std::ostream &out) const {
569  if (_arrays.empty()) {
570  out << "(empty)";
571 
572  } else {
573  Arrays::const_iterator ai;
574  ai = _arrays.begin();
575  out << *(*ai);
576  ++ai;
577  while (ai != _arrays.end()) {
578  out << ", " << *(*ai);
579  ++ai;
580  }
581  }
582 
583  if (_animation.get_animation_type() != AT_none) {
584  out << ", anim " << _animation;
585  }
586 }
587 
588 /**
589  *
590  */
591 void GeomVertexFormat::
592 write(std::ostream &out, int indent_level) const {
593  for (size_t i = 0; i < _arrays.size(); i++) {
594  indent(out, indent_level)
595  << "Array " << i << ":\n";
596  _arrays[i]->write(out, indent_level + 2);
597  }
598 
599  if (_animation.get_animation_type() != AT_none) {
600  indent(out, indent_level)
601  << "anim " << _animation << "\n";
602  }
603 }
604 
605 /**
606  *
607  */
608 void GeomVertexFormat::
609 write_with_data(std::ostream &out, int indent_level,
610  const GeomVertexData *data) const {
611  indent(out, indent_level)
612  << data->get_num_rows() << " rows.\n";
613  for (size_t i = 0; i < _arrays.size(); i++) {
614  CPT(GeomVertexArrayDataHandle) handle = data->get_array(i)->get_handle();
615  const unsigned char *array_data = handle->get_read_pointer(true);
616  indent(out, indent_level)
617  << "Array " << i << " (" << (void *)array_data << ", "
618  << *_arrays[i] << "):\n";
619  _arrays[i]->write_with_data(out, indent_level + 2, data->get_array(i));
620  }
621 }
622 
623 /**
624  * Quickly looks up the indicated column within all of the nested arrays and
625  * sets array_index and column appropriately. Returns true if the data type
626  * exists in this format, false if it does not. If it returns false,
627  * array_index is set to -1, and column is set to NULL.
628  *
629  * This may only be called after the format has been registered.
630  */
632 get_array_info(const InternalName *name, int &array_index,
633  const GeomVertexColumn *&column) const {
634  nassertr(_is_registered, false);
635 
636  DataTypesByName::const_iterator ai;
637  ai = _columns_by_name.find(name);
638  if (ai != _columns_by_name.end()) {
639  array_index = (*ai).second._array_index;
640  column = _arrays[array_index]->get_column((*ai).second._column_index);
641  return true;
642  }
643 
644  array_index = -1;
645  column = nullptr;
646 
647  return false;
648 }
649 
650 /**
651  *
652  */
653 int GeomVertexFormat::
654 compare_to(const GeomVertexFormat &other) const {
655  int compare = _animation.compare_to(other._animation);
656  if (compare != 0) {
657  return compare;
658  }
659 
660  if (_arrays.size() != other._arrays.size()) {
661  return (int)_arrays.size() - (int)other._arrays.size();
662  }
663 
664  for (size_t i = 0; i < _arrays.size(); i++) {
665  int compare = _arrays[i]->compare_to(*other._arrays[i]);
666  if (compare != 0) {
667  return compare;
668  }
669  }
670 
671  return 0;
672 }
673 
674 /**
675  * Returns the global registry object.
676  */
677 void GeomVertexFormat::
678 make_registry() {
679  if (_registry == nullptr) {
680  _registry = new Registry;
681  _registry->make_standard_formats();
682  }
683 }
684 
685 /**
686  * Called internally when the format is registered.
687  */
688 void GeomVertexFormat::
689 do_register() {
690  nassertv(!is_registered());
691  nassertv(_columns_by_name.empty());
692 
693  Arrays orig_arrays;
694  orig_arrays.swap(_arrays);
695  Arrays::const_iterator ai;
696  for (ai = orig_arrays.begin(); ai != orig_arrays.end(); ++ai) {
697  CPT(GeomVertexArrayFormat) array_format = (*ai);
698  if (!array_format->is_registered()) {
699  array_format = GeomVertexArrayFormat::register_format(array_format);
700  }
701 
702  // Let's keep arrays with nonzero stride but no used columns; they're
703  // needed to preserve the isomorphic nature of matching formats. But
704  // we'll toss arrays with 0 stride, which add nothing of value and only
705  // cause problems later.
706  if (array_format->get_stride() == 0) {
707  gobj_cat.warning()
708  << "Dropping empty array from GeomVertexFormat.\n";
709  continue;
710  }
711 
712  int array = (int)_arrays.size();
713  _arrays.push_back((GeomVertexArrayFormat *)array_format.p());
714 
715  // Now add the names to the index.
716  int num_columns = array_format->get_num_columns();
717  for (int i = 0; i < num_columns; i++) {
718  const GeomVertexColumn *column = array_format->get_column(i);
719  std::pair<DataTypesByName::iterator, bool> result;
720  result = _columns_by_name.insert(DataTypesByName::value_type(column->get_name(), DataTypeRecord()));
721  if (!result.second) {
722  gobj_cat.warning()
723  << "Column " << *column->get_name() << " repeated in format.\n";
724  } else {
725  DataTypeRecord &record = (*result.first).second;
726  record._array_index = array;
727  record._column_index = i;
728  }
729  }
730  }
731 
732  // Go back through the index now and identify the points, vectors, and morph
733  // descriptions, so we can quickly look these up later.
734  DataTypesByName::iterator ni;
735  for (ni = _columns_by_name.begin();
736  ni != _columns_by_name.end();
737  ++ni) {
738  const DataTypeRecord &record = (*ni).second;
739  const GeomVertexColumn *column = _arrays[record._array_index]->get_column(record._column_index);
740 
741  switch (column->get_contents()) {
742  case C_point:
743  // It's a point.
744  _points.push_back(column->get_name());
745  break;
746 
747  case C_vector:
748  case C_normal:
749  // It's a vector.
750  _vectors.push_back(column->get_name());
751  break;
752 
753  case C_texcoord:
754  // It's a texcoord.
755  _texcoords.push_back(column->get_name());
756  break;
757 
758  case C_morph_delta:
759  {
760  // It's a morph description.
761  MorphRecord morph;
762  morph._delta = column->get_name();
763 
764  // The delta name must be of the form "basename.morph.slidername".
765  int n = morph._delta->find_ancestor("morph");
766  if (n < 0) {
767  gobj_cat.warning()
768  << "vertex format defines " << *column->get_name()
769  << ", which is stored as a C_morph_delta, but its name does not include \"morph\".\n";
770  } else {
771  morph._slider = InternalName::make(morph._delta->get_net_basename(n - 1));
772  morph._base = morph._delta->get_ancestor(n + 1);
773 
774  if (_columns_by_name.find(morph._base) == _columns_by_name.end()) {
775  gobj_cat.warning()
776  << "vertex format defines "
777  << *column->get_name() << " but does not define "
778  << *morph._base << "\n";
779  } else {
780  _morphs.push_back(morph);
781  }
782  }
783  }
784  break;
785 
786  default:
787  // Some other type of value we don't care about caching a pointer to.
788  break;
789  }
790  }
791 
792  _is_registered = true;
793 
794  get_array_info(InternalName::get_vertex(), _vertex_array_index,
795  _vertex_column);
796  get_array_info(InternalName::get_normal(), _normal_array_index,
797  _normal_column);
798  get_array_info(InternalName::get_color(), _color_array_index,
799  _color_column);
800 }
801 
802 /**
803  * Called internally when the format is unregistered.
804  */
805 void GeomVertexFormat::
806 do_unregister() {
807  nassertv(_is_registered);
808  _is_registered = false;
809 
810  _columns_by_name.clear();
811  _points.clear();
812  _vectors.clear();
813  _texcoords.clear();
814  _morphs.clear();
815 
816  if (_post_animated_format != nullptr &&
817  _post_animated_format != this) {
818  unref_delete(_post_animated_format);
819  }
820  _post_animated_format = nullptr;
821 }
822 
823 /**
824  * Tells the BamReader how to create objects of type GeomVertexFormat.
825  */
828  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
829 }
830 
831 /**
832  * Writes the contents of this object to the datagram for shipping out to a
833  * Bam file.
834  */
838 
839  _animation.write_datagram(manager, dg);
840 
841  dg.add_uint16(_arrays.size());
842  Arrays::const_iterator ai;
843  for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
844  manager->write_pointer(dg, *ai);
845  }
846 }
847 
848 /**
849  * Receives an array of pointers, one for each time manager->read_pointer()
850  * was called in fillin(). Returns the number of pointers processed.
851  */
854  int pi = TypedWritableReferenceCount::complete_pointers(p_list, manager);
855 
856  Arrays::iterator ai;
857  for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
858  (*ai) = DCAST(GeomVertexArrayFormat, p_list[pi++]);
859  }
860 
861  return pi;
862 }
863 
864 /**
865  * This function is called by the BamReader's factory when a new object of
866  * type GeomVertexFormat is encountered in the Bam file. It should create the
867  * GeomVertexFormat and extract its information from the file.
868  */
869 TypedWritable *GeomVertexFormat::
870 make_from_bam(const FactoryParams &params) {
871  GeomVertexFormat *object = new GeomVertexFormat;
872  DatagramIterator scan;
873  BamReader *manager;
874 
875  parse_params(params, scan, manager);
876  object->fillin(scan, manager);
877 
878  return object;
879 }
880 
881 /**
882  * This internal function is called by make_from_bam to read in all of the
883  * relevant data from the BamFile for the new GeomVertexFormat.
884  */
885 void GeomVertexFormat::
886 fillin(DatagramIterator &scan, BamReader *manager) {
888 
889  _animation.fillin(scan, manager);
890 
891  int num_arrays = scan.get_uint16();
892  _arrays.reserve(num_arrays);
893  for (int i = 0; i < num_arrays; i++) {
894  manager->read_pointer(scan);
895  _arrays.push_back(nullptr);
896  }
897 }
898 
899 /**
900  *
901  */
902 GeomVertexFormat::Registry::
903 Registry() {
904 }
905 
906 /**
907  *
908  */
909 void GeomVertexFormat::Registry::
910 make_standard_formats() {
911  _empty = register_format(new GeomVertexFormat);
912 
913  _v3 = register_format(new GeomVertexArrayFormat
914  (InternalName::get_vertex(), 3,
915  NT_stdfloat, C_point));
916 
917  _v3n3 = register_format(new GeomVertexArrayFormat
918  (InternalName::get_vertex(), 3,
919  NT_stdfloat, C_point,
920  InternalName::get_normal(), 3,
921  NT_stdfloat, C_normal));
922 
923  _v3t2 = register_format(new GeomVertexArrayFormat
924  (InternalName::get_vertex(), 3,
925  NT_stdfloat, C_point,
926  InternalName::get_texcoord(), 2,
927  NT_stdfloat, C_texcoord));
928 
929  _v3n3t2 = register_format(new GeomVertexArrayFormat
930  (InternalName::get_vertex(), 3,
931  NT_stdfloat, C_point,
932  InternalName::get_normal(), 3,
933  NT_stdfloat, C_normal,
934  InternalName::get_texcoord(), 2,
935  NT_stdfloat, C_texcoord));
936 
937  // Define the DirectX-style packed color formats
938  _v3cp = register_format(new GeomVertexArrayFormat
939  (InternalName::get_vertex(), 3,
940  NT_stdfloat, C_point,
941  InternalName::get_color(), 1,
942  NT_packed_dabc, C_color));
943 
944  _v3n3cp = register_format(new GeomVertexArrayFormat
945  (InternalName::get_vertex(), 3,
946  NT_stdfloat, C_point,
947  InternalName::get_normal(), 3,
948  NT_stdfloat, C_normal,
949  InternalName::get_color(), 1,
950  NT_packed_dabc, C_color));
951 
952  _v3cpt2 = register_format(new GeomVertexArrayFormat
953  (InternalName::get_vertex(), 3,
954  NT_stdfloat, C_point,
955  InternalName::get_color(), 1,
956  NT_packed_dabc, C_color,
957  InternalName::get_texcoord(), 2,
958  NT_stdfloat, C_texcoord));
959 
960  _v3n3cpt2 = register_format(new GeomVertexArrayFormat
961  (InternalName::get_vertex(), 3,
962  NT_stdfloat, C_point,
963  InternalName::get_normal(), 3,
964  NT_stdfloat, C_normal,
965  InternalName::get_color(), 1,
966  NT_packed_dabc, C_color,
967  InternalName::get_texcoord(), 2,
968  NT_stdfloat, C_texcoord));
969 
970  // Define the OpenGL-style per-byte color formats. This is not the same as
971  // a packed format, above, because the resulting byte order is endian-
972  // independent.
973  _v3c4 = register_format(new GeomVertexArrayFormat
974  (InternalName::get_vertex(), 3,
975  NT_stdfloat, C_point,
976  InternalName::get_color(), 4,
977  NT_uint8, C_color));
978 
979  _v3n3c4 = register_format(new GeomVertexArrayFormat
980  (InternalName::get_vertex(), 3,
981  NT_stdfloat, C_point,
982  InternalName::get_normal(), 3,
983  NT_stdfloat, C_normal,
984  InternalName::get_color(), 4,
985  NT_uint8, C_color));
986 
987  _v3c4t2 = register_format(new GeomVertexArrayFormat
988  (InternalName::get_vertex(), 3,
989  NT_stdfloat, C_point,
990  InternalName::get_color(), 4,
991  NT_uint8, C_color,
992  InternalName::get_texcoord(), 2,
993  NT_stdfloat, C_texcoord));
994 
995  _v3n3c4t2 = register_format(new GeomVertexArrayFormat
996  (InternalName::get_vertex(), 3,
997  NT_stdfloat, C_point,
998  InternalName::get_normal(), 3,
999  NT_stdfloat, C_normal,
1000  InternalName::get_color(), 4,
1001  NT_uint8, C_color,
1002  InternalName::get_texcoord(), 2,
1003  NT_stdfloat, C_texcoord));
1004 }
1005 
1006 /**
1007  * Adds the indicated format to the registry, if there is not an equivalent
1008  * format already there; in either case, returns the pointer to the equivalent
1009  * format now in the registry.
1010  *
1011  * This must be called before a format may be used in a Geom. After this
1012  * call, you should discard the original pointer you passed in (which may or
1013  * may not now be invalid) and let its reference count decrement normally; you
1014  * should use only the returned value from this point on.
1015  */
1016 CPT(GeomVertexFormat) GeomVertexFormat::Registry::
1017 register_format(GeomVertexFormat *format) {
1018  if (format->is_registered()) {
1019  return format;
1020  }
1021 
1022  // Save the incoming pointer in a local PointerTo, so that if it has a zero
1023  // reference count and is not added into the map below, it will be
1024  // automatically deleted when this function returns.
1025  PT(GeomVertexFormat) pt_format = format;
1026 
1027  GeomVertexFormat *new_format;
1028  {
1029  LightReMutexHolder holder(_lock);
1030  Formats::iterator fi = _formats.insert(format).first;
1031  new_format = (*fi);
1032  if (!new_format->is_registered()) {
1033  new_format->do_register();
1034  }
1035  }
1036 
1037  return new_format;
1038 }
1039 
1040 /**
1041  * Removes the indicated format from the registry. Normally this should not
1042  * be done until the format is destructing.
1043  *
1044  * The lock should be held prior to calling this method.
1045  */
1046 void GeomVertexFormat::Registry::
1047 unregister_format(GeomVertexFormat *format) {
1048  nassertv(format->is_registered());
1049  Formats::iterator fi = _formats.find(format);
1050  nassertv(fi != _formats.end());
1051  _formats.erase(fi);
1052  format->do_unregister();
1053 }
get_num_columns
Returns the number of different columns in the array.
get_ref_count
Returns the current reference count.
remove_array
Removes the nth array from the format.
get_animation
Returns the GeomVertexAnimationSpec that indicates how this format's vertices are set up for animatio...
insert_array
Adds the indicated array definition to the list of arrays at the indicated position.
Contents get_contents() const
Returns the token representing the semantic meaning of the stored value.
set_animation
Resets the GeomVertexAnimationSpec that indicates how this format's vertices are set up for animation...
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
NumericType get_numeric_type() const
Returns the token representing the numeric type of the data storage.
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
is_registered
Returns true if this format has been registered, false if it has not.
set_array
Replaces the definition of the indicated array.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void remove_column(const InternalName *name)
Removes the column with the indicated name, if any.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
This data object is returned by GeomVertexArrayData::get_handle() or modify_handle().
virtual void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is intended to be called by each class's make_from_bam() method to read in all...
void maybe_align_columns_for_animation()
Calls align_columns_for_animation() if this format's AnimationSpec indicates that it contains animate...
This defines how a single column is interleaved within a vertex array stored within a Geom.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
is_registered
Returns true if this format has been registered, false if it has not.
void parse_params(const FactoryParams &params, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
Definition: bamReader.I:275
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
void remove_column(const InternalName *name, bool keep_empty_array=false)
Removes the named column from the format, from whichever array it exists in.
static void register_with_read_factory()
Tells the BamReader how to create objects of type GeomVertexFormat.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
bool get_array_info(const InternalName *name, int &array_index, const GeomVertexColumn *&column) const
Quickly looks up the indicated column within all of the nested arrays and sets array_index and column...
const InternalName * get_ancestor(int n) const
Returns the ancestor with the indicated index number.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
get_column
Returns the ith column of the specification, across all arrays.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:73
int get_array_with(size_t i) const
Returns the index number of the array with the ith column.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Similar to MutexHolder, but for a light reentrant mutex.
Encodes a string name in a hash table, mapping it to a pointer.
Definition: internalName.h:38
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_column_name
Returns the name of the ith column, across all arrays.
This class defines the physical layout of the vertex data stored within a Geom.
void clear_arrays()
Removes all of the array definitions from the format and starts over.
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
get_stride
Returns the total number of bytes reserved in the array for each vertex.
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
int find_ancestor(const std::string &basename) const
Returns the index of the ancestor with the indicated basename, or -1 if no ancestor has that basename...
This describes the structure of a single array within a Geom data.
virtual bool unref() const
This method overrides ReferenceCount::unref() to unregister the object when its reference count goes ...
size_t add_array(const GeomVertexArrayFormat *array_format)
Adds the indicated array definition to the list of arrays included within this vertex format definiti...
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
A class to retrieve the individual data elements previously stored in a Datagram.
const InternalName * get_name() const
Returns the name of this particular data field, e.g.
int get_total_bytes() const
Returns the number of bytes used by each element of the column: component_bytes * num_components.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
void align_columns_for_animation()
Reprocesses the columns in the format to align the C_point and C_vector columns to 16-byte boundaries...
int get_num_components() const
Returns the number of components of the column: the number of instances of the NumericType in each el...
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
void unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...
get_column
Returns the specification with the indicated name, or NULL if the name is not used.
void remove_empty_arrays()
Removes the arrays that define no columns.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void pack_columns()
Removes wasted space between columns.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool unref() const
Explicitly decrements the reference count.
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
Definition: bamWriter.cxx:317
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int compare_to(const GeomVertexColumn &other) const
This is used to unquify columns, and hence formats, for the GeomVertexFormat registry.