Panda3D
Loading...
Searching...
No Matches
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.
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.
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...
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.
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...
get_name
Returns the complete name represented by the InternalName and all of its parents.
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.
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
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.
void unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...