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  */
280 remove_column(const InternalName *name) {
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  */
312 clear_columns() {
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  */
327 pack_columns() {
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  */
416 is_data_subset_of(const GeomVertexArrayFormat &other) const {
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  */
441 count_unused_space() const {
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  */
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  */
708 write_datagram(BamWriter *manager, Datagram &dg) {
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  */
734 complete_pointers(TypedWritable **p_list, BamReader *manager) {
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 }
geomVertexData.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexArrayFormat::is_registered
is_registered
Returns true if this format has been registered, false if it has not.
Definition: geomVertexArrayFormat.h:78
LightMutexHolder
Similar to MutexHolder, but for a light mutex.
Definition: lightMutexHolder.h:25
indent
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
GeomVertexColumn::get_start
int get_start() const
Returns the byte within the array record at which this column starts.
Definition: geomVertexColumn.I:133
GeomVertexArrayData
This is the data for one array of a GeomVertexData structure.
Definition: geomVertexArrayData.h:58
GeomVertexArrayFormat::unref
virtual bool unref() const
This method overrides ReferenceCount::unref() to unregister the object when its reference count goes ...
Definition: geomVertexArrayFormat.cxx:194
GeomVertexColumn::get_column_alignment
int get_column_alignment() const
Returns the alignment requirements for this column.
Definition: geomVertexColumn.I:144
DatagramIterator::get_uint16
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
Definition: datagramIterator.I:145
GeomVertexArrayFormat::remove_column
void remove_column(const InternalName *name)
Removes the column with the indicated name, if any.
Definition: geomVertexArrayFormat.cxx:280
pvector< GeomVertexColumn * >
GeomVertexColumn::get_num_values
int get_num_values() const
Returns the number of numeric values of the column: the number of distinct numeric values that go int...
Definition: geomVertexColumn.I:99
GeomVertexArrayFormat::get_column
get_column
Returns the specification with the indicated name, or NULL if the name is not used.
Definition: geomVertexArrayFormat.h:106
Datagram::add_uint8
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:50
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
geomVertexReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexArrayFormat::add_column
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.
Definition: geomVertexArrayFormat.cxx:218
TypedWritable::complete_pointers
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().
Definition: typedWritable.cxx:81
BamReader
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
GeomVertexArrayFormat::is_data_subset_of
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...
Definition: geomVertexArrayFormat.cxx:416
indirectLess.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexArrayFormat::write_datagram
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: geomVertexArrayFormat.cxx:708
BamWriter
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
InternalName
Encodes a string name in a hash table, mapping it to a pointer.
Definition: internalName.h:38
GeomVertexReader
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
Definition: geomVertexReader.h:47
BamReader::get_factory
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
GeomVertexArrayFormat::clear_columns
void clear_columns()
Removes all columns previously added, sets the stride to zero, and prepares to start over.
Definition: geomVertexArrayFormat.cxx:312
GeomVertexArrayFormat::get_total_bytes
get_total_bytes
Returns the total number of bytes used by the data types within the format, including gaps between el...
Definition: geomVertexArrayFormat.h:93
bamReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypedWritable
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
GeomVertexArrayFormat::get_format_string
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,...
Definition: geomVertexArrayFormat.cxx:544
IndirectLess
An STL function object class, this is intended to be used on any ordered collection of pointers to cl...
Definition: indirectLess.h:25
BamWriter::get_file_minor_ver
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being written.
Definition: bamWriter.I:59
geomVertexColumn.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
Datagram::add_uint16
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
BamReader::register_finalize
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
FactoryParams
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
GeomVertexArrayData::get_num_rows
int get_num_rows() const
Returns the number of rows stored in the array, based on the number of bytes and the stride.
Definition: geomVertexArrayData.I:47
lightMutexHolder.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypedWritable::write_datagram
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: typedWritable.cxx:54
CPT_InternalName
This is a const pointer to an InternalName, and should be used in lieu of a CPT(InternalName) in func...
Definition: internalName.h:193
GeomVertexColumn::get_name
const InternalName * get_name() const
Returns the name of this particular data field, e.g.
Definition: geomVertexColumn.I:77
GeomVertexColumn::write_datagram
void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: geomVertexColumn.cxx:386
GeomVertexColumn::get_total_bytes
int get_total_bytes() const
Returns the number of bytes used by each element of the column: component_bytes * num_components.
Definition: geomVertexColumn.I:171
CPT
CPT(GeomVertexArrayFormat) GeomVertexArrayFormat
Adds the indicated format to the registry, if there is not an equivalent format already there; in eit...
Definition: geomVertexArrayFormat.cxx:828
GeomVertexColumn::get_numeric_type
NumericType get_numeric_type() const
Returns the token representing the numeric type of the data storage.
Definition: geomVertexColumn.I:116
GeomVertexColumn::get_contents
Contents get_contents() const
Returns the token representing the semantic meaning of the stored value.
Definition: geomVertexColumn.I:124
Factory::register_factory
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
GeomVertexColumn::complete_pointers
int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
Definition: geomVertexColumn.cxx:410
GeomVertexArrayFormat::register_with_read_factory
static void register_with_read_factory()
Tells the BamReader how to create objects of type GeomVertexArrayFormat.
Definition: geomVertexArrayFormat.cxx:699
GeomVertexColumn::get_num_components
int get_num_components() const
Returns the number of components of the column: the number of instances of the NumericType in each el...
Definition: geomVertexColumn.I:87
GeomVertexColumn::fillin
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...
Definition: geomVertexColumn.cxx:430
GeomVertexArrayFormat::align_columns_for_animation
void align_columns_for_animation()
Reprocesses the columns in the format to align the C_point and C_vector columns to 16-byte boundaries...
Definition: geomVertexArrayFormat.cxx:351
ReferenceCount::unref
virtual bool unref() const
Explicitly decrements the reference count.
Definition: referenceCount.I:179
GeomVertexArrayFormat::complete_pointers
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
Definition: geomVertexArrayFormat.cxx:734
GeomVertexArrayFormat::count_unused_space
int count_unused_space() const
Returns the number of bytes per row that are not assigned to any column.
Definition: geomVertexArrayFormat.cxx:441
GeomVertexColumn
This defines how a single column is interleaved within a vertex array stored within a Geom.
Definition: geomVertexColumn.h:37
GeomVertexArrayFormat::pack_columns
void pack_columns()
Removes wasted space between columns.
Definition: geomVertexArrayFormat.cxx:327
GeomVertexArrayFormat::get_stride
get_stride
Returns the total number of bytes reserved in the array for each vertex.
Definition: geomVertexArrayFormat.h:82
BamReader::get_file_minor_ver
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:83
geomVertexFormat.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
indent.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexArrayFormat::finalize
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
Definition: geomVertexArrayFormat.cxx:752
DatagramIterator::get_uint8
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
Definition: datagramIterator.I:72
TypedWritable::fillin
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...
Definition: typedWritable.cxx:103
bamWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexColumn::overlaps_with
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,...
Definition: geomVertexColumn.I:199
parse_params
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
GeomVertexArrayFormat
This describes the structure of a single array within a Geom data.
Definition: geomVertexArrayFormat.h:47