Panda3D
Loading...
Searching...
No Matches
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;
26
27GeomVertexArrayFormat::Registry *GeomVertexArrayFormat::_registry = nullptr;
28TypeHandle GeomVertexArrayFormat::_type_handle;
29
30/**
31 *
32 */
33GeomVertexArrayFormat::
34GeomVertexArrayFormat() :
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 *
46 */
47GeomVertexArrayFormat::
48GeomVertexArrayFormat(CPT_InternalName name0, int num_components0,
49 GeomVertexArrayFormat::NumericType numeric_type0,
50 GeomVertexArrayFormat::Contents contents0) :
51 _is_registered(false),
52 _stride(0),
53 _total_bytes(0),
54 _pad_to(1),
55 _divisor(0),
56 _columns_unsorted(false)
57{
58 add_column(std::move(name0), num_components0, numeric_type0, contents0);
59}
60
61/**
62 *
63 */
64GeomVertexArrayFormat::
65GeomVertexArrayFormat(CPT_InternalName name0, int num_components0,
66 GeomVertexArrayFormat::NumericType numeric_type0,
67 GeomVertexArrayFormat::Contents contents0,
68 CPT_InternalName name1, int num_components1,
69 GeomVertexArrayFormat::NumericType numeric_type1,
70 GeomVertexArrayFormat::Contents contents1) :
71 _is_registered(false),
72 _stride(0),
73 _total_bytes(0),
74 _pad_to(1),
75 _divisor(0),
76 _columns_unsorted(false)
77{
78 add_column(std::move(name0), num_components0, numeric_type0, contents0);
79 add_column(std::move(name1), num_components1, numeric_type1, contents1);
80}
81
82/**
83 *
84 */
85GeomVertexArrayFormat::
86GeomVertexArrayFormat(CPT_InternalName name0, int num_components0,
87 GeomVertexArrayFormat::NumericType numeric_type0,
88 GeomVertexArrayFormat::Contents contents0,
89 CPT_InternalName name1, int num_components1,
90 GeomVertexArrayFormat::NumericType numeric_type1,
91 GeomVertexArrayFormat::Contents contents1,
92 CPT_InternalName name2, int num_components2,
93 GeomVertexArrayFormat::NumericType numeric_type2,
94 GeomVertexArrayFormat::Contents contents2) :
95 _is_registered(false),
96 _stride(0),
97 _total_bytes(0),
98 _pad_to(1),
99 _divisor(0),
100 _columns_unsorted(false)
101{
102 add_column(std::move(name0), num_components0, numeric_type0, contents0);
103 add_column(std::move(name1), num_components1, numeric_type1, contents1);
104 add_column(std::move(name2), num_components2, numeric_type2, contents2);
105}
106
107/**
108 *
109 */
110GeomVertexArrayFormat::
111GeomVertexArrayFormat(CPT_InternalName name0, int num_components0,
112 GeomVertexArrayFormat::NumericType numeric_type0,
113 GeomVertexArrayFormat::Contents contents0,
114 CPT_InternalName name1, int num_components1,
115 GeomVertexArrayFormat::NumericType numeric_type1,
116 GeomVertexArrayFormat::Contents contents1,
117 CPT_InternalName name2, int num_components2,
118 GeomVertexArrayFormat::NumericType numeric_type2,
119 GeomVertexArrayFormat::Contents contents2,
120 CPT_InternalName name3, int num_components3,
121 GeomVertexArrayFormat::NumericType numeric_type3,
122 GeomVertexArrayFormat::Contents contents3) :
123 _is_registered(false),
124 _stride(0),
125 _total_bytes(0),
126 _pad_to(1),
127 _divisor(0),
128 _columns_unsorted(false)
129{
130 add_column(std::move(name0), num_components0, numeric_type0, contents0);
131 add_column(std::move(name1), num_components1, numeric_type1, contents1);
132 add_column(std::move(name2), num_components2, numeric_type2, contents2);
133 add_column(std::move(name3), num_components3, numeric_type3, contents3);
134}
135
136/**
137 *
138 */
139GeomVertexArrayFormat::
140GeomVertexArrayFormat(const GeomVertexArrayFormat &copy) :
141 _is_registered(false),
142 _stride(copy._stride),
143 _total_bytes(copy._total_bytes),
144 _pad_to(copy._pad_to),
145 _divisor(copy._divisor),
146 _columns_unsorted(copy._columns_unsorted)
147{
148 Columns::const_iterator dti;
149 for (dti = copy._columns.begin(); dti != copy._columns.end(); ++dti) {
150 add_column(*(*dti));
151 }
152}
153
154/**
155 *
156 */
157void GeomVertexArrayFormat::
158operator = (const GeomVertexArrayFormat &copy) {
159 nassertv(!_is_registered);
160 _stride = copy._stride;
161 _total_bytes = copy._total_bytes;
162 _pad_to = copy._pad_to;
163 _divisor = copy._divisor;
164
165 _columns.clear();
166 _columns_by_name.clear();
167 _columns_unsorted = false;
168 Columns::const_iterator dti;
169 for (dti = copy._columns.begin(); dti != copy._columns.end(); ++dti) {
170 add_column(*(*dti));
171 }
172}
173
174/**
175 *
176 */
177GeomVertexArrayFormat::
178~GeomVertexArrayFormat() {
179 // unref() should have unregistered us.
180 nassertv(!is_registered());
181
182 Columns::iterator ci;
183 for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
184 delete (*ci);
185 }
186}
187
188/**
189 * This method overrides ReferenceCount::unref() to unregister the object when
190 * its reference count goes to zero.
191 */
193unref() const {
194 Registry *registry = get_registry();
195 LightMutexHolder holder(registry->_lock);
196
197 if (ReferenceCount::unref()) {
198 return true;
199 }
200
201 if (is_registered()) {
202 registry->unregister_format((GeomVertexArrayFormat *)this);
203 }
204
205 return false;
206}
207
208/**
209 * Adds a new column to the specification. This is a table of per-vertex
210 * floating-point numbers such as "vertex" or "normal"; you must specify where
211 * in each record the table starts, and how many components (dimensions) exist
212 * per vertex.
213 *
214 * The return value is the index number of the new data type.
215 */
217add_column(CPT_InternalName name, int num_components,
218 GeomVertexArrayFormat::NumericType numeric_type,
219 GeomVertexArrayFormat::Contents contents, int start,
220 int column_alignment) {
221 if (start < 0) {
222 start = _total_bytes;
223 }
224
225 return add_column(GeomVertexColumn(std::move(name), num_components, numeric_type, contents,
226 start, column_alignment));
227}
228
229/**
230 * Adds a new column to the specification. This is a table of per-vertex
231 * floating-point numbers such as "vertex" or "normal"; you must specify where
232 * in each record the table starts, and how many components (dimensions) exist
233 * per vertex.
234 *
235 * Adding a column with the same name as a previous type, or that overlaps
236 * with one or more previous types, quietly removes the previous type(s).
237 *
238 * The return value is the index number of the new data type.
239 */
241add_column(const GeomVertexColumn &column) {
242 nassertr(!_is_registered, -1);
243
244 // Make sure there isn't already a column with this name.
245 remove_column(column.get_name());
246
247 // Also make sure there aren't any columns that overlap with this one.
248 const GeomVertexColumn *orig_column = get_column(column.get_start(), column.get_total_bytes());
249 while (orig_column != nullptr) {
250 remove_column(orig_column->get_name());
251 orig_column = get_column(column.get_start(), column.get_total_bytes());
252 }
253
254 _total_bytes = max(_total_bytes, column.get_start() + column.get_total_bytes());
255 _pad_to = max(_pad_to, column.get_column_alignment());
256 _stride = max(_stride, _total_bytes);
257 if (_pad_to > 1) {
258 _stride = ((_stride + _pad_to - 1) / _pad_to) * _pad_to;
259 }
260
261 GeomVertexColumn *new_column = new GeomVertexColumn(column);
262
263 if (!_columns.empty() && *new_column < *_columns.back()) {
264 _columns_unsorted = true;
265 }
266
267 int new_index = (int)_columns.size();
268 _columns.push_back(new_column);
269 _columns_by_name.insert(ColumnsByName::value_type(new_column->get_name(), new_column));
270
271 return new_index;
272}
273
274/**
275 * Removes the column with the indicated name, if any. This leaves a gap in
276 * the byte structure.
277 */
279remove_column(const InternalName *name) {
280 nassertv(!_is_registered);
281 ColumnsByName::iterator ni;
282 ni = _columns_by_name.find(name);
283 if (ni != _columns_by_name.end()) {
284 GeomVertexColumn *column = (*ni).second;
285 _columns_by_name.erase(ni);
286
287 Columns::iterator ci;
288 ci = find(_columns.begin(), _columns.end(), column);
289 nassertv(ci != _columns.end());
290 _columns.erase(ci);
291
292 delete column;
293
294 // Maybe we just removed the tail column. If that's so, we should
295 // recompute _total_bytes to reflect the new tail.
296 if (_columns.empty()) {
297 _total_bytes = 0;
298 } else {
299 consider_sort_columns();
300 GeomVertexColumn *last = _columns.back();
301 _total_bytes = last->get_start() + last->get_total_bytes();
302 }
303 }
304}
305
306/**
307 * Removes all columns previously added, sets the stride to zero, and prepares
308 * to start over.
309 */
312 nassertv(!_is_registered);
313
314 _columns.clear();
315 _columns_by_name.clear();
316 _columns_unsorted = false;
317 _stride = 0;
318 _total_bytes = 0;
319 _pad_to = 1;
320}
321
322/**
323 * Removes wasted space between columns.
324 */
326pack_columns() {
327 nassertv(!_is_registered);
328
329 Columns orig_columns;
330 orig_columns.swap(_columns);
332
333 Columns::const_iterator ci;
334 for (ci = orig_columns.begin(); ci != orig_columns.end(); ++ci) {
335 GeomVertexColumn *column = (*ci);
336 add_column(column->get_name(), column->get_num_components(),
337 column->get_numeric_type(), column->get_contents());
338 }
339}
340
341/**
342 * Reprocesses the columns in the format to align the C_point and C_vector
343 * columns to 16-byte boundaries to allow for the more efficient SSE2
344 * operations (assuming SSE2 is enabled in the build).
345 *
346 * The caller is responsible for testing vertex_animation_align_16 to decide
347 * whether to call this method.
348 */
351 nassertv(!_is_registered);
352
353 Columns orig_columns;
354 orig_columns.swap(_columns);
356
357 Columns::const_iterator ci;
358 for (ci = orig_columns.begin(); ci != orig_columns.end(); ++ci) {
359 GeomVertexColumn *column = (*ci);
360 if ((column->get_contents() == C_point ||
361 column->get_contents() == C_vector ||
362 column->get_contents() == C_normal) &&
363 (column->get_numeric_type() == NT_float32 ||
364 column->get_numeric_type() == NT_float64) &&
365 column->get_num_components() >= 3) {
366 add_column(column->get_name(), 4, column->get_numeric_type(), column->get_contents(), -1, 16);
367 } else {
368 add_column(column->get_name(), column->get_num_components(),
369 column->get_numeric_type(), column->get_contents(),
370 -1, column->get_column_alignment());
371 }
372 }
373}
374
375
376/**
377 * Returns the specification with the indicated name, or NULL if the name is
378 * not used.
379 */
381get_column(const InternalName *name) const {
382 ColumnsByName::const_iterator ni;
383 ni = _columns_by_name.find(name);
384 if (ni != _columns_by_name.end()) {
385 return (*ni).second;
386 }
387 return nullptr;
388}
389
390/**
391 * Returns the first specification that overlaps with any of the indicated
392 * bytes in the range, or NULL if none do.
393 */
395get_column(int start_byte, int num_bytes) const {
396 consider_sort_columns();
397 Columns::const_iterator ci;
398 for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
399 const GeomVertexColumn *column = (*ci);
400 if (column->overlaps_with(start_byte, num_bytes)) {
401 return column;
402 }
403 }
404
405 return nullptr;
406}
407
408/**
409 * Returns true if all of the fields in this array format are also present and
410 * equivalent in the other array format, and in the same byte positions, and
411 * the stride is the same. That is, true if this format can share the same
412 * data pointer as the other format (with possibly some unused gaps).
413 */
415is_data_subset_of(const GeomVertexArrayFormat &other) const {
416 if (_columns.size() > other._columns.size() ||
417 get_stride() != other.get_stride()) {
418 return false;
419 }
420
421 consider_sort_columns();
422 other.consider_sort_columns();
423 size_t i = 0;
424 size_t j = 0;
425 while (i < _columns.size() && j < other._columns.size()) {
426 if (*_columns[i] == *other._columns[j]) {
427 ++i;
428 }
429 ++j;
430 }
431
432 // If we reached the end of our list, all fields matched.
433 return (i == _columns.size());
434}
435
436/**
437 * Returns the number of bytes per row that are not assigned to any column.
438 */
440count_unused_space() const {
441 consider_sort_columns();
442
443 int unused_space = 0;
444 int last_pos = 0;
445
446 Columns::const_iterator ci;
447 for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
448 const GeomVertexColumn *column = (*ci);
449 if (column->get_start() > last_pos) {
450 unused_space += (column->get_start() - last_pos);
451 }
452 last_pos = column->get_start() + column->get_total_bytes();
453 }
454
455 if (_stride > last_pos) {
456 unused_space += (_stride - last_pos);
457 }
458
459 return unused_space;
460}
461
462/**
463 *
464 */
465void GeomVertexArrayFormat::
466output(std::ostream &out) const {
467 Columns::const_iterator ci;
468 int last_pos = 0;
469 out << "[";
470 for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
471 const GeomVertexColumn *column = (*ci);
472 if (column->get_start() > last_pos) {
473 out << " (..." << (column->get_start() - last_pos) << "...)";
474 }
475 out << " " << *column;
476 last_pos = column->get_start() + column->get_total_bytes();
477 }
478
479 if (_stride > last_pos) {
480 out << " ..." << (_stride - last_pos) << "...";
481 }
482
483 out << " ]";
484}
485
486/**
487 *
488 */
489void GeomVertexArrayFormat::
490write(std::ostream &out, int indent_level) const {
491 indent(out, indent_level)
492 << "Array format (stride = " << get_stride() << "):\n";
493 consider_sort_columns();
494 Columns::const_iterator ci;
495 for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
496 const GeomVertexColumn *column = (*ci);
497 indent(out, indent_level + 2)
498 << *column
499 << " " << column->get_numeric_type()
500 << " " << column->get_contents()
501 << " start at " << column->get_start() << "\n";
502 }
503}
504
505/**
506 *
507 */
508void GeomVertexArrayFormat::
509write_with_data(std::ostream &out, int indent_level,
510 const GeomVertexArrayData *array_data) const {
511 consider_sort_columns();
512 int num_rows = array_data->get_num_rows();
513
514 GeomVertexReader reader(array_data);
515
516 for (int i = 0; i < num_rows; i++) {
517 indent(out, indent_level)
518 << "row " << i << ":\n";
519 reader.set_row_unsafe(i);
520 Columns::const_iterator ci;
521 for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
522 const GeomVertexColumn *column = (*ci);
523 int num_values = min(column->get_num_values(), 4);
524 reader.set_column(0, column);
525 const LVecBase4f &d = reader.get_data4f();
526
527 indent(out, indent_level + 2)
528 << *column->get_name();
529 for (int v = 0; v < num_values; v++) {
530 out << " " << d[v];
531 }
532 out << "\n";
533 }
534 }
535}
536
537/**
538 * Returns a string with format codes representing the exact memory layout of
539 * the columns in memory, as understood by Python's struct module. If pad is
540 * true, extra padding bytes are added to the end as 'x' characters as needed.
541 */
543get_format_string(bool pad) const {
544 consider_sort_columns();
545
546 int row_size;
547 if (pad) {
548 row_size = get_stride();
549 } else {
550 row_size = get_total_bytes();
551 }
552
553 // Synthesize the format string.
554 char *fmt = (char *)alloca(row_size + 1);
555 memset((void *)fmt, 0, row_size + 1);
556 int fi = 0;
557 int offset = 0;
558
559 for (const GeomVertexColumn *column : _columns) {
560 if (offset < column->get_start()) {
561 // Add padding bytes to fill the gap.
562 int pad = column->get_start() - offset;
563 memset((void*) (fmt + fi), 'x', pad);
564 fi += pad;
565 offset += pad;
566 }
567
568 char fmt_code = 'x';
569 int num_components = column->get_num_components();
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 case NT_packed_ufloat:
583 fmt_code = 'I';
584 break;
585
586 case NT_float32:
587 fmt_code = 'f';
588 break;
589
590 case NT_float64:
591 fmt_code = 'd';
592 break;
593
594 case NT_int8:
595 fmt_code = 'b';
596 break;
597
598 case NT_int16:
599 fmt_code = 'h';
600 break;
601
602 case NT_int32:
603 fmt_code = 'i';
604 break;
605
606 default:
607 gobj_cat.error()
608 << "Unknown numeric type " << column->get_numeric_type() << "!\n";
609 num_components *= column->get_component_bytes();
610 }
611 memset((void*) (fmt + fi), fmt_code, num_components);
612 offset += column->get_total_bytes();
613 fi += num_components;
614 }
615
616 if (offset < row_size) {
617 // Add padding bytes.
618 int pad = row_size - offset;
619 memset((void *)(fmt + fi), 'x', pad);
620 ++fi;
621 }
622
623 return std::string(fmt, (size_t)fi);
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...
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...
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...
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.
int get_component_bytes() const
Returns the number of bytes used by each component (that is, by one element of the numeric type).
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...
Encodes a string name in a hash table, mapping it to a pointer.
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.
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().
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.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition indent.cxx:20
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.