Panda3D
 All Classes Functions Variables Enumerations
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  }
408  }
409 }
410 
411 
412 ////////////////////////////////////////////////////////////////////
413 // Function: GeomVertexArrayFormat::get_column
414 // Access: Published
415 // Description: Returns the specification with the indicated name, or
416 // NULL if the name is not used.
417 ////////////////////////////////////////////////////////////////////
418 const GeomVertexColumn *GeomVertexArrayFormat::
419 get_column(const InternalName *name) const {
420  ColumnsByName::const_iterator ni;
421  ni = _columns_by_name.find(name);
422  if (ni != _columns_by_name.end()) {
423  return (*ni).second;
424  }
425  return NULL;
426 }
427 
428 ////////////////////////////////////////////////////////////////////
429 // Function: GeomVertexArrayFormat::get_column
430 // Access: Published
431 // Description: Returns the first specification that overlaps with
432 // any of the indicated bytes in the range, or NULL if
433 // none do.
434 ////////////////////////////////////////////////////////////////////
435 const GeomVertexColumn *GeomVertexArrayFormat::
436 get_column(int start_byte, int num_bytes) const {
437  consider_sort_columns();
438  Columns::const_iterator ci;
439  for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
440  const GeomVertexColumn *column = (*ci);
441  if (column->overlaps_with(start_byte, num_bytes)) {
442  return column;
443  }
444  }
445 
446  return NULL;
447 }
448 
449 ////////////////////////////////////////////////////////////////////
450 // Function: GeomVertexArrayFormat::is_data_subset_of
451 // Access: Published
452 // Description: Returns true if all of the fields in this array
453 // format are also present and equivalent in the other
454 // array format, and in the same byte positions, and the
455 // stride is the same. That is, true if this format can
456 // share the same data pointer as the other format (with
457 // possibly some unused gaps).
458 ////////////////////////////////////////////////////////////////////
459 bool GeomVertexArrayFormat::
460 is_data_subset_of(const GeomVertexArrayFormat &other) const {
461  if (_columns.size() > other._columns.size() ||
462  get_stride() != other.get_stride()) {
463  return false;
464  }
465 
466  consider_sort_columns();
467  other.consider_sort_columns();
468  size_t i = 0;
469  size_t j = 0;
470  while (i < _columns.size() && j < other._columns.size()) {
471  if (*_columns[i] == *other._columns[j]) {
472  ++i;
473  }
474  ++j;
475  }
476 
477  // If we reached the end of our list, all fields matched.
478  return (i == _columns.size());
479 }
480 
481 ////////////////////////////////////////////////////////////////////
482 // Function: GeomVertexArrayFormat::count_unused_space
483 // Access: Published
484 // Description: Returns the number of bytes per row that are not
485 // assigned to any column.
486 ////////////////////////////////////////////////////////////////////
487 int GeomVertexArrayFormat::
488 count_unused_space() const {
489  consider_sort_columns();
490 
491  int unused_space = 0;
492  int last_pos = 0;
493 
494  Columns::const_iterator ci;
495  for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
496  const GeomVertexColumn *column = (*ci);
497  if (column->get_start() > last_pos) {
498  unused_space += (column->get_start() - last_pos);
499  }
500  last_pos = column->get_start() + column->get_total_bytes();
501  }
502 
503  if (_stride > last_pos) {
504  unused_space += (_stride - last_pos);
505  }
506 
507  return unused_space;
508 }
509 
510 ////////////////////////////////////////////////////////////////////
511 // Function: GeomVertexArrayFormat::output
512 // Access: Published
513 // Description:
514 ////////////////////////////////////////////////////////////////////
515 void GeomVertexArrayFormat::
516 output(ostream &out) const {
517  Columns::const_iterator ci;
518  int last_pos = 0;
519  out << "[";
520  for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
521  const GeomVertexColumn *column = (*ci);
522  if (column->get_start() > last_pos) {
523  out << " (..." << (column->get_start() - last_pos) << "...)";
524  }
525  out << " " << *column;
526  last_pos = column->get_start() + column->get_total_bytes();
527  }
528 
529  if (_stride > last_pos) {
530  out << " ..." << (_stride - last_pos) << "...";
531  }
532 
533  out << " ]";
534 }
535 
536 ////////////////////////////////////////////////////////////////////
537 // Function: GeomVertexArrayFormat::write
538 // Access: Published
539 // Description:
540 ////////////////////////////////////////////////////////////////////
541 void GeomVertexArrayFormat::
542 write(ostream &out, int indent_level) const {
543  indent(out, indent_level)
544  << "Array format (stride = " << get_stride() << "):\n";
545  consider_sort_columns();
546  Columns::const_iterator ci;
547  for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
548  const GeomVertexColumn *column = (*ci);
549  indent(out, indent_level + 2)
550  << *column
551  << " " << column->get_numeric_type()
552  << " " << column->get_contents()
553  << " start at " << column->get_start() << "\n";
554  }
555 }
556 
557 ////////////////////////////////////////////////////////////////////
558 // Function: GeomVertexArrayFormat::write_with_data
559 // Access: Published
560 // Description:
561 ////////////////////////////////////////////////////////////////////
562 void GeomVertexArrayFormat::
563 write_with_data(ostream &out, int indent_level,
564  const GeomVertexArrayData *array_data) const {
565  consider_sort_columns();
566  int num_rows = array_data->get_num_rows();
567 
568  GeomVertexReader reader(array_data);
569 
570  for (int i = 0; i < num_rows; i++) {
571  indent(out, indent_level)
572  << "row " << i << ":\n";
573  reader.set_row_unsafe(i);
574  Columns::const_iterator ci;
575  for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
576  const GeomVertexColumn *column = (*ci);
577  int num_values = min(column->get_num_values(), 4);
578  reader.set_column(0, column);
579  const LVecBase4f &d = reader.get_data4f();
580 
581  indent(out, indent_level + 2)
582  << *column->get_name();
583  for (int v = 0; v < num_values; v++) {
584  out << " " << d[v];
585  }
586  out << "\n";
587  }
588  }
589 }
590 
591 ////////////////////////////////////////////////////////////////////
592 // Function: GeomVertexArrayFormat::get_format_string
593 // Access: Published
594 // Description: Returns a string with format codes representing the
595 // exact memory layout of the columns in memory, as
596 // understood by Python's struct module.
597 // If pad is true, extra padding bytes are added to
598 // the end as 'x' characters as needed.
599 ////////////////////////////////////////////////////////////////////
600 string GeomVertexArrayFormat::
601 get_format_string(bool pad) const {
602  consider_sort_columns();
603 
604  int row_size;
605  if (pad) {
606  row_size = get_stride();
607  } else {
608  row_size = get_total_bytes();
609  }
610 
611  // Synthesize the format string.
612  char *fmt = (char*) malloc(row_size + 1);
613  memset((void*) fmt, 0, row_size + 1);
614  int fi = 0;
615  int offset = 0;
616 
617  for (int ci = 0; ci < get_num_columns(); ++ci) {
618  const GeomVertexColumn *column = get_column(ci);
619 
620  if (offset < column->get_start()) {
621  // Add padding bytes to fill the gap.
622  int pad = column->get_start() - offset;
623  memset((void*) (fmt + fi), 'x', pad);
624  fi += pad;
625  offset += pad;
626  }
627 
628  char fmt_code = 'x';
629  switch (column->get_numeric_type()) {
630  case NT_uint8:
631  fmt_code = 'B';
632  break;
633  case NT_uint16:
634  fmt_code = 'H';
635  break;
636  case NT_uint32:
637  case NT_packed_dcba:
638  case NT_packed_dabc:
639  fmt_code = 'I';
640  break;
641  case NT_float32:
642  fmt_code = 'f';
643  break;
644  case NT_float64:
645  fmt_code = 'd';
646  break;
647  default:
648  gobj_cat.error()
649  << "Unknown numeric type " << column->get_numeric_type() << "!\n";
650  return NULL;
651  }
652  memset((void*) (fmt + fi), fmt_code, column->get_num_components());
653  offset += column->get_total_bytes();
654  fi += column->get_num_components();
655  }
656 
657  if (offset < row_size) {
658  // Add padding bytes.
659  int pad = row_size - offset;
660  memset((void*) (fmt + fi), 'x', pad);
661  }
662 
663  string fmt_string (fmt);
664  free(fmt);
665  return fmt_string;
666 }
667 
668 ////////////////////////////////////////////////////////////////////
669 // Function: GeomVertexArrayFormat::compare_to
670 // Access: Public
671 // Description:
672 ////////////////////////////////////////////////////////////////////
673 int GeomVertexArrayFormat::
674 compare_to(const GeomVertexArrayFormat &other) const {
675  if (_stride != other._stride) {
676  return _stride - other._stride;
677  }
678  if (_total_bytes != other._total_bytes) {
679  return _total_bytes - other._total_bytes;
680  }
681  if (_pad_to != other._pad_to) {
682  return _pad_to - other._pad_to;
683  }
684  if (_divisor != other._divisor) {
685  return _divisor - other._divisor;
686  }
687  if (_columns.size() != other._columns.size()) {
688  return (int)_columns.size() - (int)other._columns.size();
689  }
690  consider_sort_columns();
691  other.consider_sort_columns();
692  for (size_t i = 0; i < _columns.size(); i++) {
693  int compare = _columns[i]->compare_to(*other._columns[i]);
694  if (compare != 0) {
695  return compare;
696  }
697  }
698 
699  return 0;
700 }
701 
702 ////////////////////////////////////////////////////////////////////
703 // Function: GeomVertexArrayFormat::sort_columns
704 // Access: Private
705 // Description: Resorts the _columns vector so that the columns
706 // are listed in the same order they appear in the
707 // record.
708 ////////////////////////////////////////////////////////////////////
709 void GeomVertexArrayFormat::
710 sort_columns() {
711  sort(_columns.begin(), _columns.end(), IndirectLess<GeomVertexColumn>());
712 }
713 
714 ////////////////////////////////////////////////////////////////////
715 // Function: GeomVertexArrayFormat::make_registry
716 // Access: Private
717 // Description: Returns the global registry object.
718 ////////////////////////////////////////////////////////////////////
719 void GeomVertexArrayFormat::
720 make_registry() {
721  if (_registry == (Registry *)NULL) {
722  _registry = new Registry;
723  }
724 }
725 
726 ////////////////////////////////////////////////////////////////////
727 // Function: GeomVertexArrayFormat::do_register
728 // Access: Private
729 // Description: Called internally when the format is registered.
730 ////////////////////////////////////////////////////////////////////
731 void GeomVertexArrayFormat::
732 do_register() {
733  nassertv(!_is_registered);
734  _is_registered = true;
735 }
736 
737 ////////////////////////////////////////////////////////////////////
738 // Function: GeomVertexArrayFormat::do_unregister
739 // Access: Private
740 // Description: Called internally when the format is unregistered.
741 ////////////////////////////////////////////////////////////////////
742 void GeomVertexArrayFormat::
743 do_unregister() {
744  nassertv(_is_registered);
745  _is_registered = false;
746 }
747 
748 ////////////////////////////////////////////////////////////////////
749 // Function: GeomVertexArrayFormat::register_with_read_factory
750 // Access: Public, Static
751 // Description: Tells the BamReader how to create objects of type
752 // GeomVertexArrayFormat.
753 ////////////////////////////////////////////////////////////////////
754 void GeomVertexArrayFormat::
755 register_with_read_factory() {
756  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
757 }
758 
759 ////////////////////////////////////////////////////////////////////
760 // Function: GeomVertexArrayFormat::write_datagram
761 // Access: Public, Virtual
762 // Description: Writes the contents of this object to the datagram
763 // for shipping out to a Bam file.
764 ////////////////////////////////////////////////////////////////////
765 void GeomVertexArrayFormat::
766 write_datagram(BamWriter *manager, Datagram &dg) {
768 
769  dg.add_uint16(_stride);
770  dg.add_uint16(_total_bytes);
771  dg.add_uint8(_pad_to);
772  dg.add_uint16(_divisor);
773 
774  consider_sort_columns();
775 
776  dg.add_uint16(_columns.size());
777  Columns::iterator ci;
778  for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
779  GeomVertexColumn *column = (*ci);
780  column->write_datagram(manager, dg);
781  }
782 }
783 
784 ////////////////////////////////////////////////////////////////////
785 // Function: GeomVertexArrayFormat::complete_pointers
786 // Access: Public, Virtual
787 // Description: Receives an array of pointers, one for each time
788 // manager->read_pointer() was called in fillin().
789 // Returns the number of pointers processed.
790 ////////////////////////////////////////////////////////////////////
791 int GeomVertexArrayFormat::
792 complete_pointers(TypedWritable **p_list, BamReader *manager) {
793  int pi = TypedWritableReferenceCount::complete_pointers(p_list, manager);
794 
795  Columns::iterator ci;
796  for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
797  GeomVertexColumn *column = (*ci);
798  pi += column->complete_pointers(p_list + pi, manager);
799  }
800 
801  return pi;
802 }
803 
804 ////////////////////////////////////////////////////////////////////
805 // Function: GeomVertexArrayFormat::finalize
806 // Access: Public, Virtual
807 // Description: Called by the BamReader to perform any final actions
808 // needed for setting up the object after all objects
809 // have been read and all pointers have been completed.
810 ////////////////////////////////////////////////////////////////////
811 void GeomVertexArrayFormat::
812 finalize(BamReader *manager) {
813  // Now we can build up the _columns_by_name index. We have to wait
814  // until finalize(), since the index is based on the nested name
815  // pointer within each column, which might not be available at the
816  // time complete_pointers() is called.
817  _columns_by_name.clear();
818  Columns::iterator ci;
819  for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
820  GeomVertexColumn *column = (*ci);
821  _columns_by_name.insert(ColumnsByName::value_type(column->get_name(), column));
822  }
823 }
824 
825 ////////////////////////////////////////////////////////////////////
826 // Function: GeomVertexArrayFormat::make_from_bam
827 // Access: Protected, Static
828 // Description: This function is called by the BamReader's factory
829 // when a new object of type GeomVertexArrayFormat is
830 // encountered in the Bam file. It should create the
831 // GeomVertexArrayFormat and extract its information
832 // from the file.
833 ////////////////////////////////////////////////////////////////////
834 TypedWritable *GeomVertexArrayFormat::
835 make_from_bam(const FactoryParams &params) {
836  GeomVertexArrayFormat *object = new GeomVertexArrayFormat;
837  DatagramIterator scan;
838  BamReader *manager;
839 
840  parse_params(params, scan, manager);
841  object->fillin(scan, manager);
842  manager->register_finalize(object);
843 
844  return object;
845 }
846 
847 ////////////////////////////////////////////////////////////////////
848 // Function: GeomVertexArrayFormat::fillin
849 // Access: Protected
850 // Description: This internal function is called by make_from_bam to
851 // read in all of the relevant data from the BamFile for
852 // the new GeomVertexArrayFormat.
853 ////////////////////////////////////////////////////////////////////
854 void GeomVertexArrayFormat::
855 fillin(DatagramIterator &scan, BamReader *manager) {
857  nassertv(!_is_registered);
858 
859  _stride = scan.get_uint16();
860  _total_bytes = scan.get_uint16();
861  _pad_to = scan.get_uint8();
862  if (manager->get_file_minor_ver() > 36) {
863  _divisor = scan.get_uint16();
864  } else {
865  _divisor = 0;
866  }
867 
868  int num_columns = scan.get_uint16();
869  _columns.reserve(num_columns);
870  for (int i = 0; i < num_columns; ++i) {
871  GeomVertexColumn *column = new GeomVertexColumn;
872  column->fillin(scan, manager);
873  _columns.push_back(column);
874  }
875  _columns_unsorted = false;
876 }
877 
878 ////////////////////////////////////////////////////////////////////
879 // Function: GeomVertexArrayFormat::Registry::Constructor
880 // Access: Public
881 // Description:
882 ////////////////////////////////////////////////////////////////////
883 GeomVertexArrayFormat::Registry::
884 Registry() {
885 }
886 
887 ////////////////////////////////////////////////////////////////////
888 // Function: GeomVertexArrayFormat::Registry::register_format
889 // Access: Public
890 // Description: Adds the indicated format to the registry, if there
891 // is not an equivalent format already there; in either
892 // case, returns the pointer to the equivalent format
893 // now in the registry.
894 //
895 // This must be called before a format may be used in a
896 // Geom. After this call, you should discard the
897 // original pointer you passed in (which may or may not
898 // now be invalid) and let its reference count decrement
899 // normally; you should use only the returned value from
900 // this point on.
901 ////////////////////////////////////////////////////////////////////
902 CPT(GeomVertexArrayFormat) GeomVertexArrayFormat::Registry::
903 register_format(GeomVertexArrayFormat *format) {
904  if (format->is_registered()) {
905  return format;
906  }
907 
908  // Save the incoming pointer in a local PointerTo, so that if it has
909  // a zero reference count and is not added into the map below, it
910  // will be automatically deleted when this function returns.
911  PT(GeomVertexArrayFormat) pt_format = format;
912 
913  GeomVertexArrayFormat *new_format;
914  {
915  LightMutexHolder holder(_lock);
916  ArrayFormats::iterator fi = _formats.insert(format).first;
917  new_format = (*fi);
918  if (!new_format->is_registered()) {
919  new_format->do_register();
920  }
921  }
922 
923  return new_format;
924 }
925 
926 ////////////////////////////////////////////////////////////////////
927 // Function: GeomVertexArrayFormat::Registry::unregister_format
928 // Access: Public
929 // Description: Removes the indicated format from the registry.
930 // Normally this should not be done until the format is
931 // destructing.
932 //
933 // The lock should be held prior to calling this method.
934 ////////////////////////////////////////////////////////////////////
935 void GeomVertexArrayFormat::Registry::
936 unregister_format(GeomVertexArrayFormat *format) {
937  nassertv(format->is_registered());
938  ArrayFormats::iterator fi = _formats.find(format);
939  nassertv(fi != _formats.end());
940  _formats.erase(fi);
941  format->do_unregister();
942 }
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
int get_num_rows() const
Returns the number of rows stored in the array, based on the number of bytes and the stride...
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
int get_total_bytes() const
Returns the number of bytes used by each element of the column: component_bytes * num_components...
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
const InternalName * get_name() const
Returns the name of this particular data field, e.g.
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_num_components() const
Returns the number of components of the column: the number of instances of the NumericType in each el...
int get_column_alignment() const
Returns the alignment requirements for this column.
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.
int get_start() const
Returns the byte within the array record at which this column starts.
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-&gt;read_pointer() was called in fillin()...
virtual bool unref() const
Explicitly decrements the reference count.
Similar to MutexHolder, but for a light mutex.
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.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
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:880
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
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
int get_num_values() const
Returns the number of numeric values of the column: the number of distinct numeric values that go int...
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...
Contents get_contents() const
Returns the token representing the semantic meaning of the stored value.
NumericType get_numeric_type() const
Returns the token representing the numeric type of the data storage.
A class to retrieve the individual data elements previously stored in a Datagram. ...
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:105
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
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-&gt;read_pointer() was called in fillin()...
This is the data for one array of a GeomVertexData structure.