Panda3D
geomVertexArrayFormat.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 geomVertexArrayFormat.cxx
10  * @author drose
11  * @date 2005-03-06
12  */
13 
14 #include "geomVertexFormat.h"
15 #include "geomVertexColumn.h"
16 #include "geomVertexData.h"
17 #include "geomVertexReader.h"
18 #include "indent.h"
19 #include "bamReader.h"
20 #include "bamWriter.h"
21 #include "indirectLess.h"
22 #include "lightMutexHolder.h"
23 
24 using std::max;
25 using std::min;
26 using std::move;
27 
28 GeomVertexArrayFormat::Registry *GeomVertexArrayFormat::_registry = nullptr;
29 TypeHandle GeomVertexArrayFormat::_type_handle;
30 
31 /**
32  *
33  */
34 GeomVertexArrayFormat::
35 GeomVertexArrayFormat() :
36  _is_registered(false),
37  _stride(0),
38  _total_bytes(0),
39  _pad_to(1),
40  _divisor(0),
41  _columns_unsorted(false)
42 {
43 }
44 
45 /**
46  *
47  */
48 GeomVertexArrayFormat::
49 GeomVertexArrayFormat(CPT_InternalName name0, int num_components0,
50  GeomVertexArrayFormat::NumericType numeric_type0,
51  GeomVertexArrayFormat::Contents contents0) :
52  _is_registered(false),
53  _stride(0),
54  _total_bytes(0),
55  _pad_to(1),
56  _divisor(0),
57  _columns_unsorted(false)
58 {
59  add_column(move(name0), num_components0, numeric_type0, contents0);
60 }
61 
62 /**
63  *
64  */
65 GeomVertexArrayFormat::
66 GeomVertexArrayFormat(CPT_InternalName name0, int num_components0,
67  GeomVertexArrayFormat::NumericType numeric_type0,
68  GeomVertexArrayFormat::Contents contents0,
69  CPT_InternalName name1, int num_components1,
70  GeomVertexArrayFormat::NumericType numeric_type1,
71  GeomVertexArrayFormat::Contents contents1) :
72  _is_registered(false),
73  _stride(0),
74  _total_bytes(0),
75  _pad_to(1),
76  _divisor(0),
77  _columns_unsorted(false)
78 {
79  add_column(move(name0), num_components0, numeric_type0, contents0);
80  add_column(move(name1), num_components1, numeric_type1, contents1);
81 }
82 
83 /**
84  *
85  */
86 GeomVertexArrayFormat::
87 GeomVertexArrayFormat(CPT_InternalName name0, int num_components0,
88  GeomVertexArrayFormat::NumericType numeric_type0,
89  GeomVertexArrayFormat::Contents contents0,
90  CPT_InternalName name1, int num_components1,
91  GeomVertexArrayFormat::NumericType numeric_type1,
92  GeomVertexArrayFormat::Contents contents1,
93  CPT_InternalName name2, int num_components2,
94  GeomVertexArrayFormat::NumericType numeric_type2,
95  GeomVertexArrayFormat::Contents contents2) :
96  _is_registered(false),
97  _stride(0),
98  _total_bytes(0),
99  _pad_to(1),
100  _divisor(0),
101  _columns_unsorted(false)
102 {
103  add_column(move(name0), num_components0, numeric_type0, contents0);
104  add_column(move(name1), num_components1, numeric_type1, contents1);
105  add_column(move(name2), num_components2, numeric_type2, contents2);
106 }
107 
108 /**
109  *
110  */
111 GeomVertexArrayFormat::
112 GeomVertexArrayFormat(CPT_InternalName name0, int num_components0,
113  GeomVertexArrayFormat::NumericType numeric_type0,
114  GeomVertexArrayFormat::Contents contents0,
115  CPT_InternalName name1, int num_components1,
116  GeomVertexArrayFormat::NumericType numeric_type1,
117  GeomVertexArrayFormat::Contents contents1,
118  CPT_InternalName name2, int num_components2,
119  GeomVertexArrayFormat::NumericType numeric_type2,
120  GeomVertexArrayFormat::Contents contents2,
121  CPT_InternalName name3, int num_components3,
122  GeomVertexArrayFormat::NumericType numeric_type3,
123  GeomVertexArrayFormat::Contents contents3) :
124  _is_registered(false),
125  _stride(0),
126  _total_bytes(0),
127  _pad_to(1),
128  _divisor(0),
129  _columns_unsorted(false)
130 {
131  add_column(move(name0), num_components0, numeric_type0, contents0);
132  add_column(move(name1), num_components1, numeric_type1, contents1);
133  add_column(move(name2), num_components2, numeric_type2, contents2);
134  add_column(move(name3), num_components3, numeric_type3, contents3);
135 }
136 
137 /**
138  *
139  */
140 GeomVertexArrayFormat::
141 GeomVertexArrayFormat(const GeomVertexArrayFormat &copy) :
142  _is_registered(false),
143  _stride(copy._stride),
144  _total_bytes(copy._total_bytes),
145  _pad_to(copy._pad_to),
146  _divisor(copy._divisor),
147  _columns_unsorted(copy._columns_unsorted)
148 {
149  Columns::const_iterator dti;
150  for (dti = copy._columns.begin(); dti != copy._columns.end(); ++dti) {
151  add_column(*(*dti));
152  }
153 }
154 
155 /**
156  *
157  */
158 void GeomVertexArrayFormat::
159 operator = (const GeomVertexArrayFormat &copy) {
160  nassertv(!_is_registered);
161  _stride = copy._stride;
162  _total_bytes = copy._total_bytes;
163  _pad_to = copy._pad_to;
164  _divisor = copy._divisor;
165 
166  _columns.clear();
167  _columns_by_name.clear();
168  _columns_unsorted = false;
169  Columns::const_iterator dti;
170  for (dti = copy._columns.begin(); dti != copy._columns.end(); ++dti) {
171  add_column(*(*dti));
172  }
173 }
174 
175 /**
176  *
177  */
178 GeomVertexArrayFormat::
179 ~GeomVertexArrayFormat() {
180  // unref() should have unregistered us.
181  nassertv(!is_registered());
182 
183  Columns::iterator ci;
184  for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
185  delete (*ci);
186  }
187 }
188 
189 /**
190  * This method overrides ReferenceCount::unref() to unregister the object when
191  * its reference count goes to zero.
192  */
194 unref() const {
195  Registry *registry = get_registry();
196  LightMutexHolder holder(registry->_lock);
197 
198  if (ReferenceCount::unref()) {
199  return true;
200  }
201 
202  if (is_registered()) {
203  registry->unregister_format((GeomVertexArrayFormat *)this);
204  }
205 
206  return false;
207 }
208 
209 /**
210  * Adds a new column to the specification. This is a table of per-vertex
211  * floating-point numbers such as "vertex" or "normal"; you must specify where
212  * in each record the table starts, and how many components (dimensions) exist
213  * per vertex.
214  *
215  * The return value is the index number of the new data type.
216  */
218 add_column(CPT_InternalName name, int num_components,
219  GeomVertexArrayFormat::NumericType numeric_type,
220  GeomVertexArrayFormat::Contents contents, int start,
221  int column_alignment) {
222  if (start < 0) {
223  start = _total_bytes;
224  }
225 
226  return add_column(GeomVertexColumn(move(name), num_components, numeric_type, contents,
227  start, column_alignment));
228 }
229 
230 /**
231  * Adds a new column to the specification. This is a table of per-vertex
232  * floating-point numbers such as "vertex" or "normal"; you must specify where
233  * in each record the table starts, and how many components (dimensions) exist
234  * per vertex.
235  *
236  * Adding a column with the same name as a previous type, or that overlaps
237  * with one or more previous types, quietly removes the previous type(s).
238  *
239  * The return value is the index number of the new data type.
240  */
242 add_column(const GeomVertexColumn &column) {
243  nassertr(!_is_registered, -1);
244 
245  // Make sure there isn't already a column with this name.
246  remove_column(column.get_name());
247 
248  // Also make sure there aren't any columns that overlap with this one.
249  const GeomVertexColumn *orig_column = get_column(column.get_start(), column.get_total_bytes());
250  while (orig_column != nullptr) {
251  remove_column(orig_column->get_name());
252  orig_column = get_column(column.get_start(), column.get_total_bytes());
253  }
254 
255  _total_bytes = max(_total_bytes, column.get_start() + column.get_total_bytes());
256  _pad_to = max(_pad_to, column.get_column_alignment());
257  _stride = max(_stride, _total_bytes);
258  if (_pad_to > 1) {
259  _stride = ((_stride + _pad_to - 1) / _pad_to) * _pad_to;
260  }
261 
262  GeomVertexColumn *new_column = new GeomVertexColumn(column);
263 
264  if (!_columns.empty() && *new_column < *_columns.back()) {
265  _columns_unsorted = true;
266  }
267 
268  int new_index = (int)_columns.size();
269  _columns.push_back(new_column);
270  _columns_by_name.insert(ColumnsByName::value_type(new_column->get_name(), new_column));
271 
272  return new_index;
273 }
274 
275 /**
276  * Removes the column with the indicated name, if any. This leaves a gap in
277  * the byte structure.
278  */
281  nassertv(!_is_registered);
282  ColumnsByName::iterator ni;
283  ni = _columns_by_name.find(name);
284  if (ni != _columns_by_name.end()) {
285  GeomVertexColumn *column = (*ni).second;
286  _columns_by_name.erase(ni);
287 
288  Columns::iterator ci;
289  ci = find(_columns.begin(), _columns.end(), column);
290  nassertv(ci != _columns.end());
291  _columns.erase(ci);
292 
293  delete column;
294 
295  // Maybe we just removed the tail column. If that's so, we should
296  // recompute _total_bytes to reflect the new tail.
297  if (_columns.empty()) {
298  _total_bytes = 0;
299  } else {
300  consider_sort_columns();
301  GeomVertexColumn *last = _columns.back();
302  _total_bytes = last->get_start() + last->get_total_bytes();
303  }
304  }
305 }
306 
307 /**
308  * Removes all columns previously added, sets the stride to zero, and prepares
309  * to start over.
310  */
313  nassertv(!_is_registered);
314 
315  _columns.clear();
316  _columns_by_name.clear();
317  _columns_unsorted = false;
318  _stride = 0;
319  _total_bytes = 0;
320  _pad_to = 1;
321 }
322 
323 /**
324  * Removes wasted space between columns.
325  */
328  nassertv(!_is_registered);
329 
330  Columns orig_columns;
331  orig_columns.swap(_columns);
332  clear_columns();
333 
334  Columns::const_iterator ci;
335  for (ci = orig_columns.begin(); ci != orig_columns.end(); ++ci) {
336  GeomVertexColumn *column = (*ci);
337  add_column(column->get_name(), column->get_num_components(),
338  column->get_numeric_type(), column->get_contents());
339  }
340 }
341 
342 /**
343  * Reprocesses the columns in the format to align the C_point and C_vector
344  * columns to 16-byte boundaries to allow for the more efficient SSE2
345  * operations (assuming SSE2 is enabled in the build).
346  *
347  * The caller is responsible for testing vertex_animation_align_16 to decide
348  * whether to call this method.
349  */
352  nassertv(!_is_registered);
353 
354  Columns orig_columns;
355  orig_columns.swap(_columns);
356  clear_columns();
357 
358  Columns::const_iterator ci;
359  for (ci = orig_columns.begin(); ci != orig_columns.end(); ++ci) {
360  GeomVertexColumn *column = (*ci);
361  if ((column->get_contents() == C_point ||
362  column->get_contents() == C_vector ||
363  column->get_contents() == C_normal) &&
364  (column->get_numeric_type() == NT_float32 ||
365  column->get_numeric_type() == NT_float64) &&
366  column->get_num_components() >= 3) {
367  add_column(column->get_name(), 4, column->get_numeric_type(), column->get_contents(), -1, 16);
368  } else {
369  add_column(column->get_name(), column->get_num_components(),
370  column->get_numeric_type(), column->get_contents(),
371  -1, column->get_column_alignment());
372  }
373  }
374 }
375 
376 
377 /**
378  * Returns the specification with the indicated name, or NULL if the name is
379  * not used.
380  */
382 get_column(const InternalName *name) const {
383  ColumnsByName::const_iterator ni;
384  ni = _columns_by_name.find(name);
385  if (ni != _columns_by_name.end()) {
386  return (*ni).second;
387  }
388  return nullptr;
389 }
390 
391 /**
392  * Returns the first specification that overlaps with any of the indicated
393  * bytes in the range, or NULL if none do.
394  */
396 get_column(int start_byte, int num_bytes) const {
397  consider_sort_columns();
398  Columns::const_iterator ci;
399  for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
400  const GeomVertexColumn *column = (*ci);
401  if (column->overlaps_with(start_byte, num_bytes)) {
402  return column;
403  }
404  }
405 
406  return nullptr;
407 }
408 
409 /**
410  * Returns true if all of the fields in this array format are also present and
411  * equivalent in the other array format, and in the same byte positions, and
412  * the stride is the same. That is, true if this format can share the same
413  * data pointer as the other format (with possibly some unused gaps).
414  */
417  if (_columns.size() > other._columns.size() ||
418  get_stride() != other.get_stride()) {
419  return false;
420  }
421 
422  consider_sort_columns();
423  other.consider_sort_columns();
424  size_t i = 0;
425  size_t j = 0;
426  while (i < _columns.size() && j < other._columns.size()) {
427  if (*_columns[i] == *other._columns[j]) {
428  ++i;
429  }
430  ++j;
431  }
432 
433  // If we reached the end of our list, all fields matched.
434  return (i == _columns.size());
435 }
436 
437 /**
438  * Returns the number of bytes per row that are not assigned to any column.
439  */
442  consider_sort_columns();
443 
444  int unused_space = 0;
445  int last_pos = 0;
446 
447  Columns::const_iterator ci;
448  for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
449  const GeomVertexColumn *column = (*ci);
450  if (column->get_start() > last_pos) {
451  unused_space += (column->get_start() - last_pos);
452  }
453  last_pos = column->get_start() + column->get_total_bytes();
454  }
455 
456  if (_stride > last_pos) {
457  unused_space += (_stride - last_pos);
458  }
459 
460  return unused_space;
461 }
462 
463 /**
464  *
465  */
466 void GeomVertexArrayFormat::
467 output(std::ostream &out) const {
468  Columns::const_iterator ci;
469  int last_pos = 0;
470  out << "[";
471  for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
472  const GeomVertexColumn *column = (*ci);
473  if (column->get_start() > last_pos) {
474  out << " (..." << (column->get_start() - last_pos) << "...)";
475  }
476  out << " " << *column;
477  last_pos = column->get_start() + column->get_total_bytes();
478  }
479 
480  if (_stride > last_pos) {
481  out << " ..." << (_stride - last_pos) << "...";
482  }
483 
484  out << " ]";
485 }
486 
487 /**
488  *
489  */
490 void GeomVertexArrayFormat::
491 write(std::ostream &out, int indent_level) const {
492  indent(out, indent_level)
493  << "Array format (stride = " << get_stride() << "):\n";
494  consider_sort_columns();
495  Columns::const_iterator ci;
496  for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
497  const GeomVertexColumn *column = (*ci);
498  indent(out, indent_level + 2)
499  << *column
500  << " " << column->get_numeric_type()
501  << " " << column->get_contents()
502  << " start at " << column->get_start() << "\n";
503  }
504 }
505 
506 /**
507  *
508  */
509 void GeomVertexArrayFormat::
510 write_with_data(std::ostream &out, int indent_level,
511  const GeomVertexArrayData *array_data) const {
512  consider_sort_columns();
513  int num_rows = array_data->get_num_rows();
514 
515  GeomVertexReader reader(array_data);
516 
517  for (int i = 0; i < num_rows; i++) {
518  indent(out, indent_level)
519  << "row " << i << ":\n";
520  reader.set_row_unsafe(i);
521  Columns::const_iterator ci;
522  for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
523  const GeomVertexColumn *column = (*ci);
524  int num_values = min(column->get_num_values(), 4);
525  reader.set_column(0, column);
526  const LVecBase4f &d = reader.get_data4f();
527 
528  indent(out, indent_level + 2)
529  << *column->get_name();
530  for (int v = 0; v < num_values; v++) {
531  out << " " << d[v];
532  }
533  out << "\n";
534  }
535  }
536 }
537 
538 /**
539  * Returns a string with format codes representing the exact memory layout of
540  * the columns in memory, as understood by Python's struct module. If pad is
541  * true, extra padding bytes are added to the end as 'x' characters as needed.
542  */
543 std::string GeomVertexArrayFormat::
544 get_format_string(bool pad) const {
545  consider_sort_columns();
546 
547  int row_size;
548  if (pad) {
549  row_size = get_stride();
550  } else {
551  row_size = get_total_bytes();
552  }
553 
554  // Synthesize the format string.
555  char *fmt = (char*) malloc(row_size + 1);
556  memset((void*) fmt, 0, row_size + 1);
557  int fi = 0;
558  int offset = 0;
559 
560  for (const GeomVertexColumn *column : _columns) {
561  if (offset < column->get_start()) {
562  // Add padding bytes to fill the gap.
563  int pad = column->get_start() - offset;
564  memset((void*) (fmt + fi), 'x', pad);
565  fi += pad;
566  offset += pad;
567  }
568 
569  char fmt_code = 'x';
570  switch (column->get_numeric_type()) {
571  case NT_uint8:
572  fmt_code = 'B';
573  break;
574 
575  case NT_uint16:
576  fmt_code = 'H';
577  break;
578 
579  case NT_uint32:
580  case NT_packed_dcba:
581  case NT_packed_dabc:
582  fmt_code = 'I';
583  break;
584 
585  case NT_float32:
586  fmt_code = 'f';
587  break;
588 
589  case NT_float64:
590  fmt_code = 'd';
591  break;
592 
593  case NT_int8:
594  fmt_code = 'b';
595  break;
596 
597  case NT_int16:
598  fmt_code = 'h';
599  break;
600 
601  case NT_int32:
602  fmt_code = 'i';
603  break;
604 
605  default:
606  gobj_cat.error()
607  << "Unknown numeric type " << column->get_numeric_type() << "!\n";
608  return nullptr;
609  }
610  memset((void*) (fmt + fi), fmt_code, column->get_num_components());
611  offset += column->get_total_bytes();
612  fi += column->get_num_components();
613  }
614 
615  if (offset < row_size) {
616  // Add padding bytes.
617  int pad = row_size - offset;
618  memset((void*) (fmt + fi), 'x', pad);
619  }
620 
621  std::string fmt_string (fmt);
622  free(fmt);
623  return fmt_string;
624 }
625 
626 /**
627  *
628  */
629 int GeomVertexArrayFormat::
630 compare_to(const GeomVertexArrayFormat &other) const {
631  if (_stride != other._stride) {
632  return _stride - other._stride;
633  }
634  if (_total_bytes != other._total_bytes) {
635  return _total_bytes - other._total_bytes;
636  }
637  if (_pad_to != other._pad_to) {
638  return _pad_to - other._pad_to;
639  }
640  if (_divisor != other._divisor) {
641  return _divisor - other._divisor;
642  }
643  if (_columns.size() != other._columns.size()) {
644  return (int)_columns.size() - (int)other._columns.size();
645  }
646  consider_sort_columns();
647  other.consider_sort_columns();
648  for (size_t i = 0; i < _columns.size(); i++) {
649  int compare = _columns[i]->compare_to(*other._columns[i]);
650  if (compare != 0) {
651  return compare;
652  }
653  }
654 
655  return 0;
656 }
657 
658 /**
659  * Resorts the _columns vector so that the columns are listed in the same
660  * order they appear in the record.
661  */
662 void GeomVertexArrayFormat::
663 sort_columns() {
664  sort(_columns.begin(), _columns.end(), IndirectLess<GeomVertexColumn>());
665 }
666 
667 /**
668  * Returns the global registry object.
669  */
670 void GeomVertexArrayFormat::
671 make_registry() {
672  if (_registry == nullptr) {
673  _registry = new Registry;
674  }
675 }
676 
677 /**
678  * Called internally when the format is registered.
679  */
680 void GeomVertexArrayFormat::
681 do_register() {
682  nassertv(!_is_registered);
683  _is_registered = true;
684 }
685 
686 /**
687  * Called internally when the format is unregistered.
688  */
689 void GeomVertexArrayFormat::
690 do_unregister() {
691  nassertv(_is_registered);
692  _is_registered = false;
693 }
694 
695 /**
696  * Tells the BamReader how to create objects of type GeomVertexArrayFormat.
697  */
700  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
701 }
702 
703 /**
704  * Writes the contents of this object to the datagram for shipping out to a
705  * Bam file.
706  */
710 
711  dg.add_uint16(_stride);
712  dg.add_uint16(_total_bytes);
713  dg.add_uint8(_pad_to);
714 
715  if (manager->get_file_minor_ver() > 36) {
716  dg.add_uint16(_divisor);
717  }
718 
719  consider_sort_columns();
720 
721  dg.add_uint16(_columns.size());
722  Columns::iterator ci;
723  for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
724  GeomVertexColumn *column = (*ci);
725  column->write_datagram(manager, dg);
726  }
727 }
728 
729 /**
730  * Receives an array of pointers, one for each time manager->read_pointer()
731  * was called in fillin(). Returns the number of pointers processed.
732  */
735  int pi = TypedWritableReferenceCount::complete_pointers(p_list, manager);
736 
737  Columns::iterator ci;
738  for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
739  GeomVertexColumn *column = (*ci);
740  pi += column->complete_pointers(p_list + pi, manager);
741  }
742 
743  return pi;
744 }
745 
746 /**
747  * Called by the BamReader to perform any final actions needed for setting up
748  * the object after all objects have been read and all pointers have been
749  * completed.
750  */
752 finalize(BamReader *manager) {
753  // Now we can build up the _columns_by_name index. We have to wait until
754  // finalize(), since the index is based on the nested name pointer within
755  // each column, which might not be available at the time complete_pointers()
756  // is called.
757  _columns_by_name.clear();
758  Columns::iterator ci;
759  for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
760  GeomVertexColumn *column = (*ci);
761  _columns_by_name.insert(ColumnsByName::value_type(column->get_name(), column));
762  }
763 }
764 
765 /**
766  * This function is called by the BamReader's factory when a new object of
767  * type GeomVertexArrayFormat is encountered in the Bam file. It should
768  * create the GeomVertexArrayFormat and extract its information from the file.
769  */
770 TypedWritable *GeomVertexArrayFormat::
771 make_from_bam(const FactoryParams &params) {
773  DatagramIterator scan;
774  BamReader *manager;
775 
776  parse_params(params, scan, manager);
777  object->fillin(scan, manager);
778  manager->register_finalize(object);
779 
780  return object;
781 }
782 
783 /**
784  * This internal function is called by make_from_bam to read in all of the
785  * relevant data from the BamFile for the new GeomVertexArrayFormat.
786  */
787 void GeomVertexArrayFormat::
788 fillin(DatagramIterator &scan, BamReader *manager) {
790  nassertv(!_is_registered);
791 
792  _stride = scan.get_uint16();
793  _total_bytes = scan.get_uint16();
794  _pad_to = scan.get_uint8();
795  if (manager->get_file_minor_ver() > 36) {
796  _divisor = scan.get_uint16();
797  } else {
798  _divisor = 0;
799  }
800 
801  int num_columns = scan.get_uint16();
802  _columns.reserve(num_columns);
803  for (int i = 0; i < num_columns; ++i) {
804  GeomVertexColumn *column = new GeomVertexColumn;
805  column->fillin(scan, manager);
806  _columns.push_back(column);
807  }
808  _columns_unsorted = false;
809 }
810 
811 /**
812  *
813  */
814 GeomVertexArrayFormat::Registry::
815 Registry() {
816 }
817 
818 /**
819  * Adds the indicated format to the registry, if there is not an equivalent
820  * format already there; in either case, returns the pointer to the equivalent
821  * format now in the registry.
822  *
823  * This must be called before a format may be used in a Geom. After this
824  * call, you should discard the original pointer you passed in (which may or
825  * may not now be invalid) and let its reference count decrement normally; you
826  * should use only the returned value from this point on.
827  */
828 CPT(GeomVertexArrayFormat) GeomVertexArrayFormat::Registry::
829 register_format(GeomVertexArrayFormat *format) {
830  if (format->is_registered()) {
831  return format;
832  }
833 
834  // Save the incoming pointer in a local PointerTo, so that if it has a zero
835  // reference count and is not added into the map below, it will be
836  // automatically deleted when this function returns.
837  PT(GeomVertexArrayFormat) pt_format = format;
838 
839  GeomVertexArrayFormat *new_format;
840  {
841  LightMutexHolder holder(_lock);
842  ArrayFormats::iterator fi = _formats.insert(format).first;
843  new_format = (*fi);
844  if (!new_format->is_registered()) {
845  new_format->do_register();
846  }
847  }
848 
849  return new_format;
850 }
851 
852 /**
853  * Removes the indicated format from the registry. Normally this should not
854  * be done until the format is destructing.
855  *
856  * The lock should be held prior to calling this method.
857  */
858 void GeomVertexArrayFormat::Registry::
859 unregister_format(GeomVertexArrayFormat *format) {
860  nassertv(format->is_registered());
861  ArrayFormats::iterator fi = _formats.find(format);
862  nassertv(fi != _formats.end());
863  _formats.erase(fi);
864  format->do_unregister();
865 }
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
This is a const pointer to an InternalName, and should be used in lieu of a CPT(InternalName) in func...
Definition: internalName.h:193
bool overlaps_with(int start_byte, int num_bytes) const
Returns true if this column overlaps with any of the bytes in the indicated range,...
Contents get_contents() const
Returns the token representing the semantic meaning of the stored value.
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
virtual bool unref() const
This method overrides ReferenceCount::unref() to unregister the object when its reference count goes ...
void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is called by make_from_bam to read in all of the relevant data from the BamFil...
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.
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
void clear_columns()
Removes all columns previously added, sets the stride to zero, and prepares to start over.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int add_column(CPT_InternalName name, int num_components, NumericType numeric_type, Contents contents, int start=-1, int column_alignment=0)
Adds a new column to the specification.
is_registered
Returns true if this format has been registered, false if it has not.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being written.
Definition: bamWriter.I:59
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
void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:83
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...
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.
An STL function object class, this is intended to be used on any ordered collection of pointers to cl...
Definition: indirectLess.h:25
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
bool is_data_subset_of(const GeomVertexArrayFormat &other) const
Returns true if all of the fields in this array format are also present and equivalent in the other a...
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
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().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
Similar to MutexHolder, but for a light mutex.
get_total_bytes
Returns the total number of bytes used by the data types within the format, including gaps between el...
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
int get_num_values() const
Returns the number of numeric values of the column: the number of distinct numeric values that go int...
int get_column_alignment() const
Returns the alignment requirements for this column.
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
void register_finalize(TypedWritable *whom)
Should be called by an object reading itself from the Bam file to indicate that this particular objec...
Definition: bamReader.cxx:808
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void align_columns_for_animation()
Reprocesses the columns in the format to align the C_point and C_vector columns to 16-byte boundaries...
Encodes a string name in a hash table, mapping it to a pointer.
Definition: internalName.h:38
int get_start() const
Returns the byte within the array record at which this column starts.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_num_rows() const
Returns the number of rows stored in the array, based on the number of bytes and the stride.
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.
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
This describes the structure of a single array within a Geom data.
std::string get_format_string(bool pad=true) const
Returns a string with format codes representing the exact memory layout of the columns in memory,...
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:50
int count_unused_space() const
Returns the number of bytes per row that are not assigned to any column.
static void register_with_read_factory()
Tells the BamReader how to create objects of type GeomVertexArrayFormat.
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.
void pack_columns()
Removes wasted space between columns.
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
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
int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
get_column
Returns the specification with the indicated name, or NULL if the name is not used.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CPT(GeomVertexArrayFormat) GeomVertexArrayFormat
Adds the indicated format to the registry, if there is not an equivalent format already there; in eit...
virtual bool unref() const
Explicitly decrements the reference count.
This is the data for one array of a GeomVertexData structure.
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.