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
24using std::max;
25using std::min;
26using std::move;
27
28GeomVertexArrayFormat::Registry *GeomVertexArrayFormat::_registry = nullptr;
29TypeHandle GeomVertexArrayFormat::_type_handle;
30
31/**
32 *
33 */
34GeomVertexArrayFormat::
35GeomVertexArrayFormat() :
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 */
48GeomVertexArrayFormat::
49GeomVertexArrayFormat(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 */
65GeomVertexArrayFormat::
66GeomVertexArrayFormat(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 */
86GeomVertexArrayFormat::
87GeomVertexArrayFormat(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 */
111GeomVertexArrayFormat::
112GeomVertexArrayFormat(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 */
140GeomVertexArrayFormat::
141GeomVertexArrayFormat(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 */
158void GeomVertexArrayFormat::
159operator = (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 */
178GeomVertexArrayFormat::
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 */
194unref() 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 */
218add_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 */
242add_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 */
280remove_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 */
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 */
327pack_columns() {
328 nassertv(!_is_registered);
329
330 Columns orig_columns;
331 orig_columns.swap(_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);
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 */
382get_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 */
396get_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 */
416is_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 */
441count_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 */
466void GeomVertexArrayFormat::
467output(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 */
490void GeomVertexArrayFormat::
491write(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 */
509void GeomVertexArrayFormat::
510write_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 */
544get_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 */
629int GeomVertexArrayFormat::
630compare_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 */
662void GeomVertexArrayFormat::
663sort_columns() {
664 sort(_columns.begin(), _columns.end(), IndirectLess<GeomVertexColumn>());
665}
666
667/**
668 * Returns the global registry object.
669 */
670void GeomVertexArrayFormat::
671make_registry() {
672 if (_registry == nullptr) {
673 _registry = new Registry;
674 }
675}
676
677/**
678 * Called internally when the format is registered.
679 */
680void GeomVertexArrayFormat::
681do_register() {
682 nassertv(!_is_registered);
683 _is_registered = true;
684}
685
686/**
687 * Called internally when the format is unregistered.
688 */
689void GeomVertexArrayFormat::
690do_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 */
708write_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 */
734complete_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 */
752finalize(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 */
770TypedWritable *GeomVertexArrayFormat::
771make_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 */
787void GeomVertexArrayFormat::
788fillin(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) {
805 column->fillin(scan, manager);
806 _columns.push_back(column);
807 }
808 _columns_unsorted = false;
809}
810
811/**
812 *
813 */
814GeomVertexArrayFormat::Registry::
815Registry() {
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 */
828CPT(GeomVertexArrayFormat) GeomVertexArrayFormat::Registry::
829register_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 */
858void GeomVertexArrayFormat::Registry::
859unregister_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}
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
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
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:83
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being written.
Definition: bamWriter.I:59
This is a const pointer to an InternalName, and should be used in lieu of a CPT(InternalName) in func...
Definition: internalName.h:193
A class to retrieve the individual data elements previously stored in a Datagram.
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:50
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:73
This is the data for one array of a GeomVertexData structure.
int get_num_rows() const
Returns the number of rows stored in the array, based on the number of bytes and the stride.
This describes the structure of a single array within a Geom data.
void remove_column(const InternalName *name)
Removes the column with the indicated name, if any.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
get_column
Returns the specification with the indicated name, or NULL if the name is not used.
void align_columns_for_animation()
Reprocesses the columns in the format to align the C_point and C_vector columns to 16-byte boundaries...
get_total_bytes
Returns the total number of bytes used by the data types within the format, including gaps between el...
get_stride
Returns the total number of bytes reserved in the array for each vertex.
is_registered
Returns true if this format has been registered, false if it has not.
virtual bool unref() const
This method overrides ReferenceCount::unref() to unregister the object when its reference count goes ...
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
int count_unused_space() const
Returns the number of bytes per row that are not assigned to any column.
std::string get_format_string(bool pad=true) const
Returns a string with format codes representing the exact memory layout of the columns in memory,...
void clear_columns()
Removes all columns previously added, sets the stride to zero, and prepares to start over.
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
static void register_with_read_factory()
Tells the BamReader how to create objects of type GeomVertexArrayFormat.
void pack_columns()
Removes wasted space between columns.
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.
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...
This defines how a single column is interleaved within a vertex array stored within a Geom.
int get_num_values() const
Returns the number of numeric values of the column: the number of distinct numeric values that go int...
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...
int get_start() const
Returns the byte within the array record at which this column starts.
NumericType get_numeric_type() const
Returns the token representing the numeric type of the data storage.
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_column_alignment() const
Returns the alignment requirements for this column.
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,...
int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
const InternalName * get_name() const
Returns the name of this particular data field, e.g.
Contents get_contents() const
Returns the token representing the semantic meaning of the stored value.
int get_total_bytes() const
Returns the number of bytes used by each element of the column: component_bytes * 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...
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
An STL function object class, this is intended to be used on any ordered collection of pointers to cl...
Definition: indirectLess.h:25
Encodes a string name in a hash table, mapping it to a pointer.
Definition: internalName.h:38
Similar to MutexHolder, but for a light mutex.
virtual bool unref() const
Explicitly decrements the reference count.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
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...
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
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().
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: dcindent.cxx:22
CPT(GeomVertexArrayFormat) GeomVertexArrayFormat
Adds the indicated format to the registry, if there is not an equivalent format already there; in eit...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.