32 using std::ostringstream;
36 NotifyCategoryDecl(drawmask, EXPCL_PANDA_PGRAPH, EXPTP_PANDA_PGRAPH);
37 NotifyCategoryDef(drawmask,
"");
39 TypeHandle PandaNode::BamReaderAuxDataDown::_type_handle;
41 PandaNode::SceneRootFunc *PandaNode::_scene_root_func;
43 PandaNodeChain PandaNode::_dirty_prev_transforms(
"_dirty_prev_transforms");
46 PStatCollector PandaNode::_reset_prev_pcollector(
"App:Collisions:Reset");
51 TypeHandle PandaNodePipelineReader::_type_handle;
76 PandaNode(
const string &name) :
78 _paths_lock(
"PandaNode::_paths_lock"),
79 _dirty_prev_transform(false)
81 if (pgraph_cat.is_debug()) {
83 <<
"Constructing " << (
void *)
this <<
", " << get_name() <<
"\n";
86 _unexpected_change_flags = 0;
89 #ifdef DO_MEMORY_USAGE 99 if (pgraph_cat.is_debug()) {
101 <<
"Destructing " << (
void *)
this <<
", " << get_name() <<
"\n";
104 if (_dirty_prev_transform) {
107 do_clear_dirty_prev_transform();
136 _paths_lock(
"PandaNode::_paths_lock"),
137 _dirty_prev_transform(false),
138 _python_tag_data(copy._python_tag_data)
140 if (pgraph_cat.is_debug()) {
142 <<
"Copying " << (
void *)
this <<
", " << get_name() <<
"\n";
144 #ifdef DO_MEMORY_USAGE 149 _unexpected_change_flags = 0;
157 CDReader copy_cdata(copy._cycler);
158 CDWriter cdata(_cycler,
true);
159 cdata->_state = copy_cdata->_state;
160 cdata->_transform = copy_cdata->_transform;
161 cdata->_prev_transform = copy_cdata->_prev_transform;
162 if (cdata->_transform != cdata->_prev_transform) {
163 do_set_dirty_prev_transform();
166 cdata->_effects = copy_cdata->_effects;
167 cdata->_tag_data = copy_cdata->_tag_data;
168 cdata->_draw_control_mask = copy_cdata->_draw_control_mask;
169 cdata->_draw_show_mask = copy_cdata->_draw_show_mask;
170 cdata->_into_collide_mask = copy_cdata->_into_collide_mask;
171 cdata->_bounds_type = copy_cdata->_bounds_type;
172 cdata->_user_bounds = copy_cdata->_user_bounds;
173 cdata->_internal_bounds =
nullptr;
174 cdata->_internal_bounds_computed = UpdateSeq::initial();
175 cdata->_internal_bounds_mark = UpdateSeq::initial();
176 ++cdata->_internal_bounds_mark;
177 cdata->_final_bounds = copy_cdata->_final_bounds;
178 cdata->_fancy_bits = copy_cdata->_fancy_bits;
290 if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
291 const LMatrix4 &mat = attribs._transform->get_mat();
294 Thread *current_thread = Thread::get_current_thread();
295 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
296 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
297 cdata->_effects = cdata->_effects->xform(mat);
298 cdata->set_fancy_bit(FB_effects, !cdata->_effects->is_empty());
300 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
358 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
bool &found_any,
360 CPT(
TransformState) next_transform = transform->compose(get_transform());
363 int num_children = cr.get_num_children();
364 for (
int i = 0; i < num_children; i++) {
365 cr.get_child(i)->calc_tight_bounds(min_point, max_point,
366 found_any, next_transform,
370 return next_transform;
498 copy_subgraph(
Thread *current_thread)
const {
499 InstanceMap inst_map;
500 return r_copy_subgraph(inst_map, current_thread);
507 count_num_descendants()
const {
510 int num_children = children.get_num_children();
512 for (
int i = 0; i < num_children; ++i) {
514 count += child->count_num_descendants();
530 nassertv(child_node !=
nullptr);
532 if (!verify_child_no_cycles(child_node)) {
544 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
545 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
546 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
548 cdata->modify_down()->insert(DownConnection(child_node, sort));
549 cdata_child->modify_up()->insert(UpConnection(
this));
551 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
553 OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) {
554 new_connection(
this, child_node, pipeline_stage, current_thread);
556 CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler);
558 force_bounds_stale();
561 child_node->parents_changed();
572 nassertv(pipeline_stage == 0);
574 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
575 PT(
Down) down = cdata->modify_down();
576 nassertv(child_index >= 0 && child_index < (
int)down->size());
579 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage,
581 PT(
Up) up = cdata_child->modify_up();
583 down->erase(down->begin() + child_index);
584 int num_erased = up->erase(UpConnection(
this));
585 nassertv(num_erased == 1);
587 sever_connection(
this, child_node, pipeline_stage, current_thread);
588 force_bounds_stale(pipeline_stage, current_thread);
591 child_node->parents_changed();
593 child_node->mark_bam_modified();
603 nassertr(child_node !=
nullptr,
false);
610 bool any_removed =
false;
612 OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) {
613 if (stage_remove_child(child_node, pipeline_stage, current_thread)) {
616 sever_connection(
this, child_node, pipeline_stage, current_thread);
617 force_bounds_stale(pipeline_stage, current_thread);
620 CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler);
625 child_node->parents_changed();
640 nassertr(orig_child !=
nullptr,
false);
641 nassertr(new_child !=
nullptr,
false);
643 if (orig_child == new_child) {
648 if (!verify_child_no_cycles(new_child)) {
656 PT(
PandaNode) keep_orig_child = orig_child;
659 bool any_replaced =
false;
661 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
662 if (stage_replace_child(orig_child, new_child, pipeline_stage, current_thread)) {
666 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
670 orig_child->parents_changed();
671 new_child->parents_changed();
690 nassertv(pipeline_stage == 0);
702 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
703 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
705 cdata->modify_stashed()->insert(
DownConnection(child_node, sort));
706 cdata_child->modify_up()->insert(UpConnection(
this));
709 new_connection(
this, child_node, pipeline_stage, current_thread);
710 force_bounds_stale(pipeline_stage, current_thread);
713 child_node->parents_changed();
730 nassertv(pipeline_stage == 0);
745 CDWriter cdata_child(child_node->_cycler);
748 cdata_child->modify_up()->insert(UpConnection(
this));
751 new_connection(
this, child_node, pipeline_stage, current_thread);
753 force_bounds_stale();
755 child_node->parents_changed();
773 nassertv(pipeline_stage == 0);
775 if (!verify_child_no_cycles(child_node)) {
787 CDWriter cdata_child(child_node->_cycler);
789 cdata->modify_stashed()->insert(
DownConnection(child_node, sort));
790 cdata_child->modify_up()->insert(UpConnection(
this));
793 new_connection(
this, child_node, pipeline_stage, current_thread);
797 child_node->parents_changed();
808 nassertv(pipeline_stage == 0);
810 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
811 Down &stashed = *cdata->modify_stashed();
812 nassertv(child_index >= 0 && child_index < (
int)stashed.size());
814 PT(
PandaNode) child_node = stashed[child_index].get_child();
815 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
817 stashed.erase(stashed.begin() + child_index);
818 int num_erased = cdata_child->modify_up()->erase(UpConnection(
this));
819 nassertv(num_erased == 1);
821 sever_connection(
this, child_node, pipeline_stage, current_thread);
822 force_bounds_stale(pipeline_stage, current_thread);
825 child_node->parents_changed();
827 child_node->mark_bam_modified();
838 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
839 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
840 PT(
Down) down = cdata->modify_down();
842 for (di = down->begin(); di != down->end(); ++di) {
844 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage,
846 cdata_child->modify_up()->erase(UpConnection(
this));
848 sever_connection(
this, child_node, pipeline_stage, current_thread);
849 child_node->parents_changed();
854 Down &stashed = *cdata->modify_stashed();
855 for (di = stashed.begin(); di != stashed.end(); ++di) {
857 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage,
859 cdata_child->modify_up()->erase(UpConnection(
this));
861 sever_connection(
this, child_node, pipeline_stage, current_thread);
862 child_node->parents_changed();
867 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
869 force_bounds_stale();
896 for (i = 0; i < num_children; i++) {
899 add_child(child_node, sort, current_thread);
902 for (i = 0; i < num_stashed; i++) {
925 for (i = 0; i < num_children; i++) {
928 add_child(child_node, sort, current_thread);
931 for (i = 0; i < num_stashed; i++) {
947 bool any_changed =
false;
948 Thread *current_thread = Thread::get_current_thread();
949 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
950 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
952 CPT(
RenderState) new_state = cdata->_state->set_attrib(attrib,
override);
953 if (cdata->_state != new_state) {
954 cdata->_state = new_state;
955 cdata->set_fancy_bit(FB_state,
true);
959 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
963 mark_bounds_stale(current_thread);
975 clear_attrib(
int slot) {
976 bool any_changed =
false;
978 Thread *current_thread = Thread::get_current_thread();
979 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
980 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
982 CPT(
RenderState) new_state = cdata->_state->remove_attrib(slot);
983 if (cdata->_state != new_state) {
984 cdata->_state = new_state;
985 cdata->set_fancy_bit(FB_state, !new_state->is_empty());
989 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
994 mark_bounds_stale(current_thread);
1008 Thread *current_thread = Thread::get_current_thread();
1009 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1010 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1011 cdata->_effects = cdata->_effects->add_effect(effect);
1012 cdata->set_fancy_bit(FB_effects,
true);
1014 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1023 Thread *current_thread = Thread::get_current_thread();
1024 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1025 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1026 cdata->_effects = cdata->_effects->remove_effect(type);
1027 cdata->set_fancy_bit(FB_effects, !cdata->_effects->is_empty());
1029 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1044 bool any_changed =
false;
1045 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1046 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1047 if (cdata->_state != state) {
1048 cdata->_state = state;
1049 cdata->set_fancy_bit(FB_state, !state->
is_empty());
1053 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1057 mark_bounds_stale(current_thread);
1072 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1073 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1074 cdata->_effects = effects;
1075 cdata->set_fancy_bit(FB_effects, !effects->
is_empty());
1077 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1094 bool any_changed =
false;
1095 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1096 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1097 if (cdata->_transform != transform) {
1098 cdata->_transform = transform;
1099 cdata->set_fancy_bit(FB_transform, !transform->
is_identity());
1102 if (pipeline_stage == 0) {
1103 if (cdata->_transform != cdata->_prev_transform) {
1104 do_set_dirty_prev_transform();
1109 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1112 mark_bounds_stale(current_thread);
1113 transform_changed();
1132 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1133 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1134 cdata->_prev_transform = transform;
1135 if (pipeline_stage == 0) {
1136 if (cdata->_transform != cdata->_prev_transform) {
1137 do_set_dirty_prev_transform();
1139 do_clear_dirty_prev_transform();
1143 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1156 do_clear_dirty_prev_transform();
1161 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1162 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1163 cdata->_prev_transform = cdata->_transform;
1165 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1179 PStatTimer timer(_reset_prev_pcollector, current_thread);
1183 while (list_node != &_dirty_prev_transforms) {
1185 nassertv(panda_node->_dirty_prev_transform);
1186 panda_node->_dirty_prev_transform =
false;
1188 CDStageWriter cdata(panda_node->_cycler, 0, current_thread);
1189 cdata->_prev_transform = cdata->_transform;
1191 list_node = panda_node->_next;
1193 panda_node->_prev =
nullptr;
1194 panda_node->_next =
nullptr;
1199 _dirty_prev_transforms._prev = &_dirty_prev_transforms;
1200 _dirty_prev_transforms._next = &_dirty_prev_transforms;
1213 set_tag(
const string &key,
const string &value,
Thread *current_thread) {
1216 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1217 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1218 cdata->_tag_data.store(key, value);
1219 cdata->set_fancy_bit(FB_tag,
true);
1221 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1231 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1232 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1233 cdata->_tag_data.remove(key);
1234 cdata->set_fancy_bit(FB_tag, !cdata->_tag_data.is_empty());
1236 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1247 if (other ==
this) {
1254 Thread *current_thread = Thread::get_current_thread();
1255 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1256 CDStageWriter cdataw(_cycler, pipeline_stage, current_thread);
1257 CDStageReader cdatar(other->_cycler, pipeline_stage, current_thread);
1259 for (
size_t n = 0; n < cdatar->_tag_data.size(); ++n) {
1260 cdataw->_tag_data.store(cdatar->_tag_data.get_key(n), cdatar->_tag_data.get_data(n));
1262 cdataw->set_fancy_bit(FB_tag, !cdataw->_tag_data.is_empty());
1264 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1268 _python_tag_data = other->_python_tag_data;
1285 for (
size_t n = 0; n < cdata->_tag_data.size(); ++n) {
1289 out << cdata->_tag_data.get_key(n);
1306 for (
size_t n = 0; n < cdata->_tag_data.size(); ++n) {
1307 keys.push_back(cdata->_tag_data.get_key(n));
1321 CDReader cdata_other(other->_cycler);
1323 const TagData &a_data = cdata->_tag_data;
1324 const TagData &b_data = cdata_other->_tag_data;
1328 while (ai < a_data.
size() && bi < b_data.
size()) {
1329 int cmp = strcmp(a_data.
get_key(ai).c_str(), b_data.
get_key(bi).c_str());
1334 cmp = strcmp(a_data.
get_key(ai).c_str(), b_data.
get_key(bi).c_str());
1342 if (ai < a_data.
size()) {
1346 if (bi < b_data.
size()) {
1353 if (_python_tag_data != other->_python_tag_data) {
1354 return (_python_tag_data < other->_python_tag_data) ? -1 : 1;
1368 if (other ==
this) {
1376 bool any_transform_changed =
false;
1377 bool any_state_changed =
false;
1378 bool any_draw_mask_changed =
false;
1379 Thread *current_thread = Thread::get_current_thread();
1380 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1381 CDStageWriter cdataw(_cycler, pipeline_stage, current_thread);
1382 CDStageReader cdatar(other->_cycler, pipeline_stage, current_thread);
1384 if (cdataw->_transform != cdatar->_transform) {
1385 any_transform_changed =
true;
1387 if (cdataw->_state != cdatar->_state) {
1388 any_state_changed =
true;
1390 if (cdataw->_draw_control_mask != cdatar->_draw_control_mask ||
1391 cdataw->_draw_show_mask != cdatar->_draw_show_mask) {
1392 any_draw_mask_changed =
true;
1395 cdataw->_transform = cdatar->_transform;
1396 cdataw->_prev_transform = cdatar->_prev_transform;
1397 cdataw->_state = cdatar->_state;
1398 cdataw->_effects = cdatar->_effects;
1399 cdataw->_draw_control_mask = cdatar->_draw_control_mask;
1400 cdataw->_draw_show_mask = cdatar->_draw_show_mask;
1404 cdataw->_into_collide_mask |= cdatar->_into_collide_mask;
1406 for (
size_t n = 0; n < cdatar->_tag_data.size(); ++n) {
1407 cdataw->_tag_data.store(cdatar->_tag_data.get_key(n), cdatar->_tag_data.get_data(n));
1410 static const int change_bits = (FB_transform | FB_state | FB_effects |
1411 FB_tag | FB_draw_mask);
1412 cdataw->_fancy_bits =
1413 (cdataw->_fancy_bits & ~change_bits) |
1414 (cdatar->_fancy_bits & change_bits);
1416 if (pipeline_stage == 0) {
1417 if (cdataw->_transform != cdataw->_prev_transform) {
1418 do_set_dirty_prev_transform();
1422 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1426 _python_tag_data = other->_python_tag_data;
1428 if (any_transform_changed || any_state_changed || any_draw_mask_changed) {
1429 mark_bounds_stale(current_thread);
1431 if (any_transform_changed) {
1432 transform_changed();
1434 if (any_state_changed) {
1437 if (any_draw_mask_changed) {
1438 draw_mask_changed();
1463 if (other ==
this) {
1480 for (pi = other->_paths.begin(); pi != other->_paths.end(); ++pi) {
1481 (*pi)->_node =
this;
1484 other->_paths.clear();
1491 Thread *current_thread = Thread::get_current_thread();
1521 _unexpected_change_flags |= flags;
1537 return _unexpected_change_flags & flags;
1556 _unexpected_change_flags &= ~flags;
1592 bool any_changed =
false;
1594 Thread *current_thread = Thread::get_current_thread();
1595 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1596 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1598 DrawMask draw_control_mask = (cdata->_draw_control_mask | show_mask | hide_mask) & ~clear_mask;
1599 DrawMask draw_show_mask = (cdata->_draw_show_mask | show_mask) & ~hide_mask;
1601 draw_show_mask |= ~draw_control_mask;
1603 if (cdata->_draw_control_mask != draw_control_mask ||
1604 cdata->_draw_show_mask != draw_show_mask) {
1605 cdata->_draw_control_mask = draw_control_mask;
1606 cdata->_draw_show_mask = draw_show_mask;
1609 cdata->set_fancy_bit(FB_draw_mask, !draw_control_mask.
is_zero());
1611 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1614 mark_bounds_stale(current_thread);
1615 draw_mask_changed();
1630 Thread *current_thread = Thread::get_current_thread();
1633 if (cdata->_last_update != cdata->_next_update) {
1637 ((
PandaNode *)
this)->update_cached(
false, pipeline_stage, cdata);
1638 return cdataw->_net_draw_control_mask;
1640 return cdata->_net_draw_control_mask;
1657 Thread *current_thread = Thread::get_current_thread();
1660 if (cdata->_last_update != cdata->_next_update) {
1664 ((
PandaNode *)
this)->update_cached(
false, pipeline_stage, cdata);
1665 return cdataw->_net_draw_show_mask;
1667 return cdata->_net_draw_show_mask;
1684 mask &= get_legal_collide_mask();
1686 bool any_changed =
false;
1687 Thread *current_thread = Thread::get_current_thread();
1688 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1689 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1690 if (cdata->_into_collide_mask != mask) {
1691 cdata->_into_collide_mask = mask;
1695 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1698 mark_bounds_stale(current_thread);
1712 get_legal_collide_mask()
const {
1724 if (cdata->_last_update != cdata->_next_update) {
1728 ((
PandaNode *)
this)->update_cached(
false, pipeline_stage, cdata);
1729 return cdataw->_net_collide_mask;
1731 return cdata->_net_collide_mask;
1739 get_off_clip_planes(
Thread *current_thread)
const {
1741 CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
1742 if (cdata->_last_update != cdata->_next_update) {
1745 CDStageWriter cdataw =
1746 ((
PandaNode *)
this)->update_cached(
false, pipeline_stage, cdata);
1747 return cdataw->_off_clip_planes;
1749 return cdata->_off_clip_planes;
1779 if (_scene_root_func !=
nullptr) {
1780 return (*_scene_root_func)(
this);
1813 output(ostream &out)
const {
1814 out << get_type() <<
" " << get_name();
1821 write(ostream &out,
int indent_level)
const {
1822 indent(out, indent_level) << *
this;
1830 out <<
" " << *transform;
1834 out <<
" " << *state;
1838 out <<
" " << *effects;
1841 if (!draw_control_mask.
is_zero()) {
1843 if (!(draw_control_mask & _overall_bit).is_zero()) {
1844 if (!(draw_show_mask & _overall_bit).is_zero()) {
1845 out <<
" (show_through)";
1850 if (!(draw_control_mask & ~_overall_bit).is_zero()) {
1851 draw_control_mask &= ~_overall_bit;
1852 if (!(draw_show_mask & draw_control_mask).is_zero()) {
1853 out <<
" (per-camera show_through)";
1855 if (!(~draw_show_mask & draw_control_mask).is_zero()) {
1856 out <<
" (per-camera hidden)";
1879 Thread *current_thread = Thread::get_current_thread();
1880 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1881 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1882 cdata->_bounds_type = bounds_type;
1883 mark_bounds_stale(pipeline_stage, current_thread);
1887 mark_internal_bounds_stale(pipeline_stage, current_thread);
1890 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1896 BoundingVolume::BoundsType PandaNode::
1897 get_bounds_type()
const {
1898 CDReader cdata(_cycler);
1899 return cdata->_bounds_type;
1914 Thread *current_thread = Thread::get_current_thread();
1915 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1916 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1917 if (volume ==
nullptr) {
1918 cdata->_user_bounds =
nullptr;
1920 cdata->_user_bounds = volume->make_copy();
1922 mark_bounds_stale(pipeline_stage, current_thread);
1925 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1933 pgraph_cat.warning()
1934 <<
"Deprecated PandaNode::set_bound() called. Use set_bounds() instead.\n";
1944 get_bounds(
Thread *current_thread)
const {
1946 CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
1947 if (cdata->_last_bounds_update != cdata->_next_update) {
1952 CDStageWriter cdataw =
1953 ((
PandaNode *)
this)->update_cached(
true, pipeline_stage, cdata);
1954 result = cdataw->_external_bounds;
1958 return cdata->_external_bounds;
1975 CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
1976 if (cdata->_last_bounds_update != cdata->_next_update) {
1981 CDStageWriter cdataw =
1982 ((
PandaNode *)
this)->update_cached(
true, pipeline_stage, cdata);
1983 result = cdataw->_external_bounds;
1984 seq = cdataw->_last_bounds_update;
1988 seq = cdata->_last_bounds_update;
1989 return cdata->_external_bounds;
2002 get_nested_vertices(
Thread *current_thread)
const {
2004 CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
2005 if (cdata->_last_bounds_update != cdata->_next_update) {
2010 CDStageWriter cdataw =
2011 ((
PandaNode *)
this)->update_cached(
true, pipeline_stage, cdata);
2012 result = cdataw->_nested_vertices;
2016 return cdata->_nested_vertices;
2033 mark_bounds_stale(
Thread *current_thread)
const {
2034 OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) {
2035 mark_bounds_stale(pipeline_stage, current_thread);
2037 CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler);
2052 mark_internal_bounds_stale(
Thread *current_thread) {
2053 OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) {
2054 mark_internal_bounds_stale(pipeline_stage, current_thread);
2056 CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler);
2125 decode_from_bam_stream(vector_uchar data,
BamReader *reader) {
2141 get_internal_bounds(
int pipeline_stage,
Thread *current_thread)
const {
2145 CDStageReader cdata(_cycler, pipeline_stage, current_thread);
2146 if (cdata->_user_bounds !=
nullptr) {
2147 return cdata->_user_bounds;
2150 if (cdata->_internal_bounds_mark == cdata->_internal_bounds_computed) {
2151 return cdata->_internal_bounds;
2154 mark = cdata->_internal_bounds_mark;
2160 int internal_vertices;
2161 compute_internal_bounds(internal_bounds, internal_vertices,
2162 pipeline_stage, current_thread);
2163 nassertr(!internal_bounds.is_null(),
nullptr);
2166 CDStageWriter cdataw(((
PandaNode *)
this)->_cycler, pipeline_stage);
2167 if (cdataw->_internal_bounds_mark == mark) {
2168 cdataw->_internal_bounds_computed = mark;
2169 cdataw->_internal_bounds = internal_bounds;
2170 cdataw->_internal_vertices = internal_vertices;
2171 ((
PandaNode *)
this)->mark_bam_modified();
2172 return cdataw->_internal_bounds;
2188 get_internal_vertices(
int pipeline_stage,
Thread *current_thread)
const {
2192 CDStageReader cdata(_cycler, pipeline_stage, current_thread);
2193 if (cdata->_internal_bounds_mark == cdata->_internal_bounds_computed) {
2194 return cdata->_internal_vertices;
2197 mark = cdata->_internal_bounds_mark;
2203 int internal_vertices;
2204 compute_internal_bounds(internal_bounds, internal_vertices,
2205 pipeline_stage, current_thread);
2206 nassertr(!internal_bounds.is_null(), 0);
2209 CDStageWriter cdataw(((
PandaNode *)
this)->_cycler, pipeline_stage);
2210 if (cdataw->_internal_bounds_mark == mark) {
2211 cdataw->_internal_bounds_computed = mark;
2212 cdataw->_internal_bounds = internal_bounds;
2213 cdataw->_internal_vertices = internal_vertices;
2214 ((
PandaNode *)
this)->mark_bam_modified();
2215 return cdataw->_internal_vertices;
2233 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
2234 CDStageWriter cdataw(_cycler, pipeline_stage, current_thread);
2235 cdataw->_internal_bounds = volume;
2236 cdataw->_internal_bounds_computed = cdataw->_internal_bounds_mark;
2238 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
2239 mark_bounds_stale(current_thread);
2251 force_bounds_stale(
Thread *current_thread) {
2252 OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) {
2253 force_bounds_stale(pipeline_stage, current_thread);
2255 CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler);
2263 force_bounds_stale(
int pipeline_stage,
Thread *current_thread) {
2265 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2266 ++cdata->_next_update;
2279 CDStageReader cdata(_cycler, pipeline_stage, current_thread);
2280 parents = Parents(cdata);
2282 int num_parents = parents.get_num_parents();
2283 for (
int i = 0; i < num_parents; ++i) {
2285 parent->mark_bounds_stale(pipeline_stage, current_thread);
2294 r_mark_geom_bounds_stale(
Thread *current_thread) {
2298 for (i = 0; i < children.get_num_children(); i++) {
2300 child->r_mark_geom_bounds_stale(current_thread);
2304 for (i = 0; i < stashed.get_num_stashed(); i++) {
2306 child->r_mark_geom_bounds_stale(current_thread);
2317 int &internal_vertices,
2319 Thread *current_thread)
const {
2321 internal_vertices = 0;
2331 nassertv((_unexpected_change_flags & UC_parents) == 0);
2340 children_changed() {
2341 nassertv((_unexpected_change_flags & UC_children) == 0);
2350 transform_changed() {
2351 nassertv((_unexpected_change_flags & UC_transform) == 0);
2361 nassertv((_unexpected_change_flags & UC_state) == 0);
2369 draw_mask_changed() {
2370 nassertv((_unexpected_change_flags & UC_draw_mask) == 0);
2384 nassertr(copy !=
nullptr,
nullptr);
2385 if (copy->get_type() != get_type()) {
2386 pgraph_cat.warning()
2387 <<
"Don't know how to copy nodes of type " << get_type() <<
"\n";
2389 if (no_unsupported_copy) {
2390 nassert_raise(
"unsupported copy");
2395 copy->r_copy_children(
this, inst_map, current_thread);
2411 Thread *current_thread) {
2412 CDReader from_cdata(from->_cycler, current_thread);
2413 CPT(Down) from_down = from_cdata->get_down();
2414 Down::const_iterator di;
2415 for (di = from_down->begin(); di != from_down->end(); ++di) {
2416 int sort = (*di).get_sort();
2424 InstanceMap::const_iterator ci;
2425 ci = inst_map.find(source_child);
2426 if (ci != inst_map.end()) {
2427 dest_child = (*ci).second;
2429 dest_child = source_child->r_copy_subgraph(inst_map, current_thread);
2430 inst_map[source_child] = dest_child;
2433 quick_add_new_child(dest_child, sort, current_thread);
2450 CPT(
RenderState) child_state = node_state->compose(child->get_state());
2451 child->
r_prepare_scene(gsg, child_state, transformer, current_thread);
2457 CPT(
RenderState) child_state = node_state->compose(child->get_state());
2458 child->
r_prepare_scene(gsg, child_state, transformer, current_thread);
2468 set_cull_callback() {
2469 Thread *current_thread = Thread::get_current_thread();
2470 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
2471 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2472 cdata->set_fancy_bit(FB_cull_callback,
true);
2474 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
2482 disable_cull_callback() {
2484 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
2485 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2486 cdata->set_fancy_bit(FB_cull_callback,
false);
2488 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
2497 stage_remove_child(
PandaNode *child_node,
int pipeline_stage,
2498 Thread *current_thread) {
2499 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2503 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage,
2505 int parent_index = child_node->do_find_parent(
this, cdata_child);
2506 if (parent_index < 0) {
2511 PT(Down) down = cdata->modify_down();
2512 int child_index = do_find_child(child_node, down);
2513 if (child_index >= 0) {
2515 down->erase(down->begin() + child_index);
2516 int num_erased = cdata_child->modify_up()->erase(UpConnection(
this));
2517 nassertr(num_erased == 1,
false);
2521 PT(Down) stashed = cdata->modify_stashed();
2522 int stashed_index = do_find_child(child_node, stashed);
2523 if (stashed_index >= 0) {
2525 stashed->erase(stashed->begin() + stashed_index);
2526 int num_erased = cdata_child->modify_up()->erase(UpConnection(
this));
2527 nassertr(num_erased == 1,
false);
2533 nassertr(
false,
false);
2543 int pipeline_stage,
Thread *current_thread) {
2545 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2546 CDStageWriter cdata_orig_child(orig_child->_cycler, pipeline_stage, current_thread);
2547 CDStageWriter cdata_new_child(new_child->_cycler, pipeline_stage, current_thread);
2551 int parent_index = orig_child->do_find_parent(
this, cdata_orig_child);
2552 if (parent_index < 0) {
2557 if (orig_child == new_child) {
2563 PT(
PandaNode) keep_orig_child = orig_child;
2566 if (stage_remove_child(new_child, pipeline_stage, current_thread)) {
2567 sever_connection(
this, new_child, pipeline_stage, current_thread);
2570 PT(Down) down = cdata->modify_down();
2571 int child_index = do_find_child(orig_child, down);
2572 if (child_index >= 0) {
2574 DownConnection &dc = (*down)[child_index];
2575 nassertr(dc.get_child() == orig_child,
false);
2576 dc.set_child(new_child);
2579 PT(Down) stashed = cdata->modify_stashed();
2580 int stashed_index = do_find_child(orig_child, stashed);
2581 if (stashed_index >= 0) {
2583 DownConnection &dc = (*stashed)[stashed_index];
2584 nassertr(dc.get_child() == orig_child,
false);
2585 dc.set_child(new_child);
2591 nassertr(
false,
false);
2597 cdata_new_child->modify_up()->insert(UpConnection(
this));
2598 int num_erased = cdata_orig_child->modify_up()->erase(UpConnection(
this));
2599 nassertr(num_erased == 1,
false);
2602 sever_connection(
this, orig_child, pipeline_stage, current_thread);
2603 new_connection(
this, new_child, pipeline_stage, current_thread);
2605 force_bounds_stale(pipeline_stage, current_thread);
2606 orig_child->parents_changed();
2607 new_child->parents_changed();
2622 quick_add_new_child(
PandaNode *child_node,
int sort,
Thread *current_thread) {
2625 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
2626 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2627 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
2629 cdata->modify_down()->insert(DownConnection(child_node, sort));
2630 cdata_child->modify_up()->insert(UpConnection(
this));
2632 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
2641 strm <<
"Detected attempt to create a cycle in the scene graph: " 2643 nassert_raise(strm.str());
2657 for (
size_t i = 0; i < parents.get_num_parents(); ++i) {
2659 if (parent->find_node_above(node)) {
2677 int pipeline_stage,
Thread *current_thread) {
2678 if (parent ==
nullptr) {
2683 pipeline_stage, current_thread);
2685 child_node->_paths.insert(child);
2691 PT(
NodePathComponent) child = get_component(parent, child_node, pipeline_stage, current_thread);
2693 if (child ==
nullptr) {
2696 child = get_top_component(child_node,
true, pipeline_stage, current_thread);
2699 reparent(parent, child, sort,
false, pipeline_stage, current_thread);
2712 nassertv(child !=
nullptr);
2714 for (
int pipeline_stage_i = pipeline_stage;
2715 pipeline_stage_i >= 0;
2716 --pipeline_stage_i) {
2717 detach_one_stage(child, pipeline_stage_i, current_thread);
2720 child->
get_node()->parents_changed();
2731 Thread *current_thread) {
2732 nassertv(child !=
nullptr);
2733 if (child->
is_top_node(pipeline_stage, current_thread)) {
2740 CDStageWriter cdata_parent(parent_node->_cycler, pipeline_stage, current_thread);
2741 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
2742 int parent_index = child_node->do_find_parent(parent_node, cdata_child);
2743 if (parent_index >= 0) {
2747 int num_erased = cdata_child->modify_up()->erase(UpConnection(parent_node));
2748 nassertv(num_erased == 1);
2755 PT(Down) down = cdata_parent->modify_down();
2756 for (di = down->begin(); di != down->end(); ++di) {
2757 if ((*di).get_child() == child_node) {
2764 PT(Down) stashed = cdata_parent->modify_stashed();
2765 for (di = stashed->begin(); di != stashed->end(); ++di) {
2766 if ((*di).get_child() == child_node) {
2777 sever_connection(parent_node, child_node, pipeline_stage, current_thread);
2779 parent_node->force_bounds_stale(pipeline_stage, current_thread);
2780 parent_node->children_changed();
2781 parent_node->mark_bam_modified();
2795 bool as_stashed,
int pipeline_stage,
Thread *current_thread) {
2796 bool any_ok =
false;
2798 if (new_parent !=
nullptr &&
2805 for (
int pipeline_stage_i = pipeline_stage;
2806 pipeline_stage_i >= 0;
2807 --pipeline_stage_i) {
2808 if (reparent_one_stage(new_parent, child, sort, as_stashed,
2809 pipeline_stage_i, current_thread)) {
2814 if (new_parent !=
nullptr) {
2815 new_parent->
get_node()->children_changed();
2818 child->
get_node()->parents_changed();
2835 int sort,
bool as_stashed,
int pipeline_stage,
2836 Thread *current_thread) {
2837 nassertr(child !=
nullptr,
false);
2843 if (!child->
is_top_node(pipeline_stage, current_thread)) {
2844 detach(child, pipeline_stage, current_thread);
2847 if (new_parent !=
nullptr) {
2852 CDStageReader cdata_child(child_node->_cycler, pipeline_stage, current_thread);
2853 int parent_index = child_node->do_find_parent(parent_node, cdata_child);
2855 if (parent_index >= 0) {
2862 child->set_next(new_parent, pipeline_stage, current_thread);
2866 CDStageWriter cdata_parent(parent_node->_cycler, pipeline_stage, current_thread);
2867 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
2870 cdata_parent->modify_stashed()->insert(DownConnection(child_node, sort));
2872 cdata_parent->modify_down()->insert(DownConnection(child_node, sort));
2874 cdata_child->modify_up()->insert(UpConnection(parent_node));
2880 nassertr(child_node->_paths.find(child) != child_node->_paths.end(),
false);
2885 child_node->fix_path_lengths(pipeline_stage, current_thread);
2886 parent_node->force_bounds_stale(pipeline_stage, current_thread);
2898 int pipeline_stage,
Thread *current_thread) {
2899 nassertr(parent !=
nullptr,
nullptr);
2907 Paths::const_iterator pi;
2908 for (pi = child_node->_paths.begin(); pi != child_node->_paths.end(); ++pi) {
2909 if ((*pi)->get_next(pipeline_stage, current_thread) == parent) {
2917 CDStageReader cdata_child(child_node->_cycler, pipeline_stage, current_thread);
2918 int parent_index = child_node->do_find_parent(parent_node, cdata_child);
2920 if (parent_index >= 0) {
2924 child_node->_paths.insert(child);
2943 get_top_component(
PandaNode *child_node,
bool force,
int pipeline_stage,
2944 Thread *current_thread) {
2949 Paths::const_iterator pi;
2950 for (pi = child_node->_paths.begin(); pi != child_node->_paths.end(); ++pi) {
2951 if ((*pi)->is_top_node(pipeline_stage, current_thread)) {
2967 pipeline_stage, current_thread);
2968 child_node->_paths.insert(child);
2981 get_generic_component(
bool accept_ambiguity,
int pipeline_stage,
2982 Thread *current_thread) {
2983 bool ambiguity_detected =
false;
2985 r_get_generic_component(accept_ambiguity, ambiguity_detected,
2986 pipeline_stage, current_thread);
2988 if (!accept_ambiguity && ambiguity_detected) {
2989 pgraph_cat.warning()
2990 <<
"Chose: " << *result <<
"\n";
2991 nassertr(!unambiguous_graph, result);
3003 r_get_generic_component(
bool accept_ambiguity,
bool &ambiguity_detected,
3004 int pipeline_stage,
Thread *current_thread) {
3008 CDStageReader cdata(_cycler, pipeline_stage, current_thread);
3010 int num_parents = cdata->get_up()->size();
3011 if (num_parents == 0) {
3013 return get_top_component(
this,
true, pipeline_stage, current_thread);
3017 if (num_parents == 1) {
3020 get_parent(0)->r_get_generic_component(accept_ambiguity, ambiguity_detected, pipeline_stage, current_thread);
3021 return get_component(parent,
this, pipeline_stage, current_thread);
3025 if (!accept_ambiguity) {
3026 pgraph_cat.warning()
3027 << *
this <<
" has " << num_parents
3028 <<
" parents; choosing arbitrary path to root.\n";
3030 ambiguity_detected =
true;
3031 CPT(Up) up = cdata->get_up();
3037 parent_node->r_get_generic_component(accept_ambiguity, ambiguity_detected, pipeline_stage, current_thread);
3038 return get_component(parent,
this, pipeline_stage, current_thread);
3048 int num_erased = _paths.erase(component);
3049 nassertv(num_erased == 1);
3066 int pipeline_stage,
Thread *current_thread) {
3070 for (pi = child_node->_paths.begin(); pi != child_node->_paths.end(); ++pi) {
3071 if (!(*pi)->is_top_node(pipeline_stage, current_thread) &&
3072 (*pi)->get_next(pipeline_stage, current_thread)->get_node() == parent_node) {
3074 (*pi)->set_top_node(pipeline_stage, current_thread);
3078 child_node->fix_path_lengths(pipeline_stage, current_thread);
3094 int pipeline_stage,
Thread *current_thread) {
3098 for (pi = child_node->_paths.begin(); pi != child_node->_paths.end(); ++pi) {
3099 if ((*pi)->is_top_node(pipeline_stage, current_thread)) {
3100 (*pi)->set_next(parent_node->get_generic_component(
false, pipeline_stage, current_thread), pipeline_stage, current_thread);
3104 child_node->fix_path_lengths(pipeline_stage, current_thread);
3116 fix_path_lengths(
int pipeline_stage,
Thread *current_thread) {
3119 bool any_wrong =
false;
3121 Paths::const_iterator pi;
3122 for (pi = _paths.begin(); pi != _paths.end(); ++pi) {
3123 if ((*pi)->fix_length(pipeline_stage, current_thread)) {
3135 CDStageReader cdata(_cycler, pipeline_stage, current_thread);
3136 children = Children(cdata);
3137 stashed = Stashed(cdata);
3140 int num_children = children.get_num_children();
3142 for (i = 0; i < num_children; ++i) {
3144 child_node->fix_path_lengths(pipeline_stage, current_thread);
3146 int num_stashed = stashed.get_num_stashed();
3147 for (i = 0; i < num_stashed; ++i) {
3149 child_node->fix_path_lengths(pipeline_stage, current_thread);
3158 r_list_descendants(ostream &out,
int indent_level)
const {
3159 write(out, indent_level);
3162 int num_children = children.get_num_children();
3164 for (
int i = 0; i < num_children; ++i) {
3165 PandaNode *child = children.get_child(i);
3166 child->r_list_descendants(out, indent_level + 2);
3171 if (num_stashed != 0) {
3172 indent(out, indent_level) <<
"(" << num_stashed <<
" stashed)\n";
3181 nassertr(node !=
nullptr, -1);
3185 Down::const_iterator di;
3186 for (di = down->begin(); di != down->end(); ++di) {
3187 if ((*di).get_child() == node) {
3188 return di - down->begin();
3210 if (drawmask_cat.is_debug()) {
3211 drawmask_cat.debug(
false)
3212 << *
this <<
"::update_cached() {\n";
3218 UpdateSeq last_update = cdata->_last_update;
3219 UpdateSeq next_update = cdata->_next_update;
3220 UpdateSeq last_bounds_update = cdata->_last_bounds_update;
3221 nassertr(last_update != next_update ||
3222 (update_bounds && last_bounds_update != next_update),
3223 CDStageWriter(_cycler, pipeline_stage, cdata));
3226 CollideMask net_collide_mask = cdata->_into_collide_mask;
3227 DrawMask net_draw_control_mask, net_draw_show_mask;
3233 net_draw_control_mask = cdata->_draw_control_mask;
3234 net_draw_show_mask = cdata->_draw_show_mask;
3237 if (drawmask_cat.is_debug()) {
3238 drawmask_cat.debug(
false)
3239 <<
"net_draw_control_mask = " << net_draw_control_mask
3240 <<
"\nnet_draw_show_mask = " << net_draw_show_mask
3243 CPT(
RenderAttrib) off_clip_planes = cdata->_state->get_attrib(ClipPlaneAttrib::get_class_slot());
3244 if (off_clip_planes ==
nullptr) {
3245 off_clip_planes = ClipPlaneAttrib::make();
3249 Children children(cdata);
3251 int num_vertices = cdata->_internal_vertices;
3257 int num_children = children.get_num_children();
3264 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 3266 if (update_bounds) {
3267 child_volumes_ref.reserve(num_children + 1);
3270 int child_volumes_i = 0;
3272 bool all_box =
true;
3275 if (update_bounds) {
3277 internal_bounds = get_internal_bounds(pipeline_stage, current_thread);
3279 if (!internal_bounds->is_empty()) {
3280 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 3281 child_volumes_ref.push_back(internal_bounds);
3283 nassertr(child_volumes_i < num_children + 1, CDStageWriter(_cycler, pipeline_stage, cdata));
3284 child_volumes[child_volumes_i++] = internal_bounds;
3285 if (internal_bounds->as_bounding_box() ==
nullptr) {
3293 for (
int i = 0; i < num_children; ++i) {
3298 CDLockedStageReader child_cdata(child->_cycler, pipeline_stage, current_thread);
3300 UpdateSeq last_child_update = update_bounds
3301 ? child_cdata->_last_bounds_update
3302 : child_cdata->_last_update;
3304 if (last_child_update != child_cdata->_next_update) {
3306 CDStageWriter child_cdataw = child->update_cached(update_bounds, pipeline_stage, child_cdata);
3308 net_collide_mask |= child_cdataw->_net_collide_mask;
3310 if (drawmask_cat.is_debug()) {
3311 drawmask_cat.debug(
false)
3312 <<
"\nchild update " << *child <<
":\n";
3315 DrawMask child_control_mask = child_cdataw->_net_draw_control_mask;
3316 DrawMask child_show_mask = child_cdataw->_net_draw_show_mask;
3317 if (!(child_control_mask | child_show_mask).is_zero()) {
3349 DrawMask exception_mask = (net_draw_control_mask ^ child_control_mask) & (net_draw_show_mask ^ child_show_mask);
3350 exception_mask &= (net_draw_control_mask ^ net_draw_show_mask);
3352 if (drawmask_cat.is_debug()) {
3353 drawmask_cat.debug(
false)
3354 <<
"exception_mask = " << exception_mask <<
"\n";
3358 net_draw_control_mask |= child_control_mask;
3359 net_draw_show_mask |= child_show_mask;
3361 net_draw_control_mask &= ~exception_mask;
3362 net_draw_show_mask |= exception_mask;
3365 if (drawmask_cat.is_debug()) {
3366 drawmask_cat.debug(
false)
3367 <<
"child_control_mask = " << child_control_mask
3368 <<
"\nchild_show_mask = " << child_show_mask
3369 <<
"\nnet_draw_control_mask = " << net_draw_control_mask
3370 <<
"\nnet_draw_show_mask = " << net_draw_show_mask
3374 off_clip_planes = orig_cp->compose_off(child_cdataw->_off_clip_planes);
3376 if (update_bounds) {
3377 if (!child_cdataw->_external_bounds->is_empty()) {
3378 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 3379 child_volumes_ref.push_back(child_cdataw->_external_bounds);
3381 nassertr(child_volumes_i < num_children + 1, CDStageWriter(_cycler, pipeline_stage, cdata));
3382 child_volumes[child_volumes_i++] = child_cdataw->_external_bounds;
3383 if (child_cdataw->_external_bounds->as_bounding_box() ==
nullptr) {
3387 num_vertices += child_cdataw->_nested_vertices;
3392 net_collide_mask |= child_cdata->_net_collide_mask;
3395 if (drawmask_cat.is_debug()) {
3396 drawmask_cat.debug(
false)
3397 <<
"\nchild fresh " << *child <<
":\n";
3399 DrawMask child_control_mask = child_cdata->_net_draw_control_mask;
3400 DrawMask child_show_mask = child_cdata->_net_draw_show_mask;
3401 if (!(child_control_mask | child_show_mask).is_zero()) {
3404 DrawMask exception_mask = (net_draw_control_mask ^ child_control_mask) & (net_draw_show_mask ^ child_show_mask);
3405 exception_mask &= (net_draw_control_mask ^ net_draw_show_mask);
3407 if (drawmask_cat.is_debug()) {
3408 drawmask_cat.debug(
false)
3409 <<
"exception_mask = " << exception_mask <<
"\n";
3413 net_draw_control_mask |= child_control_mask;
3414 net_draw_show_mask |= child_show_mask;
3416 net_draw_control_mask &= ~exception_mask;
3417 net_draw_show_mask |= exception_mask;
3420 if (drawmask_cat.is_debug()) {
3421 drawmask_cat.debug(
false)
3422 <<
"child_control_mask = " << child_control_mask
3423 <<
"\nchild_show_mask = " << child_show_mask
3424 <<
"\nnet_draw_control_mask = " << net_draw_control_mask
3425 <<
"\nnet_draw_show_mask = " << net_draw_show_mask
3429 off_clip_planes = orig_cp->compose_off(child_cdata->_off_clip_planes);
3431 if (update_bounds) {
3432 if (!child_cdata->_external_bounds->is_empty()) {
3433 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 3434 child_volumes_ref.push_back(child_cdata->_external_bounds);
3436 nassertr(child_volumes_i < num_children + 1, CDStageWriter(_cycler, pipeline_stage, cdata));
3437 child_volumes[child_volumes_i++] = child_cdata->_external_bounds;
3438 if (child_cdata->_external_bounds->as_bounding_box() ==
nullptr) {
3442 num_vertices += child_cdata->_nested_vertices;
3449 CDStageWriter cdataw(_cycler, pipeline_stage, current_thread);
3450 if (last_update == cdataw->_last_update &&
3451 next_update == cdataw->_next_update) {
3454 cdataw->_net_collide_mask = net_collide_mask;
3459 DrawMask draw_control_mask = cdataw->_draw_control_mask;
3460 DrawMask draw_show_mask = cdataw->_draw_show_mask;
3462 DrawMask show_through_mask = net_draw_control_mask & net_draw_show_mask;
3464 net_draw_control_mask |= draw_control_mask;
3465 net_draw_show_mask = (net_draw_show_mask & ~draw_control_mask) | (draw_show_mask & draw_control_mask);
3467 net_draw_show_mask |= show_through_mask;
3471 cdataw->_net_draw_control_mask = net_draw_control_mask;
3472 cdataw->_net_draw_show_mask = net_draw_show_mask | ~net_draw_control_mask;
3473 if (drawmask_cat.is_debug()) {
3474 drawmask_cat.debug(
false)
3475 <<
"renderable, set mask " << cdataw->_net_draw_show_mask <<
"\n";
3481 cdataw->_net_draw_control_mask = net_draw_control_mask;
3482 cdataw->_net_draw_show_mask = net_draw_show_mask;
3483 if (drawmask_cat.is_debug()) {
3484 drawmask_cat.debug(
false)
3485 <<
"not renderable, set mask " << cdataw->_net_draw_show_mask <<
"\n";
3489 cdataw->_off_clip_planes = off_clip_planes;
3491 if (update_bounds) {
3492 cdataw->_nested_vertices = num_vertices;
3497 BoundingVolume::BoundsType btype = cdataw->_bounds_type;
3498 if (btype == BoundingVolume::BT_default) {
3499 btype = bounds_type;
3502 if (btype == BoundingVolume::BT_box ||
3503 (btype != BoundingVolume::BT_sphere && all_box && transform->
is_identity())) {
3513 if (child_volumes_i > 0) {
3515 const BoundingVolume **child_end = child_begin + child_volumes_i;
3521 gbv->xform(transform->
get_mat());
3525 cdataw->_external_bounds = gbv;
3526 cdataw->_last_bounds_update = next_update;
3529 cdataw->_last_update = next_update;
3531 if (drawmask_cat.is_debug()) {
3532 drawmask_cat.debug(
false)
3533 <<
"} " << *
this <<
"::update_cached();\n";
3536 nassertr(cdataw->_last_update == cdataw->_next_update, cdataw);
3544 if (cdataw->_last_update == cdataw->_next_update &&
3545 (!update_bounds || cdataw->_last_bounds_update == cdataw->_next_update)) {
3553 cdata = CDLockedStageReader(_cycler, pipeline_stage, current_thread);
3555 if (cdata->_last_update == cdata->_next_update &&
3556 (!update_bounds || cdata->_last_bounds_update == cdata->_next_update)) {
3559 return CDStageWriter(_cycler, pipeline_stage, cdata);
3573 _scene_root_func = func;
3603 cdata->update_bam_nested(manager);
3634 node->fillin(scan, manager);
3676 _draw_control_mask(
DrawMask::all_off()),
3677 _draw_show_mask(
DrawMask::all_on()),
3680 _user_bounds(nullptr),
3681 _final_bounds(false),
3685 _net_draw_control_mask(
DrawMask::all_off()),
3686 _net_draw_show_mask(
DrawMask::all_off()),
3699 CData(
const PandaNode::CData ©) :
3701 _state(copy._state),
3702 _transform(copy._transform),
3703 _prev_transform(copy._prev_transform),
3705 _effects(copy._effects),
3706 _tag_data(copy._tag_data),
3707 _draw_control_mask(copy._draw_control_mask),
3708 _draw_show_mask(copy._draw_show_mask),
3709 _into_collide_mask(copy._into_collide_mask),
3710 _bounds_type(copy._bounds_type),
3711 _user_bounds(copy._user_bounds),
3712 _final_bounds(copy._final_bounds),
3713 _fancy_bits(copy._fancy_bits),
3715 _net_collide_mask(copy._net_collide_mask),
3716 _net_draw_control_mask(copy._net_draw_control_mask),
3717 _net_draw_show_mask(copy._net_draw_show_mask),
3718 _off_clip_planes(copy._off_clip_planes),
3719 _nested_vertices(copy._nested_vertices),
3720 _external_bounds(copy._external_bounds),
3721 _last_update(copy._last_update),
3722 _next_update(copy._next_update),
3723 _last_bounds_update(copy._last_bounds_update),
3726 _stashed(copy._stashed),
3746 return new CData(*
this);
3753 void PandaNode::CData::
3761 dg.
add_uint32(_draw_control_mask.get_word());
3763 dg.
add_uint32(_into_collide_mask.get_word());
3767 for (
size_t n = 0; n < _tag_data.size(); ++n) {
3772 write_up_list(*get_up(), manager, dg);
3773 write_down_list(*get_down(), manager, dg);
3774 write_down_list(*get_stashed(), manager, dg);
3781 void PandaNode::CData::
3782 update_bam_nested(
BamWriter *manager)
const {
3787 update_up_list(*get_up(), manager);
3788 update_down_list(*get_down(), manager);
3789 update_down_list(*get_stashed(), manager);
3796 int PandaNode::CData::
3802 DCAST_INTO_R(state, p_list[pi++], pi);
3806 DCAST_INTO_R(transform, p_list[pi++], pi);
3807 _prev_transform = _transform = transform;
3825 DCAST_INTO_R(effects, p_list[pi++], pi);
3842 pi += complete_up_list(*modify_up(),
"up", p_list + pi, manager);
3843 pi += complete_down_list(*modify_down(),
"down", p_list + pi, manager);
3844 pi += complete_down_list(*modify_stashed(),
"stashed", p_list + pi, manager);
3848 set_fancy_bit(FB_transform, !_transform->is_identity());
3849 set_fancy_bit(FB_state, !_state->is_empty());
3850 set_fancy_bit(FB_effects, !_effects->is_empty());
3851 set_fancy_bit(FB_tag, !_tag_data.is_empty());
3856 nassertr(!_transform->is_invalid(), pi);
3857 nassertr(!_prev_transform->is_invalid(), pi);
3866 void PandaNode::CData::
3881 _draw_control_mask = _overall_bit;
3882 _draw_show_mask = ~_overall_bit;
3891 draw_mask &= ~_overall_bit;
3892 _draw_control_mask = ~draw_mask;
3893 _draw_show_mask = draw_mask;
3901 _into_collide_mask.set_word(scan.
get_uint32());
3903 _bounds_type = BoundingVolume::BT_default;
3905 _bounds_type = (BoundingVolume::BoundsType)scan.
get_uint8();
3910 for (
int i = 0; i < num_tags; i++) {
3913 _tag_data.store(key, value);
3917 fillin_up_list(*modify_up(),
"up", scan, manager);
3918 fillin_down_list(*modify_down(),
"down", scan, manager);
3919 fillin_down_list(*modify_stashed(),
"stashed", scan, manager);
3925 void PandaNode::CData::
3938 int num_parents = 0;
3939 Up::const_iterator ui;
3940 for (ui = up_list.begin(); ui != up_list.end(); ++ui) {
3946 nassertv(num_parents == (
int)(uint16_t)num_parents);
3948 for (ui = up_list.begin(); ui != up_list.end(); ++ui) {
3959 void PandaNode::CData::
3962 int num_children = down_list.size();
3963 nassertv(num_children == (
int)(uint16_t)num_children);
3968 Down::const_iterator di;
3969 for (di = down_list.begin(); di != down_list.end(); ++di) {
3971 int sort = (*di).get_sort();
3980 void PandaNode::CData::
3982 Up::const_iterator ui;
3983 for (ui = up_list.begin(); ui != up_list.end(); ++ui) {
3994 void PandaNode::CData::
3996 Down::const_iterator di;
3997 for (di = down_list.begin(); di != down_list.end(); ++di) {
4006 int PandaNode::CData::
4012 Up new_up_list(PandaNode::get_class_type());
4013 new_up_list.reserve(num_parents);
4014 for (
int i = 0; i < num_parents; i++) {
4016 UpConnection connection(parent_node);
4017 new_up_list.push_back(connection);
4025 up_list.swap(new_up_list);
4026 new_up_list.clear();
4034 int PandaNode::CData::
4039 BamReaderAuxDataDown *aux;
4042 Down &new_down_list = aux->_down_list;
4043 for (Down::iterator di = new_down_list.begin();
4044 di != new_down_list.end();
4047 (*di).set_child(child_node);
4055 down_list.swap(new_down_list);
4056 new_down_list.clear();
4065 void PandaNode::CData::
4077 void PandaNode::CData::
4085 Down new_down_list(PandaNode::get_class_type());
4086 new_down_list.reserve(num_children);
4087 for (
int i = 0; i < num_children; i++) {
4090 DownConnection connection(
nullptr, sort);
4091 new_down_list.push_back(connection);
4096 PT(BamReaderAuxDataDown) aux =
new BamReaderAuxDataDown;
4097 aux->_down_list.swap(new_down_list);
4108 ? _cdata->_last_bounds_update
4109 : _cdata->_last_update;
4111 if (last_update != _cdata->_next_update) {
4116 #ifdef DO_PIPELINING 4118 #endif // DO_PIPELINING 4122 if (fresh_cdata->_last_update == fresh_cdata->_next_update &&
4123 (!update_bounds || fresh_cdata->_last_bounds_update == fresh_cdata->_next_update)) {
4126 if (_cdata != (
const PandaNode::CData *)fresh_cdata) {
4128 #ifdef DO_PIPELINING 4130 #endif // DO_PIPELINING 4136 PStatTimer timer(PandaNode::_update_bounds_pcollector);
4138 nassertv(cdataw->_last_update == cdataw->_next_update);
4141 if (_cdata != (
const PandaNode::CData *)cdataw) {
4143 #ifdef DO_PIPELINING 4145 #endif // DO_PIPELINING 4150 nassertv(_cdata->_last_update == _cdata->_next_update);
4151 nassertv(!update_bounds || _cdata->_last_bounds_update == _cdata->_next_update);
bool is_empty() const
Returns true if the state is empty, false otherwise.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual int get_visible_child() const
Returns the index number of the currently visible child of this node.
static BitMask< uint32_t, nbits > bit(int index)
Returns a BitMask with only the indicated bit on.
void clear_unexpected_change(unsigned int flags)
Sets one or more of the PandaNode::UnexpectedChange bits off, indicating that the corresponding prope...
virtual int get_first_visible_child() const
Returns the index number of the first visible child of this node, or a number >= get_num_children() i...
bool is_scene_root() const
Returns true if this particular node is known to be the render root of some active DisplayRegion asso...
virtual Light * as_light()
Cross-casts the node to a Light pointer, if it is one of the four kinds of Light nodes,...
virtual bool preserve_name() const
Returns true if the node's name has extrinsic meaning and must be preserved across a flatten operatio...
clear_tag
Removes the value defined for this key on this particular node.
A basic node of the scene graph or data graph.
The abstract interface to all kinds of lights.
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
PandaNode * get_stashed(size_t n) const
Returns the nth stashed child of the node.
void remove_child(int child_index, Thread *current_thread=Thread::get_current_thread())
Removes the nth child from the node.
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
This is our own Panda specialization on the default STL map.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PT(PandaNode) PandaNode
Allocates and returns a complete copy of this PandaNode and the entire scene graph rooted at this Pan...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the base class for a number of render attributes (other than transform) that may be set on sc...
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
bool replace_child(PandaNode *orig_child, PandaNode *new_child, Thread *current_thread=Thread::get_current_thread())
Searches for the orig_child node in the node's list of children, and replaces it with the new_child i...
virtual void apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, GeomTransformer &transformer)
Applies whatever attributes are specified in the AccumulatedAttribs object (and by the attrib_types b...
bool is_empty() const
Returns true if the state is empty, false otherwise.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
set_state
Sets the complete RenderState that will be applied to all nodes at this level and below.
bool has_object(const TypedWritable *obj) const
Returns true if the object has previously been written (or at least requested to be written) to the b...
DrawMask get_net_draw_show_mask() const
Returns the union of all draw_show_mask values–of renderable nodes only– at this level and below.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
virtual bool safe_to_modify_transform() const
Returns true if it is safe to automatically adjust the transform on this kind of node.
virtual PandaNode * combine_with(PandaNode *other)
Collapses this PandaNode with the other PandaNode, if possible, and returns a pointer to the combined...
static void reset_all_prev_transform(Thread *current_thread=Thread::get_current_thread())
Visits all nodes in the world with the _dirty_prev_transform flag–that is, all nodes whose _prev_tran...
void write_recorder(BamWriter *manager, Datagram &dg)
This method is provided for the benefit of classes (like MouseRecorder) that inherit from PandaMode a...
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
CPT(TransformState) PandaNode
This is used to support NodePath::calc_tight_bounds().
PandaNode * get_child(size_t n) const
Returns the nth child of the node.
void set_bounds(const BoundingVolume *volume)
Resets the bounding volume so that it is the indicated volume.
static BitMask< uint32_t, nbits > all_on()
Returns a BitMask whose bits are all on.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void list_tags(std::ostream &out, const std::string &separator="\n") const
Writes a list of all the tag keys assigned to the node to the indicated stream.
bool stash_child(PandaNode *child_node, Thread *current_thread=Thread::get_current_thread())
Stashes the indicated child node.
void get_tag_keys(vector_string &keys) const
Fills the given vector up with the list of tags on this PandaNode.
PandaNode * get_parent(size_t n) const
Returns the nth parent of the node.
bool unstash_child(PandaNode *child_node, Thread *current_thread=Thread::get_current_thread())
Returns the indicated stashed node to normal child status.
This defines a bounding sphere, consisting of a center and a radius.
This class is similar to CycleDataWriter, except it allows writing to a particular stage of the pipel...
A single page of data maintained by a PipelineCycler.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
unsigned int get_unexpected_change(unsigned int flags) const
Returns nonzero if any of the bits in the input parameter are set on this node, or zero if none of th...
Base class for objects that can be written to and read from Bam files.
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler)
Writes out the indicated CycleData object.
virtual bool has_selective_visibility() const
Should be overridden by derived classes to return true if this kind of node has some restrictions on ...
virtual bool safe_to_combine_children() const
Returns true if it is generally safe to combine the children of this PandaNode with each other.
This collects together the pieces of data that are accumulated for each node while walking the scene ...
const CycleDataType * take_pointer()
This is intended to be called only from CycleDataStageWriter when it elevates the pointer from read t...
void adjust_draw_mask(DrawMask show_mask, DrawMask hide_mask, DrawMask clear_mask)
Adjusts the hide/show bits of this particular node.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
This functions similarly to a LightAttrib.
static bool decode_raw_from_bam_stream(TypedWritable *&ptr, ReferenceCount *&ref_ptr, vector_uchar data, BamReader *reader=nullptr)
Reads the bytes created by a previous call to encode_to_bam_stream(), and extracts the single object ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static BitMask< WType, nbits > all_off()
Returns a BitMask whose bits are all off.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
This is the base class for a number of special render effects that may be set on scene graph nodes to...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PandaNode * get_node() const
Returns the node referenced by this component.
int32_t get_int32()
Extracts a signed 32-bit integer.
static void register_with_read_factory()
Tells the BamReader how to create objects of type PandaNode.
int get_int_tag(const std::string &tag) const
Returns the value previously set via set_int_tag().
get_pipeline_stage
Returns the Pipeline stage number associated with this thread.
virtual bool safe_to_combine() const
Returns true if it is generally safe to combine this particular kind of PandaNode with other kinds of...
void set_word(WordType value)
Sets the entire BitMask to the value indicated by the given word.
void copy_tags(PandaNode *other)
Copies all of the tags stored on the other node onto this node.
std::string get_string()
Extracts a variable-length string.
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
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 r_prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state, GeomTransformer &transformer, Thread *current_thread)
The recursive implementation of prepare_scene().
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
This just stores the pointers to implement a doubly-linked list of some kind of object.
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
DrawMask get_net_draw_control_mask() const
Returns the set of bits in get_net_draw_show_mask() that have been explicitly set via adjust_draw_mas...
void add_uint32(uint32_t value)
Adds an unsigned 32-bit integer to the datagram.
set_tag
Associates a user-defined value with a user-defined key which is stored on the node.
set_transform
Sets the transform that will be applied to this node and below.
get_parents
Returns an object that can be used to walk through the list of parents of the node,...
static NodePath any_path(PandaNode *node, Thread *current_thread=Thread::get_current_thread())
Returns a new NodePath that represents any arbitrary path from the root to the indicated node.
This is our own Panda specialization on the default STL vector.
get_draw_control_mask
Returns the set of bits in draw_show_mask that are considered meaningful.
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
void reset_prev_transform(Thread *current_thread=Thread::get_current_thread())
Resets the transform that represents this node's "previous" position to the same as the current trans...
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this PandaNode by the indicated matrix, if it means anything to do so.
A lightweight class that represents a single element that may be timed and/or counted via stats.
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
get_draw_show_mask
Returns the hide/show bits of this particular node.
void parse_params(const FactoryParams ¶ms, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
get_num_children
Returns the number of child nodes this node has.
get_current_thread
Returns a pointer to the currently-executing Thread object.
void release_read_stage(int pipeline_stage, const CycleData *pointer) const
Releases a pointer previously obtained via a call to read_stage().
void check_cached(bool update_bounds) const
Ensures that the draw masks etc.
A base class for all things which can have a name.
bool is_top_node(int pipeline_stage, Thread *current_thread) const
Returns true if this component represents the top node in the path.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int compare_tags(const PandaNode *other) const
Returns a number less than 0, 0, or greater than 0, to indicate the similarity of tags between this n...
set_effects
Sets the complete RenderEffects that will be applied this node.
This class is used by the SceneGraphReducer to maintain and accumulate the set of attributes we have ...
void remove_all_children(Thread *current_thread=Thread::get_current_thread())
Removes all the children from the node at once, including stashed children.
size_t get_num_children() const
Returns the number of children of the node.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
void set_bounds_type(BoundingVolume::BoundsType bounds_type)
Specifies the desired type of bounding volume that will be created for this node.
Similar to MutexHolder, but for a light mutex.
virtual bool is_collision_node() const
A simple downcast check.
BamReaderAuxData * get_aux_tag(const std::string &tag) const
Returns the value previously set via set_aux_tag().
void read_pointers(DatagramIterator &scan, int count)
A convenience function to read a contiguous list of pointers.
int get_child_sort(size_t n) const
Returns the sort index of the nth child node of this node (that is, the number that was passed to add...
bool is_under_scene_root() const
Returns true if this particular node is in a live scene graph: that is, it is a child or descendent o...
NodePathComponent * get_next(int pipeline_stage, Thread *current_thread) const
Returns the next component in the path.
virtual PandaNode * dupe_for_flatten() const
This is similar to make_copy(), but it makes a copy for the specific purpose of flatten.
void remove_stashed(int child_index, Thread *current_thread=Thread::get_current_thread())
Removes the nth stashed child from the node.
int find_parent(PandaNode *node, Thread *current_thread=Thread::get_current_thread()) const
Returns the index of the indicated parent node, if it is a parent, or -1 if it is not.
void add_string(const std::string &str)
Adds a variable-length string to the datagram.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
void copy_all_properties(PandaNode *other)
Copies the TransformState, RenderState, RenderEffects, tags, Python tags, and the show/hide state fro...
const Key & get_key(size_t n) const
Returns the key in the nth entry of the table.
virtual void add_for_draw(CullTraverser *trav, CullTraverserData &data)
Adds the node's contents to the CullResult we are building up during the cull traversal,...
uint32_t get_uint32()
Extracts an unsigned 32-bit integer.
get_children
Returns an object that can be used to walk through the list of children of the node.
void steal_children(PandaNode *other, Thread *current_thread=Thread::get_current_thread())
Moves all the children from the other node onto this node.
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
virtual void update_bam_nested(BamWriter *manager)
Called by the BamWriter when this object has not itself been modified recently, but it should check i...
void set_effect(const RenderEffect *effect)
Adds the indicated render effect to the scene graph on this node.
void set_unexpected_change(unsigned int flags)
Sets one or more of the PandaNode::UnexpectedChange bits on, indicating that the corresponding proper...
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().
virtual bool safe_to_flatten_below() const
Returns true if a flatten operation may safely continue past this node, or false if nodes below this ...
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static void set_scene_root_func(SceneRootFunc *func)
This is used by the GraphicsEngine to hook in a pointer to the scene_root_func(), the function to det...
int get_child_sort(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the sort index of the nth child node of this node (that is, the number that was passed to add...
CollideMask get_net_collide_mask(Thread *current_thread=Thread::get_current_thread()) const
Returns the union of all into_collide_mask() values set at CollisionNodes at this level and below.
void add_stashed(PandaNode *child_node, int sort=0, Thread *current_thread=Thread::get_current_thread())
Adds a new child to the node, directly as a stashed child.
set_into_collide_mask
Sets the "into" CollideMask.
A base class for things which need to inherit from both TypedWritable and from ReferenceCount.
virtual int get_unsafe_to_apply_attribs() const
Returns the union of all attributes from SceneGraphReducer::AttribTypes that may not safely be applie...
virtual bool is_lod_node() const
A simple downcast check.
virtual PandaNode * make_copy() const
Returns a newly-allocated PandaNode that is a shallow copy of this one.
This class is similar to CycleDataLockedReader, except it allows reading from a particular stage of t...
Similar to MutexHolder, but for a light reentrant mutex.
void finalize_now(TypedWritable *whom)
Forces the finalization of a particular object.
void set_attrib(const RenderAttrib *attrib, int override=0)
Adds the indicated render attribute to the scene graph on this node.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_parent
Returns the nth parent node of this node.
static void update_type(ReferenceCount *ptr, TypeHandle type)
Associates the indicated type with the given pointer.
get_stashed
Returns the nth stashed child of this node.
This class is similar to CycleDataReader, except it allows reading from a particular stage of the pip...
virtual bool is_ambient_light() const
Returns true if this is an AmbientLight, false if it is not a light, or it is some other kind of ligh...
A base class for all things that want to be reference-counted.
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
void set_bound(const BoundingVolume *volume)
Deprecated.
void replace_node(PandaNode *other)
Inserts this node into the scene graph in place of the other one, and removes the other node.
void add_int32(int32_t value)
Adds a signed 32-bit integer to the datagram.
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
bool around(const BoundingVolume **first, const BoundingVolume **last)
Resets the volume to enclose only the volumes indicated.
A thread; that is, a lightweight process.
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
int get_stashed_sort(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the sort index of the nth stashed node of this node (that is, the number that was passed to a...
Encapsulates the data from a PandaNode, pre-fetched for one stage of the pipeline.
Thread * get_current_thread() const
Returns the Thread pointer of the currently-executing thread, as passed to the constructor of this ob...
size_t get_num_stashed() const
Returns the number of stashed children of the node.
virtual bool has_single_child_visibility() const
Should be overridden by derived classes to return true if this kind of node has the special property ...
constexpr size_t size() const
Returns the total number of entries in the table.
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
A class to retrieve the individual data elements previously stored in a Datagram.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void clear_effect(TypeHandle type)
Removes the render effect of the given type from this node.
get_child
Returns the nth child node of this node.
void set_int_tag(const std::string &tag, int value)
Allows the creating object to store a temporary data value on the BamReader.
void set_prev_transform(const TransformState *transform, Thread *current_thread=Thread::get_current_thread())
Sets the transform that represents this node's "previous" position, one frame ago,...
void consider_update(const TypedWritable *obj)
Should be called from TypedWritable::update_bam_nested() to recursively check the entire hiererachy o...
TypeHandle is the identifier used to differentiate C++ class types.
This is a sequence number that increments monotonically.
virtual bool safe_to_transform() const
Returns true if it is generally safe to transform this particular kind of PandaNode by calling the xf...
int find_stashed(PandaNode *node, Thread *current_thread=Thread::get_current_thread()) const
Returns the index of the indicated stashed node, if it is a stashed child, or -1 if it is not.
virtual bool is_geom_node() const
A simple downcast check.
virtual int get_next_visible_child(int n) const
Returns the index number of the next visible child of this node following the indicated child,...
void copy_children(PandaNode *other, Thread *current_thread=Thread::get_current_thread())
Makes another instance of all the children of the other node, copying them to this node.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
size_t get_num_parents() const
Returns the number of parents of the node.
virtual bool is_renderable() const
Returns true if there is some value to visiting this particular node during the cull traversal for an...
This represents a unique collection of RenderEffect objects that correspond to a particular renderabl...
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
int get_stashed_sort(size_t n) const
Returns the sort index of the nth child node of this node (that is, the number that was passed to add...
void set_aux_tag(const std::string &tag, BamReaderAuxData *value)
Allows the creating object to store a temporary data value on the BamReader.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void mark_bam_modified()
Increments the bam_modified counter, so that this object will be invalidated and retransmitted on any...
void node_unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...
virtual bool safe_to_flatten() const
Returns true if it is generally safe to flatten out this particular kind of PandaNode by duplicating ...
get_num_stashed
Returns the number of stashed nodes this node has.
bool is_zero() const
Returns true if the entire bitmask is zero, false otherwise.
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
This class maintains a linked list of PandaNodes.
This is one component of a NodePath.