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