Panda3D
geomVertexFormat.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 geomVertexFormat.cxx
10 * @author drose
11 * @date 2005-03-07
12 */
13
14#include "geomVertexFormat.h"
15#include "geomVertexData.h"
16#include "geomMunger.h"
17#include "lightReMutexHolder.h"
18#include "indent.h"
19#include "bamReader.h"
20#include "bamWriter.h"
21
22GeomVertexFormat::Registry *GeomVertexFormat::_registry = nullptr;
23TypeHandle GeomVertexFormat::_type_handle;
24
25/**
26 *
27 */
28GeomVertexFormat::
29GeomVertexFormat() :
30 _is_registered(false),
31 _post_animated_format(nullptr)
32{
33}
34
35/**
36 *
37 */
38GeomVertexFormat::
39GeomVertexFormat(const GeomVertexArrayFormat *array_format) :
40 _is_registered(false),
41 _post_animated_format(nullptr)
42{
43 add_array(array_format);
44}
45
46/**
47 *
48 */
49GeomVertexFormat::
50GeomVertexFormat(const GeomVertexFormat &copy) :
51 _is_registered(false),
52 _animation(copy._animation),
53 _arrays(copy._arrays),
54 _post_animated_format(nullptr)
55{
56}
57
58/**
59 *
60 */
61void GeomVertexFormat::
62operator = (const GeomVertexFormat &copy) {
63 nassertv(!is_registered());
64
65 _animation = copy._animation;
66 _arrays = copy._arrays;
67}
68
69/**
70 *
71 */
72GeomVertexFormat::
73~GeomVertexFormat() {
74 // unref() should have unregistered us.
75 nassertv(!is_registered());
76}
77
78/**
79 * This method overrides ReferenceCount::unref() to unregister the object when
80 * its reference count goes to zero.
81 */
83unref() const {
84 Registry *registry = get_registry();
85 LightReMutexHolder holder(registry->_lock);
86
88 return true;
89 }
90
91 if (is_registered()) {
92 registry->unregister_format((GeomVertexFormat *)this);
93 }
94
95 return false;
96}
97
98/**
99 * Returns a suitable vertex format for sending the animated vertices to the
100 * graphics backend. This is the same format as the source format, with the
101 * CPU-animation data elements removed.
102 *
103 * This may only be called after the format has been registered. The return
104 * value will have been already registered.
105 */
106CPT(GeomVertexFormat) GeomVertexFormat::
107get_post_animated_format() const {
108 nassertr(is_registered(), nullptr);
109
110 if (_post_animated_format == nullptr) {
111 PT(GeomVertexFormat) new_format = new GeomVertexFormat(*this);
112 new_format->remove_column(InternalName::get_transform_blend());
113
114 int num_morphs = get_num_morphs();
115 for (int mi = 0; mi < num_morphs; mi++) {
116 CPT(InternalName) delta_name = get_morph_delta(mi);
117 new_format->remove_column(delta_name);
118 }
119
120 new_format->_animation.set_none();
121
122 CPT(GeomVertexFormat) registered =
123 GeomVertexFormat::register_format(new_format);
124 ((GeomVertexFormat *)this)->_post_animated_format = registered;
125 if (_post_animated_format != this) {
126 // We only keep the reference count if the new pointer is not the same
127 // as this, to avoid a circular dependency.
128 _post_animated_format->ref();
129 }
130 }
131
132 _post_animated_format->test_ref_count_integrity();
133
134 return _post_animated_format;
135}
136
137/**
138 * Returns a new GeomVertexFormat that includes all of the columns defined in
139 * either this GeomVertexFormat or the other one. If any column is defined in
140 * both formats with different sizes (for instance, texcoord2 vs. texcoord3),
141 * the new format will include the larger of the two definitions.
142 *
143 * This may only be called after both source formats have been registered.
144 * The return value will also have been already registered.
145 */
146CPT(GeomVertexFormat) GeomVertexFormat::
147get_union_format(const GeomVertexFormat *other) const {
148 nassertr(is_registered() && other->is_registered(), nullptr);
149
150 PT(GeomVertexFormat) new_format = new GeomVertexFormat;
151
152 // Preserve whichever animation type is not AT_None. (If both animation
153 // types are not AT_None, but they are different, this whole operation is
154 // questionable.)
155 if (_animation.get_animation_type() != AT_none) {
156 new_format->set_animation(_animation);
157 } else {
158 new_format->set_animation(other->get_animation());
159 }
160
161 // Keep track of the columns we have already added.
162 typedef pset< CPT(InternalName) > ColumnNames;
163 ColumnNames column_names;
164
165 // We go through all the (0)-level arrays first, then all the (1)-level
166 // arrays, and so on. We do this to ensure that the new format gets written
167 // out with all the (0)-level columns appearing before all the (1)-level
168 // columns, which might lead to a small optimization at render time.
169
170 // We also try to keep the structure as similar as possible. If both source
171 // formats have columns (A, B) in array 0, and columns (C, D, E) in array 1,
172 // then the resulting union format will also have (A, B) in array 0 and (C,
173 // D, E) in array 1. In general, a column will appear in the result in the
174 // first array it appears in either of the inputs.
175
176 size_t num_arrays = std::max(_arrays.size(), other->_arrays.size());
177 for (size_t ai = 0; ai < num_arrays; ++ai) {
179
180 // Add the columns from the first format.
181 if (ai < _arrays.size()) {
182 GeomVertexArrayFormat *array_format = _arrays[ai];
183 size_t num_columns = array_format->get_num_columns();
184 for (size_t i = 0; i < num_columns; ++i) {
185 const GeomVertexColumn *column_a = array_format->get_column(i);
186 bool inserted = column_names.insert(column_a->get_name()).second;
187 if (inserted) {
188 const GeomVertexColumn *column_b = other->get_column(column_a->get_name());
189 if (column_b != nullptr &&
190 column_b->get_total_bytes() > column_a->get_total_bytes()) {
191 // Column b is larger. Keep it.
192 new_array->add_column(column_b->get_name(),
193 column_b->get_num_components(),
194 column_b->get_numeric_type(),
195 column_b->get_contents());
196 } else {
197 // Column a is larger. Keep it.
198 new_array->add_column(column_a->get_name(),
199 column_a->get_num_components(),
200 column_a->get_numeric_type(),
201 column_a->get_contents());
202 }
203 }
204 }
205 }
206
207 // Add the columns from the second format.
208 if (ai < other->_arrays.size()) {
209 GeomVertexArrayFormat *array_format = other->_arrays[ai];
210 size_t num_columns = array_format->get_num_columns();
211 for (size_t i = 0; i < num_columns; ++i) {
212 const GeomVertexColumn *column_a = array_format->get_column(i);
213 bool inserted = column_names.insert(column_a->get_name()).second;
214 if (inserted) {
215 const GeomVertexColumn *column_b = get_column(column_a->get_name());
216 if (column_b != nullptr &&
217 column_b->get_total_bytes() > column_a->get_total_bytes()) {
218 // Column b is larger. Keep it.
219 new_array->add_column(column_b->get_name(),
220 column_b->get_num_components(),
221 column_b->get_numeric_type(),
222 column_b->get_contents());
223 } else {
224 // Column a is larger. Keep it.
225 new_array->add_column(column_a->get_name(),
226 column_a->get_num_components(),
227 column_a->get_numeric_type(),
228 column_a->get_contents());
229 }
230 }
231 }
232 }
233
234 if (new_array->get_num_columns() != 0) {
235 new_format->add_array(new_array);
236 }
237 }
238
239 // Finally, register the format for the thing.
240 return GeomVertexFormat::register_format(new_format);
241}
242
243/**
244 * Returns a modifiable pointer to the indicated array. This means
245 * duplicating it if it is shared or registered.
246 *
247 * This may not be called once the format has been registered.
248 */
249GeomVertexArrayFormat *GeomVertexFormat::
250modify_array(size_t array) {
251 nassertr(!is_registered(), nullptr);
252 nassertr(array < _arrays.size(), nullptr);
253
254 if (_arrays[array]->is_registered() ||
255 _arrays[array]->get_ref_count() > 1) {
256 _arrays[array] = new GeomVertexArrayFormat(*_arrays[array]);
257 }
258
259 return _arrays[array];
260}
261
262/**
263 * Replaces the definition of the indicated array.
264 *
265 * This may not be called once the format has been registered.
266 */
268set_array(size_t array, const GeomVertexArrayFormat *format) {
269 nassertv(!is_registered());
270 nassertv(array < _arrays.size());
271 _arrays[array] = (GeomVertexArrayFormat *)format;
272}
273
274/**
275 * Removes the nth array from the format.
276 *
277 * This may not be called once the format has been registered.
278 */
280remove_array(size_t array) {
281 nassertv(!is_registered());
282
283 nassertv(array < _arrays.size());
284 _arrays.erase(_arrays.begin() + array);
285}
286
287/**
288 * Adds the indicated array definition to the list of arrays included within
289 * this vertex format definition. The return value is the index number of the
290 * new array.
291 *
292 * This may not be called once the format has been registered.
293 */
295add_array(const GeomVertexArrayFormat *array_format) {
296 nassertr(!is_registered(), 0);
297
298 size_t new_array = _arrays.size();
299 _arrays.push_back((GeomVertexArrayFormat *)array_format);
300 return new_array;
301}
302
303/**
304 * Adds the indicated array definition to the list of arrays at the indicated
305 * position. This works just like add_array(), except that you can specify
306 * which array index the new array should have.
307 *
308 * This may not be called once the format has been registered.
309 */
311insert_array(size_t array, const GeomVertexArrayFormat *array_format) {
312 nassertv(!is_registered());
313 if (array > _arrays.size()) {
314 array = _arrays.size();
315 }
316
317 _arrays.insert(_arrays.begin() + array, (GeomVertexArrayFormat *)array_format);
318}
319
320/**
321 * Removes all of the array definitions from the format and starts over.
322 *
323 * This may not be called once the format has been registered.
324 */
326clear_arrays() {
327 nassertv(!is_registered());
328
329 _arrays.clear();
330}
331
332/**
333 * Removes the arrays that define no columns.
334 *
335 * This may not be called once the format has been registered.
336 */
339 nassertv(!is_registered());
340
341 Arrays orig_arrays;
342 orig_arrays.swap(_arrays);
343 Arrays::const_iterator ai;
344 for (ai = orig_arrays.begin(); ai != orig_arrays.end(); ++ai) {
345 GeomVertexArrayFormat *array_format = (*ai);
346 if (array_format->get_num_columns() != 0) {
347 _arrays.push_back(array_format);
348 }
349 }
350}
351
352/**
353 * Returns the total number of different columns in the specification, across
354 * all arrays.
355 */
357get_num_columns() const {
358 size_t num_columns = 0;
359 Arrays::const_iterator ai;
360 for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
361 num_columns += (*ai)->get_num_columns();
362 }
363 return num_columns;
364}
365
366/**
367 * Returns the ith column of the specification, across all arrays.
368 */
370get_column(size_t i) const {
371 Arrays::const_iterator ai;
372 for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
373 if (i < (size_t)(*ai)->get_num_columns()) {
374 return (*ai)->get_column(i);
375 }
376 i -= (*ai)->get_num_columns();
377 }
378
379 return nullptr;
380}
381
382/**
383 * Returns the name of the ith column, across all arrays.
384 */
386get_column_name(size_t i) const {
387 Arrays::const_iterator ai;
388 for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
389 if (i < (size_t)(*ai)->get_num_columns()) {
390 return (*ai)->get_column(i)->get_name();
391 }
392 i -= (*ai)->get_num_columns();
393 }
394
395 return nullptr;
396}
397
398/**
399 * Returns the index number of the array with the ith column.
400 *
401 * The return value can be passed to get_array_format() to get the format of
402 * the array. It may also be passed to GeomVertexData::get_array_data() or
403 * get_data() or set_data() to manipulate the actual array data.
404 */
406get_array_with(size_t i) const {
407 int array_index = 0;
408 for (array_index = 0; array_index < (int)_arrays.size(); array_index++) {
409 if (i < (size_t)_arrays[array_index]->get_num_columns()) {
410 return array_index;
411 }
412 i -= _arrays[array_index]->get_num_columns();
413 }
414
415 return -1;
416}
417
418/**
419 * Returns the index number of the array with the indicated column, or -1 if
420 * no arrays contained that name.
421 *
422 * The return value can be passed to get_array_format() to get the format of
423 * the array. It may also be passed to GeomVertexData::get_array_data() or
424 * get_data() or set_data() to manipulate the actual array data.
425 *
426 * This may only be called after the format has been registered.
427 */
429get_array_with(const InternalName *name) const {
430 nassertr(_is_registered, -1);
431
432 DataTypesByName::const_iterator ai;
433 ai = _columns_by_name.find(name);
434 if (ai != _columns_by_name.end()) {
435 return (*ai).second._array_index;
436 }
437 return -1;
438}
439
440/**
441 * Returns the specification with the indicated name, or NULL if the name is
442 * not used. Use get_array_with() to determine which array this column is
443 * associated with.
444 */
446get_column(const InternalName *name) const {
447 if (!_is_registered) {
448 // If the format hasn't yet been registered, we have to search for the
449 // column the hard way.
450 Arrays::const_iterator ai;
451 for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
452 const GeomVertexColumn *column = (*ai)->get_column(name);
453 if (column != nullptr) {
454 return column;
455 }
456 }
457 return nullptr;
458
459 } else {
460 // If the format has been registered, we can just check the toplevel
461 // index.
462
463 DataTypesByName::const_iterator ai;
464 ai = _columns_by_name.find(name);
465 if (ai != _columns_by_name.end()) {
466 int array_index = (*ai).second._array_index;
467 int column_index = (*ai).second._column_index;
468
469 nassertr(array_index >= 0 && array_index < (int)_arrays.size(), nullptr);
470 return _arrays[array_index]->get_column(column_index);
471 }
472 return nullptr;
473 }
474}
475
476/**
477 * Removes the named column from the format, from whichever array it exists
478 * in. If there are other columns remaining in the array, the array is left
479 * with a gap where the column used to be; if this was the only column in the
480 * array, the array is removed (unless keep_empty_array is true).
481 *
482 * This may not be called once the format has been registered.
483 */
485remove_column(const InternalName *name, bool keep_empty_array) {
486 nassertv(!_is_registered);
487
488 // Since the format's not registered, it doesn't yet have an index of
489 // columns--so we have to search all of the arrays, one at a time, until we
490 // find it.
491 for (int array = 0; array < (int)_arrays.size(); ++array) {
492 GeomVertexArrayFormat *array_format = _arrays[array];
493
494 if (array_format->get_column(name) != nullptr) {
495 // Here's the array with the named column!
496 if (array_format->is_registered() ||
497 array_format->get_ref_count() > 1) {
498 // Get a safe-to-modify copy of the array format.
499 _arrays[array] = new GeomVertexArrayFormat(*array_format);
500 array_format = _arrays[array];
501 }
502
503 array_format->remove_column(name);
504
505 // Are there any columns remaining in the array?
506 if (!keep_empty_array && array_format->get_num_columns() == 0) {
507 // Remove the whole array.
508 remove_array(array);
509 }
510 return;
511 }
512 }
513
514 // It appears that column wasn't part of the format anyway. No problem;
515 // quietly return.
516}
517
518/**
519 * Removes wasted space between columns.
520 */
522pack_columns() {
523 nassertv(!_is_registered);
524 Arrays::iterator ai;
525 for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
526 if ((*ai)->is_registered()) {
527 (*ai) = new GeomVertexArrayFormat(*(*ai));
528 }
529 (*ai)->pack_columns();
530 }
531}
532
533/**
534 * Reprocesses the columns in the format to align the C_point and C_vector
535 * columns to 16-byte boundaries to allow for the more efficient SSE2
536 * operations (assuming SSE2 is enabled in the build).
537 *
538 * Also see maybe_align_columns_for_animation().
539 */
542 nassertv(!_is_registered);
543 Arrays::iterator ai;
544 for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
545 if ((*ai)->is_registered()) {
546 (*ai) = new GeomVertexArrayFormat(*(*ai));
547 }
548 (*ai)->align_columns_for_animation();
549 }
550}
551
552/**
553 * Calls align_columns_for_animation() if this format's AnimationSpec
554 * indicates that it contains animated vertices, and if vertex-animation-
555 * align-16 is true.
556 */
559 if (_animation.get_animation_type() == AT_panda && vertex_animation_align_16) {
561 }
562}
563
564/**
565 *
566 */
567void GeomVertexFormat::
568output(std::ostream &out) const {
569 if (_arrays.empty()) {
570 out << "(empty)";
571
572 } else {
573 Arrays::const_iterator ai;
574 ai = _arrays.begin();
575 out << *(*ai);
576 ++ai;
577 while (ai != _arrays.end()) {
578 out << ", " << *(*ai);
579 ++ai;
580 }
581 }
582
583 if (_animation.get_animation_type() != AT_none) {
584 out << ", anim " << _animation;
585 }
586}
587
588/**
589 *
590 */
591void GeomVertexFormat::
592write(std::ostream &out, int indent_level) const {
593 for (size_t i = 0; i < _arrays.size(); i++) {
594 indent(out, indent_level)
595 << "Array " << i << ":\n";
596 _arrays[i]->write(out, indent_level + 2);
597 }
598
599 if (_animation.get_animation_type() != AT_none) {
600 indent(out, indent_level)
601 << "anim " << _animation << "\n";
602 }
603}
604
605/**
606 *
607 */
608void GeomVertexFormat::
609write_with_data(std::ostream &out, int indent_level,
610 const GeomVertexData *data) const {
611 indent(out, indent_level)
612 << data->get_num_rows() << " rows.\n";
613 for (size_t i = 0; i < _arrays.size(); i++) {
614 CPT(GeomVertexArrayDataHandle) handle = data->get_array(i)->get_handle();
615 const unsigned char *array_data = handle->get_read_pointer(true);
616 indent(out, indent_level)
617 << "Array " << i << " (" << (void *)array_data << ", "
618 << *_arrays[i] << "):\n";
619 _arrays[i]->write_with_data(out, indent_level + 2, data->get_array(i));
620 }
621}
622
623/**
624 * Quickly looks up the indicated column within all of the nested arrays and
625 * sets array_index and column appropriately. Returns true if the data type
626 * exists in this format, false if it does not. If it returns false,
627 * array_index is set to -1, and column is set to NULL.
628 *
629 * This may only be called after the format has been registered.
630 */
632get_array_info(const InternalName *name, int &array_index,
633 const GeomVertexColumn *&column) const {
634 nassertr(_is_registered, false);
635
636 DataTypesByName::const_iterator ai;
637 ai = _columns_by_name.find(name);
638 if (ai != _columns_by_name.end()) {
639 array_index = (*ai).second._array_index;
640 column = _arrays[array_index]->get_column((*ai).second._column_index);
641 return true;
642 }
643
644 array_index = -1;
645 column = nullptr;
646
647 return false;
648}
649
650/**
651 *
652 */
653int GeomVertexFormat::
654compare_to(const GeomVertexFormat &other) const {
655 int compare = _animation.compare_to(other._animation);
656 if (compare != 0) {
657 return compare;
658 }
659
660 if (_arrays.size() != other._arrays.size()) {
661 return (int)_arrays.size() - (int)other._arrays.size();
662 }
663
664 for (size_t i = 0; i < _arrays.size(); i++) {
665 int compare = _arrays[i]->compare_to(*other._arrays[i]);
666 if (compare != 0) {
667 return compare;
668 }
669 }
670
671 return 0;
672}
673
674/**
675 * Returns the global registry object.
676 */
677void GeomVertexFormat::
678make_registry() {
679 if (_registry == nullptr) {
680 _registry = new Registry;
681 _registry->make_standard_formats();
682 }
683}
684
685/**
686 * Called internally when the format is registered.
687 */
688void GeomVertexFormat::
689do_register() {
690 nassertv(!is_registered());
691 nassertv(_columns_by_name.empty());
692
693 Arrays orig_arrays;
694 orig_arrays.swap(_arrays);
695 Arrays::const_iterator ai;
696 for (ai = orig_arrays.begin(); ai != orig_arrays.end(); ++ai) {
697 CPT(GeomVertexArrayFormat) array_format = (*ai);
698 if (!array_format->is_registered()) {
699 array_format = GeomVertexArrayFormat::register_format(array_format);
700 }
701
702 // Let's keep arrays with nonzero stride but no used columns; they're
703 // needed to preserve the isomorphic nature of matching formats. But
704 // we'll toss arrays with 0 stride, which add nothing of value and only
705 // cause problems later.
706 if (array_format->get_stride() == 0) {
707 gobj_cat.warning()
708 << "Dropping empty array from GeomVertexFormat.\n";
709 continue;
710 }
711
712 int array = (int)_arrays.size();
713 _arrays.push_back((GeomVertexArrayFormat *)array_format.p());
714
715 // Now add the names to the index.
716 int num_columns = array_format->get_num_columns();
717 for (int i = 0; i < num_columns; i++) {
718 const GeomVertexColumn *column = array_format->get_column(i);
719 std::pair<DataTypesByName::iterator, bool> result;
720 result = _columns_by_name.insert(DataTypesByName::value_type(column->get_name(), DataTypeRecord()));
721 if (!result.second) {
722 gobj_cat.warning()
723 << "Column " << *column->get_name() << " repeated in format.\n";
724 } else {
725 DataTypeRecord &record = (*result.first).second;
726 record._array_index = array;
727 record._column_index = i;
728 }
729 }
730 }
731
732 // Go back through the index now and identify the points, vectors, and morph
733 // descriptions, so we can quickly look these up later.
734 DataTypesByName::iterator ni;
735 for (ni = _columns_by_name.begin();
736 ni != _columns_by_name.end();
737 ++ni) {
738 const DataTypeRecord &record = (*ni).second;
739 const GeomVertexColumn *column = _arrays[record._array_index]->get_column(record._column_index);
740
741 switch (column->get_contents()) {
742 case C_point:
743 // It's a point.
744 _points.push_back(column->get_name());
745 break;
746
747 case C_vector:
748 case C_normal:
749 // It's a vector.
750 _vectors.push_back(column->get_name());
751 break;
752
753 case C_texcoord:
754 // It's a texcoord.
755 _texcoords.push_back(column->get_name());
756 break;
757
758 case C_morph_delta:
759 {
760 // It's a morph description.
761 MorphRecord morph;
762 morph._delta = column->get_name();
763
764 // The delta name must be of the form "basename.morph.slidername".
765 int n = morph._delta->find_ancestor("morph");
766 if (n < 0) {
767 gobj_cat.warning()
768 << "vertex format defines " << *column->get_name()
769 << ", which is stored as a C_morph_delta, but its name does not include \"morph\".\n";
770 } else {
771 morph._slider = InternalName::make(morph._delta->get_net_basename(n - 1));
772 morph._base = morph._delta->get_ancestor(n + 1);
773
774 if (_columns_by_name.find(morph._base) == _columns_by_name.end()) {
775 gobj_cat.warning()
776 << "vertex format defines "
777 << *column->get_name() << " but does not define "
778 << *morph._base << "\n";
779 } else {
780 _morphs.push_back(morph);
781 }
782 }
783 }
784 break;
785
786 default:
787 // Some other type of value we don't care about caching a pointer to.
788 break;
789 }
790 }
791
792 _is_registered = true;
793
794 get_array_info(InternalName::get_vertex(), _vertex_array_index,
795 _vertex_column);
796 get_array_info(InternalName::get_normal(), _normal_array_index,
797 _normal_column);
798 get_array_info(InternalName::get_color(), _color_array_index,
799 _color_column);
800}
801
802/**
803 * Called internally when the format is unregistered.
804 */
805void GeomVertexFormat::
806do_unregister() {
807 nassertv(_is_registered);
808 _is_registered = false;
809
810 _columns_by_name.clear();
811 _points.clear();
812 _vectors.clear();
813 _texcoords.clear();
814 _morphs.clear();
815
816 if (_post_animated_format != nullptr &&
817 _post_animated_format != this) {
818 unref_delete(_post_animated_format);
819 }
820 _post_animated_format = nullptr;
821}
822
823/**
824 * Tells the BamReader how to create objects of type GeomVertexFormat.
825 */
828 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
829}
830
831/**
832 * Writes the contents of this object to the datagram for shipping out to a
833 * Bam file.
834 */
836write_datagram(BamWriter *manager, Datagram &dg) {
838
839 _animation.write_datagram(manager, dg);
840
841 dg.add_uint16(_arrays.size());
842 Arrays::const_iterator ai;
843 for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
844 manager->write_pointer(dg, *ai);
845 }
846}
847
848/**
849 * Receives an array of pointers, one for each time manager->read_pointer()
850 * was called in fillin(). Returns the number of pointers processed.
851 */
853complete_pointers(TypedWritable **p_list, BamReader *manager) {
854 int pi = TypedWritableReferenceCount::complete_pointers(p_list, manager);
855
856 Arrays::iterator ai;
857 for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
858 (*ai) = DCAST(GeomVertexArrayFormat, p_list[pi++]);
859 }
860
861 return pi;
862}
863
864/**
865 * This function is called by the BamReader's factory when a new object of
866 * type GeomVertexFormat is encountered in the Bam file. It should create the
867 * GeomVertexFormat and extract its information from the file.
868 */
869TypedWritable *GeomVertexFormat::
870make_from_bam(const FactoryParams &params) {
872 DatagramIterator scan;
873 BamReader *manager;
874
875 parse_params(params, scan, manager);
876 object->fillin(scan, manager);
877
878 return object;
879}
880
881/**
882 * This internal function is called by make_from_bam to read in all of the
883 * relevant data from the BamFile for the new GeomVertexFormat.
884 */
885void GeomVertexFormat::
886fillin(DatagramIterator &scan, BamReader *manager) {
888
889 _animation.fillin(scan, manager);
890
891 int num_arrays = scan.get_uint16();
892 _arrays.reserve(num_arrays);
893 for (int i = 0; i < num_arrays; i++) {
894 manager->read_pointer(scan);
895 _arrays.push_back(nullptr);
896 }
897}
898
899/**
900 *
901 */
902GeomVertexFormat::Registry::
903Registry() {
904}
905
906/**
907 *
908 */
909void GeomVertexFormat::Registry::
910make_standard_formats() {
911 _empty = register_format(new GeomVertexFormat);
912
913 _v3 = register_format(new GeomVertexArrayFormat
914 (InternalName::get_vertex(), 3,
915 NT_stdfloat, C_point));
916
917 _v3n3 = register_format(new GeomVertexArrayFormat
918 (InternalName::get_vertex(), 3,
919 NT_stdfloat, C_point,
920 InternalName::get_normal(), 3,
921 NT_stdfloat, C_normal));
922
923 _v3t2 = register_format(new GeomVertexArrayFormat
924 (InternalName::get_vertex(), 3,
925 NT_stdfloat, C_point,
926 InternalName::get_texcoord(), 2,
927 NT_stdfloat, C_texcoord));
928
929 _v3n3t2 = register_format(new GeomVertexArrayFormat
930 (InternalName::get_vertex(), 3,
931 NT_stdfloat, C_point,
932 InternalName::get_normal(), 3,
933 NT_stdfloat, C_normal,
934 InternalName::get_texcoord(), 2,
935 NT_stdfloat, C_texcoord));
936
937 // Define the DirectX-style packed color formats
938 _v3cp = register_format(new GeomVertexArrayFormat
939 (InternalName::get_vertex(), 3,
940 NT_stdfloat, C_point,
941 InternalName::get_color(), 1,
942 NT_packed_dabc, C_color));
943
944 _v3n3cp = register_format(new GeomVertexArrayFormat
945 (InternalName::get_vertex(), 3,
946 NT_stdfloat, C_point,
947 InternalName::get_normal(), 3,
948 NT_stdfloat, C_normal,
949 InternalName::get_color(), 1,
950 NT_packed_dabc, C_color));
951
952 _v3cpt2 = register_format(new GeomVertexArrayFormat
953 (InternalName::get_vertex(), 3,
954 NT_stdfloat, C_point,
955 InternalName::get_color(), 1,
956 NT_packed_dabc, C_color,
957 InternalName::get_texcoord(), 2,
958 NT_stdfloat, C_texcoord));
959
960 _v3n3cpt2 = register_format(new GeomVertexArrayFormat
961 (InternalName::get_vertex(), 3,
962 NT_stdfloat, C_point,
963 InternalName::get_normal(), 3,
964 NT_stdfloat, C_normal,
965 InternalName::get_color(), 1,
966 NT_packed_dabc, C_color,
967 InternalName::get_texcoord(), 2,
968 NT_stdfloat, C_texcoord));
969
970 // Define the OpenGL-style per-byte color formats. This is not the same as
971 // a packed format, above, because the resulting byte order is endian-
972 // independent.
973 _v3c4 = register_format(new GeomVertexArrayFormat
974 (InternalName::get_vertex(), 3,
975 NT_stdfloat, C_point,
976 InternalName::get_color(), 4,
977 NT_uint8, C_color));
978
979 _v3n3c4 = register_format(new GeomVertexArrayFormat
980 (InternalName::get_vertex(), 3,
981 NT_stdfloat, C_point,
982 InternalName::get_normal(), 3,
983 NT_stdfloat, C_normal,
984 InternalName::get_color(), 4,
985 NT_uint8, C_color));
986
987 _v3c4t2 = register_format(new GeomVertexArrayFormat
988 (InternalName::get_vertex(), 3,
989 NT_stdfloat, C_point,
990 InternalName::get_color(), 4,
991 NT_uint8, C_color,
992 InternalName::get_texcoord(), 2,
993 NT_stdfloat, C_texcoord));
994
995 _v3n3c4t2 = register_format(new GeomVertexArrayFormat
996 (InternalName::get_vertex(), 3,
997 NT_stdfloat, C_point,
998 InternalName::get_normal(), 3,
999 NT_stdfloat, C_normal,
1000 InternalName::get_color(), 4,
1001 NT_uint8, C_color,
1002 InternalName::get_texcoord(), 2,
1003 NT_stdfloat, C_texcoord));
1004}
1005
1006/**
1007 * Adds the indicated format to the registry, if there is not an equivalent
1008 * format already there; in either case, returns the pointer to the equivalent
1009 * format now in the registry.
1010 *
1011 * This must be called before a format may be used in a Geom. After this
1012 * call, you should discard the original pointer you passed in (which may or
1013 * may not now be invalid) and let its reference count decrement normally; you
1014 * should use only the returned value from this point on.
1015 */
1016CPT(GeomVertexFormat) GeomVertexFormat::Registry::
1017register_format(GeomVertexFormat *format) {
1018 if (format->is_registered()) {
1019 return format;
1020 }
1021
1022 // Save the incoming pointer in a local PointerTo, so that if it has a zero
1023 // reference count and is not added into the map below, it will be
1024 // automatically deleted when this function returns.
1025 PT(GeomVertexFormat) pt_format = format;
1026
1027 GeomVertexFormat *new_format;
1028 {
1029 LightReMutexHolder holder(_lock);
1030 Formats::iterator fi = _formats.insert(format).first;
1031 new_format = (*fi);
1032 if (!new_format->is_registered()) {
1033 new_format->do_register();
1034 }
1035 }
1036
1037 return new_format;
1038}
1039
1040/**
1041 * Removes the indicated format from the registry. Normally this should not
1042 * be done until the format is destructing.
1043 *
1044 * The lock should be held prior to calling this method.
1045 */
1046void GeomVertexFormat::Registry::
1047unregister_format(GeomVertexFormat *format) {
1048 nassertv(format->is_registered());
1049 Formats::iterator fi = _formats.find(format);
1050 nassertv(fi != _formats.end());
1051 _formats.erase(fi);
1052 format->do_unregister();
1053}
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
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
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
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
Definition: bamWriter.cxx:317
A class to retrieve the individual data elements previously stored in a Datagram.
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_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
get_animation_type
Returns the type of animation represented by this spec.
int compare_to(const GeomVertexAnimationSpec &other) const
Provides an arbitrary ordering between different animation specs.
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...
void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
This data object is returned by GeomVertexArrayData::get_handle() or modify_handle().
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.
get_column
Returns the specification with the indicated name, or NULL if the name is not used.
get_num_columns
Returns the number of different columns in the array.
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.
This defines how a single column is interleaved within a vertex array stored within a Geom.
NumericType get_numeric_type() const
Returns the token representing the numeric type of the data storage.
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 defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
This class defines the physical layout of the vertex data stored within a Geom.
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_num_morphs
Returns the number of columns within the format that represent morph deltas.
get_animation
Returns the GeomVertexAnimationSpec that indicates how this format's vertices are set up for animatio...
set_animation
Resets the GeomVertexAnimationSpec that indicates how this format's vertices are set up for animation...
void maybe_align_columns_for_animation()
Calls align_columns_for_animation() if this format's AnimationSpec indicates that it contains animate...
void remove_empty_arrays()
Removes the arrays that define no columns.
void pack_columns()
Removes wasted space between columns.
int get_array_with(size_t i) const
Returns the index number of the array with the ith column.
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
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_morph_delta
Returns the name of the column that defines the nth morph.
set_array
Replaces the definition of the indicated array.
is_registered
Returns true if this format has been registered, false if it has not.
void clear_arrays()
Removes all of the array definitions from the format and starts over.
size_t add_array(const GeomVertexArrayFormat *array_format)
Adds the indicated array definition to the list of arrays included within this vertex format definiti...
virtual bool unref() const
This method overrides ReferenceCount::unref() to unregister the object when its reference count goes ...
static void register_with_read_factory()
Tells the BamReader how to create objects of type GeomVertexFormat.
get_num_columns
Returns the total number of different columns in the specification, across all arrays.
remove_array
Removes the nth array from the format.
bool get_array_info(const InternalName *name, int &array_index, const GeomVertexColumn *&column) const
Quickly looks up the indicated column within all of the nested arrays and sets array_index and column...
insert_array
Adds the indicated array definition to the list of arrays at the indicated position.
get_column_name
Returns the name of the ith column, across all arrays.
get_column
Returns the ith column of the specification, across all arrays.
void remove_column(const InternalName *name, bool keep_empty_array=false)
Removes the named column from the format, from whichever array it exists in.
Encodes a string name in a hash table, mapping it to a pointer.
Definition: internalName.h:38
int find_ancestor(const std::string &basename) const
Returns the index of the ancestor with the indicated basename, or -1 if no ancestor has that basename...
Similar to MutexHolder, but for a light reentrant mutex.
void ref() const
Explicitly increments the reference count.
bool test_ref_count_integrity() const
Does some easy checks to make sure that the reference count isn't completely bogus.
get_ref_count
Returns the current reference count.
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().
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: dcindent.cxx:22
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CPT(GeomVertexFormat) GeomVertexFormat
Returns a suitable vertex format for sending the animated vertices to the graphics backend.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...